diff --git a/bffhd/actors/mod.rs b/bffhd/actors/mod.rs index c52c2e7..176dd90 100644 --- a/bffhd/actors/mod.rs +++ b/bffhd/actors/mod.rs @@ -16,6 +16,8 @@ use std::task::{Context, Poll}; use std::time::Duration; use once_cell::sync::Lazy; +use rumqttc::ConnectReturnCode::Success; +use rumqttc::Packet::ConnAck; use rustls::{RootCertStore}; use url::Url; use crate::actors::dummy::Dummy; @@ -153,6 +155,13 @@ pub fn load(executor: Executor, config: &Config, resources: ResourcesHandle) -> async move { match eventloop.poll().await { Ok(Event::Incoming(Incoming::Connect(_connect))) => {} + Ok(Event::Incoming(Incoming::ConnAck(connack))) => { + if connack.code == Success { + tracing::debug!(?connack, "MQTT connection established"); + } else { + tracing::error!(?connack, "MQTT connect failed"); + } + } Ok(event) => { tracing::warn!(?event, "Got unexpected mqtt event"); } diff --git a/bffhd/capnp/machine.rs b/bffhd/capnp/machine.rs index 4eb8573..952bdc4 100644 --- a/bffhd/capnp/machine.rs +++ b/bffhd/capnp/machine.rs @@ -1,10 +1,12 @@ -use crate::resources::modules::fabaccess::{Status}; +use crate::resources::modules::fabaccess::{ArchivedStatus, Status}; use crate::resources::Resource; use crate::session::SessionHandle; use api::machine_capnp::machine::{ admin, admin::Server as AdminServer, check, check::Server as CheckServer, in_use as inuse, in_use::Server as InUseServer, info, info::Server as InfoServer, manage, - manage::Server as ManageServer, use_, use_::Server as UseServer, Builder, + manage::Server as ManageServer, use_, use_::Server as UseServer, + + Builder, MachineState, }; use capnp::capability::Promise; use capnp_rpc::pry; @@ -16,9 +18,71 @@ pub struct Machine { } impl Machine { + pub fn new(session: SessionHandle, resource: Resource) -> Self { + Self { session, resource } + } + + pub fn build_into(self, mut builder: Builder) { + if self.resource.visible(&self.session) { + + builder.set_id(self.resource.get_id()); + builder.set_name(self.resource.get_name()); + if let Some(ref desc) = self.resource.get_description().description { + builder.set_description(desc); + } + if let Some(ref wiki) = self.resource.get_description().wiki { + builder.set_wiki(wiki); + } + if let Some(ref category) = self.resource.get_description().category { + builder.set_category(category); + } + builder.set_urn(&format!("urn:fabaccess:resource:{}", self.resource.get_id())); + + { + let user = self.session.get_user(); + let state = self.resource.get_state_ref(); + let state = state.as_ref(); + + if self.session.has_write(&self.resource) && match &state.inner.state { + ArchivedStatus::Free => true, + ArchivedStatus::Reserved(reserver) if reserver == &user => true, + _ => false, + } { + builder.set_use(capnp_rpc::new_client(self.clone())); + } + + if self.session.has_manage(&self.resource) { + builder.set_manage(capnp_rpc::new_client(self.clone())); + } + + // TODO: admin perm + + let s = match &state.inner.state { + ArchivedStatus::Free => MachineState::Free, + ArchivedStatus::Disabled => MachineState::Disabled, + ArchivedStatus::Blocked(_) => MachineState::Blocked, + ArchivedStatus::InUse(owner) => { + if owner == &user { + builder.set_inuse(capnp_rpc::new_client(self.clone())); + } + MachineState::InUse + }, + ArchivedStatus::Reserved(_) => MachineState::Reserved, + ArchivedStatus::ToCheck(_) => MachineState::ToCheck, + }; + if self.session.has_read(&self.resource) { + builder.set_state(s); + } + } + + builder.set_info(capnp_rpc::new_client(self)); + } + } + /// Builds a machine into the given builder. Re - pub fn build(session: SessionHandle, resource: Resource, _builder: Builder) { - if resource.visible(&session) {} + pub fn build(session: SessionHandle, resource: Resource, builder: Builder) { + let this = Self::new(session.clone(), resource.clone()); + this.build_into(builder) } } diff --git a/bffhd/resources/mod.rs b/bffhd/resources/mod.rs index 8784fd1..2c5acb6 100644 --- a/bffhd/resources/mod.rs +++ b/bffhd/resources/mod.rs @@ -35,8 +35,8 @@ impl Inner { tracing::info!(%id, ?previous, "Found previous state"); previous } else { - tracing::info!(%id, "No previous state, defaulting to `free`"); - let state = MachineState::used(UserRef::new("test".to_string()), Some(UserRef::new("prev".to_string()))); + let state = MachineState::free(None); + tracing::info!(%id, ?state, "No previous state found, setting default"); let update = state.to_state(); @@ -61,7 +61,7 @@ impl Inner { .expect("state should never be None") } - fn get_ref(&self) -> impl Deref> + '_ { + fn get_state_ref(&self) -> impl Deref> + '_ { self.signal.lock_ref() } @@ -93,10 +93,18 @@ impl Resource { self.inner.get_state() } + pub fn get_state_ref(&self) -> impl Deref> + '_ { + self.inner.get_state_ref() + } + pub fn get_id(&self) -> &str { &self.inner.id } + pub fn get_name(&self) -> &str { + self.inner.desc.name.as_str() + } + pub fn get_signal(&self) -> impl Signal> { self.inner.signal() } @@ -105,6 +113,10 @@ impl Resource { &self.inner.desc.privs } + pub fn get_description(&self) -> &MachineDescription { + &self.inner.desc + } + fn set_state(&self, state: MachineState) { let mut serializer = AllocSerializer::<1024>::default(); serializer.serialize_value(&state); @@ -181,12 +193,12 @@ impl Resource { let state = self.get_state(); let s: &Archived = state.as_ref(); let i: &Archived = &s.inner; - unimplemented!(); - /*if let Status::InUse(user) = self.get_state().state { - if user == session.get_user() { - self.set_state(MachineState::free(Some(user))); + if let ArchivedStatus::InUse(user) = &i.state { + let current = session.get_user(); + if user == ¤t { + self.set_state(MachineState::free(Some(current))); } - }*/ + } } pub async fn force_set(&self, new: Status) { diff --git a/bffhd/resources/state/db.rs b/bffhd/resources/state/db.rs index 7f39394..933adab 100644 --- a/bffhd/resources/state/db.rs +++ b/bffhd/resources/state/db.rs @@ -23,6 +23,7 @@ impl StateDB { | EnvironmentFlags::NO_TLS | EnvironmentFlags::NO_READAHEAD, ) + .set_max_dbs(8) .open(path.as_ref()) .map(Arc::new) } diff --git a/bffhd/session/mod.rs b/bffhd/session/mod.rs index 577a0bc..64a700a 100644 --- a/bffhd/session/mod.rs +++ b/bffhd/session/mod.rs @@ -25,7 +25,7 @@ impl SessionManager { pub fn open(&self, uid: impl AsRef) -> Option { let uid = uid.as_ref(); if let Some(user) = self.users.get_user(uid) { - tracing::trace!(uid, "opening new session for user"); + tracing::trace!(uid, ?user, "opening new session for user"); Some(SessionHandle { users: self.users.clone(), roles: self.roles.clone(), diff --git a/bffhd/users/db.rs b/bffhd/users/db.rs index 1af3b8c..1403777 100644 --- a/bffhd/users/db.rs +++ b/bffhd/users/db.rs @@ -105,8 +105,7 @@ impl UserDB { pub fn put(&self, uid: &str, user: &User) -> Result<(), db::Error> { let mut serializer = AllocSerializer::<1024>::default(); - let pos = serializer.serialize_value(user).expect("rkyv error"); - assert_eq!(pos, 0); + serializer.serialize_value(user).expect("rkyv error"); let v = serializer.into_serializer().into_inner(); let value = ArchivedValue::new(v); diff --git a/examples/users.toml b/examples/users.toml index 719f2fb..80a04ab 100644 --- a/examples/users.toml +++ b/examples/users.toml @@ -2,7 +2,7 @@ # These roles have to be defined in 'bffh.dhall'. # Non-existant roles will not crash the server but print a `WARN` level message in the # server log in the form "Did not find role somerole/internal while trying to tally". -roles = ["somerole/internal", "testrole/internal"] +roles = ["somerole", "testrole"] # The password will be hashed using argon2id on load time and is not available in plaintext afterwards. passwd = "secret"