1use std::sync::Arc;
2use yrs::{Map, ReadTxn as _, Transact, WriteTxn as _};
3use serde::{Deserialize, Serialize};
4
5use crate::{mapping::Mapper};
6use crate::error::Result;
7use crate::yrs_manager::YrsManager;
8use mf_state::Transaction;
9use mf_model::tree::Tree;
10use crate::RoomSnapshot;
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub enum RoomStatus {
15 NotExists,
17 Created,
19 Initialized,
21 Shutting,
23 Offline,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct RoomInfo {
30 pub room_id: String,
31 pub status: RoomStatus,
32 pub node_count: usize,
33 pub client_count: usize,
34 pub last_activity: std::time::SystemTime,
35}
36
37#[derive(Clone)]
38pub struct SyncService {
39 yrs_manager: Arc<YrsManager>,
40 client_id: u64,
41}
42
43impl SyncService {
44 pub fn new(yrs_manager: Arc<YrsManager>) -> Self {
45 Self { yrs_manager, client_id: fastrand::u64(..) }
46 }
47
48 pub fn init_room(
50 &self,
51 room_id: &str,
52 ) {
53 tracing::info!("🔄 初始化房间: {}", room_id);
54 self.yrs_manager.get_or_create_awareness(room_id);
55 }
56
57 pub async fn init_room_with_tree(
60 &self,
61 room_id: &str,
62 tree: &Tree,
63 ) -> Result<()> {
64 tracing::info!("🔄 初始化房间: {} 使用现有的树数据", room_id);
65
66 let awareness_ref = self.yrs_manager.get_or_create_awareness(room_id);
68 let mut awareness = awareness_ref.write().await;
69 let doc = awareness.doc_mut();
70 let mut txn = doc.transact_mut_with(yrs::Origin::from(self.client_id));
71
72 let nodes_map = txn.get_or_insert_map("nodes");
74 nodes_map.clear(&mut txn);
75
76 self.sync_tree_to_yrs(tree, &mut txn)?;
78
79 txn.commit();
81
82 tracing::info!(
83 "Successfully initialized room {} with tree containing {} nodes",
84 room_id,
85 tree.nodes.len()
86 );
87 Ok(())
88 }
89
90 fn sync_tree_to_yrs(
92 &self,
93 tree: &Tree,
94 txn: &mut yrs::TransactionMut,
95 ) -> Result<()> {
96 use mf_transform::{step::Step, node_step::AddNodeStep};
97
98 let registry = Mapper::global_registry();
99
100 if let Some(root_tree) = tree.all_children(&tree.root_id, None) {
102 let add_step = AddNodeStep {
104 parent_id: tree.root_id.clone(),
105 nodes: vec![root_tree],
106 };
107
108 if let Some(converter) =
110 registry.find_converter(&add_step as &dyn Step)
111 {
112 if let Err(e) =
113 converter.apply_to_yrs_txn(&add_step as &dyn Step, txn)
114 {
115 tracing::error!("🔄 同步树节点到 Yrs 失败: {}", e);
116 return Err(crate::error::TransmissionError::SyncError(
117 format!("Failed to sync tree: {}", e),
118 ));
119 }
120 } else {
121 tracing::error!(
122 "🔄 同步树节点到 Yrs 失败: 没有找到 AddNodeStep 的转换器"
123 );
124 return Err(crate::error::TransmissionError::SyncError(
125 "No converter found for AddNodeStep".to_string(),
126 ));
127 }
128 }
129
130 Ok(())
131 }
132
133 pub async fn handle_transaction_applied(
135 &self,
136 transactions: &[Transaction],
137 room_id: &str,
138 ) -> Result<()> {
139 if let Some(awareness_ref) = self.yrs_manager.get_awareness_ref(room_id)
141 {
142 let mut awareness = awareness_ref.write().await;
143 let doc = awareness.doc_mut();
144 let mut txn =
145 doc.transact_mut_with(yrs::Origin::from(self.client_id));
146
147 let registry = Mapper::global_registry();
149
150 for tr in transactions {
151 let steps = &tr.steps;
152 for step in steps {
153 if let Some(converter) =
154 registry.find_converter(step.as_ref())
155 {
156 if let Err(e) =
157 converter.apply_to_yrs_txn(step.as_ref(), &mut txn)
158 {
159 tracing::error!(
160 "🔄 应用步骤到 Yrs 事务失败: {}",
161 e
162 );
163 }
164 } else {
165 let type_name =
166 std::any::type_name_of_val(step.as_ref());
167 tracing::warn!(
168 "🔄 应用步骤到 Yrs 事务失败: 没有找到步骤的转换器: {}",
169 type_name
170 );
171 }
172 }
173 }
174
175 txn.commit();
177 tracing::debug!(
178 "🔄 应用 {} 个事务到房间: {}",
179 transactions.len(),
180 room_id
181 );
182 }
183
184 Ok(())
185 }
186
187 pub fn get_room_snapshot(
189 &self,
190 room_id: &str,
191 tree: &Tree,
192 ) -> RoomSnapshot {
193 tracing::debug!("🔄 获取房间快照: {}", room_id);
194 Mapper::tree_to_snapshot(tree, room_id.to_string())
195 }
196
197 pub async fn is_room_initialized(
199 &self,
200 room_id: &str,
201 ) -> bool {
202 if let Some(awareness_ref) = self.yrs_manager.get_awareness_ref(room_id)
203 {
204 let awareness = awareness_ref.read().await;
205 let doc = awareness.doc();
206 let txn = doc.transact();
207
208 if let Some(nodes_map) = txn.get_map("nodes") {
209 nodes_map.len(&txn) > 0
210 } else {
211 false
212 }
213 } else {
214 false
215 }
216 }
217
218 pub async fn get_room_status(
220 &self,
221 room_id: &str,
222 ) -> RoomStatus {
223 if !self.yrs_manager.room_exists(room_id) {
224 return RoomStatus::NotExists;
225 }
226
227 if self.is_room_initialized(room_id).await {
228 RoomStatus::Initialized
229 } else {
230 RoomStatus::Created
231 }
232 }
233
234 pub async fn get_room_info(
236 &self,
237 room_id: &str,
238 ) -> Option<RoomInfo> {
239 if !self.yrs_manager.room_exists(room_id) {
240 return None;
241 }
242
243 let status = self.get_room_status(room_id).await;
244 let mut node_count = 0;
245 let mut client_count = 0;
246
247 if let Some(awareness_ref) = self.yrs_manager.get_awareness_ref(room_id)
248 {
249 if let Ok(awareness) = awareness_ref.try_read() {
250 let doc = awareness.doc();
251 let txn = doc.transact();
252
253 if let Some(nodes_map) = txn.get_map("nodes") {
255 node_count = nodes_map.len(&txn);
256 }
257
258 client_count = awareness.clients().len();
260 }
261 }
262
263 Some(RoomInfo {
264 room_id: room_id.to_string(),
265 status,
266 node_count: node_count as usize,
267 client_count,
268 last_activity: std::time::SystemTime::now(),
269 })
270 }
271
272 pub async fn offline_room(
277 &self,
278 room_id: &str,
279 save_data: bool,
280 ) -> Result<Option<RoomSnapshot>> {
281 tracing::info!("🔄 开始下线房间: {}", room_id);
282
283 let mut final_snapshot = None;
284
285 if !self.yrs_manager.room_exists(room_id) {
287 tracing::warn!("🔄 尝试下线不存在的房间: {}", room_id);
288 return Ok(None);
289 }
290
291 if save_data {
293 if let Some(awareness_ref) =
294 self.yrs_manager.get_awareness_ref(room_id)
295 {
296 let awareness = awareness_ref.read().await;
297 let doc = awareness.doc();
298 let txn = doc.transact();
299
300 if let Some(nodes_map) = txn.get_map("nodes") {
302 let node_count = nodes_map.len(&txn);
303 tracing::info!(
304 "🔄 保存 {} 个节点 from room: {}",
305 node_count,
306 room_id
307 );
308
309 final_snapshot = Some(RoomSnapshot {
311 room_id: room_id.to_string(),
312 root_id: "root".to_string(), nodes: std::collections::HashMap::new(),
314 version: 0,
315 });
316 }
317 }
318 }
319
320 if let Some(_awareness_ref) =
322 self.yrs_manager.remove_room(room_id).await
323 {
324 tracing::info!("🔄 房间 '{}' 成功下线", room_id);
325 } else {
326 tracing::error!("🔄 从 YrsManager 中移除房间 '{}' 失败", room_id);
327 return Err(crate::error::TransmissionError::SyncError(format!(
328 "Failed to offline room: {}",
329 room_id
330 )));
331 }
332
333 Ok(final_snapshot)
334 }
335
336 pub async fn force_offline_room(
338 &self,
339 room_id: &str,
340 ) -> Result<bool> {
341 tracing::warn!("Force offlining room: {}", room_id);
342
343 let success = self.yrs_manager.force_cleanup_room(room_id).await;
344
345 if success {
346 tracing::info!("Room '{}' force offlined successfully", room_id);
347 } else {
348 tracing::error!("Failed to force offline room: {}", room_id);
349 }
350
351 Ok(success)
352 }
353
354 pub async fn offline_rooms(
356 &self,
357 room_ids: &[String],
358 save_data: bool,
359 ) -> Result<Vec<(String, Option<RoomSnapshot>)>> {
360 tracing::info!("🔄 批量下线 {} 个房间", room_ids.len());
361
362 let mut results = Vec::new();
363
364 for room_id in room_ids {
365 match self.offline_room(room_id, save_data).await {
366 Ok(snapshot) => {
367 results.push((room_id.clone(), snapshot));
368 },
369 Err(e) => {
370 tracing::error!("🔄 下线房间 '{}' 失败: {}", room_id, e);
371 results.push((room_id.clone(), None));
372 },
373 }
374 }
375
376 tracing::info!(
377 "🔄 批量下线完成: {}/{} 个房间成功下线",
378 results.iter().filter(|(_, snapshot)| snapshot.is_some()).count(),
379 room_ids.len()
380 );
381
382 Ok(results)
383 }
384
385 pub fn get_active_rooms(&self) -> Vec<String> {
387 self.yrs_manager.get_active_rooms()
388 }
389
390 pub async fn get_rooms_stats(&self) -> Vec<RoomInfo> {
392 let room_ids = self.get_active_rooms();
393 let mut stats = Vec::new();
394
395 for room_id in room_ids {
396 if let Some(info) = self.get_room_info(&room_id).await {
397 stats.push(info);
398 }
399 }
400
401 stats
402 }
403
404 pub fn yrs_manager(&self) -> &Arc<YrsManager> {
406 &self.yrs_manager
407 }
408}
409
410impl std::fmt::Debug for SyncService {
411 fn fmt(
412 &self,
413 f: &mut std::fmt::Formatter<'_>,
414 ) -> std::fmt::Result {
415 f.debug_struct("SyncService")
416 .field("client_id", &self.client_id)
417 .finish()
418 }
419}