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			NextProviderHandle:Arc::new(AtomicU32::new(1)),
71			ExtensionScanPaths:Arc::new(StandardMutex::new(Vec::new())),
72			EnabledProposedAPIs:Arc::new(StandardMutex::new(HashMap::new())),
73		}
74	}
75}
76
77impl Registry {
78	/// Gets the next available unique identifier for a provider registration.
79	pub fn GetNextProviderHandle(&self) -> u32 { self.NextProviderHandle.fetch_add(1, AtomicOrdering::Relaxed) }
80
81	/// Gets all registered commands.
82	pub fn GetCommands(&self) -> HashMap<String, CommandHandler<Wry>> {
83		self.CommandRegistry.lock().ok().map(|guard| guard.clone()).unwrap_or_default()
84	}
85
86	/// Registers a command.
87	pub fn RegisterCommand(&self, name:String, handler:CommandHandler<Wry>) {
88		if let Ok(mut guard) = self.CommandRegistry.lock() {
89			guard.insert(name, handler);
90			dev_log!("extensions", "[ExtensionRegistry] Command registered");
91		}
92	}
93
94	/// Unregisters a command.
95	pub fn UnregisterCommand(&self, name:&str) {
96		if let Ok(mut guard) = self.CommandRegistry.lock() {
97			guard.remove(name);
98			dev_log!("extensions", "[ExtensionRegistry] Command unregistered: {}", name);
99		}
100	}
101
102	/// Gets all extension scan paths.
103	pub fn GetExtensionScanPaths(&self) -> Vec<PathBuf> {
104		self.ExtensionScanPaths
105			.lock()
106			.ok()
107			.map(|guard| guard.clone())
108			.unwrap_or_default()
109	}
110
111	/// Sets the extension scan paths.
112	pub fn SetExtensionScanPaths(&self, paths:Vec<PathBuf>) {
113		if let Ok(mut guard) = self.ExtensionScanPaths.lock() {
114			*guard = paths;
115			dev_log!(
116				"extensions",
117				"[ExtensionRegistry] Extension scan paths updated ({} paths)",
118				guard.len()
119			);
120		}
121	}
122
123	/// Adds an extension scan path.
124	pub fn AddExtensionScanPath(&self, path:PathBuf) {
125		if let Ok(mut guard) = self.ExtensionScanPaths.lock() {
126			guard.push(path.clone());
127			dev_log!("extensions", "[ExtensionRegistry] Extension scan path added: {:?}", path);
128		}
129	}
130
131	/// Gets all enabled proposed APIs.
132	pub fn GetEnabledProposedAPIs(&self) -> HashMap<String, Vec<String>> {
133		self.EnabledProposedAPIs
134			.lock()
135			.ok()
136			.map(|guard| guard.clone())
137			.unwrap_or_default()
138	}
139
140	/// Sets the enabled proposed APIs.
141	pub fn SetEnabledProposedAPIs(&self, apis:HashMap<String, Vec<String>>) {
142		if let Ok(mut guard) = self.EnabledProposedAPIs.lock() {
143			*guard = apis;
144			dev_log!(
145				"extensions",
146				"[ExtensionRegistry] Enabled proposed APIs updated ({} entries)",
147				guard.len()
148			);
149		}
150	}
151
152	/// Enables a proposed API for an extension.
153	pub fn EnableProposedAPI(&self, extension_id:String, api_name:String) {
154		if let Ok(mut guard) = self.EnabledProposedAPIs.lock() {
155			guard.entry(extension_id).or_insert_with(Vec::new).push(api_name);
156			dev_log!("extensions", "[ExtensionRegistry] Proposed API enabled");
157		}
158	}
159}