moduforge_collaboration/
mapping.rs

1use moduforge_transform::{
2    attr_step::AttrStep,
3    mark_step::{AddMarkStep, RemoveMarkStep},
4    node_step::{AddNodeStep, RemoveNodeStep},
5    step::Step,
6};
7use moduforge_model::{mark::Mark, node::Node, tree::Tree};
8use std::{any::TypeId, collections::HashMap};
9
10use crate::{NodeData, MarkData, RoomSnapshot, StepResult};
11use serde_json::Value as JsonValue;
12use yrs::{
13    types::{array::ArrayRef, map::MapRef, Value},
14    Array, ArrayPrelim, Map, MapPrelim, TransactionMut, WriteTxn,
15};
16
17/// 将 `Step` 转换为 Yrs 事务的 Trait
18/// 这个 Trait 是动态安全的
19pub trait StepConverter: Send + Sync {
20    /// 将步骤应用到 Yrs 文档事务中
21    fn apply_to_yrs_txn(
22        &self,
23        step: &dyn Step,
24        txn: &mut TransactionMut,
25    ) -> Result<StepResult, Box<dyn std::error::Error>>;
26
27    /// 返回转换器的名称
28    fn name(&self) -> &'static str;
29
30    /// 检查此转换器是否支持给定的步骤类型
31    fn supports(
32        &self,
33        step: &dyn Step,
34    ) -> bool;
35
36    /// 获取步骤的操作描述
37    fn get_description(
38        &self,
39        step: &dyn Step,
40    ) -> String {
41        format!("Executing operation: {} ({})", step.name(), self.name())
42    }
43}
44
45/// 默认的步骤转换器,用于不支持的步骤
46pub struct DefaultStepConverter;
47
48impl StepConverter for DefaultStepConverter {
49    fn apply_to_yrs_txn(
50        &self,
51        step: &dyn Step,
52        txn: &mut TransactionMut,
53    ) -> Result<StepResult, Box<dyn std::error::Error>> {
54        Ok(StepResult {
55            step_id: uuid::Uuid::new_v4().to_string(),
56            step_name: step.name().to_string(),
57            description: format!("默认处理程序处理未知步骤: {}", step.name()),
58            timestamp: std::time::SystemTime::now()
59                .duration_since(std::time::UNIX_EPOCH)
60                .unwrap()
61                .as_millis() as u64,
62            client_id: txn
63                .origin()
64                .as_ref()
65                .map(|s| s.to_string())
66                .unwrap_or_default(),
67        })
68    }
69
70    fn name(&self) -> &'static str {
71        "DefaultStepConverter"
72    }
73
74    fn supports(
75        &self,
76        _step: &dyn Step,
77    ) -> bool {
78        true // Default converter supports all types as a fallback.
79    }
80}
81
82// --- 转换器的辅助方法 ---
83
84fn json_value_to_yrs_any(value: &JsonValue) -> yrs::Any {
85    match value {
86        JsonValue::Null => yrs::Any::Null,
87        JsonValue::Bool(b) => yrs::Any::Bool(*b),
88        JsonValue::Number(n) => {
89            if let Some(i) = n.as_i64() {
90                yrs::Any::BigInt(i)
91            } else if let Some(f) = n.as_f64() {
92                yrs::Any::Number(f)
93            } else {
94                yrs::Any::Null
95            }
96        },
97        JsonValue::String(s) => yrs::Any::String(s.clone().into()),
98        JsonValue::Array(arr) => {
99            let yrs_array: Vec<yrs::Any> =
100                arr.iter().map(json_value_to_yrs_any).collect();
101            yrs::Any::Array(yrs_array.into())
102        },
103        JsonValue::Object(obj) => {
104            let yrs_map: std::collections::HashMap<String, yrs::Any> = obj
105                .iter()
106                .map(|(k, v)| (k.clone(), json_value_to_yrs_any(v)))
107                .collect();
108            yrs::Any::Map(yrs_map.into())
109        },
110    }
111}
112
113/// 将标记添加到 Yrs 数组中
114fn add_mark_to_array(
115    marks_array: &ArrayRef,
116    txn: &mut TransactionMut,
117    mark: &Mark,
118) {
119    let mark_map = MapPrelim::<yrs::Any>::from([
120        ("type".to_string(), yrs::Any::String(mark.r#type.clone().into())),
121        ("attrs".to_string(), {
122            let attrs_map: std::collections::HashMap<String, yrs::Any> = mark
123                .attrs
124                .iter()
125                .map(|(k, v)| (k.clone(), json_value_to_yrs_any(v)))
126                .collect();
127            yrs::Any::Map(attrs_map.into())
128        }),
129    ]);
130    marks_array.push_back(txn, mark_map);
131}
132
133/// 获取或创建节点数据映射
134fn get_or_create_node_data_map(
135    nodes_map: &MapRef,
136    txn: &mut TransactionMut,
137    node_id: &str,
138) -> MapRef {
139    if let Some(Value::YMap(map)) = nodes_map.get(txn, node_id) {
140        map
141    } else {
142        nodes_map.insert(txn, node_id.to_string(), MapPrelim::<yrs::Any>::new())
143    }
144}
145
146/// 获取或创建节点属性映射
147fn get_or_create_node_attrs_map(
148    node_data_map: &MapRef,
149    txn: &mut TransactionMut,
150) -> MapRef {
151    if let Some(Value::YMap(map)) = node_data_map.get(txn, "attrs") {
152        map
153    } else {
154        node_data_map.insert(txn, "attrs", MapPrelim::<yrs::Any>::new())
155    }
156}
157
158/// 获取或创建标记数组
159fn get_or_create_marks_array(
160    node_data_map: &MapRef,
161    txn: &mut TransactionMut,
162) -> ArrayRef {
163    if let Some(Value::YArray(array)) = node_data_map.get(txn, "marks") {
164        array
165    } else {
166        node_data_map.insert(
167            txn,
168            "marks",
169            ArrayPrelim::from(Vec::<yrs::Any>::new()),
170        )
171    }
172}
173
174/// 节点相关步骤的转换器
175pub struct NodeStepConverter;
176
177impl NodeStepConverter {
178    fn insert_node_data(
179        &self,
180        txn: &mut TransactionMut,
181        nodes_map: &MapRef,
182        node: &Node,
183    ) {
184        let node_data_map =
185            get_or_create_node_data_map(nodes_map, txn, &node.id);
186        // 插入节点类型
187        node_data_map.insert(txn, "type", node.r#type.clone());
188        // 插入节点属性
189        let attrs_map =
190            node_data_map.insert(txn, "attrs", MapPrelim::<yrs::Any>::new());
191        for (key, value) in node.attrs.iter() {
192            attrs_map.insert(txn, key.clone(), json_value_to_yrs_any(value));
193        }
194        // 插入节点内容
195        let content_array = node_data_map.insert(
196            txn,
197            "content",
198            ArrayPrelim::from(Vec::<yrs::Any>::new()),
199        );
200        for child_id in &node.content {
201            content_array
202                .push_back(txn, yrs::Any::String(child_id.clone().into()));
203        }
204        // 插入节点标记
205        let marks_array = node_data_map.insert(
206            txn,
207            "marks",
208            ArrayPrelim::from(Vec::<yrs::Any>::new()),
209        );
210        for mark in &node.marks {
211            add_mark_to_array(&marks_array, txn, mark);
212        }
213    }
214}
215
216impl StepConverter for NodeStepConverter {
217    fn apply_to_yrs_txn(
218        &self,
219        step: &dyn Step,
220        txn: &mut TransactionMut,
221    ) -> Result<StepResult, Box<dyn std::error::Error>> {
222        let client_id =
223            txn.origin().as_ref().map(|s| s.to_string()).unwrap_or_default();
224
225        if let Some(add_step) = step.downcast_ref::<AddNodeStep>() {
226            let nodes_map = txn.get_or_insert_map("nodes");
227            let all_nodes = &add_step.nodes;
228
229            for node_enum in all_nodes {
230                self.insert_node_data(txn, &nodes_map, &node_enum.0);
231            }
232
233            return Ok(StepResult {
234                step_id: uuid::Uuid::new_v4().to_string(),
235                step_name: step.name().to_string(),
236                description: format!("添加 {} 个节点", all_nodes.len()),
237                timestamp: std::time::SystemTime::now()
238                    .duration_since(std::time::UNIX_EPOCH)
239                    .unwrap()
240                    .as_millis() as u64,
241                client_id,
242            });
243        } else if let Some(remove_step) = step.downcast_ref::<RemoveNodeStep>()
244        {
245            let nodes_map = txn.get_or_insert_map("nodes");
246            for node_id in &remove_step.node_ids {
247                nodes_map.remove(txn, &node_id.to_string());
248            }
249
250            return Ok(StepResult {
251                step_id: uuid::Uuid::new_v4().to_string(),
252                step_name: step.name().to_string(),
253                description: format!(
254                    "Removed {} nodes",
255                    remove_step.node_ids.len()
256                ),
257                timestamp: std::time::SystemTime::now()
258                    .duration_since(std::time::UNIX_EPOCH)
259                    .unwrap()
260                    .as_millis() as u64,
261                client_id,
262            });
263        }
264
265        Err("不支持的节点操作".into())
266    }
267
268    fn name(&self) -> &'static str {
269        "NodeStepConverter"
270    }
271
272    fn supports(
273        &self,
274        step: &dyn Step,
275    ) -> bool {
276        step.type_id() == TypeId::of::<AddNodeStep>()
277            || step.type_id() == TypeId::of::<RemoveNodeStep>()
278    }
279}
280
281/// 属性相关步骤的转换器
282pub struct AttrStepConverter;
283
284impl StepConverter for AttrStepConverter {
285    fn apply_to_yrs_txn(
286        &self,
287        step: &dyn Step,
288        txn: &mut TransactionMut,
289    ) -> Result<StepResult, Box<dyn std::error::Error>> {
290        let client_id =
291            txn.origin().as_ref().map(|s| s.to_string()).unwrap_or_default();
292        if let Some(attr_step) = step.downcast_ref::<AttrStep>() {
293            let nodes_map = txn.get_or_insert_map("nodes");
294            let node_data_map =
295                get_or_create_node_data_map(&nodes_map, txn, &attr_step.id);
296            // 获取或创建节点属性映射
297            let attrs_map = get_or_create_node_attrs_map(&node_data_map, txn);
298            // 更新节点属性
299            for (key, value) in attr_step.values.iter() {
300                attrs_map.insert(
301                    txn,
302                    key.clone(),
303                    json_value_to_yrs_any(value),
304                );
305            }
306
307            Ok(StepResult {
308                step_id: uuid::Uuid::new_v4().to_string(),
309                step_name: step.name().to_string(),
310                description: format!(
311                    "更新 {} 个属性 for node {}",
312                    attr_step.values.len(),
313                    attr_step.id
314                ),
315                timestamp: std::time::SystemTime::now()
316                    .duration_since(std::time::UNIX_EPOCH)
317                    .unwrap()
318                    .as_millis() as u64,
319                client_id,
320            })
321        } else {
322            Err("不支持的属性操作".into())
323        }
324    }
325
326    fn name(&self) -> &'static str {
327        "AttrStepConverter"
328    }
329
330    fn supports(
331        &self,
332        step: &dyn Step,
333    ) -> bool {
334        step.type_id() == TypeId::of::<AttrStep>()
335    }
336}
337
338/// 标记相关步骤的转换器
339pub struct MarkStepConverter;
340
341impl MarkStepConverter {
342    /// 从 Yrs 数组中删除标记
343    fn remove_mark_from_array(
344        &self,
345        marks_array: &ArrayRef,
346        txn: &mut TransactionMut,
347        mark_type_to_remove: &str,
348    ) {
349        let len = marks_array.len(txn);
350        for i in (0..len).rev() {
351            if let Some(Value::YMap(mark_map)) = marks_array.get(txn, i) {
352                if let Some(mark_type_value) = mark_map.get(txn, "type") {
353                    let mark_type = match mark_type_value {
354                        Value::YText(_text_ref) => {
355                            // For now, skip text refs as we can't easily extract string
356                            continue;
357                        },
358                        Value::Any(any) => any.to_string(),
359                        _ => continue,
360                    };
361                    if mark_type == mark_type_to_remove {
362                        marks_array.remove(txn, i);
363                        return;
364                    }
365                }
366            }
367        }
368    }
369}
370
371impl StepConverter for MarkStepConverter {
372    fn apply_to_yrs_txn(
373        &self,
374        step: &dyn Step,
375        txn: &mut TransactionMut,
376    ) -> Result<StepResult, Box<dyn std::error::Error>> {
377        let client_id =
378            txn.origin().as_ref().map(|s| s.to_string()).unwrap_or_default();
379
380        if let Some(add_mark_step) = step.downcast_ref::<AddMarkStep>() {
381            let nodes_map = txn.get_or_insert_map("nodes");
382            // 获取或创建节点数据映射
383            let node_data_map =
384                get_or_create_node_data_map(&nodes_map, txn, &add_mark_step.id);
385            // 获取或创建标记数组
386            let marks_array = get_or_create_marks_array(&node_data_map, txn);
387            // 添加标记
388            for mark in &add_mark_step.marks {
389                add_mark_to_array(&marks_array, txn, mark);
390            }
391
392            return Ok(StepResult {
393                step_id: uuid::Uuid::new_v4().to_string(),
394                step_name: step.name().to_string(),
395                description: format!(
396                    "添加 {} 个标记 to node {}",
397                    add_mark_step.marks.len(),
398                    add_mark_step.id
399                ),
400                timestamp: std::time::SystemTime::now()
401                    .duration_since(std::time::UNIX_EPOCH)
402                    .unwrap()
403                    .as_millis() as u64,
404                client_id,
405            });
406        } else if let Some(remove_mark_step) =
407            step.downcast_ref::<RemoveMarkStep>()
408        {
409            let nodes_map = txn.get_or_insert_map("nodes");
410            let node_data_map = get_or_create_node_data_map(
411                &nodes_map,
412                txn,
413                &remove_mark_step.id,
414            );
415            let marks_array = get_or_create_marks_array(&node_data_map, txn);
416            // 删除标记
417            for mark_type in &remove_mark_step.mark_types {
418                self.remove_mark_from_array(&marks_array, txn, mark_type);
419            }
420
421            return Ok(StepResult {
422                step_id: uuid::Uuid::new_v4().to_string(),
423                step_name: step.name().to_string(),
424                description: format!(
425                    "Removed {} marks from node {}",
426                    remove_mark_step.mark_types.len(),
427                    remove_mark_step.id
428                ),
429                timestamp: std::time::SystemTime::now()
430                    .duration_since(std::time::UNIX_EPOCH)
431                    .unwrap()
432                    .as_millis() as u64,
433                client_id,
434            });
435        }
436
437        Err("不支持的标记操作".into())
438    }
439
440    fn name(&self) -> &'static str {
441        "MarkStepConverter"
442    }
443
444    fn supports(
445        &self,
446        step: &dyn Step,
447    ) -> bool {
448        step.type_id() == TypeId::of::<AddMarkStep>()
449            || step.type_id() == TypeId::of::<RemoveMarkStep>()
450    }
451}
452
453/// 所有步骤转换器的注册表
454pub struct StepConverterRegistry {
455    converters: Vec<Box<dyn StepConverter>>,
456}
457
458impl Default for StepConverterRegistry {
459    fn default() -> Self {
460        Self::new()
461    }
462}
463
464impl StepConverterRegistry {
465    /// 创建一个新的注册表,包含所有默认的转换器
466    pub fn new() -> Self {
467        let mut registry = Self { converters: Vec::new() };
468
469        registry.register(Box::new(NodeStepConverter));
470        registry.register(Box::new(AttrStepConverter));
471        registry.register(Box::new(MarkStepConverter));
472        registry.register(Box::new(DefaultStepConverter));
473
474        registry
475    }
476
477    /// 注册一个新的转换器
478    pub fn register(
479        &mut self,
480        converter: Box<dyn StepConverter>,
481    ) {
482        tracing::info!("🔄 注册步骤转换器: {}", converter.name());
483        self.converters.push(converter);
484    }
485
486    /// 查找支持给定步骤的转换器
487    pub fn find_converter(
488        &self,
489        step: &dyn Step,
490    ) -> Option<&(dyn StepConverter)> {
491        for converter in &self.converters {
492            if converter.supports(step) {
493                return Some(converter.as_ref());
494            }
495        }
496        None
497    }
498}
499
500/// 全局映射器,用于处理转换
501#[derive(Debug)]
502pub struct Mapper;
503
504impl Mapper {
505    /// Gets the global singleton instance of the converter registry.
506    pub fn global_registry() -> &'static StepConverterRegistry {
507        use std::sync::OnceLock;
508        static REGISTRY: OnceLock<StepConverterRegistry> = OnceLock::new();
509        REGISTRY.get_or_init(StepConverterRegistry::new)
510    }
511
512    /// 将 ModuForge `Tree` 转换为 `RoomSnapshot`
513    pub fn tree_to_snapshot(
514        tree: &Tree,
515        room_id: String,
516    ) -> RoomSnapshot {
517        let mut nodes = HashMap::new();
518
519        fn collect_nodes(
520            tree: &Tree,
521            node_id: &str,
522            nodes: &mut HashMap<String, NodeData>,
523        ) {
524            if let Some(node) = tree.get_node(&node_id.to_string()) {
525                let node_data = NodeData {
526                    id: node.id.clone(),
527                    node_type: node.r#type.clone(),
528                    attrs: node
529                        .attrs
530                        .iter()
531                        .map(|(k, v)| (k.clone(), v.clone()))
532                        .collect(),
533                    content: node.content.iter().cloned().collect(),
534                    marks: node
535                        .marks
536                        .iter()
537                        .map(|mark| MarkData {
538                            mark_type: mark.r#type.clone(),
539                            attrs: mark
540                                .attrs
541                                .iter()
542                                .map(|(k, v)| (k.clone(), v.clone()))
543                                .collect(),
544                        })
545                        .collect(),
546                };
547
548                nodes.insert(node_id.to_string(), node_data);
549
550                for child_id in &node.content {
551                    collect_nodes(tree, child_id, nodes);
552                }
553            }
554        }
555
556        collect_nodes(tree, &tree.root_id, &mut nodes);
557
558        RoomSnapshot {
559            room_id,
560            root_id: tree.root_id.clone(),
561            nodes,
562            version: 0,
563        }
564    }
565}