daemon-user: refactor config files

This commit is contained in:
Luke D. Jones
2023-01-08 21:05:54 +13:00
parent 00839aaa6f
commit ab3007d53d
8 changed files with 105 additions and 171 deletions

3
Cargo.lock generated
View File

@@ -666,6 +666,7 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"toml",
]
[[package]]
@@ -816,6 +817,8 @@ version = "4.5.8"
dependencies = [
"config-traits",
"dirs",
"env_logger",
"log",
"rog_anime",
"rog_aura",
"rog_dbus",

View File

@@ -9,6 +9,7 @@ edition = "2021"
serde.workspace = true
serde_derive.workspace = true
serde_json.workspace = true
toml.workspace = true
ron.workspace = true
log.workspace = true

View File

@@ -146,6 +146,8 @@ where
self = data;
} else if let Ok(data) = serde_json::from_str(&buf) {
self = data;
} else if let Ok(data) = toml::from_str(&buf) {
self = data;
} else {
self.rename_file_old();
self = Self::new();
@@ -205,8 +207,12 @@ where
self = data;
} else if let Ok(data) = serde_json::from_str(&buf) {
self = data;
} else if let Ok(data) = toml::from_str(&buf) {
self = data;
} else if let Ok(data) = serde_json::from_str::<OldConfig>(&buf) {
self = data.into();
} else if let Ok(data) = toml::from_str::<OldConfig>(&buf) {
self = data.into();
} else {
self.rename_file_old();
self = Self::new();
@@ -274,10 +280,16 @@ where
self = data;
} else if let Ok(data) = serde_json::from_str(&buf) {
self = data;
} else if let Ok(data) = toml::from_str(&buf) {
self = data;
} else if let Ok(data) = serde_json::from_str::<OldConfig>(&buf) {
self = data.into();
} else if let Ok(data) = toml::from_str::<OldConfig>(&buf) {
self = data.into();
} else if let Ok(data) = serde_json::from_str::<OldConfig2>(&buf) {
self = data.into();
} else if let Ok(data) = toml::from_str::<OldConfig2>(&buf) {
self = data.into();
} else {
self.rename_file_old();
self = Self::new();

View File

@@ -30,3 +30,7 @@ rog_platform = { path = "../rog-platform" }
config-traits = { path = "../config-traits" }
zbus.workspace = true
# cli and logging
log.workspace = true
env_logger.workspace = true

View File

@@ -1,92 +1,30 @@
use std::fs::{create_dir, OpenOptions};
use std::io::{Read, Write};
use std::path::PathBuf;
use std::time::Duration;
use config_traits::{StdConfig, StdConfigLoad1};
use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences as AnimeSequences, Vec2};
use rog_aura::advanced::LedCode;
use rog_aura::effects::{AdvancedEffects as AuraSequences, Breathe, DoomFlicker, Effect, Static};
use rog_aura::{Colour, Speed};
use serde::de::DeserializeOwned;
use serde_derive::{Deserialize, Serialize};
use crate::error::Error;
pub trait ConfigLoadSave<T: DeserializeOwned + serde::Serialize> {
fn name(&self) -> String;
const ROOT_CONF_DIR: &str = "rog";
fn default_with_name(name: String) -> T;
fn write(&self) -> Result<(), Error>
where
Self: serde::Serialize,
{
let mut path = if let Some(dir) = dirs::config_dir() {
dir
} else {
return Err(Error::XdgVars);
};
path.push("rog");
if !path.exists() {
create_dir(path.clone())?;
}
let name = self.name();
path.push(name + ".cfg");
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&path)?;
let json = serde_json::to_string_pretty(&self).unwrap();
file.write_all(json.as_bytes())?;
Ok(())
}
fn load(name: String) -> Result<T, Error> {
let mut path = if let Some(dir) = dirs::config_dir() {
dir
} else {
return Err(Error::XdgVars);
};
path.push("rog");
if !path.exists() {
create_dir(path.clone())?;
}
path.push(name.clone() + ".cfg");
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)?;
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
let default = Self::default_with_name(name);
let json = serde_json::to_string_pretty(&default).unwrap();
file.write_all(json.as_bytes())?;
return Ok(default);
} else if let Ok(data) = serde_json::from_str::<T>(&buf) {
return Ok(data);
}
}
Err(Error::ConfigLoadFail)
}
fn root_conf_dir() -> PathBuf {
let mut dir = dirs::config_dir().unwrap_or_else(|| PathBuf::from("/tmp"));
dir.push(ROOT_CONF_DIR);
dir
}
#[derive(Debug, Deserialize, Serialize)]
pub struct UserAnimeConfig {
pub struct ConfigAnime {
pub name: String,
pub anime: Vec<ActionLoader>,
}
impl UserAnimeConfig {
impl ConfigAnime {
pub fn create(&self, anime_type: AnimeType) -> Result<AnimeSequences, Error> {
let mut seq = AnimeSequences::new(anime_type);
@@ -96,25 +34,17 @@ impl UserAnimeConfig {
Ok(seq)
}
}
impl ConfigLoadSave<UserAnimeConfig> for UserAnimeConfig {
fn name(&self) -> String {
self.name.clone()
}
fn default_with_name(name: String) -> Self {
UserAnimeConfig {
name,
..Default::default()
}
pub fn set_name(mut self, name: String) -> Self {
self.name = name;
self
}
}
impl Default for UserAnimeConfig {
impl Default for ConfigAnime {
fn default() -> Self {
Self {
name: "default".to_owned(),
name: "anime-default".to_owned(),
anime: vec![
ActionLoader::AsusImage {
file: "/usr/share/asusd/anime/custom/diagonal-template.png".into(),
@@ -172,26 +102,36 @@ impl Default for UserAnimeConfig {
}
}
impl StdConfig for ConfigAnime {
fn new() -> Self {
Self::default()
}
fn file_name(&self) -> String {
format!("{}.cfg", self.name)
}
fn config_dir() -> std::path::PathBuf {
root_conf_dir()
}
}
impl StdConfigLoad1 for ConfigAnime {}
#[derive(Debug, Deserialize, Serialize)]
pub struct UserAuraConfig {
pub struct ConfigAura {
pub name: String,
pub aura: AuraSequences,
}
impl ConfigLoadSave<UserAuraConfig> for UserAuraConfig {
fn name(&self) -> String {
self.name.clone()
}
fn default_with_name(name: String) -> Self {
UserAuraConfig {
name,
..Default::default()
}
impl ConfigAura {
pub fn set_name(mut self, name: String) -> Self {
self.name = name;
self
}
}
impl Default for UserAuraConfig {
impl Default for ConfigAura {
fn default() -> Self {
let mut seq = AuraSequences::new(false);
let mut key = Effect::Breathe(Breathe::new(
@@ -228,86 +168,52 @@ impl Default for UserAuraConfig {
seq.push(key);
Self {
name: "default".to_owned(),
name: "aura-default".to_owned(),
aura: seq,
}
}
}
impl StdConfig for ConfigAura {
fn new() -> Self {
Self::default()
}
fn file_name(&self) -> String {
format!("{}.cfg", self.name)
}
fn config_dir() -> std::path::PathBuf {
root_conf_dir()
}
}
impl StdConfigLoad1 for ConfigAura {}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(default)]
pub struct UserConfig {
pub struct ConfigBase {
/// Name of active anime config file in the user config directory
pub active_anime: Option<String>,
/// Name of active aura config file in the user config directory
pub active_aura: Option<String>,
}
impl UserConfig {
pub fn new() -> Self {
impl StdConfig for ConfigBase {
fn new() -> Self {
Self {
active_anime: Some("anime-default".to_owned()),
active_aura: Some("aura-default".to_owned()),
}
}
pub fn load(&mut self) -> Result<(), Error> {
let mut path = if let Some(dir) = dirs::config_dir() {
dir
} else {
return Err(Error::XdgVars);
};
path.push("rog");
if !path.exists() {
create_dir(path.clone())?;
}
path.push("rog-user.cfg");
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)?;
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
let json = serde_json::to_string_pretty(&self).unwrap();
file.write_all(json.as_bytes())?;
} else if let Ok(data) = serde_json::from_str::<UserConfig>(&buf) {
self.active_anime = data.active_anime;
self.active_aura = data.active_aura;
return Ok(());
}
}
Ok(())
fn file_name(&self) -> String {
"rog-user.cfg".to_owned()
}
pub fn write(&self) -> Result<(), Error> {
let mut path = if let Some(dir) = dirs::config_dir() {
dir
} else {
return Err(Error::XdgVars);
};
path.push("rog");
if !path.exists() {
create_dir(path.clone())?;
}
path.push("rog-user.cfg");
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&path)?;
let json = serde_json::to_string_pretty(&self).unwrap();
file.write_all(json.as_bytes())?;
Ok(())
fn config_dir() -> std::path::PathBuf {
root_conf_dir()
}
}
impl StdConfigLoad1 for ConfigBase {}

View File

@@ -4,6 +4,7 @@ use std::sync::{Arc, Mutex};
use std::thread::sleep;
use std::time::{Duration, Instant};
use config_traits::StdConfig;
use rog_anime::error::AnimeError;
use rog_anime::{ActionData, ActionLoader, AnimTime, Fade, Sequences, Vec2};
use rog_dbus::RogDbusClientBlocking;
@@ -11,8 +12,8 @@ use serde_derive::{Deserialize, Serialize};
use zbus::dbus_interface;
use zbus::zvariant::{ObjectPath, Type};
use crate::config::ConfigAnime;
use crate::error::Error;
use crate::user_config::{ConfigLoadSave, UserAnimeConfig};
#[derive(Debug, Clone, Deserialize, Serialize, Type)]
pub struct Timer {
@@ -134,7 +135,7 @@ impl<'a> CtrlAnimeInner<'static> {
}
pub struct CtrlAnime<'a> {
config: Arc<Mutex<UserAnimeConfig>>,
config: Arc<Mutex<ConfigAnime>>,
client: RogDbusClientBlocking<'a>,
inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
/// Must be the same Atomic as in CtrlAnimeInner
@@ -143,7 +144,7 @@ pub struct CtrlAnime<'a> {
impl CtrlAnime<'static> {
pub fn new(
config: Arc<Mutex<UserAnimeConfig>>,
config: Arc<Mutex<ConfigAnime>>,
inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
client: RogDbusClientBlocking<'static>,
inner_early_return: Arc<AtomicBool>,
@@ -206,7 +207,7 @@ impl CtrlAnime<'static> {
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
config.anime.push(action);
config.write()?;
config.write();
let json = serde_json::to_string_pretty(&*config).expect("Parse config to JSON failed");
@@ -251,7 +252,7 @@ impl CtrlAnime<'static> {
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
config.anime.push(action);
config.write()?;
config.write();
let json =
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
@@ -296,7 +297,7 @@ impl CtrlAnime<'static> {
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
config.anime.push(action);
config.write()?;
config.write();
let json =
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
@@ -321,7 +322,7 @@ impl CtrlAnime<'static> {
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
config.anime.push(action);
config.write()?;
config.write();
let json =
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");
@@ -344,7 +345,7 @@ impl CtrlAnime<'static> {
if (index as usize) < config.anime.len() {
config.anime.remove(index as usize);
}
config.write()?;
config.write();
let json =
serde_json::to_string_pretty(&*config.anime).expect("Parse config to JSON failed");

View File

@@ -1,15 +1,16 @@
use std::fs::OpenOptions;
use std::io::Read;
use std::io::{Read, Write};
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
use config_traits::{StdConfig, StdConfigLoad1};
use rog_anime::usb::get_anime_type;
use rog_aura::aura_detection::LaptopLedData;
use rog_aura::layouts::KeyLayout;
use rog_dbus::RogDbusClientBlocking;
use rog_user::config::*;
use rog_user::ctrl_anime::{CtrlAnime, CtrlAnimeInner};
use rog_user::user_config::*;
use rog_user::DBUS_NAME;
use smol::Executor;
use zbus::Connection;
@@ -21,6 +22,13 @@ const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR");
const BOARD_NAME: &str = "/sys/class/dmi/id/board_name";
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
logger
.parse_default_env()
.target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.init();
println!(" user daemon v{}", rog_user::VERSION);
println!(" rog-anime v{}", rog_anime::VERSION);
println!(" rog-dbus v{}", rog_dbus::VERSION);
@@ -29,8 +37,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let (client, _) = RogDbusClientBlocking::new()?;
let supported = client.proxies().supported().supported_functions()?;
let mut config = UserConfig::new();
config.load()?;
let config = ConfigBase::new().load();
let executor = Executor::new();
@@ -39,7 +46,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if supported.anime_ctrl.0 {
if let Some(cfg) = config.active_anime {
let anime_type = get_anime_type()?;
let anime_config = UserAnimeConfig::load(cfg)?;
let anime_config = ConfigAnime::new().set_name(cfg).load();
let anime = anime_config.create(anime_type)?;
let anime_config = Arc::new(Mutex::new(anime_config));
@@ -70,7 +77,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// if supported.keyboard_led.per_key_led_mode {
if let Some(cfg) = config.active_aura {
let mut aura_config = UserAuraConfig::load(cfg)?;
let mut aura_config = ConfigAura::new().set_name(cfg).load();
// Find and load a matching layout for laptop
let mut file = OpenOptions::new()

View File

@@ -1,4 +1,4 @@
pub mod user_config;
pub mod config;
pub mod error;