Skip to main content

cookie_agent_server/service/
mod.rs

1mod routes;
2mod runtime_notifications;
3mod subscriptions;
4mod websocket;
5
6use std::{io, net::SocketAddr, sync::Arc};
7
8use cookie_agent_engine::Engine;
9use cookie_agent_protocol::{MessageStream, TransportError};
10use thiserror::Error;
11use tokio::task::JoinHandle;
12use tokio_util::sync::CancellationToken;
13
14/// Protocol service composed with one coherent engine runtime.
15#[derive(Clone)]
16pub struct Server {
17    pub(crate) engine: Engine,
18    pub(crate) shutdown: CancellationToken,
19}
20
21impl Server {
22    #[must_use]
23    pub fn new(engine: Engine) -> Self {
24        Self {
25            engine,
26            shutdown: CancellationToken::new(),
27        }
28    }
29
30    pub fn shutdown(&self) {
31        self.shutdown.cancel();
32    }
33
34    pub async fn serve_stream<S>(self: Arc<Self>, stream: S) -> Result<(), TransportError>
35    where
36        S: MessageStream,
37    {
38        let connection_shutdown = self.shutdown.child_token();
39        cookie_agent_protocol::serve(self, stream, connection_shutdown).await
40    }
41}
42
43pub struct RunningServer {
44    pub(super) address: SocketAddr,
45    pub(super) task: JoinHandle<()>,
46}
47
48impl RunningServer {
49    #[must_use]
50    pub const fn address(&self) -> SocketAddr {
51        self.address
52    }
53
54    pub async fn wait(self) {
55        let _ = self.task.await;
56    }
57}
58
59#[derive(Debug, Error)]
60pub enum ServerError {
61    #[error("could not bind localhost websocket listener: {0}")]
62    Listen(#[source] io::Error),
63}