mf_core/extension_manager/
mod.rs

1use std::sync::Arc;
2use std::time::Instant;
3
4use mf_model::schema::Schema;
5use mf_state::plugin::Plugin;
6
7use crate::{
8    helpers::get_schema_by_resolved_extensions::get_schema_by_resolved_extensions,
9    metrics, types::Extensions, ForgeResult, XmlSchemaParser, extension::OpFn,
10};
11/// 扩展管理器
12pub struct ExtensionManager {
13    plugins: Vec<Arc<Plugin>>,
14    schema: Arc<Schema>,
15    op_fns: OpFn,
16}
17/// ExtensionManager构建器
18///
19/// 提供灵活的方式来配置和创建ExtensionManager,支持多种扩展来源
20#[derive(Default)]
21pub struct ExtensionManagerBuilder {
22    extensions: Vec<Extensions>,
23    xml_files: Vec<String>,
24    xml_contents: Vec<String>,
25}
26
27impl ExtensionManagerBuilder {
28    /// 创建新的构建器
29    pub fn new() -> Self {
30        Self::default()
31    }
32
33    /// 添加代码定义的扩展
34    ///
35    /// # 参数
36    /// * `extension` - 要添加的扩展
37    ///
38    /// # 示例
39    /// ```rust
40    /// use mf_core::{ExtensionManagerBuilder, types::Extensions, node::Node};
41    /// use mf_model::node_type::NodeSpec;
42    ///
43    /// let node = Node::create("custom_node", NodeSpec::default());
44    /// let manager = ExtensionManagerBuilder::new()
45    ///     .add_extension(Extensions::N(node))
46    ///     .build()?;
47    /// ```
48    pub fn add_extension(
49        mut self,
50        extension: Extensions,
51    ) -> Self {
52        self.extensions.push(extension);
53        self
54    }
55
56    /// 批量添加代码定义的扩展
57    ///
58    /// # 参数
59    /// * `extensions` - 要添加的扩展列表
60    pub fn add_extensions(
61        mut self,
62        extensions: Vec<Extensions>,
63    ) -> Self {
64        self.extensions.extend(extensions);
65        self
66    }
67
68    /// 添加XML文件路径
69    ///
70    /// # 参数
71    /// * `xml_file_path` - XML schema文件路径
72    ///
73    /// # 示例
74    /// ```rust
75    /// use mf_core::ExtensionManagerBuilder;
76    ///
77    /// let manager = ExtensionManagerBuilder::new()
78    ///     .add_xml_file("./schemas/base-nodes.xml")
79    ///     .add_xml_file("./schemas/custom-marks.xml")
80    ///     .build()?;
81    /// ```
82    pub fn add_xml_file<P: AsRef<str>>(
83        mut self,
84        xml_file_path: P,
85    ) -> Self {
86        self.xml_files.push(xml_file_path.as_ref().to_string());
87        self
88    }
89
90    /// 批量添加XML文件路径
91    ///
92    /// # 参数
93    /// * `xml_file_paths` - XML schema文件路径列表
94    pub fn add_xml_files<P: AsRef<str>>(
95        mut self,
96        xml_file_paths: &[P],
97    ) -> Self {
98        for path in xml_file_paths {
99            self.xml_files.push(path.as_ref().to_string());
100        }
101        self
102    }
103
104    /// 添加XML内容字符串
105    ///
106    /// # 参数
107    /// * `xml_content` - XML schema内容
108    ///
109    /// # 示例
110    /// ```rust
111    /// use mf_core::ExtensionManagerBuilder;
112    ///
113    /// let xml = r#"
114    /// <?xml version="1.0" encoding="UTF-8"?>
115    /// <schema>
116    ///   <nodes>
117    ///     <node name="custom">
118    ///       <desc>自定义节点</desc>
119    ///     </node>
120    ///   </nodes>
121    /// </schema>
122    /// "#;
123    ///
124    /// let manager = ExtensionManagerBuilder::new()
125    ///     .add_xml_content(xml)
126    ///     .build()?;
127    /// ```
128    pub fn add_xml_content<S: AsRef<str>>(
129        mut self,
130        xml_content: S,
131    ) -> Self {
132        self.xml_contents.push(xml_content.as_ref().to_string());
133        self
134    }
135
136    /// 批量添加XML内容字符串
137    ///
138    /// # 参数
139    /// * `xml_contents` - XML schema内容列表
140    pub fn add_xml_contents<S: AsRef<str>>(
141        mut self,
142        xml_contents: &[S],
143    ) -> Self {
144        for content in xml_contents {
145            self.xml_contents.push(content.as_ref().to_string());
146        }
147        self
148    }
149
150    /// 构建ExtensionManager
151    ///
152    /// # 返回值
153    /// * `ForgeResult<ExtensionManager>` - 构建的ExtensionManager实例或错误
154    pub fn build(self) -> ForgeResult<ExtensionManager> {
155        let start_time = Instant::now();
156        let mut all_extensions = self.extensions;
157
158        // 解析XML文件
159        for xml_file in &self.xml_files {
160            let extensions =
161                XmlSchemaParser::parse_multi_file_to_extensions(xml_file)
162                    .map_err(|e| {
163                        crate::error::error_utils::config_error(format!(
164                            "解析XML文件 {xml_file} 失败: {e}"
165                        ))
166                    })?;
167            all_extensions.extend(extensions);
168        }
169
170        // 解析XML内容
171        for xml_content in &self.xml_contents {
172            let extensions = XmlSchemaParser::parse_to_extensions(xml_content)
173                .map_err(|e| {
174                    crate::error::error_utils::config_error(format!(
175                        "解析XML内容失败: {e}"
176                    ))
177                })?;
178            all_extensions.extend(extensions);
179        }
180
181        metrics::xml_parsing_duration(start_time.elapsed());
182
183        // 创建ExtensionManager
184        ExtensionManager::new(&all_extensions)
185    }
186}
187
188impl ExtensionManager {
189    /// 创建ExtensionManager构建器
190    ///
191    /// # 示例
192    /// ```rust
193    /// use mf_core::ExtensionManager;
194    ///
195    /// let manager = ExtensionManager::builder()
196    ///     .add_xml_file("./schemas/main.xml")
197    ///     .build()?;
198    /// ```
199    pub fn builder() -> ExtensionManagerBuilder {
200        ExtensionManagerBuilder::new()
201    }
202
203    pub fn new(extensions: &Vec<Extensions>) -> ForgeResult<Self> {
204        let start_time = Instant::now();
205        let schema = Arc::new(get_schema_by_resolved_extensions(extensions)?);
206        let mut plugins = vec![];
207        let mut op_fns = vec![];
208        let mut extension_count = 0;
209        let mut plugin_count = 0;
210        for extension in extensions {
211            if let Extensions::E(extension) = extension {
212                extension_count += 1;
213                for plugin in extension.get_plugins() {
214                    plugin_count += 1;
215                    plugins.push(plugin.clone());
216                }
217                for op_fn in extension.get_op_fns() {
218                    op_fns.push(op_fn.clone());
219                }
220            }
221        }
222
223        metrics::extensions_loaded(extension_count);
224        metrics::plugins_loaded(plugin_count);
225        metrics::extension_manager_creation_duration(start_time.elapsed());
226
227        Ok(ExtensionManager { schema, plugins, op_fns })
228    }
229
230    /// 从XML文件创建ExtensionManager(便捷方法)
231    ///
232    /// # 参数
233    /// * `xml_file_path` - XML schema文件路径
234    ///
235    /// # 返回值
236    /// * `ForgeResult<Self>` - 返回ExtensionManager实例或错误
237    ///
238    /// # 示例
239    /// ```rust
240    /// use mf_core::ExtensionManager;
241    ///
242    /// let manager = ExtensionManager::from_xml_file("./schemas/main.xml")?;
243    /// ```
244    pub fn from_xml_file(xml_file_path: &str) -> ForgeResult<Self> {
245        Self::builder().add_xml_file(xml_file_path).build()
246    }
247
248    /// 从XML字符串创建ExtensionManager(便捷方法)
249    ///
250    /// # 参数
251    /// * `xml_content` - XML schema内容字符串
252    ///
253    /// # 返回值
254    /// * `ForgeResult<Self>` - 返回ExtensionManager实例或错误
255    ///
256    /// # 示例
257    /// ```rust
258    /// use mf_core::ExtensionManager;
259    ///
260    /// let xml = r#"
261    /// <?xml version="1.0" encoding="UTF-8"?>
262    /// <schema top_node="doc">
263    ///   <nodes>
264    ///     <node name="doc">
265    ///       <content>paragraph+</content>
266    ///     </node>
267    ///   </nodes>
268    /// </schema>
269    /// "#;
270    ///
271    /// let manager = ExtensionManager::from_xml_string(xml)?;
272    /// ```
273    pub fn from_xml_string(xml_content: &str) -> ForgeResult<Self> {
274        Self::builder().add_xml_content(xml_content).build()
275    }
276
277    /// 从多个XML文件创建ExtensionManager(便捷方法)
278    ///
279    /// # 参数
280    /// * `xml_file_paths` - XML schema文件路径列表
281    ///
282    /// # 返回值
283    /// * `ForgeResult<Self>` - 返回ExtensionManager实例或错误
284    ///
285    /// # 示例
286    /// ```rust
287    /// use mf_core::ExtensionManager;
288    ///
289    /// let files = vec![
290    ///     "./schemas/base-nodes.xml",
291    ///     "./schemas/formatting-marks.xml",
292    ///     "./schemas/custom-extensions.xml"
293    /// ];
294    ///
295    /// let manager = ExtensionManager::from_xml_files(&files)?;
296    /// ```
297    pub fn from_xml_files(xml_file_paths: &[&str]) -> ForgeResult<Self> {
298        Self::builder().add_xml_files(xml_file_paths).build()
299    }
300
301    /// 从Extensions和XML文件混合创建ExtensionManager(便捷方法)
302    ///
303    /// # 参数
304    /// * `extensions` - 已有的Extensions列表
305    /// * `xml_file_paths` - 额外的XML schema文件路径列表
306    ///
307    /// # 返回值
308    /// * `ForgeResult<Self>` - 返回ExtensionManager实例或错误
309    ///
310    /// # 示例
311    /// ```rust
312    /// use mf_core::{ExtensionManager, types::Extensions};
313    ///
314    /// let existing_extensions = vec![/* ... */];
315    /// let xml_files = vec!["./schemas/additional.xml"];
316    ///
317    /// let manager = ExtensionManager::from_mixed_sources(
318    ///     &existing_extensions,
319    ///     &xml_files
320    /// )?;
321    /// ```
322    pub fn from_mixed_sources(
323        extensions: &[Extensions],
324        xml_file_paths: &[&str],
325    ) -> ForgeResult<Self> {
326        Self::builder()
327            .add_extensions(extensions.to_vec())
328            .add_xml_files(xml_file_paths)
329            .build()
330    }
331    pub fn get_op_fns(&self) -> &OpFn {
332        &self.op_fns
333    }
334
335    pub fn get_schema(&self) -> Arc<Schema> {
336        self.schema.clone()
337    }
338    pub fn get_plugins(&self) -> &Vec<Arc<Plugin>> {
339        &self.plugins
340    }
341
342    /// 添加从快照恢复的插件
343    pub fn add_restored_plugins(
344        &mut self,
345        plugins: Vec<std::sync::Arc<mf_state::plugin::Plugin>>,
346    ) -> ForgeResult<()> {
347        self.plugins.extend(plugins);
348        Ok(())
349    }
350}
351
352#[cfg(test)]
353mod tests {
354    use super::*;
355
356    #[test]
357    fn test_extension_manager_from_xml_string() {
358        let xml = r#"
359        <?xml version="1.0" encoding="UTF-8"?>
360        <schema top_node="doc">
361          <nodes>
362            <node name="doc" group="block">
363              <desc>文档根节点</desc>
364              <content>paragraph+</content>
365            </node>
366            <node name="paragraph" group="block">
367              <desc>段落节点</desc>
368              <content>text*</content>
369              <marks>strong</marks>
370            </node>
371            <node name="text">
372              <desc>文本节点</desc>
373            </node>
374          </nodes>
375          <marks>
376            <mark name="strong" group="formatting">
377              <desc>粗体标记</desc>
378              <spanning>true</spanning>
379            </mark>
380          </marks>
381        </schema>
382        "#;
383
384        let result = ExtensionManager::from_xml_string(xml);
385        assert!(result.is_ok());
386
387        let manager = result.unwrap();
388        let schema = manager.get_schema();
389
390        // 验证schema结构
391        assert_eq!(schema.nodes.len(), 3);
392        assert_eq!(schema.marks.len(), 1);
393        assert!(schema.nodes.contains_key("doc"));
394        assert!(schema.nodes.contains_key("paragraph"));
395        assert!(schema.nodes.contains_key("text"));
396        assert!(schema.marks.contains_key("strong"));
397    }
398
399    #[test]
400    fn test_extension_manager_from_xml_files() {
401        // 创建临时目录和文件进行测试
402        let temp_dir = std::env::temp_dir().join("extension_manager_test");
403        std::fs::create_dir_all(&temp_dir).unwrap();
404
405        // 创建基础节点文件
406        let base_nodes_content = r#"
407        <?xml version="1.0" encoding="UTF-8"?>
408        <schema>
409          <nodes>
410            <node name="doc" group="block">
411              <desc>文档根节点</desc>
412              <content>paragraph+</content>
413            </node>
414            <node name="paragraph" group="block">
415              <desc>段落节点</desc>
416              <content>text*</content>
417            </node>
418            <node name="text">
419              <desc>文本节点</desc>
420            </node>
421          </nodes>
422        </schema>
423        "#;
424
425        let base_nodes_path = temp_dir.join("base-nodes.xml");
426        std::fs::write(&base_nodes_path, base_nodes_content).unwrap();
427
428        // 创建标记文件
429        let marks_content = r#"
430        <?xml version="1.0" encoding="UTF-8"?>
431        <schema>
432          <marks>
433            <mark name="strong" group="formatting">
434              <desc>粗体标记</desc>
435              <spanning>true</spanning>
436            </mark>
437            <mark name="em" group="formatting">
438              <desc>斜体标记</desc>
439              <spanning>true</spanning>
440            </mark>
441          </marks>
442        </schema>
443        "#;
444
445        let marks_path = temp_dir.join("marks.xml");
446        std::fs::write(&marks_path, marks_content).unwrap();
447
448        // 测试从多个文件创建ExtensionManager
449        let files = vec![
450            base_nodes_path.to_str().unwrap(),
451            marks_path.to_str().unwrap(),
452        ];
453
454        let result = ExtensionManager::from_xml_files(&files);
455        assert!(result.is_ok());
456
457        let manager = result.unwrap();
458        let schema = manager.get_schema();
459
460        // 验证合并后的schema
461        assert_eq!(schema.nodes.len(), 3); // doc, paragraph, text
462        assert_eq!(schema.marks.len(), 2); // strong, em
463
464        // 清理临时文件
465        std::fs::remove_dir_all(&temp_dir).unwrap();
466    }
467
468    #[test]
469    fn test_extension_manager_builder_mixed_sources() {
470        use crate::node::Node;
471        use crate::mark::Mark;
472        use mf_model::node_type::NodeSpec;
473        use mf_model::mark_type::MarkSpec;
474
475        // 创建代码定义的扩展
476        let code_node = Node::create("code_node", NodeSpec::default());
477        let code_mark = Mark::new("code_mark", MarkSpec::default());
478
479        let xml_content = r#"
480        <?xml version="1.0" encoding="UTF-8"?>
481        <schema>
482          <nodes>
483            <node name="xml_node" group="block">
484              <desc>XML定义的节点</desc>
485            </node>
486          </nodes>
487          <marks>
488            <mark name="xml_mark" group="formatting">
489              <desc>XML定义的标记</desc>
490            </mark>
491          </marks>
492        </schema>
493        "#;
494
495        // 使用Builder模式混合不同来源的扩展
496        let result = ExtensionManager::builder()
497            .add_extension(Extensions::N(code_node))
498            .add_extension(Extensions::M(code_mark))
499            .add_xml_content(xml_content)
500            .build();
501
502        if let Err(ref e) = result {
503            println!("Error: {e:?}");
504        }
505        assert!(result.is_ok());
506
507        let manager = result.unwrap();
508        let schema = manager.get_schema();
509
510        // 验证混合后的schema
511        assert_eq!(schema.nodes.len(), 2); // code_node, xml_node
512        assert_eq!(schema.marks.len(), 2); // code_mark, xml_mark
513
514        assert!(schema.nodes.contains_key("code_node"));
515        assert!(schema.nodes.contains_key("xml_node"));
516        assert!(schema.marks.contains_key("code_mark"));
517        assert!(schema.marks.contains_key("xml_mark"));
518    }
519}