feat(cli): implement main execution loop and network I/O logic
This commit is contained in:
1 parent
510f307acc
commit
c65ba48e10
1 file changed
+117
-1
+117
-1
@@ -1 +1,117 @@
|
|||||||
fn main() {}
|
use std::{
|
||||||
|
io::{self, Write},
|
||||||
|
process::ExitCode,
|
||||||
|
thread,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use irtt_cli::{format_event, CliArgs};
|
||||||
|
use irtt_client::{Client, ClientEvent, ClientTimestamp, OpenOutcome, RecvBudget};
|
||||||
|
|
||||||
|
const RECV_BUDGET: RecvBudget = RecvBudget { max_packets: 16 };
|
||||||
|
const FINAL_DRAIN: Duration = Duration::from_millis(100);
|
||||||
|
const MAX_SLEEP: Duration = Duration::from_millis(20);
|
||||||
|
|
||||||
|
fn main() -> ExitCode {
|
||||||
|
let args = CliArgs::parse();
|
||||||
|
match run(args) {
|
||||||
|
Ok(()) => ExitCode::SUCCESS,
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("irtt-rs: {err}");
|
||||||
|
ExitCode::FAILURE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(args: CliArgs) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let mode = args.output;
|
||||||
|
let mut stdout = io::BufWriter::new(io::stdout().lock());
|
||||||
|
let mut client = Client::connect(args.to_client_config())?;
|
||||||
|
|
||||||
|
let open = client.open(ClientTimestamp::now())?;
|
||||||
|
print_event(open_event(&open), mode, &mut stdout)?;
|
||||||
|
|
||||||
|
while let Some(deadline) = client.next_send_deadline() {
|
||||||
|
let now = Instant::now();
|
||||||
|
if deadline <= now {
|
||||||
|
let events = client.send_probe()?;
|
||||||
|
print_events(&events, mode, &mut stdout)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let events = client.recv_available(RECV_BUDGET)?;
|
||||||
|
print_events(&events, mode, &mut stdout)?;
|
||||||
|
|
||||||
|
let events = client.poll_timeouts(ClientTimestamp::now())?;
|
||||||
|
print_events(&events, mode, &mut stdout)?;
|
||||||
|
|
||||||
|
sleep_until_next_send(client.next_send_deadline());
|
||||||
|
}
|
||||||
|
|
||||||
|
drain_final_replies(&mut client, mode, &mut stdout)?;
|
||||||
|
|
||||||
|
let events = client.poll_timeouts(ClientTimestamp::now())?;
|
||||||
|
print_events(&events, mode, &mut stdout)?;
|
||||||
|
|
||||||
|
let events = client.close(ClientTimestamp::now())?;
|
||||||
|
print_events(&events, mode, &mut stdout)?;
|
||||||
|
stdout.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_event(outcome: &OpenOutcome) -> &ClientEvent {
|
||||||
|
match outcome {
|
||||||
|
OpenOutcome::Started { event, .. } | OpenOutcome::NoTestCompleted { event, .. } => event,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn drain_final_replies<W: Write>(
|
||||||
|
client: &mut Client,
|
||||||
|
mode: irtt_cli::OutputMode,
|
||||||
|
out: &mut W,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let deadline = Instant::now() + FINAL_DRAIN;
|
||||||
|
while Instant::now() < deadline {
|
||||||
|
let events = client.recv_available(RECV_BUDGET)?;
|
||||||
|
if events.is_empty() {
|
||||||
|
thread::sleep(Duration::from_millis(5));
|
||||||
|
} else {
|
||||||
|
print_events(&events, mode, out)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sleep_until_next_send(deadline: Option<Instant>) {
|
||||||
|
let sleep_for = match deadline {
|
||||||
|
Some(deadline) => deadline
|
||||||
|
.saturating_duration_since(Instant::now())
|
||||||
|
.min(MAX_SLEEP),
|
||||||
|
None => Duration::from_millis(1),
|
||||||
|
};
|
||||||
|
if !sleep_for.is_zero() {
|
||||||
|
thread::sleep(sleep_for);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_events<W: Write>(
|
||||||
|
events: &[ClientEvent],
|
||||||
|
mode: irtt_cli::OutputMode,
|
||||||
|
out: &mut W,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
for event in events {
|
||||||
|
print_event(event, mode, out)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_event<W: Write>(
|
||||||
|
event: &ClientEvent,
|
||||||
|
mode: irtt_cli::OutputMode,
|
||||||
|
out: &mut W,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if let Some(line) = format_event(event, mode) {
|
||||||
|
writeln!(out, "{line}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
Reference in new issue
Block a user