steer_core/app/
adapters.rs

1use crate::error::Result;
2use async_trait::async_trait;
3use std::sync::Arc;
4use tokio::sync::{Mutex, mpsc};
5
6use crate::app::AppEvent;
7use crate::app::command::AppCommand;
8use crate::app::io::{AppCommandSink, AppEventSource};
9
10/// Local adapter that implements AppCommandSink and AppEventSource for in-process communication
11pub struct LocalAdapter {
12    command_tx: mpsc::Sender<AppCommand>,
13    event_rx: Arc<Mutex<Option<mpsc::Receiver<AppEvent>>>>,
14}
15
16impl LocalAdapter {
17    pub fn new(command_tx: mpsc::Sender<AppCommand>, event_rx: mpsc::Receiver<AppEvent>) -> Self {
18        Self {
19            command_tx,
20            event_rx: Arc::new(Mutex::new(Some(event_rx))),
21        }
22    }
23}
24
25#[async_trait]
26impl AppCommandSink for LocalAdapter {
27    async fn send_command(&self, command: AppCommand) -> Result<()> {
28        self.command_tx.send(command).await.map_err(|e| {
29            crate::error::Error::InvalidOperation(format!("Failed to send command: {e}"))
30        })
31    }
32}
33
34#[async_trait]
35impl AppEventSource for LocalAdapter {
36    async fn subscribe(&self) -> mpsc::Receiver<AppEvent> {
37        // This is a blocking operation in a trait that doesn't support async
38        // We need to use block_on here
39        self.event_rx
40            .lock()
41            .await
42            .take()
43            .expect("Event receiver already taken - LocalAdapter only supports single subscription")
44    }
45}