use crate::{ audio::{Track, TrackId, TrackInfo}, FatalError, }; use flow::{error, ok, Flow}; use rusqlite::Connection; use std::collections::HashMap; use std::{ path::PathBuf, sync::{Arc, Mutex, RwLock}, }; use thiserror::Error; #[derive(Debug, Error)] pub enum DatabaseError { #[error("database is unreadable")] DatabaseUnreadable, #[error("unhandled database problem: {0}")] UnhandledError(rusqlite::Error), } pub trait MusicIndex: Sync + Send { fn add_track(&mut self, track: &TrackInfo) -> Flow; fn remove_track(&mut self, id: &TrackId) -> Flow<(), FatalError, DatabaseError>; fn get_track_info(&self, id: &TrackId) -> Flow, FatalError, DatabaseError>; } pub struct MemoryIndex { tracks: RwLock>, } impl MemoryIndex { pub fn new() -> MemoryIndex { MemoryIndex { tracks: RwLock::new(HashMap::default()), } } } impl MusicIndex for MemoryIndex { fn add_track(&mut self, info: &TrackInfo) -> Flow { let id = TrackId::default(); let track = Track { id: id.clone(), track_number: info.track_number, name: info.name.clone(), album: info.album.clone(), artist: info.artist.clone(), }; let mut tracks = self.tracks.write().unwrap(); tracks.insert(id, track.clone()); ok(track) } fn remove_track(&mut self, id: &TrackId) -> Flow<(), FatalError, DatabaseError> { let mut tracks = self.tracks.write().unwrap(); tracks.remove(&id); ok(()) } fn get_track_info<'a>( &'a self, id: &TrackId, ) -> Flow, FatalError, DatabaseError> { let track = { let tracks = self.tracks.read().unwrap(); tracks.get(&id).cloned() }; ok(track) } } pub struct ManagedConnection<'a> { pool: &'a Database, conn: Option, } impl<'a> Drop for ManagedConnection<'a> { fn drop(&mut self) { self.pool.r(self.conn.take().unwrap()); } } #[derive(Clone)] pub struct Database { path: PathBuf, pool: Arc>>, } impl Database { pub fn new(path: PathBuf) -> Flow { let connection = match Connection::open(path.clone()) { Ok(connection) => connection, Err(err) => return error(DatabaseError::UnhandledError(err)), }; ok(Database { path, pool: Arc::new(Mutex::new(vec![connection])), }) } pub fn r(&self, conn: Connection) { let mut pool = self.pool.lock().unwrap(); pool.push(conn); } }