Skip to main content

Grove/Host/
ExtensionHost.rs

1//! Extension Host Module
2//!
3//! Main extension host controller for Grove.
4//! Manages the overall host lifecycle and coordinates extension execution.
5
6use std::{path::PathBuf, sync::Arc};
7
8use anyhow::{Context, Result};
9use serde::{Deserialize, Serialize};
10use tokio::sync::RwLock;
11use tracing::{error, info, instrument, warn};
12
13use crate::{
14	Host::{Activation, HostConfig},
15	Host::ExtensionManager::ExtensionManagerImpl,
16	Transport::Strategy::Transport,
17	WASM::Runtime::{WASMConfig, WASMRuntime},
18};
19
20/// Main extension host controller
21pub struct ExtensionHostImpl {
22    /// Host configuration
23    #[allow(dead_code)]
24    config:HostConfig,
25	/// Transport for communication
26	transport:Transport,
27	/// Extension manager
28	extension_manager:Arc<ExtensionManagerImpl>,
29	/// Activation engine
30	activation_engine:Arc<Activation::ActivationEngine>,
31	/// WASM runtime
32	wasm_runtime:Arc<WASMRuntime>,
33	/// Active extensions
34	active_extensions:Arc<RwLock<Vec<String>>>,
35	/// Host state
36	state:Arc<RwLock<HostState>>,
37}
38
39/// Host state
40#[derive(Debug, Clone, PartialEq)]
41pub enum HostState {
42	/// Host has been created but not initialized
43	Created,
44	/// Host is ready to accept extensions
45	Ready,
46	/// Host is running with active extensions
47	Running,
48	/// Host is shutting down
49	ShuttingDown,
50	/// Host has been terminated
51	Terminated,
52}
53
54/// Host statistics
55#[derive(Debug, Clone, Default, Serialize, Deserialize)]
56pub struct HostStats {
57	/// Number of loaded extensions
58	pub loaded_extensions:usize,
59	/// Number of active extensions
60	pub active_extensions:usize,
61	/// Total number of activations
62	pub total_activations:u64,
63	/// Total activation time in milliseconds
64	pub total_activation_time_ms:u64,
65	/// Number of API calls made
66	pub api_calls:u64,
67	/// Number of errors encountered
68	pub errors:u64,
69	/// Host uptime in seconds
70	pub uptime_seconds:u64,
71}
72
73impl ExtensionHostImpl {
74	/// Create a new extension host
75	///
76	/// # Arguments
77	///
78	/// * `transport` - The communication transport to use
79	///
80	/// # Example
81	///
82	/// ```rust,no_run
83	/// use grove::{ExtensionHost, Transport};
84	///
85	/// # async fn example() -> anyhow::Result<()> {
86	/// let transport = Transport::default();
87	/// let host = ExtensionHost::new(transport).await?;
88	/// # Ok(())
89	/// # }
90	/// ```
91	#[instrument(skip(transport))]
92	pub async fn new(transport:Transport) -> Result<Self> { Self::with_config(transport, HostConfig::default()).await }
93
94	/// Create a new extension host with custom configuration
95	#[instrument(skip(transport, config))]
96	pub async fn with_config(transport:Transport, config:HostConfig) -> Result<Self> {
97		info!("Creating extension host with config: {:?}", config);
98
99		// Connect transport
100		transport.connect().await.context("Failed to connect transport")?;
101
102		// Create WASM runtime
103		let wasm_config = WASMConfig::new(512, 30000, true);
104		let wasm_runtime = Arc::new(WASMRuntime::new(wasm_config).await?);
105
106		// Create extension manager
107		let extension_manager = Arc::new(ExtensionManagerImpl::new(Arc::clone(&wasm_runtime), config.clone()));
108
109		// Create activation engine
110		let activation_engine = Arc::new(Activation::ActivationEngine::new(
111			Arc::clone(&extension_manager),
112			config.clone(),
113		));
114
115		info!("Extension host created successfully");
116
117		Ok(Self {
118			config,
119			transport,
120			extension_manager,
121			activation_engine,
122			wasm_runtime,
123			active_extensions:Arc::new(RwLock::new(Vec::new())),
124			state:Arc::new(RwLock::new(HostState::Created)),
125		})
126	}
127
128	/// Load an extension from a path
129	#[instrument(skip(self, path))]
130	pub async fn load_extension(&self, path:&PathBuf) -> Result<String> {
131		info!("Loading extension from: {:?}", path);
132
133		let extension_id = self
134			.extension_manager
135			.load_extension(path)
136			.await
137			.context("Failed to load extension")?;
138
139		info!("Extension loaded: {}", extension_id);
140
141		*self.state.write().await = HostState::Ready;
142
143		Ok(extension_id)
144	}
145
146	/// Unload an extension
147	#[instrument(skip(self, extension_id))]
148	pub async fn unload_extension(&self, extension_id:&str) -> Result<()> {
149		info!("Unloading extension: {}", extension_id);
150
151		self.extension_manager
152			.unload_extension(extension_id)
153			.await
154			.context("Failed to unload extension")?;
155
156		info!("Extension unloaded: {}", extension_id);
157
158		Ok(())
159	}
160
161	/// Activate an extension
162	#[instrument(skip(self, extension_id))]
163	pub async fn activate(&self, extension_id:&str) -> Result<()> {
164		info!("Activating extension: {}", extension_id);
165
166		let start = std::time::Instant::now();
167
168		let result = self
169			.activation_engine
170			.activate(extension_id)
171			.await
172			.context("Failed to activate extension")?;
173
174		let elapsed = start.elapsed().as_millis() as u64;
175
176		if result.success {
177			info!("Extension activated in {}ms: {}", elapsed, extension_id);
178
179			// Track active extension
180			let mut active = self.active_extensions.write().await;
181			if !active.contains(&extension_id.to_string()) {
182				active.push(extension_id.to_string());
183			}
184
185			*self.state.write().await = HostState::Running;
186		} else {
187			error!("Extension activation failed: {}", extension_id);
188		}
189
190		Ok(())
191	}
192
193	/// Deactivate an extension
194	#[instrument(skip(self, extension_id))]
195	pub async fn deactivate(&self, extension_id:&str) -> Result<()> {
196		info!("Deactivating extension: {}", extension_id);
197
198		self.activation_engine
199			.deactivate(extension_id)
200			.await
201			.context("Failed to deactivate extension")?;
202
203		// Remove from active extensions
204		let mut active = self.active_extensions.write().await;
205		active.retain(|id| id != extension_id);
206
207		info!("Extension deactivated: {}", extension_id);
208
209		Ok(())
210	}
211
212	/// Activate all loaded extensions
213	#[instrument(skip(self))]
214	pub async fn activate_all(&self) -> Result<Vec<String>> {
215		info!("Activating all extensions");
216
217		let extensions = self.extension_manager.list_extensions().await;
218		let mut activated = Vec::new();
219		let mut failed = Vec::new();
220
221		for extension_id in extensions {
222			match self.activate(&extension_id).await {
223				Ok(_) => activated.push(extension_id),
224				Err(e) => {
225					error!("Failed to activate {}: {}", extension_id, e);
226					failed.push(extension_id);
227				},
228			}
229		}
230
231		warn!("Activated {} extensions, {} failed", activated.len(), failed.len());
232
233		Ok(activated)
234	}
235
236	/// Deactivate all active extensions
237	#[instrument(skip(self))]
238	pub async fn deactivate_all(&self) -> Result<()> {
239		info!("Deactivating all extensions");
240
241		let active = self.active_extensions.read().await.clone();
242
243		for extension_id in active {
244			if let Err(e) = self.deactivate(&extension_id).await {
245				error!("Failed to deactivate {}: {}", extension_id, e);
246			}
247		}
248
249		*self.state.write().await = HostState::Ready;
250
251		Ok(())
252	}
253
254	/// Get host statistics
255	pub async fn stats(&self) -> HostStats {
256		let active_extensions = self.active_extensions.read().await.len();
257		let loaded_extensions = self.extension_manager.list_extensions().await.len();
258		let extension_stats = self.extension_manager.stats().await;
259
260		HostStats {
261			loaded_extensions,
262			active_extensions,
263			total_activations:extension_stats.total_activated as u64,
264			total_activation_time_ms:extension_stats.total_activation_time_ms,
265			api_calls:0, // Track through API bridge
266			errors:extension_stats.errors,
267			uptime_seconds:0, // Track from host start time
268		}
269	}
270
271	/// Get host state
272	pub async fn state(&self) -> HostState { self.state.read().await.clone() }
273
274	/// Get the transport
275	pub fn transport(&self) -> &Transport { &self.transport }
276
277	/// Get the extension manager
278	pub fn extension_manager(&self) -> &Arc<ExtensionManagerImpl> { &self.extension_manager }
279
280	/// Get the activation engine
281	pub fn activation_engine(&self) -> &Arc<Activation::ActivationEngine> { &self.activation_engine }
282
283	/// Get the WASM runtime
284	pub fn wasm_runtime(&self) -> &Arc<WASMRuntime> { &self.wasm_runtime }
285
286	/// Shutdown the host and clean up resources
287	#[instrument(skip(self))]
288	pub async fn shutdown(&self) -> Result<()> {
289		info!("Shutting down extension host");
290
291		*self.state.write().await = HostState::ShuttingDown;
292
293		// Deactivate all extensions
294		if let Err(e) = self.deactivate_all().await {
295			error!("Error deactivating extensions during shutdown: {}", e);
296		}
297
298		// Close transport
299		if let Err(e) = self.transport.close().await {
300			error!("Error closing transport during shutdown: {}", e);
301		}
302
303		// Shutdown WASM runtime
304		if let Err(e) = self.wasm_runtime.shutdown().await {
305			error!("Error shutting down WASM runtime: {}", e);
306		}
307
308		*self.state.write().await = HostState::Terminated;
309
310		info!("Extension host shutdown complete");
311
312		Ok(())
313	}
314}
315
316impl Drop for ExtensionHostImpl {
317	fn drop(&mut self) {
318		info!("ExtensionHost dropped");
319	}
320}
321
322#[cfg(test)]
323mod tests {
324	use super::*;
325
326	#[tokio::test]
327	async fn test_host_state() {
328		assert_eq!(HostState::Created, HostState::Created);
329		assert_eq!(HostState::Ready, HostState::Ready);
330		assert_eq!(HostState::Running, HostState::Running);
331	}
332
333	#[test]
334	fn test_host_stats_default() {
335		let stats = HostStats::default();
336		assert_eq!(stats.loaded_extensions, 0);
337		assert_eq!(stats.active_extensions, 0);
338	}
339
340	#[test]
341	fn test_host_config_default() {
342		let config = HostConfig::default();
343		assert_eq!(config.max_extensions, 100);
344		assert_eq!(config.lazy_activation, true);
345	}
346}