diff --git a/src-native/data.rs b/src-native/data.rs index 5a6e9ac..0e198db 100644 --- a/src-native/data.rs +++ b/src-native/data.rs @@ -11,7 +11,7 @@ use std::io::Write; use std::path::{Path, PathBuf}; use std::sync::OnceLock; use std::time::Instant; -use tokio::sync::Mutex; +use tokio::sync::{Mutex, MutexGuard}; pub fn path_to_string>(path: P) -> String { path.as_ref() @@ -20,15 +20,6 @@ pub fn path_to_string>(path: P) -> String { .to_string() } -pub struct Data { - pub paths: Paths, - pub library: Library, - /// Current tag being edited - pub current_tag: Option, -} - -pub static DATA: OnceLock> = OnceLock::new(); - pub fn app_log_dir() -> Result { #[cfg(target_os = "macos")] { @@ -46,7 +37,22 @@ pub fn app_log_dir() -> Result { } } +pub struct Data { + pub paths: Paths, + pub library: Library, + /// Current tag being edited + pub current_tag: Option, +} + +pub static DATA: OnceLock> = OnceLock::new(); + impl Data { + pub async fn get_async() -> MutexGuard<'static, Data> { + DATA.get().expect("No data initialised").lock().await + } + pub fn get_blocking() -> MutexGuard<'static, Data> { + DATA.get().expect("No data initialised").blocking_lock() + } pub fn save(&mut self) -> Result<()> { let mut now = Instant::now(); let formatter = serde_json::ser::PrettyFormatter::with_indent(b" "); // tab @@ -119,12 +125,8 @@ impl Data { library: loaded_library, current_tag: None, }; - match DATA.set(Mutex::new(data)) { - Ok(()) => (), - Err(_) => { - panic!("Failed to set DATA"); - } - }; + // if it fails, it was already set. the user might just have reloaded + let _result = DATA.set(Mutex::new(data)); return Ok(()); } } diff --git a/src-native/data_js.rs b/src-native/data_js.rs index ff92bcf..a240d79 100644 --- a/src-native/data_js.rs +++ b/src-native/data_js.rs @@ -1,12 +1,7 @@ -use crate::data::{DATA, Data, app_log_dir, path_to_string}; +use crate::data::{Data, app_log_dir, path_to_string}; use crate::library::Paths; use napi::Result; use std::fs; -use tokio::sync::MutexGuard; - -pub fn get_data() -> MutexGuard<'static, Data> { - DATA.get().expect("No data initialised").blocking_lock() -} #[napi(js_name = "load_data")] #[allow(dead_code)] @@ -39,7 +34,7 @@ pub fn load_data( #[napi(js_name = "get_paths")] #[allow(dead_code)] pub fn get_paths() -> Paths { - let data = get_data(); + let data = Data::get_blocking(); data.paths.clone() } #[napi(js_name = "get_logs_dir")] @@ -54,7 +49,7 @@ pub fn get_logs_dir() -> Result { #[napi(js_name = "save")] #[allow(dead_code)] pub fn save() -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); data.save()?; Ok(()) } diff --git a/src-native/itunes_import.rs b/src-native/itunes_import.rs index a887093..17d2652 100644 --- a/src-native/itunes_import.rs +++ b/src-native/itunes_import.rs @@ -1,4 +1,4 @@ -use crate::data_js::get_data; +use crate::data::Data; use crate::get_now_timestamp; use crate::library::Paths; use crate::library_types::{ @@ -586,7 +586,7 @@ pub struct ItunesImport { impl ItunesImport { #[napi(factory)] pub fn new() -> Self { - let data = get_data(); + let data = Data::get_blocking(); Self { new_library: Some(data.library.clone()).into(), itunes_track_paths: HashMap::new().into(), @@ -599,7 +599,7 @@ impl ItunesImport { } #[napi] pub fn finish(&mut self) -> napi::Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let itunes_track_paths = &mut *self.itunes_track_paths.lock().unwrap(); for (itunes_path, ferrum_file) in itunes_track_paths { let new_path = data.paths.get_track_file_path(ferrum_file); diff --git a/src-native/library.rs b/src-native/library.rs index c84966c..f213dc4 100644 --- a/src-native/library.rs +++ b/src-native/library.rs @@ -1,6 +1,5 @@ #[cfg(feature = "napi-rs")] -#[cfg(feature = "napi-rs")] -use crate::data_js::get_data; +use crate::data::Data; use crate::library_types::{ItemId, Library, SpecialTrackListName, TrackList, VersionedLibrary}; use anyhow::{Context, Result, bail}; use linked_hash_map::LinkedHashMap; @@ -192,7 +191,7 @@ pub fn get_track_field_type(field: &str) -> Result { #[napi(js_name = "get_genres")] #[allow(dead_code)] pub fn get_genres() -> Vec { - let mut data = get_data(); + let mut data = Data::get_blocking(); let genres = data.library.get_genres(); genres.clone() } @@ -201,7 +200,7 @@ pub fn get_genres() -> Vec { #[napi(js_name = "get_artists")] #[allow(dead_code)] pub fn get_artists() -> Vec { - let mut data = get_data(); + let mut data = Data::get_blocking(); let genres = data.library.get_artists(); genres.clone() } diff --git a/src-native/page.rs b/src-native/page.rs index 6acd77d..be5315e 100644 --- a/src-native/page.rs +++ b/src-native/page.rs @@ -1,10 +1,9 @@ #[cfg(feature = "napi-rs")] -use crate::data_js::get_data; +use crate::data::Data; use crate::filter::filter; use crate::library_types::{ItemId, Library, TrackList}; use crate::sort::sort; -#[cfg(feature = "napi-rs")] -use napi::Result; +use anyhow::Result; use serde::{Deserialize, Serialize}; use specta::Type; @@ -32,7 +31,7 @@ pub struct TracksPage { #[cfg_attr(feature = "napi", napi(js_name = "get_tracks_page"))] #[allow(dead_code)] pub fn get_tracks_page(options: TracksPageOptions) -> Result { - let data = get_data(); + let data = Data::get_blocking(); Ok(get_tracks_page_from_library(options, &data.library)?) } diff --git a/src-native/playlists.rs b/src-native/playlists.rs index d164e88..7c1f3f2 100644 --- a/src-native/playlists.rs +++ b/src-native/playlists.rs @@ -1,5 +1,4 @@ use crate::data::Data; -use crate::data_js::get_data; use crate::library_types::{ ItemId, Library, SpecialTrackListName, TRACK_ID_MAP, TrackID, TrackList, get_track_ids_from_item_ids, new_item_ids_from_track_ids, @@ -26,7 +25,7 @@ pub struct TrackListDetails { #[napi(js_name = "get_track_lists_details")] #[allow(dead_code)] pub fn get_track_lists_details() -> HashMap { - let data = get_data(); + let data = Data::get_blocking(); data.library .trackLists .iter() @@ -59,7 +58,7 @@ pub fn get_track_lists_details() -> HashMap { #[napi(js_name = "get_track_list", ts_return_type = "TrackList")] #[allow(dead_code)] pub fn get_track_list<'a>(id: String, env: Env) -> Result> { - let data = get_data(); + let data = Data::get_blocking(); let tracklist = data.library.get_tracklist(&id)?; Ok(env.to_js_value(&tracklist)?) } @@ -123,7 +122,7 @@ fn remove_child_id(library: &mut Library, parent_id: &String, child_id: &String) #[napi(js_name = "delete_track_list")] #[allow(dead_code)] pub fn delete_track_list(id: String) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let parent_id = data.library.get_parent_id(&id).context("No parent found")?; let mut ids = HashSet::new(); @@ -143,7 +142,7 @@ pub fn delete_track_list(id: String) -> Result<()> { #[napi(js_name = "add_tracks_to_playlist")] #[allow(dead_code)] pub fn add_tracks(playlist_id: String, track_ids: Vec) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let playlist = match data.library.get_tracklist_mut(&playlist_id)? { TrackList::Playlist(playlist) => playlist, TrackList::Folder(_) => bail!("Cannot add track to folder"), @@ -157,7 +156,7 @@ pub fn add_tracks(playlist_id: String, track_ids: Vec) -> Result<()> { #[napi(js_name = "playlist_filter_duplicates")] #[allow(dead_code)] pub fn filter_duplicates(playlist_id: TrackID, ids: Vec) -> Result> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let mut track_ids: HashSet = HashSet::from_iter(ids); let playlist = match data.library.get_tracklist_mut(&playlist_id)? { TrackList::Playlist(playlist) => playlist, @@ -175,7 +174,7 @@ pub fn filter_duplicates(playlist_id: TrackID, ids: Vec) -> Result Result> { - let data = get_data(); + let data = Data::get_blocking(); Ok(get_track_playlist_ids_in_library(&data.library, &track_id)) } @@ -203,7 +202,7 @@ pub fn get_track_playlist_ids_in_library(library: &Library, track_id: &str) -> V #[napi(js_name = "remove_from_playlist")] #[allow(dead_code)] pub fn remove_from_playlist(playlist_id: TrackID, item_ids: Vec) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let playlist = match data.library.get_tracklist_mut(&playlist_id)? { TrackList::Playlist(playlist) => playlist, _ => bail!("Cannot remove track from non-playlist"), @@ -249,7 +248,7 @@ pub fn delete_file(path: &PathBuf) -> Result<()> { #[napi(js_name = "delete_tracks_with_item_ids")] #[allow(dead_code)] pub fn delete_tracks_with_item_ids(item_ids: Vec) -> Result<()> { - let data = &mut *get_data(); + let data = &mut *Data::get_blocking(); let library = &mut data.library; let track_ids = get_track_ids_from_item_ids(&item_ids); for track_id in &track_ids { @@ -267,7 +266,7 @@ pub fn new_playlist( is_folder: bool, parent_id: String, ) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let library = &mut data.library; let list = match is_folder { @@ -306,7 +305,7 @@ pub fn new_playlist( #[napi(js_name = "update_playlist")] #[allow(dead_code)] pub fn update_playlist(id: String, name: String, description: String) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); match data.library.trackLists.get_mut(&id) { Some(TrackList::Special(_)) => bail!("Cannot edit special playlists"), @@ -364,7 +363,7 @@ fn get_children_if_user_editable<'a>( #[napi(js_name = "move_playlist")] #[allow(dead_code)] pub fn move_playlist(id: String, from_id: String, to_id: String, to_index: u32) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); match data.library.trackLists.get(&id) { Some(TrackList::Special(_)) => bail!("Cannot move special playlist"), @@ -406,7 +405,7 @@ pub fn move_playlist(id: String, from_id: String, to_id: String, to_index: u32) #[napi(js_name = "move_tracks")] #[allow(dead_code)] pub fn move_tracks(playlist_id: String, mut item_ids: Vec, to_index: u32) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let playlist = match data.library.get_tracklist_mut(&playlist_id)? { TrackList::Playlist(playlist) => playlist, _ => bail!("Cannot rearrange tracks in non-playlist"), diff --git a/src-native/tracks/mod.rs b/src-native/tracks/mod.rs index fad9068..9325e2a 100644 --- a/src-native/tracks/mod.rs +++ b/src-native/tracks/mod.rs @@ -1,4 +1,4 @@ -use crate::data_js::get_data; +use crate::data::Data; use crate::get_now_timestamp; use crate::library::Paths; use crate::library_types::{ItemId, MsSinceUnixEpoch, TRACK_ID_MAP, Track, TrackID}; @@ -17,7 +17,7 @@ pub use tag::Tag; #[napi(js_name = "get_track")] #[allow(dead_code)] pub fn get_track(id: String) -> Result { - let data = get_data(); + let data = Data::get_blocking(); let track = data.library.get_track(&id)?; Ok(track.clone()) } @@ -31,7 +31,7 @@ pub struct KeyedTrack { #[napi(js_name = "get_track_by_item_id")] #[allow(dead_code)] pub fn get_track_by_item_id(item_id: ItemId) -> Result { - let data = get_data(); + let data = Data::get_blocking(); let id_map = TRACK_ID_MAP.read().unwrap(); let track_id = &id_map[item_id as usize]; let track = data.library.get_track(&track_id)?; @@ -55,7 +55,7 @@ pub fn get_track_ids(item_ids: Vec) -> Vec { #[napi(js_name = "track_exists")] #[allow(dead_code)] pub fn track_exists(id: String) -> bool { - let data = get_data(); + let data = Data::get_blocking(); let tracks = &data.library.get_tracks(); tracks.contains_key(&id) } @@ -63,7 +63,7 @@ pub fn track_exists(id: String) -> bool { #[napi(js_name = "add_play")] #[allow(dead_code)] pub fn add_play(track_id: String) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let track = data.library.get_track_mut(&track_id)?; let timestamp = get_now_timestamp(); match &mut track.plays { @@ -80,7 +80,7 @@ pub fn add_play(track_id: String) -> Result<()> { #[napi(js_name = "add_skip")] #[allow(dead_code)] pub fn add_skip(track_id: String) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let track = data.library.get_track_mut(&track_id)?; let timestamp = get_now_timestamp(); match &mut track.skips { @@ -97,7 +97,7 @@ pub fn add_skip(track_id: String) -> Result<()> { #[napi(js_name = "add_play_time")] #[allow(dead_code)] pub fn add_play_time(id: TrackID, start: MsSinceUnixEpoch, dur_ms: i64) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let tracks = data.library.get_tracks(); tracks.get(&id).context("Track ID not found")?; data.library.playTime.push((id, start, dur_ms)); @@ -145,7 +145,7 @@ pub fn generate_filename(paths: &Paths, artist: &str, title: &str, ext: &str) -> #[napi(js_name = "import_file")] #[allow(dead_code)] pub fn import_file(path: String, now: MsSinceUnixEpoch) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let id = data.library.generate_id(); let track = import::import(&data, Path::new(&path), now)?; data.library.insert_track(id, track); @@ -155,7 +155,7 @@ pub fn import_file(path: String, now: MsSinceUnixEpoch) -> Result<()> { #[napi(js_name = "load_tags")] #[allow(dead_code)] pub fn load_tags(track_id: String) -> Result<()> { - let data = &mut *get_data(); + let data = &mut *Data::get_blocking(); data.current_tag = None; let track = data .library @@ -179,7 +179,7 @@ pub struct JsImage { #[napi(js_name = "get_image")] #[allow(dead_code)] pub fn get_image(index: u32) -> Result> { - let data = get_data(); + let data = Data::get_blocking(); let tag = match &data.current_tag { Some(tag) => tag, @@ -205,7 +205,7 @@ pub fn get_image(index: u32) -> Result> { #[napi(js_name = "set_image")] #[allow(dead_code)] pub fn set_image(index: u32, path: String) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let tag = match &mut data.current_tag { Some(tag) => tag, None => bail!("No tag loaded"), @@ -218,7 +218,7 @@ pub fn set_image(index: u32, path: String) -> Result<()> { #[napi(js_name = "set_image_data")] #[allow(dead_code)] pub fn set_image_data(index: u32, bytes: ArrayBuffer) -> Result<()> { - let mut data = get_data(); + let mut data = Data::get_blocking(); let tag = match &mut data.current_tag { Some(tag) => tag, None => bail!("No tag loaded"), @@ -230,7 +230,7 @@ pub fn set_image_data(index: u32, bytes: ArrayBuffer) -> Result<()> { #[napi(js_name = "remove_image")] #[allow(dead_code)] pub fn remove_image(index: u32) -> () { - let mut data = get_data(); + let mut data = Data::get_blocking(); match data.current_tag { Some(ref mut tag) => { tag.remove_image(index as usize); @@ -242,7 +242,7 @@ pub fn remove_image(index: u32) -> () { #[napi(js_name = "update_track_info")] #[allow(dead_code)] pub fn update_track_info(track_id: String, info: md::TrackMD) -> Result<()> { - let data = &mut *get_data(); + let data = &mut *Data::get_blocking(); let track = data.library.get_track_mut(&track_id)?; let tag = match &mut data.current_tag { diff --git a/src-native/view_options.rs b/src-native/view_options.rs index d03a9e7..ccfa0c7 100644 --- a/src-native/view_options.rs +++ b/src-native/view_options.rs @@ -1,4 +1,4 @@ -use crate::data_js::get_data; +use crate::data::Data; use crate::library::Paths; use crate::path_to_json; use anyhow::{Context, Result}; @@ -42,7 +42,7 @@ impl ViewOptions { #[napi(js_name = "load_view_options")] #[allow(dead_code)] pub fn load_view_options() -> Result { - let data = get_data(); + let data = Data::get_blocking(); Ok(ViewOptions::load(&data.paths)) } #[napi(js_name = "save_view_options")]