Skip to main content

eureka_mmanager/download/chapter/
task.rs

1pub mod messages;
2
3use std::ops::Deref;
4
5use actix::prelude::*;
6use mangadex_api::utils::download::chapter::DownloadMode as Mode;
7use mangadex_api_schema_rust::v5::ChapterObject;
8use uuid::Uuid;
9
10use crate::{
11    download::{
12        messages::{DropSingleTaskMessage, StopTask, TaskSubscriberMessages},
13        state::{DownloadTaskState, TaskState},
14    },
15    recipients::Recipients,
16    ArcRwLock,
17};
18
19use super::ChapterDownloadManager;
20
21#[derive(Debug, Clone)]
22pub enum ChapterDownloadingState {
23    Preloading,
24    FetchingData,
25    FetchingImage {
26        filename: String,
27        index: usize,
28        len: usize,
29    },
30    FetchingAtHomeData,
31}
32
33pub type ChapterDownloadTaskState = DownloadTaskState<ChapterObject, ChapterDownloadingState>;
34
35#[derive(Debug, Clone, Copy)]
36pub enum DownloadMode {
37    Normal,
38    DataSaver,
39}
40
41impl Message for DownloadMode {
42    type Result = ();
43}
44
45impl From<DownloadMode> for Mode {
46    fn from(value: DownloadMode) -> Self {
47        match value {
48            DownloadMode::Normal => Self::Normal,
49            DownloadMode::DataSaver => Self::DataSaver,
50        }
51    }
52}
53
54impl From<Mode> for DownloadMode {
55    fn from(value: Mode) -> Self {
56        match value {
57            Mode::Normal => Self::Normal,
58            Mode::DataSaver => Self::DataSaver,
59        }
60    }
61}
62
63impl From<DownloadMode> for api_core::data_push::chapter::image::Mode {
64    fn from(value: DownloadMode) -> Self {
65        match value {
66            DownloadMode::Normal => api_core::data_push::chapter::image::Mode::Data,
67            DownloadMode::DataSaver => api_core::data_push::chapter::image::Mode::DataSaver,
68        }
69    }
70}
71
72#[derive(Debug)]
73pub struct ChapterDownloadTask {
74    id: Uuid,
75    mode: DownloadMode,
76    handle: Option<SpawnHandle>,
77    state: ArcRwLock<ChapterDownloadTaskState>,
78    manager: Addr<ChapterDownloadManager>,
79    subscribers: Recipients<TaskSubscriberMessages<ChapterDownloadTaskState>>,
80    should_stop: bool,
81    force_port_443: bool,
82}
83
84impl ChapterDownloadTask {
85    fn sync_state_subscribers(&self) {
86        self.subscribers.do_send(TaskSubscriberMessages::State(
87            self.state.read().deref().clone(),
88        ));
89    }
90}
91
92impl Drop for ChapterDownloadTask {
93    fn drop(&mut self) {
94        if !self.should_stop {
95            self.manager.do_send(DropSingleTaskMessage(self.id));
96        }
97        self.subscribers.do_send(TaskSubscriberMessages::Dropped);
98    }
99}
100
101impl Actor for ChapterDownloadTask {
102    type Context = Context<Self>;
103    fn stopping(&mut self, _ctx: &mut Self::Context) -> Running {
104        if std::convert::Into::<TaskState>::into(self.state.read().deref()).is_loading()
105            || self.subscribers.has_connection()
106        {
107            Running::Continue
108        } else {
109            Running::Stop
110        }
111    }
112}
113
114impl Handler<StopTask> for ChapterDownloadTask {
115    type Result = ();
116    fn handle(&mut self, _msg: StopTask, ctx: &mut Self::Context) -> Self::Result {
117        self.should_stop = true;
118        ctx.terminate();
119    }
120}
121
122impl ChapterDownloadTask {
123    pub(super) fn new<M: Into<DownloadMode>>(
124        id: Uuid,
125        mode: M,
126        force_port_443: bool,
127        manager: Addr<ChapterDownloadManager>,
128    ) -> Self {
129        Self {
130            id,
131            mode: mode.into(),
132            handle: None,
133            state: Default::default(),
134            subscribers: Default::default(),
135            manager,
136            should_stop: false,
137            force_port_443,
138        }
139    }
140}
141
142impl Handler<DownloadMode> for ChapterDownloadTask {
143    type Result = <DownloadMode as Message>::Result;
144    fn handle(&mut self, msg: DownloadMode, _ctx: &mut Self::Context) -> Self::Result {
145        let state = std::convert::Into::<TaskState>::into(self.state.read().deref());
146        if !state.is_loading() {
147            self.mode = msg;
148        }
149    }
150}