Store user state in binary CBOR format

The state structure is growing a little too complex to store it as a TOML.
User state is now stored at `~/.config/ncspot/userstate.cbor`.
This commit is contained in:
Henrik Friedrichsen
2021-04-11 00:44:40 +02:00
parent e61e18608b
commit 50fcab4d7a
4 changed files with 61 additions and 7 deletions

17
Cargo.lock generated
View File

@@ -1293,6 +1293,12 @@ dependencies = [
"tracing-futures",
]
[[package]]
name = "half"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
[[package]]
name = "hashbrown"
version = "0.9.1"
@@ -2029,6 +2035,7 @@ dependencies = [
"reqwest 0.9.24",
"rspotify",
"serde",
"serde_cbor",
"serde_json",
"strum 0.20.0",
"strum_macros 0.20.1",
@@ -3200,6 +3207,16 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde_cbor"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622"
dependencies = [
"half",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.125"

View File

@@ -47,6 +47,7 @@ strum_macros = "0.20.1"
libc = "0.2"
regex = "1"
ioctl-rs = { version = "0.2", optional = true }
serde_cbor = "0.11.1"
[dependencies.cursive]
version = "0.16.3"

View File

@@ -9,7 +9,7 @@ use platform_dirs::AppDirs;
use crate::command::{SortDirection, SortKey};
use crate::playable::Playable;
use crate::queue;
use crate::serialization::{Serializer, TOML};
use crate::serialization::{Serializer, CBOR, TOML};
pub const CLIENT_ID: &str = "d420a117a32841c2b3474932e49fb54b";
@@ -66,7 +66,6 @@ pub struct QueueState {
pub current_track: Option<usize>,
pub random_order: Option<Vec<usize>>,
pub track_progress: std::time::Duration,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub queue: Vec<Playable>,
}
@@ -76,7 +75,6 @@ pub struct UserState {
pub shuffle: bool,
pub repeat: queue::RepeatSetting,
pub queuestate: QueueState,
#[serde(serialize_with = "toml::ser::tables_last")]
pub playlist_orders: HashMap<String, SortingOrder>,
}
@@ -109,8 +107,8 @@ impl Config {
});
let mut userstate = {
let path = config_path("userstate.toml");
TOML.load_or_generate_default(path, || Ok(UserState::default()), true)
let path = config_path("userstate.cbor");
CBOR.load_or_generate_default(path, || Ok(UserState::default()), true)
.expect("could not load user state")
};
@@ -145,9 +143,9 @@ impl Config {
}
pub fn save_state(&self) {
let path = config_path("userstate.toml");
let path = config_path("userstate.cbor");
debug!("saving user state to {}", path.display());
if let Err(e) = TOML.write(path, self.state().clone()) {
if let Err(e) = CBOR.write(path, self.state().clone()) {
error!("Could not save user state: {}", e);
}
}

View File

@@ -68,4 +68,42 @@ impl Serializer for TomlSerializer {
}
}
pub struct CborSerializer {}
impl Serializer for CborSerializer {
fn load<P: AsRef<Path>, T: serde::Serialize + serde::de::DeserializeOwned>(
&self,
path: P,
) -> Result<T, String> {
let contents = std::fs::read(&path)
.map_err(|e| format!("Unable to read {}: {}", path.as_ref().to_string_lossy(), e))?;
serde_cbor::from_slice(&contents).map_err(|e| {
format!(
"Unable to parse CBOR {}: {}",
path.as_ref().to_string_lossy(),
e
)
})
}
fn write<P: AsRef<Path>, T: serde::Serialize>(&self, path: P, value: T) -> Result<T, String> {
let file = std::fs::File::create(&path).map_err(|e| {
format!(
"Failed creating file {}: {}",
path.as_ref().to_string_lossy(),
e
)
})?;
serde_cbor::to_writer(file, &value)
.map(|_| value)
.map_err(|e| {
format!(
"Failed writing content to {}: {}",
path.as_ref().display(),
e
)
})
}
}
pub static TOML: TomlSerializer = TomlSerializer {};
pub static CBOR: CborSerializer = CborSerializer {};