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