tano-database 0.1.0

Tano database
use color_eyre::eyre::Result;
use tano_providers::local::parse_song::ParsedSong;
use tokio::sync::{mpsc, oneshot};

use crate::{
    actor::{DatabaseActor, cmd::DatabaseCmd, run_database_actor},
    album::Album,
    artist::Artist,
    local_song::{LocalSong, SyncLocalSong},
    song::Song,
};

const DATABASE_ACTOR_KILLED: &str = "DatabaseActor task has been killed";

#[derive(Clone)]
pub struct DatabaseActorHandle {
    sender: mpsc::Sender<DatabaseCmd>,
}

impl Default for DatabaseActorHandle {
    fn default() -> Self {
        let (sender, receiver) = mpsc::channel(8);
        let actor = DatabaseActor::new(receiver);
        tokio::spawn(run_database_actor(actor));

        Self { sender }
    }
}

impl DatabaseActorHandle {
    pub async fn get_songs(&self) -> Result<Vec<Song>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetSongs { respond_to: send };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_albums(&self) -> Result<Vec<Album>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetAlbums { respond_to: send };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_album_artists(&self, album_id: i64) -> Result<Vec<Artist>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetAlbumArtists {
            album_id,
            respond_to: send,
        };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_album(&self, id: i64) -> Result<Option<Album>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetAlbum {
            id,
            respond_to: send,
        };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_album_songs(&self, album_id: i64) -> Result<Vec<Song>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetAlbumSongs {
            album_id,
            respond_to: send,
        };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_artists(&self) -> Result<Vec<Artist>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetArtists { respond_to: send };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_sync_local_songs(&self, provider_id: u64) -> Result<Vec<SyncLocalSong>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetSyncLocalSong {
            respond_to: send,
            provider_id,
        };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_song_ids(&self) -> Result<Vec<i64>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetSongIds { respond_to: send };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn sync_local_songs(
        &self,
        provider_id: u64,
        new_songs: Vec<ParsedSong>,
        updated_songs: Vec<(i64, ParsedSong)>,
        to_update_path: Vec<(i64, String)>,
        to_delete_ids: Vec<i64>,
    ) -> Result<()> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::SyncLocalSongs {
            provider_id,
            new_songs,
            updated_songs,
            to_update_path,
            to_delete_ids,
            respond_to: send,
        };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn load_database(&self) -> Result<()> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::LoadDatabase { respond_to: send };

        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_local_song_by_path(
        &self,
        provider_id: u64,
        path: String,
    ) -> Result<Option<LocalSong>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetLocalSongByPath {
            provider_id,
            path,
            respond_to: send,
        };
        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn get_local_song_by_inode(
        &self,
        provider_id: u64,
        inode: i64,
    ) -> Result<Option<LocalSong>> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::GetLocalSongByInode {
            provider_id,
            inode,
            respond_to: send,
        };
        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn update_local_song_path(&self, id: i64, path: String) -> Result<()> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::UpdateLocalSongPath {
            id,
            path,
            respond_to: send,
        };
        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn insert_local_song(
        &self,
        provider_id: u64,
        parsed_song: ParsedSong,
    ) -> Result<i64> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::InsertLocalSong {
            provider_id,
            parsed_song,
            respond_to: send,
        };
        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn update_local_song(
        &self,
        provider_id: u64,
        id: i64,
        parsed_song: ParsedSong,
    ) -> Result<()> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::UpdateLocalSong {
            provider_id,
            id,
            parsed_song,
            respond_to: send,
        };
        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }

    pub async fn delete_local_song(&self, id: i64) -> Result<()> {
        let (send, recv) = oneshot::channel();
        let cmd = DatabaseCmd::DeleteLocalSong {
            id,
            respond_to: send,
        };
        let _ = self.sender.send(cmd).await;
        recv.await.expect(DATABASE_ACTOR_KILLED)
    }
}