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
17pub trait StepConverter: Send + Sync {
20 fn apply_to_yrs_txn(
22 &self,
23 step: &dyn Step,
24 txn: &mut TransactionMut,
25 ) -> Result<StepResult, Box<dyn std::error::Error>>;
26 fn apply_yrs_to_step(&self) {}
28
29 fn name(&self) -> &'static str;
31
32 fn supports(
34 &self,
35 step: &dyn Step,
36 ) -> bool;
37
38 fn get_description(
40 &self,
41 step: &dyn Step,
42 ) -> String {
43 format!("Executing operation: {} ({})", step.name(), self.name())
44 }
45}
46
47pub 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 }
82}
83
84pub 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 node_data_map.insert(txn, "type", node.r#type.clone());
98 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 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 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 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 self.insert_node_data(txn, nodes_map, &node_enum.0);
138
139 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 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
232pub 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 let attrs_map =
252 Utils::get_or_create_node_attrs_map(&node_data_map, txn);
253 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
293pub struct MarkStepConverter;
295
296impl MarkStepConverter {
297 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 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 let node_data_map = Utils::get_or_create_node_data_map(
339 &nodes_map,
340 txn,
341 &add_mark_step.id,
342 );
343 let marks_array =
345 Utils::get_or_create_marks_array(&node_data_map, txn);
346 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 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
413pub 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 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 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 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#[derive(Debug)]
462pub struct Mapper;
463
464impl Mapper {
465 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 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 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}