Theoretically adding queue support and optimistic manifest downloading (#1). Needs tests when actual functions are implemented

This commit is contained in:
quexeky
2024-10-19 19:31:43 +11:00
parent dd23ca8481
commit dcd8fa80c0

View File

@ -1,3 +1,4 @@
use std::future::Future;
use std::sync::{Arc, Mutex};
use std::sync::atomic::AtomicUsize;
use serde::{Deserialize, Serialize};
@ -5,35 +6,40 @@ use versions::Version;
use crate::AppState;
use crate::downloads::progress::ProgressChecker;
#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize)]
#[serde(rename_all="camelCase")]
pub struct GameDownload {
id: String,
version: Version,
progress: GameDownloadState
progress: Arc<AtomicUsize>,
state: Mutex<GameDownloadState>,
manifest: Option<Mutex<GameDownloadManifest>>
}
#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq)]
pub enum GameDownloadState {
Uninitialised,
Queued,
Manifest,
Downloading(Arc<AtomicUsize>),
Downloading,
Finished,
Stalled,
Failed,
Cancelled
}
#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq)]
pub enum GameDownloadError {
ManifestAlreadyExists,
ManifestDoesNotExist,
ManifestDownloadError,
}
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[serde(rename_all="camelCase")]
pub struct GameChunkCtx {
chunk_id: usize,
}
#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq)]
pub struct GameDownloadManifest {
// TODO: Implement game manifest
}
@ -43,17 +49,38 @@ impl GameDownload {
Self {
id,
version,
progress: GameDownloadState::Uninitialised
progress: Arc::new(AtomicUsize::new(0)),
state: Mutex::from(GameDownloadState::Uninitialised),
manifest: None
}
}
pub async fn download(&mut self, max_threads: usize, contexts: Vec<GameChunkCtx>) -> Result<(), GameDownloadError> {
pub async fn queue(&self) -> Result<(), GameDownloadError> {
self.change_state(GameDownloadState::Queued);
if self.manifest.is_none() {
return Ok(())
}
self.download_manifest().await
}
pub async fn download(&self, max_threads: usize, contexts: Vec<GameChunkCtx>) -> Result<(), GameDownloadError> {
let progress = Arc::new(AtomicUsize::new(0));
self.progress = GameDownloadState::Downloading(progress.clone());
self.change_state(GameDownloadState::Downloading);
let progress = ProgressChecker::new(Box::new(download_game_chunk), progress);
progress.run_contexts_parallel_async(contexts, max_threads).await;
Ok(())
}
pub async fn download_manifest(&mut self) -> Result<GameDownloadManifest, GameDownloadError> {
pub async fn download_manifest(&self) -> Result<(), GameDownloadError> {
if self.manifest.is_some() {
return Err(GameDownloadError::ManifestAlreadyExists);
}
todo!() // Need to actually download the manifest
}
pub fn change_state(&self, state: GameDownloadState) {
let mut lock = self.state.lock().unwrap();
*lock = state;
}
}
impl GameDownloadManifest {
fn parse_to_chunks(&self) -> Vec<GameChunkCtx> {
todo!()
}
}
@ -71,18 +98,26 @@ pub async fn start_game_download(
) -> Result<(), GameDownloadError> {
let mut download = Arc::new(GameDownload::new(game_id, game_version));
let mut app_state = state.lock().unwrap();
app_state.game_downloads.push(download.clone());
let manifest = match download.download_manifest().await {
Ok(manifest) => { manifest }
Err(e) => { return Err(e) }
let tmp = download.clone();
let manifest = &tmp.manifest;
let Some(unlocked) = manifest else { return Err(GameDownloadError::ManifestDoesNotExist) };
let lock = unlocked.lock().unwrap();
let chunks = lock.parse_to_chunks();
/*
let manifest = match d.manifest {
Some(lock) => {
let lock = lock.lock().unwrap();
lock.parse_to_chunks()
},
None => { return Err(GameDownloadError::ManifestDoesNotExist) }
};
*/
download.download(max_threads, manifest.parse_to_chunks()).await
app_state.game_downloads.push(download.clone());
download.download(max_threads, chunks).await
}
impl GameDownloadManifest {
fn parse_to_chunks(self) -> Vec<GameChunkCtx> {
todo!()
}
}