wsprism_gateway/dispatch/
dispatcher.rs

1use std::sync::Arc;
2
3use async_trait::async_trait;
4use dashmap::DashMap;
5
6use wsprism_core::error::{Result, WsPrismError};
7use wsprism_core::protocol::hot::HotFrame;
8use wsprism_core::protocol::text::Envelope;
9
10use crate::realtime::RealtimeCtx;
11
12/// Text services (Ext Lane). Can be extended by WASM later.
13#[async_trait]
14pub trait TextService: Send + Sync {
15    fn svc(&self) -> &'static str;
16    async fn handle(&self, ctx: RealtimeCtx, env: Envelope) -> Result<()>;
17}
18
19/// Binary services (Hot Lane). **Native only** (no WASM/script).
20#[async_trait]
21pub trait BinaryService: Send + Sync {
22    fn svc_id(&self) -> u8;
23    async fn handle_binary(&self, ctx: RealtimeCtx, frame: HotFrame) -> Result<()>;
24}
25
26/// Registry and dispatcher for Text (Ext lane) and Binary (Hot lane) services.
27#[derive(Default)]
28pub struct Dispatcher {
29    text: DashMap<&'static str, Arc<dyn TextService>>,
30    hot: DashMap<u8, Arc<dyn BinaryService>>,
31}
32
33impl Dispatcher {
34    pub fn new() -> Self {
35        Self {
36            text: DashMap::new(),
37            hot: DashMap::new(),
38        }
39    }
40
41    pub fn register_text(&self, svc: Arc<dyn TextService>) {
42        self.text.insert(svc.svc(), svc);
43    }
44
45    pub fn register_hot(&self, svc: Arc<dyn BinaryService>) {
46        self.hot.insert(svc.svc_id(), svc);
47    }
48
49    pub fn registered_text_svcs(&self) -> Vec<&'static str> {
50        self.text.iter().map(|e| *e.key()).collect()
51    }
52
53    pub fn registered_hot_svcs(&self) -> Vec<u8> {
54        self.hot.iter().map(|e| *e.key()).collect()
55    }
56
57    pub async fn dispatch_text(&self, ctx: RealtimeCtx, env: Envelope) -> Result<()> {
58        let svc = env.svc.as_str();
59        let handler = self
60            .text
61            .get(svc)
62            .ok_or_else(|| WsPrismError::BadRequest(format!("unknown svc: {svc}")))?
63            .value()
64            .clone();
65        handler.handle(ctx, env).await
66    }
67
68    pub async fn dispatch_hot(&self, ctx: RealtimeCtx, frame: HotFrame) -> Result<()> {
69        let sid = frame.svc_id;
70        let handler = self
71            .hot
72            .get(&sid)
73            .ok_or_else(|| WsPrismError::BadRequest(format!("unknown hot svc_id: {sid}")))?
74            .value()
75            .clone();
76        handler.handle_binary(ctx, frame).await
77    }
78}