mf_core/
extension_manager.rs1use std::sync::Arc;
2use std::time::Instant;
3
4use mf_model::schema::Schema;
5use mf_state::{ops::GlobalResourceManager, plugin::Plugin};
6
7use crate::{
8 helpers::get_schema_by_resolved_extensions::get_schema_by_resolved_extensions,
9 metrics, types::Extensions, ForgeResult, XmlSchemaParser,
10};
11pub struct ExtensionManager {
13 plugins: Vec<Arc<Plugin>>,
14 schema: Arc<Schema>,
15 op_fns: Vec<
16 Arc<dyn Fn(&GlobalResourceManager) -> ForgeResult<()> + Send + Sync>,
17 >,
18}
19#[derive(Default)]
23pub struct ExtensionManagerBuilder {
24 extensions: Vec<Extensions>,
25 xml_files: Vec<String>,
26 xml_contents: Vec<String>,
27}
28
29impl ExtensionManagerBuilder {
30 pub fn new() -> Self {
32 Self::default()
33 }
34
35 pub fn add_extension(mut self, extension: Extensions) -> Self {
51 self.extensions.push(extension);
52 self
53 }
54
55 pub fn add_extensions(mut self, extensions: Vec<Extensions>) -> Self {
60 self.extensions.extend(extensions);
61 self
62 }
63
64 pub fn add_xml_file<P: AsRef<str>>(mut self, xml_file_path: P) -> Self {
79 self.xml_files.push(xml_file_path.as_ref().to_string());
80 self
81 }
82
83 pub fn add_xml_files<P: AsRef<str>>(mut self, xml_file_paths: &[P]) -> Self {
88 for path in xml_file_paths {
89 self.xml_files.push(path.as_ref().to_string());
90 }
91 self
92 }
93
94 pub fn add_xml_content<S: AsRef<str>>(mut self, xml_content: S) -> Self {
119 self.xml_contents.push(xml_content.as_ref().to_string());
120 self
121 }
122
123 pub fn add_xml_contents<S: AsRef<str>>(mut self, xml_contents: &[S]) -> Self {
128 for content in xml_contents {
129 self.xml_contents.push(content.as_ref().to_string());
130 }
131 self
132 }
133
134 pub fn build(self) -> ForgeResult<ExtensionManager> {
139 let start_time = Instant::now();
140 let mut all_extensions = self.extensions;
141
142 for xml_file in &self.xml_files {
144 let extensions = XmlSchemaParser::parse_multi_file_to_extensions(xml_file)
145 .map_err(|e| crate::error::error_utils::config_error(
146 format!("解析XML文件 {} 失败: {}", xml_file, e)
147 ))?;
148 all_extensions.extend(extensions);
149 }
150
151 for xml_content in &self.xml_contents {
153 let extensions = XmlSchemaParser::parse_to_extensions(xml_content)
154 .map_err(|e| crate::error::error_utils::config_error(
155 format!("解析XML内容失败: {}", e)
156 ))?;
157 all_extensions.extend(extensions);
158 }
159
160 metrics::xml_parsing_duration(start_time.elapsed());
161
162 ExtensionManager::new(&all_extensions)
164 }
165}
166
167impl ExtensionManager {
168 pub fn builder() -> ExtensionManagerBuilder {
179 ExtensionManagerBuilder::new()
180 }
181
182 pub fn new(extensions: &Vec<Extensions>) -> ForgeResult<Self> {
183 let start_time = Instant::now();
184 let schema = Arc::new(get_schema_by_resolved_extensions(extensions)?);
185 let mut plugins = vec![];
186 let mut op_fns = vec![];
187 let mut extension_count = 0;
188 let mut plugin_count = 0;
189 for extension in extensions {
190 if let Extensions::E(extension) = extension {
191 extension_count += 1;
192 for plugin in extension.get_plugins() {
193 plugin_count += 1;
194 plugins.push(plugin.clone());
195 }
196 for op_fn in extension.get_op_fns() {
197 op_fns.push(op_fn.clone());
198 }
199 }
200 }
201
202 metrics::extensions_loaded(extension_count);
203 metrics::plugins_loaded(plugin_count);
204 metrics::extension_manager_creation_duration(start_time.elapsed());
205
206 Ok(ExtensionManager { schema, plugins, op_fns })
207 }
208
209 pub fn from_xml_file(xml_file_path: &str) -> ForgeResult<Self> {
224 Self::builder()
225 .add_xml_file(xml_file_path)
226 .build()
227 }
228
229 pub fn from_xml_string(xml_content: &str) -> ForgeResult<Self> {
255 Self::builder()
256 .add_xml_content(xml_content)
257 .build()
258 }
259
260 pub fn from_xml_files(xml_file_paths: &[&str]) -> ForgeResult<Self> {
281 Self::builder()
282 .add_xml_files(xml_file_paths)
283 .build()
284 }
285
286 pub fn from_mixed_sources(
308 extensions: &[Extensions],
309 xml_file_paths: &[&str]
310 ) -> ForgeResult<Self> {
311 Self::builder()
312 .add_extensions(extensions.to_vec())
313 .add_xml_files(xml_file_paths)
314 .build()
315 }
316 pub fn get_op_fns(
317 &self
318 ) -> &Vec<
319 Arc<dyn Fn(&GlobalResourceManager) -> ForgeResult<()> + Send + Sync>,
320 > {
321 &self.op_fns
322 }
323
324 pub fn get_schema(&self) -> Arc<Schema> {
325 self.schema.clone()
326 }
327 pub fn get_plugins(&self) -> &Vec<Arc<Plugin>> {
328 &self.plugins
329 }
330
331 pub fn add_extensions(&mut self, new_extensions: Vec<Extensions>) -> ForgeResult<()> {
350 let mut all_extensions = Vec::new();
352
353 for (name, node_type) in &self.schema.nodes {
356 let node = crate::node::Node::create(name, node_type.spec.clone());
357 all_extensions.push(Extensions::N(node));
358 }
359
360 for (name, mark_type) in &self.schema.marks {
361 let mark = crate::mark::Mark::new(name, mark_type.spec.clone());
362 all_extensions.push(Extensions::M(mark));
363 }
364
365 all_extensions.extend(new_extensions);
367
368 let new_manager = Self::new(&all_extensions)?;
370
371 self.schema = new_manager.schema;
373 self.plugins = new_manager.plugins;
374 self.op_fns = new_manager.op_fns;
375
376 Ok(())
377 }
378
379 pub fn add_xml_file(&mut self, xml_file_path: &str) -> ForgeResult<()> {
387 let extensions = XmlSchemaParser::parse_multi_file_to_extensions(xml_file_path)
388 .map_err(|e| crate::error::error_utils::config_error(
389 format!("解析XML文件 {} 失败: {}", xml_file_path, e)
390 ))?;
391
392 self.add_extensions(extensions)
393 }
394
395 pub fn add_xml_content(&mut self, xml_content: &str) -> ForgeResult<()> {
403 let extensions = XmlSchemaParser::parse_to_extensions(xml_content)
404 .map_err(|e| crate::error::error_utils::config_error(
405 format!("解析XML内容失败: {}", e)
406 ))?;
407
408 self.add_extensions(extensions)
409 }
410}
411
412#[cfg(test)]
413mod tests {
414 use super::*;
415
416 #[test]
417 fn test_extension_manager_from_xml_string() {
418 let xml = r#"
419 <?xml version="1.0" encoding="UTF-8"?>
420 <schema top_node="doc">
421 <nodes>
422 <node name="doc" group="block">
423 <desc>文档根节点</desc>
424 <content>paragraph+</content>
425 </node>
426 <node name="paragraph" group="block">
427 <desc>段落节点</desc>
428 <content>text*</content>
429 <marks>strong</marks>
430 </node>
431 <node name="text">
432 <desc>文本节点</desc>
433 </node>
434 </nodes>
435 <marks>
436 <mark name="strong" group="formatting">
437 <desc>粗体标记</desc>
438 <spanning>true</spanning>
439 </mark>
440 </marks>
441 </schema>
442 "#;
443
444 let result = ExtensionManager::from_xml_string(xml);
445 assert!(result.is_ok());
446
447 let manager = result.unwrap();
448 let schema = manager.get_schema();
449
450 assert_eq!(schema.nodes.len(), 3);
452 assert_eq!(schema.marks.len(), 1);
453 assert!(schema.nodes.contains_key("doc"));
454 assert!(schema.nodes.contains_key("paragraph"));
455 assert!(schema.nodes.contains_key("text"));
456 assert!(schema.marks.contains_key("strong"));
457 }
458
459 #[test]
460 fn test_extension_manager_from_xml_files() {
461 let temp_dir = std::env::temp_dir().join("extension_manager_test");
463 std::fs::create_dir_all(&temp_dir).unwrap();
464
465 let base_nodes_content = r#"
467 <?xml version="1.0" encoding="UTF-8"?>
468 <schema>
469 <nodes>
470 <node name="doc" group="block">
471 <desc>文档根节点</desc>
472 <content>paragraph+</content>
473 </node>
474 <node name="paragraph" group="block">
475 <desc>段落节点</desc>
476 <content>text*</content>
477 </node>
478 <node name="text">
479 <desc>文本节点</desc>
480 </node>
481 </nodes>
482 </schema>
483 "#;
484
485 let base_nodes_path = temp_dir.join("base-nodes.xml");
486 std::fs::write(&base_nodes_path, base_nodes_content).unwrap();
487
488 let marks_content = r#"
490 <?xml version="1.0" encoding="UTF-8"?>
491 <schema>
492 <marks>
493 <mark name="strong" group="formatting">
494 <desc>粗体标记</desc>
495 <spanning>true</spanning>
496 </mark>
497 <mark name="em" group="formatting">
498 <desc>斜体标记</desc>
499 <spanning>true</spanning>
500 </mark>
501 </marks>
502 </schema>
503 "#;
504
505 let marks_path = temp_dir.join("marks.xml");
506 std::fs::write(&marks_path, marks_content).unwrap();
507
508 let files = vec![
510 base_nodes_path.to_str().unwrap(),
511 marks_path.to_str().unwrap(),
512 ];
513
514 let result = ExtensionManager::from_xml_files(&files);
515 assert!(result.is_ok());
516
517 let manager = result.unwrap();
518 let schema = manager.get_schema();
519
520 assert_eq!(schema.nodes.len(), 3); assert_eq!(schema.marks.len(), 2); std::fs::remove_dir_all(&temp_dir).unwrap();
526 }
527
528 #[test]
529 fn test_extension_manager_builder_mixed_sources() {
530 use crate::node::Node;
531 use crate::mark::Mark;
532 use mf_model::node_type::NodeSpec;
533 use mf_model::mark_type::MarkSpec;
534
535 let code_node = Node::create("code_node", NodeSpec::default());
537 let code_mark = Mark::new("code_mark", MarkSpec::default());
538
539 let xml_content = r#"
540 <?xml version="1.0" encoding="UTF-8"?>
541 <schema>
542 <nodes>
543 <node name="xml_node" group="block">
544 <desc>XML定义的节点</desc>
545 </node>
546 </nodes>
547 <marks>
548 <mark name="xml_mark" group="formatting">
549 <desc>XML定义的标记</desc>
550 </mark>
551 </marks>
552 </schema>
553 "#;
554
555 let result = ExtensionManager::builder()
557 .add_extension(Extensions::N(code_node))
558 .add_extension(Extensions::M(code_mark))
559 .add_xml_content(xml_content)
560 .build();
561
562 if let Err(ref e) = result {
563 println!("Error: {:?}", e);
564 }
565 assert!(result.is_ok());
566
567 let manager = result.unwrap();
568 let schema = manager.get_schema();
569
570 assert_eq!(schema.nodes.len(), 2); assert_eq!(schema.marks.len(), 2); assert!(schema.nodes.contains_key("code_node"));
575 assert!(schema.nodes.contains_key("xml_node"));
576 assert!(schema.marks.contains_key("code_mark"));
577 assert!(schema.marks.contains_key("xml_mark"));
578 }
579
580 #[test]
581 fn test_dynamic_extension_addition() {
582 use crate::node::Node;
583 use mf_model::node_type::NodeSpec;
584
585 let xml_content = r#"
587 <?xml version="1.0" encoding="UTF-8"?>
588 <schema>
589 <nodes>
590 <node name="initial_node">
591 <desc>初始节点</desc>
592 </node>
593 </nodes>
594 </schema>
595 "#;
596
597 let mut manager = ExtensionManager::from_xml_string(xml_content).unwrap();
598
599 assert_eq!(manager.get_schema().nodes.len(), 1);
601 assert!(manager.get_schema().nodes.contains_key("initial_node"));
602
603 let new_node = Node::create("dynamic_node", NodeSpec::default());
605 let result = manager.add_extensions(vec![Extensions::N(new_node)]);
606 assert!(result.is_ok());
607
608 assert_eq!(manager.get_schema().nodes.len(), 2);
610 assert!(manager.get_schema().nodes.contains_key("initial_node"));
611 assert!(manager.get_schema().nodes.contains_key("dynamic_node"));
612
613 let additional_xml = r#"
615 <?xml version="1.0" encoding="UTF-8"?>
616 <schema>
617 <nodes>
618 <node name="xml_dynamic_node">
619 <desc>动态添加的XML节点</desc>
620 </node>
621 </nodes>
622 </schema>
623 "#;
624
625 let result = manager.add_xml_content(additional_xml);
626 assert!(result.is_ok());
627
628 assert_eq!(manager.get_schema().nodes.len(), 3);
630 assert!(manager.get_schema().nodes.contains_key("initial_node"));
631 assert!(manager.get_schema().nodes.contains_key("dynamic_node"));
632 assert!(manager.get_schema().nodes.contains_key("xml_dynamic_node"));
633 }
634}