mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-09 20:12:14 +10:00
* fix: launching on linux * feat: #70 * feat: add dummy store page * feat: add store redir and refresh button to library * feat: cache first object fetching * feat: Remove let_chains feature and update to Rust 2024 Signed-off-by: quexeky <git@quexeky.dev> * feat: Check for if process was manually stopped Signed-off-by: quexeky <git@quexeky.dev> * fix: use bitcode instead of serde * chore: remove logs * fix: clippy * fix: clippy 2 * fix: swap to stop icon --------- Signed-off-by: quexeky <git@quexeky.dev> Co-authored-by: quexeky <git@quexeky.dev>
196 lines
5.8 KiB
Rust
196 lines
5.8 KiB
Rust
use std::{
|
|
any::Any,
|
|
collections::VecDeque,
|
|
fmt::Debug,
|
|
sync::{
|
|
mpsc::{SendError, Sender},
|
|
Mutex, MutexGuard,
|
|
},
|
|
thread::JoinHandle,
|
|
};
|
|
|
|
use log::{debug, info};
|
|
use serde::Serialize;
|
|
|
|
use crate::{
|
|
database::models::data::DownloadableMetadata,
|
|
error::application_download_error::ApplicationDownloadError,
|
|
};
|
|
|
|
use super::{
|
|
download_manager_builder::{CurrentProgressObject, DownloadAgent},
|
|
util::queue::Queue,
|
|
};
|
|
|
|
pub enum DownloadManagerSignal {
|
|
/// Resumes (or starts) the DownloadManager
|
|
Go,
|
|
/// Pauses the DownloadManager
|
|
Stop,
|
|
/// Called when a DownloadAgent has fully completed a download.
|
|
Completed(DownloadableMetadata),
|
|
/// Generates and appends a DownloadAgent
|
|
/// to the registry and queue
|
|
Queue(DownloadAgent),
|
|
/// Tells the Manager to stop the current
|
|
/// download, sync everything to disk, and
|
|
/// then exit
|
|
Finish,
|
|
/// Stops, removes, and tells a download to cleanup
|
|
Cancel(DownloadableMetadata),
|
|
/// Any error which occurs in the agent
|
|
Error(ApplicationDownloadError),
|
|
/// Pushes UI update
|
|
UpdateUIQueue,
|
|
UpdateUIStats(usize, usize), //kb/s and seconds
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum DownloadManagerStatus {
|
|
Downloading,
|
|
Paused,
|
|
Empty,
|
|
Error,
|
|
}
|
|
|
|
impl Serialize for DownloadManagerStatus {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: serde::Serializer,
|
|
{
|
|
serializer.serialize_str(&format!["{self:?}"])
|
|
}
|
|
}
|
|
|
|
#[derive(Serialize, Clone, Debug)]
|
|
pub enum DownloadStatus {
|
|
Queued,
|
|
Downloading,
|
|
Validating,
|
|
Error,
|
|
}
|
|
|
|
/// Accessible front-end for the DownloadManager
|
|
///
|
|
/// The system works entirely through signals, both internally and externally,
|
|
/// all of which are accessible through the DownloadManagerSignal type, but
|
|
/// should not be used directly. Rather, signals are abstracted through this
|
|
/// interface.
|
|
///
|
|
/// The actual download queue may be accessed through the .edit() function,
|
|
/// which provides raw access to the underlying queue.
|
|
/// THIS EDITING IS BLOCKING!!!
|
|
pub struct DownloadManager {
|
|
terminator: Mutex<Option<JoinHandle<Result<(), ()>>>>,
|
|
download_queue: Queue,
|
|
progress: CurrentProgressObject,
|
|
command_sender: Sender<DownloadManagerSignal>,
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
impl DownloadManager {
|
|
pub fn new(
|
|
terminator: JoinHandle<Result<(), ()>>,
|
|
download_queue: Queue,
|
|
progress: CurrentProgressObject,
|
|
command_sender: Sender<DownloadManagerSignal>,
|
|
) -> Self {
|
|
Self {
|
|
terminator: Mutex::new(Some(terminator)),
|
|
download_queue,
|
|
progress,
|
|
command_sender,
|
|
}
|
|
}
|
|
|
|
pub fn queue_download(
|
|
&self,
|
|
download: DownloadAgent,
|
|
) -> Result<(), SendError<DownloadManagerSignal>> {
|
|
info!("creating download with meta {:?}", download.metadata());
|
|
self.command_sender
|
|
.send(DownloadManagerSignal::Queue(download))?;
|
|
self.command_sender.send(DownloadManagerSignal::Go)
|
|
}
|
|
pub fn edit(&self) -> MutexGuard<'_, VecDeque<DownloadableMetadata>> {
|
|
self.download_queue.edit()
|
|
}
|
|
pub fn read_queue(&self) -> VecDeque<DownloadableMetadata> {
|
|
self.download_queue.read()
|
|
}
|
|
pub fn get_current_download_progress(&self) -> Option<f64> {
|
|
let progress_object = (*self.progress.lock().unwrap()).clone()?;
|
|
Some(progress_object.get_progress())
|
|
}
|
|
pub fn rearrange_string(&self, meta: &DownloadableMetadata, new_index: usize) {
|
|
let mut queue = self.edit();
|
|
let current_index = get_index_from_id(&mut queue, meta).unwrap();
|
|
let to_move = queue.remove(current_index).unwrap();
|
|
queue.insert(new_index, to_move);
|
|
self.command_sender
|
|
.send(DownloadManagerSignal::UpdateUIQueue)
|
|
.unwrap();
|
|
}
|
|
pub fn cancel(&self, meta: DownloadableMetadata) {
|
|
self.command_sender
|
|
.send(DownloadManagerSignal::Cancel(meta))
|
|
.unwrap();
|
|
}
|
|
pub fn rearrange(&self, current_index: usize, new_index: usize) {
|
|
if current_index == new_index {
|
|
return;
|
|
};
|
|
|
|
let needs_pause = current_index == 0 || new_index == 0;
|
|
if needs_pause {
|
|
self.command_sender
|
|
.send(DownloadManagerSignal::Stop)
|
|
.unwrap();
|
|
}
|
|
|
|
debug!("moving download at index {current_index} to index {new_index}");
|
|
|
|
let mut queue = self.edit();
|
|
let to_move = queue.remove(current_index).unwrap();
|
|
queue.insert(new_index, to_move);
|
|
drop(queue);
|
|
|
|
if needs_pause {
|
|
self.command_sender.send(DownloadManagerSignal::Go).unwrap();
|
|
}
|
|
self.command_sender
|
|
.send(DownloadManagerSignal::UpdateUIQueue)
|
|
.unwrap();
|
|
self.command_sender.send(DownloadManagerSignal::Go).unwrap();
|
|
}
|
|
pub fn pause_downloads(&self) {
|
|
self.command_sender
|
|
.send(DownloadManagerSignal::Stop)
|
|
.unwrap();
|
|
}
|
|
pub fn resume_downloads(&self) {
|
|
self.command_sender.send(DownloadManagerSignal::Go).unwrap();
|
|
}
|
|
pub fn ensure_terminated(&self) -> Result<Result<(), ()>, Box<dyn Any + Send>> {
|
|
self.command_sender
|
|
.send(DownloadManagerSignal::Finish)
|
|
.unwrap();
|
|
let terminator = self.terminator.lock().unwrap().take();
|
|
terminator.unwrap().join()
|
|
}
|
|
pub fn get_sender(&self) -> Sender<DownloadManagerSignal> {
|
|
self.command_sender.clone()
|
|
}
|
|
}
|
|
|
|
/// Takes in the locked value from .edit() and attempts to
|
|
/// get the index of whatever id is passed in
|
|
fn get_index_from_id(
|
|
queue: &mut MutexGuard<'_, VecDeque<DownloadableMetadata>>,
|
|
meta: &DownloadableMetadata,
|
|
) -> Option<usize> {
|
|
queue
|
|
.iter()
|
|
.position(|download_agent| download_agent == meta)
|
|
}
|