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