use std::sync::Arc;
use std::time::Instant;
use mf_model::schema::Schema;
use mf_state::plugin::Plugin;
use crate::{
helpers::get_schema_by_resolved_extensions::get_schema_by_resolved_extensions,
metrics, types::Extensions, ForgeResult, XmlSchemaParser, extension::OpFn,
};
pub struct ExtensionManager {
plugins: Vec<Arc<Plugin>>,
schema: Arc<Schema>,
op_fns: OpFn,
}
#[derive(Default)]
pub struct ExtensionManagerBuilder {
extensions: Vec<Extensions>,
xml_files: Vec<String>,
xml_contents: Vec<String>,
}
impl ExtensionManagerBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn add_extension(
mut self,
extension: Extensions,
) -> Self {
self.extensions.push(extension);
self
}
pub fn add_extensions(
mut self,
extensions: Vec<Extensions>,
) -> Self {
self.extensions.extend(extensions);
self
}
pub fn add_xml_file<P: AsRef<str>>(
mut self,
xml_file_path: P,
) -> Self {
self.xml_files.push(xml_file_path.as_ref().to_string());
self
}
pub fn add_xml_files<P: AsRef<str>>(
mut self,
xml_file_paths: &[P],
) -> Self {
for path in xml_file_paths {
self.xml_files.push(path.as_ref().to_string());
}
self
}
pub fn add_xml_content<S: AsRef<str>>(
mut self,
xml_content: S,
) -> Self {
self.xml_contents.push(xml_content.as_ref().to_string());
self
}
pub fn add_xml_contents<S: AsRef<str>>(
mut self,
xml_contents: &[S],
) -> Self {
for content in xml_contents {
self.xml_contents.push(content.as_ref().to_string());
}
self
}
pub fn build(self) -> ForgeResult<ExtensionManager> {
let start_time = Instant::now();
let mut all_extensions = self.extensions;
for xml_file in &self.xml_files {
let extensions =
XmlSchemaParser::parse_multi_file_to_extensions(xml_file)
.map_err(|e| {
crate::error::error_utils::config_error(format!(
"解析XML文件 {xml_file} 失败: {e}"
))
})?;
all_extensions.extend(extensions);
}
for xml_content in &self.xml_contents {
let extensions = XmlSchemaParser::parse_to_extensions(xml_content)
.map_err(|e| {
crate::error::error_utils::config_error(format!(
"解析XML内容失败: {e}"
))
})?;
all_extensions.extend(extensions);
}
metrics::xml_parsing_duration(start_time.elapsed());
ExtensionManager::new(&all_extensions)
}
}
impl ExtensionManager {
pub fn builder() -> ExtensionManagerBuilder {
ExtensionManagerBuilder::new()
}
pub fn new(extensions: &Vec<Extensions>) -> ForgeResult<Self> {
let start_time = Instant::now();
let schema = Arc::new(get_schema_by_resolved_extensions(extensions)?);
let mut plugins = vec![];
let mut op_fns = vec![];
let mut extension_count = 0;
let mut plugin_count = 0;
for extension in extensions {
if let Extensions::E(extension) = extension {
extension_count += 1;
for plugin in extension.get_plugins() {
plugin_count += 1;
plugins.push(plugin.clone());
}
for op_fn in extension.get_op_fns() {
op_fns.push(op_fn.clone());
}
}
}
metrics::extensions_loaded(extension_count);
metrics::plugins_loaded(plugin_count);
metrics::extension_manager_creation_duration(start_time.elapsed());
Ok(ExtensionManager { schema, plugins, op_fns })
}
pub fn from_xml_file(xml_file_path: &str) -> ForgeResult<Self> {
Self::builder().add_xml_file(xml_file_path).build()
}
pub fn from_xml_string(xml_content: &str) -> ForgeResult<Self> {
Self::builder().add_xml_content(xml_content).build()
}
pub fn from_xml_files(xml_file_paths: &[&str]) -> ForgeResult<Self> {
Self::builder().add_xml_files(xml_file_paths).build()
}
pub fn from_mixed_sources(
extensions: &[Extensions],
xml_file_paths: &[&str],
) -> ForgeResult<Self> {
Self::builder()
.add_extensions(extensions.to_vec())
.add_xml_files(xml_file_paths)
.build()
}
pub fn get_op_fns(&self) -> &OpFn {
&self.op_fns
}
pub fn get_schema(&self) -> Arc<Schema> {
self.schema.clone()
}
pub fn get_plugins(&self) -> &Vec<Arc<Plugin>> {
&self.plugins
}
pub fn add_restored_plugins(
&mut self,
plugins: Vec<std::sync::Arc<mf_state::plugin::Plugin>>,
) -> ForgeResult<()> {
self.plugins.extend(plugins);
Ok(())
}
}