use std::sync::Arc;
use tokio::sync::{mpsc, RwLock};
use super::manager::{ExtensionLoadFailure, ExtensionManager};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExtensionLoaderEvent {
Started,
Loaded {
plugin: String,
loaded: usize,
failed: usize,
},
Failed {
failure: ExtensionLoadFailure,
loaded: usize,
failed: usize,
},
Finished {
loaded: Vec<String>,
failed: Vec<ExtensionLoadFailure>,
},
}
impl ExtensionLoaderEvent {
pub fn progress_counts(&self) -> Option<(usize, usize)> {
match self {
ExtensionLoaderEvent::Started => Some((0, 0)),
ExtensionLoaderEvent::Loaded { loaded, failed, .. } => Some((*loaded, *failed)),
ExtensionLoaderEvent::Failed { loaded, failed, .. } => Some((*loaded, *failed)),
ExtensionLoaderEvent::Finished { loaded, failed } => Some((loaded.len(), failed.len())),
}
}
}
pub fn spawn_discover_and_load(
manager: Arc<RwLock<ExtensionManager>>,
tx: mpsc::UnboundedSender<ExtensionLoaderEvent>,
) -> tokio::task::JoinHandle<()> {
tokio::spawn(async move {
let _ = tx.send(ExtensionLoaderEvent::Started);
let (loaded, failed) = manager
.write()
.await
.discover_and_load_with_progress(|event| {
let _ = tx.send(event);
})
.await;
let _ = tx.send(ExtensionLoaderEvent::Finished { loaded, failed });
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn progress_counts_report_finished_totals() {
let event = ExtensionLoaderEvent::Finished {
loaded: vec!["a".into(), "b".into()],
failed: vec![ExtensionLoadFailure {
plugin: "bad".into(),
manifest_path: None,
reason: "oops".into(),
hint: "fix it".into(),
}],
};
assert_eq!(event.progress_counts(), Some((2, 1)));
}
}