Start implementing assets
This commit is contained in:
parent
be2c15be39
commit
7a4eb4694b
@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
@ -122,9 +124,21 @@ pub async fn get_version_detail(reqwest: &Client, version : &Version) -> Result<
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct AssetsManifest {
|
pub struct AssetsManifest {
|
||||||
objects: Map<String, Value>,
|
pub objects: HashMap<String, AssetObject>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_version_assets(assets_index: &AssetIndex) -> Result<()> {
|
#[derive(Serialize, Deserialize)]
|
||||||
bail!("Not yet implemented")
|
pub struct AssetObject {
|
||||||
|
pub hash: String,
|
||||||
|
pub size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_version_assets(reqwest: &Client , assets_index: &AssetIndex) -> Result<AssetsManifest> {
|
||||||
|
let received: AssetsManifest = reqwest
|
||||||
|
.get(assets_index.url.clone())
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.json()
|
||||||
|
.await?;
|
||||||
|
Ok(received)
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ use tokio::{fs, io::{AsyncWriteExt, AsyncSeekExt}, sync::mpsc};
|
|||||||
|
|
||||||
use crate::authentification::GameProfile;
|
use crate::authentification::GameProfile;
|
||||||
|
|
||||||
use self::manifest::{VersionDetail, get_version_manifest, get_version_from_manifest, get_version_detail, Library, OSName, get_version_assets};
|
use self::manifest::{VersionDetail, get_version_manifest, get_version_from_manifest, get_version_detail, Library, OSName, get_version_assets, AssetsManifest};
|
||||||
|
|
||||||
|
|
||||||
#[cfg(target_os="windows")]
|
#[cfg(target_os="windows")]
|
||||||
@ -41,6 +41,7 @@ pub struct ClientOptions<'a> {
|
|||||||
pub struct MinecraftClient<'a> {
|
pub struct MinecraftClient<'a> {
|
||||||
opts: &'a ClientOptions<'a>,
|
opts: &'a ClientOptions<'a>,
|
||||||
details: VersionDetail,
|
details: VersionDetail,
|
||||||
|
assets: AssetsManifest,
|
||||||
reqwest_client: Client,
|
reqwest_client: Client,
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -48,20 +49,23 @@ pub struct MinecraftClient<'a> {
|
|||||||
impl<'a> MinecraftClient<'_> {
|
impl<'a> MinecraftClient<'_> {
|
||||||
pub async fn new(opts: &'a ClientOptions<'a>) -> Result<MinecraftClient<'a>> {
|
pub async fn new(opts: &'a ClientOptions<'a>) -> Result<MinecraftClient<'a>> {
|
||||||
let reqwest_client = Client::new();
|
let reqwest_client = Client::new();
|
||||||
let details = Self::load_manifest(&reqwest_client, &opts).await?;
|
let manifest = Self::load_manifest(&reqwest_client, &opts).await?;
|
||||||
|
let details = manifest.0;
|
||||||
|
let assets = manifest.1;
|
||||||
Ok(MinecraftClient {
|
Ok(MinecraftClient {
|
||||||
opts,
|
opts,
|
||||||
reqwest_client,
|
reqwest_client,
|
||||||
details,
|
details,
|
||||||
|
assets,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_manifest(reqwest_client: &Client, opts: &ClientOptions<'a>) -> Result<VersionDetail> {
|
async fn load_manifest(reqwest_client: &Client, opts: &ClientOptions<'a>) -> Result<(VersionDetail, AssetsManifest)> {
|
||||||
let manifest = get_version_manifest(&reqwest_client).await?;
|
let manifest = get_version_manifest(&reqwest_client).await?;
|
||||||
let version = get_version_from_manifest(&manifest, opts.version_number.clone(), &opts.version_type).await?;
|
let version = get_version_from_manifest(&manifest, opts.version_number.clone(), &opts.version_type).await?;
|
||||||
let details = get_version_detail(&reqwest_client, version).await?;
|
let details = get_version_detail(&reqwest_client, version).await?;
|
||||||
// let version_assets = get_version_assets(&details.asset_index).await?;
|
let version_assets = get_version_assets(reqwest_client, &details.asset_index).await?;
|
||||||
Ok(details)
|
Ok((details, version_assets))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn download_requirements(&mut self) -> Result<()> {
|
pub async fn download_requirements(&mut self) -> Result<()> {
|
||||||
@ -73,6 +77,10 @@ impl<'a> MinecraftClient<'_> {
|
|||||||
if !lib.exists() {
|
if !lib.exists() {
|
||||||
fs::create_dir(lib).await?;
|
fs::create_dir(lib).await?;
|
||||||
}
|
}
|
||||||
|
let asset = &self.opts.root_path.join("assets").join("objects");
|
||||||
|
if !asset.exists() {
|
||||||
|
fs::create_dir_all(asset).await?;
|
||||||
|
}
|
||||||
self.download_libraries(lib).await?;
|
self.download_libraries(lib).await?;
|
||||||
self.opts.log_channel.closed().await;
|
self.opts.log_channel.closed().await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -92,7 +100,7 @@ impl<'a> MinecraftClient<'_> {
|
|||||||
let mut file = if (&file_path).exists() {
|
let mut file = if (&file_path).exists() {
|
||||||
let f = fs::File::open(&file_path).await;
|
let f = fs::File::open(&file_path).await;
|
||||||
match f {
|
match f {
|
||||||
Ok(f) => f,
|
Ok(mut f) => { if f.seek(std::io::SeekFrom::End(0)).await? == i.downloads.artifact.size { f } else { fs::File::create(file_path).await? } },
|
||||||
Err(err) => bail!(err),
|
Err(err) => bail!(err),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -128,6 +136,7 @@ impl<'a> MinecraftClient<'_> {
|
|||||||
} else {
|
} else {
|
||||||
println!("{} already downloaded", i.name);
|
println!("{} already downloaded", i.name);
|
||||||
}
|
}
|
||||||
|
println!("Sending message");
|
||||||
self.opts.log_channel.send( ProgressMessage { p_type: "libraries".to_string(), current: progress + 1, total }).await?;
|
self.opts.log_channel.send( ProgressMessage { p_type: "libraries".to_string(), current: progress + 1, total }).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -138,7 +147,35 @@ impl<'a> MinecraftClient<'_> {
|
|||||||
self.details.libraries.retain(|e| { Self::should_use_library(e) });
|
self.details.libraries.retain(|e| { Self::should_use_library(e) });
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn download_assets(&mut self) -> Result<()> {
|
async fn download_assets(&mut self, object_folder: PathBuf) -> Result<()> {
|
||||||
|
for (_, (key, value)) in self.assets.objects.iter().enumerate() {
|
||||||
|
let hash = value.hash.clone();
|
||||||
|
let two_hex = hash.chars().take(2).collect::<String>();
|
||||||
|
let hex_folder = object_folder.join(&two_hex);
|
||||||
|
if !hex_folder.exists() {
|
||||||
|
fs::create_dir(&hex_folder).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_path = hex_folder.join(&hash);
|
||||||
|
let mut file = if (&file_path).exists() {
|
||||||
|
let f = fs::File::open(&file_path).await;
|
||||||
|
match f {
|
||||||
|
Ok(f) => f,
|
||||||
|
Err(err) => bail!(err),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fs::File::create(file_path).await?
|
||||||
|
};
|
||||||
|
|
||||||
|
let url = format!("https://resources.download.minecraft.net/{}/{}", two_hex, hash);
|
||||||
|
let received = self.reqwest_client
|
||||||
|
.get(url)
|
||||||
|
.send()
|
||||||
|
.await?
|
||||||
|
.bytes()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
}
|
||||||
bail!("Not yet implemented")
|
bail!("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ async fn login(app: tauri::AppHandle, _window: tauri::Window, state: tauri::Stat
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn download(app: tauri::AppHandle, state: tauri::State<'_, Mutex<CustomState>>) -> Result<String, String> {
|
async fn download(app: tauri::AppHandle, state: tauri::State<'_, Mutex<CustomState>>) -> Result<String, String> {
|
||||||
|
println!("starting download");
|
||||||
if let Some(base_dir) = BaseDirs::new() {
|
if let Some(base_dir) = BaseDirs::new() {
|
||||||
let data_folder = base_dir.data_dir().join(".altarik_test");
|
let data_folder = base_dir.data_dir().join(".altarik_test");
|
||||||
let root_path = data_folder.as_path();
|
let root_path = data_folder.as_path();
|
||||||
@ -56,7 +57,7 @@ async fn download(app: tauri::AppHandle, state: tauri::State<'_, Mutex<CustomSta
|
|||||||
if game_profile.is_none() {
|
if game_profile.is_none() {
|
||||||
return Err("You're not connected".to_string());
|
return Err("You're not connected".to_string());
|
||||||
}
|
}
|
||||||
let (sender, receiver) = mpsc::channel(50);
|
let (sender, receiver) = mpsc::channel(60);
|
||||||
let opts = ClientOptions {
|
let opts = ClientOptions {
|
||||||
authorization: game_profile.unwrap(),
|
authorization: game_profile.unwrap(),
|
||||||
log_channel: sender.clone(),
|
log_channel: sender.clone(),
|
||||||
@ -102,7 +103,7 @@ async fn download_libraries(opts: ClientOptions<'_>) -> Result<String, String> {
|
|||||||
async fn read_channel(mut receiver: mpsc::Receiver<ProgressMessage>, app: tauri::AppHandle) -> Result<()> {
|
async fn read_channel(mut receiver: mpsc::Receiver<ProgressMessage>, app: tauri::AppHandle) -> Result<()> {
|
||||||
loop {
|
loop {
|
||||||
match receiver.recv().await {
|
match receiver.recv().await {
|
||||||
Some(msg) => app.emit_all("progress", msg)?,
|
Some(msg) => { println!("received {:?}", msg); app.emit_all("progress", msg)? },
|
||||||
None => break Ok(())
|
None => break Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user