diff --git a/bffhd/capnp/machinesystem.rs b/bffhd/capnp/machinesystem.rs index bbd12ca..e868b79 100644 --- a/bffhd/capnp/machinesystem.rs +++ b/bffhd/capnp/machinesystem.rs @@ -6,6 +6,7 @@ use api::machinesystem_capnp::machine_system::{ use capnp::capability::Promise; use capnp_rpc::pry; use crate::capnp::machine::Machine; +use crate::RESOURCES; use crate::resources::Resource; use crate::resources::search::ResourcesHandle; @@ -17,8 +18,8 @@ pub struct Machines { impl Machines { pub fn new(session: SessionHandle) -> Self { - let resources = ResourcesHandle::new(); - Self { session, resources } + // FIXME no unwrap bad + Self { session, resources: RESOURCES.get().unwrap().clone() } } } diff --git a/bffhd/lib.rs b/bffhd/lib.rs index aa3d477..0e10d84 100644 --- a/bffhd/lib.rs +++ b/bffhd/lib.rs @@ -46,6 +46,7 @@ use std::sync::Arc; use anyhow::Context; use futures_rustls::TlsAcceptor; use futures_util::StreamExt; +use once_cell::sync::OnceCell; use rustls::{Certificate, KeyLogFile, PrivateKey, ServerConfig}; use rustls::server::NoClientAuth; use signal_hook::consts::signal::*; @@ -54,6 +55,9 @@ use crate::authentication::AuthenticationHandle; use crate::capnp::APIServer; use crate::config::{Config, TlsListen}; use crate::resources::modules::fabaccess::MachineState; +use crate::resources::Resource; +use crate::resources::search::ResourcesHandle; +use crate::resources::state::db::StateDB; use crate::session::SessionManager; use crate::tls::TlsConfig; @@ -63,6 +67,8 @@ pub struct Diflouroborane { executor: Executor<'static>, } +pub static RESOURCES: OnceCell = OnceCell::new(); + impl Diflouroborane { pub fn new() -> Self { let executor = Executor::new(); @@ -88,8 +94,12 @@ impl Diflouroborane { SIGTERM, ]).context("Failed to construct signal handler")?; - // - Load Machines from config - // - Load states from DB + let statedb = StateDB::create(&config.db_path).context("Failed to open state DB")?; + let statedb = Arc::new(statedb); + let resources = ResourcesHandle::new(config.machines.iter().map(|(id, desc)| { + Resource::new(Arc::new(resources::Inner::new(id.to_string(), statedb.clone(), desc.clone()))) + })); + RESOURCES.set(resources); // - Connect modules to machines let tlsconfig = TlsConfig::new(config.tlskeylog.as_ref(), !config.is_quiet())?; diff --git a/bffhd/resources/mod.rs b/bffhd/resources/mod.rs index 7388dca..5191cde 100644 --- a/bffhd/resources/mod.rs +++ b/bffhd/resources/mod.rs @@ -3,6 +3,7 @@ use std::sync::Arc; use futures_signals::signal::{Mutable, Signal, SignalExt}; use lmdb::RoTransaction; use rkyv::Archived; +use crate::config::MachineDescription; use crate::db::LMDBorrow; use crate::resources::modules::fabaccess::{MachineState, Status}; use crate::resources::state::db::StateDB; @@ -22,11 +23,12 @@ pub struct PermissionDenied; pub(crate) struct Inner { id: String, - db: StateDB, + db: Arc, signal: Mutable, + desc: MachineDescription, } impl Inner { - pub fn new(id: String, db: StateDB) -> Self { + pub fn new(id: String, db: Arc, desc: MachineDescription) -> Self { let state = if let Some(previous) = db.get_output(id.as_bytes()).unwrap() { let state = MachineState::from(&previous); tracing::info!(%id, ?state, "Found previous state"); @@ -37,7 +39,7 @@ impl Inner { }; let signal = Mutable::new(state); - Self { id, db, signal } + Self { id, db, signal, desc } } pub fn signal(&self) -> impl Signal { diff --git a/bffhd/resources/search.rs b/bffhd/resources/search.rs index a1dcb5c..05b516f 100644 --- a/bffhd/resources/search.rs +++ b/bffhd/resources/search.rs @@ -1,13 +1,21 @@ +use std::collections::HashMap; use std::sync::Arc; use crate::resources::Resource; struct Inner { - + id: HashMap, } impl Inner { - pub fn new() -> Self { - Self { } + pub fn new(resources: impl IntoIterator) -> Self { + let mut id = HashMap::new(); + + for resource in resources { + let old = id.insert(resource.inner.id.clone(), resource); + assert!(old.is_none()); + } + + Self { id } } } @@ -17,22 +25,34 @@ pub struct ResourcesHandle { } impl ResourcesHandle { - pub fn new() -> Self { + pub fn new(resources: impl IntoIterator) -> Self { Self { - inner: Arc::new(Inner::new()), + inner: Arc::new(Inner::new(resources)), } } pub fn list_all(&self) -> impl IntoIterator { - unimplemented!(); - &[] + self.inner.id.values() } pub fn get_by_id(&self, id: &str) -> Option<&Resource> { - unimplemented!() + self.inner.id.get(id) } pub fn get_by_urn(&self, urn: &str) -> Option<&Resource> { - unimplemented!() + if let Some(id) = { + let mut parts = urn.split_terminator(':'); + let part_urn = parts.next().map(|u| u == "urn").unwrap_or(false); + let part_fabaccess = parts.next().map(|f| f == "fabaccess").unwrap_or(false); + let part_resource = parts.next().map(|r| r == "resource").unwrap_or(false); + if !(part_urn && part_fabaccess && part_resource) { + return None; + } + parts.next().map(|s| s.to_string()) + } { + self.get_by_id(&id) + } else { + None + } } }