Skip to main content

dingtalk_stream/
handlers.rs

1//! Handlers module for DingTalk Stream SDK
2//!
3//! Provides trait-based handlers for different message types
4
5use crate::frames::down_message::callback_message::CallbackMessage;
6use crate::frames::down_message::event_message::EventMessage;
7use crate::frames::down_message::system_message::SystemMessage;
8use crate::frames::down_message::MessageTopic;
9use crate::frames::up_message::callback_message::WebhookMessage;
10use crate::DingTalkStream;
11use async_trait::async_trait;
12use std::fmt::{Display, Formatter};
13use std::sync::Arc;
14use tokio::sync::mpsc::Sender;
15use tokio_tungstenite::tungstenite::Message;
16
17/// Callback handler trait for handling callback messages
18#[async_trait]
19pub trait CallbackHandler: Send + Sync {
20    /// Process a callback message
21    async fn process(
22        &self,
23        client: Arc<DingTalkStream>,
24        message: &CallbackMessage,
25        cb_webhook_msg_sender: Option<Sender<WebhookMessage>>,
26    ) -> Result<Resp, Error>;
27
28    /// Pre-start hook
29    fn pre_start(&self) {}
30
31    /// Get the topic this handler handles
32    fn topic(&self) -> &MessageTopic;
33}
34
35/// Event handler trait for handling event messages
36#[async_trait]
37pub trait EventHandler: Send + Sync {
38    /// Process an event message
39    async fn process(
40        &self,
41        client: Arc<DingTalkStream>,
42        message: &EventMessage,
43    ) -> Result<Resp, Error>;
44
45    /// Pre-start hook
46    fn pre_start(&self) {}
47}
48
49/// System handler trait for handling system messages
50#[async_trait]
51pub trait SystemHandler: Send + Sync {
52    /// Process a system message
53    async fn process(
54        &self,
55        client: Arc<DingTalkStream>,
56        message: &SystemMessage,
57    ) -> Result<Resp, Error>;
58
59    /// Pre-start hook
60    fn pre_start(&self) {}
61}
62
63#[derive(Debug, Clone)]
64pub enum Resp {
65    Text(String),
66    Json(serde_json::Value),
67}
68
69impl Display for Resp {
70    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
71        match self {
72            Resp::Text(text) => write!(f, "Text: {}", text),
73            Resp::Json(json) => write!(f, "JSON: {}", json),
74        }
75    }
76}
77
78#[derive(Debug, Clone)]
79pub struct Error {
80    pub msg: String,
81    pub code: ErrorCode,
82}
83
84impl Display for Error {
85    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86        f.write_str(&format!("Error: {} (Code: {})", self.msg, self.code))
87    }
88}
89
90impl std::error::Error for Error {}
91
92#[derive(Debug, Clone, Copy)]
93#[repr(i32)]
94pub enum ErrorCode {
95    BadRequest = 400i32,
96    Unauthorized = 401,
97    Forbidden = 403,
98    NotFound = 404,
99    MethodNotAllowed = 405,
100    TooManyRequests = 429,
101    InternalServerError = 500,
102    BadGateway = 502,
103    ServiceUnavailable = 503,
104    GatewayTimeout = 504,
105}
106
107impl Display for ErrorCode {
108    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
109        f.write_str(&format!("{}", *self as i32))
110    }
111}
112
113/// Default no-op callback handler
114pub struct DefaultCallbackHandler {
115    pub topic: MessageTopic,
116}
117
118impl DefaultCallbackHandler {
119    pub fn new(topic: &str) -> Self {
120        Self {
121            topic: MessageTopic::Callback(topic.to_string()),
122        }
123    }
124}
125
126#[derive(Debug, Copy, Clone)]
127pub enum LifecycleEvent<'a> {
128    Start,
129    Connecting {
130        websocket_url: &'a str,
131    },
132    Connected {
133        websocket_url: &'a str,
134    },
135    WebsocketWrite {
136        payload: &'a str,
137        result: &'a crate::Result<()>,
138    },
139    WebsocketWriteWithRetry {
140        payload: &'a str,
141        cnt: u8,
142        result: &'a crate::Result<()>,
143    },
144    WebsocketRead {
145        result: &'a crate::Result<Message>,
146    },
147    Keepalive {
148        payload: &'a str,
149        result: &'a crate::Result<()>,
150    },
151    Disconnected {
152        result: &'a crate::Result<()>,
153    },
154    Stopped,
155}
156#[allow(unused)]
157#[async_trait]
158pub trait LifecycleListener: Send + Sync {
159    async fn on_event<'a>(&self, client: Arc<DingTalkStream>, event: LifecycleEvent<'a>) {}
160
161    async fn on_start(&self, client: Arc<DingTalkStream>) {
162        let _ = self.on_event(client, LifecycleEvent::Start).await;
163    }
164
165    async fn on_connecting(&self, client: Arc<DingTalkStream>, websocket_url: &str) {
166        let _ = self
167            .on_event(client, LifecycleEvent::Connecting { websocket_url })
168            .await;
169    }
170
171    async fn on_connected(&self, client: Arc<DingTalkStream>, websocket_url: &str) {
172        let _ = self
173            .on_event(client, LifecycleEvent::Connected { websocket_url })
174            .await;
175    }
176
177    async fn on_websocket_write(
178        &self,
179        client: Arc<DingTalkStream>,
180        payload: &str,
181        result: &crate::Result<()>,
182    ) {
183        let _ = self
184            .on_event(client, LifecycleEvent::WebsocketWrite { payload, result })
185            .await;
186    }
187
188    async fn on_websocket_write_with_retry(
189        &self,
190        client: Arc<DingTalkStream>,
191        payload: &str,
192        cnt: u8,
193        result: &crate::Result<()>,
194    ) {
195        let _ = self
196            .on_event(
197                client,
198                LifecycleEvent::WebsocketWriteWithRetry {
199                    payload,
200                    cnt,
201                    result,
202                },
203            )
204            .await;
205    }
206
207    async fn on_websocket_read(
208        &self,
209        client: Arc<DingTalkStream>,
210        result: &crate::Result<Message>,
211    ) {
212        let _ = self
213            .on_event(client, LifecycleEvent::WebsocketRead { result })
214            .await;
215    }
216
217    async fn on_keepalive(
218        &self,
219        client: Arc<DingTalkStream>,
220        payload: &str,
221        result: &crate::Result<()>,
222    ) {
223        let _ = self
224            .on_event(client, LifecycleEvent::Keepalive { payload, result })
225            .await;
226    }
227
228    async fn on_disconnected(&self, client: Arc<DingTalkStream>, result: &crate::Result<()>) {
229        let _ = self
230            .on_event(client, LifecycleEvent::Disconnected { result })
231            .await;
232    }
233
234    async fn on_stopped(&self, client: Arc<DingTalkStream>) {
235        let _ = self.on_event(client, LifecycleEvent::Stopped).await;
236    }
237}
238
239#[derive(Debug, Clone, Copy, Default)]
240pub(crate) struct DefaultLifecycleListener;
241
242impl LifecycleListener for DefaultLifecycleListener {}