homecore_plugins/
registry.rs1use std::collections::{BTreeMap, BTreeSet};
9use std::sync::Arc;
10
11use homecore::HomeCore;
12use tokio::sync::RwLock;
13
14use crate::error::PluginError;
15use crate::manifest::PluginManifest;
16use crate::plugin::{HomeCorePlugin, PluginId};
17use crate::runtime::{LoadedPlugin, PluginRuntime};
18use crate::StateChangedEventJson;
19
20pub struct PluginRegistry<R: PluginRuntime> {
25 runtime: R,
26 plugins: RwLock<BTreeMap<PluginId, LoadedPlugin>>,
27 loading: RwLock<BTreeSet<PluginId>>,
28}
29
30impl<R: PluginRuntime> PluginRegistry<R> {
31 pub fn new(runtime: R) -> Self {
33 Self {
34 runtime,
35 plugins: RwLock::new(BTreeMap::new()),
36 loading: RwLock::new(BTreeSet::new()),
37 }
38 }
39
40 pub async fn load(
45 &self,
46 manifest: PluginManifest,
47 plugin: Arc<dyn HomeCorePlugin>,
48 hc: HomeCore,
49 ) -> Result<PluginId, PluginError> {
50 let id = PluginId::new(&manifest.domain);
51
52 {
53 let guard = self.plugins.read().await;
54 let mut loading = self.loading.write().await;
55 if guard.contains_key(&id) || !loading.insert(id.clone()) {
56 return Err(PluginError::AlreadyLoaded(id.to_string()));
57 }
58 }
59
60 let result = self
61 .runtime
62 .load(id.clone(), manifest, plugin)
63 .await;
64 let loaded = match result {
65 Ok(loaded) => loaded,
66 Err(error) => {
67 self.loading.write().await.remove(&id);
68 return Err(error);
69 }
70 };
71 if let Err(error) = loaded.setup(hc).await {
72 let _ = loaded.unload().await;
74 self.loading.write().await.remove(&id);
75 return Err(PluginError::SetupFailed(error.to_string()));
76 }
77 self.plugins.write().await.insert(id.clone(), loaded);
78 self.loading.write().await.remove(&id);
79 Ok(id)
80 }
81
82 pub async fn unload(&self, id: &PluginId) -> Result<(), PluginError> {
86 let loaded = {
87 let mut guard = self.plugins.write().await;
88 guard
89 .remove(id)
90 .ok_or_else(|| PluginError::NotFound(id.to_string()))?
91 };
92
93 if let Err(error) = loaded.unload().await {
94 self.plugins.write().await.insert(id.clone(), loaded);
96 return Err(PluginError::UnloadFailed(error.to_string()));
97 }
98
99 Ok(())
100 }
101
102 pub async fn list(&self) -> Vec<(PluginId, String)> {
104 let guard = self.plugins.read().await;
105 guard
106 .iter()
107 .map(|(id, lp)| (id.clone(), lp.manifest.domain.clone()))
108 .collect()
109 }
110
111 pub async fn contains(&self, id: &PluginId) -> bool {
113 self.plugins.read().await.contains_key(id)
114 }
115
116 pub async fn state_changed(&self, event: &StateChangedEventJson) -> Vec<(PluginId, PluginError)> {
118 let guard = self.plugins.read().await;
119 let mut errors = Vec::new();
120 for (id, plugin) in guard.iter() {
121 if let Err(error) = plugin.state_changed(event).await {
122 errors.push((id.clone(), error));
123 }
124 }
125 errors
126 }
127
128 pub async fn shutdown(&self) -> Vec<(PluginId, PluginError)> {
131 let ids: Vec<_> = self.plugins.read().await.keys().cloned().rev().collect();
132 let mut errors = Vec::new();
133 for id in ids {
134 if let Err(error) = self.unload(&id).await {
135 errors.push((id, error));
136 }
137 }
138 errors
139 }
140}