1use std::net::SocketAddr;
2use std::sync::Arc;
3use tokio::net::{TcpListener, TcpStream};
4use tokio_tungstenite::{accept_async, tungstenite::Message};
5use futures_util::{StreamExt, SinkExt};
6use dashmap::DashMap;
7use uuid::Uuid;
8use serde::{Deserialize, Serialize};
9use tokio::sync::mpsc;
10use tokio::sync::Mutex;
11use crate::{Result, TransmissionError, YrsManager, ClientInfo, SyncService};
12use anyhow;
13use yrs::updates::decoder::Decode;
14use moduforge_core::runtime::ForgeRuntime;
15use yrs::Transact;
16use yrs::ReadTxn;
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub enum WsMessage {
20 JoinRoom { room_id: String },
22 LeaveRoom { room_id: String },
24 YrsUpdate { room_id: String, update: Vec<u8> },
26 YrsSyncRequest { room_id: String, state_vector: Vec<u8> },
28 StateSync {
30 room_id: String,
31 operation: String,
32 data: serde_json::Value,
33 timestamp: u64
34 },
35 Ping,
37 Pong,
39 Error { message: String },
41 Notification { message: String },
43}
44
45#[derive(Debug, Clone)]
47pub enum BroadcastMessage {
48 ToRoom { room_id: String, message: Arc<String>, exclude_client: Option<String> },
50 ToRoomBinary { room_id: String, data: Arc<Vec<u8>>, exclude_client: Option<String> },
52 ToClient { client_id: String, message: Arc<String> },
54 ToClientBinary { client_id: String, data: Arc<Vec<u8>> },
56}
57
58#[derive(Debug, Clone)]
61pub enum OutgoingMessage {
62 Text(Arc<String>),
63 Binary(Arc<Vec<u8>>),
64 }
66
67impl From<OutgoingMessage> for Message {
68 fn from(msg: OutgoingMessage) -> Self {
69 match msg {
70 OutgoingMessage::Text(text) => Message::Text((*text).clone()),
71 OutgoingMessage::Binary(data) => Message::Binary((*data).clone()),
72 }
73 }
74}
75
76#[derive(Debug, Clone)]
78pub struct ClientConnection {
79 pub info: ClientInfo,
80 pub sender: mpsc::UnboundedSender<OutgoingMessage>,
81}
82
83pub struct WebSocketServer {
84 yrs_manager: Arc<YrsManager>,
85 clients: Arc<DashMap<String, ClientConnection>>,
87 room_clients: Arc<DashMap<String, Vec<String>>>,
89 broadcast_tx: mpsc::UnboundedSender<BroadcastMessage>,
91 broadcast_rx: Arc<tokio::sync::Mutex<mpsc::UnboundedReceiver<BroadcastMessage>>>,
92}
93
94impl WebSocketServer {
95 pub fn new(yrs_manager: Arc<YrsManager>) -> Self {
96 let (broadcast_tx, broadcast_rx) = mpsc::unbounded_channel();
97
98 Self {
99 yrs_manager,
100 clients: Arc::new(DashMap::new()),
101 room_clients: Arc::new(DashMap::new()),
102 broadcast_tx,
103 broadcast_rx: Arc::new(tokio::sync::Mutex::new(broadcast_rx)),
104 }
105 }
106
107 pub async fn start(
109 self: Arc<Self>,
110 addr: SocketAddr,
111 sync_service: Arc<SyncService>,
112 runtime: Arc<Mutex<ForgeRuntime>>
113 ) -> Result<()> {
114 let listener = TcpListener::bind(addr).await?;
115 tracing::info!("WebSocket 服务器启动在: {}", addr);
116
117 self.clone().start_broadcast_handler().await;
119
120 while let Ok((stream, addr)) = listener.accept().await {
121 let server = self.clone();
122 let sync_service = sync_service.clone();
123 let runtime = runtime.clone();
124
125 tokio::spawn(async move {
126 if let Err(e) = server.handle_connection(
127 stream,
128 addr,
129 sync_service,
130 runtime,
131 ).await {
132 tracing::error!("处理连接失败: {}", e);
133 }
134 });
135 }
136
137 Ok(())
138 }
139
140 async fn start_broadcast_handler(self: Arc<Self>) {
142 let clients = self.clients.clone();
143 let room_clients = self.room_clients.clone();
144 let broadcast_rx = self.broadcast_rx.clone();
145
146 tokio::spawn(async move {
147 let mut rx = broadcast_rx.lock().await;
148
149 while let Some(broadcast_msg) = rx.recv().await {
150 Self::handle_broadcast_message(broadcast_msg, &clients, &room_clients).await;
151 }
152 });
153 }
154
155 async fn handle_broadcast_message(
157 message: BroadcastMessage,
158 clients: &DashMap<String, ClientConnection>,
159 room_clients: &DashMap<String, Vec<String>>,
160 ) {
161 match message {
162 BroadcastMessage::ToRoom { room_id, message, exclude_client } => {
163 let outgoing_msg = OutgoingMessage::Text(message);
164 if let Some(client_list) = room_clients.get(&room_id) {
165 for client_id in client_list.iter() {
166 if let Some(ref exclude) = exclude_client {
167 if client_id == exclude {
168 continue;
169 }
170 }
171
172 if let Some(client) = clients.get(client_id) {
173 let _ = client.sender.send(outgoing_msg.clone());
174 }
175 }
176 }
177 }
178 BroadcastMessage::ToRoomBinary { room_id, data, exclude_client } => {
179 let outgoing_msg = OutgoingMessage::Binary(data);
180 if let Some(client_list) = room_clients.get(&room_id) {
181 for client_id in client_list.iter() {
182 if let Some(ref exclude) = exclude_client {
183 if client_id == exclude {
184 continue;
185 }
186 }
187
188 if let Some(client) = clients.get(client_id) {
189 let _ = client.sender.send(outgoing_msg.clone());
190 }
191 }
192 }
193 }
194 BroadcastMessage::ToClient { client_id, message } => {
195 if let Some(client) = clients.get(&client_id) {
196 let _ = client.sender.send(OutgoingMessage::Text(message));
197 }
198 }
199 BroadcastMessage::ToClientBinary { client_id, data } => {
200 if let Some(client) = clients.get(&client_id) {
201 let _ = client.sender.send(OutgoingMessage::Binary(data));
202 }
203 }
204 }
205 }
206
207 async fn handle_connection(
208 self: Arc<Self>,
209 stream: TcpStream,
210 addr: SocketAddr,
211 sync_service: Arc<SyncService>,
212 runtime: Arc<Mutex<ForgeRuntime>>,
213 ) -> Result<()> {
214 let ws_stream = accept_async(stream).await
215 .map_err(|e| TransmissionError::WebSocketError(e.to_string()))?;
216
217 let client_id = Uuid::new_v4().to_string();
218 tracing::info!("新客户端连接: {} ({})", client_id, addr);
219
220 let (mut ws_sender, mut ws_receiver) = ws_stream.split();
221 let (msg_tx, mut msg_rx) = mpsc::unbounded_channel::<OutgoingMessage>();
222
223 let client_info = ClientInfo {
225 id: client_id.clone(),
226 room_id: String::new(),
227 connected_at: std::time::SystemTime::now(),
228 };
229
230 let client_connection = ClientConnection {
231 info: client_info,
232 sender: msg_tx,
233 };
234
235 self.clients.insert(client_id.clone(), client_connection);
236
237 let client_id_clone = client_id.clone();
238
239 let send_task = tokio::spawn(async move {
241 while let Some(message) = msg_rx.recv().await {
242 if ws_sender.send(message.into()).await.is_err() {
243 break;
244 }
245 }
246 });
247
248 while let Some(msg) = ws_receiver.next().await {
250 match msg {
251 Ok(Message::Text(text)) => {
252 if let Ok(ws_msg) = serde_json::from_str::<WsMessage>(&text) {
253 if let Err(e) = self.handle_message(
254 &client_id,
255 ws_msg,
256 &sync_service,
257 &runtime,
258 ).await {
259 tracing::error!("处理消息失败: {}" , e);
260 let error_msg = WsMessage::Error {
261 message: e.to_string()
262 };
263 if let Ok(json) = serde_json::to_string(&error_msg) {
264 let _ = self.broadcast_tx.send(BroadcastMessage::ToClient {
265 client_id: client_id.clone(),
266 message: Arc::new(json),
267 });
268 }
269 }
270 }
271 }
272 Ok(Message::Binary(_data)) => {
273 tracing::warn!("收到未包装的二进制消息,已忽略");
275 }
276 Ok(Message::Close(_)) => {
277 break;
278 }
279 Err(_) => {
280 break;
281 }
282 _ => {}
283 }
284 }
285
286 send_task.abort();
288 self.cleanup_client(&client_id_clone).await;
289
290 Ok(())
291 }
292
293 async fn handle_message(
294 &self,
295 client_id: &str,
296 message: WsMessage,
297 sync_service: &Arc<SyncService>,
298 runtime: &Arc<Mutex<ForgeRuntime>>,
299 ) -> Result<()> {
300 match message {
301 WsMessage::JoinRoom { room_id } => {
302 if let Some(mut client) = self.clients.get_mut(client_id) {
303 client.info.room_id = room_id.clone();
304 }
305 self.room_clients.entry(room_id.clone()).or_default().push(client_id.to_string());
306 let _doc = self.yrs_manager.get_or_create_doc(&room_id);
307 tracing::info!("客户端 {} 加入房间 {}", client_id, room_id);
308 Ok(())
309 }
310 WsMessage::LeaveRoom { room_id } => {
311 if let Some(mut client_list) = self.room_clients.get_mut(&room_id) {
312 client_list.retain(|id| id != client_id);
313 }
314 if let Some(mut client) = self.clients.get_mut(client_id) {
315 client.info.room_id = String::new();
316 }
317 tracing::info!("客户端 {} 离开房间 {}", client_id, room_id);
318 Ok(())
319 }
320 WsMessage::YrsUpdate { room_id, update } => {
321 let doc = self.yrs_manager.get_doc(&room_id).ok_or_else(|| TransmissionError::RoomNotFound(room_id.clone()))?;
322 if let Err(e) = apply_update_to_doc(&doc, &update) {
323 tracing::error!("应用更新失败: {}", e);
324 } else {
325 self.broadcast_tx.send(BroadcastMessage::ToRoomBinary {
326 room_id,
327 data: Arc::new(update),
328 exclude_client: Some(client_id.to_string()),
329 }).map_err(|e| TransmissionError::Other(anyhow::anyhow!(e.to_string())))?;
330 }
331 Ok(())
332 }
333 WsMessage::YrsSyncRequest { room_id, state_vector } => {
334 tracing::debug!("收到来自 {} 的同步请求,房间: {}", client_id, room_id);
335
336 let tree = runtime.lock().await.doc().get_inner().clone();
337 let diff_update = sync_service.handle_sync_request(&room_id, &tree, &state_vector).await?;
338
339 if !diff_update.is_empty() {
340 self.broadcast_tx.send(BroadcastMessage::ToClientBinary {
341 client_id: client_id.to_string(),
342 data: Arc::new(diff_update),
343 }).map_err(|e| TransmissionError::Other(anyhow::anyhow!(e.to_string())))?;
344 }
345
346 Ok(())
347 }
348 WsMessage::Ping => {
349 let pong = WsMessage::Pong;
350 let json = serde_json::to_string(&pong)?;
351 self.broadcast_tx.send(BroadcastMessage::ToClient {
352 client_id: client_id.to_string(),
353 message: Arc::new(json),
354 }).map_err(|e| TransmissionError::Other(anyhow::anyhow!(e.to_string())))?;
355 Ok(())
356 }
357 _ => Ok(()),
358 }
359 }
360
361 async fn cleanup_client(
362 &self,
363 client_id: &str,
364 ) {
365 if let Some((_, client)) = self.clients.remove(client_id) {
366 tracing::info!("客户端断开连接: {}", client_id);
367 let room_id = client.info.room_id;
368
369 if !room_id.is_empty() {
370 let should_remove_doc = if let Some(mut room) = self.room_clients.get_mut(&room_id) {
371 room.retain(|id| id != client_id);
372 room.is_empty()
373 } else {
374 false
375 };
376
377 if should_remove_doc {
378 if self.room_clients.remove(&room_id).is_some() {
379 self.yrs_manager.remove_doc(&room_id);
380 tracing::info!("房间 {} 已空,移除Yrs Doc", room_id);
381 }
382 }
383 }
384 }
385 }
386
387 pub fn client_count(&self) -> usize {
389 self.clients.len()
390 }
391
392 pub fn room_count(&self) -> usize {
394 self.room_clients.len()
395 }
396
397 pub fn broadcast_to_room(&self, room_id: &str, message: String, exclude_client: Option<String>) -> Result<()> {
399 self.broadcast_tx.send(BroadcastMessage::ToRoom {
400 room_id: room_id.to_string(),
401 message: Arc::new(message),
402 exclude_client
403 }).map_err(|e| TransmissionError::Other(anyhow::anyhow!(e.to_string())))
404 }
405
406 pub fn broadcast_binary_to_room(&self, room_id: &str, data: Vec<u8>, exclude_client: Option<String>) -> Result<()> {
408 self.broadcast_tx.send(BroadcastMessage::ToRoomBinary {
409 room_id: room_id.to_string(),
410 data: Arc::new(data),
411 exclude_client
412 }).map_err(|e| TransmissionError::Other(anyhow::anyhow!(e.to_string())))
413 }
414
415 pub fn send_to_client(&self, client_id: &str, message: String) -> Result<()> {
417 self.broadcast_tx.send(BroadcastMessage::ToClient {
418 client_id: client_id.to_string(),
419 message: Arc::new(message)
420 }).map_err(|e| TransmissionError::Other(anyhow::anyhow!(e.to_string())))
421 }
422
423 pub fn send_binary_to_client(&self, client_id: &str, data: Vec<u8>) -> Result<()> {
425 self.broadcast_tx.send(BroadcastMessage::ToClientBinary {
426 client_id: client_id.to_string(),
427 data: Arc::new(data)
428 }).map_err(|e| TransmissionError::Other(anyhow::anyhow!(e.to_string())))
429 }
430}
431
432fn apply_update_to_doc(doc: &Arc<yrs::Doc>, update: &[u8]) -> crate::Result<()> {
434 let u = yrs::Update::decode_v1(update)?;
435 let mut txn = doc.transact_mut();
436 txn.apply_update(u)?;
437 Ok(())
438}
439
440#[allow(dead_code)]
441fn get_diff_update_from_doc(doc: &Arc<yrs::Doc>, sv: &[u8]) -> std::result::Result<Vec<u8>, yrs::encoding::read::Error> {
442 let state_vector = yrs::StateVector::decode_v1(sv)?;
443 let txn = doc.transact();
444 Ok(txn.encode_diff_v1(&state_vector))
445}