eureka_mmanager/download/
manga.rs1pub mod messages;
2pub mod task;
3
4use std::{collections::HashMap, sync::Arc, time::Duration};
5
6use actix::{prelude::*, WeakAddr};
7use shrink_fit_wrapper::ShrinkFitWrapper;
8use tokio::sync::Notify;
9use uuid::Uuid;
10
11use crate::download::messages::StopTask;
12
13use self::task::MangaDownloadTask;
14
15use super::{
16 messages::{DropSingleTaskMessage, GetTaskMessage, StartDownload},
17 state::{DownloadManagerState, DownloadMessageState},
18 traits::{managers::TaskManager, task::AsyncState},
19};
20
21#[derive(Debug)]
22pub struct MangaDownloadManager {
23 state: Addr<DownloadManagerState>,
24 tasks: ShrinkFitWrapper<HashMap<Uuid, WeakAddr<MangaDownloadTask>>>,
25 notify: Arc<Notify>,
26}
27
28impl MangaDownloadManager {
29 pub fn new(state: Addr<DownloadManagerState>) -> Self {
30 Self {
31 state,
32 tasks: ShrinkFitWrapper::new(HashMap::new())
33 .set_shrink_duration_cycle(Duration::from_secs(6 * 60)),
34 notify: Arc::new(Notify::new()),
35 }
36 }
37}
38
39impl Actor for MangaDownloadManager {
40 type Context = Context<Self>;
41}
42
43#[derive(Debug, Clone, Copy)]
44pub struct MangaDownloadMessage {
45 id: Uuid,
46 state: DownloadMessageState,
48}
49
50impl From<Uuid> for MangaDownloadMessage {
51 fn from(value: Uuid) -> Self {
52 Self::new(value)
53 }
54}
55
56impl From<MangaDownloadMessage> for Uuid {
57 fn from(value: MangaDownloadMessage) -> Self {
58 value.id
59 }
60}
61
62impl MangaDownloadMessage {
63 pub fn new(id: Uuid) -> Self {
64 Self {
65 id,
66 state: Default::default(),
67 }
68 }
69 pub fn state(self, state: DownloadMessageState) -> Self {
70 Self { state, ..self }
71 }
72}
73
74impl Message for MangaDownloadMessage {
75 type Result = Addr<MangaDownloadTask>;
76}
77
78impl TaskManager for MangaDownloadManager {
79 type DownloadMessage = MangaDownloadMessage;
80 type Task = MangaDownloadTask;
81 fn drop_task(&mut self, id: Uuid) {
82 if let Some(task) = self.tasks.get(&id) {
83 if task.upgrade().is_none() {
84 self.tasks.as_mut().remove(&id);
85 }
86 }
87 self.notify.notify_waiters();
88 }
89 fn state(&self) -> Addr<DownloadManagerState> {
90 self.state.clone()
91 }
92 fn notify(&self) -> Arc<Notify> {
93 self.notify.clone()
94 }
95 fn tasks(&self) -> Vec<Addr<Self::Task>> {
96 self.tasks
97 .values()
98 .flat_map(|task| task.upgrade())
99 .collect()
100 }
101 fn tasks_id(&self) -> Vec<Uuid> {
102 self.tasks
103 .iter()
104 .flat_map(|(id, tasks)| {
105 if tasks.upgrade().is_some() {
106 Some(id)
107 } else {
108 None
109 }
110 })
111 .copied()
112 .collect()
113 }
114 fn new_task(
115 &mut self,
116 msg: Self::DownloadMessage,
117 ctx: &mut Self::Context,
118 ) -> Addr<Self::Task> {
119 let task = {
120 match self.tasks.as_mut().entry(msg.id) {
121 std::collections::hash_map::Entry::Occupied(mut occupied_entry) => {
122 let weak = occupied_entry.get_mut();
123 if let Some(tsk) = weak.upgrade() {
124 tsk
125 } else {
126 let tsk = Self::Task::new(msg.id, ctx.address()).start();
127 let _weak = std::mem::replace(weak, tsk.downgrade());
128 tsk
129 }
130 }
131 std::collections::hash_map::Entry::Vacant(vacant_entry) => {
132 let tsk = Self::Task::new(msg.id, ctx.address()).start();
133 vacant_entry.insert(tsk.downgrade());
134 tsk
135 }
136 }
137 };
138 let re_task = task.clone();
139 self.notify.notify_waiters();
140
141 if let DownloadMessageState::Downloading = msg.state {
142 let fut = async move {
143 let s = re_task.state().await?;
144 if !s.is_loading() {
145 re_task.send(StartDownload).await?;
146 }
147 Ok::<_, actix::MailboxError>(())
148 }
149 .into_actor(self)
150 .map(|s, _, _| {
151 if let Err(er) = s {
152 log::error!("{er}");
153 }
154 });
155 ctx.wait(fut)
156 }
157 task
158 }
159 fn get_task(&self, id: Uuid) -> Option<Addr<Self::Task>> {
160 self.tasks.get(&id).and_then(WeakAddr::upgrade)
161 }
162}
163
164impl Handler<MangaDownloadMessage> for MangaDownloadManager {
165 type Result = <MangaDownloadMessage as Message>::Result;
166 fn handle(&mut self, msg: MangaDownloadMessage, ctx: &mut Self::Context) -> Self::Result {
168 self.new_task(msg, ctx)
169 }
170}
171
172impl Handler<DropSingleTaskMessage> for MangaDownloadManager {
173 type Result = <DropSingleTaskMessage as Message>::Result;
174 fn handle(&mut self, msg: DropSingleTaskMessage, _ctx: &mut Self::Context) -> Self::Result {
175 self.drop_task(msg.0);
176 }
177}
178
179impl Handler<GetTaskMessage<MangaDownloadTask>> for MangaDownloadManager {
180 type Result = <GetTaskMessage<MangaDownloadTask> as Message>::Result;
181 fn handle(
182 &mut self,
183 msg: GetTaskMessage<MangaDownloadTask>,
184 _ctx: &mut Self::Context,
185 ) -> Self::Result {
186 self.get_task(msg.into())
187 }
188}
189
190impl Drop for MangaDownloadManager {
191 fn drop(&mut self) {
192 self.tasks
193 .values()
194 .flat_map(|maybe_task| maybe_task.upgrade())
195 .for_each(|task| task.do_send(StopTask));
196 }
197}