use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::ops::ControlFlow;
use std::time::Duration;
use clap::Args;
use crate::input::InputArgs;
use crate::json;
use crate::print::print_event;
use crate::si::{self, Event, Si};
#[derive(Clone, Debug, Args)]
pub struct Options {
#[command(flatten)]
input: InputArgs,
#[arg(long, value_parser = crate::print::parse_id)]
service: Option<u16>,
#[arg(long, default_value_t = 30)]
timeout: u64,
#[arg(long)]
json: bool,
}
pub fn run(options: &Options, verbose: bool) -> anyhow::Result<()> {
let mut events = BTreeMap::<u16, BTreeMap<u16, Event>>::new();
si::read(
options.input.open()?,
Duration::from_secs(options.timeout),
|si| {
if let Si::Events(found) = si
&& options
.service
.is_none_or(|service_id| service_id == found.service_id)
{
let service = events.entry(found.service_id).or_default();
for event in found.events {
let changed = match service.entry(event.id) {
Entry::Occupied(known) => {
let known = known.into_mut();
known.merge(event).then_some(known)
}
Entry::Vacant(entry) => Some(entry.insert(event)),
};
if options.json
&& let Some(event) = changed
{
let mut value = json::event(event);
value["service_id"] = found.service_id.into();
println!("{value}");
}
}
}
ControlFlow::Continue(())
},
)?;
if options.json {
return Ok(());
}
for (service_id, events) in events {
println!("Service: {service_id:#06X}");
let mut events: Vec<_> = events.into_values().collect();
events.sort_by_key(|event| event.start_time);
for event in &events {
print_event(event, 2, verbose);
}
}
Ok(())
}