1use std::time::{SystemTime, UNIX_EPOCH};
2use mf_model::mark::Mark;
3use mf_model::tree::Tree;
4use mf_state::transaction::Transaction;
5use crate::AwarenessRef;
7use serde_json::Value as JsonValue;
8use yrs::{Map, ReadTxn, Transact};
9use yrs::{
10 types::{array::ArrayRef, map::MapRef, Value},
11 Array, ArrayPrelim, MapPrelim, TransactionMut, WriteTxn,
12};
13
14use crate::ClientResult;
15use mf_model::{node::Node, attrs::Attrs, types::NodeId};
16use std::sync::Arc;
17use std::collections::HashMap;
18
19pub struct Utils;
21impl Utils {
22 pub fn get_unix_time() -> u64 {
23 SystemTime::now()
24 .duration_since(UNIX_EPOCH)
25 .unwrap_or_default()
26 .as_millis() as u64
27 }
28 pub fn apply_yrs_to_tree(doc: &yrs::Doc) -> ClientResult<Tree> {
31 use mf_model::types::NodeId;
32 use std::collections::HashMap;
33
34 let root_id = Utils::get_root_id_from_yrs_doc(doc)?;
35 let txn = doc.transact();
36 let nodes_map = txn
37 .get_map("nodes")
38 .ok_or(anyhow::anyhow!("Yrs 文档中没有找到 nodes 映射"))?;
39 let mut tree_nodes = HashMap::new();
40 let mut parent_map = HashMap::new();
41
42 Utils::build_tree_nodes_from_yrs(
43 &root_id,
44 &nodes_map,
45 &txn,
46 &mut tree_nodes,
47 &mut parent_map,
48 None,
49 )?;
50
51 let root_node = tree_nodes
52 .get(&NodeId::from(root_id))
53 .ok_or(anyhow::anyhow!("根节点不存在"))?
54 .as_ref()
55 .clone();
56 let root_enum =
57 Utils::build_node_enum_from_map(&root_node, &tree_nodes);
58 Ok(Tree::from(root_enum))
59 }
60 pub async fn apply_tree_to_yrs(
63 awareness_ref: AwarenessRef,
64 tree: &Tree,
65 ) -> ClientResult<()> {
66 let mut awareness = awareness_ref.write().await;
67 let doc = awareness.doc_mut();
68 let mut txn =
69 doc.transact_mut_with(doc.client_id().clone().to_string());
70
71 let nodes_map = txn.get_or_insert_map("nodes");
73 nodes_map.clear(&mut txn);
74
75 Utils::sync_tree_to_yrs(tree, &mut txn)?;
77
78 let meta_map = txn.get_or_insert_map("meta");
80 meta_map.insert(
81 &mut txn,
82 "root_id",
83 yrs::Any::String(tree.root_id.to_string().into()),
84 );
85
86 txn.commit();
88
89 tracing::info!(
90 "成功初始化树,包含 {} 个节点,根节点ID: {}",
91 tree.nodes.iter().map(|shard| shard.len()).sum::<usize>(),
92 tree.root_id
93 );
94 Ok(())
95 }
96
97 pub fn sync_tree_to_yrs(
99 tree: &Tree,
100 txn: &mut yrs::TransactionMut,
101 ) -> ClientResult<()> {
102 use mf_transform::node_step::AddNodeStep;
103
104 if let Some(root_tree) = tree.all_children(&tree.root_id, None) {
106 let add_step = AddNodeStep {
109 parent_id: tree.root_id.clone(),
110 nodes: vec![root_tree],
111 };
112
113 let context = crate::mapping::create_context(
115 "tree_sync_client".to_string(),
116 "tree_sync_user".to_string(),
117 );
118
119 if let Err(e) =
120 crate::mapping::convert_step(&add_step, txn, &context)
121 {
122 tracing::error!("🔄 同步树节点到 Yrs 失败: {}", e);
123 return Err(anyhow::anyhow!(format!(
124 "Failed to sync tree: {}",
125 e
126 )));
127 }
128 }
129
130 Ok(())
131 }
132 pub async fn apply_transaction_to_yrs(
134 awareness_ref: AwarenessRef,
135 transaction: &Transaction,
136 ) -> ClientResult<()> {
137 let mut awareness = awareness_ref.write().await;
140 let doc = awareness.doc_mut();
141 let mut txn =
142 doc.transact_mut_with(doc.client_id().clone().to_string());
143 let context = crate::mapping::create_context(
145 "transaction_client".to_string(),
146 "transaction_user".to_string(),
147 );
148
149 let steps = &transaction.steps;
150 for step in steps {
151 if let Err(e) =
152 crate::mapping::convert_step(step.as_ref(), &mut txn, &context)
153 {
154 tracing::error!("🔄 应用步骤到 Yrs 事务失败: {}", e);
155 }
156 }
157 txn.commit();
159 tracing::debug!(
160 "🔄 应用 {} 个步骤到文档: {}",
161 transaction.steps.len(),
162 doc.client_id()
163 );
164
165 Ok(())
166 }
167
168 pub async fn apply_transactions_to_yrs(
170 awareness_ref: AwarenessRef,
171 transactions: &[Transaction],
172 ) -> ClientResult<()> {
173 let mut awareness = awareness_ref.write().await;
176 let doc = awareness.doc_mut();
177 let mut txn =
178 doc.transact_mut_with(doc.client_id().clone().to_string());
179
180 let context = crate::mapping::create_context(
182 "bulk_transaction_client".to_string(),
183 "bulk_transaction_user".to_string(),
184 );
185
186 for tr in transactions {
187 let steps = &tr.steps;
188 for step in steps {
189 if let Err(e) = crate::mapping::convert_step(
190 step.as_ref(),
191 &mut txn,
192 &context,
193 ) {
194 tracing::error!("🔄 应用步骤到 Yrs 事务失败: {}", e);
195 }
196 }
197 }
198 txn.commit();
200 tracing::debug!(
201 "🔄 应用 {} 个事务到文档: {}",
202 transactions.len(),
203 doc.client_id()
204 );
205
206 Ok(())
207 }
208
209 pub fn json_value_to_yrs_any(value: &JsonValue) -> yrs::Any {
212 match value {
213 JsonValue::Null => yrs::Any::Null,
214 JsonValue::Bool(b) => yrs::Any::Bool(*b),
215 JsonValue::Number(n) => {
216 if let Some(i) = n.as_i64() {
217 yrs::Any::BigInt(i)
218 } else if let Some(f) = n.as_f64() {
219 yrs::Any::Number(f)
220 } else {
221 yrs::Any::Null
222 }
223 },
224 JsonValue::String(s) => yrs::Any::String(s.clone().into()),
225 JsonValue::Array(arr) => {
226 let yrs_array: Vec<yrs::Any> =
227 arr.iter().map(Utils::json_value_to_yrs_any).collect();
228 yrs::Any::Array(yrs_array.into())
229 },
230 JsonValue::Object(obj) => {
231 let yrs_map: std::collections::HashMap<String, yrs::Any> = obj
232 .iter()
233 .map(|(k, v)| (k.clone(), Utils::json_value_to_yrs_any(v)))
234 .collect();
235 yrs::Any::Map(yrs_map.into())
236 },
237 }
238 }
239
240 pub fn add_mark_to_array(
242 marks_array: &ArrayRef,
243 txn: &mut TransactionMut,
244 mark: &Mark,
245 ) {
246 let mark_map = MapPrelim::<yrs::Any>::from([
247 ("type".to_string(), yrs::Any::String(mark.r#type.clone().into())),
248 ("attrs".to_string(), {
249 let attrs_map: std::collections::HashMap<String, yrs::Any> =
250 mark.attrs
251 .iter()
252 .map(|(k, v)| {
253 (k.clone(), Utils::json_value_to_yrs_any(v))
254 })
255 .collect();
256 yrs::Any::Map(attrs_map.into())
257 }),
258 ]);
259 marks_array.push_back(txn, mark_map);
260 }
261
262 pub fn get_or_create_node_data_map(
264 nodes_map: &MapRef,
265 txn: &mut TransactionMut,
266 node_id: &str,
267 ) -> MapRef {
268 if let Some(Value::YMap(map)) = nodes_map.get(txn, node_id) {
269 map
270 } else {
271 nodes_map.insert(
272 txn,
273 node_id.to_string(),
274 MapPrelim::<yrs::Any>::new(),
275 )
276 }
277 }
278
279 pub fn get_or_create_node_attrs_map(
281 node_data_map: &MapRef,
282 txn: &mut TransactionMut,
283 ) -> MapRef {
284 if let Some(Value::YMap(map)) = node_data_map.get(txn, "attrs") {
285 map
286 } else {
287 node_data_map.insert(txn, "attrs", MapPrelim::<yrs::Any>::new())
288 }
289 }
290
291 pub fn get_or_create_content_array(
293 node_data_map: &MapRef,
294 txn: &mut TransactionMut,
295 ) -> ArrayRef {
296 if let Some(Value::YArray(array)) = node_data_map.get(txn, "content") {
297 array
298 } else {
299 node_data_map.insert(
300 txn,
301 "content",
302 ArrayPrelim::from(Vec::<yrs::Any>::new()),
303 )
304 }
305 }
306
307 pub fn yrs_any_to_json_value(value: &yrs::Any) -> Option<JsonValue> {
309 match value {
310 yrs::Any::Null => Some(JsonValue::Null),
311 yrs::Any::Bool(b) => Some(JsonValue::Bool(*b)),
312 yrs::Any::Number(n) => {
313 Some(JsonValue::Number(serde_json::Number::from_f64(*n)?))
314 },
315 yrs::Any::BigInt(i) => {
316 Some(JsonValue::Number(serde_json::Number::from(*i)))
317 },
318 yrs::Any::String(s) => Some(JsonValue::String(s.to_string())),
319 yrs::Any::Array(arr) => {
320 let json_array: Vec<JsonValue> = arr
321 .iter()
322 .filter_map(Utils::yrs_any_to_json_value)
323 .collect();
324 Some(JsonValue::Array(json_array))
325 },
326 yrs::Any::Map(map) => {
327 let json_map: std::collections::HashMap<String, JsonValue> =
328 map.iter()
329 .filter_map(|(k, v)| {
330 Utils::yrs_any_to_json_value(v)
331 .map(|json_v| (k.to_string(), json_v))
332 })
333 .collect();
334 Some(JsonValue::Object(serde_json::Map::from_iter(json_map)))
335 },
336 _ => None, }
338 }
339
340 pub fn get_or_create_marks_array(
342 node_data_map: &MapRef,
343 txn: &mut TransactionMut,
344 ) -> ArrayRef {
345 if let Some(Value::YArray(array)) = node_data_map.get(txn, "marks") {
346 array
347 } else {
348 node_data_map.insert(
349 txn,
350 "marks",
351 ArrayPrelim::from(Vec::<yrs::Any>::new()),
352 )
353 }
354 }
355
356 pub fn get_root_id_from_yrs_doc(doc: &yrs::Doc) -> ClientResult<String> {
358 let txn = doc.transact();
359 if let Some(meta_map) = txn.get_map("meta") {
361 if let Some(yrs::types::Value::Any(any)) =
362 meta_map.get(&txn, "root_id")
363 {
364 return Ok(any.to_string());
365 }
366 }
367 let nodes_map = txn
369 .get_map("nodes")
370 .ok_or(anyhow::anyhow!("Yrs 文档中没有找到 nodes 映射"))?;
371 if let Some((key, _)) = nodes_map.iter(&txn).next() {
372 return Ok(key.to_string());
373 }
374 Err(anyhow::anyhow!("Yrs 文档中没有找到根节点"))
375 }
376
377 pub fn build_tree_nodes_from_yrs(
379 node_id: &str,
380 nodes_map: &yrs::types::map::MapRef,
381 txn: &yrs::Transaction,
382 tree_nodes: &mut HashMap<NodeId, Arc<Node>>,
383 parent_map: &mut HashMap<NodeId, NodeId>,
384 parent_id: Option<&NodeId>,
385 ) -> ClientResult<()> {
386 let node_data = nodes_map.get(txn, node_id);
387 if node_data.is_none() {
388 return Err(anyhow::anyhow!(
389 "节点 {} 在 Yrs 文档中不存在",
390 node_id
391 ));
392 }
393 let node_data = node_data.unwrap();
394 if let yrs::types::Value::YMap(node_map) = node_data {
395 let node_type = node_map
397 .get(txn, "type")
398 .and_then(|v| match v {
399 yrs::types::Value::Any(any) => Some(any.to_string()),
400 _ => None,
401 })
402 .unwrap_or_else(|| "unknown".to_string());
403
404 let mut attrs = Attrs::default();
406 if let Some(yrs::types::Value::YMap(attrs_yrs_map)) =
407 node_map.get(txn, "attrs")
408 {
409 for (key, value) in attrs_yrs_map.iter(txn) {
410 if let yrs::types::Value::Any(any_value) = value {
411 if let Some(json_value) =
412 Utils::yrs_any_to_json_value(&any_value)
413 {
414 attrs.insert(key.to_string(), json_value);
415 }
416 }
417 }
418 }
419
420 let mut content = imbl::Vector::new();
422 if let Some(yrs::types::Value::YArray(content_yrs_array)) =
423 node_map.get(txn, "content")
424 {
425 for item in content_yrs_array.iter(txn) {
426 if let yrs::types::Value::Any(any) = item {
427 content.push_back(NodeId::from(any.to_string()));
428 }
429 }
430 }
431
432 let mut marks = imbl::Vector::new();
434 if let Some(yrs::types::Value::YArray(marks_yrs_array)) =
435 node_map.get(txn, "marks")
436 {
437 for item in marks_yrs_array.iter(txn) {
438 if let yrs::types::Value::YMap(mark_map) = item {
439 let mark_type = mark_map
440 .get(txn, "type")
441 .and_then(|v| match v {
442 yrs::types::Value::Any(any) => {
443 Some(any.to_string())
444 },
445 _ => None,
446 })
447 .unwrap_or_else(|| "unknown".to_string());
448
449 let mut mark_attrs = Attrs::default();
450 if let Some(yrs::types::Value::YMap(attrs_yrs_map)) =
451 mark_map.get(txn, "attrs")
452 {
453 for (key, value) in attrs_yrs_map.iter(txn) {
454 if let yrs::types::Value::Any(any_value) = value
455 {
456 if let Some(json_value) =
457 Utils::yrs_any_to_json_value(&any_value)
458 {
459 mark_attrs.insert(
460 key.to_string(),
461 json_value,
462 );
463 }
464 }
465 }
466 }
467
468 marks.push_back(Mark {
469 r#type: mark_type,
470 attrs: mark_attrs,
471 });
472 }
473 }
474 }
475
476 let content_vec: Vec<NodeId> =
478 content.clone().into_iter().collect();
479 let marks_vec: Vec<Mark> = marks.clone().into_iter().collect();
480 let node =
481 Node::new(node_id, node_type, attrs, content_vec, marks_vec);
482
483 let node_id_typed = NodeId::from(node_id);
484 tree_nodes.insert(node_id_typed.clone(), Arc::new(node));
485
486 if let Some(parent) = parent_id {
488 parent_map.insert(node_id_typed.clone(), parent.clone());
489 }
490
491 for child_id in content {
493 Utils::build_tree_nodes_from_yrs(
494 &child_id,
495 nodes_map,
496 txn,
497 tree_nodes,
498 parent_map,
499 Some(&node_id_typed),
500 )?;
501 }
502 }
503 Ok(())
504 }
505
506 pub fn build_node_enum_from_map(
508 node: &Node,
509 tree_nodes: &HashMap<NodeId, Arc<Node>>,
510 ) -> mf_model::node_definition::NodeTree {
511 let mut children = Vec::new();
512 for child_id in &node.content {
513 if let Some(child_node) = tree_nodes.get(child_id) {
514 children.push(Utils::build_node_enum_from_map(
515 child_node, tree_nodes,
516 ));
517 }
518 }
519 mf_model::node_definition::NodeTree(node.clone(), children)
520 }
521}