Skip to content

Commit

Permalink
feat(rust): Improve JSON output of ockam node show
Browse files Browse the repository at this point in the history
Improves the output of the command `ockam node show --output json`
adding all the information that is being displayed with the plain
output. Refactors the plain response to build it using the Output
trait erasing the a clippy alert in the process.

Closes #6142
  • Loading branch information
kriogenia committed Oct 4, 2023
1 parent 7053ea5 commit 515f18c
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 199 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,11 @@ impl OutletStatus {
}

/// Response body when returning a list of Inlets
#[derive(Debug, Clone, Decode, Encode)]
#[derive(Debug, Clone, Decode, Encode, Serialize)]
#[rustfmt::skip]
#[cbor(map)]
pub struct InletList {
#[serde(rename = "inlets")]
#[n(1)] pub list: Vec<InletStatus>
}

Expand All @@ -251,10 +252,11 @@ impl InletList {
}

/// Response body when returning a list of Outlets
#[derive(Debug, Clone, Decode, Encode)]
#[derive(Debug, Clone, Decode, Encode, Serialize)]
#[rustfmt::skip]
#[cbor(map)]
pub struct OutletList {
#[serde(rename = "outlets")]
#[n(1)] pub list: Vec<OutletStatus>
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::time::Duration;

use minicbor::{Decode, Encode};
use serde::Serialize;

use ockam::identity::{Identifier, DEFAULT_TIMEOUT};
use ockam_core::flow_control::FlowControlId;
use ockam_core::{route, Address, Result};
use ockam_multiaddr::MultiAddr;
use serde::Serialize;

use crate::error::ApiError;
use crate::nodes::registry::{SecureChannelInfo, SecureChannelListenerInfo};
Expand Down Expand Up @@ -144,11 +144,13 @@ impl ShowSecureChannelListenerRequest {
}

/// Response body to show a Secure Channel Listener
#[derive(Debug, Clone, Decode, Encode)]
#[derive(Debug, Clone, Decode, Encode, Serialize)]
#[rustfmt::skip]
#[cbor(map)]
pub struct ShowSecureChannelListenerResponse {
#[n(1)] pub addr: Address,
#[serde(rename = "address", serialize_with = "crate::util::serialize_as_multiaddr")]
#[n(1)] pub addr: Address,
#[serde(rename = "flow_control")]
#[n(2)] pub flow_control_id: FlowControlId,
}

Expand Down Expand Up @@ -236,10 +238,11 @@ impl ShowSecureChannelResponse {
}
}

#[derive(Debug, Clone, Decode, Encode)]
#[derive(Debug, Clone, Decode, Encode, Serialize)]
#[rustfmt::skip]
#[cbor(map)]
pub struct SecureChannelListenersList {
#[serde(rename = "secure_channel_listeners")]
#[n(1)] pub list: Vec<ShowSecureChannelListenerResponse>,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,9 @@ impl StartOktaIdentityProviderRequest {
#[rustfmt::skip]
#[cbor(map)]
pub struct ServiceStatus {
#[serde(rename = "address", serialize_with = "crate::util::serialize_as_multiaddr")]
#[n(2)] pub addr: String,
#[serde(rename = "type")]
#[n(3)] pub service_type: String,
}

Expand All @@ -383,6 +385,7 @@ impl ServiceStatus {
#[rustfmt::skip]
#[cbor(map)]
pub struct ServiceList {
#[serde(rename = "services")]
#[n(1)] pub list: Vec<ServiceStatus>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,31 @@ use ockam_core::flow_control::FlowControlId;
use ockam_core::{Error, Result};
use ockam_multiaddr::proto::Worker;
use ockam_multiaddr::MultiAddr;
use serde::Serialize;
use std::net::SocketAddrV4;

/// Response body when interacting with a transport
#[derive(Debug, Clone, Decode, Encode)]
#[derive(Debug, Clone, Decode, Encode, Serialize)]
#[rustfmt::skip]
#[cbor(map)]
pub struct TransportStatus {
/// The type of transport to create
#[serde(rename = "type")]
#[n(1)] pub tt: TransportType,
/// The mode the transport should operate in
#[serde(rename = "mode")]
#[n(2)] pub tm: TransportMode,
/// Corresponding socket address
#[serde(rename = "socket")]
#[n(3)] pub socket_addr: String,
/// Corresponding worker address
#[serde(rename = "worker")]
#[n(4)] pub worker_addr: String,
/// Corresponding worker address
#[serde(skip)]
#[n(5)] pub processor_address: String,
/// Corresponding flow control id
#[serde(rename = "flow_control")]
#[n(6)] pub flow_control_id: FlowControlId,
}

Expand Down Expand Up @@ -58,10 +65,11 @@ impl TransportStatus {
}

/// Response body when interacting with a transport
#[derive(Debug, Clone, Decode, Encode)]
#[derive(Debug, Clone, Decode, Encode, Serialize)]
#[rustfmt::skip]
#[cbor(map)]
pub struct TransportList {
#[serde(rename = "transports")]
#[n(1)] pub list: Vec<TransportStatus>
}

Expand Down
10 changes: 10 additions & 0 deletions implementations/rust/ockam/ockam_api/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use miette::miette;
use serde::Serializer;
use std::net::{SocketAddrV4, SocketAddrV6};

use ockam::TcpTransport;
Expand Down Expand Up @@ -307,6 +308,15 @@ pub fn addr_to_multiaddr<T: Into<Address>>(a: T) -> Option<MultiAddr> {
route_to_multiaddr(&r)
}

/// Serialize the field attempting to convert it first to a MultiAddr.
pub fn serialize_as_multiaddr<T, S>(t: &T, s: S) -> Result<S::Ok, S::Error>
where
T: Into<Address> + Clone,
S: Serializer,
{
s.serialize_some(&addr_to_multiaddr(t.clone()))
}

/// Tells whether the input MultiAddr references a local node or a remote node.
///
/// This should be called before cleaning the MultiAddr.
Expand Down
1 change: 1 addition & 0 deletions implementations/rust/ockam/ockam_command/src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod default;
mod delete;
mod list;
mod logs;
pub mod models;
mod show;
mod start;
mod stop;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod portal;
pub mod show;
42 changes: 42 additions & 0 deletions implementations/rust/ockam/ockam_command/src/node/models/portal.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::net::SocketAddr;

use ockam_api::{
addr_to_multiaddr,
nodes::models::portal::{InletStatus, OutletStatus},
route_to_multiaddr,
};
use ockam_core::Route;
use ockam_multiaddr::MultiAddr;
use serde::Serialize;

/// Information to display of the inlets in the `ockam node show` command
#[derive(Debug, Serialize)]
pub struct ShowInletStatus {
pub listen_address: String,
pub route_to_outlet: Option<MultiAddr>,
}

impl From<InletStatus> for ShowInletStatus {
fn from(value: InletStatus) -> Self {
Self {
listen_address: value.bind_addr,
route_to_outlet: Route::parse(value.outlet_route).and_then(|r| route_to_multiaddr(&r)),
}
}
}

/// Information to display of the inlets in the `ockam node show` command
#[derive(Debug, Serialize)]
pub struct ShowOutletStatus {
pub forward_address: SocketAddr,
pub address: Option<MultiAddr>,
}

impl From<OutletStatus> for ShowOutletStatus {
fn from(value: OutletStatus) -> Self {
Self {
forward_address: value.socket_addr,
address: addr_to_multiaddr(value.worker_addr),
}
}
}
175 changes: 175 additions & 0 deletions implementations/rust/ockam/ockam_command/src/node/models/show.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
use std::fmt::Display;

use colorful::Colorful;

use ockam_multiaddr::{
proto::{DnsAddr, Node, Tcp},
MultiAddr,
};
use serde::Serialize;

use ockam_api::{
addr_to_multiaddr,
nodes::models::{
secure_channel::SecureChannelListenersList,
services::ServiceList,
transport::TransportList,
},
};

use crate::output::Output;

use super::portal::{ShowInletStatus, ShowOutletStatus};

#[derive(Debug, Serialize)]
pub struct ShowNodeResponse<'a> {
pub is_default: bool,
pub name: &'a str,
pub is_up: bool,
pub route: RouteToNode,
#[serde(skip_serializing_if = "Option::is_none")]
pub identity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub tcp_listeners: Option<TransportList>,
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub secure_channel_listeners: Option<SecureChannelListenersList>,
pub inlets: Vec<ShowInletStatus>,
pub outlets: Vec<ShowOutletStatus>,
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub service_list: Option<ServiceList>,
}
#[derive(Debug, Serialize)]
pub struct RouteToNode {
#[serde(skip_serializing_if = "Option::is_none")]
pub short: Option<MultiAddr>,
#[serde(skip_serializing_if = "Option::is_none")]
pub verbose: Option<MultiAddr>,
}

impl<'a> ShowNodeResponse<'a> {
pub fn new(
is_default: bool,
name: &'a str,
is_up: bool,
node_port: Option<u16>,
) -> ShowNodeResponse {
let mut m = MultiAddr::default();
let short = m.push_back(Node::new(name)).ok().map(|_| m);

let verbose = node_port.and_then(|port| {
let mut m = MultiAddr::default();
if m.push_back(DnsAddr::new("localhost")).is_ok() && m.push_back(Tcp::new(port)).is_ok()
{
Some(m)
} else {
None
}
});

ShowNodeResponse {
is_default,
name,
is_up,
route: RouteToNode { short, verbose },
identity: None,
tcp_listeners: None,
secure_channel_listeners: None,
inlets: Default::default(),
outlets: Default::default(),
service_list: None,
}
}
}

impl<'a> Display for ShowNodeResponse<'a> {
fn fmt(&self, buffer: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(buffer, "Node:")?;

if self.is_default {
writeln!(buffer, " Name: {} (default)", self.name)?;
} else {
writeln!(buffer, " Name: {}", self.name)?;
}

writeln!(
buffer,
" Status: {}",
match self.is_up {
true => "UP".light_green(),
false => "DOWN".light_red(),
}
)?;

writeln!(buffer, " Route To Node:")?;
if let Some(short) = &self.route.short {
writeln!(buffer, " Short: {short}")?;
}
if let Some(verbose) = &self.route.verbose {
writeln!(buffer, " Verbose: {verbose}")?;
}

if let Some(identity) = &self.identity {
writeln!(buffer, " Identity: {}", identity)?;
}

if let Some(list) = &self.tcp_listeners {
writeln!(buffer, " Transports:")?;
for e in &list.list {
writeln!(buffer, " Transport:")?;
writeln!(buffer, " Type: {}", &e.tt)?;
writeln!(buffer, " Mode: {}", &e.tm)?;
writeln!(buffer, " Socket: {}", &e.socket_addr)?;
writeln!(buffer, " Worker: {}", &e.worker_addr)?;
writeln!(buffer, " FlowControlId: {}", &e.flow_control_id)?;
}
}

if let Some(list) = &self.secure_channel_listeners {
writeln!(buffer, " Secure Channel Listeners:")?;
for e in &list.list {
writeln!(buffer, " Listener:")?;
if let Some(ma) = addr_to_multiaddr(e.addr.clone()) {
writeln!(buffer, " Address: {ma}")?;
writeln!(buffer, " FlowControlId: {}", &e.flow_control_id)?;
}
}
}

writeln!(buffer, " Inlets:")?;
for e in &self.inlets {
writeln!(buffer, " Inlet:")?;
writeln!(buffer, " Listen Address: {}", e.listen_address)?;
if let Some(r) = &e.route_to_outlet {
writeln!(buffer, " Route To Outlet: {r}")?;
}
}

writeln!(buffer, " Outlets:")?;
for e in &self.outlets {
writeln!(buffer, " Outlet:")?;
writeln!(buffer, " Forward Address: {}", e.forward_address)?;
if let Some(ma) = &e.address {
writeln!(buffer, " Address: {ma}")?;
}
}

if let Some(list) = &self.service_list {
writeln!(buffer, " Services:")?;
for e in &list.list {
writeln!(buffer, " Service:")?;
writeln!(buffer, " Type: {}", e.service_type)?;
if let Some(ma) = addr_to_multiaddr(e.addr.as_str()) {
writeln!(buffer, " Address: {ma}")?;
}
}
}

Ok(())
}
}

impl<'a> Output for ShowNodeResponse<'a> {
fn output(&self) -> crate::error::Result<String> {
Ok(self.to_string())
}
}
Loading

0 comments on commit 515f18c

Please sign in to comment.