synaps_cli/extensions/
loader.rs1use std::sync::Arc;
8
9use tokio::sync::{mpsc, RwLock};
10
11use super::manager::{ExtensionLoadFailure, ExtensionManager};
12
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum ExtensionLoaderEvent {
15 Started,
16 Loaded { plugin: String, loaded: usize, failed: usize },
17 Failed { failure: ExtensionLoadFailure, loaded: usize, failed: usize },
18 Finished { loaded: Vec<String>, failed: Vec<ExtensionLoadFailure> },
19}
20
21impl ExtensionLoaderEvent {
22 pub fn progress_counts(&self) -> Option<(usize, usize)> {
23 match self {
24 ExtensionLoaderEvent::Started => Some((0, 0)),
25 ExtensionLoaderEvent::Loaded { loaded, failed, .. } => Some((*loaded, *failed)),
26 ExtensionLoaderEvent::Failed { loaded, failed, .. } => Some((*loaded, *failed)),
27 ExtensionLoaderEvent::Finished { loaded, failed } => Some((loaded.len(), failed.len())),
28 }
29 }
30}
31
32pub fn spawn_discover_and_load(
33 manager: Arc<RwLock<ExtensionManager>>,
34 tx: mpsc::UnboundedSender<ExtensionLoaderEvent>,
35) -> tokio::task::JoinHandle<()> {
36 tokio::spawn(async move {
37 let _ = tx.send(ExtensionLoaderEvent::Started);
38 let (loaded, failed) = manager.write().await.discover_and_load_with_progress(|event| {
39 let _ = tx.send(event);
40 }).await;
41 let _ = tx.send(ExtensionLoaderEvent::Finished { loaded, failed });
42 })
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn progress_counts_report_finished_totals() {
51 let event = ExtensionLoaderEvent::Finished {
52 loaded: vec!["a".into(), "b".into()],
53 failed: vec![ExtensionLoadFailure {
54 plugin: "bad".into(),
55 manifest_path: None,
56 reason: "oops".into(),
57 hint: "fix it".into(),
58 }],
59 };
60 assert_eq!(event.progress_counts(), Some((2, 1)));
61 }
62}