use tokio::sync::mpsc;
use super::write::{keep_offline, ready_offline, SafetyOptions, PASSIVE};
use super::EventSink;
use crate::tui::capture::CaptureEvent;
use crate::tui::message::{Command, OpOutcome, WorkerEvent};
use crate::tui::network::discovery::DiscoveryEvent;
use crate::tui::network::NetworkEvent;
use crate::tui::point::BrowseResult;
use crate::tui::safety::{Level, SafetyCommand, SafetyEvent};
use crate::tui::watched::{Source, WatchCommand, WatchEvent};
pub(crate) async fn serve(
sink: &EventSink,
mut commands: mpsc::Receiver<Command>,
options: &SafetyOptions,
) {
tracing::info!("passive: no network client; nothing is transmitted");
if !sink.deliver(WorkerEvent::Passive).await {
return;
}
ready_offline(sink, options).await;
loop {
tokio::select! {
biased;
() = sink.cancelled() => break,
command = commands.recv() => match command {
None | Some(Command::Disconnect) => break,
Some(Command::Safety(SafetyCommand::Keep)) => {
keep_offline(options, Level::Passive).await;
}
Some(command) => refuse(sink, command).await,
},
}
}
}
pub(crate) fn transmits(command: &Command) -> bool {
matches!(
command,
Command::WhoIs { .. }
| Command::Browse { .. }
| Command::Names { .. }
| Command::Watch(_)
| Command::Safety(_)
| Command::Network(_)
| Command::Discovery(_)
)
}
pub(crate) async fn refuse(sink: &EventSink, command: Command) {
let reason = PASSIVE.to_string();
let event = match command {
Command::WhoIs { op, .. } => WorkerEvent::OpFinished {
op,
outcome: OpOutcome::Failed(reason),
},
Command::Browse { req, .. } | Command::Names { req, .. } => WorkerEvent::Browse {
req,
result: BrowseResult::Failed(reason),
},
Command::Watch(WatchCommand::Add { row, .. }) => WorkerEvent::Watch(WatchEvent::Source {
row,
source: Source::Failed(reason),
}),
Command::Safety(
SafetyCommand::Prepare { req, .. }
| SafetyCommand::Execute { req, .. }
| SafetyCommand::Revert { req },
) => WorkerEvent::Safety(SafetyEvent::Refused {
req: Some(req),
reason,
}),
Command::Network(command) => {
WorkerEvent::Network(NetworkEvent::Refused { command, reason })
}
Command::Discovery(command) => {
WorkerEvent::Discovery(DiscoveryEvent::Refused { command, reason })
}
Command::Safety(SafetyCommand::Arm { .. }) => {
WorkerEvent::Safety(SafetyEvent::Refused { req: None, reason })
}
Command::Capture(_) => WorkerEvent::Capture(CaptureEvent::Ended {
what: crate::tui::capture::worker::TAP.into(),
why: "a passive session has no transport to tap".into(),
}),
_ => return,
};
sink.deliver(event).await;
}