Skip to main content

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;
45
46use crate::{Environment::CommandProvider::CommandHandler, dev_log};
47
48/// Extension registry containing command registry and provider handle state.
49#[derive(Clone)]
50pub struct Registry {
51	/// Registered CLI commands.
52	pub CommandRegistry:Arc<StandardMutex<HashMap<String, CommandHandler<Wry>>>>,
53
54	/// Counter for generating unique provider handles.
55	pub NextProviderHandle:Arc<AtomicU32>,
56
57	/// Paths to scan for extensions.
58	pub ExtensionScanPaths:Arc<StandardMutex<Vec<PathBuf>>>,
59
60	/// Enabled proposed APIs for extensions.
61	pub EnabledProposedAPIs:Arc<StandardMutex<HashMap<String, Vec<String>>>>,
62}
63
64impl Default for Registry {
65	fn default() -> Self {
66		dev_log!("extensions", "[ExtensionRegistry] Initializing default extension registry...");
67
68		Self {
69			CommandRegistry:Arc::new(StandardMutex::new(HashMap::new())),
70
71			NextProviderHandle:Arc::new(AtomicU32::new(1)),
72
73			ExtensionScanPaths:Arc::new(StandardMutex::new(Vec::new())),
74
75			EnabledProposedAPIs:Arc::new(StandardMutex::new(HashMap::new())),
76		}
77	}
78}
79
80impl Registry {
81	/// Gets the next available unique identifier for a provider registration.
82	pub fn GetNextProviderHandle(&self) -> u32 { self.NextProviderHandle.fetch_add(1, AtomicOrdering::Relaxed) }
83
84	/// Gets all registered commands.
85	pub fn GetCommands(&self) -> HashMap<String, CommandHandler<Wry>> {
86		self.CommandRegistry.lock().ok().map(|guard| guard.clone()).unwrap_or_default()
87	}
88
89	/// Registers a command.
90	pub fn RegisterCommand(&self, name:String, handler:CommandHandler<Wry>) {
91		if let Ok(mut guard) = self.CommandRegistry.lock() {
92			guard.insert(name, handler);
93
94			dev_log!("extensions", "[ExtensionRegistry] Command registered");
95		}
96	}
97
98	/// Unregisters a command.
99	pub fn UnregisterCommand(&self, name:&str) {
100		if let Ok(mut guard) = self.CommandRegistry.lock() {
101			guard.remove(name);
102
103			dev_log!("extensions", "[ExtensionRegistry] Command unregistered: {}", name);
104		}
105	}
106
107	/// Gets all extension scan paths.
108	pub fn GetExtensionScanPaths(&self) -> Vec<PathBuf> {
109		self.ExtensionScanPaths
110			.lock()
111			.ok()
112			.map(|guard| guard.clone())
113			.unwrap_or_default()
114	}
115
116	/// Sets the extension scan paths.
117	pub fn SetExtensionScanPaths(&self, paths:Vec<PathBuf>) {
118		if let Ok(mut guard) = self.ExtensionScanPaths.lock() {
119			*guard = paths;
120			dev_log!(
121				"extensions",
122				"[ExtensionRegistry] Extension scan paths updated ({} paths)",
123				guard.len()
124			);
125		}
126	}
127
128	/// Adds an extension scan path.
129	pub fn AddExtensionScanPath(&self, path:PathBuf) {
130		if let Ok(mut guard) = self.ExtensionScanPaths.lock() {
131			guard.push(path.clone());
132
133			dev_log!("extensions", "[ExtensionRegistry] Extension scan path added: {:?}", path);
134		}
135	}
136
137	/// Gets all enabled proposed APIs.
138	pub fn GetEnabledProposedAPIs(&self) -> HashMap<String, Vec<String>> {
139		self.EnabledProposedAPIs
140			.lock()
141			.ok()
142			.map(|guard| guard.clone())
143			.unwrap_or_default()
144	}
145
146	/// Sets the enabled proposed APIs.
147	pub fn SetEnabledProposedAPIs(&self, apis:HashMap<String, Vec<String>>) {
148		if let Ok(mut guard) = self.EnabledProposedAPIs.lock() {
149			*guard = apis;
150			dev_log!(
151				"extensions",
152				"[ExtensionRegistry] Enabled proposed APIs updated ({} entries)",
153				guard.len()
154			);
155		}
156	}
157
158	/// Enables a proposed API for an extension.
159	pub fn EnableProposedAPI(&self, extension_id:String, api_name:String) {
160		if let Ok(mut guard) = self.EnabledProposedAPIs.lock() {
161			guard.entry(extension_id).or_insert_with(Vec::new).push(api_name);
162
163			dev_log!("extensions", "[ExtensionRegistry] Proposed API enabled");
164		}
165	}
166}