Make machine correctly load state and set previous/current use in API

This commit is contained in:
Nadja Reitzenstein 2021-12-01 15:46:52 +01:00
parent 9fcb7664aa
commit 47781b445e
7 changed files with 131 additions and 34 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "diflouroborane"
version = "0.3.0"
version = "0.3.1"
authors = [ "dequbed <me@dequbed.space>"
, "Kai Jan Kriegel <kai@kjkriegel.de>"
, "Joseph Langosch <thejoklla@gmail.com>"

View File

@ -65,13 +65,52 @@ impl info::Server for Machine {
_: info::GetMachineInfoExtendedParams,
mut results: info::GetMachineInfoExtendedResults,
) -> Promise<(), capnp::Error> {
if self.perms.manage {
let mut builder = results.get();
let mut extinfo = builder.init_machine_info_extended();
let mut current = extinfo.init_current_user();
current.set_username(&self.userid.uid);
}
Promise::ok(())
let machine = self.machine.get_inner();
let perms = self.perms.clone();
let f = async move {
if perms.manage {
let mut builder = results.get();
let mut extinfo = builder.init_machine_info_extended();
let guard = machine.lock().await;
// "previous" user
if let Some(user) = guard.get_previous() {
let mut previous = extinfo.reborrow().init_transfer_user();
previous.set_username(&user.uid);
}
let state = guard.read_state();
let state_lock = state.lock_ref();
match state_lock.state {
Status::Free => {}
Status::InUse(ref user) => if user.is_some() {
let user = user.as_ref().unwrap();
let mut current = extinfo.init_current_user();
current.set_username(&user.uid);
}
Status::ToCheck(ref user) => {
let mut current = extinfo.init_current_user();
current.set_username(&user.uid);
}
Status::Blocked(ref user) => {
let mut current = extinfo.init_current_user();
current.set_username(&user.uid);
}
Status::Disabled => {}
Status::Reserved(ref user) => {
let mut current = extinfo.init_current_user();
current.set_username(&user.uid);
}
}
}
Ok(())
};
let g = smol::future::race(f, smol::Timer::after(Duration::from_secs(4))
.map(|_| Err(capnp::Error::failed("Waiting for machine lock timed out!".to_string()))));
Promise::from_future(g)
}
fn get_reservation_list(

View File

@ -24,10 +24,12 @@ pub mod access;
/// Stores&Retrieves Machines
pub mod machine;
pub type MachineDB = machine::internal::Internal;
#[derive(Clone)]
pub struct Databases {
pub access: Arc<access::AccessControl>,
pub machine: Arc<machine::internal::Internal>,
pub machine: Arc<MachineDB>,
pub userdb: Arc<user::Internal>,
}

View File

@ -75,7 +75,7 @@ impl MachineState {
pub fn init(log: Logger, _config: &Config, env: Arc<lmdb::Environment>) -> Result<Internal> {
let mut flags = lmdb::DatabaseFlags::empty();
flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true);
//flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true);
let machdb = env.create_db(Some("machines"), flags)?;
debug!(&log, "Opened machine db successfully.");

View File

@ -2,7 +2,7 @@ use std::sync::Arc;
use slog::Logger;
use lmdb::{Environment, Transaction, RwTransaction, Cursor};
use lmdb::{Environment, Transaction, RwTransaction, Cursor, RoTransaction};
use super::{MachineIdentifier, MachineState};
use crate::error::Result;
@ -37,11 +37,11 @@ impl Internal {
self.get_with_txn(&txn, id)
}
pub fn put_with_txn(&self, txn: &mut RwTransaction, uuid: &String, status: &MachineState)
pub fn put_with_txn(&self, txn: &mut RwTransaction, id: &String, status: &MachineState)
-> Result<()>
{
let bytes = flexbuffers::to_vec(status)?;
txn.put(self.db, &uuid.as_bytes(), &bytes, lmdb::WriteFlags::empty())?;
txn.put(self.db, &id.as_bytes(), &bytes, lmdb::WriteFlags::empty())?;
Ok(())
}
@ -52,11 +52,20 @@ impl Internal {
txn.commit().map_err(Into::into)
}
pub fn iter<T: Transaction>(&self, txn: &T) -> Result<impl Iterator<Item=MachineState>> {
pub fn iter<'txn, T: Transaction>(&self, txn: &'txn T)
-> Result<impl Iterator<Item=(&'txn str, MachineState)>>
{
let mut cursor = txn.open_ro_cursor(self.db)?;
Ok(cursor.iter_start().map(|buf| {
let (_kbuf, vbuf) = buf.unwrap();
flexbuffers::from_slice(vbuf).unwrap()
let (kbuf, vbuf) = buf.unwrap();
let id = unsafe { std::str::from_utf8_unchecked(kbuf) };
let state = flexbuffers::from_slice(vbuf).unwrap();
(id, state)
}))
}
pub fn txn(&self) -> Result<RoTransaction> {
let txn = self.env.begin_ro_txn()?;
Ok(txn)
}
}

View File

@ -19,12 +19,13 @@ use futures::channel::{mpsc, oneshot};
use futures_signals::signal::Signal;
use futures_signals::signal::SignalExt;
use futures_signals::signal::{Mutable, ReadOnlyMutable};
use slog::Logger;
use crate::error::{Result, Error};
use crate::db::access;
use crate::db::{access, Databases, MachineDB};
use crate::db::machine::{MachineIdentifier, MachineState, Status};
use crate::db::user::{User, UserData};
use crate::db::user::{User, UserData, UserId};
use crate::network::MachineMap;
use crate::space;
@ -73,13 +74,14 @@ impl Machine {
}
}
pub fn construct
( id: MachineIdentifier
, desc: MachineDescription
, state: MachineState
) -> Machine
pub fn construct(
id: MachineIdentifier,
desc: MachineDescription,
state: MachineState,
db: Arc<MachineDB>,
) -> Machine
{
Self::new(Inner::new(id, state), desc)
Self::new(Inner::new(id, state, db), desc)
}
pub fn do_state_change(&self, new_state: MachineState)
@ -136,17 +138,20 @@ pub struct Inner {
/// case of an actor it should then make sure that the real world matches up with the set state
state: Mutable<MachineState>,
reset: Option<MachineState>,
previous: Option<UserId>,
db: Arc<MachineDB>,
}
impl Inner {
pub fn new ( id: MachineIdentifier
, state: MachineState
) -> Inner
{
pub fn new(id: MachineIdentifier, state: MachineState, db: Arc<MachineDB>) -> Inner {
Inner {
id,
state: Mutable::new(state),
reset: None,
previous: None,
db,
}
}
@ -162,8 +167,13 @@ impl Inner {
Box::pin(self.state.signal_cloned().dedupe_cloned())
}
fn replace_state(&mut self, new_state: MachineState) -> MachineState {
self.db.put(&self.id, &new_state);
self.state.replace(new_state)
}
pub fn do_state_change(&mut self, new_state: MachineState) {
let old_state = self.state.replace(new_state);
let old_state = self.replace_state(new_state);
self.reset.replace(old_state);
}
@ -176,9 +186,30 @@ impl Inner {
}
pub fn reset_state(&mut self) {
if let Some(state) = self.reset.take() {
self.state.replace(state);
let previous_state = self.read_state();
let state_lock = previous_state.lock_ref();
// Only update previous user if state changed from InUse or ToCheck to whatever.
match state_lock.state {
Status::InUse(ref user) => {
self.previous = user.clone();
},
Status::ToCheck(ref user) => {
self.previous = Some(user.clone());
},
_ => {},
}
drop(state_lock);
if let Some(state) = self.reset.take() {
self.replace_state(state);
} else {
// Default to Free
self.replace_state(MachineState::free());
}
}
pub fn get_previous(&self) -> &Option<UserId> {
&self.previous
}
}
@ -242,15 +273,22 @@ impl MachineDescription {
}
}
pub fn load(config: &crate::config::Config)
pub fn load(config: &crate::config::Config, db: Databases, log: &Logger)
-> Result<MachineMap>
{
let mut map = config.machines.clone();
let db = db.machine;
let it = map.drain()
.map(|(k,v)| {
// TODO: Read state from the state db
(v.name.clone(), Machine::construct(k, v, MachineState::new()))
if let Some(state) = db.get(&k).unwrap() {
debug!(log, "Loading old state from db for {}: {:?}", &k, &state);
(v.name.clone(), Machine::construct(k, v, state, db.clone()))
} else {
debug!(log, "No old state found in db for {}, creating new.", &k);
(v.name.clone(), Machine::construct(k, v, MachineState::new(), db.clone()))
}
});

View File

@ -167,7 +167,16 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
let ex = Executor::new();
let db = db::Databases::new(&log, &config)?;
let machines = machine::load(&config)?;
{
info!(log, "Loaded DB state:");
let txn = db.machine.txn()?;
for (id, state) in db.machine.iter(&txn)? {
info!(log, "- {}: {:?}", id, state);
}
info!(log, "Loaded DB state END.");
}
let machines = machine::load(&config, db.clone(), &log)?;
let (actor_map, actors) = actor::load(&log, &config)?;
let (init_map, initiators) = initiator::load(&log, &config)?;