mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-13 08:12:44 +10:00
fix: assorted fixes
This commit is contained in:
12
app.vue
12
app.vue
@ -20,10 +20,18 @@ import {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const state = useAppState();
|
const state = useAppState();
|
||||||
state.value = JSON.parse(await invoke("fetch_state"));
|
try {
|
||||||
|
state.value = JSON.parse(await invoke("fetch_state"));
|
||||||
|
} catch (e) {
|
||||||
|
console.error("failed to parse state", e);
|
||||||
|
}
|
||||||
|
|
||||||
router.beforeEach(async () => {
|
router.beforeEach(async () => {
|
||||||
state.value = JSON.parse(await invoke("fetch_state"));
|
try {
|
||||||
|
state.value = JSON.parse(await invoke("fetch_state"));
|
||||||
|
} catch (e) {
|
||||||
|
console.error("failed to parse state", e);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setupHooks();
|
setupHooks();
|
||||||
|
|||||||
@ -2,7 +2,13 @@ import { listen } from "@tauri-apps/api/event";
|
|||||||
import type { DownloadableMetadata } from "~/types";
|
import type { DownloadableMetadata } from "~/types";
|
||||||
|
|
||||||
export type QueueState = {
|
export type QueueState = {
|
||||||
queue: Array<{ meta: DownloadableMetadata; status: string; progress: number | null }>;
|
queue: Array<{
|
||||||
|
meta: DownloadableMetadata;
|
||||||
|
status: string;
|
||||||
|
progress: number | null;
|
||||||
|
current: number;
|
||||||
|
max: number;
|
||||||
|
}>;
|
||||||
status: string;
|
status: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,4 +31,4 @@ listen("update_queue", (event) => {
|
|||||||
listen("update_stats", (event) => {
|
listen("update_stats", (event) => {
|
||||||
const stats = useStatsState();
|
const stats = useStatsState();
|
||||||
stats.value = event.payload as StatsState;
|
stats.value = event.payload as StatsState;
|
||||||
});
|
});
|
||||||
|
|||||||
@ -48,9 +48,7 @@ export function initialNavigation(state: Ref<AppState>) {
|
|||||||
|
|
||||||
switch (state.value.status) {
|
switch (state.value.status) {
|
||||||
case AppStatus.NotConfigured:
|
case AppStatus.NotConfigured:
|
||||||
router.push({ path: "/setup" }).then(() => {
|
router.push({ path: "/setup" });
|
||||||
console.log("Pushed Setup");
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
case AppStatus.SignedOut:
|
case AppStatus.SignedOut:
|
||||||
router.push("/auth");
|
router.push("/auth");
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
<template />
|
<template />
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
definePageMeta({
|
||||||
|
layout: false
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -242,7 +242,7 @@
|
|||||||
"
|
"
|
||||||
:loading="installLoading"
|
:loading="installLoading"
|
||||||
type="submit"
|
type="submit"
|
||||||
class="w-full sm:w-fit"
|
class="ml-2 w-full sm:w-fit"
|
||||||
>
|
>
|
||||||
Install
|
Install
|
||||||
</LoadingButton>
|
</LoadingButton>
|
||||||
|
|||||||
@ -1,23 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bg-zinc-950 p-4 min-h-full space-y-4">
|
<div class="bg-zinc-950 p-4 min-h-full space-y-4">
|
||||||
<div class="h-16 overflow-hidden relative rounded-xl flex flex-row border border-zinc-900">
|
<div
|
||||||
|
class="h-16 overflow-hidden relative rounded-xl flex flex-row border border-zinc-900"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="bg-zinc-900 z-10 w-32 flex flex-col gap-x-2 text-blue-400 font-display items-left justify-center pl-2">
|
class="bg-zinc-900 z-10 w-32 flex flex-col gap-x-2 text-blue-400 font-display items-left justify-center pl-2"
|
||||||
<span class="font-semibold">{{ formatKilobytes(stats.speed) }}</span>
|
>
|
||||||
<span v-if="stats.time > 0" class="text-sm">{{ formatTime(stats.time) }} left</span>
|
<span class="font-semibold">{{ formatKilobytes(stats.speed) }}/s</span>
|
||||||
|
<span v-if="stats.time > 0" class="text-sm"
|
||||||
|
>{{ formatTime(stats.time) }} left</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="absolute inset-0 h-full flex flex-row items-end justify-end">
|
<div class="absolute inset-0 h-full flex flex-row items-end justify-end">
|
||||||
<div v-for="bar in speedHistory" :style="{ height: `${bar / speedMax * 100}%` }"
|
<div
|
||||||
class="w-[8px] bg-blue-600/40" />
|
v-for="bar in speedHistory"
|
||||||
|
:style="{ height: `${(bar / speedMax) * 100}%` }"
|
||||||
|
class="w-[8px] bg-blue-600/40"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<draggable v-model="queue.queue" @end="onEnd">
|
<draggable v-model="queue.queue" @end="onEnd">
|
||||||
<template #item="{ element }: { element: (typeof queue.value.queue)[0] }">
|
<template #item="{ element }: { element: (typeof queue.value.queue)[0] }">
|
||||||
<li v-if="games[element.meta.id]" :key="element.meta.id"
|
<li
|
||||||
class="mb-4 bg-zinc-900 rounded-lg flex flex-row justify-between gap-x-6 py-5 px-4">
|
v-if="games[element.meta.id]"
|
||||||
|
:key="element.meta.id"
|
||||||
|
class="mb-4 bg-zinc-900 rounded-lg flex flex-row justify-between gap-x-6 py-5 px-4"
|
||||||
|
>
|
||||||
<div class="w-full flex items-center max-w-md gap-x-4 relative">
|
<div class="w-full flex items-center max-w-md gap-x-4 relative">
|
||||||
<img class="size-24 flex-none bg-zinc-800 object-cover rounded" :src="games[element.meta.id].cover" alt="" />
|
<img
|
||||||
|
class="size-24 flex-none bg-zinc-800 object-cover rounded"
|
||||||
|
:src="games[element.meta.id].cover"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
<div class="min-w-0 flex-auto">
|
<div class="min-w-0 flex-auto">
|
||||||
<p class="text-xl font-semibold text-zinc-100">
|
<p class="text-xl font-semibold text-zinc-100">
|
||||||
<NuxtLink :href="`/library/${element.meta.id}`" class="">
|
<NuxtLink :href="`/library/${element.meta.id}`" class="">
|
||||||
@ -35,47 +49,68 @@
|
|||||||
<p class="text-md text-zinc-500 uppercase font-display font-bold">
|
<p class="text-md text-zinc-500 uppercase font-display font-bold">
|
||||||
{{ element.status }}
|
{{ element.status }}
|
||||||
</p>
|
</p>
|
||||||
<div v-if="element.progress" class="mt-1 w-96 bg-zinc-800 rounded-lg overflow-hidden">
|
<div
|
||||||
<div class="h-2 bg-blue-600" :style="{ width: `${element.progress * 100}%` }" />
|
v-if="element.progress"
|
||||||
|
class="mt-1 w-96 bg-zinc-800 rounded-lg overflow-hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="h-2 bg-blue-600"
|
||||||
|
:style="{ width: `${element.progress * 100}%` }"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<span
|
||||||
|
class="mt-2 inline-flex items-center gap-x-1 text-zinc-400 text-sm font-display"
|
||||||
|
><span class="text-zinc-300">{{
|
||||||
|
formatKilobytes(element.current / 1000)
|
||||||
|
}}</span>
|
||||||
|
/
|
||||||
|
<span class="">{{ formatKilobytes(element.max / 1000) }}</span
|
||||||
|
><ServerIcon class="size-5"
|
||||||
|
/></span>
|
||||||
</div>
|
</div>
|
||||||
<button @click="() => cancelGame(element.meta)" class="group">
|
<button @click="() => cancelGame(element.meta)" class="group">
|
||||||
<XMarkIcon class="transition size-8 flex-none text-zinc-600 group-hover:text-zinc-300"
|
<XMarkIcon
|
||||||
aria-hidden="true" />
|
class="transition size-8 flex-none text-zinc-600 group-hover:text-zinc-300"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<p v-else>Loading...</p>
|
<p v-else>Loading...</p>
|
||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
<div class="text-zinc-600 uppercase font-semibold font-display w-full text-center" v-if="queue.queue.length == 0">
|
<div
|
||||||
|
class="text-zinc-600 uppercase font-semibold font-display w-full text-center"
|
||||||
|
v-if="queue.queue.length == 0"
|
||||||
|
>
|
||||||
No items in the queue
|
No items in the queue
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { XMarkIcon } from "@heroicons/vue/20/solid";
|
import { ServerIcon, XMarkIcon } from "@heroicons/vue/20/solid";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import type { DownloadableMetadata, Game, GameStatus } from "~/types";
|
import type { DownloadableMetadata, Game, GameStatus } from "~/types";
|
||||||
|
|
||||||
const windowWidth = ref(window.innerWidth);
|
const windowWidth = ref(window.innerWidth);
|
||||||
window.addEventListener('resize', (event) => {
|
window.addEventListener("resize", (event) => {
|
||||||
windowWidth.value = window.innerWidth;
|
windowWidth.value = window.innerWidth;
|
||||||
})
|
});
|
||||||
|
|
||||||
const queue = useQueueState();
|
const queue = useQueueState();
|
||||||
const stats = useStatsState();
|
const stats = useStatsState();
|
||||||
const speedHistory = useState<Array<number>>(() => []);
|
const speedHistory = useState<Array<number>>(() => []);
|
||||||
const speedHistoryMax = computed(() => windowWidth.value / 8);
|
const speedHistoryMax = computed(() => windowWidth.value / 8);
|
||||||
const speedMax = computed(() => speedHistory.value.reduce((a, b) => a > b ? a : b) * 1.3);
|
const speedMax = computed(
|
||||||
|
() => speedHistory.value.reduce((a, b) => (a > b ? a : b)) * 1.3
|
||||||
|
);
|
||||||
const previousGameId = ref<string | undefined>();
|
const previousGameId = ref<string | undefined>();
|
||||||
|
|
||||||
const games: Ref<{
|
const games: Ref<{
|
||||||
[key: string]: { game: Game; status: Ref<GameStatus>; cover: string };
|
[key: string]: { game: Game; status: Ref<GameStatus>; cover: string };
|
||||||
}> = ref({});
|
}> = ref({});
|
||||||
|
|
||||||
|
|
||||||
function resetHistoryGraph() {
|
function resetHistoryGraph() {
|
||||||
speedHistory.value = [];
|
speedHistory.value = [];
|
||||||
stats.value = { time: 0, speed: 0 };
|
stats.value = { time: 0, speed: 0 };
|
||||||
@ -97,8 +132,7 @@ function checkReset(v: QueueState) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// If it's a different game now
|
// If it's a different game now
|
||||||
if (currentGame != previousGameId.value
|
if (currentGame != previousGameId.value) {
|
||||||
) {
|
|
||||||
previousGameId.value = currentGame;
|
previousGameId.value = currentGame;
|
||||||
resetHistoryGraph();
|
resetHistoryGraph();
|
||||||
return;
|
return;
|
||||||
@ -115,10 +149,12 @@ watch(stats, (v) => {
|
|||||||
speedHistory.value.splice(0, 1);
|
speedHistory.value.splice(0, 1);
|
||||||
}
|
}
|
||||||
checkReset(queue.value);
|
checkReset(queue.value);
|
||||||
})
|
});
|
||||||
|
|
||||||
function loadGamesForQueue(v: typeof queue.value) {
|
function loadGamesForQueue(v: typeof queue.value) {
|
||||||
for (const { meta: { id } } of v.queue) {
|
for (const {
|
||||||
|
meta: { id },
|
||||||
|
} of v.queue) {
|
||||||
if (games.value[id]) return;
|
if (games.value[id]) return;
|
||||||
(async () => {
|
(async () => {
|
||||||
const gameData = await useGame(id);
|
const gameData = await useGame(id);
|
||||||
@ -152,7 +188,7 @@ function formatKilobytes(bytes: number): string {
|
|||||||
unitIndex++;
|
unitIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${value.toFixed(1)} ${units[unitIndex]}/s`;
|
return `${value.toFixed(1)} ${units[unitIndex]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTime(seconds: number): string {
|
function formatTime(seconds: number): string {
|
||||||
@ -162,7 +198,7 @@ function formatTime(seconds: number): string {
|
|||||||
|
|
||||||
const minutes = Math.floor(seconds / 60);
|
const minutes = Math.floor(seconds / 60);
|
||||||
if (minutes < 60) {
|
if (minutes < 60) {
|
||||||
return `${minutes}m ${Math.round(seconds % 60)}s`
|
return `${minutes}m ${Math.round(seconds % 60)}s`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hours = Math.floor(minutes / 60);
|
const hours = Math.floor(minutes / 60);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
export default defineNuxtPlugin((nuxtApp) => {
|
export default defineNuxtPlugin((nuxtApp) => {
|
||||||
// Also possible
|
// Also possible
|
||||||
nuxtApp.hook("vue:error", (error, instance, info) => {
|
nuxtApp.hook("vue:error", (error, instance, info) => {
|
||||||
console.log(error);
|
console.error(error, info);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
router.replace(`/error`);
|
router.replace(`/error`);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fs::{self, create_dir_all},
|
fs::{self, create_dir_all},
|
||||||
path::PathBuf,
|
hash::Hash,
|
||||||
|
path::{Path, PathBuf},
|
||||||
sync::{LazyLock, Mutex, RwLockReadGuard, RwLockWriteGuard},
|
sync::{LazyLock, Mutex, RwLockReadGuard, RwLockWriteGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,10 +92,18 @@ impl Database {
|
|||||||
Self {
|
Self {
|
||||||
applications: DatabaseApplications {
|
applications: DatabaseApplications {
|
||||||
install_dirs: vec![games_base_dir.into()],
|
install_dirs: vec![games_base_dir.into()],
|
||||||
..Default::default()
|
game_statuses: HashMap::new(),
|
||||||
|
game_versions: HashMap::new(),
|
||||||
|
installed_game_version: HashMap::new(),
|
||||||
|
transient_statuses: HashMap::new(),
|
||||||
},
|
},
|
||||||
prev_database,
|
prev_database,
|
||||||
..Default::default()
|
base_url: "".to_owned(),
|
||||||
|
auth: None,
|
||||||
|
settings: Settings {
|
||||||
|
autostart: false,
|
||||||
|
max_download_threads: 4,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -350,6 +350,8 @@ impl DownloadManagerBuilder {
|
|||||||
meta: DownloadableMetadata::clone(key),
|
meta: DownloadableMetadata::clone(key),
|
||||||
status: val.status(),
|
status: val.status(),
|
||||||
progress: val.progress().get_progress(),
|
progress: val.progress().get_progress(),
|
||||||
|
current: val.progress().sum(),
|
||||||
|
max: val.progress().get_max(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@ -23,7 +23,7 @@ pub struct ProgressObject {
|
|||||||
//last_update: Arc<RwLock<Instant>>,
|
//last_update: Arc<RwLock<Instant>>,
|
||||||
last_update_time: Arc<AtomicInstant>,
|
last_update_time: Arc<AtomicInstant>,
|
||||||
bytes_last_update: Arc<AtomicUsize>,
|
bytes_last_update: Arc<AtomicUsize>,
|
||||||
rolling: RollingProgressWindow<256>,
|
rolling: RollingProgressWindow<250>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ProgressHandle {
|
pub struct ProgressHandle {
|
||||||
@ -46,6 +46,15 @@ impl ProgressHandle {
|
|||||||
.fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
|
.fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
|
||||||
calculate_update(&self.progress_object);
|
calculate_update(&self.progress_object);
|
||||||
}
|
}
|
||||||
|
pub fn skip(&self, amount: usize) {
|
||||||
|
self.progress
|
||||||
|
.fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
// Offset the bytes at last offset by this amount
|
||||||
|
self.progress_object
|
||||||
|
.bytes_last_update
|
||||||
|
.fetch_add(amount, Ordering::Relaxed);
|
||||||
|
// Dont' fire update
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgressObject {
|
impl ProgressObject {
|
||||||
@ -97,15 +106,15 @@ impl ProgressObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[throttle(1, Duration::from_millis(20))]
|
#[throttle(1, Duration::from_millis(20))]
|
||||||
pub fn calculate_update(progress_object: &ProgressObject) {
|
pub fn calculate_update(progress: &ProgressObject) {
|
||||||
let last_update_time = progress_object
|
let last_update_time = progress
|
||||||
.last_update_time
|
.last_update_time
|
||||||
.swap(Instant::now(), Ordering::SeqCst);
|
.swap(Instant::now(), Ordering::SeqCst);
|
||||||
let time_since_last_update = Instant::now().duration_since(last_update_time).as_millis();
|
let time_since_last_update = Instant::now().duration_since(last_update_time).as_millis();
|
||||||
|
|
||||||
let current_bytes_downloaded = progress_object.sum();
|
let current_bytes_downloaded = progress.sum();
|
||||||
let max = progress_object.get_max();
|
let max = progress.get_max();
|
||||||
let bytes_at_last_update = progress_object
|
let bytes_at_last_update = progress
|
||||||
.bytes_last_update
|
.bytes_last_update
|
||||||
.swap(current_bytes_downloaded, Ordering::Relaxed);
|
.swap(current_bytes_downloaded, Ordering::Relaxed);
|
||||||
|
|
||||||
@ -115,8 +124,8 @@ pub fn calculate_update(progress_object: &ProgressObject) {
|
|||||||
|
|
||||||
let bytes_remaining = max - current_bytes_downloaded; // bytes
|
let bytes_remaining = max - current_bytes_downloaded; // bytes
|
||||||
|
|
||||||
progress_object.update_window(kilobytes_per_second);
|
progress.update_window(kilobytes_per_second);
|
||||||
push_update(progress_object, bytes_remaining);
|
push_update(progress, bytes_remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[throttle(1, Duration::from_millis(500))]
|
#[throttle(1, Duration::from_millis(500))]
|
||||||
|
|||||||
@ -127,25 +127,17 @@ impl GameDownloadAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn download_manifest(&self) -> Result<(), ApplicationDownloadError> {
|
fn download_manifest(&self) -> Result<(), ApplicationDownloadError> {
|
||||||
let base_url = DB.fetch_base_url();
|
|
||||||
let manifest_url = base_url
|
|
||||||
.join(
|
|
||||||
format!(
|
|
||||||
"/api/v1/client/game/manifest?id={}&version={}",
|
|
||||||
self.id,
|
|
||||||
encode(&self.version)
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let header = generate_authorization_header();
|
let header = generate_authorization_header();
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
let response = client
|
let response = make_request(
|
||||||
.get(manifest_url.to_string())
|
&client,
|
||||||
.header("Authorization", header)
|
&["/api/v1/client/game/manifest"],
|
||||||
.send()
|
&[("id", &self.id), ("version", &self.version)],
|
||||||
.unwrap();
|
|f| f.header("Authorization", header),
|
||||||
|
)
|
||||||
|
.map_err(|e| ApplicationDownloadError::Communication(e))?
|
||||||
|
.send()
|
||||||
|
.map_err(|e| ApplicationDownloadError::Communication(e.into()))?;
|
||||||
|
|
||||||
if response.status() != 200 {
|
if response.status() != 200 {
|
||||||
return Err(ApplicationDownloadError::Communication(
|
return Err(ApplicationDownloadError::Communication(
|
||||||
@ -266,9 +258,10 @@ impl GameDownloadAgent {
|
|||||||
|
|
||||||
let progress = self.progress.get(index);
|
let progress = self.progress.get(index);
|
||||||
let progress_handle = ProgressHandle::new(progress, self.progress.clone());
|
let progress_handle = ProgressHandle::new(progress, self.progress.clone());
|
||||||
|
|
||||||
// If we've done this one already, skip it
|
// If we've done this one already, skip it
|
||||||
if self.completed_contexts.lock().unwrap().contains(&index) {
|
if self.completed_contexts.lock().unwrap().contains(&index) {
|
||||||
progress_handle.add(context.length);
|
progress_handle.skip(context.length);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,8 +312,10 @@ impl GameDownloadAgent {
|
|||||||
// 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 completed_lock_len != contexts.len() {
|
if completed_lock_len != contexts.len() {
|
||||||
info!(
|
info!(
|
||||||
"download agent for {} exited without completing",
|
"download agent for {} exited without completing ({}/{})",
|
||||||
self.id.clone()
|
self.id.clone(),
|
||||||
|
completed_lock_len,
|
||||||
|
contexts.len(),
|
||||||
);
|
);
|
||||||
self.stored_manifest
|
self.stored_manifest
|
||||||
.set_completed_contexts(self.completed_contexts.lock().unwrap().as_slice());
|
.set_completed_contexts(self.completed_contexts.lock().unwrap().as_slice());
|
||||||
@ -385,6 +380,7 @@ impl Downloadable for GameDownloadAgent {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: fix this function. It doesn't restart the download properly, nor does it reset the state properly
|
||||||
fn on_incomplete(&self, app_handle: &tauri::AppHandle) {
|
fn on_incomplete(&self, app_handle: &tauri::AppHandle) {
|
||||||
let meta = self.metadata();
|
let meta = self.metadata();
|
||||||
*self.status.lock().unwrap() = DownloadStatus::Queued;
|
*self.status.lock().unwrap() = DownloadStatus::Queued;
|
||||||
|
|||||||
@ -133,7 +133,6 @@ pub fn download_game_chunk(
|
|||||||
|
|
||||||
if response.status() != 200 {
|
if response.status() != 200 {
|
||||||
let err = response.json().unwrap();
|
let err = response.json().unwrap();
|
||||||
warn!("{:?}", err);
|
|
||||||
return Err(ApplicationDownloadError::Communication(
|
return Err(ApplicationDownloadError::Communication(
|
||||||
RemoteAccessError::InvalidResponse(err),
|
RemoteAccessError::InvalidResponse(err),
|
||||||
));
|
));
|
||||||
|
|||||||
@ -53,6 +53,8 @@ pub struct QueueUpdateEventQueueData {
|
|||||||
pub meta: DownloadableMetadata,
|
pub meta: DownloadableMetadata,
|
||||||
pub status: DownloadStatus,
|
pub status: DownloadStatus,
|
||||||
pub progress: f64,
|
pub progress: f64,
|
||||||
|
pub current: usize,
|
||||||
|
pub max: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize, Clone)]
|
#[derive(serde::Serialize, Clone)]
|
||||||
@ -81,16 +83,13 @@ pub struct GameVersionOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
|
pub fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
|
||||||
let base_url = DB.fetch_base_url();
|
|
||||||
let library_url = base_url.join("/api/v1/client/user/library")?;
|
|
||||||
|
|
||||||
let header = generate_authorization_header();
|
let header = generate_authorization_header();
|
||||||
|
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
let response = client
|
let response = make_request(&client, &["/api/v1/client/user/library"], &[], |f| {
|
||||||
.get(library_url.to_string())
|
f.header("Authorization", header)
|
||||||
.header("Authorization", header)
|
})?
|
||||||
.send()?;
|
.send()?;
|
||||||
|
|
||||||
if response.status() != 200 {
|
if response.status() != 200 {
|
||||||
let err = response.json().unwrap();
|
let err = response.json().unwrap();
|
||||||
@ -290,26 +289,23 @@ pub fn on_game_complete(
|
|||||||
app_handle: &AppHandle,
|
app_handle: &AppHandle,
|
||||||
) -> Result<(), RemoteAccessError> {
|
) -> Result<(), RemoteAccessError> {
|
||||||
// Fetch game version information from remote
|
// Fetch game version information from remote
|
||||||
let base_url = DB.fetch_base_url();
|
|
||||||
if meta.version.is_none() {
|
if meta.version.is_none() {
|
||||||
return Err(RemoteAccessError::GameNotFound);
|
return Err(RemoteAccessError::GameNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
let endpoint = base_url.join(
|
|
||||||
format!(
|
|
||||||
"/api/v1/client/metadata/version?id={}&version={}",
|
|
||||||
meta.id,
|
|
||||||
encode(meta.version.as_ref().unwrap())
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
)?;
|
|
||||||
let header = generate_authorization_header();
|
let header = generate_authorization_header();
|
||||||
|
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
let response = client
|
let response = make_request(
|
||||||
.get(endpoint.to_string())
|
&client,
|
||||||
.header("Authorization", header)
|
&["/api/v1/client/metadata/version"],
|
||||||
.send()?;
|
&[
|
||||||
|
("id", &meta.id),
|
||||||
|
("version", meta.version.as_ref().unwrap()),
|
||||||
|
],
|
||||||
|
|f| f.header("Authorization", header),
|
||||||
|
)?
|
||||||
|
.send()?;
|
||||||
|
|
||||||
let data: GameVersion = response.json()?;
|
let data: GameVersion = response.json()?;
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,7 @@ use remote::auth::{self, generate_authorization_header, recieve_handshake};
|
|||||||
use remote::commands::{
|
use remote::commands::{
|
||||||
auth_initiate, gen_drop_url, manual_recieve_handshake, retry_connect, sign_out, use_remote,
|
auth_initiate, gen_drop_url, manual_recieve_handshake, retry_connect, sign_out, use_remote,
|
||||||
};
|
};
|
||||||
|
use remote::requests::make_request;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@ -355,23 +356,16 @@ pub fn run() {
|
|||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.register_asynchronous_uri_scheme_protocol("object", move |_ctx, request, responder| {
|
.register_asynchronous_uri_scheme_protocol("object", move |_ctx, request, responder| {
|
||||||
let base_url = DB.fetch_base_url();
|
|
||||||
|
|
||||||
// Drop leading /
|
// Drop leading /
|
||||||
let object_id = &request.uri().path()[1..];
|
let object_id = &request.uri().path()[1..];
|
||||||
|
|
||||||
let object_url = base_url
|
|
||||||
.join("/api/v1/client/object/")
|
|
||||||
.unwrap()
|
|
||||||
.join(object_id)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let header = generate_authorization_header();
|
let header = generate_authorization_header();
|
||||||
let client: reqwest::blocking::Client = reqwest::blocking::Client::new();
|
let client: reqwest::blocking::Client = reqwest::blocking::Client::new();
|
||||||
let response = client
|
let response = make_request(&client, &["/api/v1/client/object/", object_id], &[], |f| {
|
||||||
.get(object_url.to_string())
|
f.header("Authorization", header)
|
||||||
.header("Authorization", header)
|
})
|
||||||
.send();
|
.unwrap()
|
||||||
|
.send();
|
||||||
if response.is_err() {
|
if response.is_err() {
|
||||||
warn!(
|
warn!(
|
||||||
"failed to fetch object with error: {}",
|
"failed to fetch object with error: {}",
|
||||||
|
|||||||
@ -15,6 +15,8 @@ use crate::{
|
|||||||
AppState, AppStatus, User, DB,
|
AppState, AppStatus, User, DB,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::requests::make_request;
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct InitiateRequestBody {
|
struct InitiateRequestBody {
|
||||||
@ -67,16 +69,15 @@ pub fn generate_authorization_header() -> String {
|
|||||||
pub fn fetch_user() -> Result<User, RemoteAccessError> {
|
pub fn fetch_user() -> Result<User, RemoteAccessError> {
|
||||||
let base_url = DB.fetch_base_url();
|
let base_url = DB.fetch_base_url();
|
||||||
|
|
||||||
let endpoint = base_url.join("/api/v1/client/user")?;
|
|
||||||
let header = generate_authorization_header();
|
let header = generate_authorization_header();
|
||||||
|
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
let response = client
|
let response = make_request(&client, &["/api/v1/client/user"], &[], |f| {
|
||||||
.get(endpoint.to_string())
|
f.header("Authorization", header)
|
||||||
.header("Authorization", header)
|
})?
|
||||||
.send()?;
|
.send()?;
|
||||||
if response.status() != 200 {
|
if response.status() != 200 {
|
||||||
let err: DropServerError = response.json().unwrap();
|
let err: DropServerError = response.json()?;
|
||||||
warn!("{:?}", err);
|
warn!("{:?}", err);
|
||||||
|
|
||||||
if err.status_message == "Nonce expired" {
|
if err.status_message == "Nonce expired" {
|
||||||
|
|||||||
@ -4,17 +4,17 @@ use crate::{database::db::DatabaseImpls, error::remote_access_error::RemoteAcces
|
|||||||
|
|
||||||
pub fn make_request<T: AsRef<str>, F: FnOnce(RequestBuilder) -> RequestBuilder>(
|
pub fn make_request<T: AsRef<str>, F: FnOnce(RequestBuilder) -> RequestBuilder>(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
endpoints: &[T],
|
path_components: &[T],
|
||||||
params: &[(T, T)],
|
query: &[(T, T)],
|
||||||
f: F,
|
f: F,
|
||||||
) -> Result<RequestBuilder, RemoteAccessError> {
|
) -> Result<RequestBuilder, RemoteAccessError> {
|
||||||
let mut base_url = DB.fetch_base_url();
|
let mut base_url = DB.fetch_base_url();
|
||||||
for endpoint in endpoints {
|
for endpoint in path_components {
|
||||||
base_url = base_url.join(endpoint.as_ref())?;
|
base_url = base_url.join(endpoint.as_ref())?;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut queries = base_url.query_pairs_mut();
|
let mut queries = base_url.query_pairs_mut();
|
||||||
for (param, val) in params {
|
for (param, val) in query {
|
||||||
queries.append_pair(param.as_ref(), val.as_ref());
|
queries.append_pair(param.as_ref(), val.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user