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 build-trust#6142
  • Loading branch information
kriogenia committed Oct 4, 2023
1 parent 7053ea5 commit a4efd9e
Show file tree
Hide file tree
Showing 11 changed files with 310 additions and 195 deletions.
10 changes: 8 additions & 2 deletions implementations/rust/ockam/ockam_api/src/nodes/models/portal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,14 @@ impl InletStatus {
#[rustfmt::skip]
#[cbor(map)]
pub struct OutletStatus {
#[serde(rename = "forward_address")]
#[n(1)] pub socket_addr: SocketAddr,
#[serde(rename = "address", serialize_with = "crate::util::serialize_as_multiaddr")]
#[n(2)] pub worker_addr: Address,
#[serde(skip)]
#[n(3)] pub alias: String,
/// An optional status payload
#[serde(skip)]
#[n(4)] pub payload: Option<String>,
}

Expand Down Expand Up @@ -237,10 +241,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 +256,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 @@ -22,6 +22,7 @@ mod show;
mod start;
mod stop;
pub mod util;
pub mod models;
pub use create::*;

const LONG_ABOUT: &str = include_str!("./static/long_about.txt");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod portal;
pub mod show;
23 changes: 23 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,23 @@
use ockam_api::{
nodes::models::portal::{InletList, InletStatus},
route_to_multiaddr,
};
use ockam_core::Route;
use ockam_multiaddr::MultiAddr;
use serde::{Serialize, Serializer};

/// Response body when interacting with a portal endpoint
#[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)),
}
}
}
181 changes: 181 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,181 @@
use std::fmt::Display;

use colorful::Colorful;

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

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

use crate::output::Output;

use super::portal::ShowInletStatus;

#[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>,
#[serde(skip_serializing_if = "Option::is_none", flatten)]
pub outlets: Option<OutletList>,
#[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: None,
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}")?;
}
}

if let Some(outlets) = &self.outlets {
writeln!(buffer, " Outlets:")?;
for e in &outlets.list {
writeln!(buffer, " Outlet:")?;
writeln!(buffer, " Forward Address: {}", e.socket_addr)?;
if let Some(ma) = addr_to_multiaddr(e.worker_addr.to_string()) {
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 a4efd9e

Please sign in to comment.