Skip to main content

sz_orm_websocket/
lib.rs

1//! # SZ-ORM WebSocket — 实时推送
2//!
3//! 提供 WebSocket 长连接管理、消息推送与认证支持,可选启用 `server` feature
4//! 启动独立 WebSocket 服务。
5//!
6//! ## 主要模块
7//!
8//! - [`handler`] — 连接处理与会话管理
9//! - [`pusher`] — 消息推送器
10//! - [`server`] — WebSocket 服务端(feature = "server")
11
12pub mod error;
13pub mod handler;
14pub mod pusher;
15
16pub use error::WsError;
17pub use handler::*;
18pub use pusher::*;
19
20#[cfg(feature = "server")]
21pub mod server;
22
23#[cfg(feature = "server")]
24pub use server::WsServer;
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29
30    #[test]
31    fn test_websocket_connection_new() {
32        let conn = WebSocketConnection::new("conn1");
33        assert_eq!(conn.id, "conn1");
34        assert!(!conn.is_authenticated);
35        assert!(conn.user_id.is_none());
36    }
37
38    #[test]
39    fn test_websocket_connection_with_user() {
40        let conn = WebSocketConnection::new("conn1").with_user(123);
41        assert_eq!(conn.user_id, Some(123));
42        assert!(conn.is_authenticated);
43    }
44
45    #[test]
46    fn test_websocket_connection_with_address() {
47        let conn = WebSocketConnection::new("conn1").with_address("127.0.0.1:8080");
48        assert_eq!(conn.remote_addr, Some("127.0.0.1:8080".to_string()));
49    }
50
51    #[test]
52    fn test_websocket_connection_subscribe() {
53        let mut conn = WebSocketConnection::new("conn1");
54        conn.subscribe("room1");
55        conn.subscribe("room2");
56        conn.subscribe("room1");
57
58        assert_eq!(conn.subscriptions.len(), 2);
59        assert!(conn.subscriptions.contains(&"room1".to_string()));
60        assert!(conn.subscriptions.contains(&"room2".to_string()));
61    }
62
63    #[test]
64    fn test_websocket_connection_unsubscribe() {
65        let mut conn = WebSocketConnection::new("conn1");
66        conn.subscribe("room1");
67        conn.subscribe("room2");
68        conn.unsubscribe("room1");
69
70        assert_eq!(conn.subscriptions.len(), 1);
71        assert!(!conn.subscriptions.contains(&"room1".to_string()));
72    }
73
74    #[test]
75    fn test_ws_message_builder_text() {
76        let msg = WsMessageBuilder::new().text("hello").build();
77
78        assert_eq!(msg.msg_type, MessageType::Text);
79        assert_eq!(msg.payload, b"hello");
80    }
81
82    #[test]
83    fn test_ws_message_builder_binary() {
84        let msg = WsMessageBuilder::new().binary(vec![1, 2, 3, 4]).build();
85
86        assert_eq!(msg.msg_type, MessageType::Binary);
87        assert_eq!(msg.payload, vec![1, 2, 3, 4]);
88    }
89
90    #[test]
91    fn test_ws_message_builder_json() {
92        let msg = WsMessageBuilder::new()
93            .json(&serde_json::json!({"key": "value"}))
94            .unwrap()
95            .build();
96
97        assert_eq!(msg.msg_type, MessageType::Text);
98        let parsed: serde_json::Value = serde_json::from_slice(&msg.payload).unwrap();
99        assert_eq!(parsed["key"], "value");
100    }
101
102    #[test]
103    fn test_ws_message_builder_with_sender() {
104        let msg = WsMessageBuilder::new()
105            .text("hello")
106            .with_sender(123)
107            .build();
108
109        assert_eq!(msg.sender_id, Some(123));
110    }
111
112    #[test]
113    fn test_ws_message_builder_with_room() {
114        let msg = WsMessageBuilder::new()
115            .text("hello")
116            .with_room("room1")
117            .build();
118
119        assert_eq!(msg.room_id, Some("room1".to_string()));
120    }
121
122    #[test]
123    fn test_ws_message_builder_notification() {
124        let msg = WsMessageBuilder::new()
125            .text("notice")
126            .notification()
127            .build();
128
129        assert_eq!(msg.msg_type, MessageType::Notification);
130    }
131
132    #[test]
133    fn test_ws_message_builder_system() {
134        let msg = WsMessageBuilder::new().text("system").system().build();
135
136        assert_eq!(msg.msg_type, MessageType::System);
137    }
138
139    #[test]
140    fn test_ws_context_new() {
141        let ctx = WsContext::new("conn1");
142        assert_eq!(ctx.connection_id, "conn1");
143        assert!(ctx.user_id.is_none());
144    }
145
146    #[test]
147    fn test_ws_context_with_user() {
148        let ctx = WsContext::new("conn1").with_user(123);
149        assert_eq!(ctx.user_id, Some(123));
150    }
151
152    #[test]
153    fn test_ws_context_with_metadata() {
154        let ctx = WsContext::new("conn1")
155            .with_metadata("key1", "value1")
156            .with_metadata("key2", "value2");
157
158        assert_eq!(ctx.metadata.get("key1"), Some(&"value1".to_string()));
159        assert_eq!(ctx.metadata.get("key2"), Some(&"value2".to_string()));
160    }
161
162    #[test]
163    fn test_push_result_new() {
164        let result = PushResult::new(10);
165        assert_eq!(result.total, 10);
166        assert_eq!(result.success, 0);
167        assert_eq!(result.failed, 0);
168    }
169
170    #[test]
171    fn test_push_result_add() {
172        let mut result = PushResult::new(10);
173        result.add_success();
174        result.add_success();
175        result.add_failure();
176
177        assert_eq!(result.success, 2);
178        assert_eq!(result.failed, 1);
179    }
180
181    #[test]
182    fn test_push_result_success_rate() {
183        let mut result = PushResult::new(10);
184        result.add_success();
185        result.add_success();
186        result.add_success();
187
188        assert_eq!(result.success_rate(), 30.0);
189    }
190
191    #[test]
192    fn test_push_result_zero_total() {
193        let result = PushResult::new(0);
194        assert_eq!(result.success_rate(), 0.0);
195    }
196
197    #[tokio::test]
198    async fn test_realtime_pusher_new() {
199        let pusher = RealtimePusher::new();
200        let count = pusher.connection_count().await;
201        assert_eq!(count, 0);
202    }
203
204    #[tokio::test]
205    async fn test_realtime_pusher_register_connection() {
206        let pusher = RealtimePusher::new();
207        pusher.register_connection("conn1").await;
208
209        let count = pusher.connection_count().await;
210        assert_eq!(count, 1);
211    }
212
213    #[tokio::test]
214    async fn test_realtime_pusher_unregister_connection() {
215        let pusher = RealtimePusher::new();
216        pusher.register_connection("conn1").await;
217        pusher.unregister_connection("conn1").await;
218
219        let count = pusher.connection_count().await;
220        assert_eq!(count, 0);
221    }
222
223    #[tokio::test]
224    async fn test_realtime_pusher_subscribe() {
225        let pusher = RealtimePusher::new();
226        pusher.register_connection("conn1").await;
227        pusher.subscribe("conn1", "room1").await.unwrap();
228
229        let count = pusher.room_count("room1").await;
230        assert_eq!(count, 1);
231    }
232
233    #[tokio::test]
234    async fn test_realtime_pusher_unsubscribe() {
235        let pusher = RealtimePusher::new();
236        pusher.register_connection("conn1").await;
237        pusher.subscribe("conn1", "room1").await.unwrap();
238        pusher.unsubscribe("conn1", "room1").await;
239
240        let count = pusher.room_count("room1").await;
241        assert_eq!(count, 0);
242    }
243
244    #[tokio::test]
245    async fn test_realtime_pusher_room_list() {
246        let pusher = RealtimePusher::new();
247        pusher.register_connection("conn1").await;
248        pusher.subscribe("conn1", "room1").await.unwrap();
249        pusher.subscribe("conn1", "room2").await.unwrap();
250
251        let rooms = pusher.room_list().await;
252        assert!(rooms.contains(&"room1".to_string()));
253        assert!(rooms.contains(&"room2".to_string()));
254    }
255
256    #[tokio::test]
257    async fn test_realtime_pusher_push_to_room() {
258        let pusher = RealtimePusher::new();
259        pusher.register_connection("conn1").await;
260        pusher.subscribe("conn1", "room1").await.unwrap();
261
262        let result = pusher.push_to_room("room1", vec![1, 2, 3]).await;
263        assert!(result.is_ok());
264    }
265
266    #[tokio::test]
267    async fn test_realtime_pusher_broadcast() {
268        let pusher = RealtimePusher::new();
269        pusher.register_connection("conn1").await;
270        pusher.register_connection("conn2").await;
271
272        let result = pusher.broadcast(vec![1, 2, 3]).await;
273        assert!(result.is_ok());
274        assert_eq!(result.unwrap(), 2);
275    }
276
277    #[tokio::test]
278    async fn test_realtime_pusher_push_order_status() {
279        let pusher = RealtimePusher::new();
280        pusher.register_connection("conn1").await;
281
282        let result = pusher.push_order_status(123, 456, "shipped").await;
283        assert!(result.is_ok());
284    }
285
286    #[tokio::test]
287    async fn test_realtime_pusher_push_customer_message() {
288        let pusher = RealtimePusher::new();
289        pusher.register_connection("conn1").await;
290        pusher.subscribe("conn1", "room1").await.unwrap();
291
292        let result = pusher.push_customer_message("room1", 123, "hello").await;
293        assert!(result.is_ok());
294    }
295}