synor/apps/cli/src/output.rs
Gulshan Yadav 48949ebb3f Initial commit: Synor blockchain monorepo
A complete blockchain implementation featuring:
- synord: Full node with GHOSTDAG consensus
- explorer-web: Modern React blockchain explorer with 3D DAG visualization
- CLI wallet and tools
- Smart contract SDK and example contracts (DEX, NFT, token)
- WASM crypto library for browser/mobile
2026-01-08 05:22:17 +05:30

178 lines
4.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Output formatting.
use console::style;
use serde::Serialize;
use tabled::{builder::Builder, settings::Style as TableStyle};
/// Output format.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OutputFormat {
Text,
Json,
}
impl OutputFormat {
pub fn from_str(s: &str) -> Self {
match s.to_lowercase().as_str() {
"json" => OutputFormat::Json,
_ => OutputFormat::Text,
}
}
}
/// Prints a value in the specified format.
pub fn print_value<T: Serialize + std::fmt::Debug>(value: &T, format: OutputFormat) {
match format {
OutputFormat::Json => {
println!("{}", serde_json::to_string_pretty(value).unwrap());
}
OutputFormat::Text => {
println!("{:#?}", value);
}
}
}
/// Prints a success message.
pub fn print_success(message: &str) {
println!("{} {}", style("").green().bold(), message);
}
/// Prints an error message.
pub fn print_error(message: &str) {
eprintln!("{} {}", style("").red().bold(), message);
}
/// Prints a warning message.
pub fn print_warning(message: &str) {
println!("{} {}", style("").yellow().bold(), message);
}
/// Prints info message.
pub fn print_info(message: &str) {
println!("{} {}", style("").blue().bold(), message);
}
/// Prints a key-value pair.
pub fn print_kv(key: &str, value: &str) {
println!("{}: {}", style(key).bold(), value);
}
/// Prints a header.
pub fn print_header(title: &str) {
println!();
println!("{}", style(title).bold().underlined());
println!();
}
/// Prints a table.
pub fn print_table(headers: Vec<&str>, rows: Vec<Vec<String>>) {
let mut builder = Builder::default();
builder.push_record(headers);
for row in rows {
builder.push_record(row);
}
let mut table = builder.build();
let styled = table.with(TableStyle::rounded());
println!("{}", styled);
}
/// Formats SYNOR amount.
pub fn format_synor(sompi: u64) -> String {
let synor = sompi as f64 / 100_000_000.0;
format!("{:.8} SYNOR", synor)
}
/// Formats a hash for display.
pub fn format_hash(hash: &str) -> String {
if hash.len() > 16 {
format!("{}...{}", &hash[..8], &hash[hash.len() - 8..])
} else {
hash.to_string()
}
}
/// Formats a timestamp.
pub fn format_timestamp(ts: u64) -> String {
use chrono::{DateTime, Utc};
let dt = DateTime::<Utc>::from_timestamp_millis(ts as i64)
.unwrap_or_else(|| DateTime::<Utc>::from_timestamp(0, 0).unwrap());
dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
}
/// Formats duration.
pub fn format_duration(seconds: u64) -> String {
if seconds < 60 {
format!("{}s", seconds)
} else if seconds < 3600 {
format!("{}m {}s", seconds / 60, seconds % 60)
} else if seconds < 86400 {
format!("{}h {}m", seconds / 3600, (seconds % 3600) / 60)
} else {
format!("{}d {}h", seconds / 86400, (seconds % 86400) / 3600)
}
}
/// Formats hashrate.
pub fn format_hashrate(hps: f64) -> String {
const K: f64 = 1000.0;
const M: f64 = K * 1000.0;
const G: f64 = M * 1000.0;
const T: f64 = G * 1000.0;
if hps >= T {
format!("{:.2} TH/s", hps / T)
} else if hps >= G {
format!("{:.2} GH/s", hps / G)
} else if hps >= M {
format!("{:.2} MH/s", hps / M)
} else if hps >= K {
format!("{:.2} KH/s", hps / K)
} else {
format!("{:.2} H/s", hps)
}
}
/// Formats bytes size.
pub fn format_size(bytes: u64) -> String {
const KB: u64 = 1024;
const MB: u64 = KB * 1024;
const GB: u64 = MB * 1024;
if bytes >= GB {
format!("{:.2} GB", bytes as f64 / GB as f64)
} else if bytes >= MB {
format!("{:.2} MB", bytes as f64 / MB as f64)
} else if bytes >= KB {
format!("{:.2} KB", bytes as f64 / KB as f64)
} else {
format!("{} B", bytes)
}
}
/// Progress bar for long operations.
pub fn create_progress_bar(len: u64, message: &str) -> indicatif::ProgressBar {
let pb = indicatif::ProgressBar::new(len);
pb.set_style(
indicatif::ProgressStyle::default_bar()
.template("{msg} [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
.unwrap()
.progress_chars("=>-"),
);
pb.set_message(message.to_string());
pb
}
/// Spinner for indeterminate operations.
pub fn create_spinner(message: &str) -> indicatif::ProgressBar {
let sp = indicatif::ProgressBar::new_spinner();
sp.set_style(
indicatif::ProgressStyle::default_spinner()
.template("{spinner:.green} {msg}")
.unwrap(),
);
sp.set_message(message.to_string());
sp
}