extern crate alloc;
mod client;
mod wiring;
use alloc::{boxed::Box, vec::Vec};
use app_core::domain_primitives::Amount;
use core::num::{NonZeroU64, NonZeroUsize};
use pipecircuit_mio::worker::{ManagedWorker, WorkerJoined, WorkerStartFailure};
use std::{env, process::ExitCode, thread};
fn main() -> ExitCode {
let mut additions = Vec::new();
for argument in env::args_os().skip(1) {
match argument.to_str().map(str::parse::<NonZeroU64>) {
Some(Ok(amount)) => additions.push(Amount::new(amount)),
Some(Err(failure)) => {
eprintln!("Expected positive u64 additions: {failure}");
return ExitCode::FAILURE;
}
None => {
eprintln!("Expected a UTF-8 integer, received {argument:?}");
return ExitCode::FAILURE;
}
}
}
let wiring::Application {
mut pipecircuit,
peer,
peer_reactor,
} = match wiring::open(wiring::Configuration {
requests: NonZeroUsize::MIN,
replies: NonZeroUsize::MIN,
retained_replies: NonZeroUsize::MIN,
dispatch_quantum: NonZeroUsize::MIN,
}) {
Ok(application) => application,
Err(failure) => {
eprintln!("Installation refused: {failure}");
return ExitCode::FAILURE;
}
};
let wake = peer.clone_peer_wake();
let worker = match ManagedWorker::spawn_notifying(
thread::Builder::new().name("counter-client".into()),
Box::new(client::Client {
endpoint: peer,
reactor: peer_reactor,
additions,
}),
wake,
|client| client.run(),
) {
Ok(worker) => worker,
Err(failure) => {
match failure {
WorkerStartFailure::Spawn { worker, failure } => {
drop(worker);
eprintln!("Client thread could not start: {failure}");
}
WorkerStartFailure::Handoff { worker, outcome } => {
drop(worker);
let _reported = report_join(outcome);
eprintln!("Client state could not be handed to the thread");
}
}
return ExitCode::FAILURE;
}
};
let conducted = pipecircuit.conduct();
let (_, circuit) = pipecircuit.into_parts();
let (_host, installation) = circuit.into_parts();
let (pipes, _policy) = installation.into_parts();
let (endpoint, retained) = pipes.client.into_transport().into_parts();
let abandoned = retained.len();
let closed = endpoint.close();
let joined = report_join(worker.join());
match (conducted, closed, abandoned, joined) {
(Ok(wiring::Completion::ClientDisconnected), Ok(()), 0, true) => ExitCode::SUCCESS,
(conducted, closed, abandoned, _) => {
eprintln!("Circuit: {conducted:?}; close: {closed:?}; abandoned replies: {abandoned}");
ExitCode::FAILURE
}
}
}
fn report_join(
outcome: WorkerJoined<pipecircuit_mio::worker::NotifiedWorkerExit<client::Exit>>,
) -> bool {
match outcome {
WorkerJoined::Stopped(exit) => {
let notification = exit.notification;
match (exit.outcome, notification) {
(
Ok(client::Exit {
exchange: Ok(()),
close: Ok(()),
}),
Ok(()),
) => true,
(Ok(exit), notification) => {
eprintln!("Client: {exit:?}; completion notification: {notification:?}");
false
}
(Err(payload), notification) => {
eprintln!(
"Client unwound: {payload:?}; completion notification: {notification:?}"
);
false
}
}
}
WorkerJoined::NotStarted(failure) => {
eprintln!("Client did not receive its state: {failure}");
false
}
WorkerJoined::Panicked(payload) => {
eprintln!("Client supervision unwound: {payload:?}");
false
}
}
}