mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-10 12:32:14 +10:00
chore(download agent): moved to completed index arr to help
serialization
This commit is contained in:
@ -31,7 +31,8 @@ pub struct GameDownloadAgent {
|
|||||||
pub version: String,
|
pub version: String,
|
||||||
pub control_flag: DownloadThreadControl,
|
pub control_flag: DownloadThreadControl,
|
||||||
pub base_dir: String,
|
pub base_dir: String,
|
||||||
contexts: Mutex<Vec<DropDownloadContext>>,
|
contexts: Vec<DropDownloadContext>,
|
||||||
|
completed_contexts: Mutex<Vec<usize>>,
|
||||||
pub manifest: Mutex<Option<DropManifest>>,
|
pub manifest: Mutex<Option<DropManifest>>,
|
||||||
pub progress: Arc<ProgressObject>,
|
pub progress: Arc<ProgressObject>,
|
||||||
sender: Sender<DownloadManagerSignal>,
|
sender: Sender<DownloadManagerSignal>,
|
||||||
@ -56,7 +57,7 @@ impl Display for GameDownloadError {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
GameDownloadError::Communication(error) => write!(f, "{}", error),
|
GameDownloadError::Communication(error) => write!(f, "{}", error),
|
||||||
GameDownloadError::Setup(error) => write!(f, "{:?}", error),
|
GameDownloadError::Setup(error) => write!(f, "An error occurred while setting up the download: {}", error),
|
||||||
GameDownloadError::Lock => write!(f, "Failed to acquire lock. Something has gone very wrong internally. Please restart the application"),
|
GameDownloadError::Lock => write!(f, "Failed to acquire lock. Something has gone very wrong internally. Please restart the application"),
|
||||||
GameDownloadError::Checksum => write!(f, "Checksum failed to validate for download"),
|
GameDownloadError::Checksum => write!(f, "Checksum failed to validate for download"),
|
||||||
GameDownloadError::IoError(error) => write!(f, "{}", error),
|
GameDownloadError::IoError(error) => write!(f, "{}", error),
|
||||||
@ -65,6 +66,14 @@ impl Display for GameDownloadError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for SetupError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
SetupError::Context => write!(f, "Failed to generate contexts for download"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl GameDownloadAgent {
|
impl GameDownloadAgent {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: String,
|
id: String,
|
||||||
@ -88,38 +97,15 @@ impl GameDownloadAgent {
|
|||||||
control_flag,
|
control_flag,
|
||||||
manifest: Mutex::new(None),
|
manifest: Mutex::new(None),
|
||||||
base_dir: data_base_dir_path.to_str().unwrap().to_owned(),
|
base_dir: data_base_dir_path.to_str().unwrap().to_owned(),
|
||||||
contexts: Mutex::new(Vec::new()),
|
contexts: Vec::new(),
|
||||||
|
completed_contexts: Mutex::new(Vec::new()),
|
||||||
progress: Arc::new(ProgressObject::new(0, 0, sender.clone())),
|
progress: Arc::new(ProgressObject::new(0, 0, sender.clone())),
|
||||||
sender,
|
sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_contexts(
|
|
||||||
id: String,
|
|
||||||
version: String,
|
|
||||||
base_dir: String,
|
|
||||||
manifest: DropManifest,
|
|
||||||
contexts: Vec<DropDownloadContext>,
|
|
||||||
sender: Sender<DownloadManagerSignal>,
|
|
||||||
) -> Self {
|
|
||||||
let control_flag = DownloadThreadControl::new(DownloadThreadControlFlag::Stop);
|
|
||||||
|
|
||||||
let me = Self {
|
|
||||||
id,
|
|
||||||
version,
|
|
||||||
control_flag,
|
|
||||||
manifest: Mutex::new(Some(manifest)),
|
|
||||||
base_dir,
|
|
||||||
contexts: Mutex::new(contexts),
|
|
||||||
progress: Arc::new(ProgressObject::new(0, 0, sender.clone())),
|
|
||||||
sender,
|
|
||||||
};
|
|
||||||
me.set_progress_object_params();
|
|
||||||
me
|
|
||||||
}
|
|
||||||
|
|
||||||
// Blocking
|
// Blocking
|
||||||
pub fn setup_download(&self) -> Result<(), GameDownloadError> {
|
pub fn setup_download(&mut self) -> Result<(), GameDownloadError> {
|
||||||
self.ensure_manifest_exists()?;
|
self.ensure_manifest_exists()?;
|
||||||
info!("Ensured manifest exists");
|
info!("Ensured manifest exists");
|
||||||
|
|
||||||
@ -132,7 +118,7 @@ impl GameDownloadAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Blocking
|
// Blocking
|
||||||
pub fn download(&self) -> Result<(), GameDownloadError> {
|
pub fn download(&mut self) -> Result<(), GameDownloadError> {
|
||||||
self.setup_download()?;
|
self.setup_download()?;
|
||||||
self.set_progress_object_params();
|
self.set_progress_object_params();
|
||||||
let timer = Instant::now();
|
let timer = Instant::now();
|
||||||
@ -200,10 +186,9 @@ impl GameDownloadAgent {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lock = self.contexts.lock().unwrap();
|
let length = self.contexts.len();
|
||||||
let length = lock.len();
|
|
||||||
|
|
||||||
let chunk_count = lock.iter().map(|chunk| chunk.length).sum();
|
let chunk_count = self.contexts.iter().map(|chunk| chunk.length).sum();
|
||||||
|
|
||||||
debug!("Setting ProgressObject max to {}", chunk_count);
|
debug!("Setting ProgressObject max to {}", chunk_count);
|
||||||
self.progress.set_max(chunk_count);
|
self.progress.set_max(chunk_count);
|
||||||
@ -213,18 +198,16 @@ impl GameDownloadAgent {
|
|||||||
self.progress.set_time_now();
|
self.progress.set_time_now();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_contexts(&self) -> Result<(), GameDownloadError> {
|
pub fn ensure_contexts(&mut self) -> Result<(), GameDownloadError> {
|
||||||
let context_lock = self.contexts.lock().unwrap();
|
if !self.contexts.is_empty() {
|
||||||
if !context_lock.is_empty() {
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
drop(context_lock);
|
|
||||||
|
|
||||||
self.generate_contexts()?;
|
self.generate_contexts()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_contexts(&self) -> Result<(), GameDownloadError> {
|
pub fn generate_contexts(&mut self) -> Result<(), GameDownloadError> {
|
||||||
let manifest = self.manifest.lock().unwrap().clone().unwrap();
|
let manifest = self.manifest.lock().unwrap().clone().unwrap();
|
||||||
let game_id = self.id.clone();
|
let game_id = self.id.clone();
|
||||||
|
|
||||||
@ -261,13 +244,9 @@ impl GameDownloadAgent {
|
|||||||
let _ = fallocate(file, FallocateFlags::empty(), 0, running_offset);
|
let _ = fallocate(file, FallocateFlags::empty(), 0, running_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.contexts = contexts;
|
||||||
|
|
||||||
if let Ok(mut context_lock) = self.contexts.lock() {
|
Ok(())
|
||||||
*context_lock = contexts;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(GameDownloadError::Setup(SetupError::Context))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&self) -> Result<(), ()> {
|
pub fn run(&self) -> Result<(), ()> {
|
||||||
@ -283,9 +262,14 @@ impl GameDownloadAgent {
|
|||||||
let completed_indexes_loop_arc = completed_indexes.clone();
|
let completed_indexes_loop_arc = completed_indexes.clone();
|
||||||
|
|
||||||
pool.scope(move |scope| {
|
pool.scope(move |scope| {
|
||||||
let contexts = self.contexts.lock().unwrap();
|
let completed_lock = self.completed_contexts.lock().unwrap();
|
||||||
|
|
||||||
|
for (index, context) in self.contexts.iter().enumerate() {
|
||||||
|
// If we've done this one already, skip it
|
||||||
|
if completed_lock.contains(&index) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (index, context) in contexts.iter().enumerate() {
|
|
||||||
let context = context.clone();
|
let context = context.clone();
|
||||||
let control_flag = self.control_flag.clone(); // Clone arcs
|
let control_flag = self.control_flag.clone(); // Clone arcs
|
||||||
let progress = self.progress.get(index); // Clone arcs
|
let progress = self.progress.get(index); // Clone arcs
|
||||||
@ -309,18 +293,13 @@ impl GameDownloadAgent {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut context_lock = self.contexts.lock().unwrap();
|
let mut completed_lock = self.completed_contexts.lock().unwrap();
|
||||||
let mut completed_lock = completed_indexes.lock().unwrap();
|
let newly_completed_lock = completed_indexes.lock().unwrap();
|
||||||
|
|
||||||
// Sort desc so we don't have to modify indexes
|
completed_lock.extend(newly_completed_lock.iter());
|
||||||
completed_lock.sort_by(|a, b| b.cmp(a));
|
|
||||||
|
|
||||||
for index in completed_lock.iter() {
|
|
||||||
context_lock.remove(*index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're not out of contexts, we're not done, so we don't fire completed
|
// If we're not out of contexts, we're not done, so we don't fire completed
|
||||||
if !context_lock.is_empty() {
|
if completed_lock.len() != self.contexts.len() {
|
||||||
info!("da for {} exited without completing", self.id.clone());
|
info!("da for {} exited without completing", self.id.clone());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -333,25 +312,3 @@ impl GameDownloadAgent {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub struct GameDownloadAgentOfflineState {
|
|
||||||
id: String,
|
|
||||||
version: String,
|
|
||||||
base_dir: String,
|
|
||||||
manifest: DropManifest,
|
|
||||||
contexts: Vec<DropDownloadContext>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GameDownloadAgentOfflineState {
|
|
||||||
fn to_download_agent(self, sender: Sender<DownloadManagerSignal>) -> GameDownloadAgent {
|
|
||||||
GameDownloadAgent::from_contexts(
|
|
||||||
self.id,
|
|
||||||
self.version,
|
|
||||||
self.base_dir,
|
|
||||||
self.manifest,
|
|
||||||
self.contexts,
|
|
||||||
sender,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -68,7 +68,7 @@ Behold, my madness - quexeky
|
|||||||
pub type CurrentProgressObject = Arc<Mutex<Option<Arc<ProgressObject>>>>;
|
pub type CurrentProgressObject = Arc<Mutex<Option<Arc<ProgressObject>>>>;
|
||||||
|
|
||||||
pub struct DownloadManagerBuilder {
|
pub struct DownloadManagerBuilder {
|
||||||
download_agent_registry: HashMap<String, Arc<GameDownloadAgent>>,
|
download_agent_registry: HashMap<String, Arc<Mutex<GameDownloadAgent>>>,
|
||||||
download_queue: Queue,
|
download_queue: Queue,
|
||||||
command_receiver: Receiver<DownloadManagerSignal>,
|
command_receiver: Receiver<DownloadManagerSignal>,
|
||||||
sender: Sender<DownloadManagerSignal>,
|
sender: Sender<DownloadManagerSignal>,
|
||||||
@ -156,7 +156,7 @@ impl DownloadManagerBuilder {
|
|||||||
|
|
||||||
fn sync_download_agent(&self) {}
|
fn sync_download_agent(&self) {}
|
||||||
|
|
||||||
fn remove_and_cleanup_game(&mut self, game_id: &String) -> Arc<GameDownloadAgent> {
|
fn remove_and_cleanup_game(&mut self, game_id: &String) -> Arc<Mutex<GameDownloadAgent>> {
|
||||||
self.download_queue.pop_front();
|
self.download_queue.pop_front();
|
||||||
let download_agent = self.download_agent_registry.remove(game_id).unwrap();
|
let download_agent = self.download_agent_registry.remove(game_id).unwrap();
|
||||||
self.cleanup_current_download();
|
self.cleanup_current_download();
|
||||||
@ -227,13 +227,16 @@ impl DownloadManagerBuilder {
|
|||||||
if interface.id == game_id {
|
if interface.id == game_id {
|
||||||
info!("Popping consumed data");
|
info!("Popping consumed data");
|
||||||
let download_agent = self.remove_and_cleanup_game(&game_id);
|
let download_agent = self.remove_and_cleanup_game(&game_id);
|
||||||
|
let download_agent_lock = download_agent.lock().unwrap();
|
||||||
|
|
||||||
if let Err(error) = on_game_complete(
|
let version = download_agent_lock.version.clone();
|
||||||
game_id,
|
let install_dir = download_agent_lock.base_dir.clone();
|
||||||
download_agent.version.clone(),
|
|
||||||
download_agent.base_dir.clone(),
|
drop(download_agent_lock);
|
||||||
&self.app_handle,
|
|
||||||
) {
|
if let Err(error) =
|
||||||
|
on_game_complete(game_id, version, install_dir, &self.app_handle)
|
||||||
|
{
|
||||||
self.sender
|
self.sender
|
||||||
.send(DownloadManagerSignal::Error(
|
.send(DownloadManagerSignal::Error(
|
||||||
GameDownloadError::Communication(error),
|
GameDownloadError::Communication(error),
|
||||||
@ -248,19 +251,24 @@ impl DownloadManagerBuilder {
|
|||||||
|
|
||||||
fn manage_queue_signal(&mut self, id: String, version: String, target_download_dir: usize) {
|
fn manage_queue_signal(&mut self, id: String, version: String, target_download_dir: usize) {
|
||||||
info!("Got signal Queue");
|
info!("Got signal Queue");
|
||||||
let download_agent = Arc::new(GameDownloadAgent::new(
|
let download_agent = Arc::new(Mutex::new(GameDownloadAgent::new(
|
||||||
id.clone(),
|
id.clone(),
|
||||||
version,
|
version,
|
||||||
target_download_dir,
|
target_download_dir,
|
||||||
self.sender.clone(),
|
self.sender.clone(),
|
||||||
));
|
)));
|
||||||
|
let download_agent_lock = download_agent.lock().unwrap();
|
||||||
|
|
||||||
let agent_status = GameDownloadStatus::Queued;
|
let agent_status = GameDownloadStatus::Queued;
|
||||||
let interface_data = GameDownloadAgentQueueStandin {
|
let interface_data = GameDownloadAgentQueueStandin {
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
status: Mutex::new(agent_status),
|
status: Mutex::new(agent_status),
|
||||||
progress: download_agent.progress.clone(),
|
progress: download_agent_lock.progress.clone(),
|
||||||
};
|
};
|
||||||
let version_name = download_agent.version.clone();
|
let version_name = download_agent_lock.version.clone();
|
||||||
|
|
||||||
|
drop(download_agent_lock);
|
||||||
|
|
||||||
self.download_agent_registry
|
self.download_agent_registry
|
||||||
.insert(interface_data.id.clone(), download_agent);
|
.insert(interface_data.id.clone(), download_agent);
|
||||||
self.download_queue.append(interface_data);
|
self.download_queue.append(interface_data);
|
||||||
@ -287,24 +295,28 @@ impl DownloadManagerBuilder {
|
|||||||
.get(&agent_data.id)
|
.get(&agent_data.id)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone();
|
.clone();
|
||||||
|
let download_agent_lock = download_agent.lock().unwrap();
|
||||||
self.current_download_agent = Some(agent_data);
|
self.current_download_agent = Some(agent_data);
|
||||||
// Cloning option should be okay because it only clones the Arc inside, not the AgentInterfaceData
|
// Cloning option should be okay because it only clones the Arc inside, not the AgentInterfaceData
|
||||||
let agent_data = self.current_download_agent.clone().unwrap();
|
let agent_data = self.current_download_agent.clone().unwrap();
|
||||||
|
|
||||||
let version_name = download_agent.version.clone();
|
let version_name = download_agent_lock.version.clone();
|
||||||
|
|
||||||
let progress_object = download_agent.progress.clone();
|
let progress_object = download_agent_lock.progress.clone();
|
||||||
*self.progress.lock().unwrap() = Some(progress_object);
|
*self.progress.lock().unwrap() = Some(progress_object);
|
||||||
|
|
||||||
let active_control_flag = download_agent.control_flag.clone();
|
let active_control_flag = download_agent_lock.control_flag.clone();
|
||||||
self.active_control_flag = Some(active_control_flag.clone());
|
self.active_control_flag = Some(active_control_flag.clone());
|
||||||
|
|
||||||
let sender = self.sender.clone();
|
let sender = self.sender.clone();
|
||||||
|
|
||||||
|
drop(download_agent_lock);
|
||||||
|
|
||||||
info!("Spawning download");
|
info!("Spawning download");
|
||||||
let mut download_thread_lock = self.current_download_thread.lock().unwrap();
|
let mut download_thread_lock = self.current_download_thread.lock().unwrap();
|
||||||
*download_thread_lock = Some(spawn(move || {
|
*download_thread_lock = Some(spawn(move || {
|
||||||
match download_agent.download() {
|
let mut download_agent_lock = download_agent.lock().unwrap();
|
||||||
|
match download_agent_lock.download() {
|
||||||
// Returns once we've exited the download
|
// Returns once we've exited the download
|
||||||
// (not necessarily completed)
|
// (not necessarily completed)
|
||||||
// The download agent will fire the completed event for us
|
// The download agent will fire the completed event for us
|
||||||
@ -315,6 +327,7 @@ impl DownloadManagerBuilder {
|
|||||||
sender.send(DownloadManagerSignal::Error(err)).unwrap();
|
sender.send(DownloadManagerSignal::Error(err)).unwrap();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
drop(download_agent_lock);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Set status for games
|
// Set status for games
|
||||||
@ -347,7 +360,7 @@ impl DownloadManagerBuilder {
|
|||||||
*lock = GameDownloadStatus::Error;
|
*lock = GameDownloadStatus::Error;
|
||||||
self.set_status(DownloadManagerStatus::Error(error));
|
self.set_status(DownloadManagerStatus::Error(error));
|
||||||
|
|
||||||
let game_id = self.current_download_agent.as_ref().unwrap().id.clone();
|
let game_id = current_status.id.clone();
|
||||||
self.set_game_status(game_id, DatabaseGameStatus::Remote {});
|
self.set_game_status(game_id, DatabaseGameStatus::Remote {});
|
||||||
|
|
||||||
self.sender.send(DownloadManagerSignal::Update).unwrap();
|
self.sender.send(DownloadManagerSignal::Update).unwrap();
|
||||||
|
|||||||
@ -234,7 +234,7 @@ pub fn run() {
|
|||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let tray = TrayIconBuilder::new()
|
TrayIconBuilder::new()
|
||||||
.icon(app.default_window_icon().unwrap().clone())
|
.icon(app.default_window_icon().unwrap().clone())
|
||||||
.menu(&menu)
|
.menu(&menu)
|
||||||
.on_menu_event(|app, event| match event.id.as_ref() {
|
.on_menu_event(|app, event| match event.id.as_ref() {
|
||||||
|
|||||||
Reference in New Issue
Block a user