//! `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>, } 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 { 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 { 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<()>; }