fix: Caching version list
This commit is contained in:
parent
ffab61ebf0
commit
a75ce01c72
5 changed files with 113 additions and 14 deletions
|
|
@ -6,4 +6,7 @@ pub const VERSION: &str = "0.1.0";
|
|||
pub const USER_AGENT: &str = "OneLauncher/1.0.0 (polyfrost.org)";
|
||||
pub const CLIENT_ID: &str = "9419b7ee-1448-4d1b-b52a-550d8f36ab56";
|
||||
|
||||
// Minecraft
|
||||
pub const MINECRAFT_VERSIONS_MANIFEST: &str = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json";
|
||||
|
||||
// Java Downloading
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use uuid::Uuid;
|
|||
|
||||
use crate::PolyResult;
|
||||
|
||||
use super::{minecraft::MinecraftManifest, vanilla};
|
||||
use super::{minecraft::{MinecraftManifest, ReleaseType}, vanilla::{self, VanillaImpl}};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Manifest {
|
||||
|
|
@ -27,16 +27,33 @@ pub struct Instance {
|
|||
pub client: ClientType,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Version {
|
||||
id: String,
|
||||
url: String,
|
||||
#[serde(default)]
|
||||
release_type: ReleaseType,
|
||||
#[serde(default)]
|
||||
release_time: chrono::DateTime<chrono::Utc>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum ClientType {
|
||||
Vanilla
|
||||
Vanilla(VanillaImpl)
|
||||
}
|
||||
|
||||
impl ClientType {
|
||||
pub async fn get_versions(&self, file: Option<&PathBuf>) -> PolyResult<Vec<Version>> {
|
||||
match self {
|
||||
ClientType::Vanilla(_) => vanilla::get_versions(file).await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ClientTrait: Send + Sync {
|
||||
fn from_instance(instance: Instance) -> Self where Self: Sized;
|
||||
|
||||
async fn launch(&self) -> PolyResult<()>;
|
||||
async fn setup(&self) -> PolyResult<()>;
|
||||
|
||||
|
|
@ -47,6 +64,7 @@ pub trait ClientTrait: Send + Sync {
|
|||
}
|
||||
|
||||
pub struct ClientManager {
|
||||
handle: AppHandle,
|
||||
instances: HashMap<Uuid, Instance>,
|
||||
instances_dir: PathBuf,
|
||||
|
||||
|
|
@ -63,6 +81,7 @@ impl ClientManager {
|
|||
let manifests = load_and_serialize::<Manifest>(&manifests_dir)?;
|
||||
|
||||
Ok(Self {
|
||||
handle: handle.clone(),
|
||||
instances,
|
||||
instances_dir,
|
||||
manifests,
|
||||
|
|
@ -101,8 +120,10 @@ impl ClientManager {
|
|||
group: Option<Uuid>,
|
||||
client: ClientType
|
||||
) -> PolyResult<Uuid> {
|
||||
// TODO: Implement cahcing
|
||||
let url = String::from("https://piston-meta.mojang.com/v1/packages/d546f1707a3f2b7d034eece5ea2e311eda875787/1.8.9.json");
|
||||
let version_cache = self.handle.path().app_config_dir()?.join("versions_cache.json");
|
||||
let versions = client.get_versions(Some(&version_cache)).await?;
|
||||
let url = &versions.iter().find(|v| v.id == version).ok_or(anyhow!("Version not found"))?.url;
|
||||
|
||||
let uuid = Uuid::new_v4();
|
||||
|
||||
// Save the manifest
|
||||
|
|
|
|||
|
|
@ -1,16 +1,89 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{fs, path::PathBuf};
|
||||
use anyhow::anyhow;
|
||||
use async_trait::async_trait;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::{constants::MINECRAFT_VERSIONS_MANIFEST, utils::http, PolyResult};
|
||||
use super::{client::{ClientTrait, Version}, minecraft::MinecraftManifest};
|
||||
|
||||
use crate::{utils::http, PolyResult};
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VanillaImpl;
|
||||
|
||||
use super::minecraft::MinecraftManifest;
|
||||
#[async_trait]
|
||||
impl ClientTrait for VanillaImpl {
|
||||
async fn launch(&self) -> PolyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn retrieve_versions() -> PolyResult<HashMap<String, String>> {
|
||||
let map = HashMap::new();
|
||||
async fn setup(&self) -> PolyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Ok(map)
|
||||
async fn install_game(&self) -> PolyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn install_libraries(&self) -> PolyResult<String> {
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
async fn install_natives(&self) -> PolyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn install_assets(&self) -> PolyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn retrieve_version_manifest(url: String) -> PolyResult<MinecraftManifest> {
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
struct VersionList {
|
||||
versions: Vec<Version>
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct CachedVersions {
|
||||
last_updated: i64,
|
||||
versions: Vec<Version>,
|
||||
}
|
||||
|
||||
pub async fn get_versions(file: Option<&PathBuf>) -> PolyResult<Vec<Version>> {
|
||||
if let Some(file) = file {
|
||||
if file.exists() && file.is_file() {
|
||||
if let Some(versions) = get_cached_versions(file).await? {
|
||||
return Ok(versions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let response = http::create_client()?.get(MINECRAFT_VERSIONS_MANIFEST).send().await?;
|
||||
let response = response.json::<VersionList>().await?;
|
||||
|
||||
if let Some(file) = file {
|
||||
fs::write(file, serde_json::to_string(&CachedVersions {
|
||||
last_updated: chrono::Utc::now().timestamp(),
|
||||
versions: response.versions.clone()
|
||||
})?)?;
|
||||
}
|
||||
|
||||
Ok(response.versions)
|
||||
}
|
||||
|
||||
async fn get_cached_versions(file: &PathBuf) -> PolyResult<Option<Vec<Version>>> {
|
||||
let cached = serde_json::from_str::<CachedVersions>(&fs::read_to_string(file)?)?;
|
||||
let head_request = http::create_client()?.head(MINECRAFT_VERSIONS_MANIFEST).send().await?;
|
||||
|
||||
let last_updated = head_request.headers().get("Last-Modified").ok_or(anyhow!("Last-Modified header not found"))?;
|
||||
let last_updated = last_updated.to_str().map_err(|_| anyhow!("Failed to convert Last-Modified header to string"))?;
|
||||
let last_updated = chrono::DateTime::parse_from_rfc2822(last_updated)?;
|
||||
|
||||
if cached.last_updated < last_updated.timestamp() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(cached.versions))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn retrieve_version_manifest(url: &str) -> PolyResult<MinecraftManifest> {
|
||||
let manifest = http::create_client()?.get(url).send().await?.json::<MinecraftManifest>().await?;
|
||||
Ok(manifest)
|
||||
}
|
||||
|
|
@ -52,6 +52,9 @@ pub enum PolyError {
|
|||
/// Wrapper around [`anyhow::Error`] to handle generic errors.
|
||||
#[error(transparent)]
|
||||
AnyhowError(#[from] anyhow::Error),
|
||||
/// Wrapper around [`chrono::ParseError`] to handle date parsing errors.
|
||||
#[error("failed to parse a date: {0}")]
|
||||
ChronoError(#[from] chrono::ParseError),
|
||||
}
|
||||
|
||||
/// Alias for a [`Result`] with the error type [`PolyError`].
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { invoke } from '@tauri-apps/api/core';
|
||||
import * as uuid from 'uuid';
|
||||
import Button from '../components/base/Button';
|
||||
|
||||
function BrowserPage() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue