1use super::*;
2use crate::ast::PdfDocument;
3use crate::plugins::{loader::PluginLoader, registry::PluginRegistry};
4use std::collections::HashMap;
5use std::sync::Arc;
6
7pub struct PluginManager {
9 registry: Arc<PluginRegistry>,
10 loader: PluginLoader,
11 execution_config: ExecutionConfig,
12}
13
14#[derive(Debug, Clone)]
16pub struct ExecutionConfig {
17 pub parallel_execution: bool,
18 pub max_execution_time_ms: Option<u64>,
19 pub max_memory_usage_mb: Option<usize>,
20 pub abort_on_error: bool,
21 pub collect_statistics: bool,
22}
23
24impl Default for ExecutionConfig {
25 fn default() -> Self {
26 Self {
27 parallel_execution: false,
28 max_execution_time_ms: Some(30000), max_memory_usage_mb: Some(512), abort_on_error: true,
31 collect_statistics: true,
32 }
33 }
34}
35
36#[derive(Debug, Clone)]
38pub struct ExecutionSummary {
39 pub total_plugins: usize,
40 pub successful_plugins: usize,
41 pub failed_plugins: usize,
42 pub total_execution_time_ms: u64,
43 pub plugin_results: HashMap<String, PluginResult>,
44 pub statistics: HashMap<String, PluginStatistics>,
45}
46
47impl PluginManager {
48 pub fn new() -> Self {
50 let registry = Arc::new(PluginRegistry::new());
51 let loader = PluginLoader::new(Arc::clone(®istry));
52
53 Self {
54 registry,
55 loader,
56 execution_config: ExecutionConfig::default(),
57 }
58 }
59
60 pub fn with_config(config: ExecutionConfig) -> Self {
62 let mut manager = Self::new();
63 manager.execution_config = config;
64 manager
65 }
66
67 pub fn register_plugin(&mut self, plugin: Arc<dyn AstPlugin>) -> PluginResult {
69 self.loader.load_plugin(plugin)
70 }
71
72 pub fn load_plugins_from_file<P: AsRef<std::path::Path>>(
74 &mut self,
75 path: P,
76 ) -> Result<Vec<PluginResult>, Box<dyn std::error::Error>> {
77 let content = std::fs::read_to_string(path)?;
78 let config: serde_json::Value = serde_json::from_str(&content)?;
79
80 let plugins_config = config
81 .get("plugins")
82 .and_then(|v| v.as_array())
83 .ok_or("Invalid plugin configuration")?;
84
85 let load_config = crate::plugins::loader::LoadConfig::default();
86 let configs: Vec<serde_json::Value> = plugins_config.to_vec();
87
88 Ok(self.loader.load_plugins(&configs, &load_config))
89 }
90
91 pub fn add_plugin_path<P: AsRef<std::path::Path>>(&mut self, path: P) {
93 self.loader.add_search_path(path);
94 }
95
96 pub fn discover_and_load_plugins(&mut self) -> Vec<PluginResult> {
98 let discovered = self.loader.discover_plugins();
99 let mut results = Vec::new();
100 let load_config = crate::plugins::loader::LoadConfig::default();
101
102 for path in discovered {
103 let result = self.loader.load_from_path(&path, &load_config);
104 results.push(result);
105 }
106
107 results
108 }
109
110 pub fn execute_plugins(&self, document: &mut PdfDocument) -> ExecutionSummary {
112 let start_time = std::time::Instant::now();
113 let plugin_names = self.registry.list_plugins();
114 let mut summary = ExecutionSummary {
115 total_plugins: plugin_names.len(),
116 successful_plugins: 0,
117 failed_plugins: 0,
118 total_execution_time_ms: 0,
119 plugin_results: HashMap::new(),
120 statistics: HashMap::new(),
121 };
122
123 let mut pipeline =
124 PluginPipeline::new().with_parallel_execution(self.execution_config.parallel_execution);
125
126 for name in &plugin_names {
128 if let Some(plugin) = self.registry.get_plugin(name) {
129 pipeline.add_plugin(plugin.clone_plugin());
130 }
131 }
132
133 let results = pipeline.execute(document);
135
136 for (i, result) in results.into_iter().enumerate() {
138 if let Some(plugin_name) = plugin_names.get(i) {
139 match result {
140 PluginResult::Success | PluginResult::Modified(_) => {
141 summary.successful_plugins += 1;
142 }
143 _ => {
144 summary.failed_plugins += 1;
145 }
146 }
147 summary.plugin_results.insert(plugin_name.clone(), result);
148 }
149 }
150
151 if self.execution_config.collect_statistics {
153 summary
154 .statistics
155 .insert("pipeline".to_string(), pipeline.get_statistics().clone());
156 }
157
158 summary.total_execution_time_ms = start_time.elapsed().as_millis() as u64;
159 summary
160 }
161
162 pub fn execute_plugins_by_name(
164 &self,
165 document: &mut PdfDocument,
166 plugin_names: &[String],
167 ) -> ExecutionSummary {
168 let start_time = std::time::Instant::now();
169 let mut summary = ExecutionSummary {
170 total_plugins: plugin_names.len(),
171 successful_plugins: 0,
172 failed_plugins: 0,
173 total_execution_time_ms: 0,
174 plugin_results: HashMap::new(),
175 statistics: HashMap::new(),
176 };
177
178 let mut pipeline =
179 PluginPipeline::new().with_parallel_execution(self.execution_config.parallel_execution);
180
181 for name in plugin_names {
183 if let Some(plugin) = self.registry.get_plugin(name) {
184 pipeline.add_plugin(plugin.clone_plugin());
185 }
186 }
187
188 let results = pipeline.execute(document);
190
191 for (i, result) in results.into_iter().enumerate() {
193 if let Some(plugin_name) = plugin_names.get(i) {
194 match result {
195 PluginResult::Success | PluginResult::Modified(_) => {
196 summary.successful_plugins += 1;
197 }
198 _ => {
199 summary.failed_plugins += 1;
200 }
201 }
202 summary.plugin_results.insert(plugin_name.clone(), result);
203 }
204 }
205
206 summary.total_execution_time_ms = start_time.elapsed().as_millis() as u64;
207 summary
208 }
209
210 pub fn execute_plugins_for_type(
212 &self,
213 document: &mut PdfDocument,
214 node_type: &crate::ast::NodeType,
215 ) -> ExecutionSummary {
216 let start_time = std::time::Instant::now();
217 let plugins = self.registry.get_plugins_for_type(node_type);
218 let mut summary = ExecutionSummary {
219 total_plugins: plugins.len(),
220 successful_plugins: 0,
221 failed_plugins: 0,
222 total_execution_time_ms: 0,
223 plugin_results: HashMap::new(),
224 statistics: HashMap::new(),
225 };
226
227 let mut pipeline =
228 PluginPipeline::new().with_parallel_execution(self.execution_config.parallel_execution);
229
230 for plugin in &plugins {
232 pipeline.add_plugin(plugin.clone_plugin());
233 }
234
235 let results = pipeline.execute(document);
237
238 for (i, result) in results.into_iter().enumerate() {
240 if let Some(plugin) = plugins.get(i) {
241 let plugin_name = plugin.metadata().name.clone();
242 match result {
243 PluginResult::Success | PluginResult::Modified(_) => {
244 summary.successful_plugins += 1;
245 }
246 _ => {
247 summary.failed_plugins += 1;
248 }
249 }
250 summary.plugin_results.insert(plugin_name, result);
251 }
252 }
253
254 summary.total_execution_time_ms = start_time.elapsed().as_millis() as u64;
255 summary
256 }
257
258 pub fn get_plugin_info(&self, name: &str) -> Option<PluginMetadata> {
260 self.registry.get_metadata(name)
261 }
262
263 pub fn list_plugins(&self) -> Vec<PluginMetadata> {
265 self.registry.list_metadata()
266 }
267
268 pub fn list_plugins_by_tag(&self, tag: &str) -> Vec<PluginMetadata> {
270 let plugin_names = self.registry.find_by_tag(tag);
271 plugin_names
272 .into_iter()
273 .filter_map(|name| self.registry.get_metadata(&name))
274 .collect()
275 }
276
277 pub fn validate_dependencies(&self) -> HashMap<String, PluginResult> {
279 let mut results = HashMap::new();
280 let plugin_names = self.registry.list_plugins();
281
282 for name in plugin_names {
283 let result = self.registry.check_dependencies(&name);
284 results.insert(name, result);
285 }
286
287 results
288 }
289
290 pub fn unload_plugin(&mut self, name: &str) -> PluginResult {
292 self.loader.unload_plugin(name)
293 }
294
295 pub fn reload_plugin(&mut self, name: &str) -> PluginResult {
297 let load_config = crate::plugins::loader::LoadConfig::default();
298 self.loader.reload_plugin(name, &load_config)
299 }
300
301 pub fn set_execution_config(&mut self, config: ExecutionConfig) {
303 self.execution_config = config;
304 }
305
306 pub fn get_execution_config(&self) -> &ExecutionConfig {
308 &self.execution_config
309 }
310
311 pub fn registry(&self) -> &PluginRegistry {
313 &self.registry
314 }
315
316 pub fn loader(&self) -> &PluginLoader {
318 &self.loader
319 }
320
321 pub fn loader_mut(&mut self) -> &mut PluginLoader {
323 &mut self.loader
324 }
325}
326
327impl Default for PluginManager {
328 fn default() -> Self {
329 Self::new()
330 }
331}
332
333pub mod convenience {
335 use super::*;
336
337 pub fn execute_plugin(plugin: Arc<dyn AstPlugin>, document: &mut PdfDocument) -> PluginResult {
339 let mut context = PluginContext::new()
340 .with_document(document)
341 .with_graph(&mut document.ast);
342
343 plugin.process_document(document, &mut context)
344 }
345
346 pub fn execute_plugins_sequence(
348 plugins: Vec<Arc<dyn AstPlugin>>,
349 document: &mut PdfDocument,
350 ) -> Vec<PluginResult> {
351 let mut results = Vec::new();
352 let mut context = PluginContext::new()
353 .with_document(document)
354 .with_graph(&mut document.ast);
355
356 for plugin in plugins {
357 let result = plugin.process_document(document, &mut context);
358 results.push(result);
359 }
360
361 results
362 }
363
364 pub fn create_default_manager() -> PluginManager {
366 let mut manager = PluginManager::new();
367
368 let basic_validator = Arc::new(super::loader::BasicValidatorPlugin::new());
370 let basic_transformer = Arc::new(super::loader::BasicTransformerPlugin::new());
371
372 let _ = manager.register_plugin(basic_validator);
373 let _ = manager.register_plugin(basic_transformer);
374
375 manager
376 }
377}
378
379#[derive(Debug, Clone)]
381pub enum PluginExecutionError {
382 PluginNotFound(String),
383 DependencyError(String),
384 ExecutionTimeout,
385 MemoryLimitExceeded,
386 PluginError(String),
387}
388
389impl std::fmt::Display for PluginExecutionError {
390 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
391 match self {
392 PluginExecutionError::PluginNotFound(name) => {
393 write!(f, "Plugin not found: {}", name)
394 }
395 PluginExecutionError::DependencyError(msg) => {
396 write!(f, "Dependency error: {}", msg)
397 }
398 PluginExecutionError::ExecutionTimeout => {
399 write!(f, "Plugin execution timeout")
400 }
401 PluginExecutionError::MemoryLimitExceeded => {
402 write!(f, "Plugin memory limit exceeded")
403 }
404 PluginExecutionError::PluginError(msg) => {
405 write!(f, "Plugin error: {}", msg)
406 }
407 }
408 }
409}
410
411impl std::error::Error for PluginExecutionError {}