Skip to main content

mocra_core/engine/task/
assembler.rs

1#![allow(unused)]
2use crate::common::interface::ModuleTrait;
3use crate::common::model::ModuleConfig;
4#[cfg(feature = "store")]
5use crate::common::model::entity::*;
6#[cfg(feature = "store")]
7use crate::common::model::entity::{
8    RelModuleDataMiddlewareModel, RelModuleDownloadMiddlewareModel,
9};
10use std::collections::HashMap;
11use std::path::{Path, PathBuf};
12use std::sync::Arc;
13
14/// Builds module configuration objects from database entities and relations.
15#[cfg(feature = "store")]
16pub struct ConfigAssembler;
17
18#[cfg(feature = "store")]
19impl ConfigAssembler {
20    /// Builds a relation config map for middleware-like entities.
21    pub fn build_relation_config<T, F, G>(
22        relations: &[T],
23        entities: &[G],
24        extract_entity_id: F,
25        extract_name: fn(&G) -> &str,
26    ) -> HashMap<String, serde_json::Value>
27    where
28        T: AsRef<RelModuleDataMiddlewareModel> + AsRef<RelModuleDownloadMiddlewareModel>,
29        F: Fn(&T) -> i32,
30        G: Clone,
31    {
32        let config_map = HashMap::new();
33        for relation in relations {
34            let entity_id = extract_entity_id(relation);
35            if let Some(entity) = entities.iter().find(|e| {
36                // Generic ID matching is intentionally left as a placeholder.
37                let _ = entity_id;
38                false
39            }) {
40                let name = extract_name(entity);
41                let _ = name;
42            }
43        }
44        config_map
45    }
46
47    /// Builds relation config map for data middleware.
48    pub fn build_data_middleware_relation_config(
49        relations: &[RelModuleDataMiddlewareModel],
50        middlewares: &[DataMiddlewareModel],
51    ) -> HashMap<String, serde_json::Value> {
52        let mut config_map = HashMap::new();
53        for relation in relations {
54            if let Some(middleware) = middlewares
55                .iter()
56                .find(|m| m.id == relation.data_middleware_id)
57            {
58                config_map.insert(middleware.name.clone(), relation.config.clone());
59            }
60        }
61        config_map
62    }
63
64    /// Builds relation config map for download middleware.
65    pub fn build_download_middleware_relation_config(
66        relations: &[RelModuleDownloadMiddlewareModel],
67        middlewares: &[DownloadMiddlewareModel],
68    ) -> HashMap<String, serde_json::Value> {
69        let mut config_map = HashMap::new();
70        for relation in relations {
71            if let Some(middleware) = middlewares
72                .iter()
73                .find(|m| m.id == relation.download_middleware_id)
74            {
75                config_map.insert(middleware.name.clone(), relation.config.clone());
76            }
77        }
78        config_map
79    }
80
81    /// Builds base middleware config map (`name -> config`).
82    pub fn build_middleware_base_config<T: HasNameAndConfig>(
83        middlewares: &[T],
84    ) -> HashMap<String, serde_json::Value> {
85        middlewares
86            .iter()
87            .map(|m| (m.name().clone(), m.config().clone()))
88            .collect()
89    }
90
91    /// Assembles the complete `ModuleConfig` from account/platform/module entities.
92    #[allow(clippy::too_many_arguments)]
93    pub fn assemble_module_config(
94        account: &AccountModel,
95        platform: &PlatformModel,
96        module: &ModuleModel,
97        rel_account_platform: &RelAccountPlatformModel,
98        rel_module_platform: &RelModulePlatformModel,
99        rel_module_account: &RelModuleAccountModel,
100        data_middleware: &[DataMiddlewareModel],
101        download_middleware: &[DownloadMiddlewareModel],
102        rel_module_data_middleware: &[RelModuleDataMiddlewareModel],
103        rel_module_download_middleware: &[RelModuleDownloadMiddlewareModel],
104    ) -> ModuleConfig {
105        let data_middleware_config = Self::build_middleware_base_config(data_middleware);
106        let download_middleware_config = Self::build_middleware_base_config(download_middleware);
107        let rel_module_data_middleware_config = Self::build_data_middleware_relation_config(
108            rel_module_data_middleware,
109            data_middleware,
110        );
111        let rel_module_download_middleware_config = Self::build_download_middleware_relation_config(
112            rel_module_download_middleware,
113            download_middleware,
114        );
115
116        ModuleConfig {
117            account_config: account.config.clone(),
118            platform_config: platform.config.clone(),
119            module_config: module.config.clone(),
120            data_middleware_config,
121            download_middleware_config,
122            rel_account_platform_config: rel_account_platform.config.clone(),
123            rel_module_account_config: rel_module_account.config.clone(),
124            rel_module_platform_config: rel_module_platform.config.clone(),
125            rel_module_data_middleware_config,
126            rel_module_download_middleware_config,
127        }
128    }
129}
130
131/// Shared abstraction for entities exposing a name and config payload.
132#[cfg(feature = "store")]
133pub trait HasNameAndConfig {
134    fn name(&self) -> &String;
135    fn config(&self) -> &serde_json::Value;
136}
137
138#[cfg(feature = "store")]
139impl HasNameAndConfig for DataMiddlewareModel {
140    fn name(&self) -> &String {
141        &self.name
142    }
143
144    fn config(&self) -> &serde_json::Value {
145        &self.config
146    }
147}
148
149#[cfg(feature = "store")]
150impl HasNameAndConfig for DownloadMiddlewareModel {
151    fn name(&self) -> &String {
152        &self.name
153    }
154
155    fn config(&self) -> &serde_json::Value {
156        &self.config
157    }
158}
159
160pub struct ModuleItem {
161    pub module: Arc<dyn ModuleTrait>,
162    pub origin: Option<PathBuf>,
163}
164impl From<Arc<dyn ModuleTrait>> for ModuleItem {
165    fn from(value: Arc<dyn ModuleTrait>) -> Self {
166        Self {
167            module: value,
168            origin: None,
169        }
170    }
171}
172
173/// Registry-like assembler for loaded module implementations.
174pub struct ModuleAssembler {
175    modules: HashMap<String, ModuleItem>,
176}
177
178impl ModuleAssembler {
179    pub fn new() -> Self {
180        Self {
181            modules: HashMap::new(),
182        }
183    }
184
185    /// Registers a module implementation by its name.
186    pub fn register_module(&mut self, module: Arc<dyn ModuleTrait>) {
187        self.modules.insert(module.name().clone(), module.into());
188    }
189    pub fn remove_module(&mut self, name: &str) {
190        self.modules.remove(name);
191    }
192    pub fn remove_by_origin(&mut self, origin: &Path) {
193        self.modules
194            .retain(|_, w| w.origin.as_deref().map(|p| p != origin).unwrap_or(true));
195    }
196    pub fn module_names(&self) -> Vec<String> {
197        self.modules.keys().cloned().collect()
198    }
199    pub fn set_origin(&mut self, names: &[String], origin: &Path) {
200        for n in names {
201            if let Some(item) = self.modules.get_mut(n) {
202                item.origin = Some(origin.to_path_buf());
203            }
204        }
205    }
206    /// Returns a module by name.
207    pub fn get_module(&self, name: &str) -> Option<Arc<dyn ModuleTrait>> {
208        self.modules.get(name).map(|x| x.module.clone())
209    }
210
211    pub fn get_all_modules(&self) -> Vec<Arc<dyn ModuleTrait>> {
212        self.modules.values().map(|x| x.module.clone()).collect()
213    }
214}
215
216impl Default for ModuleAssembler {
217    fn default() -> Self {
218        Self::new()
219    }
220}