ic_query/cloud_engine/
text.rs1use super::{CloudEngineOperatorReport, CloudEnginePricesReport, CloudEngineReportContext};
8use crate::{
9 human_quantity::decimal_cycle_count_text,
10 table::{ColumnAlign, render_table},
11 text_value::{optional_text, sanitize_text, yes_no},
12};
13
14#[must_use]
16pub fn cloud_engine_operator_report_text(report: &CloudEngineOperatorReport) -> String {
17 let mut lines = context_lines(&report.context);
18 lines.extend([
19 format!("subnet_id: {}", report.subnet_id),
20 format!(
21 "operator_binding_present: {}",
22 yes_no(report.operator_binding_present)
23 ),
24 format!(
25 "operator_canister_id: {}",
26 optional_text(report.operator_canister_id.as_ref())
27 ),
28 format!(
29 "engine_owner: {}",
30 optional_text(report.engine_owner.as_ref())
31 ),
32 format!(
33 "platform_admin: {}",
34 optional_text(report.platform_admin.as_ref())
35 ),
36 format!(
37 "caffeine_enabled: {}",
38 report
39 .caffeine_enabled
40 .map_or_else(|| "-".to_string(), |enabled| yes_no(enabled).to_string())
41 ),
42 format!(
43 "claimed_domain_count: {}",
44 report
45 .claimed_domain_count
46 .map_or_else(|| "-".to_string(), |count| count.to_string())
47 ),
48 ]);
49
50 if let Some(domains) = report.claimed_domains.as_ref()
51 && !domains.is_empty()
52 {
53 lines.push(String::new());
54 lines.push("Claimed domains".to_string());
55 lines.extend(
56 domains
57 .iter()
58 .map(|domain| format!(" {}", sanitize_text(domain))),
59 );
60 }
61 lines.join("\n")
62}
63
64#[must_use]
66pub fn cloud_engine_prices_report_text(report: &CloudEnginePricesReport) -> String {
67 let mut lines = context_lines(&report.context);
68 lines.extend([
69 format!("network_fee: {}", report.network_fee),
70 format!("price_count: {}", report.price_count),
71 ]);
72
73 if !report.prices.is_empty() {
74 let headers = [
75 "Key",
76 "Node type",
77 "Data center",
78 "Provider",
79 "Net/month",
80 "Gross/month",
81 "Updated (ns)",
82 ];
83 let alignments = [
84 ColumnAlign::Left,
85 ColumnAlign::Left,
86 ColumnAlign::Left,
87 ColumnAlign::Left,
88 ColumnAlign::Right,
89 ColumnAlign::Right,
90 ColumnAlign::Right,
91 ];
92 let rows = report
93 .prices
94 .iter()
95 .map(|row| {
96 [
97 row.key.clone(),
98 row.node_type.to_string(),
99 row.data_center_id
100 .as_deref()
101 .map_or_else(|| "-".to_string(), sanitize_text),
102 row.provider_id.clone().unwrap_or_else(|| "-".to_string()),
103 decimal_cycle_count_text(&row.net_cycles_per_month),
104 decimal_cycle_count_text(&row.gross_cycles_per_month),
105 row.updated_at_unix_nanos.to_string(),
106 ]
107 })
108 .collect::<Vec<_>>();
109 lines.push(String::new());
110 lines.push("Marketplace prices".to_string());
111 lines.push(render_table(&headers, &rows, &alignments));
112 }
113 lines.join("\n")
114}
115
116fn context_lines(context: &CloudEngineReportContext) -> Vec<String> {
117 vec![
118 format!("network: {}", sanitize_text(&context.network)),
119 format!("authority: {}", sanitize_text(&context.authority)),
120 format!("engine_canister_id: {}", context.engine_canister_id),
121 format!("fetched_at: {}", sanitize_text(&context.fetched_at)),
122 format!(
123 "source_endpoint: {}",
124 sanitize_text(&context.source_endpoint)
125 ),
126 format!("fetched_by: {}", sanitize_text(&context.fetched_by)),
127 format!("certified: {}", yes_no(context.certified)),
128 format!(
129 "point_in_time_guaranteed: {}",
130 yes_no(context.point_in_time_guaranteed)
131 ),
132 format!("query_call_count: {}", context.query_call_count),
133 ]
134}