From cd4874aa64172a33138410e0e787ace4930c8b3d Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Sat, 18 Sep 2021 16:31:14 +0000 Subject: [PATCH] refactor: db data --- --- a/src/db/db.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Small .toml based readable data store - -use anyhow::{Context, Result}; -use serde::{de::DeserializeOwned, Serialize}; -use std::{ - cell::Cell, - collections::HashSet, - io::Write, - ops::{Deref, DerefMut}, - path::Path, - path::PathBuf, - sync::{Arc, Mutex}, -}; - -struct DbInternal { - root: PathBuf, - locked_paths: HashSet, -} - -pub trait DbData: DeserializeOwned + Serialize + Default { - const DB_NAME: &'static str; - - fn open(db: &Db) -> Result> { - db.db::() - } -} - -#[derive(Clone)] -pub struct Db(Arc>); -impl Db { - pub fn new(root: impl AsRef) -> Result { - let root: &Path = root.as_ref(); - std::fs::create_dir_all(&root).context("db root")?; - Ok(Db(Arc::new(Mutex::new(DbInternal { - root: root.to_owned(), - locked_paths: HashSet::new(), - })))) - } - - pub fn db(&self) -> Result> { - let name = T::DB_NAME; - assert!(!name.contains("/") && !name.contains("\\")); - let mut db = self.0.lock().unwrap(); - let mut data_path = db.root.clone(); - data_path.push(format!("{}.toml", name)); - - if !db.locked_paths.insert(data_path.clone()) { - anyhow::bail!("file is already open"); - } - - let data = if data_path.exists() { - let raw_data = std::fs::read(&data_path).context("reading file")?; - toml::from_slice(&raw_data).context("parsing file")? - } else { - T::default() - }; - - Ok(DbFile { - db: self.clone(), - root: db.root.clone(), - path: data_path, - data, - dirty: Cell::new(false), - }) - } -} - -pub struct DbFile { - db: Db, - root: PathBuf, - path: PathBuf, - data: T, - dirty: Cell, -} - -impl Deref for DbFile { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.data - } -} - -impl DerefMut for DbFile { - fn deref_mut(&mut self) -> &mut Self::Target { - self.dirty.set(true); - &mut self.data - } -} - -impl DbFile { - pub fn write(&self) -> Result<()> { - if !self.dirty.get() { - return Ok(()); - } - let mut temp = tempfile::Builder::new() - .prefix("~") - .suffix(".toml") - .tempfile_in(&self.root)?; - let mut out = String::new(); - let mut serializer = toml::Serializer::new(&mut out); - serializer.pretty_array(true).pretty_string(true); - self.data.serialize(&mut serializer)?; - temp.write_all(&out.as_bytes())?; - temp.persist(&self.path)?; - self.dirty.set(false); - Ok(()) - } -} - -impl Drop for DbFile { - fn drop(&mut self) { - let mut db = self.db.0.lock().unwrap(); - self.write().unwrap(); - db.locked_paths.remove(&self.path); - } -} --- /dev/null +++ b/src/db/dbr.rs @@ -0,0 +1,117 @@ +//! Small .toml based readable data store + +use anyhow::{Context, Result}; +use serde::{de::DeserializeOwned, Serialize}; +use std::{ + cell::Cell, + collections::HashSet, + io::Write, + ops::{Deref, DerefMut}, + path::Path, + path::PathBuf, + sync::{Arc, Mutex}, +}; + +struct DbInternal { + root: PathBuf, + locked_paths: HashSet, +} + +pub trait DbData: DeserializeOwned + Serialize + Default { + const DB_NAME: &'static str; + + fn open(db: &Db) -> Result> { + db.db::() + } +} + +#[derive(Clone)] +pub struct Db(Arc>); +impl Db { + pub fn new(root: impl AsRef) -> Result { + let root: &Path = root.as_ref(); + std::fs::create_dir_all(&root).context("db root")?; + Ok(Db(Arc::new(Mutex::new(DbInternal { + root: root.to_owned(), + locked_paths: HashSet::new(), + })))) + } + + pub fn db(&self) -> Result> { + let name = T::DB_NAME; + assert!(!name.contains('/') && !name.contains('\\')); + let mut db = self.0.lock().unwrap(); + let mut data_path = db.root.clone(); + data_path.push(format!("{}.toml", name)); + + if !db.locked_paths.insert(data_path.clone()) { + anyhow::bail!("file is already open"); + } + + let data = if data_path.exists() { + let raw_data = std::fs::read(&data_path).context("reading file")?; + toml::from_slice(&raw_data).context("parsing file")? + } else { + T::default() + }; + + Ok(DbFile { + db: self.clone(), + root: db.root.clone(), + path: data_path, + data, + dirty: Cell::new(false), + }) + } +} + +pub struct DbFile { + db: Db, + root: PathBuf, + path: PathBuf, + data: T, + dirty: Cell, +} + +impl Deref for DbFile { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.data + } +} + +impl DerefMut for DbFile { + fn deref_mut(&mut self) -> &mut Self::Target { + self.dirty.set(true); + &mut self.data + } +} + +impl DbFile { + pub fn write(&self) -> Result<()> { + if !self.dirty.get() { + return Ok(()); + } + let mut temp = tempfile::Builder::new() + .prefix("~") + .suffix(".toml") + .tempfile_in(&self.root)?; + let mut out = String::new(); + let mut serializer = toml::Serializer::new(&mut out); + serializer.pretty_array(true).pretty_string(true); + self.data.serialize(&mut serializer)?; + temp.write_all(out.as_bytes())?; + temp.persist(&self.path)?; + self.dirty.set(false); + Ok(()) + } +} + +impl Drop for DbFile { + fn drop(&mut self) { + let mut db = self.db.0.lock().unwrap(); + self.write().unwrap(); + db.locked_paths.remove(&self.path); + } +} --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,4 +1,4 @@ -mod db; +mod dbr; pub mod secret; -pub use db::*; +pub use dbr::*; --- a/src/db/secret.rs +++ b/src/db/secret.rs @@ -1,5 +1,5 @@ -use crate::{command::CommandExt, host::FleetConfig, nix::SECRETS_ATTRIBUTE}; -use anyhow::{bail, Result}; +use crate::{command::CommandExt, host::FleetOpts, nix::SECRETS_ATTRIBUTE}; +use anyhow::{bail, Context, Result}; use log::info; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::{ @@ -10,7 +10,7 @@ }; use time::{Duration, PrimitiveDateTime}; -use super::db::DbData; +use super::DbData; #[derive(Serialize, Deserialize, Debug)] pub struct SecretListData { @@ -31,7 +31,9 @@ }) s) "#, ) + .arg("--json") .run_json() + .context("while getting secret list") } struct ReadableDate(PrimitiveDateTime); @@ -109,17 +111,18 @@ // Secrets are generated on machine running fleet command pub fn generate_secret( &mut self, - fleet_config: FleetConfig, + _fleet_config: &FleetOpts, secret: &str, data: &SecretListData, ) -> Result<()> { let mut rage_keys = String::new(); - for (i, owner) in data.owners.iter().enumerate() { + for (i, _owner) in data.owners.iter().enumerate() { if i != 0 { rage_keys.push(' '); } rage_keys.push_str("--recipient \""); - // rage_keys.push_str(&keys.get_host_key(&owner)?); + // rage_keys.push_str(&fleet_config.clone().build()?.host(owner)?.key()?); + //rage_keys.push_str(&keys.get_host_key(&owner)?); rage_keys.push('"') } let created_at: PrimitiveDateTime = SystemTime::now().into(); @@ -154,7 +157,7 @@ let name = entry.file_name(); let name = name .to_str() - .ok_or(anyhow::anyhow!("file name should be utf-8"))?; + .ok_or_else(|| anyhow::anyhow!("file name should be utf-8"))?; let value = String::from_utf8(std::fs::read(entry.path())?)?; if let Some(name) = name.strip_prefix("pub_") { secret_data.public_data.insert(name.into(), value); @@ -176,7 +179,7 @@ return Ok(true); } - if !secret.is_valid(&data) { + if !secret.is_valid(data) { return Ok(true); } @@ -185,12 +188,13 @@ pub fn ensure_generated( &mut self, // keys: &KeyDb, + fleet_config: &FleetOpts, secret: &str, data: &SecretListData, ) -> Result<()> { if self.need_to_generate(secret, data)? { info!("Generating secret {}", secret); - // self.generate_secret(keys, secret, data)?; + self.generate_secret(fleet_config, secret, data)?; } Ok(()) -- gitstuff