use std::time::Duration;
use tokio::sync::broadcast;
use wcode_harness::actor::SessionHandle;
use wcode_harness::event::AgentEvent;
use wcode_harness::protocol::{Request, SessionId};
#[cfg(unix)]
use crate::client::Client;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Closed;
impl std::fmt::Display for Closed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("session is closed")
}
}
impl std::error::Error for Closed {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AskError {
Closed,
Timeout,
}
impl std::fmt::Display for AskError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
AskError::Closed => "session is closed",
AskError::Timeout => "the ask timed out",
})
}
}
impl std::error::Error for AskError {}
#[derive(Clone)]
pub enum Backend {
Local(SessionHandle),
#[cfg(unix)]
Remote(Client),
}
impl Backend {
pub fn send(&self, request: Request) -> Result<(), Closed> {
match self {
Backend::Local(handle) => handle.send(request).map_err(|_| Closed),
#[cfg(unix)]
Backend::Remote(client) => client.send(request),
}
}
pub fn send_from(&self, from: SessionId, request: Request) -> Result<(), Closed> {
match self {
Backend::Local(handle) => handle.send_from(from, request).map_err(|_| Closed),
#[cfg(unix)]
Backend::Remote(client) => client.send_from(from, request),
}
}
pub async fn ask_within(
&self,
request: Request,
dur: Duration,
) -> Result<AgentEvent, AskError> {
match self {
Backend::Local(handle) => tokio::time::timeout(dur, handle.ask(request))
.await
.map_err(|_| AskError::Timeout)?
.map_err(|_| AskError::Closed),
#[cfg(unix)]
Backend::Remote(client) => client.ask_within(request, dur).await,
}
}
pub async fn ask(&self, request: Request) -> Result<AgentEvent, Closed> {
match self {
Backend::Local(handle) => handle.ask(request).await.map_err(|_| Closed),
#[cfg(unix)]
Backend::Remote(client) => client.ask(request).await,
}
}
pub fn subscribe(&self) -> broadcast::Receiver<AgentEvent> {
match self {
Backend::Local(handle) => handle.subscribe(),
#[cfg(unix)]
Backend::Remote(client) => client.subscribe(),
}
}
}
impl From<SessionHandle> for Backend {
fn from(handle: SessionHandle) -> Self {
Backend::Local(handle)
}
}
#[cfg(unix)]
impl From<Client> for Backend {
fn from(client: Client) -> Self {
Backend::Remote(client)
}
}