Implemented new reading/writing in utils, improved library init function

This commit is contained in:
G2-Games 2024-01-19 21:22:03 -06:00
parent 0f49c50c42
commit 0f5eda5d1d
5 changed files with 108 additions and 78 deletions

14
.gitignore vendored
View file

@ -1,9 +1,15 @@
# Rust binary output dir
target/
music_database*
*.db3*
config.toml
# Rust configuration
Cargo.lock
# Database files
*.db3*
music_database*
# Storage formats
*.kate-swp*
*.m3u
*.m3u8
*.m3u8
*.json

View file

@ -1,7 +1,11 @@
use std::{path::{PathBuf, Path}, marker::PhantomData, fs::{File, OpenOptions, self}, io::{Error, Write, Read}, default};
use std::{
path::PathBuf,
fs::{File, OpenOptions, self},
io::{Error, Write, Read},
};
use serde::{Serialize, Deserialize};
use serde_json::{to_string, to_string_pretty};
use serde_json::to_string_pretty;
use thiserror::Error;
use uuid::Uuid;
@ -11,6 +15,7 @@ pub struct ConfigLibrary {
pub path: PathBuf,
pub uuid: Uuid
}
impl ConfigLibrary {
pub fn new() -> Self {
ConfigLibrary::default()
@ -22,6 +27,7 @@ impl ConfigLibrary {
}
}
}
impl Default for ConfigLibrary {
fn default() -> Self {
ConfigLibrary {
@ -31,29 +37,71 @@ impl Default for ConfigLibrary {
}
}
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct ConfigLibraries {
default_library: Uuid,
pub library_folder: PathBuf,
pub libraries: Vec<ConfigLibrary>,
}
impl ConfigLibraries {
//TODO: Add new function for test tube
pub fn set_default(mut self, uuid: &Uuid) {
self.default_library = *uuid;
}
pub fn get_default(&self) -> Result<&ConfigLibrary, ConfigError> {
for library in &self.libraries {
if library.uuid == self.default_library {
return Ok(library)
}
}
Err(ConfigError::NoDefaultLibrary)
}
pub fn get_library(&self, uuid: &Uuid) -> Result<ConfigLibrary, ConfigError> {
for library in &self.libraries {
if &library.uuid == uuid {
return Ok(library.to_owned())
}
}
Err(ConfigError::NoConfigLibrary(*uuid))
}
pub fn uuid_exists(&self, uuid: &Uuid) -> bool {
for library in &self.libraries {
if &library.uuid == uuid {
return true
}
}
false
}
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct Config {
pub path: PathBuf,
pub libraries: ConfigLibraries,
volume: f32,
}
#[test]
fn config_test_() {
Config {
path: PathBuf::from("F:\\temp\\config.json"),
fn config_test() {
let _ = Config {
path: PathBuf::from("config_test.json"),
libraries: ConfigLibraries {
libraries: vec![ConfigLibrary::default(),ConfigLibrary::default(),ConfigLibrary::default()],
libraries: vec![
ConfigLibrary::default(),
ConfigLibrary::default(),
ConfigLibrary::default()
],
..Default::default()
},
..Default::default()
}.to_file();
}.write_file();
}
impl Config {
pub fn new() -> Self {
Config {
@ -64,38 +112,12 @@ impl Config {
..Default::default()
}
}
pub fn new_main() -> Self {
Config::default()
}
//TODO: Add new function for test tube
pub fn set_default_library(mut self, uuid: &Uuid) {
self.libraries.default_library = *uuid;
}
pub fn get_default_library(&self) -> Result<&ConfigLibrary, ConfigError> {
for library in &self.libraries.libraries {
if library.uuid == self.libraries.default_library {
return Ok(library)
}
}
Err(ConfigError::NoDefaultLibrary)
}
pub fn get_library(&self, uuid: &Uuid) -> Result<ConfigLibrary, ConfigError> {
for library in &self.libraries.libraries {
if &library.uuid == uuid {
return Ok(library.to_owned())
}
}
Err(ConfigError::NoConfigLibrary(*uuid))
}
pub fn library_exists(&self, uuid: &Uuid) -> bool {
for library in &self.libraries.libraries {
if &library.uuid == uuid {
return true
}
}
false
}
pub fn to_file(&self) -> Result<(), Error> {
pub fn write_file(&self) -> Result<(), Error> {
let mut writer = self.path.clone();
writer.set_extension("tmp");
let mut file = OpenOptions::new().create(true).truncate(true).read(true).write(true).open(&writer)?;
@ -106,7 +128,8 @@ impl Config {
fs::rename(writer, self.path.as_path())?;
Ok(())
}
pub fn load_file(path: PathBuf) -> Result<Self, Error> {
pub fn read_file(path: PathBuf) -> Result<Self, Error> {
let mut file: File = File::open(path)?;
let mut bun: String = String::new();
_ = file.read_to_string(&mut bun);

View file

@ -3,6 +3,8 @@ pub mod music_storage {
pub mod music_collection;
pub mod playlist;
mod utils;
#[allow(dead_code)]
pub mod db_reader;
}

View file

@ -1,8 +1,6 @@
// Crate things
use super::utils::{find_images, normalize, read_library, write_library};
use super::music_collection::MusicCollection;
use super::utils::{find_images, normalize, read_file, write_file};
use crate::config::config::Config;
use crate::music_storage::library;
// Various std things
use std::collections::BTreeMap;
@ -316,25 +314,30 @@ impl Album<'_> {
const BLOCKED_EXTENSIONS: [&str; 4] = ["vob", "log", "txt", "sf2"];
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct MusicLibrary {
pub name: String,
pub uuid: Uuid,
pub library: Vec<Song>,
}
#[test]
fn test_() {
let a = MusicLibrary::init(Arc::new(RwLock::from(Config::new())), None).unwrap();
dbg!(a);
}
fn library_init() {
let uuidv4 = Uuid::new_v4();
let a = MusicLibrary::init(Arc::new(RwLock::from(Config::new())), uuidv4).unwrap();
dbg!(a);
}
impl MusicLibrary {
pub fn new() -> Self {
pub fn new(name: String, uuid: Uuid) -> Self {
MusicLibrary {
name: String::default(),
uuid: Uuid::default(),
name,
uuid,
library: Vec::new(),
}
}
/*
pub fn with_uuid(uuid: Uuid, path: PathBuf) -> Result<Self, Box<dyn Error>> {
MusicLibrary {
name: String::new(),
@ -344,40 +347,35 @@ impl MusicLibrary {
todo!()
}
*/
/// Initialize the database
///
/// If the database file already exists, return the [MusicLibrary], otherwise create
/// the database first. This needs to be run before anything else to retrieve
/// the [MusicLibrary] Vec
pub fn init(config: Arc<RwLock<Config>>, uuid: Option<Uuid>) -> Result<Self, Box<dyn Error>> {
pub fn init(config: Arc<RwLock<Config>>, uuid: Uuid) -> Result<Self, Box<dyn Error>> {
let global_config = &*config.read().unwrap();
let mut library = MusicLibrary::new();
let library: MusicLibrary = match global_config.libraries.uuid_exists(&uuid) {
true => read_file(global_config.libraries.get_library(&uuid)?.path)?,
false => {
// If the library does not exist, re-create it
let lib = MusicLibrary::new(String::new(), uuid);
write_file(&lib, global_config.libraries.get_library(&uuid)?.path)?;
lib
}
};
if let Some(uuid) = uuid {
match global_config.library_exists(&uuid) {
true => {
library.library = read_library(global_config.get_library(&uuid)?.path)?;
},
false => {
// Create the database if it does not exist
write_library(&library.library, global_config.path.clone())?;
library = MusicLibrary::with_uuid(uuid, global_config.path.parent().unwrap().to_path_buf())?;
}
};
}else {
write_library(&library.library, global_config.path.clone())?;
}
Ok(library)
}
/// Serializes the database out to the file specified in the config
pub fn save(&self, config: &Config) -> Result<(), Box<dyn Error>> {
let path = config.get_library(&self.uuid)?.path;
let path = config.libraries.get_library(&self.uuid)?.path;
match path.try_exists() {
Ok(_) => {
write_library(&self.library, path)?;
write_file(&self.library, path)?;
}
Err(error) => return Err(error.into()),
}

View file

@ -6,7 +6,7 @@ use walkdir::WalkDir;
use snap;
use super::library::{AlbumArt, Song, URI};
use super::library::{AlbumArt, URI};
use unidecode::unidecode;
pub(super) fn normalize(input_string: &str) -> String {
@ -19,35 +19,36 @@ pub(super) fn normalize(input_string: &str) -> String {
normalized
}
pub(super) fn read_library(path: PathBuf) -> Result<Vec<Song>, Box<dyn Error>> {
pub(super) fn read_file<T: for<'de> serde::Deserialize<'de>>(path: PathBuf) -> Result<T, Box<dyn Error>> {
// Create a new snap reader over the database file
let database = fs::File::open(path)?;
let reader = BufReader::new(database);
let mut d = snap::read::FrameDecoder::new(reader);
// Decode the library from the serialized data into the vec
let library: Vec<Song> = bincode::serde::decode_from_std_read(
let library: T = bincode::serde::decode_from_std_read(
&mut d,
bincode::config::standard()
.with_little_endian()
.with_variable_int_encoding(),
)?;
Ok(library)
}
pub(super) fn write_library(
library: &Vec<Song>,
pub(super) fn write_file<T: serde::Serialize>(
library: &T,
path: PathBuf,
) -> Result<(), Box<dyn Error>> {
// Create 2 new names for the file, a temporary one for writing out, and a backup
// Create a temporary name for writing out
let mut writer_name = path.clone();
writer_name.set_extension("tmp");
// Create a new BufWriter on the file and make a snap frame encoer for it too
// Create a new BufWriter on the file and a snap frame encoder
let writer = BufWriter::new(fs::File::create(&writer_name)?);
let mut e = snap::write::FrameEncoder::new(writer);
// Write out the data using bincode
// Write out the data
bincode::serde::encode_into_std_write(
library,
&mut e,