mirror of
https://github.com/deuxfleurs-org/garage.git
synced 2026-08-20 01:52:15 +00:00
Uniform framework for bg variable management
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
//! Job runner for futures and async functions
|
||||
|
||||
pub mod vars;
|
||||
pub mod worker;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::error::{Error, OkOrMessage};
|
||||
use crate::migrate::Migrate;
|
||||
use crate::persister::PersisterShared;
|
||||
|
||||
pub struct BgVars {
|
||||
vars: HashMap<&'static str, Box<dyn BgVarTrait>>,
|
||||
}
|
||||
|
||||
impl BgVars {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
vars: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_rw<V, T, GF, SF>(
|
||||
&mut self,
|
||||
p: &PersisterShared<V>,
|
||||
name: &'static str,
|
||||
get_fn: GF,
|
||||
set_fn: SF,
|
||||
) where
|
||||
V: Migrate + Default + Send + Sync,
|
||||
T: FromStr + ToString + Send + Sync + 'static,
|
||||
GF: Fn(&PersisterShared<V>) -> T + Send + Sync + 'static,
|
||||
SF: Fn(&PersisterShared<V>, T) -> Result<(), Error> + Send + Sync + 'static,
|
||||
{
|
||||
let p1 = p.clone();
|
||||
let get_fn = move || get_fn(&p1);
|
||||
|
||||
let p2 = p.clone();
|
||||
let set_fn = move |v| set_fn(&p2, v);
|
||||
|
||||
self.vars.insert(name, Box::new(BgVar { get_fn, set_fn }));
|
||||
}
|
||||
|
||||
pub fn register_ro<V, T, GF>(&mut self, p: &PersisterShared<V>, name: &'static str, get_fn: GF)
|
||||
where
|
||||
V: Migrate + Default + Send + Sync,
|
||||
T: FromStr + ToString + Send + Sync + 'static,
|
||||
GF: Fn(&PersisterShared<V>) -> T + Send + Sync + 'static,
|
||||
{
|
||||
let p1 = p.clone();
|
||||
let get_fn = move || get_fn(&p1);
|
||||
|
||||
let set_fn = move |_| Err(Error::Message(format!("Cannot set value of {}", name)));
|
||||
|
||||
self.vars.insert(name, Box::new(BgVar { get_fn, set_fn }));
|
||||
}
|
||||
|
||||
pub fn get(&self, var: &str) -> Result<String, Error> {
|
||||
Ok(self
|
||||
.vars
|
||||
.get(var)
|
||||
.ok_or_message("variable does not exist")?
|
||||
.get())
|
||||
}
|
||||
|
||||
pub fn get_all(&self) -> Vec<(&'static str, String)> {
|
||||
self.vars.iter().map(|(k, v)| (*k, v.get())).collect()
|
||||
}
|
||||
|
||||
pub fn set(&self, var: &str, val: &str) -> Result<(), Error> {
|
||||
self.vars
|
||||
.get(var)
|
||||
.ok_or_message("variable does not exist")?
|
||||
.set(val)
|
||||
}
|
||||
}
|
||||
|
||||
// ----
|
||||
|
||||
trait BgVarTrait: Send + Sync + 'static {
|
||||
fn get(&self) -> String;
|
||||
fn set(&self, v: &str) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
struct BgVar<T, GF, SF>
|
||||
where
|
||||
T: FromStr + ToString + Send + Sync + 'static,
|
||||
GF: Fn() -> T + Send + Sync + 'static,
|
||||
SF: Fn(T) -> Result<(), Error> + Sync + Send + 'static,
|
||||
{
|
||||
get_fn: GF,
|
||||
set_fn: SF,
|
||||
}
|
||||
|
||||
impl<T, GF, SF> BgVarTrait for BgVar<T, GF, SF>
|
||||
where
|
||||
T: FromStr + ToString + Sync + Send + 'static,
|
||||
GF: Fn() -> T + Sync + Send + 'static,
|
||||
SF: Fn(T) -> Result<(), Error> + Sync + Send + 'static,
|
||||
{
|
||||
fn get(&self) -> String {
|
||||
(self.get_fn)().to_string()
|
||||
}
|
||||
|
||||
fn set(&self, vstr: &str) -> Result<(), Error> {
|
||||
let value = vstr
|
||||
.parse()
|
||||
.map_err(|_| Error::Message(format!("invalid value: {}", vstr)))?;
|
||||
(self.set_fn)(value)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
@@ -84,3 +85,36 @@ impl<T: Migrate> Persister<T> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PersisterShared<V: Migrate + Default>(Arc<(Persister<V>, RwLock<V>)>);
|
||||
|
||||
impl<V: Migrate + Default> Clone for PersisterShared<V> {
|
||||
fn clone(&self) -> PersisterShared<V> {
|
||||
PersisterShared(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Migrate + Default> PersisterShared<V> {
|
||||
pub fn new(base_dir: &Path, file_name: &str) -> Self {
|
||||
let persister = Persister::new(base_dir, file_name);
|
||||
let value = persister.load().unwrap_or_default();
|
||||
Self(Arc::new((persister, RwLock::new(value))))
|
||||
}
|
||||
|
||||
pub fn get_with<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&V) -> R,
|
||||
{
|
||||
let value = self.0 .1.read().unwrap();
|
||||
f(&value)
|
||||
}
|
||||
|
||||
pub fn set_with<F>(&self, f: F) -> Result<(), Error>
|
||||
where
|
||||
F: FnOnce(&mut V),
|
||||
{
|
||||
let mut value = self.0 .1.write().unwrap();
|
||||
f(&mut value);
|
||||
self.0 .0.save(&value)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user