feat(settings): Settings1 стаб + атомарный стор + seed дефолтов
Store (load_or_seed/get/set/reset/list, durable-write) + SettingsService #[interface] + bin. v0: строковые значения (variant на проводе), сам сеет дефолты. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Alexander <akotenev2003@gmail.com>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
//! `ru.shturman.Settings1` — server-стаб. Хранит строки (v0); namespace-изоляция по `sender` — позже (v3).
|
||||
|
||||
use crate::store::Store;
|
||||
use shturman_ipc::Error;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use zbus::interface;
|
||||
use zbus::object_server::SignalContext;
|
||||
use zbus::zvariant::{OwnedValue, Value};
|
||||
|
||||
pub struct SettingsService {
|
||||
store: Arc<Mutex<Store>>,
|
||||
}
|
||||
|
||||
impl SettingsService {
|
||||
pub fn new(store: Store) -> Self {
|
||||
Self {
|
||||
store: Arc::new(Mutex::new(store)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "ru.shturman.Settings1")]
|
||||
impl SettingsService {
|
||||
async fn get(&self, key: &str) -> Result<OwnedValue, Error> {
|
||||
let store = self.store.lock().await;
|
||||
match store.get(key) {
|
||||
Some(v) => OwnedValue::try_from(Value::from(v.to_string()))
|
||||
.map_err(|e| Error::InvalidArgument(format!("value convert: {e}"))),
|
||||
None => Err(Error::InvalidArgument(format!("unknown key: {key}"))),
|
||||
}
|
||||
}
|
||||
|
||||
async fn set(
|
||||
&self,
|
||||
key: String,
|
||||
value: Value<'_>,
|
||||
#[zbus(signal_context)] ctx: SignalContext<'_>,
|
||||
) -> Result<(), Error> {
|
||||
let s = match value {
|
||||
Value::Str(s) => s.as_str().to_string(),
|
||||
_ => {
|
||||
return Err(Error::InvalidArgument(
|
||||
"v0 поддерживает только строковые значения".into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
self.store
|
||||
.lock()
|
||||
.await
|
||||
.set(&key, &s)
|
||||
.map_err(|e| Error::InvalidArgument(format!("persist: {e}")))?;
|
||||
let _ = Self::changed(&ctx, &key, &Value::from(s)).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list(&self, prefix: &str) -> Vec<String> {
|
||||
self.store.lock().await.list(prefix)
|
||||
}
|
||||
|
||||
async fn reset(
|
||||
&self,
|
||||
key: String,
|
||||
#[zbus(signal_context)] ctx: SignalContext<'_>,
|
||||
) -> Result<(), Error> {
|
||||
let new = self
|
||||
.store
|
||||
.lock()
|
||||
.await
|
||||
.reset(&key)
|
||||
.map_err(|e| Error::InvalidArgument(format!("persist: {e}")))?;
|
||||
let _ = Self::changed(&ctx, &key, &Value::from(new.unwrap_or_default())).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[zbus(signal)]
|
||||
async fn changed(ctx: &SignalContext<'_>, key: &str, value: &Value<'_>) -> zbus::Result<()>;
|
||||
}
|
||||
Reference in New Issue
Block a user