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 5, 2023
1 parent 7053ea5 commit 63a3b94
Show file tree
Hide file tree
Showing 8 changed files with 372 additions and 191 deletions.
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;
mod models;
mod show;
mod start;
mod stop;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pub mod portal;
pub mod secure_channel;
pub mod services;
pub mod show;
pub mod transport;
44 changes: 44 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,44 @@
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,
#[serde(skip_serializing_if = "Option::is_none")]
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,
#[serde(skip_serializing_if = "Option::is_none")]
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),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use ockam_api::{
addr_to_multiaddr, nodes::models::secure_channel::ShowSecureChannelListenerResponse,
};
use ockam_core::flow_control::FlowControlId;
use ockam_multiaddr::MultiAddr;
use serde::Serialize;

/// Information to display of the secure channel listeners in the `ockam node show` command
#[derive(Debug, Serialize)]
pub struct ShowSecureChannelListener {
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<MultiAddr>,
pub flow_control: FlowControlId,
}

impl From<ShowSecureChannelListenerResponse> for ShowSecureChannelListener {
fn from(value: ShowSecureChannelListenerResponse) -> Self {
Self {
address: addr_to_multiaddr(value.addr),
flow_control: value.flow_control_id,
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use ockam_api::{addr_to_multiaddr, nodes::models::services::ServiceStatus};
use ockam_multiaddr::MultiAddr;
use serde::Serialize;

/// Information to display of the services in the `ockam node show` command
#[derive(Debug, Serialize)]
pub struct ShowServiceStatus {
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<MultiAddr>,
#[serde(rename = "type")]
pub service_type: String,
}

impl From<ServiceStatus> for ShowServiceStatus {
fn from(value: ServiceStatus) -> Self {
Self {
address: addr_to_multiaddr(value.addr),
service_type: value.service_type,
}
}
}
163 changes: 163 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,163 @@
use std::fmt::Display;

use colorful::Colorful;

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

use crate::output::Output;

use super::{
portal::{ShowInletStatus, ShowOutletStatus},
secure_channel::ShowSecureChannelListener,
services::ShowServiceStatus,
transport::ShowTransportStatus,
};

/// Information to display in the `ockam node show` command
#[derive(Debug, Serialize)]
pub struct ShowNodeResponse {
pub is_default: bool,
pub name: String,
pub is_up: bool,
pub route: RouteToNode,
#[serde(skip_serializing_if = "Option::is_none")]
pub identity: Option<String>,
pub transports: Vec<ShowTransportStatus>,
pub secure_channel_listeners: Vec<ShowSecureChannelListener>,
pub inlets: Vec<ShowInletStatus>,
pub outlets: Vec<ShowOutletStatus>,
pub services: Vec<ShowServiceStatus>,
}
#[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 ShowNodeResponse {
pub fn new(
is_default: bool,
name: &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: name.to_owned(),
is_up,
route: RouteToNode { short, verbose },
identity: None,
transports: Default::default(),
secure_channel_listeners: Default::default(),
inlets: Default::default(),
outlets: Default::default(),
services: Default::default(),
}
}
}

impl Display for ShowNodeResponse {
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)?;
}

writeln!(buffer, " Transports:")?;
for e in &self.transports {
writeln!(buffer, " Transport:")?;
writeln!(buffer, " Type: {}", &e.tt)?;
writeln!(buffer, " Mode: {}", &e.mode)?;
writeln!(buffer, " Socket: {}", &e.socket)?;
writeln!(buffer, " Worker: {}", &e.worker)?;
writeln!(buffer, " FlowControlId: {}", &e.flow_control)?;
}

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

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}")?;
}
}

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

Ok(())
}
}

impl Output for ShowNodeResponse {
fn output(&self) -> crate::error::Result<String> {
Ok(self.to_string())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use ockam_api::nodes::models::transport::{TransportMode, TransportStatus, TransportType};
use ockam_core::flow_control::FlowControlId;
use serde::Serialize;

/// Information to display of the transports in the `ockam node show` command
#[derive(Debug, Serialize)]
pub struct ShowTransportStatus {
#[serde(rename = "type")]
pub tt: TransportType,
pub mode: TransportMode,
pub socket: String,
pub worker: String,
pub flow_control: FlowControlId,
}

impl From<TransportStatus> for ShowTransportStatus {
fn from(value: TransportStatus) -> Self {
Self {
tt: value.tt,
mode: value.tm,
socket: value.socket_addr,
worker: value.worker_addr,
flow_control: value.flow_control_id,
}
}
}
Loading

0 comments on commit 63a3b94

Please sign in to comment.