use std::sync::{Arc, Mutex};
use arc_swap::ArcSwap;
use nichlink_run_method::{GraftPlan, Registry};
use crate::{HostError, PluginInstance};
pub struct Deployment<I> {
pub generation: u64,
pub registry: Registry,
pub plugin: Arc<I>,
}
pub struct HotDeployment<I> {
current: ArcSwap<Deployment<I>>,
writer: Mutex<()>,
}
impl<I: PluginInstance> HotDeployment<I> {
pub fn new(registry: Registry, plugin: I) -> Result<Self, HostError> {
plugin.health_check()?;
Ok(Self {
current: ArcSwap::from_pointee(Deployment {
generation: 0,
registry,
plugin: Arc::new(plugin),
}),
writer: Mutex::new(()),
})
}
pub fn load(&self) -> Arc<Deployment<I>> {
self.current.load_full()
}
pub fn replace(
&self,
plugin: I,
plan: &GraftPlan,
external: &Registry,
) -> Result<u64, HostError> {
plugin.health_check()?;
let _writer = self
.writer
.lock()
.map_err(|_| HostError::Process("deployment writer lock was poisoned".to_owned()))?;
let live = self.current.load_full();
let registry = live
.registry
.overlay(plan, external)
.map_err(|error| HostError::Registry(error.to_string()))?;
let generation = live.generation.saturating_add(1);
self.current.store(Arc::new(Deployment {
generation,
registry,
plugin: Arc::new(plugin),
}));
Ok(generation)
}
}