use std::time::Duration;
use vantage_faker::{LiveFolderConfig, LiveFolderSim};
fn human_bytes(n: u64) -> String {
if n < 1024 {
format!("{n:>5} B ")
} else if n < 1024 * 1024 {
format!("{:5.1} KB", n as f64 / 1024.0)
} else if n < 1024 * 1024 * 1024 {
format!("{:5.1} MB", n as f64 / 1024.0 / 1024.0)
} else {
format!("{:5.1} GB", n as f64 / 1024.0 / 1024.0 / 1024.0)
}
}
fn render(entries: &[(String, vantage_faker::live_folder::Entry)]) {
use vantage_faker::live_folder::EntryKind;
let mut by_parent: std::collections::BTreeMap<
String,
Vec<(String, vantage_faker::live_folder::Entry)>,
> = std::collections::BTreeMap::new();
for (path, entry) in entries {
let parent = match path.rsplit_once('/') {
Some((p, _)) => p.to_string(),
None => String::new(),
};
by_parent
.entry(parent)
.or_default()
.push((path.clone(), entry.clone()));
}
fn walk(
prefix: &str,
path: &str,
by_parent: &std::collections::BTreeMap<
String,
Vec<(String, vantage_faker::live_folder::Entry)>,
>,
) {
let Some(children) = by_parent.get(path) else {
return;
};
let last_idx = children.len().saturating_sub(1);
for (i, (child_path, entry)) in children.iter().enumerate() {
let is_last = i == last_idx;
let branch = if is_last { "└── " } else { "├── " };
let cont = if is_last { " " } else { "│ " };
let modified = entry.modified;
let m_full = vantage_faker::live_folder::format_ts(modified);
let m_str = m_full.split(' ').nth(1).unwrap_or("");
let c_full = vantage_faker::live_folder::format_ts(entry.created);
let c_str = c_full.split(' ').nth(1).unwrap_or("");
match entry.kind {
EntryKind::File => {
println!(
"{prefix}{branch}{:<28} {:<10} mod {m_str} created {c_str}",
entry.name,
human_bytes(entry.size)
);
}
EntryKind::Folder => {
println!("{prefix}{branch}{}/ mod {m_str}", entry.name);
let new_prefix = format!("{prefix}{cont}");
walk(&new_prefix, child_path, by_parent);
}
}
}
}
println!(
"\nvantage-faker · live folder tree (5 GB chunks, 0.1% error rate, 2h backfill) · mod = modified UTC · Ctrl-C to quit\n"
);
walk("", "", &by_parent);
}
#[tokio::main]
async fn main() {
let cfg = LiveFolderConfig {
backfill: Duration::from_secs(2 * 3600),
chunk_threshold: 5 * 1024 * 1024 * 1024, error_pct_per_sec: 0.1, ..LiveFolderConfig::default()
};
let sim = LiveFolderSim::new(cfg);
loop {
print!("\x1B[2J\x1B[H");
let snap = sim.snapshot();
render(&snap);
tokio::time::sleep(Duration::from_secs(1)).await;
}
}