use std::{
convert::{TryFrom, TryInto},
io::{Read, Write},
};
use anyhow::Result;
use clap::{crate_authors, crate_version, Parser};
use dtn7_plus::news::{new_news, reply_news, NewsBundle};
#[derive(Parser)]
#[clap(version = crate_version!(), author = crate_authors!())]
struct Opts {
#[clap(short, long, parse(from_occurrences))]
verbose: i32,
#[clap(subcommand)]
subcmds: SubCommand,
}
#[derive(Parser)]
enum SubCommand {
Post(PostCmd),
Reply(ReplyCmd),
Read(ReadCmd),
}
#[derive(Parser)]
struct PostCmd {
#[clap(short, long)]
src_node_name: String,
#[clap(short, long)]
dst_group: String,
#[clap(short, long)]
topic: String,
#[clap(short, long)]
message: String,
#[clap(short = 'H', long)]
hex: bool,
}
fn cmd_post(opts: PostCmd, _log_level: i32) -> Result<()> {
let msg = if opts.message == "-" {
let mut raw_bytes: Vec<u8> = Vec::new();
std::io::stdin()
.read_to_end(&mut raw_bytes)
.expect("Error reading from stdin.");
String::from_utf8(raw_bytes)?
} else {
opts.message
};
let post = new_news(
&opts.src_node_name,
&opts.dst_group,
&opts.topic,
None,
None,
&msg,
Vec::new(),
true,
)?
.to_cbor();
if opts.hex {
println!("{}", bp7::helpers::hexify(&post));
} else {
std::io::stdout().write_all(&post).unwrap();
}
Ok(())
}
#[derive(Parser)]
struct ReplyCmd {
#[clap(short, long)]
src_node_name: String,
#[clap(short, long)]
message: String,
#[clap(short, long)]
input_newsbundle: String,
#[clap(short = 'H', long)]
hex: bool,
}
fn cmd_reply(opts: ReplyCmd, _log_level: i32) -> Result<()> {
let msg = if opts.message == "-" {
let mut raw_bytes: Vec<u8> = Vec::new();
std::io::stdin()
.read_to_end(&mut raw_bytes)
.expect("Error reading from stdin.");
String::from_utf8(raw_bytes)?
} else {
opts.message
};
let raw_bytes = bp7::helpers::unhexify(&opts.input_newsbundle)?;
let news_bundle: NewsBundle = raw_bytes.try_into()?;
let post = reply_news(&news_bundle, &opts.src_node_name, &msg, true)?.to_cbor();
if opts.hex {
println!("{}", bp7::helpers::hexify(&post));
} else {
std::io::stdout().write_all(&post).unwrap();
}
Ok(())
}
#[derive(Parser)]
struct ReadCmd {
#[clap(short = 'H', long)]
hex: Option<String>,
#[clap(short, long)]
path: Option<String>,
}
fn cmd_read(opts: ReadCmd, _log_level: i32) -> Result<()> {
let bytes = if let Some(hex_str) = opts.hex {
bp7::helpers::unhexify(&hex_str)?
} else {
let mut raw_bytes: Vec<u8> = Vec::new();
std::io::stdin()
.read_to_end(&mut raw_bytes)
.expect("Error reading from stdin.");
raw_bytes
};
let news = NewsBundle::try_from(bytes)?;
println!("{}", news);
Ok(())
}
fn main() -> Result<()> {
let opts: Opts = Opts::parse();
let log_level = opts.verbose;
match opts.subcmds {
SubCommand::Post(post) => {
cmd_post(post, log_level)?;
}
SubCommand::Read(read) => {
cmd_read(read, log_level)?;
}
SubCommand::Reply(reply) => {
cmd_reply(reply, log_level)?;
}
}
Ok(())
}