use anyhow::Result;
use async_trait::async_trait;
#[async_trait]
pub trait WorkerHandle: Send + 'static {
fn id(&self) -> u32;
async fn ready(&mut self) -> Result<()>;
async fn execute(
&mut self,
method: &str,
payload: serde_json::Value,
) -> Result<serde_json::Value>;
async fn terminate(&mut self) -> Result<()>;
}
#[async_trait]
pub trait Runtime: Send + Sync + 'static {
async fn spawn(&self) -> Result<Box<dyn WorkerHandle>>;
}
type MockResponder =
std::sync::Arc<dyn Fn(&str, &serde_json::Value) -> Result<serde_json::Value> + Send + Sync>;
pub struct MockRuntime {
responder: MockResponder,
next_id: std::sync::atomic::AtomicU32,
}
impl MockRuntime {
pub fn echo() -> Self {
Self {
responder: std::sync::Arc::new(|_method, payload| Ok(payload.clone())),
next_id: std::sync::atomic::AtomicU32::new(10000),
}
}
}
#[async_trait]
impl Runtime for MockRuntime {
async fn spawn(&self) -> Result<Box<dyn WorkerHandle>> {
let id = self
.next_id
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Ok(Box::new(MockWorker {
id,
responder: self.responder.clone(),
terminated: false,
}))
}
}
pub struct MockWorker {
id: u32,
responder: MockResponder,
terminated: bool,
}
#[async_trait]
impl WorkerHandle for MockWorker {
fn id(&self) -> u32 {
self.id
}
async fn ready(&mut self) -> Result<()> {
Ok(())
}
async fn execute(
&mut self,
method: &str,
payload: serde_json::Value,
) -> Result<serde_json::Value> {
if self.terminated {
anyhow::bail!("worker terminated");
}
(self.responder)(method, &payload)
}
async fn terminate(&mut self) -> Result<()> {
self.terminated = true;
Ok(())
}
}