use std::path::PathBuf;
use bcur::ur::Decoder;
use bcur::{State, UrType};
use clap::Args;
use crate::error::{Error, Result};
use crate::io_util::{read_text, write_bytes};
#[derive(Debug, Args)]
pub(crate) struct DecodeArgs {
#[arg(long = "type")]
ur_type: Option<String>,
#[arg(long)]
hex: bool,
#[arg(short, long)]
out: Option<PathBuf>,
input: Option<PathBuf>,
}
pub(crate) fn run(args: &DecodeArgs) -> Result<()> {
let text = read_text(args.input.as_deref())?;
let lines: Vec<(usize, &str)> = text
.lines()
.enumerate()
.map(|(i, line)| (i + 1, line.trim()))
.filter(|(_, line)| !line.is_empty())
.collect();
if lines.is_empty() {
return Err(Error::msg("no UR lines in input"));
}
let mut decoder = Decoder::default();
if let Some(t) = args.ur_type.as_deref() {
decoder = decoder.accept([UrType::new(t)?]);
}
for (lineno, line) in lines {
match decoder.receive(line) {
Ok(_) => {
let progress = decoder.progress();
if progress.fragment_count() > 0 {
eprintln!(
"part {} rank={}/{} recovered={}",
lineno,
progress.rank(),
progress.fragment_count(),
progress.recovered(),
);
}
if matches!(decoder.state(), State::Complete(_)) {
let data = decoder.into_decoded()?.into_parts().1;
return write_bytes(args.out.as_deref(), &data, args.hex);
}
}
Err(error) if error.is_fatal() => return Err(error.into()),
Err(error) => eprintln!("bcur: skipped line {lineno}: {error}"),
}
}
Err(Error::msg(
"stream ended before the fountain message completed",
))
}