spacegate_plugin/
instance.rs1use std::{
2 any::{Any, TypeId},
3 collections::{HashMap, HashSet},
4 sync::{
5 atomic::{AtomicU64, Ordering},
6 Arc, Weak,
7 },
8};
9
10use serde::{Deserialize, Serialize};
11use spacegate_kernel::{helper_layers::function::FnLayer, BoxError, BoxLayer, BoxResult};
12use spacegate_model::PluginConfig;
13
14use crate::mount::{MountPoint, MountPointIndex};
15
16pub struct PluginInstance {
17 pub config: PluginConfig,
19 pub mount_points: HashMap<MountPointIndex, DropTracer>,
21 pub hooks: PluginInstanceHooks,
23 pub plugin_function: crate::layer::PluginFunction,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Hash)]
27pub(crate) struct DropMarker {
28 drop_signal: Arc<u64>,
29}
30
31#[derive(Debug, Clone, Default)]
32
33pub(crate) struct DropMarkerSet {
34 pub(crate) inner: HashSet<DropMarker>,
35}
36
37#[derive(Debug, Clone)]
38pub struct DropTracer {
39 drop_signal: Weak<u64>,
40}
41
42impl DropTracer {
43 pub fn all_dropped(&self) -> bool {
44 self.drop_signal.strong_count() == 0
45 }
46}
47
48pub(crate) fn drop_trace() -> (DropTracer, DropMarker) {
49 static COUNT: AtomicU64 = AtomicU64::new(0);
50 let drop_signal = Arc::new(COUNT.fetch_add(1, Ordering::SeqCst));
51 (
52 DropTracer {
53 drop_signal: Arc::downgrade(&drop_signal),
54 },
55 DropMarker { drop_signal: drop_signal.clone() },
56 )
57}
58
59type PluginInstanceHook = Box<dyn Fn(&PluginInstance) -> Result<(), BoxError> + Send + Sync + 'static>;
60
61#[derive(Default)]
62pub struct PluginInstanceResource {
63 inner: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
64}
65
66impl PluginInstanceResource {
67 pub fn get<T: 'static + Send + Sync>(&self) -> Option<&T> {
68 self.inner.get(&TypeId::of::<T>()).and_then(|v| v.downcast_ref())
69 }
70 pub fn get_mut<T: 'static + Send + Sync>(&mut self) -> Option<&mut T> {
71 self.inner.get_mut(&TypeId::of::<T>()).and_then(|v| v.downcast_mut())
72 }
73 pub fn insert<T: 'static + Send + Sync>(&mut self, value: T) {
74 self.inner.insert(TypeId::of::<T>(), Box::new(value));
75 }
76}
77
78impl std::fmt::Debug for PluginInstanceResource {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 f.debug_tuple(stringify!(PluginInstanceResource)).finish()
81 }
82}
83
84#[derive(Default)]
85pub struct PluginInstanceHooks {
86 pub after_create: Option<PluginInstanceHook>,
87 pub before_mount: Option<PluginInstanceHook>,
88 pub after_mount: Option<PluginInstanceHook>,
89 pub before_destroy: Option<PluginInstanceHook>,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct PluginInstanceSnapshot {
94 pub config: PluginConfig,
95 pub mount_points: HashSet<MountPointIndex>,
96}
97
98macro_rules! expose_hooks {
99 ($($hook: ident, $setter: ident)*) => {
100 $(
101 pub(crate) fn $hook(&self) -> BoxResult<()> {
102 self.call_hook(&self.hooks.$hook)
103 }
104 pub(crate) fn $setter<M>(&mut self, hook: M)
105 where M: Fn(&PluginInstance) -> Result<(), BoxError> + Send + Sync + 'static
106 {
107 self.hooks.$hook = Some(Box::new(hook))
108 }
109 )*
110 };
111}
112#[allow(dead_code)]
113impl PluginInstance {
114 pub(crate) fn mount_at<M: MountPoint>(&mut self, mount_point: &mut M, index: MountPointIndex) -> Result<(), BoxError> {
115 let tracer = mount_point.mount(self)?;
116 self.mount_points.insert(index, tracer);
117 Ok(())
118 }
119 pub fn snapshot(&self) -> PluginInstanceSnapshot {
120 PluginInstanceSnapshot {
121 config: self.config.clone(),
122 mount_points: self.mount_points.iter().filter_map(|(index, tracer)| if !tracer.all_dropped() { Some(index.clone()) } else { None }).collect(),
123 }
124 }
125 pub(crate) fn call_hook(&self, hook: &Option<PluginInstanceHook>) -> BoxResult<()> {
126 if let Some(ref hook) = hook {
127 (hook)(self)
128 } else {
129 Ok(())
130 }
131 }
132 pub fn make(&self) -> BoxLayer {
133 BoxLayer::new(FnLayer::new(self.plugin_function.clone()))
134 }
135 pub(crate) fn mount_points_gc(&mut self) {
138 self.mount_points.retain(|_, tracer| !tracer.all_dropped());
139 }
140 expose_hooks! {
141 after_create, set_after_create
142 before_mount, set_before_create
143 after_mount, set_after_mount
144 before_destroy, set_before_destroy
145 }
146}