mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-09 20:12:14 +10:00
Process manager fixes (#71)
* fix: launching on linux * feat: #70 * feat: add dummy store page * feat: add store redir and refresh button to library * feat: cache first object fetching * feat: Remove let_chains feature and update to Rust 2024 Signed-off-by: quexeky <git@quexeky.dev> * feat: Check for if process was manually stopped Signed-off-by: quexeky <git@quexeky.dev> * fix: use bitcode instead of serde * chore: remove logs * fix: clippy * fix: clippy 2 * fix: swap to stop icon --------- Signed-off-by: quexeky <git@quexeky.dev> Co-authored-by: quexeky <git@quexeky.dev>
This commit is contained in:
@ -61,6 +61,7 @@ import {
|
||||
ChevronDownIcon,
|
||||
PlayIcon,
|
||||
QueueListIcon,
|
||||
StopIcon,
|
||||
WrenchIcon,
|
||||
} from "@heroicons/vue/20/solid";
|
||||
|
||||
@ -128,7 +129,7 @@ const buttonIcons: { [key in GameStatusEnum]: Component } = {
|
||||
[GameStatusEnum.Installed]: PlayIcon,
|
||||
[GameStatusEnum.Updating]: ArrowDownTrayIcon,
|
||||
[GameStatusEnum.Uninstalling]: TrashIcon,
|
||||
[GameStatusEnum.Running]: PlayIcon,
|
||||
[GameStatusEnum.Running]: StopIcon,
|
||||
[GameStatusEnum.PartiallyInstalled]: ArrowDownTrayIcon
|
||||
};
|
||||
|
||||
|
||||
@ -1,12 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="mb-3 inline-flex gap-x-2">
|
||||
<div
|
||||
class="relative mb-3 transition-transform duration-300 hover:scale-105 active:scale-95"
|
||||
class="relative transition-transform duration-300 hover:scale-105 active:scale-95"
|
||||
>
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"
|
||||
>
|
||||
<MagnifyingGlassIcon class="h-5 w-5 text-zinc-400" aria-hidden="true" />
|
||||
<MagnifyingGlassIcon
|
||||
class="h-5 w-5 text-zinc-400"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
@ -15,6 +19,13 @@
|
||||
placeholder="Search library..."
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
@click="() => calculateGames(true)"
|
||||
class="p-1 flex items-center justify-center transition-transform duration-300 size-10 hover:scale-110 active:scale-90 rounded-lg bg-zinc-800/50 text-zinc-100"
|
||||
>
|
||||
<ArrowPathIcon class="size-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<TransitionGroup name="list" tag="ul" class="flex flex-col gap-y-1.5">
|
||||
<NuxtLink
|
||||
@ -60,7 +71,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { MagnifyingGlassIcon } from "@heroicons/vue/20/solid";
|
||||
import { ArrowPathIcon, MagnifyingGlassIcon } from "@heroicons/vue/20/solid";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { GameStatusEnum, type Game, type GameStatus } from "~/types";
|
||||
import { TransitionGroup } from "vue";
|
||||
@ -76,7 +87,7 @@ const gameStatusTextStyle: { [key in GameStatusEnum]: string } = {
|
||||
[GameStatusEnum.Updating]: "text-blue-500",
|
||||
[GameStatusEnum.Uninstalling]: "text-zinc-100",
|
||||
[GameStatusEnum.SetupRequired]: "text-yellow-500",
|
||||
[GameStatusEnum.PartiallyInstalled]: "text-gray-600"
|
||||
[GameStatusEnum.PartiallyInstalled]: "text-gray-600",
|
||||
};
|
||||
const gameStatusText: { [key in GameStatusEnum]: string } = {
|
||||
[GameStatusEnum.Remote]: "Not installed",
|
||||
@ -87,7 +98,7 @@ const gameStatusText: { [key in GameStatusEnum]: string } = {
|
||||
[GameStatusEnum.Uninstalling]: "Uninstalling...",
|
||||
[GameStatusEnum.SetupRequired]: "Setup required",
|
||||
[GameStatusEnum.Running]: "Running",
|
||||
[GameStatusEnum.PartiallyInstalled]: "Partially installed"
|
||||
[GameStatusEnum.PartiallyInstalled]: "Partially installed",
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
@ -101,16 +112,20 @@ const icons: { [key: string]: string } = {};
|
||||
|
||||
const rawGames: Ref<Game[], Game[]> = ref([]);
|
||||
|
||||
async function calculateGames() {
|
||||
rawGames.value = await invoke("fetch_library");
|
||||
for (const game of rawGames.value) {
|
||||
async function calculateGames(clearAll = false) {
|
||||
if (clearAll) rawGames.value = [];
|
||||
// If we update immediately, the navigation gets re-rendered before we
|
||||
// add all the necessary state, and it freaks tf out
|
||||
const newGames = await invoke<typeof rawGames.value>("fetch_library");
|
||||
for (const game of newGames) {
|
||||
if (games[game.id]) continue;
|
||||
games[game.id] = await useGame(game.id);
|
||||
}
|
||||
for (const game of rawGames.value) {
|
||||
for (const game of newGames) {
|
||||
if (icons[game.id]) continue;
|
||||
icons[game.id] = await useObject(game.mIconObjectId);
|
||||
}
|
||||
rawGames.value = newGames;
|
||||
}
|
||||
|
||||
await calculateGames();
|
||||
|
||||
@ -14,7 +14,6 @@ export type SerializedGameStatus = [
|
||||
];
|
||||
|
||||
export const parseStatus = (status: SerializedGameStatus): GameStatus => {
|
||||
console.log(status);
|
||||
if (status[0]) {
|
||||
return {
|
||||
type: status[0].type,
|
||||
@ -48,7 +47,6 @@ export const useGame = async (gameId: string) => {
|
||||
status: SerializedGameStatus;
|
||||
version?: GameVersion;
|
||||
} = event.payload as any;
|
||||
console.log(payload.status);
|
||||
gameStatusRegistry[gameId].value = parseStatus(payload.status);
|
||||
|
||||
/**
|
||||
|
||||
@ -18,7 +18,7 @@ export function setupHooks() {
|
||||
});
|
||||
|
||||
listen("auth/finished", async (event) => {
|
||||
router.push("/store");
|
||||
router.push("/library");
|
||||
state.value = JSON.parse(await invoke("fetch_state"));
|
||||
});
|
||||
|
||||
@ -30,12 +30,31 @@ export function setupHooks() {
|
||||
description: `Drop encountered an error while downloading your game: "${(
|
||||
event.payload as unknown as string
|
||||
).toString()}"`,
|
||||
buttonText: "Close"
|
||||
buttonText: "Close",
|
||||
},
|
||||
(e, c) => c()
|
||||
);
|
||||
});
|
||||
|
||||
// This is for errors that (we think) aren't our fault
|
||||
listen("launch_external_error", (event) => {
|
||||
createModal(
|
||||
ModalType.Confirmation,
|
||||
{
|
||||
title: "Did something go wrong?",
|
||||
description:
|
||||
"Drop detected that something might've gone wrong with launching your game. Do you want to open the log directory?",
|
||||
buttonText: "Open",
|
||||
},
|
||||
async (e, c) => {
|
||||
if (e == "confirm") {
|
||||
await invoke("open_process_logs", { gameId: event.payload });
|
||||
}
|
||||
c();
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
document.addEventListener("contextmenu", (event) => {
|
||||
@ -63,6 +82,6 @@ export function initialNavigation(state: Ref<AppState>) {
|
||||
router.push("/error/serverunavailable");
|
||||
break;
|
||||
default:
|
||||
router.push("/store");
|
||||
router.push("/library");
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
"@tauri-apps/api": ">=2.0.0",
|
||||
"@tauri-apps/plugin-deep-link": "~2",
|
||||
"@tauri-apps/plugin-dialog": "^2.0.1",
|
||||
"@tauri-apps/plugin-opener": "^2.4.0",
|
||||
"@tauri-apps/plugin-os": "~2",
|
||||
"@tauri-apps/plugin-shell": "^2.2.1",
|
||||
"koa": "^2.16.1",
|
||||
|
||||
@ -106,8 +106,6 @@ const systemData = await invoke<{
|
||||
dataDir: string;
|
||||
}>("fetch_system_data");
|
||||
|
||||
console.log(systemData);
|
||||
|
||||
clientId.value = systemData.clientId;
|
||||
baseUrl.value = systemData.baseUrl;
|
||||
dataDir.value = systemData.dataDir;
|
||||
|
||||
@ -1,3 +1,37 @@
|
||||
<template>
|
||||
<div class="grow w-full h-full flex items-center justify-center">
|
||||
<div class="flex flex-col items-center">
|
||||
<BuildingStorefrontIcon
|
||||
class="h-12 w-12 text-blue-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div class="mt-3 text-center sm:mt-5">
|
||||
<h1 class="text-3xl font-semibold font-display leading-6 text-zinc-100">
|
||||
Store not supported in client
|
||||
</h1>
|
||||
<div class="mt-4">
|
||||
<p class="text-sm text-zinc-400 max-w-lg">
|
||||
Currently, Drop requires you to view the store in your browser.
|
||||
Please click the button below to open it in your default browser.
|
||||
</p>
|
||||
<NuxtLink
|
||||
:href="storeUrl"
|
||||
target="_blank"
|
||||
class="mt-6 transition text-sm/6 font-semibold text-zinc-400 hover:text-zinc-100 inline-flex gap-x-2 items-center duration-200 hover:scale-105"
|
||||
>
|
||||
Open Store <ArrowTopRightOnSquareIcon class="size-4" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ArrowTopRightOnSquareIcon,
|
||||
BuildingStorefrontIcon,
|
||||
} from "@heroicons/vue/20/solid";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
|
||||
const storeUrl = await invoke<string>("gen_drop_url", { path: "/store" });
|
||||
</script>
|
||||
|
||||
248
src-tauri/Cargo.lock
generated
248
src-tauri/Cargo.lock
generated
@ -68,6 +68,12 @@ version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "ashpd"
|
||||
version = "0.11.0"
|
||||
@ -427,15 +433,6 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "binary-stream"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4ef03ef225ea9a0b680a5926a58cb45d8eb56abf23d8a8b5c5dbc61235e2dac"
|
||||
dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
@ -445,6 +442,30 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcode"
|
||||
version = "0.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf300f4aa6e66f3bdff11f1236a88c622fe47ea814524792240b4d554d9858ee"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitcode_derive",
|
||||
"bytemuck",
|
||||
"glam",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitcode_derive"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42b6b4cb608b8282dc3b53d0f4c9ab404655d562674c682db7e6c0458cc83c23"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@ -538,9 +559,9 @@ checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf"
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "7.0.0"
|
||||
version = "8.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
|
||||
checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@ -549,9 +570,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "4.0.3"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd"
|
||||
checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
@ -946,15 +967,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cssparser"
|
||||
version = "0.27.2"
|
||||
version = "0.29.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a"
|
||||
checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa"
|
||||
dependencies = [
|
||||
"cssparser-macros",
|
||||
"dtoa-short",
|
||||
"itoa 0.4.8",
|
||||
"itoa",
|
||||
"matches",
|
||||
"phf 0.8.0",
|
||||
"phf 0.10.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"smallvec",
|
||||
@ -1250,6 +1271,7 @@ name = "drop-app"
|
||||
version = "0.3.0-rc-7"
|
||||
dependencies = [
|
||||
"atomic-instant-full",
|
||||
"bitcode",
|
||||
"boxcar",
|
||||
"cacache 13.1.0",
|
||||
"chrono",
|
||||
@ -1278,7 +1300,6 @@ dependencies = [
|
||||
"rustix 0.38.44",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde-binary",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"sha1",
|
||||
@ -1290,6 +1311,7 @@ dependencies = [
|
||||
"tauri-plugin-autostart",
|
||||
"tauri-plugin-deep-link",
|
||||
"tauri-plugin-dialog",
|
||||
"tauri-plugin-opener",
|
||||
"tauri-plugin-os",
|
||||
"tauri-plugin-shell",
|
||||
"tauri-plugin-single-instance",
|
||||
@ -1906,6 +1928,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glam"
|
||||
version = "0.30.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50a99dbe56b72736564cfa4b85bf9a33079f16ae8b74983ab06af3b1a3696b11"
|
||||
|
||||
[[package]]
|
||||
name = "glib"
|
||||
version = "0.18.5"
|
||||
@ -2131,16 +2159,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "html5ever"
|
||||
version = "0.26.0"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7"
|
||||
checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c"
|
||||
dependencies = [
|
||||
"log",
|
||||
"mac",
|
||||
"markup5ever",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"match_token",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2151,7 +2177,7 @@ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2162,7 +2188,7 @@ checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2271,7 +2297,7 @@ dependencies = [
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
@ -2293,7 +2319,7 @@ dependencies = [
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
@ -2563,12 +2589,6 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
@ -2684,14 +2704,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kuchikiki"
|
||||
version = "0.8.2"
|
||||
version = "0.8.8-speedreader"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8"
|
||||
checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2"
|
||||
dependencies = [
|
||||
"cssparser",
|
||||
"html5ever",
|
||||
"indexmap 1.9.3",
|
||||
"matches",
|
||||
"indexmap 2.9.0",
|
||||
"selectors",
|
||||
]
|
||||
|
||||
@ -2856,18 +2875,29 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "markup5ever"
|
||||
version = "0.11.0"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016"
|
||||
checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18"
|
||||
dependencies = [
|
||||
"log",
|
||||
"phf 0.10.1",
|
||||
"phf_codegen 0.10.0",
|
||||
"phf 0.11.3",
|
||||
"phf_codegen 0.11.3",
|
||||
"string_cache",
|
||||
"string_cache_codegen",
|
||||
"tendril",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "match_token"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.10"
|
||||
@ -2982,9 +3012,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "muda"
|
||||
version = "0.16.1"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492"
|
||||
checksum = "58b89bf91c19bf036347f1ab85a81c560f08c0667c8601bece664d860a600988"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dpi",
|
||||
@ -3588,9 +3618,7 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
||||
dependencies = [
|
||||
"phf_macros 0.8.0",
|
||||
"phf_shared 0.8.0",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3599,7 +3627,9 @@ version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
|
||||
dependencies = [
|
||||
"phf_macros 0.10.0",
|
||||
"phf_shared 0.10.0",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3624,12 +3654,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "phf_codegen"
|
||||
version = "0.10.0"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd"
|
||||
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
|
||||
dependencies = [
|
||||
"phf_generator 0.10.0",
|
||||
"phf_shared 0.10.0",
|
||||
"phf_generator 0.11.3",
|
||||
"phf_shared 0.11.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3664,12 +3694,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "phf_macros"
|
||||
version = "0.8.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c"
|
||||
checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
|
||||
dependencies = [
|
||||
"phf_generator 0.8.0",
|
||||
"phf_shared 0.8.0",
|
||||
"phf_generator 0.10.0",
|
||||
"phf_shared 0.10.0",
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -4558,22 +4588,20 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "selectors"
|
||||
version = "0.22.0"
|
||||
version = "0.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe"
|
||||
checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cssparser",
|
||||
"derive_more",
|
||||
"fxhash",
|
||||
"log",
|
||||
"matches",
|
||||
"phf 0.8.0",
|
||||
"phf_codegen 0.8.0",
|
||||
"precomputed-hash",
|
||||
"servo_arc",
|
||||
"smallvec",
|
||||
"thin-slice",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4594,17 +4622,6 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-binary"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b550db407b83ed53a4f76f888bfd7441b685abc2c086e20fb47781a286940506"
|
||||
dependencies = [
|
||||
"binary-stream",
|
||||
"serde",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-untagged"
|
||||
version = "0.1.7"
|
||||
@ -4654,7 +4671,7 @@ version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
@ -4687,7 +4704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
@ -4729,7 +4746,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap 2.9.0",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
@ -4759,9 +4776,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "servo_arc"
|
||||
version = "0.1.1"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432"
|
||||
checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741"
|
||||
dependencies = [
|
||||
"nodrop",
|
||||
"stable_deref_trait",
|
||||
@ -5162,9 +5179,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tao"
|
||||
version = "0.33.0"
|
||||
version = "0.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82"
|
||||
checksum = "49c380ca75a231b87b6c9dd86948f035012e7171d1a7c40a9c2890489a7ffd8a"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation 0.10.1",
|
||||
@ -5238,17 +5255,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri"
|
||||
version = "2.5.1"
|
||||
version = "2.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7b0bc1aec81bda6bc455ea98fcaed26b3c98c1648c627ad6ff1c704e8bf8cbc"
|
||||
checksum = "124e129c9c0faa6bec792c5948c89e86c90094133b0b9044df0ce5f0a8efaa0d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"dirs 6.0.0",
|
||||
"dunce",
|
||||
"embed_plist",
|
||||
"futures-util",
|
||||
"getrandom 0.2.16",
|
||||
"getrandom 0.3.3",
|
||||
"glob",
|
||||
"gtk",
|
||||
"heck 0.5.0",
|
||||
@ -5290,9 +5306,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-build"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7a0350f0df1db385ca5c02888a83e0e66655c245b7443db8b78a70da7d7f8fc"
|
||||
checksum = "12f025c389d3adb83114bec704da973142e82fc6ec799c7c750c5e21cefaec83"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cargo_toml",
|
||||
@ -5312,9 +5328,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-codegen"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93f035551bf7b11b3f51ad9bc231ebbe5e085565527991c16cf326aa38cdf47"
|
||||
checksum = "f5df493a1075a241065bc865ed5ef8d0fbc1e76c7afdc0bf0eccfaa7d4f0e406"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"brotli",
|
||||
@ -5339,9 +5355,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-macros"
|
||||
version = "2.2.0"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8db4df25e2d9d45de0c4c910da61cd5500190da14ae4830749fee3466dddd112"
|
||||
checksum = "f237fbea5866fa5f2a60a21bea807a2d6e0379db070d89c3a10ac0f2d4649bbc"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
@ -5353,9 +5369,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37a5ebe6a610d1b78a94650896e6f7c9796323f408800cef436e0fa0539de601"
|
||||
checksum = "1d9a0bd00bf1930ad1a604d08b0eb6b2a9c1822686d65d7f4731a7723b8901d3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"glob",
|
||||
@ -5442,6 +5458,28 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-opener"
|
||||
version = "2.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecee219f11cdac713ab32959db5d0cceec4810ba4f4458da992292ecf9660321"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"glob",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation 0.3.1",
|
||||
"open",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.12",
|
||||
"url",
|
||||
"windows",
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-os"
|
||||
version = "2.2.1"
|
||||
@ -5499,9 +5537,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.6.0"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00f004905d549854069e6774533d742b03cacfd6f03deb08940a8677586cbe39"
|
||||
checksum = "9e7bb73d1bceac06c20b3f755b2c8a2cb13b20b50083084a8cf3700daf397ba4"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
@ -5521,9 +5559,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime-wry"
|
||||
version = "2.6.0"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f85d056f4d4b014fe874814034f3416d57114b617a493a4fe552580851a3f3a2"
|
||||
checksum = "902b5aa9035e16f342eb64f8bf06ccdc2808e411a2525ed1d07672fa4e780bad"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http 1.3.1",
|
||||
@ -5548,9 +5586,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tauri-utils"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2900399c239a471bcff7f15c4399eb1a8c4fe511ba2853e07c996d771a5e0a4"
|
||||
checksum = "41743bbbeb96c3a100d234e5a0b60a46d5aa068f266160862c7afdbf828ca02e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"brotli",
|
||||
@ -5619,12 +5657,6 @@ dependencies = [
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thin-slice"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
@ -5694,7 +5726,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa 1.0.15",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
@ -5945,9 +5977,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tray-icon"
|
||||
version = "0.20.1"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f7eee98ec5c90daf179d55c20a49d8c0d043054ce7c26336c09a24d31f14fa0"
|
||||
checksum = "2da75ec677957aa21f6e0b361df0daab972f13a5bee3606de0638fd4ee1c666a"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dirs 6.0.0",
|
||||
@ -6438,9 +6470,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b542b5cfbd9618c46c2784e4d41ba218c336ac70d44c55e47b251033e7d85601"
|
||||
checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4"
|
||||
dependencies = [
|
||||
"webview2-com-macros",
|
||||
"webview2-com-sys",
|
||||
@ -6463,9 +6495,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com-sys"
|
||||
version = "0.37.0"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae2d11c4a686e4409659d7891791254cf9286d3cfe0eef54df1523533d22295"
|
||||
checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c"
|
||||
dependencies = [
|
||||
"thiserror 2.0.12",
|
||||
"windows",
|
||||
@ -6938,9 +6970,9 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
|
||||
[[package]]
|
||||
name = "wry"
|
||||
version = "0.51.2"
|
||||
version = "0.52.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c886a0a9d2a94fd90cfa1d929629b79cfefb1546e2c7430c63a47f0664c0e4e2"
|
||||
checksum = "12a714d9ba7075aae04a6e50229d6109e3d584774b99a6a8c60de1698ca111b9"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"block2 0.6.1",
|
||||
|
||||
@ -3,7 +3,7 @@ name = "drop-app"
|
||||
version = "0.3.0-rc-7"
|
||||
description = "The client application for the open-source, self-hosted game distribution platform Drop"
|
||||
authors = ["Drop OSS"]
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -25,7 +25,6 @@ tauri-build = { version = "2.0.0", features = [] }
|
||||
[dependencies]
|
||||
tauri-plugin-shell = "2.2.1"
|
||||
serde_json = "1"
|
||||
serde-binary = "0.5.0"
|
||||
rayon = "1.10.0"
|
||||
webbrowser = "1.0.2"
|
||||
url = "2.5.2"
|
||||
@ -67,6 +66,8 @@ filetime = "0.2.25"
|
||||
walkdir = "2.5.0"
|
||||
known-folders = "1.2.0"
|
||||
native_model = { version = "0.6.1", features = ["rmp_serde_1_3"] }
|
||||
tauri-plugin-opener = "2.4.0"
|
||||
bitcode = "0.6.6"
|
||||
# tailscale = { path = "./tailscale" }
|
||||
|
||||
[dependencies.dynfmt]
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
"core:window:allow-close",
|
||||
"deep-link:default",
|
||||
"dialog:default",
|
||||
"os:default"
|
||||
"os:default",
|
||||
"opener:default"
|
||||
]
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
Arc, Mutex,
|
||||
mpsc::{Receiver, Sender, channel},
|
||||
},
|
||||
thread::{spawn, JoinHandle},
|
||||
thread::{JoinHandle, spawn},
|
||||
};
|
||||
|
||||
use log::{debug, error, info, warn};
|
||||
@ -295,11 +295,12 @@ impl DownloadManagerBuilder {
|
||||
}
|
||||
fn manage_completed_signal(&mut self, meta: DownloadableMetadata) {
|
||||
debug!("got signal Completed");
|
||||
if let Some(interface) = &self.current_download_agent {
|
||||
if interface.metadata() == meta {
|
||||
if let Some(interface) = &self.current_download_agent
|
||||
&& interface.metadata() == meta
|
||||
{
|
||||
self.remove_and_cleanup_front_download(&meta);
|
||||
}
|
||||
}
|
||||
|
||||
self.push_ui_queue_update();
|
||||
self.sender.send(DownloadManagerSignal::Go).unwrap();
|
||||
}
|
||||
|
||||
@ -148,9 +148,7 @@ impl DownloadManager {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
debug!(
|
||||
"moving download at index {current_index} to index {new_index}"
|
||||
);
|
||||
debug!("moving download at index {current_index} to index {new_index}");
|
||||
|
||||
let mut queue = self.edit();
|
||||
let to_move = queue.remove(current_index).unwrap();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
pub mod commands;
|
||||
pub mod download_manager_frontend;
|
||||
pub mod download_manager_builder;
|
||||
pub mod download_manager_frontend;
|
||||
pub mod downloadable;
|
||||
pub mod util;
|
||||
|
||||
@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use serde_with::SerializeDisplay;
|
||||
|
||||
use super::{remote_access_error::RemoteAccessError};
|
||||
use super::remote_access_error::RemoteAccessError;
|
||||
|
||||
// TODO: Rename / separate from downloads
|
||||
#[derive(Debug, SerializeDisplay)]
|
||||
|
||||
@ -13,6 +13,7 @@ pub enum ProcessError {
|
||||
IOError(Error),
|
||||
FormatError(String), // String errors supremacy
|
||||
InvalidPlatform,
|
||||
OpenerError(tauri_plugin_opener::Error)
|
||||
}
|
||||
|
||||
impl Display for ProcessError {
|
||||
@ -22,11 +23,12 @@ impl Display for ProcessError {
|
||||
ProcessError::NotInstalled => "Game not installed",
|
||||
ProcessError::AlreadyRunning => "Game already running",
|
||||
ProcessError::NotDownloaded => "Game not downloaded",
|
||||
ProcessError::InvalidID => "Invalid Game ID",
|
||||
ProcessError::InvalidVersion => "Invalid Game version",
|
||||
ProcessError::InvalidID => "Invalid game ID",
|
||||
ProcessError::InvalidVersion => "Invalid game version",
|
||||
ProcessError::IOError(error) => &error.to_string(),
|
||||
ProcessError::InvalidPlatform => "This Game cannot be played on the current platform",
|
||||
ProcessError::InvalidPlatform => "This game cannot be played on the current platform",
|
||||
ProcessError::FormatError(e) => &format!("Failed to format template: {e}"),
|
||||
ProcessError::OpenerError(error) => &format!("Failed to open directory: {error}"),
|
||||
};
|
||||
write!(f, "{s}")
|
||||
}
|
||||
|
||||
@ -37,14 +37,13 @@ pub fn fetch_game(
|
||||
game_id: String,
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
) -> Result<FetchGameStruct, RemoteAccessError> {
|
||||
let res = offline!(
|
||||
offline!(
|
||||
state,
|
||||
fetch_game_logic,
|
||||
fetch_game_logic_offline,
|
||||
game_id,
|
||||
state
|
||||
);
|
||||
res
|
||||
)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@ -5,7 +5,9 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
database::{db::borrow_db_checked, models::data::GameDownloadStatus},
|
||||
download_manager::{download_manager_frontend::DownloadManagerSignal, downloadable::Downloadable},
|
||||
download_manager::{
|
||||
download_manager_frontend::DownloadManagerSignal, downloadable::Downloadable,
|
||||
},
|
||||
error::download_manager_error::DownloadManagerError,
|
||||
AppState,
|
||||
};
|
||||
|
||||
@ -19,6 +19,7 @@ use crate::remote::auth::generate_authorization_header;
|
||||
use crate::remote::cache::{cache_object, get_cached_object, get_cached_object_db};
|
||||
use crate::remote::requests::make_request;
|
||||
use crate::AppState;
|
||||
use bitcode::{Encode, Decode};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct FetchGameStruct {
|
||||
@ -27,7 +28,7 @@ pub struct FetchGameStruct {
|
||||
version: Option<GameVersion>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Default, Encode, Decode)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Game {
|
||||
id: String,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#![feature(fn_traits)]
|
||||
#![feature(duration_constructors)]
|
||||
#![deny(clippy::all)]
|
||||
|
||||
mod database;
|
||||
@ -10,6 +11,7 @@ mod error;
|
||||
mod process;
|
||||
mod remote;
|
||||
|
||||
use crate::process::commands::open_process_logs;
|
||||
use crate::{database::db::DatabaseImpls, games::downloads::commands::resume_download};
|
||||
use client::commands::fetch_state;
|
||||
use client::{
|
||||
@ -25,8 +27,8 @@ use database::models::data::GameDownloadStatus;
|
||||
use download_manager::commands::{
|
||||
cancel_game, move_download_in_queue, pause_downloads, resume_downloads,
|
||||
};
|
||||
use download_manager::download_manager_frontend::DownloadManager;
|
||||
use download_manager::download_manager_builder::DownloadManagerBuilder;
|
||||
use download_manager::download_manager_frontend::DownloadManager;
|
||||
use games::collections::commands::{
|
||||
add_game_to_collection, create_collection, delete_collection, delete_game_in_collection,
|
||||
fetch_collection, fetch_collections,
|
||||
@ -69,6 +71,7 @@ use tauri::tray::TrayIconBuilder;
|
||||
use tauri::{AppHandle, Manager, RunEvent, WindowEvent};
|
||||
use tauri_plugin_deep_link::DeepLinkExt;
|
||||
use tauri_plugin_dialog::DialogExt;
|
||||
use bitcode::{Encode, Decode};
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Eq, PartialEq)]
|
||||
pub enum AppStatus {
|
||||
@ -81,7 +84,7 @@ pub enum AppStatus {
|
||||
ServerUnavailable,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[derive(Clone, Serialize, Deserialize, Encode, Decode)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct User {
|
||||
id: String,
|
||||
@ -225,7 +228,8 @@ pub fn custom_panic_handler(e: &PanicHookInfo) -> Option<()> {
|
||||
.as_secs()
|
||||
));
|
||||
let mut file = File::create_new(crash_file).ok()?;
|
||||
file.write_all(format!("Drop crashed with the following panic:\n{e}").as_bytes()).ok()?;
|
||||
file.write_all(format!("Drop crashed with the following panic:\n{e}").as_bytes())
|
||||
.ok()?;
|
||||
drop(file);
|
||||
|
||||
Some(())
|
||||
@ -235,11 +239,11 @@ pub fn custom_panic_handler(e: &PanicHookInfo) -> Option<()> {
|
||||
pub fn run() {
|
||||
panic::set_hook(Box::new(|e| {
|
||||
let _ = custom_panic_handler(e);
|
||||
let dft = panic::take_hook();
|
||||
dft.call((e,));
|
||||
println!("{e}");
|
||||
}));
|
||||
|
||||
let mut builder = tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_os::init())
|
||||
.plugin(tauri_plugin_dialog::init());
|
||||
|
||||
@ -299,6 +303,7 @@ pub fn run() {
|
||||
kill_game,
|
||||
toggle_autostart,
|
||||
get_autostart_enabled,
|
||||
open_process_logs
|
||||
])
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
|
||||
@ -38,3 +38,13 @@ pub fn kill_game(
|
||||
.kill_game(game_id)
|
||||
.map_err(ProcessError::IOError)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn open_process_logs(
|
||||
game_id: String,
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
) -> Result<(), ProcessError> {
|
||||
let state_lock = state.lock().unwrap();
|
||||
let mut process_manager_lock = state_lock.process_manager.lock().unwrap();
|
||||
process_manager_lock.open_process_logs(game_id)
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::OpenOptions,
|
||||
fs::{OpenOptions, create_dir_all},
|
||||
io::{self},
|
||||
path::PathBuf,
|
||||
process::{Command, ExitStatus},
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex},
|
||||
thread::spawn,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use dynfmt::Format;
|
||||
@ -14,11 +15,13 @@ use dynfmt::SimpleCurlyFormat;
|
||||
use log::{debug, info, warn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use shared_child::SharedChild;
|
||||
use tauri::{AppHandle, Manager};
|
||||
use tauri::{AppHandle, Emitter, Manager};
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
|
||||
use crate::{
|
||||
AppState, DB,
|
||||
database::{
|
||||
db::{borrow_db_mut_checked, DATA_ROOT_DIR},
|
||||
db::{DATA_ROOT_DIR, borrow_db_mut_checked},
|
||||
models::data::{
|
||||
ApplicationTransientStatus, DownloadType, DownloadableMetadata, GameDownloadStatus,
|
||||
GameVersion,
|
||||
@ -26,13 +29,18 @@ use crate::{
|
||||
},
|
||||
error::process_error::ProcessError,
|
||||
games::{library::push_game_update, state::GameStatusManager},
|
||||
AppState, DB,
|
||||
};
|
||||
|
||||
pub struct RunningProcess {
|
||||
handle: Arc<SharedChild>,
|
||||
start: SystemTime,
|
||||
manually_killed: bool,
|
||||
}
|
||||
|
||||
pub struct ProcessManager<'a> {
|
||||
current_platform: Platform,
|
||||
log_output_dir: PathBuf,
|
||||
processes: HashMap<String, Arc<SharedChild>>,
|
||||
processes: HashMap<String, RunningProcess>,
|
||||
app_handle: AppHandle,
|
||||
game_launchers: HashMap<(Platform, Platform), &'a (dyn ProcessHandler + Sync + Send + 'static)>,
|
||||
}
|
||||
@ -77,10 +85,11 @@ impl ProcessManager<'_> {
|
||||
}
|
||||
|
||||
pub fn kill_game(&mut self, game_id: String) -> Result<(), io::Error> {
|
||||
match self.processes.get(&game_id) {
|
||||
Some(child) => {
|
||||
child.kill()?;
|
||||
child.wait()?;
|
||||
match self.processes.get_mut(&game_id) {
|
||||
Some(process) => {
|
||||
process.manually_killed = true;
|
||||
process.handle.kill()?;
|
||||
process.handle.wait()?;
|
||||
Ok(())
|
||||
}
|
||||
None => Err(io::Error::new(
|
||||
@ -90,15 +99,26 @@ impl ProcessManager<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_process_logs(&mut self, game_id: String) -> Result<(), ProcessError> {
|
||||
let dir = self.log_output_dir.join(game_id);
|
||||
self.app_handle
|
||||
.opener()
|
||||
.open_path(dir.to_str().unwrap(), None::<&str>)
|
||||
.map_err(ProcessError::OpenerError)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_process_finish(&mut self, game_id: String, result: Result<ExitStatus, std::io::Error>) {
|
||||
if !self.processes.contains_key(&game_id) {
|
||||
warn!("process on_finish was called, but game_id is no longer valid. finished with result: {result:?}");
|
||||
warn!(
|
||||
"process on_finish was called, but game_id is no longer valid. finished with result: {result:?}"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("process for {:?} exited with {:?}", &game_id, result);
|
||||
|
||||
self.processes.remove(&game_id);
|
||||
let process = self.processes.remove(&game_id).unwrap();
|
||||
|
||||
let mut db_handle = borrow_db_mut_checked();
|
||||
let meta = db_handle
|
||||
@ -114,9 +134,9 @@ impl ProcessManager<'_> {
|
||||
version_name,
|
||||
install_dir,
|
||||
}) = current_state
|
||||
&& let Ok(exit_code) = result
|
||||
&& exit_code.success()
|
||||
{
|
||||
if let Ok(exit_code) = result {
|
||||
if exit_code.success() {
|
||||
db_handle.applications.game_statuses.insert(
|
||||
game_id.clone(),
|
||||
GameDownloadStatus::Installed {
|
||||
@ -125,15 +145,21 @@ impl ProcessManager<'_> {
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(db_handle);
|
||||
|
||||
let elapsed = process.start.elapsed().unwrap_or(Duration::ZERO);
|
||||
// If we started and ended really quickly, something might've gone wrong
|
||||
// Or if the status isn't 0
|
||||
// Or if it's an error
|
||||
if !process.manually_killed
|
||||
&& (elapsed.as_secs() <= 2 || result.is_err() || !result.unwrap().success())
|
||||
{
|
||||
warn!("drop detected that the game {game_id} may have failed to launch properly");
|
||||
let _ = self.app_handle.emit("launch_external_error", &game_id);
|
||||
}
|
||||
|
||||
let status = GameStatusManager::fetch_state(&game_id);
|
||||
|
||||
push_game_update(&self.app_handle, &game_id, None, status);
|
||||
|
||||
// TODO better management
|
||||
}
|
||||
|
||||
pub fn valid_platform(&self, platform: &Platform) -> Result<bool, String> {
|
||||
@ -156,7 +182,7 @@ impl ProcessManager<'_> {
|
||||
{
|
||||
Some(GameDownloadStatus::Installed { version_name, .. }) => version_name,
|
||||
Some(GameDownloadStatus::SetupRequired { .. }) => {
|
||||
return Err(ProcessError::SetupRequired)
|
||||
return Err(ProcessError::SetupRequired);
|
||||
}
|
||||
_ => return Err(ProcessError::NotInstalled),
|
||||
};
|
||||
@ -202,18 +228,17 @@ impl ProcessManager<'_> {
|
||||
.get(version_name)
|
||||
.ok_or(ProcessError::InvalidVersion)?;
|
||||
|
||||
// TODO: refactor this path with open_process_logs
|
||||
let game_log_folder = &self.log_output_dir.join(game_id);
|
||||
create_dir_all(game_log_folder).map_err(ProcessError::IOError)?;
|
||||
|
||||
let current_time = chrono::offset::Local::now();
|
||||
let log_file = OpenOptions::new()
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.read(true)
|
||||
.create(true)
|
||||
.open(self.log_output_dir.join(format!(
|
||||
"{}-{}-{}.log",
|
||||
&game_id,
|
||||
&version,
|
||||
current_time.timestamp()
|
||||
)))
|
||||
.open(game_log_folder.join(format!("{}-{}.log", &version, current_time.timestamp())))
|
||||
.map_err(ProcessError::IOError)?;
|
||||
|
||||
let error_file = OpenOptions::new()
|
||||
@ -221,9 +246,8 @@ impl ProcessManager<'_> {
|
||||
.truncate(true)
|
||||
.read(true)
|
||||
.create(true)
|
||||
.open(self.log_output_dir.join(format!(
|
||||
"{}-{}-{}-error.log",
|
||||
&game_id,
|
||||
.open(game_log_folder.join(format!(
|
||||
"{}-{}-error.log",
|
||||
&version,
|
||||
current_time.timestamp()
|
||||
)))
|
||||
@ -282,7 +306,7 @@ impl ProcessManager<'_> {
|
||||
#[cfg(unix)]
|
||||
let mut command: Command = Command::new("sh");
|
||||
#[cfg(unix)]
|
||||
command.arg("-c").arg(launch_string);
|
||||
command.args(vec!["-c", &launch_string]);
|
||||
|
||||
command
|
||||
.stderr(error_file)
|
||||
@ -325,7 +349,14 @@ impl ProcessManager<'_> {
|
||||
drop(app_state_handle);
|
||||
});
|
||||
|
||||
self.processes.insert(meta.id, wait_thread_handle);
|
||||
self.processes.insert(
|
||||
meta.id,
|
||||
RunningProcess {
|
||||
handle: wait_thread_handle,
|
||||
start: SystemTime::now(),
|
||||
manually_killed: false,
|
||||
},
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
use std::{
|
||||
fmt::Display,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
database::{db::borrow_db_checked, models::data::Database},
|
||||
error::remote_access_error::RemoteAccessError,
|
||||
};
|
||||
use bitcode::{Decode, DecodeOwned, Encode};
|
||||
use cacache::Integrity;
|
||||
use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder, Response};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use serde_binary::binary_stream::Endian;
|
||||
use http::{Response, header::CONTENT_TYPE, response::Builder as ResponseBuilder};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! offline {
|
||||
@ -19,31 +23,48 @@ macro_rules! offline {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cache_object<K: AsRef<str>, D: Serialize + DeserializeOwned>(
|
||||
pub fn cache_object<K: AsRef<str>, D: Encode>(
|
||||
key: K,
|
||||
data: &D,
|
||||
) -> Result<Integrity, RemoteAccessError> {
|
||||
let bytes = serde_binary::to_vec(data, Endian::Little).unwrap();
|
||||
let bytes = bitcode::encode(data);
|
||||
cacache::write_sync(&borrow_db_checked().cache_dir, key, bytes)
|
||||
.map_err(RemoteAccessError::Cache)
|
||||
}
|
||||
pub fn get_cached_object<K: AsRef<str>, D: Serialize + DeserializeOwned>(
|
||||
pub fn get_cached_object<K: AsRef<str> + Display, D: Encode + DecodeOwned>(
|
||||
key: K,
|
||||
) -> Result<D, RemoteAccessError> {
|
||||
get_cached_object_db::<K, D>(key, &borrow_db_checked())
|
||||
}
|
||||
pub fn get_cached_object_db<K: AsRef<str>, D: Serialize + DeserializeOwned>(
|
||||
pub fn get_cached_object_db<K: AsRef<str> + Display, D: DecodeOwned>(
|
||||
key: K,
|
||||
db: &Database,
|
||||
) -> Result<D, RemoteAccessError> {
|
||||
let bytes = cacache::read_sync(&db.cache_dir, key).map_err(RemoteAccessError::Cache)?;
|
||||
let data = serde_binary::from_slice::<D>(&bytes, Endian::Little).unwrap();
|
||||
let bytes = cacache::read_sync(&db.cache_dir, &key).map_err(RemoteAccessError::Cache)?;
|
||||
let data = bitcode::decode::<D>(&bytes).map_err(|_| {
|
||||
RemoteAccessError::Cache(cacache::Error::EntryNotFound(
|
||||
db.cache_dir.clone(),
|
||||
key.to_string(),
|
||||
))
|
||||
})?;
|
||||
Ok(data)
|
||||
}
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Encode, Decode)]
|
||||
pub struct ObjectCache {
|
||||
content_type: String,
|
||||
body: Vec<u8>,
|
||||
expiry: u128,
|
||||
}
|
||||
|
||||
impl ObjectCache {
|
||||
pub fn has_expired(&self) -> bool {
|
||||
let duration = Duration::from_millis(self.expiry.try_into().unwrap());
|
||||
SystemTime::UNIX_EPOCH
|
||||
.checked_add(duration)
|
||||
.unwrap()
|
||||
.elapsed()
|
||||
.is_err()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Response<Vec<u8>>> for ObjectCache {
|
||||
@ -57,6 +78,12 @@ impl From<Response<Vec<u8>>> for ObjectCache {
|
||||
.unwrap()
|
||||
.to_owned(),
|
||||
body: value.body().clone(),
|
||||
expiry: SystemTime::now()
|
||||
.checked_add(Duration::from_days(1))
|
||||
.unwrap()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_millis(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,3 +93,9 @@ impl From<ObjectCache> for Response<Vec<u8>> {
|
||||
resp_builder.body(value.body).unwrap()
|
||||
}
|
||||
}
|
||||
impl From<&ObjectCache> for Response<Vec<u8>> {
|
||||
fn from(value: &ObjectCache) -> Self {
|
||||
let resp_builder = ResponseBuilder::new().header(CONTENT_TYPE, value.content_type.clone());
|
||||
resp_builder.body(value.body.clone()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,14 @@ pub fn fetch_object(request: http::Request<Vec<u8>>, responder: UriSchemeRespond
|
||||
// Drop leading /
|
||||
let object_id = &request.uri().path()[1..];
|
||||
|
||||
let cache_result = get_cached_object::<&str, ObjectCache>(object_id);
|
||||
if let Ok(cache_result) = &cache_result
|
||||
&& !cache_result.has_expired()
|
||||
{
|
||||
responder.respond(cache_result.into());
|
||||
return;
|
||||
}
|
||||
|
||||
let header = generate_authorization_header();
|
||||
let client: reqwest::blocking::Client = reqwest::blocking::Client::new();
|
||||
let response = make_request(&client, &["/api/v1/client/object/", object_id], &[], |f| {
|
||||
@ -20,10 +28,8 @@ pub fn fetch_object(request: http::Request<Vec<u8>>, responder: UriSchemeRespond
|
||||
.unwrap()
|
||||
.send();
|
||||
if response.is_err() {
|
||||
let data = get_cached_object::<&str, ObjectCache>(object_id);
|
||||
|
||||
match data {
|
||||
Ok(data) => responder.respond(data.into()),
|
||||
match cache_result {
|
||||
Ok(cache_result) => responder.respond(cache_result.into()),
|
||||
Err(e) => {
|
||||
warn!("{e}")
|
||||
}
|
||||
@ -38,7 +44,9 @@ pub fn fetch_object(request: http::Request<Vec<u8>>, responder: UriSchemeRespond
|
||||
);
|
||||
let data = Vec::from(response.bytes().unwrap());
|
||||
let resp = resp_builder.body(data).unwrap();
|
||||
if cache_result.is_err() || cache_result.unwrap().has_expired() {
|
||||
cache_object::<&str, ObjectCache>(object_id, &resp.clone().into()).unwrap();
|
||||
}
|
||||
|
||||
responder.respond(resp);
|
||||
}
|
||||
|
||||
@ -3,6 +3,6 @@ pub mod auth;
|
||||
pub mod cache;
|
||||
pub mod commands;
|
||||
pub mod fetch_object;
|
||||
pub mod utils;
|
||||
pub mod requests;
|
||||
pub mod server_proto;
|
||||
pub mod utils;
|
||||
|
||||
@ -33,10 +33,7 @@ pub fn handle_server_proto(request: Request<Vec<u8>>, responder: UriSchemeRespon
|
||||
|
||||
let whitelist_prefix = ["/store", "/api", "/_", "/fonts"];
|
||||
|
||||
if whitelist_prefix
|
||||
.iter()
|
||||
.all(|f| !path.starts_with(f))
|
||||
{
|
||||
if whitelist_prefix.iter().all(|f| !path.starts_with(f)) {
|
||||
webbrowser::open(&new_uri.to_string()).unwrap();
|
||||
return;
|
||||
}
|
||||
|
||||
12
yarn.lock
12
yarn.lock
@ -1508,6 +1508,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-2.0.1.tgz#dc49d899fb873b96ee1d46a171384625ba5ad404"
|
||||
integrity sha512-eoQWT+Tq1qSwQpHV+nw1eNYe5B/nm1PoRjQCRiEOS12I1b+X4PUcREfXVX8dPcBT6GrzWGDtaecY0+1p0Rfqlw==
|
||||
|
||||
"@tauri-apps/api@^2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/api/-/api-2.6.0.tgz#efd873bf04b0d72cea81f9397e16218f5deafe0f"
|
||||
integrity sha512-hRNcdercfgpzgFrMXWwNDBN0B7vNzOzRepy6ZAmhxi5mDLVPNrTpo9MGg2tN/F7JRugj4d2aF7E1rtPXAHaetg==
|
||||
|
||||
"@tauri-apps/cli-darwin-arm64@2.0.1":
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.0.1.tgz#5816c0099977f705d1a7249822fa51f5d3c3750a"
|
||||
@ -1588,6 +1593,13 @@
|
||||
dependencies:
|
||||
"@tauri-apps/api" "^2.0.0"
|
||||
|
||||
"@tauri-apps/plugin-opener@^2.4.0":
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-opener/-/plugin-opener-2.4.0.tgz#57eae5998e1c396791af16832a9dde16eca06439"
|
||||
integrity sha512-43VyN8JJtvKWJY72WI/KNZszTpDpzHULFxQs0CJBIYUdCRowQ6Q1feWTDb979N7nldqSuDOaBupZ6wz2nvuWwQ==
|
||||
dependencies:
|
||||
"@tauri-apps/api" "^2.6.0"
|
||||
|
||||
"@tauri-apps/plugin-os@~2":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-os/-/plugin-os-2.2.0.tgz#ef5511269f59c0ccc580a9d09600034cfaa9743b"
|
||||
|
||||
Reference in New Issue
Block a user