1use crate::{
5 cli::show::{self, ApplyStyle},
6 runner::WorkflowReceiptInfo,
7 workflow::{self, IndexedResources},
8};
9use chrono::NaiveDateTime;
10use faststr::FastStr;
11use libipld::Cid;
12use serde::{Deserialize, Serialize};
13use std::{fmt, net::SocketAddr, sync::Arc};
14use tabled::{
15 builder::Builder,
16 col,
17 settings::{object::Rows, Format, Modify},
18 Table, Tabled,
19};
20
21use super::{DynamicNodeInfo, StaticNodeInfo};
22
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Tabled)]
26pub struct AckWorkflow {
27 pub(crate) cid: Cid,
28 pub(crate) name: FastStr,
29 pub(crate) num_tasks: u32,
30 pub(crate) progress_count: u32,
31 #[tabled(skip)]
32 pub(crate) resources: IndexedResources,
33 #[tabled(skip)]
34 pub(crate) replayed_receipt_info: Vec<WorkflowReceiptInfo>,
35 pub(crate) timestamp: String,
36}
37
38impl fmt::Display for AckWorkflow {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(
41 f,
42 "cid: {}, progress: {}/{}, timestamp: {}",
43 self.cid, self.progress_count, self.num_tasks, self.timestamp
44 )
45 }
46}
47
48impl AckWorkflow {
49 pub(crate) fn new(
51 workflow_info: Arc<workflow::Info>,
52 replayed_receipt_info: Vec<WorkflowReceiptInfo>,
53 name: FastStr,
54 timestamp: NaiveDateTime,
55 ) -> Self {
56 Self {
57 cid: workflow_info.cid,
58 name,
59 num_tasks: workflow_info.num_tasks,
60 progress_count: workflow_info.progress_count,
61 resources: workflow_info.resources.clone(),
62 replayed_receipt_info,
63 timestamp: timestamp.format("%Y-%m-%d %H:%M:%S").to_string(),
64 }
65 }
66}
67
68impl show::ConsoleTable for AckWorkflow {
69 fn table(&self) -> show::Output {
70 show::Output::new(Table::new(vec![self]).to_string())
71 }
72
73 fn echo_table(&self) -> Result<(), std::io::Error> {
74 let table = self.table();
75
76 let mut resource_table = Table::new(
77 self.resources
78 .iter()
79 .map(|v| v.to_string())
80 .collect::<Vec<String>>(),
81 );
82
83 resource_table
84 .with(Modify::new(Rows::first()).with(Format::content(|_s| "Resources".to_string())));
85
86 let mut receipt_table_builder = Builder::default();
87 receipt_table_builder.push_record([
88 "Replayed Receipt".to_string(),
89 "Invocation Ran".to_string(),
90 "Instruction".to_string(),
91 ]);
92
93 for (cid, info) in &self.replayed_receipt_info {
94 if let Some((ran, instruction)) = info {
95 receipt_table_builder.push_record([
96 cid.to_string(),
97 ran.to_string(),
98 instruction.to_string(),
99 ]);
100 }
101 }
102
103 if receipt_table_builder.count_records() == 1 {
105 receipt_table_builder.push_record([
106 "<none>".to_string(),
107 "".to_string(),
108 "".to_string(),
109 ]);
110 };
111
112 let receipt_table = receipt_table_builder.build();
113
114 let tbl = col![table, resource_table, receipt_table].default_with_title("run");
115
116 tbl.echo()
117 }
118}
119
120#[derive(Debug, Tabled)]
122pub(crate) struct Ping {
123 address: SocketAddr,
124 response: String,
125}
126
127impl Ping {
128 pub(crate) fn new(address: SocketAddr, response: String) -> Self {
130 Self { address, response }
131 }
132}
133
134impl show::ConsoleTable for Ping {
135 fn table(&self) -> show::Output {
136 Table::new(vec![&self]).default_with_title("ping/pong")
137 }
138
139 fn echo_table(&self) -> Result<(), std::io::Error> {
140 self.table().echo()
141 }
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize, Tabled)]
146pub struct AckNodeInfo {
147 static_info: StaticNodeInfo,
149 dyn_info: DynamicNodeInfo,
151}
152
153impl fmt::Display for AckNodeInfo {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 write!(f, "")
156 }
157}
158
159impl AckNodeInfo {
160 pub(crate) fn new(static_info: StaticNodeInfo, dyn_info: DynamicNodeInfo) -> Self {
162 Self {
163 static_info,
164 dyn_info,
165 }
166 }
167}
168
169impl show::ConsoleTable for AckNodeInfo {
170 fn table(&self) -> show::Output {
171 show::Output::new(Table::new(vec![self]).to_string())
172 }
173
174 fn echo_table(&self) -> Result<(), std::io::Error> {
175 let static_info_table = Table::new(vec![&self.static_info]);
176
177 let mut listeners_table = Table::new(
178 self.dyn_info
179 .listeners
180 .iter()
181 .map(|v| v.to_string())
182 .collect::<Vec<String>>(),
183 );
184
185 let conns = self
186 .dyn_info
187 .connections
188 .iter()
189 .map(|(k, v)| vec![k.to_string(), v.to_string()])
190 .collect::<Vec<Vec<String>>>();
191
192 let mut conns_table_builder = tabled::builder::Builder::from_iter(conns);
193
194 if conns_table_builder.count_records() == 0 {
196 conns_table_builder.push_record([
197 "Connections".to_string(),
198 "".to_string(),
199 "".to_string(),
200 ]);
201 conns_table_builder.push_record(["<none>".to_string(), "".to_string(), "".to_string()]);
202 } else {
203 conns_table_builder.insert_record(
204 0,
205 ["Connections".to_string(), "".to_string(), "".to_string()],
206 );
207 }
208
209 listeners_table.with(
210 Modify::new(Rows::first()).with(Format::content(|_s| "Listen Addresses".to_string())),
211 );
212 let conns_table = conns_table_builder.build();
213
214 let tbl = col![static_info_table, listeners_table, conns_table].default_with_title("node");
215
216 tbl.echo()
217 }
218}
219
220#[derive(Debug, Tabled)]
222pub struct Info {
223 version: String,
224 git_sha: String,
225 timestamp: String,
226 features: String,
227}
228
229impl Default for Info {
230 fn default() -> Self {
231 Self::new()
232 }
233}
234
235impl Info {
236 pub(crate) fn new() -> Self {
238 Self {
239 version: env!("CARGO_PKG_VERSION").to_string(),
240 git_sha: option_env!("VERGEN_GIT_SHA")
241 .unwrap_or("unknown")
242 .to_string(),
243 timestamp: option_env!("VERGEN_GIT_COMMIT_TIMESTAMP")
244 .unwrap_or("unknown")
245 .to_string(),
246 features: env!("VERGEN_CARGO_FEATURES").to_string(),
247 }
248 }
249}
250
251impl show::ConsoleTable for Info {
252 fn table(&self) -> show::Output {
253 Table::new(vec![&self]).default_with_title("info")
254 }
255
256 fn echo_table(&self) -> Result<(), std::io::Error> {
257 self.table().echo()
258 }
259}