eureka-mmanager 0.3.2

An Actix actor collection for downloading manga, chapters, covers from Mangadex
Documentation
pub mod messages;

use std::ops::Deref;

use actix::prelude::*;
use mangadex_api::utils::download::chapter::DownloadMode as Mode;
use mangadex_api_schema_rust::v5::ChapterObject;
use uuid::Uuid;

use crate::{
    download::{
        messages::{DropSingleTaskMessage, StopTask, TaskSubscriberMessages},
        state::{DownloadTaskState, TaskState},
    },
    recipients::Recipients,
    ArcRwLock,
};

use super::ChapterDownloadManager;

#[derive(Debug, Clone)]
pub enum ChapterDownloadingState {
    Preloading,
    FetchingData,
    FetchingImage {
        filename: String,
        index: usize,
        len: usize,
    },
    FetchingAtHomeData,
}

pub type ChapterDownloadTaskState = DownloadTaskState<ChapterObject, ChapterDownloadingState>;

#[derive(Debug, Clone, Copy)]
pub enum DownloadMode {
    Normal,
    DataSaver,
}

impl Message for DownloadMode {
    type Result = ();
}

impl From<DownloadMode> for Mode {
    fn from(value: DownloadMode) -> Self {
        match value {
            DownloadMode::Normal => Self::Normal,
            DownloadMode::DataSaver => Self::DataSaver,
        }
    }
}

impl From<Mode> for DownloadMode {
    fn from(value: Mode) -> Self {
        match value {
            Mode::Normal => Self::Normal,
            Mode::DataSaver => Self::DataSaver,
        }
    }
}

impl From<DownloadMode> for api_core::data_push::chapter::image::Mode {
    fn from(value: DownloadMode) -> Self {
        match value {
            DownloadMode::Normal => api_core::data_push::chapter::image::Mode::Data,
            DownloadMode::DataSaver => api_core::data_push::chapter::image::Mode::DataSaver,
        }
    }
}

#[derive(Debug)]
pub struct ChapterDownloadTask {
    id: Uuid,
    mode: DownloadMode,
    handle: Option<SpawnHandle>,
    state: ArcRwLock<ChapterDownloadTaskState>,
    manager: Addr<ChapterDownloadManager>,
    subscribers: Recipients<TaskSubscriberMessages<ChapterDownloadTaskState>>,
    should_stop: bool,
}

impl ChapterDownloadTask {
    fn sync_state_subscribers(&self) {
        self.subscribers.do_send(TaskSubscriberMessages::State(
            self.state.read().deref().clone(),
        ));
    }
}

impl Drop for ChapterDownloadTask {
    fn drop(&mut self) {
        if !self.should_stop {
            self.manager.do_send(DropSingleTaskMessage(self.id));
        }
        self.subscribers.do_send(TaskSubscriberMessages::Dropped);
    }
}

impl Actor for ChapterDownloadTask {
    type Context = Context<Self>;
    fn stopping(&mut self, _ctx: &mut Self::Context) -> Running {
        if std::convert::Into::<TaskState>::into(self.state.read().deref()).is_loading()
            || self.subscribers.has_connection()
        {
            Running::Continue
        } else {
            Running::Stop
        }
    }
}

impl Handler<StopTask> for ChapterDownloadTask {
    type Result = ();
    fn handle(&mut self, _msg: StopTask, ctx: &mut Self::Context) -> Self::Result {
        self.should_stop = true;
        ctx.terminate();
    }
}

impl ChapterDownloadTask {
    pub(super) fn new<M: Into<DownloadMode>>(
        id: Uuid,
        mode: M,
        manager: Addr<ChapterDownloadManager>,
    ) -> Self {
        Self {
            id,
            mode: mode.into(),
            handle: None,
            state: Default::default(),
            subscribers: Default::default(),
            manager,
            should_stop: false,
        }
    }
}

impl Handler<DownloadMode> for ChapterDownloadTask {
    type Result = <DownloadMode as Message>::Result;
    fn handle(&mut self, msg: DownloadMode, _ctx: &mut Self::Context) -> Self::Result {
        let state = std::convert::Into::<TaskState>::into(self.state.read().deref());
        if !state.is_loading() {
            self.mode = msg;
        }
    }
}