Mountain/ApplicationState/State/ExtensionState/ExtensionRegistry/
ExtensionRegistry.rs

1//! # ExtensionRegistry Module (ApplicationState)
2//!
3//! ## RESPONSIBILITIES
4//! Manages extension registry including command registry and provider handle
5//! management. Tracks extension scan paths and enabled proposed APIs.
6//!
7//! ## ARCHITECTURAL ROLE
8//! ExtensionRegistry is part of the **ExtensionState** module, representing
9//! the command registry and provider handle management.
10//!
11//! ## KEY COMPONENTS
12//! - Registry: Main struct containing command registry and provider state
13//! - Default: Initialization implementation
14//! - Helper methods: Registry manipulation utilities
15//!
16//! ## ERROR HANDLING
17//! - Thread-safe access via `Arc<Mutex<...>>`
18//! - Proper lock error handling with `MapLockError` helpers
19//!
20//! ## LOGGING
21//! State changes are logged at appropriate levels (debug, info, warn, error).
22//!
23//! ## PERFORMANCE CONSIDERATIONS
24//! - Lock mutexes briefly and release immediately
25//! - Avoid nested locks to prevent deadlocks
26//! - Use Arc for shared ownership across threads
27//! - Use AtomicU32 for unique provider handles
28//!
29//! ## TODO
30//! - [ ] Add command validation invariants
31//! - [ ] Implement command discovery events
32//! - [ ] Add command metrics collection
33
34use std::{
35	collections::HashMap,
36	path::PathBuf,
37	sync::{
38		Arc,
39		Mutex as StandardMutex,
40		atomic::{AtomicU32, Ordering as AtomicOrdering},
41	},
42};
43
44use tauri::Wry;
45use log::debug;
46
47use crate::Environment::CommandProvider::CommandHandler;
48
49/// Extension registry containing command registry and provider handle state.
50#[derive(Clone)]
51pub struct Registry {
52	/// Registered CLI commands.
53	pub CommandRegistry:Arc<StandardMutex<HashMap<String, CommandHandler<Wry>>>>,
54
55	/// Counter for generating unique provider handles.
56	pub NextProviderHandle:Arc<AtomicU32>,
57
58	/// Paths to scan for extensions.
59	pub ExtensionScanPaths:Arc<StandardMutex<Vec<PathBuf>>>,
60
61	/// Enabled proposed APIs for extensions.
62	pub EnabledProposedAPIs:Arc<StandardMutex<HashMap<String, Vec<String>>>>,
63}
64
65impl Default for Registry {
66	fn default() -> Self {
67		debug!("[ExtensionRegistry] Initializing default extension registry...");
68
69		Self {
70			CommandRegistry:Arc::new(StandardMutex::new(HashMap::new())),
71			NextProviderHandle:Arc::new(AtomicU32::new(1)),
72			ExtensionScanPaths:Arc::new(StandardMutex::new(Vec::new())),
73			EnabledProposedAPIs:Arc::new(StandardMutex::new(HashMap::new())),
74		}
75	}
76}
77
78impl Registry {
79	/// Gets the next available unique identifier for a provider registration.
80	pub fn GetNextProviderHandle(&self) -> u32 { self.NextProviderHandle.fetch_add(1, AtomicOrdering::Relaxed) }
81
82	/// Gets all registered commands.
83	pub fn GetCommands(&self) -> HashMap<String, CommandHandler<Wry>> {
84		self.CommandRegistry.lock().ok().map(|guard| guard.clone()).unwrap_or_default()
85	}
86
87	/// Registers a command.
88	pub fn RegisterCommand(&self, name:String, handler:CommandHandler<Wry>) {
89		if let Ok(mut guard) = self.CommandRegistry.lock() {
90			guard.insert(name, handler);
91			debug!("[ExtensionRegistry] Command registered");
92		}
93	}
94
95	/// Unregisters a command.
96	pub fn UnregisterCommand(&self, name:&str) {
97		if let Ok(mut guard) = self.CommandRegistry.lock() {
98			guard.remove(name);
99			debug!("[ExtensionRegistry] Command unregistered: {}", name);
100		}
101	}
102
103	/// Gets all extension scan paths.
104	pub fn GetExtensionScanPaths(&self) -> Vec<PathBuf> {
105		self.ExtensionScanPaths
106			.lock()
107			.ok()
108			.map(|guard| guard.clone())
109			.unwrap_or_default()
110	}
111
112	/// Sets the extension scan paths.
113	pub fn SetExtensionScanPaths(&self, paths:Vec<PathBuf>) {
114		if let Ok(mut guard) = self.ExtensionScanPaths.lock() {
115			*guard = paths;
116			debug!("[ExtensionRegistry] Extension scan paths updated ({} paths)", guard.len());
117		}
118	}
119
120	/// Adds an extension scan path.
121	pub fn AddExtensionScanPath(&self, path:PathBuf) {
122		if let Ok(mut guard) = self.ExtensionScanPaths.lock() {
123			guard.push(path.clone());
124			debug!("[ExtensionRegistry] Extension scan path added: {:?}", path);
125		}
126	}
127
128	/// Gets all enabled proposed APIs.
129	pub fn GetEnabledProposedAPIs(&self) -> HashMap<String, Vec<String>> {
130		self.EnabledProposedAPIs
131			.lock()
132			.ok()
133			.map(|guard| guard.clone())
134			.unwrap_or_default()
135	}
136
137	/// Sets the enabled proposed APIs.
138	pub fn SetEnabledProposedAPIs(&self, apis:HashMap<String, Vec<String>>) {
139		if let Ok(mut guard) = self.EnabledProposedAPIs.lock() {
140			*guard = apis;
141			debug!("[ExtensionRegistry] Enabled proposed APIs updated ({} entries)", guard.len());
142		}
143	}
144
145	/// Enables a proposed API for an extension.
146	pub fn EnableProposedAPI(&self, extension_id:String, api_name:String) {
147		if let Ok(mut guard) = self.EnabledProposedAPIs.lock() {
148			guard.entry(extension_id).or_insert_with(Vec::new).push(api_name);
149			debug!("[ExtensionRegistry] Proposed API enabled");
150		}
151	}
152}