feat(cache): Added forceOffline in settings and caching games & library
This commit is contained in:
@@ -47,6 +47,7 @@ async function calculateGames(): Promise<Game[]> {
|
||||
return await invoke("fetch_library");
|
||||
}
|
||||
catch(e) {
|
||||
console.log(e)
|
||||
libraryDownloadError = true;
|
||||
return new Array();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="border-b border-zinc-600 py-2 px-1">
|
||||
<div
|
||||
class="-ml-4 -mt-2 flex flex-wrap items-center justify-between sm:flex-nowrap"
|
||||
>
|
||||
<div class="-ml-4 -mt-2 flex flex-wrap items-center justify-between sm:flex-nowrap">
|
||||
<div class="ml-4 mt-2">
|
||||
<h3 class="text-base font-display font-semibold text-zinc-100">
|
||||
Install directories
|
||||
@@ -15,27 +13,17 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="ml-4 mt-2 shrink-0">
|
||||
<button
|
||||
@click="() => (open = true)"
|
||||
type="button"
|
||||
class="relative inline-flex items-center rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
|
||||
>
|
||||
<button @click="() => (open = true)" type="button"
|
||||
class="relative inline-flex items-center rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600">
|
||||
Add new directory
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul role="list" class="divide-y divide-gray-800">
|
||||
<li
|
||||
v-for="(dir, dirIdx) in dirs"
|
||||
:key="dir"
|
||||
class="flex justify-between gap-x-6 py-5"
|
||||
>
|
||||
<li v-for="(dir, dirIdx) in dirs" :key="dir" class="flex justify-between gap-x-6 py-5">
|
||||
<div class="flex min-w-0 gap-x-4">
|
||||
<FolderIcon
|
||||
class="h-6 w-6 text-blue-600 flex-none rounded-full"
|
||||
alt=""
|
||||
/>
|
||||
<FolderIcon class="h-6 w-6 text-blue-600 flex-none rounded-full" alt="" />
|
||||
<div class="min-w-0 flex-auto">
|
||||
<p class="text-sm/6 text-zinc-100">
|
||||
{{ dir }}
|
||||
@@ -43,16 +31,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex shrink-0 items-center gap-x-6">
|
||||
<button
|
||||
@click="() => deleteDirectory(dirIdx)"
|
||||
:disabled="dirs.length <= 1"
|
||||
:class="[
|
||||
dirs.length <= 1
|
||||
? 'text-zinc-700'
|
||||
: 'text-zinc-400 hover:text-zinc-100',
|
||||
'-m-2.5 block p-2.5',
|
||||
]"
|
||||
>
|
||||
<button @click="() => deleteDirectory(dirIdx)" :disabled="dirs.length <= 1" :class="[
|
||||
dirs.length <= 1
|
||||
? 'text-zinc-700'
|
||||
: 'text-zinc-400 hover:text-zinc-100',
|
||||
'-m-2.5 block p-2.5',
|
||||
]">
|
||||
<span class="sr-only">Open options</span>
|
||||
<TrashIcon class="size-5" aria-hidden="true" />
|
||||
</button>
|
||||
@@ -72,37 +56,44 @@
|
||||
Maximum Download Threads
|
||||
</label>
|
||||
<div class="mt-2">
|
||||
<input
|
||||
type="number"
|
||||
name="threads"
|
||||
id="threads"
|
||||
min="1"
|
||||
max="32"
|
||||
v-model="downloadThreads"
|
||||
@keypress="validateNumberInput"
|
||||
@paste="validatePaste"
|
||||
class="block w-full rounded-md border-0 py-1.5 text-zinc-100 shadow-sm ring-1 ring-inset ring-zinc-700 bg-zinc-800 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
|
||||
/>
|
||||
<input type="number" name="threads" id="threads" min="1" max="32" v-model="downloadThreads"
|
||||
@keypress="validateNumberInput" @paste="validatePaste"
|
||||
class="block w-full rounded-md border-0 py-1.5 text-zinc-100 shadow-sm ring-1 ring-inset ring-zinc-700 bg-zinc-800 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6" />
|
||||
</div>
|
||||
<p class="mt-2 text-sm text-zinc-400">
|
||||
The maximum number of concurrent download threads. Higher values may
|
||||
download faster but use more system resources. Default is 4.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-10 space-y-8">
|
||||
<div class="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<h3 class="text-sm font-medium leading-6 text-zinc-100">Force Offline</h3>
|
||||
<p class="mt-1 text-sm leading-6 text-zinc-400">
|
||||
Drop will not make any external connections
|
||||
</p>
|
||||
</div>
|
||||
<Switch v-model="forceOffline" :class="[
|
||||
forceOffline ? 'bg-blue-600' : 'bg-zinc-700',
|
||||
'relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out'
|
||||
]">
|
||||
<span :class="[
|
||||
forceOffline ? 'translate-x-5' : 'translate-x-0',
|
||||
'pointer-events-none relative inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out'
|
||||
]" />
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-6">
|
||||
<button
|
||||
type="button"
|
||||
@click="saveDownloadThreads"
|
||||
:disabled="saveState.loading"
|
||||
:class="[
|
||||
'inline-flex items-center rounded-md px-3 py-2 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 transition-colors duration-300',
|
||||
saveState.success
|
||||
? 'bg-green-600 hover:bg-green-500 focus-visible:outline-green-600'
|
||||
: 'bg-blue-600 hover:bg-blue-500 focus-visible:outline-blue-600',
|
||||
'disabled:bg-blue-600/50 disabled:cursor-not-allowed'
|
||||
]"
|
||||
>
|
||||
<button type="button" @click="saveSettings" :disabled="saveState.loading" :class="[
|
||||
'inline-flex items-center rounded-md px-3 py-2 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 transition-colors duration-300',
|
||||
saveState.success
|
||||
? 'bg-green-600 hover:bg-green-500 focus-visible:outline-green-600'
|
||||
: 'bg-blue-600 hover:bg-blue-500 focus-visible:outline-blue-600',
|
||||
'disabled:bg-blue-600/50 disabled:cursor-not-allowed'
|
||||
]">
|
||||
{{ saveState.success ? 'Saved' : 'Save Changes' }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -110,49 +101,27 @@
|
||||
</div>
|
||||
<TransitionRoot as="template" :show="open">
|
||||
<Dialog class="relative z-50" @close="open = false">
|
||||
<TransitionChild
|
||||
as="template"
|
||||
enter="ease-out duration-300"
|
||||
enter-from="opacity-0"
|
||||
enter-to="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leave-from="opacity-100"
|
||||
leave-to="opacity-0"
|
||||
>
|
||||
<div
|
||||
class="fixed inset-0 bg-zinc-950 bg-opacity-75 transition-opacity"
|
||||
/>
|
||||
<TransitionChild as="template" enter="ease-out duration-300" enter-from="opacity-0" enter-to="opacity-100"
|
||||
leave="ease-in duration-200" leave-from="opacity-100" leave-to="opacity-0">
|
||||
<div class="fixed inset-0 bg-zinc-950 bg-opacity-75 transition-opacity" />
|
||||
</TransitionChild>
|
||||
|
||||
<div class="fixed inset-0 z-10 w-screen overflow-y-auto">
|
||||
<div
|
||||
class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0"
|
||||
>
|
||||
<TransitionChild
|
||||
as="template"
|
||||
enter="ease-out duration-300"
|
||||
<div class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
|
||||
<TransitionChild as="template" enter="ease-out duration-300"
|
||||
enter-from="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
enter-to="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave="ease-in duration-200"
|
||||
enter-to="opacity-100 translate-y-0 sm:scale-100" leave="ease-in duration-200"
|
||||
leave-from="opacity-100 translate-y-0 sm:scale-100"
|
||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
leave-to="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95">
|
||||
<DialogPanel
|
||||
class="relative transform overflow-hidden rounded-lg bg-zinc-900 px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6"
|
||||
>
|
||||
class="relative transform overflow-hidden rounded-lg bg-zinc-900 px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div class="mt-3 w-full sm:ml-4 sm:mt-0">
|
||||
<div>
|
||||
<label
|
||||
for="dir"
|
||||
class="block text-sm/6 font-medium text-zinc-100"
|
||||
>Select game directory</label
|
||||
>
|
||||
<label for="dir" class="block text-sm/6 font-medium text-zinc-100">Select game directory</label>
|
||||
<div class="mt-2">
|
||||
<button
|
||||
@click="() => selectDirectory()"
|
||||
class="block text-left w-full rounded-md border-0 px-3 py-1.5 text-zinc-100 shadow-sm ring-1 ring-inset ring-zinc-700 bg-zinc-800 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm/6"
|
||||
>
|
||||
<button @click="() => selectDirectory()"
|
||||
class="block text-left w-full rounded-md border-0 px-3 py-1.5 text-zinc-100 shadow-sm ring-1 ring-inset ring-zinc-700 bg-zinc-800 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm/6">
|
||||
{{
|
||||
currentDirectory ?? "Click to select a directory..."
|
||||
}}
|
||||
@@ -165,36 +134,25 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<LoadingButton
|
||||
:disabled="currentDirectory == undefined"
|
||||
type="button"
|
||||
:loading="createDirectoryLoading"
|
||||
@click="() => submitDirectory()"
|
||||
:class="[
|
||||
<LoadingButton :disabled="currentDirectory == undefined" type="button" :loading="createDirectoryLoading"
|
||||
@click="() => submitDirectory()" :class="[
|
||||
'inline-flex w-full shadow-sm sm:ml-3 sm:w-auto',
|
||||
currentDirectory === undefined
|
||||
? 'text-zinc-400 bg-blue-600/10 hover:bg-blue-600/10'
|
||||
: 'text-white bg-blue-600 hover:bg-blue-500',
|
||||
]"
|
||||
>
|
||||
]">
|
||||
Add
|
||||
</LoadingButton>
|
||||
<button
|
||||
type="button"
|
||||
<button type="button"
|
||||
class="mt-3 inline-flex w-full justify-center rounded-md bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-100 shadow-sm ring-1 ring-inset ring-zinc-800 hover:bg-zinc-900 sm:mt-0 sm:w-auto"
|
||||
@click="() => cancelDirectory()"
|
||||
ref="cancelButtonRef"
|
||||
>
|
||||
@click="() => cancelDirectory()" ref="cancelButtonRef">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="error" class="mt-3 rounded-md bg-red-600/10 p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<XCircleIcon
|
||||
class="h-5 w-5 text-red-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<XCircleIcon class="h-5 w-5 text-red-600" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-red-600">
|
||||
@@ -220,6 +178,7 @@ import {
|
||||
} from "@headlessui/vue";
|
||||
import { FolderIcon, TrashIcon, XCircleIcon } from "@heroicons/vue/16/solid";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { Switch } from '@headlessui/vue'
|
||||
import { type Settings } from "~/types";
|
||||
|
||||
const open = ref(false);
|
||||
@@ -231,6 +190,7 @@ const dirs = ref<Array<string>>([]);
|
||||
|
||||
const settings = await invoke<Settings>("fetch_settings");
|
||||
const downloadThreads = ref(settings?.maxDownloadThreads ?? 4);
|
||||
const forceOffline = ref(settings?.forceOffline ?? false);
|
||||
|
||||
const saveState = reactive({
|
||||
loading: false,
|
||||
@@ -293,21 +253,21 @@ async function deleteDirectory(index: number) {
|
||||
await updateDirs();
|
||||
}
|
||||
|
||||
async function saveDownloadThreads() {
|
||||
async function saveSettings() {
|
||||
try {
|
||||
saveState.loading = true;
|
||||
await invoke("update_settings", {
|
||||
newSettings: { maxDownloadThreads: downloadThreads.value },
|
||||
newSettings: { maxDownloadThreads: downloadThreads.value, forceOffline: forceOffline.value },
|
||||
});
|
||||
|
||||
|
||||
// Show success state
|
||||
saveState.success = true;
|
||||
|
||||
|
||||
// Reset back to normal state after 2 seconds
|
||||
setTimeout(() => {
|
||||
saveState.success = false;
|
||||
}, 2000);
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to save settings:', error);
|
||||
} finally {
|
||||
@@ -317,8 +277,8 @@ async function saveDownloadThreads() {
|
||||
|
||||
function validateNumberInput(event: KeyboardEvent) {
|
||||
// Allow only numbers and basic control keys
|
||||
if (!/^\d$/.test(event.key) &&
|
||||
!['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
|
||||
if (!/^\d$/.test(event.key) &&
|
||||
!['Backspace', 'Delete', 'Tab', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ pub enum GameDownloadStatus {
|
||||
}
|
||||
|
||||
// Stuff that shouldn't be synced to disk
|
||||
#[derive(Clone, Serialize)]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub enum ApplicationTransientStatus {
|
||||
Downloading { version_name: String },
|
||||
Uninstalling {},
|
||||
@@ -149,7 +149,7 @@ impl DatabaseImpls for DatabaseInterface {
|
||||
let db_path = data_root_dir.join("drop.db");
|
||||
let games_base_dir = data_root_dir.join("games");
|
||||
let logs_root_dir = data_root_dir.join("logs");
|
||||
let cache_dir = data_root_dir.join("cache/");
|
||||
let cache_dir = data_root_dir.join("cache");
|
||||
|
||||
debug!("creating data directory at {:?}", data_root_dir);
|
||||
create_dir_all(data_root_dir.clone()).unwrap();
|
||||
|
||||
@@ -48,7 +48,7 @@ pub enum DownloadManagerSignal {
|
||||
Uninstall(DownloadableMetadata),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum DownloadManagerStatus {
|
||||
Downloading,
|
||||
Paused,
|
||||
|
||||
@@ -255,7 +255,7 @@ impl DownloadManagerBuilder {
|
||||
}
|
||||
Err(e) => {
|
||||
error!("download {:?} has error {}", download_agent.metadata(), &e);
|
||||
download_agent.on_error(&app_handle, e.clone());
|
||||
download_agent.on_error(&app_handle, &e);
|
||||
sender.send(DownloadManagerSignal::Error(e)).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -287,7 +287,7 @@ impl DownloadManagerBuilder {
|
||||
fn manage_error_signal(&mut self, error: ApplicationDownloadError) {
|
||||
debug!("got signal Error");
|
||||
if let Some(current_agent) = self.current_download_agent.clone() {
|
||||
current_agent.on_error(&self.app_handle, error.clone());
|
||||
current_agent.on_error(&self.app_handle, &error);
|
||||
|
||||
self.stop_and_wait_current_download();
|
||||
self.remove_and_cleanup_front_download(¤t_agent.metadata());
|
||||
|
||||
@@ -16,7 +16,7 @@ pub trait Downloadable: Send + Sync {
|
||||
fn status(&self) -> DownloadStatus;
|
||||
fn metadata(&self) -> DownloadableMetadata;
|
||||
fn on_initialised(&self, app_handle: &AppHandle);
|
||||
fn on_error(&self, app_handle: &AppHandle, error: ApplicationDownloadError);
|
||||
fn on_error(&self, app_handle: &AppHandle, error: &ApplicationDownloadError);
|
||||
fn on_complete(&self, app_handle: &AppHandle);
|
||||
fn on_incomplete(&self, app_handle: &AppHandle);
|
||||
fn on_cancelled(&self, app_handle: &AppHandle);
|
||||
|
||||
@@ -8,7 +8,7 @@ use serde_with::SerializeDisplay;
|
||||
use super::{remote_access_error::RemoteAccessError, setup_error::SetupError};
|
||||
|
||||
// TODO: Rename / separate from downloads
|
||||
#[derive(Debug, Clone, SerializeDisplay)]
|
||||
#[derive(Debug, SerializeDisplay)]
|
||||
pub enum ApplicationDownloadError {
|
||||
Communication(RemoteAccessError),
|
||||
Checksum,
|
||||
|
||||
@@ -10,7 +10,7 @@ use url::ParseError;
|
||||
|
||||
use super::drop_server_error::DropServerError;
|
||||
|
||||
#[derive(Debug, Clone, SerializeDisplay)]
|
||||
#[derive(Debug, SerializeDisplay)]
|
||||
pub enum RemoteAccessError {
|
||||
FetchError(Arc<reqwest::Error>),
|
||||
ParsingError(ParseError),
|
||||
@@ -21,6 +21,7 @@ pub enum RemoteAccessError {
|
||||
InvalidRedirect,
|
||||
ManifestDownloadFailed(StatusCode, String),
|
||||
OutOfSync,
|
||||
Cache(cacache::Error),
|
||||
Generic(String),
|
||||
}
|
||||
|
||||
@@ -52,6 +53,7 @@ impl Display for RemoteAccessError {
|
||||
),
|
||||
RemoteAccessError::OutOfSync => write!(f, "server's and client's time are out of sync. Please ensure they are within at least 30 seconds of each other"),
|
||||
RemoteAccessError::Generic(message) => write!(f, "{}", message),
|
||||
RemoteAccessError::Cache(error) => write!(f, "Cache Error: {}", error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::sync::Mutex;
|
||||
use tauri::{AppHandle, Manager};
|
||||
|
||||
use crate::{
|
||||
database::db::GameVersion, error::{library_error::LibraryError, remote_access_error::RemoteAccessError}, games::library::{get_current_meta, uninstall_game_logic}, offline, AppState
|
||||
database::db::GameVersion, error::{library_error::LibraryError, remote_access_error::RemoteAccessError}, games::library::{fetch_game_logic_offline, fetch_library_logic_offline, get_current_meta, uninstall_game_logic}, offline, AppState
|
||||
};
|
||||
|
||||
use super::{
|
||||
@@ -15,17 +15,16 @@ use super::{
|
||||
};
|
||||
|
||||
#[tauri::command]
|
||||
pub fn fetch_library(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
|
||||
let state = app.state::<Mutex<AppState>>();
|
||||
offline!(state, fetch_library_logic, fetch_library_logic, app)
|
||||
pub fn fetch_library(state: tauri::State<'_, Mutex<AppState>>) -> Result<Vec<Game>, RemoteAccessError> {
|
||||
offline!(state, fetch_library_logic, fetch_library_logic_offline, state)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn fetch_game(
|
||||
game_id: String,
|
||||
app: tauri::AppHandle,
|
||||
state: tauri::State<'_, Mutex<AppState>>
|
||||
) -> Result<FetchGameStruct, RemoteAccessError> {
|
||||
fetch_game_logic(game_id, app)
|
||||
offline!(state, fetch_game_logic, fetch_game_logic_offline, game_id, state)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@@ -362,7 +362,7 @@ impl Downloadable for GameDownloadAgent {
|
||||
*self.status.lock().unwrap() = DownloadStatus::Queued;
|
||||
}
|
||||
|
||||
fn on_error(&self, app_handle: &tauri::AppHandle, error: ApplicationDownloadError) {
|
||||
fn on_error(&self, app_handle: &tauri::AppHandle, error: &ApplicationDownloadError) {
|
||||
*self.status.lock().unwrap() = DownloadStatus::Error;
|
||||
app_handle
|
||||
.emit("download_error", error.to_string())
|
||||
|
||||
@@ -14,10 +14,11 @@ use crate::download_manager::downloadable_metadata::DownloadableMetadata;
|
||||
use crate::error::remote_access_error::RemoteAccessError;
|
||||
use crate::games::state::{GameStatusManager, GameStatusWithTransient};
|
||||
use crate::remote::auth::generate_authorization_header;
|
||||
use crate::remote::cache::{cache_object, get_cached_object};
|
||||
use crate::remote::requests::make_request;
|
||||
use crate::AppState;
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct FetchGameStruct {
|
||||
game: Game,
|
||||
status: GameStatusWithTransient,
|
||||
@@ -66,10 +67,11 @@ pub struct StatsUpdateEvent {
|
||||
pub time: usize,
|
||||
}
|
||||
|
||||
pub fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
|
||||
pub fn fetch_library_logic(state: tauri::State<'_, Mutex<AppState>>) -> Result<Vec<Game>, RemoteAccessError> {
|
||||
let header = generate_authorization_header();
|
||||
|
||||
let client = reqwest::blocking::Client::new();
|
||||
println!("Making library request");
|
||||
let response = make_request(&client, &["/api/v1/client/user/library"], &[], |f| {
|
||||
f.header("Authorization", header)
|
||||
})?
|
||||
@@ -80,10 +82,10 @@ pub fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessErro
|
||||
warn!("{:?}", err);
|
||||
return Err(RemoteAccessError::InvalidResponse(err));
|
||||
}
|
||||
println!("Getting Games");
|
||||
|
||||
let games: Vec<Game> = response.json()?;
|
||||
|
||||
let state = app.state::<Mutex<AppState>>();
|
||||
let mut handle = state.lock().unwrap();
|
||||
|
||||
let mut db_handle = borrow_db_mut_checked();
|
||||
@@ -97,17 +99,30 @@ pub fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessErro
|
||||
.insert(game.id.clone(), GameDownloadStatus::Remote {});
|
||||
}
|
||||
}
|
||||
|
||||
drop(handle);
|
||||
drop(db_handle);
|
||||
println!("Caching");
|
||||
cache_object("library", &games)?;
|
||||
|
||||
println!("Finished caching");
|
||||
|
||||
Ok(games)
|
||||
}
|
||||
pub fn fetch_library_logic_offline(_state: tauri::State<'_, Mutex<AppState>>) -> Result<Vec<Game>, RemoteAccessError> {
|
||||
let mut games: Vec<Game> = get_cached_object("library")?;
|
||||
|
||||
let db_handle = borrow_db_checked();
|
||||
|
||||
games.retain(|game| {
|
||||
db_handle.applications.installed_game_version.contains_key(&game.id)
|
||||
});
|
||||
|
||||
Ok(games)
|
||||
}
|
||||
pub fn fetch_game_logic(
|
||||
id: String,
|
||||
app: tauri::AppHandle,
|
||||
state: tauri::State<'_, Mutex<AppState>>
|
||||
) -> Result<FetchGameStruct, RemoteAccessError> {
|
||||
let state = app.state::<Mutex<AppState>>();
|
||||
let mut state_handle = state.lock().unwrap();
|
||||
|
||||
let game = state_handle.games.get(&id);
|
||||
@@ -155,9 +170,18 @@ pub fn fetch_game_logic(
|
||||
status,
|
||||
};
|
||||
|
||||
cache_object(id, &data)?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn fetch_game_logic_offline(
|
||||
id: String,
|
||||
_state: tauri::State<'_, Mutex<AppState>>
|
||||
) -> Result<FetchGameStruct, RemoteAccessError> {
|
||||
get_cached_object(id)
|
||||
}
|
||||
|
||||
pub fn fetch_game_verion_options_logic(
|
||||
game_id: String,
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
use cacache::Integrity;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
use crate::{database::db::borrow_db_checked, error::remote_access_error::RemoteAccessError};
|
||||
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! offline {
|
||||
($var:expr, $func1:expr, $func2:expr, $( $arg:expr ),* ) => {
|
||||
|
||||
if crate::borrow_db_checked().settings.force_offline || $var.lock().unwrap().status == crate::AppStatus::Offline {
|
||||
$func1( $( $arg ), *)
|
||||
} else {
|
||||
$func2( $( $arg ), *)
|
||||
} else {
|
||||
$func1( $( $arg ), *)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cache_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(key: K, data: &D) -> Result<Integrity, RemoteAccessError> {
|
||||
let bytes = bincode::serialize(data).unwrap();
|
||||
cacache::write_sync(&borrow_db_checked().cache_dir, key, bytes).map_err(|e| RemoteAccessError::Cache(e))
|
||||
}
|
||||
pub fn get_cached_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(key: K) -> Result<D,RemoteAccessError> {
|
||||
let bytes = cacache::read_sync(&borrow_db_checked().cache_dir, key).map_err(|e| RemoteAccessError::Cache(e))?;
|
||||
let data = bincode::deserialize::<D>(&bytes).unwrap();
|
||||
Ok(data)
|
||||
}
|
||||
@@ -77,4 +77,5 @@ export type DownloadableMetadata = {
|
||||
export type Settings = {
|
||||
autostart: boolean,
|
||||
maxDownloadThreads: number,
|
||||
forceOffline: boolean
|
||||
}
|
||||
Reference in New Issue
Block a user