use crate::domain::ntp::ProbeResult;
use crate::stats::Stats;
use console::style;
pub fn render_probe(r: &ProbeResult, verbose: bool) -> String {
let ip_val = if r.target.ip.is_ipv6() {
format!("{}", style(format!("[{}]", r.target.ip)).green())
} else {
format!("{}", style(r.target.ip).green())
};
let mut out = format!(
"{srv_lbl} {srv_val}\n\
{ip_lbl} {ip_val}:{port}\n\
{utc_lbl} {utc_val}\n\
{loc_lbl} {loc_val}\n\
{off_lbl} {off_val:.3} ms\n\
{rtt_lbl} {rtt_val:.3} ms",
srv_lbl = style("Server:").cyan().bold(),
srv_val = style(&r.target.name).green(),
ip_lbl = style("IP:").cyan().bold(),
ip_val = ip_val,
port = style(r.target.port).green(),
utc_lbl = style("UTC Time:").cyan().bold(),
utc_val = style(r.utc.to_rfc2822()).green(),
loc_lbl = style("Local Time:").cyan().bold(),
loc_val = style(r.local.format("%Y-%m-%d %H:%M:%S")).green(),
off_lbl = style("Clock Offset:").cyan().bold(),
off_val = r.offset_ms,
rtt_lbl = style("Round Trip Delay:").cyan().bold(),
rtt_val = r.rtt_ms,
);
if verbose {
out.push_str(&format!(
"\n{str_lbl} {str_val}\n{ref_lbl} {ref_val}\n{str_ts}: {timestamp}",
str_lbl = style("Stratum:").cyan().bold(),
str_val = r.stratum,
ref_lbl = style("Reference ID:").cyan().bold(),
ref_val = r.ref_id,
str_ts = style("Timestamp").cyan().bold(),
timestamp = r.timestamp
));
}
out
}
pub fn render_compare(results: &[ProbeResult], verbose: bool) -> String {
let mut out = String::new();
if results.len() == 2 {
out.push_str(&format!(
"{}:{} {}:{} and {}\n",
style("Comparing").bold(),
style(&results[0].target.name).green(),
style(&results[0].target.port).green(),
style(&results[1].target.name).green(),
style(&results[1].target.port).green()
));
} else {
out.push_str(&format!(
"{} {} servers\n",
style("Comparing (async):").bold(),
results.len()
));
}
for r in results {
let ip_style = if r.target.ip.is_ipv6() {
style(r.target.ip).cyan()
} else {
style(r.target.ip).blue()
};
let ip_version = if r.target.ip.is_ipv6() { "v6" } else { "v4" };
let offset_style = style(format!("{:.3} ms", r.offset_ms)).yellow();
out.push_str(&format!(
"{} [{} {}]: {}\n",
style(&r.target.name).green().bold(),
ip_style,
ip_version,
offset_style
));
if verbose {
out.push_str(&format!(
" {} {}\n {} {}\n {} {:.3} ms\n",
style("Stratum:").cyan().bold(),
r.stratum,
style("Reference ID:").cyan().bold(),
r.ref_id,
style("Round Trip Delay:").cyan().bold(),
r.rtt_ms
));
}
}
let min = results
.iter()
.map(|r| r.offset_ms)
.fold(f64::INFINITY, f64::min);
let max = results
.iter()
.map(|r| r.offset_ms)
.fold(f64::NEG_INFINITY, f64::max);
let avg = results.iter().map(|r| r.offset_ms).sum::<f64>() / results.len() as f64;
let diff = max - min;
out.push_str(&format!(
"{} {:.3} ms (min: {:.3}, max: {:.3}, avg: {:.3})\n",
style("Max drift:").cyan().bold(),
diff,
min,
max,
avg
));
out
}
pub fn render_short_probe(r: &ProbeResult) -> String {
format!(
"{name}:{port} {offset}",
name = style(&r.target.name).green(),
port = r.target.port,
offset = style(format!("{:.3} ms", r.offset_ms)).yellow()
)
}
pub fn render_short_compare(results: &[ProbeResult]) -> String {
results
.iter()
.map(|r| {
format!(
"{name}:{port}:{off}",
name = style(&r.target.name).green(),
port = r.target.port,
off = style(format!("{:.3}", r.offset_ms)).yellow()
)
})
.collect::<Vec<_>>()
.join(" ")
}
pub fn render_stats(name: &str, stats: &Stats) -> String {
fn fmt_ms(v: f64) -> String {
format!("{:.3} ms", v)
}
format!(
"\n{n}: {avg_lbl} {avg} ({min_lbl} {min}, {max_lbl} {max}) {rtt_lbl} {rtt} ({cnt} {rqst})",
n = style(name).green().bold(),
avg_lbl = style("avg").cyan().bold(),
avg = style(fmt_ms(stats.offset_avg)).green(),
min_lbl = style("min").cyan().bold(),
min = style(fmt_ms(stats.offset_min)).green(),
max_lbl = style("max").cyan().bold(),
max = style(fmt_ms(stats.offset_max)).green(),
rtt_lbl = style("rtt").cyan().bold(),
rtt = style(fmt_ms(stats.rtt_avg)).green(),
cnt = style(stats.count).green(),
rqst = style("requests").green(),
)
}
pub fn render_simple_probe(r: &ProbeResult) -> String {
format!(
"{name}:{port} {offset}",
name = style(&r.target.name).green(),
port = style(&r.target.port).green(),
offset = style(format!("{:.3} ms", r.offset_ms)).yellow()
)
}
pub fn render_simple_compare(results: &[ProbeResult]) -> String {
results
.iter()
.map(render_simple_probe)
.collect::<Vec<_>>()
.join("\n")
}