Skip to content

Commit

Permalink
feat(rust): add lock file to cli state items
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianbenavides committed Nov 7, 2023
1 parent a0b0de4 commit fef75fc
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions implementations/rust/ockam/ockam_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ aws-config = { version = "0.56.1", default-features = false, features = ["rustls
base64-url = "2.0.0"
bytes = { version = "1.5.0", default-features = false, features = ["serde"] }
either = { version = "1.9.0", default-features = false }
fs2 = { version = "0.4.3" }
hex = { version = "0.4.3", default-features = false, features = ["alloc", "serde"] }
home = "0.5"
kafka-protocol = "0.7.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ impl NodeState {
fn _delete(&self, sikgill: bool) -> Result<()> {
self.kill_process(sikgill)?;
std::fs::remove_dir_all(&self.path)?;
let _ = std::fs::remove_file(self.path.with_extension("lock"));
let _ = std::fs::remove_dir(&self.path); // Make sure the dir is gone
info!(name=%self.name, "node deleted");
Ok(())
Expand Down
56 changes: 39 additions & 17 deletions implementations/rust/ockam/ockam_api/src/cli_state/traits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::cli_state::{file_stem, CliState, CliStateError};
use fs2::FileExt;
use ockam_core::errcode::{Kind, Origin};
use ockam_core::{async_trait, Error};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -82,7 +83,7 @@ pub trait StateDirTrait: Sized + Send + Sync {
config: <<Self as StateDirTrait>::Item as StateItemTrait>::Config,
) -> Result<Self::Item> {
let path = self.path(&name);
let state = Self::Item::new(path, config)?;
let state = with_lock(&path, || Self::Item::new(path.clone(), config))?;
if !self.default_path()?.exists() {
self.set_default(&name)?;
}
Expand Down Expand Up @@ -252,18 +253,38 @@ pub trait StateItemTrait: Sized + Send {

/// Persist the item to disk after updating the config.
fn persist(&self) -> Result<()> {
let contents = serde_json::to_string(self.config())?;
std::fs::write(self.path(), contents)?;
Ok(())
with_lock(self.path(), || {
let contents = serde_json::to_string(self.config())?;
std::fs::write(self.path(), contents)?;
Ok(())
})
}

fn delete(&self) -> Result<()> {
std::fs::remove_file(self.path())?;
with_lock(self.path(), || {
std::fs::remove_file(self.path())?;
Ok(())
})?;
let _ = std::fs::remove_file(self.path().with_extension("lock"));
Ok(())
}

fn path(&self) -> &PathBuf;
fn config(&self) -> &Self::Config;
}

fn with_lock<T>(path: &Path, f: impl FnOnce() -> Result<T>) -> Result<T> {
let lock_file = std::fs::OpenOptions::new()
.write(true)
.read(true)
.create(true)
.open(path.with_extension("lock"))?;
lock_file.lock_exclusive()?;
let res = f();
lock_file.unlock()?;
res
}

#[cfg(test)]
mod tests {
use crate::cli_state::{StateDirTrait, StateItemTrait};
Expand All @@ -282,14 +303,14 @@ mod tests {
}
impl StateDirTrait for TestConfig {
type Item = TestConfigItem;
const DEFAULT_FILENAME: &'static str = "";
const DIR_NAME: &'static str = "";
const DEFAULT_FILENAME: &'static str = "test";
const DIR_NAME: &'static str = "test";
const HAS_DATA_DIR: bool = false;

fn new(root_path: &Path) -> Self {
Self {
dir: Self::build_dir(root_path),
}
let dir = Self::build_dir(root_path);
std::fs::create_dir_all(&dir).unwrap();
Self { dir }
}

fn dir(&self) -> &PathBuf {
Expand All @@ -299,20 +320,21 @@ mod tests {

struct TestConfigItem {
path: PathBuf,
config: String,
config: u32,
}
impl StateItemTrait for TestConfigItem {
type Config = String;
type Config = u32;

fn new(path: PathBuf, config: Self::Config) -> crate::cli_state::Result<Self> {
Ok(TestConfigItem { path, config })
let contents = serde_json::to_string(&config)?;
std::fs::write(&path, contents)?;
Ok(Self { path, config })
}

fn load(path: PathBuf) -> crate::cli_state::Result<Self> {
Ok(TestConfigItem {
path,
config: "config".into(),
})
let contents = std::fs::read_to_string(&path)?;
let config = serde_json::from_str(&contents)?;
Ok(TestConfigItem { path, config })
}

fn path(&self) -> &PathBuf {
Expand Down

0 comments on commit fef75fc

Please sign in to comment.