nichlink_plugin_host/
deployment.rs1use std::sync::{Arc, Mutex};
5
6use arc_swap::ArcSwap;
7use nichlink_run_method::{GraftPlan, Registry};
8
9use crate::{HostError, PluginInstance};
10
11pub struct Deployment<I> {
14 pub generation: u64,
17 pub registry: Registry,
20 pub plugin: Arc<I>,
23}
24
25pub struct HotDeployment<I> {
28 current: ArcSwap<Deployment<I>>,
29 writer: Mutex<()>,
30}
31
32impl<I: PluginInstance> HotDeployment<I> {
33 pub fn new(registry: Registry, plugin: I) -> Result<Self, HostError> {
36 plugin.health_check()?;
37 Ok(Self {
38 current: ArcSwap::from_pointee(Deployment {
39 generation: 0,
40 registry,
41 plugin: Arc::new(plugin),
42 }),
43 writer: Mutex::new(()),
44 })
45 }
46
47 pub fn load(&self) -> Arc<Deployment<I>> {
50 self.current.load_full()
51 }
52
53 pub fn replace(
56 &self,
57 plugin: I,
58 plan: &GraftPlan,
59 external: &Registry,
60 ) -> Result<u64, HostError> {
61 plugin.health_check()?;
62 let _writer = self
63 .writer
64 .lock()
65 .map_err(|_| HostError::Process("deployment writer lock was poisoned".to_owned()))?;
66 let live = self.current.load_full();
67 let registry = live
68 .registry
69 .overlay(plan, external)
70 .map_err(|error| HostError::Registry(error.to_string()))?;
71 let generation = live.generation.saturating_add(1);
72 self.current.store(Arc::new(Deployment {
73 generation,
74 registry,
75 plugin: Arc::new(plugin),
76 }));
77 Ok(generation)
78 }
79}