diff --git a/bffhd/capnp/machine.rs b/bffhd/capnp/machine.rs index 202baf0..590891b 100644 --- a/bffhd/capnp/machine.rs +++ b/bffhd/capnp/machine.rs @@ -1,4 +1,4 @@ -use crate::resources::modules::fabaccess::MachineState; +use crate::resources::modules::fabaccess::{MachineState, Status}; use crate::resources::Resource; use crate::session::SessionHandle; use api::machine_capnp::machine::{ @@ -49,7 +49,7 @@ impl UseServer for Machine { let session = self.session.clone(); Promise::from_future(async move { let user = session.get_user(); - resource.try_update(session, MachineState::used(user)).await; + resource.try_update(session, Status::InUse(user)).await; Ok(()) }) } @@ -64,7 +64,7 @@ impl UseServer for Machine { Promise::from_future(async move { let user = session.get_user(); resource - .try_update(session, MachineState::reserved(user)) + .try_update(session, Status::Reserved(user)) .await; Ok(()) }) @@ -166,7 +166,7 @@ impl ManageServer for Machine { let session = self.session.clone(); Promise::from_future(async move { resource - .force_set(MachineState::used(session.get_user())) + .force_set(Status::InUse(session.get_user())) .await; Ok(()) }) @@ -180,7 +180,7 @@ impl ManageServer for Machine { let resource = self.resource.clone(); let session = self.session.clone(); Promise::from_future(async move { - resource.force_set(MachineState::free()).await; + resource.force_set(Status::Free).await; Ok(()) }) } @@ -203,7 +203,7 @@ impl ManageServer for Machine { let session = self.session.clone(); Promise::from_future(async move { resource - .force_set(MachineState::blocked(session.get_user())) + .force_set(Status::Blocked(session.get_user())) .await; Ok(()) }) @@ -215,7 +215,7 @@ impl ManageServer for Machine { ) -> Promise<(), ::capnp::Error> { let mut resource = self.resource.clone(); Promise::from_future(async move { - resource.force_set(MachineState::disabled()).await; + resource.force_set(Status::Disabled).await; Ok(()) }) } @@ -230,12 +230,12 @@ impl AdminServer for Machine { use api::schema::machine_capnp::machine::MachineState as APIMState; let user = self.session.get_user(); let state = match pry!(pry!(params.get()).get_state()) { - APIMState::Free => MachineState::free(), - APIMState::Blocked => MachineState::blocked(user), - APIMState::Disabled => MachineState::disabled(), - APIMState::InUse => MachineState::used(user), - APIMState::Reserved => MachineState::reserved(user), - APIMState::ToCheck => MachineState::check(user), + APIMState::Free => Status::Free, + APIMState::Blocked => Status::Blocked(user), + APIMState::Disabled => Status::Disabled, + APIMState::InUse => Status::InUse(user), + APIMState::Reserved => Status::Reserved(user), + APIMState::ToCheck => Status::ToCheck(user), APIMState::Totakeover => return Promise::err(::capnp::Error::unimplemented( "totakeover not implemented".to_string(), )), diff --git a/bffhd/db/mod.rs b/bffhd/db/mod.rs index e8d2f66..233b506 100644 --- a/bffhd/db/mod.rs +++ b/bffhd/db/mod.rs @@ -30,7 +30,6 @@ pub use typed::{ mod hash; pub use hash::{ HashDB, - Entry, }; mod fix; @@ -45,11 +44,12 @@ use std::sync::Arc; use std::path::Path; use crate::users::db::{User, UserDB}; use std::collections::HashMap; -use crate::resources::state::{OwnedEntry, State, db::StateDB}; +use rkyv::Infallible; +use crate::resources::state::{State, db::StateDB}; use std::iter::FromIterator; use std::ops::Deref; use crate::authentication::db::PassDB; -use crate::resources::db::ResourceDB; +use crate::resources::search::ResourcesHandle; use crate::utils::oid::{ArchivedObjectIdentifier, ObjectIdentifier}; use crate::resources::state::value::SerializeValue; @@ -117,98 +117,24 @@ impl>> Adapter for AlignedAdapter } } -#[derive(Debug)] -pub struct Databases { - pub userdb: UserDB, - pub passdb: PassDB, - pub resourcedb: ResourceDB, - pub statedb: StateDB, -} - -impl Databases { - pub fn open>(path: P) -> Result { - let env = Arc::new(Environment::new() - .open(&Path::join(path.as_ref(), "internal"))? - ); - let userdb = unsafe { UserDB::open(env.clone())? }; - let passdb = unsafe { PassDB::open(env.clone())? }; - let resourcedb = unsafe { ResourceDB::open(env)? }; - - let statedb = StateDB::open(&Path::join(path.as_ref(), "state"))?; - - Ok(Self { userdb, passdb, resourcedb, statedb }) - } - - pub fn create>(path: P) -> Result { - let env = Arc::new(Environment::new() - .set_max_dbs(16) - .open(path.as_ref())? - ); - let userdb = unsafe { UserDB::create(env.clone())? }; - let passdb = unsafe { PassDB::create(env.clone())? }; - let resourcedb = unsafe { ResourceDB::create(env)? }; - - let statedb = StateDB::create(&Path::join(path.as_ref(), "state"))?; - - Ok(Self { userdb, passdb, resourcedb, statedb }) - } -} - #[derive(Debug, serde::Serialize)] pub struct Dump { users: HashMap, passwds: HashMap, - states: HashMap, + states: HashMap, } impl Dump { - pub fn new(dbs: &Databases) -> Result { - let users = HashMap::from_iter(dbs.userdb.get_all()?.into_iter()); - let passwds = HashMap::from_iter(dbs.passdb.get_all()?.into_iter()); + pub fn new(userdb: UserDB, passdb: PassDB, resources: ResourcesHandle) -> Result { + let users = HashMap::from_iter(userdb.get_all()?.into_iter()); + let passwds = HashMap::from_iter(passdb.get_all()?.into_iter()); let mut states = HashMap::new(); - for (name, id) in dbs.resourcedb.get_all()?.into_iter() { - let input = dbs.statedb.get_input(id)?.map(|input| { - let input: &Archived = input.deref(); - let hash: u64 = input.hash; - let inner = input.inner.iter() - .map(|entry| { - - let oid: &ArchivedObjectIdentifier = &entry.oid; - let bytes: &[u8] = oid.deref(); - let mut vec = Vec::with_capacity(bytes.len()); - vec.copy_from_slice(bytes); - let oid = ObjectIdentifier::new_unchecked(vec.into_boxed_slice()); - - let val: Box = entry.val - .deserialize(&mut rkyv::Infallible).unwrap(); - - OwnedEntry { oid, val } - }).collect(); - State { hash, inner } - }).unwrap_or(State::build().finish()); - - let output = dbs.statedb.get_output(id)?.map(|output| { - let output: &Archived = output.deref(); - let hash: u64 = output.hash; - let inner = output.inner.iter().map(|entry| { - - let oid: &ArchivedObjectIdentifier = &entry.oid; - let bytes: &[u8] = oid.deref(); - let mut vec = Vec::with_capacity(bytes.len()); - vec.copy_from_slice(bytes); - let oid = ObjectIdentifier::new_unchecked(vec.into_boxed_slice()); - - let val: Box = entry.val - .deserialize(&mut rkyv::Infallible).unwrap(); - - OwnedEntry { oid, val } - }).collect(); - - State { hash, inner } - }).unwrap_or(State::build().finish()); - - let old = states.insert(name, (input, output)); - assert!(old.is_none()); + for resource in resources.list_all().into_iter() { + if let Some(output) = resource.get_raw_state() { + let output: State = Deserialize::::deserialize(output.deref(), &mut Infallible).unwrap(); + let old = states.insert(resource.get_id().to_string(), output); + assert!(old.is_none()); + } } Ok(Self { users, passwds, states }) diff --git a/bffhd/lib.rs b/bffhd/lib.rs index 3685876..aa3d477 100644 --- a/bffhd/lib.rs +++ b/bffhd/lib.rs @@ -53,6 +53,7 @@ use executor::pool::Executor; use crate::authentication::AuthenticationHandle; use crate::capnp::APIServer; use crate::config::{Config, TlsListen}; +use crate::resources::modules::fabaccess::MachineState; use crate::session::SessionManager; use crate::tls::TlsConfig; @@ -87,7 +88,9 @@ impl Diflouroborane { SIGTERM, ]).context("Failed to construct signal handler")?; - + // - Load Machines from config + // - Load states from DB + // - Connect modules to machines let tlsconfig = TlsConfig::new(config.tlskeylog.as_ref(), !config.is_quiet())?; let acceptor = tlsconfig.make_tls_acceptor(&config.tlsconfig)?; diff --git a/bffhd/resources/db.rs b/bffhd/resources/db.rs index 73bd1cf..8010175 100644 --- a/bffhd/resources/db.rs +++ b/bffhd/resources/db.rs @@ -6,6 +6,7 @@ use crate::db::RawDB; use std::sync::Arc; use crate::db::{Environment, DatabaseFlags}; use crate::db::Result; +use crate::resources::state::db::StateDB; #[derive(Clone, Debug, PartialEq, Eq)] #[derive(Archive, Serialize, Deserialize)] @@ -15,56 +16,4 @@ pub struct Resource { id: String, name_idx: u64, description_idx: u64, -} - -#[derive(Debug, Clone)] -pub struct ResourceDB { - env: Arc, - db: DB>, - id_index: DB>, -} - -impl ResourceDB { - pub unsafe fn new(env: Arc, db: RawDB, id_index: RawDB) -> Self { - let db = DB::new_unchecked(db); - let id_index = DB::new_unchecked(id_index); - - Self { env, db, id_index } - } - - pub unsafe fn open(env: Arc) -> Result { - let db = RawDB::open(&env, Some("resources"))?; - let idx = RawDB::open(&env, Some("resources-idx"))?; - Ok(Self::new(env, db, idx)) - } - - pub unsafe fn create(env: Arc) -> Result { - let flags = DatabaseFlags::empty(); - let db = RawDB::create(&env, Some("resources"), flags)?; - let idx = RawDB::create(&env, Some("resources-idx"), flags)?; - Ok(Self::new(env, db, idx)) - } - - pub fn lookup_id>(&self, id: S) -> Result> { - let txn = self.env.begin_ro_txn()?; - let id = self.id_index.get(&txn, &id.as_ref().as_bytes()).map(|ok| { - ok.map(|num| *num) - })?; - Ok(id) - } - - pub fn get_all(&self) -> Result> { - let txn = self.env.begin_ro_txn()?; - let mut cursor = self.id_index.open_ro_cursor(&txn)?; - let iter = cursor.iter_start(); - let mut out = Vec::new(); - - for id in iter { - let (name, id) = id?; - let name = unsafe { std::str::from_utf8_unchecked(name).to_string() }; - out.push((name, *id)); - } - - Ok(out) - } } \ No newline at end of file diff --git a/bffhd/resources/driver.rs b/bffhd/resources/driver.rs index 156f4f6..3e188b7 100644 --- a/bffhd/resources/driver.rs +++ b/bffhd/resources/driver.rs @@ -4,9 +4,9 @@ use async_trait::async_trait; use futures_signals::signal::Mutable; use async_oneshot::Sender; use async_channel::Receiver; +use crate::resources::state::db::StateDB; use super::state::State; -use super::state::db::StateAccessor; /// A resources in BFFH has to contain several different parts; /// - Currently set state @@ -77,7 +77,8 @@ pub struct ResourceDriver { rx: Receiver, // output - db: StateAccessor, + db: StateDB, + key: String, signal: Mutable, } @@ -99,7 +100,7 @@ impl ResourceDriver { // "Best" solution would be to tell the resources to rollback their interal // changes on a fatal failure and then notify the Claimant, while simply trying // again for temporary failures. - let _ = self.db.set(&state, &outstate); + let _ = self.db.update(self.key.as_bytes(), &state, &outstate); self.signal.set(outstate); }, Err(e) => { diff --git a/bffhd/resources/mod.rs b/bffhd/resources/mod.rs index 4b0653d..7388dca 100644 --- a/bffhd/resources/mod.rs +++ b/bffhd/resources/mod.rs @@ -1,4 +1,11 @@ +use std::ops::Deref; +use std::sync::Arc; +use futures_signals::signal::{Mutable, Signal, SignalExt}; +use lmdb::RoTransaction; +use rkyv::Archived; +use crate::db::LMDBorrow; use crate::resources::modules::fabaccess::{MachineState, Status}; +use crate::resources::state::db::StateDB; use crate::resources::state::State; use crate::session::SessionHandle; use crate::users::User; @@ -13,15 +20,78 @@ pub mod modules; pub struct PermissionDenied; -#[derive(Clone)] -pub struct Resource {} +pub(crate) struct Inner { + id: String, + db: StateDB, + signal: Mutable, +} +impl Inner { + pub fn new(id: String, db: StateDB) -> 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"); + state + } else { + tracing::info!(%id, "No previous state, defaulting to `free`"); + MachineState::free(None) + }; + let signal = Mutable::new(state); -impl Resource { - pub fn get_state(&self) -> MachineState { - unimplemented!() + Self { id, db, signal } + } + + pub fn signal(&self) -> impl Signal { + Box::pin(self.signal.signal_cloned().dedupe_cloned()) + } + + fn get_state(&self) -> MachineState { + MachineState::from(&self.db.get_output(self.id.as_bytes()).unwrap().unwrap()) + } + + fn get_raw_state(&self) -> Option>> { + self.db.get_output(self.id.as_bytes()).unwrap() } fn set_state(&self, state: MachineState) { + let span = tracing::debug_span!("set", id = %self.id, ?state, "Updating state"); + let _guard = span.enter(); + tracing::debug!("Updating state"); + tracing::trace!("Updating DB"); + let update = state.to_state(); + self.db.update(self.id.as_bytes(), &update, &update).unwrap(); + tracing::trace!("Updated DB, sending update signal"); + self.signal.set(state); + tracing::trace!("Sent update signal"); + } +} + +#[derive(Clone)] +pub struct Resource { + inner: Arc +} + +impl Resource { + pub(crate) fn new(inner: Arc) -> Self { + Self { inner } + } + + pub fn get_raw_state(&self) -> Option>> { + self.inner.get_raw_state() + } + + pub fn get_state(&self) -> MachineState { + self.inner.get_state() + } + + pub fn get_id(&self) -> &str { + &self.inner.id + } + + fn set_state(&self, state: MachineState) { + + } + + fn set_status(&self, state: Status) { unimplemented!() } @@ -29,14 +99,14 @@ impl Resource { unimplemented!() } - pub async fn try_update(&self, session: SessionHandle, new: MachineState) { + pub async fn try_update(&self, session: SessionHandle, new: Status) { let old = self.get_state(); let user = session.get_user(); if session.has_manage(self) // Default allow for managers || (session.has_write(self) // Decision tree for writers - && match (old.state, &new.state) { + && match (old.state, &new) { // Going from available to used by the person requesting is okay. (Status::Free, Status::InUse(who)) // Check that the person requesting does not request for somebody else. @@ -67,7 +137,7 @@ impl Resource { }) // Default permissions everybody has - || match (old.state, &new.state) { + || match (old.state, &new) { // Returning things we've been using is okay. This includes both if // they're being freed or marked as to be checked. (Status::InUse(who), Status::Free | Status::ToCheck(_)) if who == user => true, @@ -79,20 +149,19 @@ impl Resource { _ => false, } { - self.set_state(new); + self.set_status(new); } } pub async fn give_back(&self, session: SessionHandle) { if let Status::InUse(user) = self.get_state().state { if user == session.get_user() { - self.set_state(MachineState::free()); - self.set_previous_user(user); + self.set_state(MachineState::free(Some(user))); } } } - pub async fn force_set(&self, new: MachineState) { + pub async fn force_set(&self, new: Status) { unimplemented!() } diff --git a/bffhd/resources/modules/fabaccess.rs b/bffhd/resources/modules/fabaccess.rs index 3d6ccd0..42b0b11 100644 --- a/bffhd/resources/modules/fabaccess.rs +++ b/bffhd/resources/modules/fabaccess.rs @@ -1,10 +1,13 @@ +use std::ops::Deref; use crate::utils::oid::ObjectIdentifier; use once_cell::sync::Lazy; -use rkyv::{Archive, Deserialize, Serialize}; +use rkyv::{Archive, Archived, Deserialize, Serialize, Infallible}; use rkyv_dyn::{DynError, DynSerializer}; use std::str::FromStr; use crate::oidvalue; +use crate::resources::state::{State}; +use crate::resources::state::value::Value; use crate::session::SessionHandle; use crate::users::User; @@ -49,66 +52,77 @@ pub enum Status { serde::Serialize, serde::Deserialize, )] -#[archive_attr(derive(Debug, PartialEq, serde::Serialize, serde::Deserialize))] +#[archive_attr(derive(Debug, PartialEq))] /// The status of the machine pub struct MachineState { pub state: Status, + pub previous: Option, } impl MachineState { pub fn new() -> Self { Self { state: Status::Free, + previous: None, } } - pub fn from(state: Status) -> Self { - Self { state } + pub fn from(dbstate: &Archived) -> Self { + use std::any::TypeId; + let state: &Archived = &dbstate.inner; + Deserialize::deserialize(state, &mut Infallible).unwrap() + } + pub fn to_state(&self) -> State { + State { + inner: self.clone() + } } - pub fn free() -> Self { + pub fn free(previous: Option) -> Self { Self { state: Status::Free, + previous, } } - pub fn used(user: User) -> Self { + pub fn used(user: User, previous: Option) -> Self { Self { state: Status::InUse(user), + previous, } } - pub fn blocked(user: User) -> Self { + pub fn blocked(user: User, previous: Option) -> Self { Self { state: Status::Blocked(user), + previous, } } - pub fn disabled() -> Self { + pub fn disabled(previous: Option) -> Self { Self { state: Status::Disabled, + previous, } } - pub fn reserved(user: User) -> Self { + pub fn reserved(user: User, previous: Option) -> Self { Self { state: Status::Reserved(user), + previous, } } pub fn check(user: User) -> Self { Self { state: Status::ToCheck(user), + previous: Some(user), } } - - pub fn make_used(&mut self, session: SessionHandle) -> Self { - unimplemented!() - } } -static OID_TYPE: Lazy = +pub static OID_TYPE: Lazy = Lazy::new(|| ObjectIdentifier::from_str("1.3.6.1.4.1.48398.612.1.14").unwrap()); -static OID_VALUE: Lazy = +pub static OID_VALUE: Lazy = Lazy::new(|| ObjectIdentifier::from_str("1.3.6.1.4.1.48398.612.2.4").unwrap()); oidvalue!(OID_TYPE, MachineState, ArchivedMachineState); diff --git a/bffhd/resources/state/db.rs b/bffhd/resources/state/db.rs index df73922..91116b5 100644 --- a/bffhd/resources/state/db.rs +++ b/bffhd/resources/state/db.rs @@ -29,7 +29,7 @@ use crate::resources::state::State; type StateAdapter = AllocAdapter; /// State Database containing the currently set state -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct StateDB { /// The environment for all the databases below env: Arc, @@ -55,18 +55,6 @@ impl StateDB { Self { env: Arc::new(env), input, output } } - pub fn init>(path: P) -> lmdb::Result { - let env = Self::open_env(path)?; - let input = unsafe { - DB::create(&env, Some("input"), DatabaseFlags::INTEGER_KEY)? - }; - let output = unsafe { - DB::create(&env, Some("output"), DatabaseFlags::INTEGER_KEY)? - }; - - Ok(Self::new(env, input, output)) - } - pub fn open>(path: P) -> lmdb::Result { let env = Self::open_env(path)?; let input = unsafe { DB::open(&env, Some("input"))? }; @@ -84,17 +72,17 @@ impl StateDB { Ok(Self::new(env, input, output)) } - fn update_txn(&self, txn: &mut RwTransaction, key: u64, input: &State, output: &State) + fn update_txn(&self, txn: &mut RwTransaction, key: impl AsRef<[u8]>, input: &State, output: &State) -> Result<(), DBError> { let flags = WriteFlags::empty(); - let k = key.to_ne_bytes(); + let k = key.as_ref(); self.input.put(txn, &k, input, flags)?; self.output.put(txn, &k, output, flags)?; Ok(()) } - pub fn update(&self, key: u64, input: &State, output: &State) + pub fn update(&self, key: impl AsRef<[u8]>, input: &State, output: &State) -> Result<(), DBError> { let mut txn = self.env.begin_rw_txn().map_err(StateAdapter::from_db_err)?; @@ -103,11 +91,11 @@ impl StateDB { txn.commit().map_err(StateAdapter::from_db_err) } - fn get(&self, db: &DB, key: u64) + fn get(&self, db: &DB, key: impl AsRef<[u8]>) -> Result>>, DBError> { let txn = self.env.begin_ro_txn().map_err(StateAdapter::from_db_err)?; - if let Some(state) = db.get(&txn, &key.to_ne_bytes())? { + if let Some(state) = db.get(&txn, &key.as_ref())? { let ptr = state.into(); Ok(Some(unsafe { LMDBorrow::new(ptr, txn) })) } else { @@ -116,46 +104,14 @@ impl StateDB { } #[inline(always)] - pub fn get_input(&self, key: u64) + pub fn get_input(&self, key: impl AsRef<[u8]>) -> Result>>, DBError> { self.get(&self.input, key) } #[inline(always)] - pub fn get_output(&self, key: u64) + pub fn get_output(&self, key: impl AsRef<[u8]>) -> Result>>, DBError> { self.get(&self.output, key) } - - pub fn accessor(&self, key: u64) -> StateAccessor { - StateAccessor::new(key, self.clone()) - } -} - -#[derive(Debug)] -pub struct StateAccessor { - key: u64, - db: StateDB -} - -impl StateAccessor { - pub fn new(key: u64, db: StateDB) -> Self { - Self { key, db } - } - - pub fn get_input(&self) - -> Result>>, DBError> - { - self.db.get_input(self.key) - } - - pub fn get_output(&self) - -> Result>>, DBError> - { - self.db.get_output(self.key) - } - - pub fn set(&self, input: &State, output: &State) -> Result<(), DBError> { - self.db.update(self.key, input, output) - } } #[cfg(test)] @@ -171,7 +127,7 @@ mod tests { let tmpdir = tempfile::tempdir().unwrap(); let mut tmppath = tmpdir.path().to_owned(); tmppath.push("db"); - let db = StateDB::init(tmppath).unwrap(); + let db = StateDB::create(tmppath).unwrap(); let b = State::build() .add(OID_COLOUR.clone(), Box::new(Vec3u8 { a: 1, b: 2, c: 3})) .add(OID_POWERED.clone(), Box::new(true)) diff --git a/bffhd/resources/state/mod.rs b/bffhd/resources/state/mod.rs index 7411199..69e02a3 100644 --- a/bffhd/resources/state/mod.rs +++ b/bffhd/resources/state/mod.rs @@ -16,159 +16,72 @@ use rkyv::{ out_field, Serialize, }; -use serde::de::{Error, MapAccess}; +use serde::de::{Error, MapAccess, Unexpected}; use serde::Deserializer; use serde::ser::SerializeMap; use value::{RegisteredImpl, SerializeValue}; +use crate::MachineState; +use crate::resources::modules::fabaccess::OID_VALUE; use crate::utils::oid::ObjectIdentifier; -use crate::resources::state::value::{DynOwnedVal, DynVal, TypeOid, }; +use crate::resources::state::value::{DynOwnedVal, DynVal, TypeOid, Value}; pub mod value; pub mod db; -#[derive(serde::Serialize, serde::Deserialize)] #[derive(Archive, Serialize, Deserialize)] -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq)] #[archive_attr(derive(Debug))] -/// State object of a resources -/// -/// This object serves three functions: -/// 1. it is constructed by modification via Claims or via internal resources logic -/// 2. it is serializable and storable in the database -/// 3. it is sendable and forwarded to all Actors and Notifys pub struct State { - pub hash: u64, - pub inner: Vec, + pub inner: MachineState, } -impl State { - pub fn build() -> StateBuilder { - StateBuilder::new() - } - pub fn hash(&self) -> u64 { - self.hash - } -} - -impl PartialEq> for State { - fn eq(&self, other: &Archived) -> bool { - self.hash == other.hash - } -} - -impl Eq for State {} - impl fmt::Debug for State { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut sf = f.debug_struct("State"); - for OwnedEntry { oid, val } in self.inner.iter() { - let k: String = oid.into(); - sf.field(k.as_ref(), val); - } + //for Entry { oid, val } in self.inner.iter() { + let k: String = OID_VALUE.deref().into(); + sf.field(k.as_ref(), &self.inner); + //} sf.finish() } } -#[derive(Debug)] -pub struct StateBuilder { - hasher: DefaultHasher, - inner: Vec -} - -impl StateBuilder { - pub fn new() -> Self { - let hasher = DefaultHasher::new(); - Self { inner: Vec::new(), hasher } - } - - pub fn finish(self) -> State { - State { - hash: self.hasher.finish(), - inner: self.inner, - } - } - - /// Add key-value pair to the State being built. - /// - /// We have to use this split system here because type erasure prevents us from limiting values - /// to `Hash`. Specifically, you can't have a trait object of `Hash` because `Hash` depends on - /// `Self`. In this function however the compiler still knows the exact type of `V` and can - /// call statically call its `hash` method. - pub fn add(mut self, oid: ObjectIdentifier, val: Box) -> Self - where V: SerializeValue + Hash + Archive, - Archived: TypeOid + RegisteredImpl, - { - // Hash before creating the StateEntry struct which removes the type information - oid.hash(&mut self.hasher); - val.hash(&mut self.hasher); - self.inner.push(OwnedEntry { oid, val }); - - self - } -} - -#[derive(Debug)] -pub struct Entry<'a> { - pub oid: &'a ObjectIdentifier, - pub val: &'a dyn SerializeValue, -} - -#[derive(Debug, Clone, Archive, Serialize, Deserialize)] -#[archive_attr(derive(Debug))] -pub struct OwnedEntry { - pub oid: ObjectIdentifier, - pub val: Box, -} - -impl PartialEq for OwnedEntry { - fn eq(&self, other: &Self) -> bool { - self.oid == other.oid && self.val.dyn_eq(other.val.as_value()) - } -} - -impl<'a> serde::Serialize for Entry<'a> { +impl serde::Serialize for State { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer { let mut ser = serializer.serialize_map(Some(1))?; - ser.serialize_entry(&self.oid, &DynVal(self.val))?; + ser.serialize_entry(OID_VALUE.deref(), &self.inner)?; ser.end() } } - -impl serde::Serialize for OwnedEntry { - fn serialize(&self, serializer: S) -> Result - where S: serde::Serializer - { - let mut ser = serializer.serialize_map(Some(1))?; - ser.serialize_entry(&self.oid, &DynVal(self.val.deref()))?; - ser.end() - } -} -impl<'de> serde::Deserialize<'de> for OwnedEntry { +impl<'de> serde::Deserialize<'de> for State { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { - deserializer.deserialize_map(OwnedEntryVisitor) + deserializer.deserialize_map(StateVisitor) } } -struct OwnedEntryVisitor; -impl<'de> serde::de::Visitor<'de> for OwnedEntryVisitor { - type Value = OwnedEntry; +struct StateVisitor; +impl<'de> serde::de::Visitor<'de> for StateVisitor { + type Value = State; fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - write!(formatter, "an one entry map from OID to some value object") + write!(formatter, "a map from OIDs to value objects") } fn visit_map>(self, mut map: A) -> Result { let oid: ObjectIdentifier = map.next_key()? .ok_or(A::Error::missing_field("oid"))?; - let val: DynOwnedVal = map.next_value()?; - Ok(OwnedEntry { oid, val: val.0 }) + if oid != *OID_VALUE.deref() { + return Err(A::Error::invalid_value(Unexpected::Other("Unknown OID"), &"OID of fabaccess state")) + } + let val: MachineState = map.next_value()?; + Ok(State { inner: val }) } } diff --git a/bffhd/resources/state/value.rs b/bffhd/resources/state/value.rs index 91dfadf..0367f2c 100644 --- a/bffhd/resources/state/value.rs +++ b/bffhd/resources/state/value.rs @@ -276,8 +276,8 @@ impl Clone for Box { } #[ptr_meta::pointee] -pub trait DeserializeValue: Value + DeserializeDynOid {} -impl DeserializeValue for T {} +pub trait DeserializeValue: DeserializeDynOid {} +impl DeserializeValue for T {} impl ArchivePointee for dyn DeserializeValue { type ArchivedMetadata = ArchivedValueMetadata; diff --git a/bin/bffhd/main.rs b/bin/bffhd/main.rs index 6646bc2..758f6ae 100644 --- a/bin/bffhd/main.rs +++ b/bin/bffhd/main.rs @@ -1,5 +1,5 @@ use clap::{Arg, Command}; -use diflouroborane::db::{Databases, Dump}; +use diflouroborane::db::Dump; use diflouroborane::{config, Diflouroborane, error::Error}; use std::net::ToSocketAddrs; use std::os::unix::prelude::AsRawFd;