use crate::digest::Digest256;
use crate::error::Result;
use crate::manifest::{
AgentInfo, CacheLayer, EffectsLayer, MEDIATYPE_V1, Manifest, ModelLayer, TraceLayer, WorldLayer,
};
use crate::store::PfStore;
use chrono::Utc;
use std::sync::Arc;
use std::thread;
pub trait LayerCapture: Send + Sync {
fn kind(&self) -> LayerKind;
fn capture(&self, store: &PfStore) -> Result<LayerDescriptor>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LayerKind {
Model,
Cache,
World,
Effects,
Trace,
}
#[derive(Clone, Debug)]
pub enum LayerDescriptor {
Model(ModelLayer),
Cache(CacheLayer),
World(WorldLayer),
Effects(EffectsLayer),
Trace(TraceLayer),
}
pub struct Snapshotter {
agent: AgentInfo,
model: Arc<dyn LayerCapture>,
cache: Arc<dyn LayerCapture>,
world: Arc<dyn LayerCapture>,
effects: Arc<dyn LayerCapture>,
trace: Arc<dyn LayerCapture>,
}
impl Snapshotter {
pub fn new(
agent: AgentInfo,
model: Arc<dyn LayerCapture>,
cache: Arc<dyn LayerCapture>,
world: Arc<dyn LayerCapture>,
effects: Arc<dyn LayerCapture>,
trace: Arc<dyn LayerCapture>,
) -> Self {
Self {
agent,
model,
cache,
world,
effects,
trace,
}
}
pub fn snapshot(&self, store: &PfStore, parents: Vec<Digest256>) -> Result<Digest256> {
let descriptors: Result<Vec<LayerDescriptor>> = thread::scope(|scope| {
let model_cap = self.model.clone();
let cache_cap = self.cache.clone();
let world_cap = self.world.clone();
let effects_cap = self.effects.clone();
let trace_cap = self.trace.clone();
let h_model = scope.spawn(move || model_cap.capture(store));
let h_cache = scope.spawn(move || cache_cap.capture(store));
let h_world = scope.spawn(move || world_cap.capture(store));
let h_effects = scope.spawn(move || effects_cap.capture(store));
let h_trace = scope.spawn(move || trace_cap.capture(store));
let mut out = Vec::with_capacity(5);
for handle in [h_model, h_cache, h_world, h_effects, h_trace] {
out.push(handle.join().expect("capture thread panicked")?);
}
Ok(out)
});
let descriptors = descriptors?;
let mut model = None;
let mut cache = None;
let mut world = None;
let mut effects = None;
let mut trace = None;
for d in descriptors {
match d {
LayerDescriptor::Model(x) => model = Some(x),
LayerDescriptor::Cache(x) => cache = Some(x),
LayerDescriptor::World(x) => world = Some(x),
LayerDescriptor::Effects(x) => effects = Some(x),
LayerDescriptor::Trace(x) => trace = Some(x),
}
}
let manifest = Manifest {
schema_version: 1,
media_type: MEDIATYPE_V1.to_owned(),
agent: self.agent.clone(),
model: model.expect("model capture must produce ModelLayer"),
cache: cache.expect("cache capture must produce CacheLayer"),
world: world.expect("world capture must produce WorldLayer"),
effects: effects.expect("effects capture must produce EffectsLayer"),
trace: trace.expect("trace capture must produce TraceLayer"),
created_at: Utc::now(),
parents,
};
store.put_manifest(&manifest)
}
}