From 9d7ba0eeda37358825adaa29bf5091ccb09c2636 Mon Sep 17 00:00:00 2001 From: Gregor Reitzenstein Date: Fri, 18 Sep 2020 13:14:24 +0200 Subject: [PATCH] MachineDB dump/load --- src/machine.rs | 96 ++++++++++++++++++++++++++++++++++++++++---------- src/main.rs | 12 ++++--- 2 files changed, 85 insertions(+), 23 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 9229e76..3cd8a62 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,6 +1,9 @@ +use std::str::FromStr; use std::collections::HashMap; +use std::fs; use std::fs::File; use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; use slog::Logger; @@ -17,7 +20,7 @@ use capnp::Error; use uuid::Uuid; -use lmdb::{Transaction, RwTransaction}; +use lmdb::{Transaction, RwTransaction, Cursor}; use smol::channel::{Receiver, Sender}; @@ -39,17 +42,6 @@ pub enum Status { Blocked, } -pub struct MachinesProvider { - log: Logger, - mdb: MachineDB, -} - -impl MachinesProvider { - pub fn new(log: Logger, mdb: MachineDB) -> Self { - Self { log, mdb } - } -} - #[derive(Clone)] pub struct Machines { inner: Arc>, @@ -167,13 +159,14 @@ impl Machine { } } -pub struct MachineDB { +pub struct MachinesProvider { + log: Logger, db: lmdb::Database, } -impl MachineDB { - pub fn new(db: lmdb::Database) -> Self { - Self { db } +impl MachinesProvider { + pub fn new(log: Logger, db: lmdb::Database) -> Self { + Self { log, db } } pub fn get_machine(&self, txn: &T, uuid: Uuid) @@ -199,8 +192,75 @@ impl MachineDB { Ok(()) } + + pub fn load_db(&mut self, txn: &mut RwTransaction, mut path: PathBuf) -> Result<()> { + path.push("machines"); + for entry in std::fs::read_dir(path)? { + let entry = entry?; + let path = entry.path(); + if path.is_file() { + // will only ever be none if the path has no file name and then how is it a file?! + let machID_str = path + .file_stem().expect("Found a file with no filename?") + .to_str().expect("Found an OsStr that isn't valid Unicode. Fix your OS!"); + let machID = match uuid::Uuid::from_str(machID_str) { + Ok(i) => i, + Err(e) => { + warn!(self.log, "File {} had a invalid name. Expected an u64 in [0-9a-z] hex with optional file ending: {}. Skipping!", path.display(), e); + continue; + } + }; + let s = match fs::read_to_string(path.as_path()) { + Ok(s) => s, + Err(e) => { + warn!(self.log, "Failed to open file {}: {}, skipping!" + , path.display() + , e); + continue; + } + }; + let mach: Machine = match toml::from_str(&s) { + Ok(r) => r, + Err(e) => { + warn!(self.log, "Failed to parse mach at path {}: {}, skipping!" + , path.display() + , e); + continue; + } + }; + self.put_machine(txn, machID, mach)?; + debug!(self.log, "Loaded machine {}", machID); + } else { + warn!(self.log, "Path {} is not a file, skipping!", path.display()); + } + } + + Ok(()) + } + + pub fn dump_db(&self, txn: &T, mut path: PathBuf) -> Result<()> { + path.push("machines"); + let mut mach_cursor = txn.open_ro_cursor(self.db)?; + for buf in mach_cursor.iter_start() { + let (kbuf, vbuf) = buf?; + let machID = uuid::Uuid::from_slice(kbuf).unwrap(); + let mach: Machine = flexbuffers::from_slice(vbuf)?; + let filename = format!("{}.yml", machID.to_hyphenated().to_string()); + path.set_file_name(filename); + let mut fp = std::fs::File::create(&path)?; + let out = toml::to_vec(&mach)?; + fp.write_all(&out)?; + } + + Ok(()) + } } -pub async fn init(log: Logger, config: &Settings) -> Result { - unimplemented!() +pub fn init(log: Logger, config: &Settings, env: &lmdb::Environment) -> Result { + let mut flags = lmdb::DatabaseFlags::empty(); + flags.set(lmdb::DatabaseFlags::INTEGER_KEY, true); + let machdb = env.create_db(Some("machines"), flags)?; + debug!(&log, "Opened machine db successfully."); + + Ok(MachinesProvider::new(log, machdb)) } diff --git a/src/main.rs b/src/main.rs index 7e8739e..facdb4c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,7 +132,7 @@ fn main() -> Result<(), Error> { // Start loading the machine database, authentication system and permission system // All of those get a custom logger so the source of a log message can be better traced and // filtered - let machinedb_f = machine::init(log.new(o!("system" => "machines")), &config); + let mdb = machine::init(log.new(o!("system" => "machines")), &config, &env); let pdb = access::init(log.new(o!("system" => "permissions")), &config, &env); let authentication_f = auth::init(log.new(o!("system" => "authentication")), config.clone()); @@ -148,7 +148,8 @@ fn main() -> Result<(), Error> { let mut txn = env.begin_rw_txn()?; let path = path.to_path_buf(); - pdb?.load_db(&mut txn, path)?; + pdb?.load_db(&mut txn, path.clone())?; + mdb?.load_db(&mut txn, path)?; txn.commit(); } else { error!(log, "You must provide a directory path to load from"); @@ -165,9 +166,9 @@ fn main() -> Result<(), Error> { let txn = env.begin_ro_txn()?; let path = path.to_path_buf(); - pdb?.dump_db(&txn, path)?; + pdb?.dump_db(&txn, path.clone())?; + mdb?.dump_db(&txn, path)?; } else { - error!(log, "You must provide a directory path to dump into"); } @@ -204,7 +205,7 @@ fn main() -> Result<(), Error> { //}); // Error out if any of the subsystems failed to start. - //let mach = mach?; + let mdb = mdb?; let pdb = pdb?; //let auth = auth?; @@ -240,6 +241,7 @@ fn main() -> Result<(), Error> { use uuid::Uuid; use machine::{Status, Machine}; let mut machine = Machine::new(Uuid::new_v4(), "Testmachine".to_string(), 0); + println!("{}", toml::to_string(&machine).unwrap()); let f = regs.actuators.subscribe("shelly".to_string(), machine.signal()); exec.run_until(f);