mf_collab_client/
mapping.rs

1use mf_transform::{
2    attr_step::AttrStep,
3    mark_step::{AddMarkStep, RemoveMarkStep},
4    node_step::{AddNodeStep, RemoveNodeStep},
5    step::Step,
6};
7use mf_model::{node::Node, tree::Tree};
8use std::{any::TypeId};
9
10use crate::{types::StepResult, utils::Utils};
11use yrs::{
12    types::{array::ArrayRef, map::MapRef, Value},
13    Array, ArrayPrelim, Map, MapPrelim, ReadTxn, Transact, TransactionMut,
14    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    /// 将 Yrs 变更转换成 ModuForge step
27    fn apply_yrs_to_step(&self) {}
28
29    /// 返回转换器的名称
30    fn name(&self) -> &'static str;
31
32    /// 检查此转换器是否支持给定的步骤类型
33    fn supports(
34        &self,
35        step: &dyn Step,
36    ) -> bool;
37
38    /// 获取步骤的操作描述
39    fn get_description(
40        &self,
41        step: &dyn Step,
42    ) -> String {
43        format!("Executing operation: {} ({})", step.name(), self.name())
44    }
45}
46
47/// 默认的步骤转换器,用于不支持的步骤
48pub struct DefaultStepConverter;
49
50impl StepConverter for DefaultStepConverter {
51    fn apply_to_yrs_txn(
52        &self,
53        step: &dyn Step,
54        txn: &mut TransactionMut,
55    ) -> Result<StepResult, Box<dyn std::error::Error>> {
56        Ok(StepResult {
57            step_id: uuid::Uuid::new_v4().to_string(),
58            step_name: step.name().to_string(),
59            description: format!("默认处理程序处理未知步骤: {}", step.name()),
60            timestamp: std::time::SystemTime::now()
61                .duration_since(std::time::UNIX_EPOCH)
62                .unwrap()
63                .as_millis() as u64,
64            client_id: txn
65                .origin()
66                .as_ref()
67                .map(|s| s.to_string())
68                .unwrap_or_default(),
69        })
70    }
71
72    fn name(&self) -> &'static str {
73        "DefaultStepConverter"
74    }
75
76    fn supports(
77        &self,
78        _step: &dyn Step,
79    ) -> bool {
80        true // Default converter supports all types as a fallback.
81    }
82}
83
84/// 节点相关步骤的转换器
85pub struct NodeStepConverter;
86
87impl NodeStepConverter {
88    fn insert_node_data(
89        &self,
90        txn: &mut TransactionMut,
91        nodes_map: &MapRef,
92        node: &Node,
93    ) {
94        let node_data_map =
95            Utils::get_or_create_node_data_map(nodes_map, txn, &node.id);
96        // 插入节点类型
97        node_data_map.insert(txn, "type", node.r#type.clone());
98        // 插入节点属性
99        let attrs_map =
100            node_data_map.insert(txn, "attrs", MapPrelim::<yrs::Any>::new());
101        for (key, value) in node.attrs.iter() {
102            attrs_map.insert(
103                txn,
104                key.clone(),
105                Utils::json_value_to_yrs_any(value),
106            );
107        }
108        // 插入节点内容
109        let content_array = node_data_map.insert(
110            txn,
111            "content",
112            ArrayPrelim::from(Vec::<yrs::Any>::new()),
113        );
114        for child_id in &node.content {
115            content_array
116                .push_back(txn, yrs::Any::String(child_id.clone().into()));
117        }
118        // 插入节点标记
119        let marks_array = node_data_map.insert(
120            txn,
121            "marks",
122            ArrayPrelim::from(Vec::<yrs::Any>::new()),
123        );
124        for mark in &node.marks {
125            Utils::add_mark_to_array(&marks_array, txn, mark);
126        }
127    }
128
129    /// 递归插入节点及其所有子节点
130    fn insert_node_enum_recursive(
131        &self,
132        txn: &mut TransactionMut,
133        nodes_map: &MapRef,
134        node_enum: &mf_model::node_type::NodeEnum,
135    ) {
136        // 插入当前节点
137        self.insert_node_data(txn, nodes_map, &node_enum.0);
138
139        // 递归插入所有子节点
140        for child_enum in &node_enum.1 {
141            self.insert_node_enum_recursive(txn, nodes_map, child_enum);
142        }
143    }
144}
145
146impl StepConverter for NodeStepConverter {
147    fn apply_to_yrs_txn(
148        &self,
149        step: &dyn Step,
150        txn: &mut TransactionMut,
151    ) -> Result<StepResult, Box<dyn std::error::Error>> {
152        let client_id =
153            txn.origin().as_ref().map(|s| s.to_string()).unwrap_or_default();
154
155        if let Some(add_step) = step.downcast_ref::<AddNodeStep>() {
156            let nodes_map = txn.get_or_insert_map("nodes");
157            let all_nodes = &add_step.nodes;
158            let parent_id = add_step.parent_id.clone();
159
160            // 如果parent_id 不是根节点需要 修改 parent_id节点的 content 数组
161            // 获取根节点 id 从 meta 区域
162            let meta_map = txn.get_or_insert_map("meta");
163            let root_id = meta_map.get(txn, "root_id");
164            if let Some(root_id) = root_id
165                && root_id.to_string(txn) != parent_id
166            {
167                let node_data_map = Utils::get_or_create_node_data_map(
168                    &nodes_map, txn, &parent_id,
169                );
170                let content_array =
171                    Utils::get_or_create_content_array(&node_data_map, txn);
172                for node_enum in all_nodes {
173                    content_array.push_back(
174                        txn,
175                        yrs::Any::String(node_enum.0.id.clone().into()),
176                    );
177                }
178            }
179
180            for node_enum in all_nodes {
181                self.insert_node_enum_recursive(txn, &nodes_map, node_enum);
182            }
183
184            return Ok(StepResult {
185                step_id: uuid::Uuid::new_v4().to_string(),
186                step_name: step.name().to_string(),
187                description: format!("添加 {} 个节点", all_nodes.len()),
188                timestamp: std::time::SystemTime::now()
189                    .duration_since(std::time::UNIX_EPOCH)
190                    .unwrap()
191                    .as_millis() as u64,
192                client_id,
193            });
194        } else if let Some(remove_step) = step.downcast_ref::<RemoveNodeStep>()
195        {
196            let nodes_map = txn.get_or_insert_map("nodes");
197            for node_id in &remove_step.node_ids {
198                nodes_map.remove(txn, &node_id.to_string());
199            }
200
201            return Ok(StepResult {
202                step_id: uuid::Uuid::new_v4().to_string(),
203                step_name: step.name().to_string(),
204                description: format!(
205                    "Removed {} nodes",
206                    remove_step.node_ids.len()
207                ),
208                timestamp: std::time::SystemTime::now()
209                    .duration_since(std::time::UNIX_EPOCH)
210                    .unwrap()
211                    .as_millis() as u64,
212                client_id,
213            });
214        }
215
216        Err("不支持的节点操作".into())
217    }
218
219    fn name(&self) -> &'static str {
220        "NodeStepConverter"
221    }
222
223    fn supports(
224        &self,
225        step: &dyn Step,
226    ) -> bool {
227        step.type_id() == TypeId::of::<AddNodeStep>()
228            || step.type_id() == TypeId::of::<RemoveNodeStep>()
229    }
230}
231
232/// 属性相关步骤的转换器
233pub struct AttrStepConverter;
234
235impl StepConverter for AttrStepConverter {
236    fn apply_to_yrs_txn(
237        &self,
238        step: &dyn Step,
239        txn: &mut TransactionMut,
240    ) -> Result<StepResult, Box<dyn std::error::Error>> {
241        let client_id =
242            txn.origin().as_ref().map(|s| s.to_string()).unwrap_or_default();
243        if let Some(attr_step) = step.downcast_ref::<AttrStep>() {
244            let nodes_map = txn.get_or_insert_map("nodes");
245            let node_data_map = Utils::get_or_create_node_data_map(
246                &nodes_map,
247                txn,
248                &attr_step.id,
249            );
250            // 获取或创建节点属性映射
251            let attrs_map =
252                Utils::get_or_create_node_attrs_map(&node_data_map, txn);
253            // 更新节点属性
254            for (key, value) in attr_step.values.iter() {
255                attrs_map.insert(
256                    txn,
257                    key.clone(),
258                    Utils::json_value_to_yrs_any(value),
259                );
260            }
261
262            Ok(StepResult {
263                step_id: uuid::Uuid::new_v4().to_string(),
264                step_name: step.name().to_string(),
265                description: format!(
266                    "更新 {} 个属性 for node {}",
267                    attr_step.values.len(),
268                    attr_step.id
269                ),
270                timestamp: std::time::SystemTime::now()
271                    .duration_since(std::time::UNIX_EPOCH)
272                    .unwrap()
273                    .as_millis() as u64,
274                client_id,
275            })
276        } else {
277            Err("不支持的属性操作".into())
278        }
279    }
280
281    fn name(&self) -> &'static str {
282        "AttrStepConverter"
283    }
284
285    fn supports(
286        &self,
287        step: &dyn Step,
288    ) -> bool {
289        step.type_id() == TypeId::of::<AttrStep>()
290    }
291}
292
293/// 标记相关步骤的转换器
294pub struct MarkStepConverter;
295
296impl MarkStepConverter {
297    /// 从 Yrs 数组中删除标记
298    fn remove_mark_from_array(
299        &self,
300        marks_array: &ArrayRef,
301        txn: &mut TransactionMut,
302        mark_type_to_remove: &str,
303    ) {
304        let len = marks_array.len(txn);
305        for i in (0..len).rev() {
306            if let Some(Value::YMap(mark_map)) = marks_array.get(txn, i) {
307                if let Some(mark_type_value) = mark_map.get(txn, "type") {
308                    let mark_type = match mark_type_value {
309                        Value::YText(_text_ref) => {
310                            // For now, skip text refs as we can't easily extract string
311                            continue;
312                        },
313                        Value::Any(any) => any.to_string(),
314                        _ => continue,
315                    };
316                    if mark_type == mark_type_to_remove {
317                        marks_array.remove(txn, i);
318                        return;
319                    }
320                }
321            }
322        }
323    }
324}
325
326impl StepConverter for MarkStepConverter {
327    fn apply_to_yrs_txn(
328        &self,
329        step: &dyn Step,
330        txn: &mut TransactionMut,
331    ) -> Result<StepResult, Box<dyn std::error::Error>> {
332        let client_id =
333            txn.origin().as_ref().map(|s| s.to_string()).unwrap_or_default();
334
335        if let Some(add_mark_step) = step.downcast_ref::<AddMarkStep>() {
336            let nodes_map = txn.get_or_insert_map("nodes");
337            // 获取或创建节点数据映射
338            let node_data_map = Utils::get_or_create_node_data_map(
339                &nodes_map,
340                txn,
341                &add_mark_step.id,
342            );
343            // 获取或创建标记数组
344            let marks_array =
345                Utils::get_or_create_marks_array(&node_data_map, txn);
346            // 添加标记
347            for mark in &add_mark_step.marks {
348                Utils::add_mark_to_array(&marks_array, txn, mark);
349            }
350
351            return Ok(StepResult {
352                step_id: uuid::Uuid::new_v4().to_string(),
353                step_name: step.name().to_string(),
354                description: format!(
355                    "添加 {} 个标记 to node {}",
356                    add_mark_step.marks.len(),
357                    add_mark_step.id
358                ),
359                timestamp: std::time::SystemTime::now()
360                    .duration_since(std::time::UNIX_EPOCH)
361                    .unwrap()
362                    .as_millis() as u64,
363                client_id,
364            });
365        } else if let Some(remove_mark_step) =
366            step.downcast_ref::<RemoveMarkStep>()
367        {
368            let nodes_map = txn.get_or_insert_map("nodes");
369            let node_data_map = Utils::get_or_create_node_data_map(
370                &nodes_map,
371                txn,
372                &remove_mark_step.id,
373            );
374            let marks_array =
375                Utils::get_or_create_marks_array(&node_data_map, txn);
376            // 删除标记
377            for mark_type in &remove_mark_step.mark_types {
378                self.remove_mark_from_array(&marks_array, txn, mark_type);
379            }
380
381            return Ok(StepResult {
382                step_id: uuid::Uuid::new_v4().to_string(),
383                step_name: step.name().to_string(),
384                description: format!(
385                    "Removed {} marks from node {}",
386                    remove_mark_step.mark_types.len(),
387                    remove_mark_step.id
388                ),
389                timestamp: std::time::SystemTime::now()
390                    .duration_since(std::time::UNIX_EPOCH)
391                    .unwrap()
392                    .as_millis() as u64,
393                client_id,
394            });
395        }
396
397        Err("不支持的标记操作".into())
398    }
399
400    fn name(&self) -> &'static str {
401        "MarkStepConverter"
402    }
403
404    fn supports(
405        &self,
406        step: &dyn Step,
407    ) -> bool {
408        step.type_id() == TypeId::of::<AddMarkStep>()
409            || step.type_id() == TypeId::of::<RemoveMarkStep>()
410    }
411}
412
413/// 所有步骤转换器的注册表
414pub struct StepConverterRegistry {
415    converters: Vec<Box<dyn StepConverter>>,
416}
417
418impl Default for StepConverterRegistry {
419    fn default() -> Self {
420        Self::new()
421    }
422}
423
424impl StepConverterRegistry {
425    /// 创建一个新的注册表,包含所有默认的转换器
426    pub fn new() -> Self {
427        let mut registry = Self { converters: Vec::new() };
428
429        registry.register(Box::new(NodeStepConverter));
430        registry.register(Box::new(AttrStepConverter));
431        registry.register(Box::new(MarkStepConverter));
432        registry.register(Box::new(DefaultStepConverter));
433
434        registry
435    }
436
437    /// 注册一个新的转换器
438    pub fn register(
439        &mut self,
440        converter: Box<dyn StepConverter>,
441    ) {
442        tracing::info!("🔄 注册步骤转换器: {}", converter.name());
443        self.converters.push(converter);
444    }
445
446    /// 查找支持给定步骤的转换器
447    pub fn find_converter(
448        &self,
449        step: &dyn Step,
450    ) -> Option<&(dyn StepConverter)> {
451        for converter in &self.converters {
452            if converter.supports(step) {
453                return Some(converter.as_ref());
454            }
455        }
456        None
457    }
458}
459
460/// 全局映射器,用于处理转换
461#[derive(Debug)]
462pub struct Mapper;
463
464impl Mapper {
465    /// Gets the global singleton instance of the converter registry.
466    pub fn global_registry() -> &'static StepConverterRegistry {
467        use std::sync::OnceLock;
468        static REGISTRY: OnceLock<StepConverterRegistry> = OnceLock::new();
469        REGISTRY.get_or_init(StepConverterRegistry::new)
470    }
471
472
473    /// 获取 Yrs 文档的版本信息
474    pub fn get_yrs_doc_version(doc: &yrs::Doc) -> u64 {
475        let txn = doc.transact();
476        txn.state_vector().len() as u64
477    }
478
479    /// 检查 Yrs 文档是否为空
480    pub fn is_yrs_doc_empty(doc: &yrs::Doc) -> bool {
481        let txn = doc.transact();
482        let nodes_map = txn.get_map("nodes");
483        nodes_map.map_or(true, |map| map.len(&txn) == 0)
484    }
485}