Compare commits

..

37 Commits

Author SHA1 Message Date
c78079e4be bump version to 0.3.1-appimage 2025-08-03 12:58:04 +10:00
92e42262c1 Merge branch 'develop' of https://github.com/Beethoven-n/drop-app into Beethoven-n-develop 2025-08-03 12:55:27 +10:00
106c229c8f (build/appimage/drop-app.d/drop-oss-app.desktop) add drop link handling 2025-08-02 21:39:10 -05:00
527476e7c1 (build_appimage.sh) don't use sudo for this u don't need it 2025-08-02 21:39:10 -05:00
81d324a026 (build_appimage.sh) wrong variable. whoops! 2025-08-02 21:39:09 -05:00
3d5de9bec8 (build/appimage/appimagetool) these don't belong here! woops! 2025-08-02 21:39:09 -05:00
380084bb95 (build/appimage/drop-oss-app.d/) 2025-08-02 21:39:09 -05:00
50d76bb76f (build/appimage/appimagetool) 2025-08-02 21:39:09 -05:00
de3be25914 (build_appimage.sh) 2025-08-02 21:39:09 -05:00
95fc7d9605 (.github/workflows/release.yml) add --nobuild flag 2025-08-02 21:39:08 -05:00
f9c45053cc (build/appimage/drop-app.d/AppRun) change program name 2025-08-02 21:39:08 -05:00
683e3ac7f2 (build/appimage/drop-app.d/) rename AppDir
lol woops this caused a typo that cascaded into an appimage that failed
to find the executable
2025-08-02 21:39:08 -05:00
fe586be658 (build_appimage.sh) install libs by UID and GID
installing by $USER caused issues when i did it so i've fixed it
also added $PWD because ./ was lazy
2025-08-02 21:39:08 -05:00
aa034c21a9 (build_appimage.sh) add basic arch detection 2025-08-02 21:39:08 -05:00
50f7955734 (.github/workflows/release.yml) add build_appimage.sh to workflow 2025-08-02 21:39:07 -05:00
73608ab85b (build_appimage.sh) add build script
this should build the appimage without tauri's involvement
2025-08-02 21:39:07 -05:00
1ed29aaa12 (src-tauri/tauri.conf.json) remove appimage target from tauri
tauri was overcomplicating this. let's make the appimage independent of
that
2025-08-02 21:39:07 -05:00
849dc26677 (build/) add build directory for non-tauri builds 2025-08-02 21:39:07 -05:00
7db2e42006 (appimage/build_appimage.sh) 2025-08-02 21:39:07 -05:00
61fa43dd86 (appimage/) add manual appimage
the existing one is broken, and i think it might be tauri's fault.
2025-08-02 21:39:06 -05:00
301152a69f (build_appimage.sh) don't use sudo for this u don't need it 2025-08-02 20:54:08 -05:00
5e945734c7 (build_appimage.sh) wrong variable. whoops! 2025-08-02 20:53:49 -05:00
53211e94fe (build/appimage/appimagetool) these don't belong here! woops! 2025-08-02 20:52:51 -05:00
af49a6751f (build/appimage/drop-oss-app.d/) 2025-08-02 20:27:46 -05:00
9e93ec688c (build/appimage/appimagetool) 2025-08-02 20:27:46 -05:00
a70c2c64e4 (build_appimage.sh) 2025-08-02 20:27:46 -05:00
d63d6efa3e (.github/workflows/release.yml) add --nobuild flag 2025-08-02 20:18:02 -05:00
51555e43ee (build/appimage/drop-app.d/AppRun) change program name 2025-08-02 20:17:13 -05:00
cb7c297443 (build/appimage/drop-app.d/) rename AppDir
lol woops this caused a typo that cascaded into an appimage that failed
to find the executable
2025-08-02 20:16:37 -05:00
4484de0507 (build_appimage.sh) install libs by UID and GID
installing by $USER caused issues when i did it so i've fixed it
also added $PWD because ./ was lazy
2025-08-02 20:15:03 -05:00
4599e5713c (build_appimage.sh) add basic arch detection 2025-08-02 18:05:53 -05:00
263cceb17f (.github/workflows/release.yml) add build_appimage.sh to workflow 2025-08-02 18:05:25 -05:00
0249a3248f (build_appimage.sh) add build script
this should build the appimage without tauri's involvement
2025-08-02 16:45:55 -05:00
bf4b2e0ad6 (src-tauri/tauri.conf.json) remove appimage target from tauri
tauri was overcomplicating this. let's make the appimage independent of
that
2025-08-02 16:45:24 -05:00
7555cc3cdf (build/) add build directory for non-tauri builds 2025-08-02 16:45:24 -05:00
6f30d248eb (appimage/build_appimage.sh) 2025-08-02 14:42:36 -05:00
cc562662f0 (appimage/) add manual appimage
the existing one is broken, and i think it might be tauri's fault.
2025-08-02 14:42:36 -05:00
123 changed files with 9085 additions and 9869 deletions

View File

@ -51,7 +51,7 @@ jobs:
if: matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-22.04-arm' # This must match the platform value defined above. if: matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-22.04-arm' # This must match the platform value defined above.
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf xdg-utils sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
# webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2. # webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2.
@ -69,9 +69,9 @@ jobs:
security set-keychain-settings -t 3600 -u build.keychain security set-keychain-settings -t 3600 -u build.keychain
curl https://droposs.org/drop.crt --output drop.pem curl https://droposs.org/drop.crt --output drop.pem
sudo security authorizationdb write com.apple.trust-settings.user allow sudo security authorizationdb write com.apple.trust-settings.admin allow
security add-trusted-cert -r trustRoot -k build.keychain -p codeSign -u -1 drop.pem sudo security add-trusted-cert -d -r trustRoot -k build.keychain -p codeSign -u -1 drop.pem
sudo security authorizationdb remove com.apple.trust-settings.user sudo security authorizationdb remove com.apple.trust-settings.admin
security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
@ -94,11 +94,15 @@ jobs:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }} APPLE_SIGNING_IDENTITY: ${{ env.CERT_ID }}
NO_STRIP: true
with: with:
tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version. tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version.
releaseName: 'Auto-release v__VERSION__' releaseName: 'Auto-release v__VERSION__'
releaseBody: 'See the assets to download this version and install. This release was created automatically.' releaseBody: 'See the assets to download this version and install. This release was created automatically.'
releaseDraft: false releaseDraft: false
prerelease: true prerelease: true
args: ${{ matrix.args }} args: ${{ matrix.args }}
- name: Bundle Appimage
if: matrix.platform == 'ubuntu-22.04' || matrix.platform == 'ubuntu-22.04-arm'
run:
build_appimage.sh --nobuild

5
.gitignore vendored
View File

@ -26,7 +26,4 @@ dist-ssr
.output .output
src-tauri/flamegraph.svg src-tauri/flamegraph.svg
src-tauri/perf* src-tauri/perf*
/*.AppImage
/squashfs-root

9
.gitmodules vendored
View File

@ -1,6 +1,9 @@
[submodule "drop-base"]
path = drop-base
url = https://github.com/drop-oss/drop-base
[submodule "src-tauri/tailscale/libtailscale"] [submodule "src-tauri/tailscale/libtailscale"]
path = src-tauri/tailscale/libtailscale path = src-tauri/tailscale/libtailscale
url = https://github.com/tailscale/libtailscale.git url = https://github.com/tailscale/libtailscale.git
[submodule "libs/drop-base"] [submodule "src-tauri/umu/umu-launcher"]
path = libs/drop-base path = src-tauri/umu/umu-launcher
url = https://github.com/drop-oss/drop-base.git url = https://github.com/Open-Wine-Components/umu-launcher.git

View File

@ -10,6 +10,8 @@
import "~/composables/downloads.js"; import "~/composables/downloads.js";
import { invoke } from "@tauri-apps/api/core"; import { invoke } from "@tauri-apps/api/core";
import { AppStatus } from "~/types";
import { listen } from "@tauri-apps/api/event";
import { useAppState } from "./composables/app-state.js"; import { useAppState } from "./composables/app-state.js";
import { import {
initialNavigation, initialNavigation,
@ -19,26 +21,19 @@ import {
const router = useRouter(); const router = useRouter();
const state = useAppState(); const state = useAppState();
try {
async function fetchState() { state.value = JSON.parse(await invoke("fetch_state"));
try { } catch (e) {
state.value = JSON.parse(await invoke("fetch_state")); console.error("failed to parse state", e);
if (!state.value)
throw createError({
statusCode: 500,
statusMessage: `App state is: ${state.value}`,
fatal: true,
});
} catch (e) {
console.error("failed to parse state", e);
throw e;
}
} }
await fetchState();
// This is inefficient but apparently we do it lol // This is inefficient but apparently we do it lol
router.beforeEach(async () => { router.beforeEach(async () => {
await fetchState(); try {
state.value = JSON.parse(await invoke("fetch_state"));
} catch (e) {
console.error("failed to parse state", e);
}
}); });
setupHooks(); setupHooks();

View File

Before

Width:  |  Height:  |  Size: 6.5 MiB

After

Width:  |  Height:  |  Size: 6.5 MiB

View File

@ -1,48 +0,0 @@
import fs from "fs";
import process from "process";
import childProcess from "child_process";
import createLogger from "pino";
const OUTPUT = "./.output";
const logger = createLogger({ transport: { target: "pino-pretty" } });
async function spawn(exec, opts) {
const output = childProcess.spawn(exec, { ...opts, shell: true });
output.stdout.on("data", (data) => {
process.stdout.write(data);
});
output.stderr.on("data", (data) => {
process.stderr.write(data);
});
return await new Promise((resolve, reject) => {
output.on("error", (err) => reject(err));
output.on("exit", () => resolve());
});
}
const views = fs.readdirSync(".").filter((view) => {
const expectedPath = `./${view}/package.json`;
return fs.existsSync(expectedPath);
});
fs.mkdirSync(OUTPUT, { recursive: true });
for (const view of views) {
const loggerChild = logger.child({});
process.chdir(`./${view}`);
loggerChild.info(`Install deps for "${view}"`);
await spawn("yarn");
loggerChild.info(`Building "${view}"`);
await spawn("yarn build", {
env: { ...process.env, NUXT_APP_BASE_URL: `/${view}/` },
});
process.chdir("..");
fs.cpSync(`./${view}/.output/public`, `${OUTPUT}/${view}`, {
recursive: true,
});
}

View File

@ -0,0 +1 @@
drop-oss-app.png

View File

@ -0,0 +1,8 @@
#!/bin/sh
program="drop-app"
# point to libraries and run
LD_LIBRARY_PATH=$APPDIR/usr/lib:/usr/local/lib:/usr/lib $APPDIR/usr/bin/$program $@
# vim:ft=sh

View File

@ -0,0 +1,8 @@
[Desktop Entry]
Name=drop-oss-app
Comment=The client application for the open-source, self-hosted game distribution platform Drop
Exec=AppRun
Icon=drop-oss-app
Type=Application
Categories=Game;Network
MimeType=x-scheme-handler/drop

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

38
build_appimage.sh Executable file
View File

@ -0,0 +1,38 @@
#!/bin/sh
# run this from the root of the git repo to make this work
arch="$(uname -m)"
git_dir="$PWD"
target_dir="$git_dir/src-tauri/target/"
appimage_dir="$git_dir/build/appimage"
appdir="$appimage_dir/drop-app.d"
build() {
# set up the repo
git submodule init
git submodule update --recursive
# set up yarn and build
yarn
yarn tauri build
}
rm -f $appdir/usr/bin/* $appdir/usr/lib/*
if [[ ! "$1" == "--nobuild" ]]; then
build
fi
# install binaries in the appdir, then the libraries
cp $target_dir/release/drop-app $appdir/usr/bin
for i in $(readelf -d "$target_dir/release/drop-app" |grep NEEDED |cut -d'[' -f2 |tr -d ]);
do
install -g 1000 -o 1000 -Dm755 "$(ls -L1 /usR/LIB/$i)" $appdir/usr/lib
done
wget -O $appimage_dir/appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$arch.AppImage
cd $appimage_dir
chmod u+x appimagetool
appimagetool $appdir

View File

@ -37,7 +37,7 @@
<component class="h-5" :is="item.icon" /> <component class="h-5" :is="item.icon" />
</HeaderWidget> </HeaderWidget>
</li> </li>
<OfflineHeaderWidget v-if="state?.status === AppStatus.Offline" /> <OfflineHeaderWidget v-if="state.status === AppStatus.Offline" />
<HeaderUserWidget /> <HeaderUserWidget />
</ol> </ol>
</div> </div>

View File

@ -1,5 +1,5 @@
<template> <template>
<Menu v-if="state?.user" as="div" class="relative inline-block"> <Menu v-if="state.user" as="div" class="relative inline-block">
<MenuButton> <MenuButton>
<HeaderWidget> <HeaderWidget>
<div class="inline-flex items-center text-zinc-300 hover:text-white"> <div class="inline-flex items-center text-zinc-300 hover:text-white">
@ -87,7 +87,7 @@ router.afterEach(() => {
const state = useAppState(); const state = useAppState();
const profilePictureUrl: string = await useObject( const profilePictureUrl: string = await useObject(
state.value?.user?.profilePictureObjectId ?? "" state.value.user?.profilePictureObjectId ?? ""
); );
const adminUrl: string = await invoke("gen_drop_url", { const adminUrl: string = await invoke("gen_drop_url", {
path: "/admin", path: "/admin",

View File

@ -1,59 +1,72 @@
<template> <template>
<div class="flex flex-col h-full"> <div>
<div class="mb-3 inline-flex gap-x-2"> <div class="mb-3 inline-flex gap-x-2">
<div class="relative transition-transform duration-300 hover:scale-105 active:scale-95"> <div
<div class="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3"> class="relative transition-transform duration-300 hover:scale-105 active:scale-95"
<MagnifyingGlassIcon class="h-5 w-5 text-zinc-400" aria-hidden="true" /> >
<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"
/>
</div> </div>
<input type="text" v-model="searchQuery" <input
type="text"
v-model="searchQuery"
class="block w-full rounded-lg border-0 bg-zinc-800/50 py-2 pl-10 pr-3 text-zinc-100 placeholder:text-zinc-500 focus:bg-zinc-800 focus:ring-2 focus:ring-inset focus:ring-blue-500 sm:text-sm sm:leading-6" class="block w-full rounded-lg border-0 bg-zinc-800/50 py-2 pl-10 pr-3 text-zinc-100 placeholder:text-zinc-500 focus:bg-zinc-800 focus:ring-2 focus:ring-inset focus:ring-blue-500 sm:text-sm sm:leading-6"
placeholder="Search library..." /> placeholder="Search library..."
/>
</div> </div>
<button @click="() => calculateGames(true)" <button
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"> @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" /> <ArrowPathIcon class="size-4" />
</button> </button>
</div> </div>
<TransitionGroup name="list" tag="ul" class="flex flex-col gap-y-1.5"> <TransitionGroup name="list" tag="ul" class="flex flex-col gap-y-1.5">
<NuxtLink v-for="(nav, navIndex) in filteredNavigation" :key="nav.id" :class="[ <NuxtLink
'transition-all duration-300 rounded-lg flex items-center py-2 px-3 hover:scale-105 active:scale-95 hover:shadow-lg hover:shadow-zinc-950/50', v-for="nav in filteredNavigation"
navIndex === currentNavigation :key="nav.id"
? 'bg-zinc-800 text-zinc-100 shadow-md shadow-zinc-950/20' :class="[
: nav.isInstalled.value 'transition-all duration-300 rounded-lg flex items-center py-2 px-3 hover:scale-105 active:scale-95 hover:shadow-lg hover:shadow-zinc-950/50',
nav.index === currentNavigation
? 'bg-zinc-800 text-zinc-100 shadow-md shadow-zinc-950/20'
: nav.isInstalled.value
? 'text-zinc-300 hover:bg-zinc-800/90 hover:text-zinc-200' ? 'text-zinc-300 hover:bg-zinc-800/90 hover:text-zinc-200'
: 'text-zinc-500 hover:bg-zinc-800/70 hover:text-zinc-300', : 'text-zinc-500 hover:bg-zinc-800/70 hover:text-zinc-300',
]" :href="nav.route"> ]"
:href="nav.route"
>
<div class="flex items-center w-full gap-x-3"> <div class="flex items-center w-full gap-x-3">
<div class="flex-none transition-transform duration-300 hover:-rotate-2"> <div
<img class="size-8 object-cover bg-zinc-900 rounded-lg transition-all duration-300 shadow-sm" class="flex-none transition-transform duration-300 hover:-rotate-2"
:src="icons[nav.id]" alt="" /> >
<img
class="size-8 object-cover bg-zinc-900 rounded-lg transition-all duration-300 shadow-sm"
:src="icons[nav.id]"
alt=""
/>
</div> </div>
<div class="flex flex-col flex-1"> <div class="flex flex-col flex-1">
<p class="truncate text-xs font-display leading-5 flex-1 font-semibold"> <p
class="truncate text-xs font-display leading-5 flex-1 font-semibold"
>
{{ nav.label }} {{ nav.label }}
</p> </p>
<p class="text-xs font-medium" :class="[gameStatusTextStyle[games[nav.id].status.value.type]]"> <p
class="text-xs font-medium"
:class="[gameStatusTextStyle[games[nav.id].status.value.type]]"
>
{{ gameStatusText[games[nav.id].status.value.type] }} {{ gameStatusText[games[nav.id].status.value.type] }}
</p> </p>
</div> </div>
</div> </div>
</NuxtLink> </NuxtLink>
</TransitionGroup> </TransitionGroup>
<div v-if="loading" class="h-full grow flex p-8 justify-center text-zinc-100">
<div role="status">
<svg aria-hidden="true" class="w-6 h-6 text-transparent animate-spin fill-zinc-600" viewBox="0 0 100 101"
fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor" />
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill" />
</svg>
<span class="sr-only">Loading...</span>
</div>
</div>
</div> </div>
</template> </template>
@ -67,12 +80,12 @@ import { listen } from "@tauri-apps/api/event";
// Style information // Style information
const gameStatusTextStyle: { [key in GameStatusEnum]: string } = { const gameStatusTextStyle: { [key in GameStatusEnum]: string } = {
[GameStatusEnum.Installed]: "text-green-500", [GameStatusEnum.Installed]: "text-green-500",
[GameStatusEnum.Downloading]: "text-zinc-400", [GameStatusEnum.Downloading]: "text-blue-500",
[GameStatusEnum.Validating]: "text-blue-300", [GameStatusEnum.Validating]: "text-blue-300",
[GameStatusEnum.Running]: "text-green-500", [GameStatusEnum.Running]: "text-green-500",
[GameStatusEnum.Remote]: "text-zinc-500", [GameStatusEnum.Remote]: "text-zinc-500",
[GameStatusEnum.Queued]: "text-zinc-400", [GameStatusEnum.Queued]: "text-blue-500",
[GameStatusEnum.Updating]: "text-zinc-400", [GameStatusEnum.Updating]: "text-blue-500",
[GameStatusEnum.Uninstalling]: "text-zinc-100", [GameStatusEnum.Uninstalling]: "text-zinc-100",
[GameStatusEnum.SetupRequired]: "text-yellow-500", [GameStatusEnum.SetupRequired]: "text-yellow-500",
[GameStatusEnum.PartiallyInstalled]: "text-gray-400", [GameStatusEnum.PartiallyInstalled]: "text-gray-400",
@ -94,7 +107,6 @@ const router = useRouter();
const searchQuery = ref(""); const searchQuery = ref("");
const loading = ref(false);
const games: { const games: {
[key: string]: { game: Game; status: Ref<GameStatus, GameStatus> }; [key: string]: { game: Game; status: Ref<GameStatus, GameStatus> };
} = {}; } = {};
@ -103,10 +115,7 @@ const icons: { [key: string]: string } = {};
const rawGames: Ref<Game[], Game[]> = ref([]); const rawGames: Ref<Game[], Game[]> = ref([]);
async function calculateGames(clearAll = false) { async function calculateGames(clearAll = false) {
if (clearAll) { if (clearAll) rawGames.value = [];
rawGames.value = [];
loading.value = true;
}
// If we update immediately, the navigation gets re-rendered before we // If we update immediately, the navigation gets re-rendered before we
// add all the necessary state, and it freaks tf out // add all the necessary state, and it freaks tf out
const newGames = await invoke<typeof rawGames.value>("fetch_library"); const newGames = await invoke<typeof rawGames.value>("fetch_library");
@ -118,22 +127,10 @@ async function calculateGames(clearAll = false) {
if (icons[game.id]) continue; if (icons[game.id]) continue;
icons[game.id] = await useObject(game.mIconObjectId); icons[game.id] = await useObject(game.mIconObjectId);
} }
loading.value = false;
rawGames.value = newGames; rawGames.value = newGames;
} }
// Wait up to 300 ms for the library to load, otherwise await calculateGames();
// show the loading state while we while
await new Promise<void>((r) => {
let hasResolved = false;
const resolveFunc = () => {
if (!hasResolved) r();
hasResolved = true
}
calculateGames(true).then(resolveFunc);
setTimeout(resolveFunc, 300);
})
const navigation = computed(() => const navigation = computed(() =>
rawGames.value.map((game) => { rawGames.value.map((game) => {
@ -141,7 +138,8 @@ const navigation = computed(() =>
const isInstalled = computed( const isInstalled = computed(
() => () =>
status.value.type != GameStatusEnum.Remote status.value.type == GameStatusEnum.Installed ||
status.value.type == GameStatusEnum.SetupRequired
); );
const item = { const item = {
@ -154,11 +152,9 @@ const navigation = computed(() =>
return item; return item;
}) })
); );
const { currentNavigation, recalculateNavigation } = useCurrentNavigationIndex(
const route = useRoute(); navigation.value
const currentNavigation = computed(() => { );
return navigation.value.findIndex((e) => e.route == route.path)
});
const filteredNavigation = computed(() => { const filteredNavigation = computed(() => {
if (!searchQuery.value) if (!searchQuery.value)
@ -173,7 +169,9 @@ listen("update_library", async (event) => {
console.log("Updating library"); console.log("Updating library");
let oldNavigation = navigation.value[currentNavigation.value]; let oldNavigation = navigation.value[currentNavigation.value];
await calculateGames(); await calculateGames();
if (oldNavigation.route !== navigation.value[currentNavigation.value].route) { recalculateNavigation();
if (oldNavigation !== navigation.value[currentNavigation.value]) {
console.log("Triggered");
router.push("/library"); router.push("/library");
} }
}); });

3
composables/app-state.ts Normal file
View File

@ -0,0 +1,3 @@
import type { AppState } from "~/types";
export const useAppState = () => useState<AppState>("state");

View File

@ -43,7 +43,6 @@ export const useGame = async (gameId: string) => {
gameStatusRegistry[gameId] = ref(parseStatus(data.status)); gameStatusRegistry[gameId] = ref(parseStatus(data.status));
listen(`update_game/${gameId}`, (event) => { listen(`update_game/${gameId}`, (event) => {
console.log(event);
const payload: { const payload: {
status: SerializedGameStatus; status: SerializedGameStatus;
version?: GameVersion; version?: GameVersion;

View File

@ -65,13 +65,7 @@ export function setupHooks() {
*/ */
} }
export function initialNavigation(state: ReturnType<typeof useAppState>) { export function initialNavigation(state: Ref<AppState>) {
if (!state.value)
throw createError({
statusCode: 500,
statusMessage: "App state not valid",
fatal: true,
});
const router = useRouter(); const router = useRouter();
switch (state.value.status) { switch (state.value.status) {

1
drop-base Submodule

Submodule drop-base added at 26698e5b06

View File

@ -7,7 +7,6 @@
class="mx-auto w-full max-w-7xl px-6 pt-6 sm:pt-10 lg:col-span-2 lg:col-start-1 lg:row-start-1 lg:px-8" class="mx-auto w-full max-w-7xl px-6 pt-6 sm:pt-10 lg:col-span-2 lg:col-start-1 lg:row-start-1 lg:px-8"
> >
<Logo class="h-10 w-auto sm:h-12" /> <Logo class="h-10 w-auto sm:h-12" />
</header> </header>
<main <main
class="mx-auto w-full max-w-7xl px-6 py-24 sm:py-32 lg:col-span-2 lg:col-start-1 lg:row-start-2 lg:px-8" class="mx-auto w-full max-w-7xl px-6 py-24 sm:py-32 lg:col-span-2 lg:col-start-1 lg:row-start-2 lg:px-8"

Submodule libs/drop-base deleted from 04125e89be

View File

@ -1,3 +0,0 @@
import type { AppState } from "~/types";
export const useAppState = () => useState<AppState | undefined>("state");

View File

@ -1,37 +0,0 @@
{
"name": "view",
"private": true,
"version": "0.3.2",
"type": "module",
"scripts": {
"build": "nuxt generate",
"dev": "nuxt dev",
"postinstall": "nuxt prepare",
"tauri": "tauri"
},
"dependencies": {
"@headlessui/vue": "^1.7.23",
"@heroicons/vue": "^2.1.5",
"@nuxtjs/tailwindcss": "^6.12.2",
"@tauri-apps/api": "^2.7.0",
"koa": "^2.16.1",
"markdown-it": "^14.1.0",
"micromark": "^4.0.1",
"nuxt": "^3.16.0",
"scss": "^0.2.4",
"vue-router": "latest",
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.9",
"@tailwindcss/typography": "^0.5.15",
"@types/markdown-it": "^14.1.2",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.47",
"sass-embedded": "^1.79.4",
"tailwindcss": "^3.4.13",
"typescript": "^5.8.3",
"vue-tsc": "^2.2.10"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}

View File

@ -1,16 +0,0 @@
<template>
<div class="mx-auto flex flex-col items-center gap-y-4 max-w-2xl py-32 sm:py-48 lg:py-56">
<div>
<Wordmark />
</div>
<div class="text-center">
<h1 class="text-balance text-4xl font-bold font-display tracking-tight text-zinc-100 sm:text-6xl">
Under construction
</h1>
<p class="mt-6 text-lg leading-8 text-zinc-400">
Yes, we know. We're working on it <a class="text-white" target="_blank"
href="https://github.com/Drop-OSS/drop-app/issues/52">here.</a>
</p>
</div>
</div>
</template>

View File

@ -1,16 +0,0 @@
<template>
<div class="mx-auto flex flex-col items-center gap-y-4 max-w-2xl py-32 sm:py-48 lg:py-56">
<div>
<Wordmark />
</div>
<div class="text-center">
<h1 class="text-balance text-4xl font-bold font-display tracking-tight text-zinc-100 sm:text-6xl">
Under construction
</h1>
<p class="mt-6 text-lg leading-8 text-zinc-400">
Yes, we know. We're working on it <a class="text-white" target="_blank"
href="https://github.com/Drop-OSS/drop-app/issues/52">here.</a>
</p>
</div>
</div>
</template>

File diff suppressed because it is too large Load Diff

View File

@ -13,9 +13,5 @@ export default defineNuxtConfig({
ssr: false, ssr: false,
extends: [["../libs/drop-base"]], extends: [["./drop-base"]],
app: {
baseURL: "/main",
}
}); });

View File

@ -1,22 +0,0 @@
## This script is largely useless, because there's not much we can do about AppImage size
ARCH=$(uname -m)
# build tauri apps
# NO_STRIP=true yarn tauri build -- --verbose
# unpack appimage
APPIMAGE=$(ls ./src-tauri/target/release/bundle/appimage/*.AppImage)
"$APPIMAGE" --appimage-extract
# strip binary
APPIMAGE_UNPACK="./squashfs-root"
find $APPIMAGE_UNPACK -type f -exec strip -s {} \;
APPIMAGETOOL=$(echo "obsolete-appimagetool-$ARCH.AppImage")
wget -O $APPIMAGETOOL "https://github.com/AppImage/AppImageKit/releases/download/13/$APPIMAGETOOL"
chmod +x $APPIMAGETOOL
APPIMAGE_OUTPUT=$(./$APPIMAGETOOL $APPIMAGE_UNPACK | grep ".AppImage" | grep squashfs-root | awk '{ print $6 }')
mv $APPIMAGE_OUTPUT "$APPIMAGE"

View File

@ -1,22 +1,46 @@
{ {
"name": "drop-app", "name": "drop-app",
"private": true, "private": true,
"version": "0.3.1-appimage",
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "node ./build.mjs", "build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"tauri": "tauri" "tauri": "tauri"
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "^2.7.0", "@headlessui/vue": "^1.7.23",
"@tauri-apps/plugin-deep-link": "^2.4.1", "@heroicons/vue": "^2.1.5",
"@tauri-apps/plugin-dialog": "^2.3.2", "@nuxtjs/tailwindcss": "^6.12.2",
"@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-opener": "^2.4.0",
"@tauri-apps/plugin-os": "^2.3.0", "@tauri-apps/plugin-os": "~2",
"@tauri-apps/plugin-shell": "^2.3.0", "@tauri-apps/plugin-shell": "^2.2.1",
"pino": "^9.7.0", "koa": "^2.16.1",
"pino-pretty": "^13.1.1" "markdown-it": "^14.1.0",
"micromark": "^4.0.1",
"nuxt": "^3.16.0",
"scss": "^0.2.4",
"vue": "latest",
"vue-router": "latest",
"vuedraggable": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "^2.7.1" "@tailwindcss/forms": "^0.5.9",
} "@tailwindcss/typography": "^0.5.15",
"@tauri-apps/cli": ">=2.0.0",
"@types/markdown-it": "^14.1.2",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.47",
"sass-embedded": "^1.79.4",
"tailwindcss": "^3.4.13",
"typescript": "^5.8.3",
"vue-tsc": "^2.2.10"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
} }

View File

@ -243,10 +243,7 @@
</div> </div>
</Listbox> </Listbox>
</div> </div>
<div <div v-else class="mt-1 rounded-md bg-red-600/10 p-4">
v-else-if="versionOptions === null || versionOptions?.length == 0"
class="mt-1 rounded-md bg-red-600/10 p-4"
>
<div class="flex"> <div class="flex">
<div class="flex-shrink-0"> <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" />
@ -259,27 +256,6 @@
</div> </div>
</div> </div>
</div> </div>
<div v-else class="w-full flex items-center justify-center p-4">
<div role="status">
<svg
aria-hidden="true"
class="w-7 h-7 text-transparent animate-spin fill-white"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span class="sr-only">Loading...</span>
</div>
</div>
<div v-if="installDirs"> <div v-if="installDirs">
<Listbox as="div" v-model="installDir"> <Listbox as="div" v-model="installDir">
<ListboxLabel class="block text-sm/6 font-medium text-zinc-100" <ListboxLabel class="block text-sm/6 font-medium text-zinc-100"
@ -534,13 +510,13 @@ async function installFlow() {
installDirs.value = undefined; installDirs.value = undefined;
try { try {
versionOptions.value = await invoke("fetch_game_version_options", { versionOptions.value = await invoke("fetch_game_verion_options", {
gameId: game.value.id, gameId: game.value.id,
}); });
console.log(versionOptions.value);
installDirs.value = await invoke("fetch_download_dir_stats"); installDirs.value = await invoke("fetch_download_dir_stats");
} catch (error) { } catch (error) {
installError.value = (error as string).toString(); installError.value = (error as string).toString();
versionOptions.value = undefined;
} }
} }

279
src-tauri/Cargo.lock generated
View File

@ -898,7 +898,7 @@ dependencies = [
"bitflags 2.9.1", "bitflags 2.9.1",
"core-foundation 0.10.1", "core-foundation 0.10.1",
"core-graphics-types", "core-graphics-types",
"foreign-types 0.5.0", "foreign-types",
"libc", "libc",
] ]
@ -1284,7 +1284,7 @@ dependencies = [
[[package]] [[package]]
name = "drop-app" name = "drop-app"
version = "0.3.2" version = "0.3.1-appimage"
dependencies = [ dependencies = [
"atomic-instant-full", "atomic-instant-full",
"bitcode", "bitcode",
@ -1301,7 +1301,6 @@ dependencies = [
"hex 0.4.3", "hex 0.4.3",
"http 1.3.1", "http 1.3.1",
"http-serde 2.1.1", "http-serde 2.1.1",
"humansize",
"known-folders", "known-folders",
"log", "log",
"log4rs", "log4rs",
@ -1312,7 +1311,7 @@ dependencies = [
"rand 0.9.1", "rand 0.9.1",
"rayon", "rayon",
"regex", "regex",
"reqwest 0.12.22", "reqwest 0.12.16",
"reqwest-middleware 0.4.2", "reqwest-middleware 0.4.2",
"reqwest-middleware-cache", "reqwest-middleware-cache",
"reqwest-websocket", "reqwest-websocket",
@ -1325,7 +1324,6 @@ dependencies = [
"sha1", "sha1",
"shared_child", "shared_child",
"slice-deque", "slice-deque",
"sysinfo",
"tar", "tar",
"tauri", "tauri",
"tauri-build", "tauri-build",
@ -1588,15 +1586,6 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared 0.1.1",
]
[[package]] [[package]]
name = "foreign-types" name = "foreign-types"
version = "0.5.0" version = "0.5.0"
@ -1604,7 +1593,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
dependencies = [ dependencies = [
"foreign-types-macros", "foreign-types-macros",
"foreign-types-shared 0.3.1", "foreign-types-shared",
] ]
[[package]] [[package]]
@ -1618,12 +1607,6 @@ dependencies = [
"syn 2.0.101", "syn 2.0.101",
] ]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]] [[package]]
name = "foreign-types-shared" name = "foreign-types-shared"
version = "0.3.1" version = "0.3.1"
@ -2312,15 +2295,6 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "humansize"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7"
dependencies = [
"libm",
]
[[package]] [[package]]
name = "humantime" name = "humantime"
version = "2.2.0" version = "2.2.0"
@ -2381,7 +2355,6 @@ dependencies = [
"hyper 1.6.0", "hyper 1.6.0",
"hyper-util", "hyper-util",
"rustls", "rustls",
"rustls-native-certs",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls",
@ -2389,22 +2362,6 @@ dependencies = [
"webpki-roots", "webpki-roots",
] ]
[[package]]
name = "hyper-tls"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"bytes",
"http-body-util",
"hyper 1.6.0",
"hyper-util",
"native-tls",
"tokio",
"tokio-native-tls",
"tower-service",
]
[[package]] [[package]]
name = "hyper-util" name = "hyper-util"
version = "0.1.13" version = "0.1.13"
@ -2817,9 +2774,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.174" version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -2831,12 +2788,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "libm"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
[[package]] [[package]]
name = "libredox" name = "libredox"
version = "0.1.3" version = "0.1.3"
@ -3099,23 +3050,6 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "native-tls"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
dependencies = [
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework 2.11.1",
"security-framework-sys",
"tempfile",
]
[[package]] [[package]]
name = "native_model" name = "native_model"
version = "0.6.1" version = "0.6.1"
@ -3208,15 +3142,6 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "ntapi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "num-bigint" name = "num-bigint"
version = "0.4.6" version = "0.4.6"
@ -3413,16 +3338,6 @@ dependencies = [
"objc2-core-foundation", "objc2-core-foundation",
] ]
[[package]]
name = "objc2-io-kit"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
dependencies = [
"libc",
"objc2-core-foundation",
]
[[package]] [[package]]
name = "objc2-io-surface" name = "objc2-io-surface"
version = "0.3.1" version = "0.3.1"
@ -3553,50 +3468,6 @@ dependencies = [
"pathdiff", "pathdiff",
] ]
[[package]]
name = "openssl"
version = "0.10.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
dependencies = [
"bitflags 2.9.1",
"cfg-if",
"foreign-types 0.3.2",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]
[[package]]
name = "openssl-probe"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
version = "0.9.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "option-ext" name = "option-ext"
version = "0.2.0" version = "0.2.0"
@ -4420,9 +4291,9 @@ dependencies = [
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.12.22" version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" checksum = "2bf597b113be201cb2269b4c39b39a804d01b99ee95a4278f0ed04e45cff1c71"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"bytes", "bytes",
@ -4435,23 +4306,22 @@ dependencies = [
"http-body-util", "http-body-util",
"hyper 1.6.0", "hyper 1.6.0",
"hyper-rustls", "hyper-rustls",
"hyper-tls",
"hyper-util", "hyper-util",
"ipnet",
"js-sys", "js-sys",
"log", "log",
"native-tls", "mime",
"once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"quinn", "quinn",
"rustls", "rustls",
"rustls-native-certs",
"rustls-pki-types", "rustls-pki-types",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"sync_wrapper 1.0.2", "sync_wrapper 1.0.2",
"tokio", "tokio",
"tokio-native-tls",
"tokio-rustls", "tokio-rustls",
"tokio-util", "tokio-util",
"tower", "tower",
@ -4490,7 +4360,7 @@ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
"http 1.3.1", "http 1.3.1",
"reqwest 0.12.22", "reqwest 0.12.16",
"serde", "serde",
"thiserror 1.0.69", "thiserror 1.0.69",
"tower-service", "tower-service",
@ -4525,7 +4395,7 @@ dependencies = [
"async-tungstenite", "async-tungstenite",
"bytes", "bytes",
"futures-util", "futures-util",
"reqwest 0.12.22", "reqwest 0.12.16",
"thiserror 2.0.12", "thiserror 2.0.12",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -4688,18 +4558,6 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "rustls-native-certs"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
dependencies = [
"openssl-probe",
"rustls-pki-types",
"schannel",
"security-framework 3.2.0",
]
[[package]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.12.0" version = "1.12.0"
@ -4742,15 +4600,6 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "schannel"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
dependencies = [
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "schemars" name = "schemars"
version = "0.8.22" version = "0.8.22"
@ -4784,42 +4633,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.9.1",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316"
dependencies = [
"bitflags 2.9.1",
"core-foundation 0.10.1",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "selectors" name = "selectors"
version = "0.24.0" version = "0.24.0"
@ -5189,7 +5002,7 @@ dependencies = [
"bytemuck", "bytemuck",
"cfg_aliases", "cfg_aliases",
"core-graphics", "core-graphics",
"foreign-types 0.5.0", "foreign-types",
"js-sys", "js-sys",
"log", "log",
"objc2 0.5.2", "objc2 0.5.2",
@ -5377,20 +5190,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "sysinfo"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d"
dependencies = [
"libc",
"memchr",
"ntapi",
"objc2-core-foundation",
"objc2-io-kit",
"windows",
]
[[package]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.5.1" version = "0.5.1"
@ -5503,9 +5302,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri" name = "tauri"
version = "2.7.0" version = "2.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "352a4bc7bf6c25f5624227e3641adf475a6535707451b09bb83271df8b7a6ac7" checksum = "124e129c9c0faa6bec792c5948c89e86c90094133b0b9044df0ce5f0a8efaa0d"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -5530,7 +5329,7 @@ dependencies = [
"percent-encoding", "percent-encoding",
"plist", "plist",
"raw-window-handle", "raw-window-handle",
"reqwest 0.12.22", "reqwest 0.12.16",
"serde", "serde",
"serde_json", "serde_json",
"serde_repr", "serde_repr",
@ -5554,9 +5353,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-build" name = "tauri-build"
version = "2.3.1" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "182d688496c06bf08ea896459bf483eb29cdff35c1c4c115fb14053514303064" checksum = "12f025c389d3adb83114bec704da973142e82fc6ec799c7c750c5e21cefaec83"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo_toml", "cargo_toml",
@ -5576,9 +5375,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-codegen" name = "tauri-codegen"
version = "2.3.1" version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b54a99a6cd8e01abcfa61508177e6096a4fe2681efecee9214e962f2f073ae4a" checksum = "f5df493a1075a241065bc865ed5ef8d0fbc1e76c7afdc0bf0eccfaa7d4f0e406"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"brotli", "brotli",
@ -5603,9 +5402,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-macros" name = "tauri-macros"
version = "2.3.2" version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7945b14dc45e23532f2ded6e120170bbdd4af5ceaa45784a6b33d250fbce3f9e" checksum = "f237fbea5866fa5f2a60a21bea807a2d6e0379db070d89c3a10ac0f2d4649bbc"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@ -5785,9 +5584,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-runtime" name = "tauri-runtime"
version = "2.7.1" version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b1cc885be806ea15ff7b0eb47098a7b16323d9228876afda329e34e2d6c4676" checksum = "9e7bb73d1bceac06c20b3f755b2c8a2cb13b20b50083084a8cf3700daf397ba4"
dependencies = [ dependencies = [
"cookie", "cookie",
"dpi", "dpi",
@ -5807,9 +5606,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-runtime-wry" name = "tauri-runtime-wry"
version = "2.7.2" version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe653a2fbbef19fe898efc774bc52c8742576342a33d3d028c189b57eb1d2439" checksum = "902b5aa9035e16f342eb64f8bf06ccdc2808e411a2525ed1d07672fa4e780bad"
dependencies = [ dependencies = [
"gtk", "gtk",
"http 1.3.1", "http 1.3.1",
@ -5834,9 +5633,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-utils" name = "tauri-utils"
version = "2.6.0" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330c15cabfe1d9f213478c9e8ec2b0c76dab26bb6f314b8ad1c8a568c1d186e" checksum = "41743bbbeb96c3a100d234e5a0b60a46d5aa068f266160862c7afdbf828ca02e"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"brotli", "brotli",
@ -6061,16 +5860,6 @@ dependencies = [
"syn 2.0.101", "syn 2.0.101",
] ]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]] [[package]]
name = "tokio-rustls" name = "tokio-rustls"
version = "0.26.2" version = "0.26.2"
@ -6175,9 +5964,9 @@ dependencies = [
[[package]] [[package]]
name = "tower-http" name = "tower-http"
version = "0.6.6" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e"
dependencies = [ dependencies = [
"bitflags 2.9.1", "bitflags 2.9.1",
"bytes", "bytes",
@ -6482,12 +6271,6 @@ version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5" checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5"
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "version-compare" name = "version-compare"
version = "0.2.0" version = "0.2.0"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "drop-app" name = "drop-app"
version = "0.3.2" version = "0.3.1-appimage"
description = "The client application for the open-source, self-hosted game distribution platform Drop" description = "The client application for the open-source, self-hosted game distribution platform Drop"
authors = ["Drop OSS"] authors = ["Drop OSS"]
edition = "2024" edition = "2024"
@ -71,8 +71,6 @@ bitcode = "0.6.6"
reqwest-websocket = "0.5.0" reqwest-websocket = "0.5.0"
futures-lite = "2.6.0" futures-lite = "2.6.0"
page_size = "0.6.0" page_size = "0.6.0"
sysinfo = "0.36.1"
humansize = "2.1.3"
# tailscale = { path = "./tailscale" } # tailscale = { path = "./tailscale" }
[dependencies.dynfmt] [dependencies.dynfmt]
@ -80,7 +78,7 @@ version = "0.1.5"
features = ["curly"] features = ["curly"]
[dependencies.tauri] [dependencies.tauri]
version = "2.7.0" version = "2.1.1"
features = ["protocol-asset", "tray-icon"] features = ["protocol-asset", "tray-icon"]
[dependencies.tokio] [dependencies.tokio]
@ -104,9 +102,9 @@ version = "2"
features = ["other_errors"] # You can also use "yaml_enc" or "bin_enc" features = ["other_errors"] # You can also use "yaml_enc" or "bin_enc"
[dependencies.reqwest] [dependencies.reqwest]
version = "0.12.22" version = "0.12"
default-features = false default-features = false
features = ["json", "http2", "blocking", "rustls-tls", "native-tls-alpn", "rustls-tls-native-roots"] features = ["json", "http2", "blocking", "rustls-tls-webpki-roots"]
[dependencies.serde] [dependencies.serde]
version = "1" version = "1"

View File

@ -266,7 +266,6 @@ pub mod data {
pub install_dirs: Vec<PathBuf>, pub install_dirs: Vec<PathBuf>,
// Guaranteed to exist if the game also exists in the app state map // Guaranteed to exist if the game also exists in the app state map
pub game_statuses: HashMap<String, GameDownloadStatus>, pub game_statuses: HashMap<String, GameDownloadStatus>,
pub game_versions: HashMap<String, HashMap<String, GameVersion>>, pub game_versions: HashMap<String, HashMap<String, GameVersion>>,
pub installed_game_version: HashMap<String, DownloadableMetadata>, pub installed_game_version: HashMap<String, DownloadableMetadata>,

View File

@ -124,16 +124,11 @@ impl DownloadManagerBuilder {
self.current_download_agent = None; self.current_download_agent = None;
let mut download_thread_lock = self.current_download_thread.lock().unwrap(); let mut download_thread_lock = self.current_download_thread.lock().unwrap();
*download_thread_lock = None;
if let Some(unfinished_thread) = download_thread_lock.take()
&& !unfinished_thread.is_finished()
{
unfinished_thread.join().unwrap();
}
drop(download_thread_lock); drop(download_thread_lock);
} }
fn stop_and_wait_current_download(&self) -> bool { fn stop_and_wait_current_download(&self) {
self.set_status(DownloadManagerStatus::Paused); self.set_status(DownloadManagerStatus::Paused);
if let Some(current_flag) = &self.active_control_flag { if let Some(current_flag) = &self.active_control_flag {
current_flag.set(DownloadThreadControlFlag::Stop); current_flag.set(DownloadThreadControlFlag::Stop);
@ -141,10 +136,8 @@ impl DownloadManagerBuilder {
let mut download_thread_lock = self.current_download_thread.lock().unwrap(); let mut download_thread_lock = self.current_download_thread.lock().unwrap();
if let Some(current_download_thread) = download_thread_lock.take() { if let Some(current_download_thread) = download_thread_lock.take() {
return current_download_thread.join().is_ok(); current_download_thread.join().unwrap();
}; }
true
} }
fn manage_queue(mut self) -> Result<(), ()> { fn manage_queue(mut self) -> Result<(), ()> {
@ -220,6 +213,10 @@ impl DownloadManagerBuilder {
&& self.download_queue.read().front().unwrap() && self.download_queue.read().front().unwrap()
== &self.current_download_agent.as_ref().unwrap().metadata() == &self.current_download_agent.as_ref().unwrap().metadata()
{ {
debug!(
"Current download agent: {:?}",
self.current_download_agent.as_ref().unwrap().metadata()
);
return; return;
} }
@ -257,16 +254,12 @@ impl DownloadManagerBuilder {
} }
}; };
// If the download gets canceled // If the download gets cancelled
// immediately return, on_cancelled gets called for us earlier // immediately return, on_cancelled gets called for us earlier
if !download_result { if !download_result {
return; return;
} }
if download_agent.control_flag().get() == DownloadThreadControlFlag::Stop {
return;
}
let validate_result = match download_agent.validate(&app_handle) { let validate_result = match download_agent.validate(&app_handle) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
@ -281,10 +274,6 @@ impl DownloadManagerBuilder {
} }
}; };
if download_agent.control_flag().get() == DownloadThreadControlFlag::Stop {
return;
}
if validate_result { if validate_result {
download_agent.on_complete(&app_handle); download_agent.on_complete(&app_handle);
sender sender
@ -327,7 +316,6 @@ impl DownloadManagerBuilder {
self.stop_and_wait_current_download(); self.stop_and_wait_current_download();
self.remove_and_cleanup_front_download(&current_agent.metadata()); self.remove_and_cleanup_front_download(&current_agent.metadata());
} }
self.push_ui_queue_update();
self.set_status(DownloadManagerStatus::Error); self.set_status(DownloadManagerStatus::Error);
} }
fn manage_cancel_signal(&mut self, meta: &DownloadableMetadata) { fn manage_cancel_signal(&mut self, meta: &DownloadableMetadata) {

View File

@ -1,8 +1,8 @@
use std::{ use std::{
sync::{ sync::{
Arc, Mutex,
atomic::{AtomicUsize, Ordering}, atomic::{AtomicUsize, Ordering},
mpsc::Sender, mpsc::Sender,
Arc, Mutex,
}, },
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -23,10 +23,9 @@ 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<1>, rolling: RollingProgressWindow<250>,
} }
#[derive(Clone)]
pub struct ProgressHandle { pub struct ProgressHandle {
progress: Arc<AtomicUsize>, progress: Arc<AtomicUsize>,
progress_object: Arc<ProgressObject>, progress_object: Arc<ProgressObject>,
@ -128,7 +127,7 @@ pub fn calculate_update(progress: &ProgressObject) {
.bytes_last_update .bytes_last_update
.swap(current_bytes_downloaded, Ordering::Acquire); .swap(current_bytes_downloaded, Ordering::Acquire);
let bytes_since_last_update = current_bytes_downloaded.saturating_sub(bytes_at_last_update); let bytes_since_last_update = current_bytes_downloaded - bytes_at_last_update;
let kilobytes_per_second = bytes_since_last_update / (time_since_last_update as usize).max(1); let kilobytes_per_second = bytes_since_last_update / (time_since_last_update as usize).max(1);

View File

@ -1,49 +1,30 @@
use std::{ use std::{
fmt::{Display, Formatter}, fmt::{Display, Formatter},
io, sync::Arc, io,
}; };
use serde_with::SerializeDisplay; use serde_with::SerializeDisplay;
use humansize::{format_size, BINARY};
use super::remote_access_error::RemoteAccessError; use super::remote_access_error::RemoteAccessError;
// TODO: Rename / separate from downloads // TODO: Rename / separate from downloads
#[derive(Debug, SerializeDisplay)] #[derive(Debug, SerializeDisplay)]
pub enum ApplicationDownloadError { pub enum ApplicationDownloadError {
NotInitialized,
Communication(RemoteAccessError), Communication(RemoteAccessError),
DiskFull(u64, u64),
#[allow(dead_code)]
Checksum, Checksum,
Lock, Lock,
IoError(Arc<io::Error>), IoError(io::ErrorKind),
DownloadError, DownloadError,
} }
impl Display for ApplicationDownloadError { impl Display for ApplicationDownloadError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
ApplicationDownloadError::NotInitialized => write!(f, "Download not initalized, did something go wrong?"),
ApplicationDownloadError::DiskFull(required, available) => write!(
f,
"Game requires {}, {} remaining left on disk.",
format_size(*required, BINARY),
format_size(*available, BINARY),
),
ApplicationDownloadError::Communication(error) => write!(f, "{error}"), ApplicationDownloadError::Communication(error) => write!(f, "{error}"),
ApplicationDownloadError::Lock => write!( ApplicationDownloadError::Lock => write!(f, "failed to acquire lock. Something has gone very wrong internally. Please restart the application"),
f, ApplicationDownloadError::Checksum => write!(f, "checksum failed to validate for download"),
"failed to acquire lock. Something has gone very wrong internally. Please restart the application"
),
ApplicationDownloadError::Checksum => {
write!(f, "checksum failed to validate for download")
}
ApplicationDownloadError::IoError(error) => write!(f, "io error: {error}"), ApplicationDownloadError::IoError(error) => write!(f, "io error: {error}"),
ApplicationDownloadError::DownloadError => write!( ApplicationDownloadError::DownloadError => write!(f, "download failed. See Download Manager status for specific error"),
f,
"Download failed. See Download Manager status for specific error"
),
} }
} }
} }

View File

@ -1,96 +1,109 @@
use serde_json::json; use serde_json::json;
use url::Url;
use crate::{ use crate::{
DB,
database::db::DatabaseImpls,
error::remote_access_error::RemoteAccessError, error::remote_access_error::RemoteAccessError,
remote::{ remote::{auth::generate_authorization_header, requests::make_request, utils::DROP_CLIENT_SYNC},
auth::generate_authorization_header,
requests::{generate_url, make_authenticated_get},
utils::DROP_CLIENT_ASYNC,
},
}; };
use super::collection::{Collection, Collections}; use super::collection::{Collection, Collections};
#[tauri::command] #[tauri::command]
pub async fn fetch_collections() -> Result<Collections, RemoteAccessError> { pub fn fetch_collections() -> Result<Collections, RemoteAccessError> {
let response = let client = DROP_CLIENT_SYNC.clone();
make_authenticated_get(generate_url(&["/api/v1/client/collection"], &[])?).await?; let response = make_request(&client, &["/api/v1/client/collection"], &[], |r| {
r.header("Authorization", generate_authorization_header())
})?
.send()?;
Ok(response.json().await?) Ok(response.json()?)
} }
#[tauri::command] #[tauri::command]
pub async fn fetch_collection(collection_id: String) -> Result<Collection, RemoteAccessError> { pub fn fetch_collection(collection_id: String) -> Result<Collection, RemoteAccessError> {
let response = make_authenticated_get(generate_url( let client = DROP_CLIENT_SYNC.clone();
let response = make_request(
&client,
&["/api/v1/client/collection/", &collection_id], &["/api/v1/client/collection/", &collection_id],
&[], &[],
)?) |r| r.header("Authorization", generate_authorization_header()),
.await?; )?
.send()?;
Ok(response.json().await?) Ok(response.json()?)
} }
#[tauri::command] #[tauri::command]
pub async fn create_collection(name: String) -> Result<Collection, RemoteAccessError> { pub fn create_collection(name: String) -> Result<Collection, RemoteAccessError> {
let client = DROP_CLIENT_ASYNC.clone(); let client = DROP_CLIENT_SYNC.clone();
let url = generate_url(&["/api/v1/client/collection"], &[])?; let base_url = DB.fetch_base_url();
let base_url = Url::parse(&format!("{base_url}api/v1/client/collection/"))?;
let response = client let response = client
.post(url) .post(base_url)
.header("Authorization", generate_authorization_header()) .header("Authorization", generate_authorization_header())
.json(&json!({"name": name})) .json(&json!({"name": name}))
.send() .send()?;
.await?;
Ok(response.json().await?) Ok(response.json()?)
} }
#[tauri::command] #[tauri::command]
pub async fn add_game_to_collection( pub fn add_game_to_collection(
collection_id: String, collection_id: String,
game_id: String, game_id: String,
) -> Result<(), RemoteAccessError> { ) -> Result<(), RemoteAccessError> {
let client = DROP_CLIENT_ASYNC.clone(); let client = DROP_CLIENT_SYNC.clone();
let url = Url::parse(&format!(
let url = generate_url(&["/api/v1/client/collection", &collection_id, "entry"], &[])?; "{}api/v1/client/collection/{}/entry/",
DB.fetch_base_url(),
collection_id
))?;
client client
.post(url) .post(url)
.header("Authorization", generate_authorization_header()) .header("Authorization", generate_authorization_header())
.json(&json!({"id": game_id})) .json(&json!({"id": game_id}))
.send() .send()?;
.await?;
Ok(()) Ok(())
} }
#[tauri::command] #[tauri::command]
pub async fn delete_collection(collection_id: String) -> Result<bool, RemoteAccessError> { pub fn delete_collection(collection_id: String) -> Result<bool, RemoteAccessError> {
let client = DROP_CLIENT_ASYNC.clone(); let client = DROP_CLIENT_SYNC.clone();
let base_url = Url::parse(&format!(
let url = generate_url(&["/api/v1/client/collection", &collection_id], &[])?; "{}api/v1/client/collection/{}",
DB.fetch_base_url(),
collection_id
))?;
let response = client let response = client
.delete(url) .delete(base_url)
.header("Authorization", generate_authorization_header()) .header("Authorization", generate_authorization_header())
.send() .send()?;
.await?;
Ok(response.json().await?) Ok(response.json()?)
} }
#[tauri::command] #[tauri::command]
pub async fn delete_game_in_collection( pub fn delete_game_in_collection(
collection_id: String, collection_id: String,
game_id: String, game_id: String,
) -> Result<(), RemoteAccessError> { ) -> Result<(), RemoteAccessError> {
let client = DROP_CLIENT_ASYNC.clone(); let client = DROP_CLIENT_SYNC.clone();
let base_url = Url::parse(&format!(
let url = generate_url(&["/api/v1/client/collection", &collection_id, "entry"], &[])?; "{}api/v1/client/collection/{}/entry",
DB.fetch_base_url(),
collection_id
))?;
client client
.delete(url) .delete(base_url)
.header("Authorization", generate_authorization_header()) .header("Authorization", generate_authorization_header())
.json(&json!({"id": game_id})) .json(&json!({"id": game_id}))
.send().await?; .send()?;
Ok(()) Ok(())
} }

View File

@ -18,28 +18,28 @@ use crate::{
use super::{ use super::{
library::{ library::{
FetchGameStruct, Game, fetch_game_logic, fetch_game_version_options_logic, FetchGameStruct, Game, fetch_game_logic, fetch_game_verion_options_logic,
fetch_library_logic, fetch_library_logic,
}, },
state::{GameStatusManager, GameStatusWithTransient}, state::{GameStatusManager, GameStatusWithTransient},
}; };
#[tauri::command] #[tauri::command]
pub async fn fetch_library( pub fn fetch_library(
state: tauri::State<'_, Mutex<AppState<'_>>>, state: tauri::State<'_, Mutex<AppState>>,
) -> Result<Vec<Game>, RemoteAccessError> { ) -> Result<Vec<Game>, RemoteAccessError> {
offline!( offline!(
state, state,
fetch_library_logic, fetch_library_logic,
fetch_library_logic_offline, fetch_library_logic_offline,
state state
).await )
} }
#[tauri::command] #[tauri::command]
pub async fn fetch_game( pub fn fetch_game(
game_id: String, game_id: String,
state: tauri::State<'_, Mutex<AppState<'_>>>, state: tauri::State<'_, Mutex<AppState>>,
) -> Result<FetchGameStruct, RemoteAccessError> { ) -> Result<FetchGameStruct, RemoteAccessError> {
offline!( offline!(
state, state,
@ -47,7 +47,7 @@ pub async fn fetch_game(
fetch_game_logic_offline, fetch_game_logic_offline,
game_id, game_id,
state state
).await )
} }
#[tauri::command] #[tauri::command]
@ -68,9 +68,9 @@ pub fn uninstall_game(game_id: String, app_handle: AppHandle) -> Result<(), Libr
} }
#[tauri::command] #[tauri::command]
pub async fn fetch_game_version_options( pub fn fetch_game_verion_options(
game_id: String, game_id: String,
state: tauri::State<'_, Mutex<AppState<'_>>>, state: tauri::State<'_, Mutex<AppState>>,
) -> Result<Vec<GameVersion>, RemoteAccessError> { ) -> Result<Vec<GameVersion>, RemoteAccessError> {
fetch_game_version_options_logic(game_id, state).await fetch_game_verion_options_logic(game_id, state)
} }

View File

@ -3,48 +3,43 @@ use std::{
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use crate::{ use crate::{
AppState, database::{db::borrow_db_checked, models::data::GameDownloadStatus},
database::{ download_manager::{
db::borrow_db_checked, download_manager_frontend::DownloadManagerSignal, downloadable::Downloadable,
models::data::GameDownloadStatus,
}, },
download_manager::downloadable::Downloadable, error::download_manager_error::DownloadManagerError,
error::application_download_error::ApplicationDownloadError, AppState,
}; };
use super::download_agent::GameDownloadAgent; use super::download_agent::GameDownloadAgent;
#[tauri::command] #[tauri::command]
pub async fn download_game( pub fn download_game(
game_id: String, game_id: String,
game_version: String, game_version: String,
install_dir: usize, install_dir: usize,
state: tauri::State<'_, Mutex<AppState<'_>>>, state: tauri::State<'_, Mutex<AppState>>,
) -> Result<(), ApplicationDownloadError> { ) -> Result<(), DownloadManagerError<DownloadManagerSignal>> {
let sender = { state.lock().unwrap().download_manager.get_sender().clone() }; let sender = state.lock().unwrap().download_manager.get_sender();
let game_download_agent = Arc::new(Box::new(GameDownloadAgent::new_from_index(
let game_download_agent = game_id,
GameDownloadAgent::new_from_index(game_id.clone(), game_version.clone(), install_dir, sender).await?; game_version,
install_dir,
let game_download_agent = sender,
Arc::new(Box::new(game_download_agent) as Box<dyn Downloadable + Send + Sync>); )) as Box<dyn Downloadable + Send + Sync>);
state Ok(state
.lock() .lock()
.unwrap() .unwrap()
.download_manager .download_manager
.queue_download(game_download_agent.clone()) .queue_download(game_download_agent)?)
.unwrap();
Ok(())
} }
#[tauri::command] #[tauri::command]
pub async fn resume_download( pub fn resume_download(
game_id: String, game_id: String,
state: tauri::State<'_, Mutex<AppState<'_>>>, state: tauri::State<'_, Mutex<AppState>>,
) -> Result<(), ApplicationDownloadError> { ) -> Result<(), DownloadManagerError<DownloadManagerSignal>> {
let s = borrow_db_checked() let s = borrow_db_checked()
.applications .applications
.game_statuses .game_statuses
@ -61,25 +56,17 @@ pub async fn resume_download(
install_dir, install_dir,
} => (version_name, install_dir), } => (version_name, install_dir),
}; };
let sender = state.lock().unwrap().download_manager.get_sender(); let sender = state.lock().unwrap().download_manager.get_sender();
let parent_dir: PathBuf = install_dir.into(); let parent_dir: PathBuf = install_dir.into();
let game_download_agent = Arc::new(Box::new(GameDownloadAgent::new(
let game_download_agent = Arc::new(Box::new( game_id,
GameDownloadAgent::new( version_name.clone(),
game_id, parent_dir.parent().unwrap().to_path_buf(),
version_name.clone(), sender,
parent_dir.parent().unwrap().to_path_buf(), )) as Box<dyn Downloadable + Send + Sync>);
sender, Ok(state
)
.await?,
) as Box<dyn Downloadable + Send + Sync>);
state
.lock() .lock()
.unwrap() .unwrap()
.download_manager .download_manager
.queue_download(game_download_agent) .queue_download(game_download_agent)?)
.unwrap();
Ok(())
} }

Some files were not shown because too many files have changed in this diff Show More