90 lines
2.8 KiB
Rust
90 lines
2.8 KiB
Rust
use blockchain::env;
|
|
use blockchain::fs;
|
|
use blockchain::tilde;
|
|
use rustyline::completion::FilenameCompleter;
|
|
use rustyline::error::ReadlineError;
|
|
use rustyline::{history::DefaultHistory, CompletionType, Config, Editor};
|
|
use rustyline_derive::Completer;
|
|
use rustyline_derive::Helper as RustyHelper;
|
|
use rustyline_derive::Highlighter as RustyHighlighter;
|
|
use rustyline_derive::Hinter as RustyHinter;
|
|
use rustyline_derive::Validator as RustyValidator;
|
|
|
|
fn format_balance(balance: u64) -> String {
|
|
// Balance files store atomic units; display as whole coins with 8 decimals.
|
|
let whole = balance / 100_000_000;
|
|
let fractional = balance % 100_000_000;
|
|
format!("{whole}.{fractional:08}")
|
|
}
|
|
|
|
#[derive(RustyHelper, Completer, RustyHinter, RustyHighlighter, RustyValidator)]
|
|
struct PathHelper {
|
|
#[rustyline(Completer)]
|
|
completer: FilenameCompleter,
|
|
}
|
|
|
|
fn prompt_for_path(prompt: &str) -> Result<String, String> {
|
|
// Rustyline provides path completion for interactive balance-file lookup.
|
|
let config = Config::builder()
|
|
.completion_type(CompletionType::List)
|
|
.build();
|
|
let mut editor =
|
|
Editor::<PathHelper, DefaultHistory>::with_config(config).map_err(|e| e.to_string())?;
|
|
editor.set_helper(Some(PathHelper {
|
|
completer: FilenameCompleter::new(),
|
|
}));
|
|
|
|
match editor.readline(prompt) {
|
|
Ok(line) => Ok(line.trim().to_string()),
|
|
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
|
|
Err("Input cancelled".to_string())
|
|
}
|
|
Err(err) => Err(format!("Failed to read balance file path: {err}")),
|
|
}
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
// The tool accepts a balance file path as an arg or prompts with completion.
|
|
let args: Vec<String> = env::args().collect();
|
|
|
|
if args.len() > 1 && args.len() != 2 {
|
|
eprintln!("Usage: ./lookup_local_balance <path/to/file.bal>");
|
|
return;
|
|
}
|
|
|
|
let balance_file_path = if args.len() == 2 {
|
|
args[1].clone()
|
|
} else {
|
|
match prompt_for_path("Please enter the path to the balance file: ") {
|
|
Ok(path) => path,
|
|
Err(err) => {
|
|
eprintln!("{err}");
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Allow users to type paths with ~ and read the balance bytes from disk.
|
|
let expanded_path = tilde(&balance_file_path).to_string();
|
|
let bytes = match fs::read(&expanded_path) {
|
|
Ok(bytes) => bytes,
|
|
Err(err) => {
|
|
eprintln!("Error reading file: {err}");
|
|
return;
|
|
}
|
|
};
|
|
|
|
if bytes.len() < 8 {
|
|
eprintln!("Error: File should have at least 8 bytes of data");
|
|
return;
|
|
}
|
|
|
|
// The first 8 bytes are the little-endian u64 balance value.
|
|
let mut buffer = [0u8; 8];
|
|
buffer.copy_from_slice(&bytes[..8]);
|
|
let value = u64::from_le_bytes(buffer);
|
|
|
|
println!("{}", format_balance(value));
|
|
}
|