@@ -40,12 +40,10 @@
diff --git a/desktop/pages/queue.vue b/desktop/pages/queue.vue
new file mode 100644
index 00000000..fcf44e9f
--- /dev/null
+++ b/desktop/pages/queue.vue
@@ -0,0 +1,24 @@
+
+
+
+
+ {{ element.id }}
+
+
+
+ {{ current }}
+ {{ rest }}
+
+
+
diff --git a/desktop/pages/settings.vue b/desktop/pages/settings.vue
index 35b9783b..1e92a0f6 100644
--- a/desktop/pages/settings.vue
+++ b/desktop/pages/settings.vue
@@ -13,8 +13,8 @@
:href="item.route"
:class="[
itemIdx === currentPageIndex
- ? 'bg-zinc-800/50 text-blue-600'
- : 'text-zinc-400 hover:bg-zinc-800/30 hover:text-blue-600',
+ ? 'bg-zinc-800/50 text-zinc-100'
+ : 'text-zinc-400 hover:bg-zinc-800/30 hover:text-zinc-200',
'transition group flex gap-x-3 rounded-md p-2 pr-12 text-sm font-semibold leading-6',
]"
>
@@ -22,8 +22,8 @@
:is="item.icon"
:class="[
itemIdx === currentPageIndex
- ? 'text-blue-600'
- : 'text-zinc-400 group-hover:text-blue-600',
+ ? 'text-zinc-100'
+ : 'text-zinc-400 group-hover:text-zinc-200',
'transition h-6 w-6 shrink-0',
]"
aria-hidden="true"
diff --git a/desktop/pages/settings/downloads.vue b/desktop/pages/settings/downloads.vue
index 27e0f695..237ea72c 100644
--- a/desktop/pages/settings/downloads.vue
+++ b/desktop/pages/settings/downloads.vue
@@ -1,3 +1,238 @@
-
-
\ No newline at end of file
+
+
+
+
+
+ Install directories
+
+
+ This is where Drop will download game files to, and store them
+ indefinitely while you play. Drop and games may store other
+ information elsewhere, like saves or mods.
+
+
+
+ (open = true)"
+ type="button"
+ class="relative inline-flex items-center rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
+ >
+ Add new directory
+
+
+
+
+
+
+
+
+ deleteDirectory(dirIdx)"
+ :disabled="dirs.length <= 1"
+ :class="[
+ dirs.length <= 1
+ ? 'text-zinc-700'
+ : 'text-zinc-400 hover:text-zinc-100',
+ '-m-2.5 block p-2.5',
+ ]"
+ >
+ Open options
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Select game directory
+
+ selectDirectory()"
+ class="block text-left w-full rounded-md border-0 px-3 py-1.5 text-zinc-100 shadow-sm ring-1 ring-inset ring-zinc-700 bg-zinc-800 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm/6"
+ >
+ {{
+ currentDirectory ?? "Click to select a directory..."
+ }}
+
+
+
+ Select an empty directory to add.
+
+
+
+
+
+ submitDirectory()"
+ :class="[
+ 'inline-flex w-full shadow-sm sm:ml-3 sm:w-auto',
+ currentDirectory === undefined
+ ? 'text-zinc-400 bg-blue-600/10 hover:bg-blue-600/10'
+ : 'text-white bg-blue-600 hover:bg-blue-500',
+ ]"
+ >
+ Upload
+
+ cancelDirectory()"
+ ref="cancelButtonRef"
+ >
+ Cancel
+
+
+
+
+
+
+
+
+
+ {{ error }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/desktop/pages/store/index.vue b/desktop/pages/store/index.vue
index ee5f7b22..696d67cd 100644
--- a/desktop/pages/store/index.vue
+++ b/desktop/pages/store/index.vue
@@ -7,8 +7,29 @@
@click="startGameDownload"
>
Download game
-
({{ Math.floor(progress * 1000) / 10 }}%)
+
+ ({{ Math.floor(progress * 1000) / 10 }}%)
+
+
+ Cancel game download
+
+
+ Pause game download
+
+
+ Resume game download
+
+
diff --git a/desktop/plugins/vuedraggable.ts b/desktop/plugins/vuedraggable.ts
new file mode 100644
index 00000000..58d50a0b
--- /dev/null
+++ b/desktop/plugins/vuedraggable.ts
@@ -0,0 +1,5 @@
+import draggable from "vuedraggable";
+
+export default defineNuxtPlugin((nuxtApp) => {
+ nuxtApp.vueApp.component("draggable", draggable);
+});
diff --git a/desktop/prisma/schema.prisma b/desktop/prisma/schema.prisma
deleted file mode 100644
index 1ca51a1f..00000000
--- a/desktop/prisma/schema.prisma
+++ /dev/null
@@ -1,150 +0,0 @@
-// This should be copied from the main Drop repo
-// TODO: do this automatically
-
-generator client {
- provider = "prisma-client-js"
-}
-
-datasource db {
- provider = "postgresql"
- url = env("DATABASE_URL")
-}
-
-model User {
- id String @id @default(uuid())
- username String @unique
- admin Boolean @default(false)
-
- email String
- displayName String
- profilePicture String // Object
-
- authMecs LinkedAuthMec[]
- clients Client[]
-}
-
-enum AuthMec {
- Simple
-}
-
-model LinkedAuthMec {
- userId String
- mec AuthMec
-
- credentials Json
-
- user User @relation(fields: [userId], references: [id])
-
- @@id([userId, mec])
-}
-
-enum ClientCapabilities {
- DownloadAggregation
-}
-
-enum Platform {
- Windows @map("windows")
- Linux @map("linux")
-}
-
-// References a device
-model Client {
- id String @id @default(uuid())
- userId String
- user User @relation(fields: [userId], references: [id])
-
- endpoint String
- capabilities ClientCapabilities[]
-
- name String
- platform Platform
- lastConnected DateTime
-}
-
-enum MetadataSource {
- Custom
- GiantBomb
-}
-
-model Game {
- id String @id @default(uuid())
-
- metadataSource MetadataSource
- metadataId String
-
- // Any field prefixed with m is filled in from metadata
- // Acts as a cache so we can search and filter it
- mName String // Name of game
- mShortDescription String // Short description
- mDescription String // Supports markdown
- mDevelopers Developer[]
- mPublishers Publisher[]
-
- mReviewCount Int
- mReviewRating Float
-
- mIconId String // linked to objects in s3
- mBannerId String // linked to objects in s3
- mCoverId String
- mImageLibrary String[] // linked to objects in s3
-
- versions GameVersion[]
- libraryBasePath String @unique // Base dir for all the game versions
-
- @@unique([metadataSource, metadataId], name: "metadataKey")
-}
-
-// A particular set of files that relate to the version
-model GameVersion {
- gameId String
- game Game @relation(fields: [gameId], references: [id])
- versionName String // Sub directory for the game files
-
- platform Platform
- launchCommand String // Command to run to start. Platform-specific. Windows games on Linux will wrap this command in Proton/Wine
- setupCommand String // Command to setup game (dependencies and such)
- dropletManifest Json // Results from droplet
-
- versionIndex Int
- delta Boolean @default(false)
-
- @@id([gameId, versionName])
-}
-
-model Developer {
- id String @id @default(uuid())
-
- metadataSource MetadataSource
- metadataId String
- metadataOriginalQuery String
-
- mName String
- mShortDescription String
- mDescription String
- mLogo String
- mBanner String
- mWebsite String
-
- games Game[]
-
- @@unique([metadataSource, metadataId, metadataOriginalQuery], name: "metadataKey")
-}
-
-model Publisher {
- id String @id @default(uuid())
-
- metadataSource MetadataSource
- metadataId String
- metadataOriginalQuery String
-
- mName String
- mShortDescription String
- mDescription String
- mLogo String
- mBanner String
- mWebsite String
-
- games Game[]
-
- @@unique([metadataSource, metadataId, metadataOriginalQuery], name: "metadataKey")
-}
diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock
index ead261bf..9a75a23b 100644
--- a/desktop/src-tauri/Cargo.lock
+++ b/desktop/src-tauri/Cargo.lock
@@ -58,9 +58,9 @@ dependencies = [
[[package]]
name = "anyhow"
-version = "1.0.89"
+version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
+checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
[[package]]
name = "arc-swap"
@@ -70,9 +70,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
[[package]]
name = "ashpd"
-version = "0.9.2"
+version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d43c03d9e36dd40cab48435be0b09646da362c278223ca535493877b2c1dee9"
+checksum = "e9c39d707614dbcc6bed00015539f488d8e3fe3e66ed60961efc0c90f4b380b3"
dependencies = [
"enumflags2",
"futures-channel",
@@ -86,7 +86,7 @@ dependencies = [
"wayland-backend",
"wayland-client",
"wayland-protocols",
- "zbus",
+ "zbus 5.1.1",
]
[[package]]
@@ -139,9 +139,9 @@ dependencies = [
[[package]]
name = "async-io"
-version = "2.3.4"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8"
+checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059"
dependencies = [
"async-lock",
"cfg-if",
@@ -194,7 +194,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -229,7 +229,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -282,12 +282,6 @@ dependencies = [
"windows-targets 0.52.6",
]
-[[package]]
-name = "base64"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
-
[[package]]
name = "base64"
version = "0.21.7"
@@ -300,15 +294,6 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
-[[package]]
-name = "bincode"
-version = "1.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
-dependencies = [
- "serde",
-]
-
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -363,9 +348,9 @@ dependencies = [
[[package]]
name = "brotli"
-version = "6.0.0"
+version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b"
+checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -390,9 +375,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "bytemuck"
-version = "1.18.0"
+version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae"
+checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
[[package]]
name = "byteorder"
@@ -402,9 +387,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
-version = "1.7.2"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
dependencies = [
"serde",
]
@@ -420,7 +405,7 @@ dependencies = [
"glib",
"libc",
"once_cell",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -445,9 +430,9 @@ dependencies = [
[[package]]
name = "cargo-platform"
-version = "0.1.8"
+version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
+checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
dependencies = [
"serde",
]
@@ -463,7 +448,7 @@ dependencies = [
"semver",
"serde",
"serde_json",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -473,14 +458,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719"
dependencies = [
"serde",
- "toml 0.8.2",
+ "toml 0.8.19",
]
[[package]]
name = "cc"
-version = "1.1.25"
+version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8d9e0b4957f635b8d3da819d0db5603620467ecf1f692d22a8c2717ce27e6d8"
+checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
dependencies = [
"shlex",
]
@@ -614,6 +599,16 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+[[package]]
+name = "cookie"
+version = "0.18.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
+dependencies = [
+ "time",
+ "version_check",
+]
+
[[package]]
name = "core-foundation"
version = "0.9.4"
@@ -666,9 +661,9 @@ dependencies = [
[[package]]
name = "cpufeatures"
-version = "0.2.14"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
+checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
dependencies = [
"libc",
]
@@ -756,17 +751,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
name = "ctor"
-version = "0.2.8"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
+checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
dependencies = [
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -790,7 +785,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -801,7 +796,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -835,7 +830,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -890,13 +885,24 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
[[package]]
name = "dlib"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
dependencies = [
- "libloading",
+ "libloading 0.8.6",
]
[[package]]
@@ -919,7 +925,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -1012,14 +1018,14 @@ checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "embed-resource"
-version = "2.5.0"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4e24052d7be71f0efb50c201557f6fe7d237cfd5a64fd5bcd7fd8fe32dbbffa"
+checksum = "b68b6f9f63a0b6a38bc447d4ce84e2b388f3ec95c99c641c8ff0dd3ef89a6379"
dependencies = [
"cc",
"memchr",
"rustc_version",
- "toml 0.8.2",
+ "toml 0.8.19",
"vswhom",
"winreg",
]
@@ -1032,9 +1038,9 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
[[package]]
name = "encoding_rs"
-version = "0.8.34"
+version = "0.8.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
dependencies = [
"cfg-if",
]
@@ -1063,7 +1069,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -1084,12 +1090,12 @@ dependencies = [
[[package]]
name = "errno"
-version = "0.3.9"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -1105,9 +1111,9 @@ dependencies = [
[[package]]
name = "event-listener-strategy"
-version = "0.5.2"
+version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1"
+checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
dependencies = [
"event-listener",
"pin-project-lite",
@@ -1115,15 +1121,15 @@ dependencies = [
[[package]]
name = "fastrand"
-version = "2.1.1"
+version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "fdeflate"
-version = "0.3.5"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab"
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
@@ -1140,23 +1146,14 @@ dependencies = [
[[package]]
name = "flate2"
-version = "1.0.34"
+version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"miniz_oxide",
]
-[[package]]
-name = "fluent-uri"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d"
-dependencies = [
- "bitflags 1.3.2",
-]
-
[[package]]
name = "fnv"
version = "1.0.7"
@@ -1190,7 +1187,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -1259,9 +1256,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-lite"
-version = "2.3.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5"
+checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1"
dependencies = [
"fastrand",
"futures-core",
@@ -1278,7 +1275,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -1472,7 +1469,7 @@ dependencies = [
"once_cell",
"pin-project-lite",
"smallvec",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -1508,7 +1505,7 @@ dependencies = [
"memchr",
"once_cell",
"smallvec",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -1518,11 +1515,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc"
dependencies = [
"heck 0.4.1",
- "proc-macro-crate 2.0.2",
+ "proc-macro-crate 2.0.0",
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -1601,14 +1598,14 @@ dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
name = "h2"
-version = "0.4.6"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
+checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e"
dependencies = [
"atomic-waker",
"bytes",
@@ -1616,7 +1613,7 @@ dependencies = [
"futures-core",
"futures-sink",
"http",
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"slab",
"tokio",
"tokio-util",
@@ -1637,9 +1634,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hashbrown"
-version = "0.15.0"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
@@ -1653,12 +1650,6 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-[[package]]
-name = "hermit-abi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
-
[[package]]
name = "hermit-abi"
version = "0.4.0"
@@ -1696,13 +1687,13 @@ dependencies = [
[[package]]
name = "http"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
dependencies = [
"bytes",
"fnv",
- "itoa 1.0.11",
+ "itoa 1.0.14",
]
[[package]]
@@ -1742,9 +1733,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hyper"
-version = "1.4.1"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05"
+checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
dependencies = [
"bytes",
"futures-channel",
@@ -1753,7 +1744,7 @@ dependencies = [
"http",
"http-body",
"httparse",
- "itoa 1.0.11",
+ "itoa 1.0.14",
"pin-project-lite",
"smallvec",
"tokio",
@@ -1795,9 +1786,9 @@ dependencies = [
[[package]]
name = "hyper-util"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b"
+checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
dependencies = [
"bytes",
"futures-channel",
@@ -1845,6 +1836,124 @@ dependencies = [
"png",
]
+[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -1853,12 +1962,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
-version = "0.5.0"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
dependencies = [
- "unicode-bidi",
- "unicode-normalization",
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
]
[[package]]
@@ -1874,12 +1994,12 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.6.0"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
- "hashbrown 0.15.0",
+ "hashbrown 0.15.2",
"serde",
]
@@ -1934,9 +2054,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
-version = "1.0.11"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "javascriptcore-rs"
@@ -1972,7 +2092,7 @@ dependencies = [
"combine",
"jni-sys",
"log",
- "thiserror",
+ "thiserror 1.0.69",
"walkdir",
"windows-sys 0.45.0",
]
@@ -1985,32 +2105,32 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "js-sys"
-version = "0.3.70"
+version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
dependencies = [
+ "once_cell",
"wasm-bindgen",
]
[[package]]
name = "json-patch"
-version = "2.0.0"
+version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc"
+checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08"
dependencies = [
"jsonptr",
"serde",
"serde_json",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
name = "jsonptr"
-version = "0.4.7"
+version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627"
+checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70"
dependencies = [
- "fluent-uri",
"serde",
"serde_json",
]
@@ -2065,15 +2185,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf"
dependencies = [
"gtk-sys",
- "libloading",
+ "libloading 0.7.4",
"once_cell",
]
[[package]]
name = "libc"
-version = "0.2.159"
+version = "0.2.168"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
[[package]]
name = "libloading"
@@ -2085,6 +2205,16 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "libloading"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
+dependencies = [
+ "cfg-if",
+ "windows-targets 0.52.6",
+]
+
[[package]]
name = "libredox"
version = "0.1.3"
@@ -2101,6 +2231,12 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+[[package]]
+name = "litemap"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
+
[[package]]
name = "lock_api"
version = "0.4.12"
@@ -2148,7 +2284,7 @@ dependencies = [
"serde-value",
"serde_json",
"serde_yaml",
- "thiserror",
+ "thiserror 1.0.69",
"thread-id",
"typemap-ors",
"winapi",
@@ -2228,11 +2364,10 @@ dependencies = [
[[package]]
name = "mio"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
- "hermit-abi 0.3.9",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.52.0",
@@ -2240,9 +2375,9 @@ dependencies = [
[[package]]
name = "muda"
-version = "0.15.1"
+version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8123dfd4996055ac9b15a60ad263b44b01e539007523ad7a4a533a3d93b0591"
+checksum = "fdae9c00e61cc0579bcac625e8ad22104c60548a025bfc972dc83868a28e1484"
dependencies = [
"crossbeam-channel",
"dpi",
@@ -2254,7 +2389,7 @@ dependencies = [
"once_cell",
"png",
"serde",
- "thiserror",
+ "thiserror 1.0.69",
"windows-sys 0.59.0",
]
@@ -2287,7 +2422,7 @@ dependencies = [
"ndk-sys",
"num_enum",
"raw-window-handle",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -2313,12 +2448,13 @@ checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "nix"
-version = "0.27.1"
+version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
+ "cfg_aliases",
"libc",
"memoffset",
]
@@ -2359,10 +2495,10 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
dependencies = [
- "proc-macro-crate 2.0.2",
+ "proc-macro-crate 3.2.0",
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -2372,7 +2508,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
- "objc_exception",
]
[[package]]
@@ -2380,6 +2515,9 @@ name = "objc-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
+dependencies = [
+ "cc",
+]
[[package]]
name = "objc2"
@@ -2407,6 +2545,30 @@ dependencies = [
"objc2-quartz-core",
]
+[[package]]
+name = "objc2-cloud-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
+dependencies = [
+ "bitflags 2.6.0",
+ "block2",
+ "objc2",
+ "objc2-core-location",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-contacts"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
[[package]]
name = "objc2-core-data"
version = "0.2.2"
@@ -2431,6 +2593,18 @@ dependencies = [
"objc2-metal",
]
+[[package]]
+name = "objc2-core-location"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-contacts",
+ "objc2-foundation",
+]
+
[[package]]
name = "objc2-encode"
version = "4.0.3"
@@ -2450,6 +2624,18 @@ dependencies = [
"objc2",
]
+[[package]]
+name = "objc2-link-presentation"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+]
+
[[package]]
name = "objc2-metal"
version = "0.2.2"
@@ -2476,21 +2662,71 @@ dependencies = [
]
[[package]]
-name = "objc_exception"
-version = "0.1.2"
+name = "objc2-symbols"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
+checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
dependencies = [
- "cc",
+ "objc2",
+ "objc2-foundation",
]
[[package]]
-name = "objc_id"
-version = "0.1.1"
+name = "objc2-ui-kit"
+version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
+checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
dependencies = [
- "objc",
+ "bitflags 2.6.0",
+ "block2",
+ "objc2",
+ "objc2-cloud-kit",
+ "objc2-core-data",
+ "objc2-core-image",
+ "objc2-core-location",
+ "objc2-foundation",
+ "objc2-link-presentation",
+ "objc2-quartz-core",
+ "objc2-symbols",
+ "objc2-uniform-type-identifiers",
+ "objc2-user-notifications",
+]
+
+[[package]]
+name = "objc2-uniform-type-identifiers"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
+dependencies = [
+ "block2",
+ "objc2",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-user-notifications"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
+dependencies = [
+ "bitflags 2.6.0",
+ "block2",
+ "objc2",
+ "objc2-core-location",
+ "objc2-foundation",
+]
+
+[[package]]
+name = "objc2-web-kit"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65"
+dependencies = [
+ "bitflags 2.6.0",
+ "block2",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
]
[[package]]
@@ -2504,18 +2740,15 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.20.1"
+version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
-dependencies = [
- "portable-atomic",
-]
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
[[package]]
name = "open"
-version = "5.3.0"
+version = "5.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3"
+checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c"
dependencies = [
"is-wsl",
"libc",
@@ -2524,9 +2757,9 @@ dependencies = [
[[package]]
name = "openssl"
-version = "0.10.66"
+version = "0.10.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
+checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
dependencies = [
"bitflags 2.6.0",
"cfg-if",
@@ -2545,7 +2778,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -2565,9 +2798,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
-version = "0.9.103"
+version = "0.9.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
+checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
dependencies = [
"cc",
"libc",
@@ -2677,9 +2910,9 @@ dependencies = [
[[package]]
name = "pathdiff"
-version = "0.2.1"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
[[package]]
name = "percent-encoding"
@@ -2791,7 +3024,7 @@ dependencies = [
"phf_shared 0.11.2",
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -2823,9 +3056,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
[[package]]
name = "pin-utils"
@@ -2857,7 +3090,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
dependencies = [
"base64 0.22.1",
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"quick-xml 0.32.0",
"serde",
"time",
@@ -2865,9 +3098,9 @@ dependencies = [
[[package]]
name = "png"
-version = "0.17.14"
+version = "0.17.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0"
+checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d"
dependencies = [
"bitflags 1.3.2",
"crc32fast",
@@ -2878,25 +3111,19 @@ dependencies = [
[[package]]
name = "polling"
-version = "3.7.3"
+version = "3.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511"
+checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f"
dependencies = [
"cfg-if",
"concurrent-queue",
- "hermit-abi 0.4.0",
+ "hermit-abi",
"pin-project-lite",
"rustix",
"tracing",
"windows-sys 0.59.0",
]
-[[package]]
-name = "portable-atomic"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
-
[[package]]
name = "powerfmt"
version = "0.2.0"
@@ -2930,12 +3157,20 @@ dependencies = [
[[package]]
name = "proc-macro-crate"
-version = "2.0.2"
+version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
+checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8"
dependencies = [
- "toml_datetime",
- "toml_edit 0.20.2",
+ "toml_edit 0.20.7",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b"
+dependencies = [
+ "toml_edit 0.22.22",
]
[[package]]
@@ -2970,9 +3205,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
@@ -3128,14 +3363,14 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom 0.2.15",
"libredox",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
name = "regex"
-version = "1.11.0"
+version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@@ -3145,9 +3380,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.8"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@@ -3162,9 +3397,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "reqwest"
-version = "0.12.8"
+version = "0.12.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b"
+checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -3208,9 +3443,9 @@ dependencies = [
[[package]]
name = "rfd"
-version = "0.15.0"
+version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e"
+checksum = "46f6f80a9b882647d9014673ca9925d30ffc9750f2eed2b4490e189eaebd01e8"
dependencies = [
"ashpd",
"block2",
@@ -3261,11 +3496,9 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "460d97902465327d69ecfe8cefdb5972c6f94d6127ac9e992acdb51458bebc27"
dependencies = [
- "base64 0.12.3",
- "bincode",
"serde",
"tempfile",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -3285,22 +3518,22 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.38.37"
+version = "0.38.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
+checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
dependencies = [
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
]
[[package]]
name = "rustls"
-version = "0.23.14"
+version = "0.23.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8"
+checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1"
dependencies = [
"once_cell",
"rustls-pki-types",
@@ -3320,9 +3553,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
-version = "1.9.0"
+version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55"
+checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
[[package]]
name = "rustls-webpki"
@@ -3352,9 +3585,9 @@ dependencies = [
[[package]]
name = "schannel"
-version = "0.1.24"
+version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b"
+checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
dependencies = [
"windows-sys 0.59.0",
]
@@ -3383,7 +3616,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -3413,9 +3646,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.12.0"
+version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6"
+checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
dependencies = [
"core-foundation-sys",
"libc",
@@ -3452,9 +3685,9 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.210"
+version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [
"serde_derive",
]
@@ -3482,13 +3715,13 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.210"
+version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -3499,16 +3732,16 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
name = "serde_json"
-version = "1.0.128"
+version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
dependencies = [
- "itoa 1.0.11",
+ "itoa 1.0.14",
"memchr",
"ryu",
"serde",
@@ -3522,7 +3755,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -3541,22 +3774,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
- "itoa 1.0.11",
+ "itoa 1.0.14",
"ryu",
"serde",
]
[[package]]
name = "serde_with"
-version = "3.10.0"
+version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9720086b3357bcb44fce40117d769a4d068c70ecfa190850a980a71755f66fcc"
+checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817"
dependencies = [
"base64 0.22.1",
"chrono",
"hex",
"indexmap 1.9.3",
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"serde",
"serde_derive",
"serde_json",
@@ -3566,14 +3799,14 @@ dependencies = [
[[package]]
name = "serde_with_macros"
-version = "3.10.0"
+version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f1abbfe725f27678f4663bcacb75a83e829fd464c25d78dd038a3a29e307cec"
+checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d"
dependencies = [
"darling",
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -3582,8 +3815,8 @@ version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
- "indexmap 2.6.0",
- "itoa 1.0.11",
+ "indexmap 2.7.0",
+ "itoa 1.0.14",
"ryu",
"serde",
"unsafe-libyaml",
@@ -3697,9 +3930,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "socket2"
-version = "0.5.7"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
dependencies = [
"libc",
"windows-sys 0.52.0",
@@ -3833,9 +4066,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.79"
+version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
+checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
@@ -3844,13 +4077,24 @@ dependencies = [
[[package]]
name = "sync_wrapper"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
dependencies = [
"futures-core",
]
+[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
[[package]]
name = "system-configuration"
version = "0.6.1"
@@ -3881,15 +4125,15 @@ dependencies = [
"cfg-expr",
"heck 0.5.0",
"pkg-config",
- "toml 0.8.2",
+ "toml 0.8.19",
"version-compare",
]
[[package]]
name = "tao"
-version = "0.30.3"
+version = "0.30.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0dbbebe82d02044dfa481adca1550d6dd7bd16e086bc34fa0fbecceb5a63751"
+checksum = "6682a07cf5bab0b8a2bd20d0a542917ab928b5edb75ebd4eda6b05cbaab872da"
dependencies = [
"bitflags 2.6.0",
"cocoa",
@@ -3932,7 +4176,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -3943,9 +4187,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tauri"
-version = "2.0.1"
+version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3fad474c02a3bcd4a304afff97159a31b9bab84e29563f7109c7b0ce8cd774e"
+checksum = "e545de0a2dfe296fa67db208266cd397c5a55ae782da77973ef4c4fac90e9f2c"
dependencies = [
"anyhow",
"bytes",
@@ -3980,7 +4224,7 @@ dependencies = [
"tauri-runtime",
"tauri-runtime-wry",
"tauri-utils",
- "thiserror",
+ "thiserror 2.0.6",
"tokio",
"tray-icon",
"url",
@@ -3993,9 +4237,9 @@ dependencies = [
[[package]]
name = "tauri-build"
-version = "2.0.1"
+version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "935f9b3c49b22b3e2e485a57f46d61cd1ae07b1cbb2ba87387a387caf2d8c4e7"
+checksum = "7bd2a4bcfaf5fb9f4be72520eefcb61ae565038f8ccba2a497d8c28f463b8c01"
dependencies = [
"anyhow",
"cargo_toml",
@@ -4009,15 +4253,15 @@ dependencies = [
"serde_json",
"tauri-utils",
"tauri-winres",
- "toml 0.8.2",
+ "toml 0.8.19",
"walkdir",
]
[[package]]
name = "tauri-codegen"
-version = "2.0.1"
+version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95d7443dd4f0b597704b6a14b964ee2ed16e99928d8e6292ae9825f09fbcd30e"
+checksum = "bf79faeecf301d3e969b1fae977039edb77a4c1f25cc0a961be298b54bff97cf"
dependencies = [
"base64 0.22.1",
"brotli",
@@ -4031,9 +4275,9 @@ dependencies = [
"serde",
"serde_json",
"sha2",
- "syn 2.0.79",
+ "syn 2.0.90",
"tauri-utils",
- "thiserror",
+ "thiserror 2.0.6",
"time",
"url",
"uuid",
@@ -4042,23 +4286,23 @@ dependencies = [
[[package]]
name = "tauri-macros"
-version = "2.0.1"
+version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d2c0963ccfc3f5194415f2cce7acc975942a8797fbabfb0aa1ed6f59326ae7f"
+checksum = "c52027c8c5afb83166dacddc092ee8fff50772f9646d461d8c33ee887e447a03"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
"tauri-codegen",
"tauri-utils",
]
[[package]]
name = "tauri-plugin"
-version = "2.0.1"
+version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2e6660a409963e4d57b9bfab4addd141eeff41bd3a7fb14e13004a832cf7ef6"
+checksum = "e753f2a30933a9bbf0a202fa47d7cc4a3401f06e8d6dcc53b79aa62954828c79"
dependencies = [
"anyhow",
"glob",
@@ -4067,25 +4311,25 @@ dependencies = [
"serde",
"serde_json",
"tauri-utils",
- "toml 0.8.2",
+ "toml 0.8.19",
"walkdir",
]
[[package]]
name = "tauri-plugin-deep-link"
-version = "2.0.1"
+version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "31a9b5725027c6e9e075b06cb2d5c2cd3b5c29daa8012b404e1ff755cc56082f"
+checksum = "1fb46bb8be2c47e344892f387c7aeb6a203a9edea0001e3017c0518d15520786"
dependencies = [
"dunce",
- "log",
"rust-ini",
"serde",
"serde_json",
"tauri",
"tauri-plugin",
"tauri-utils",
- "thiserror",
+ "thiserror 2.0.6",
+ "tracing",
"url",
"windows-registry 0.3.0",
"windows-result",
@@ -4093,9 +4337,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-dialog"
-version = "2.0.1"
+version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddb2fe88b602461c118722c574e2775ab26a4e68886680583874b2f6520608b7"
+checksum = "0962c2b9210e43cd849790d33bdf3d28c0e50d9884493fb340835244a708b5ba"
dependencies = [
"log",
"raw-window-handle",
@@ -4105,15 +4349,15 @@ dependencies = [
"tauri",
"tauri-plugin",
"tauri-plugin-fs",
- "thiserror",
+ "thiserror 2.0.6",
"url",
]
[[package]]
name = "tauri-plugin-fs"
-version = "2.0.1"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab300488ebec3487ca5f56289692e7e45feb07eea8d5e1dba497f7dc9dd9c407"
+checksum = "0cdaf6701ee5efc83161cf41004aa5aec4d255c9fb2d2b11fe518fe506acc588"
dependencies = [
"anyhow",
"dunce",
@@ -4125,16 +4369,18 @@ dependencies = [
"serde_repr",
"tauri",
"tauri-plugin",
- "thiserror",
+ "tauri-utils",
+ "thiserror 2.0.6",
+ "toml 0.8.19",
"url",
"uuid",
]
[[package]]
name = "tauri-plugin-shell"
-version = "2.0.1"
+version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "371fb9aca2823990a2d0db7970573be5fdf07881fcaa2b835b29631feb84aec1"
+checksum = "0ad7880c5586b6b2104be451e3d7fc0f3800c84bda69e9ba81c828f87cb34267"
dependencies = [
"encoding_rs",
"log",
@@ -4147,31 +4393,31 @@ dependencies = [
"shared_child",
"tauri",
"tauri-plugin",
- "thiserror",
+ "thiserror 1.0.69",
"tokio",
]
[[package]]
name = "tauri-plugin-single-instance"
-version = "2.0.1"
+version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a25ac834491d089699a2bc9266a662faf373c9f779f05a2235bc6e4d9e61769a"
+checksum = "494d348f82cfa766df4d2ebd96fc38b9cada6d120f13a36fd11395180213ec74"
dependencies = [
- "log",
"serde",
"serde_json",
"tauri",
"tauri-plugin-deep-link",
- "thiserror",
+ "thiserror 2.0.6",
+ "tracing",
"windows-sys 0.59.0",
- "zbus",
+ "zbus 4.4.0",
]
[[package]]
name = "tauri-runtime"
-version = "2.0.1"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af12ad1af974b274ef1d32a94e6eba27a312b429ef28fcb98abc710df7f9151d"
+checksum = "cce18d43f80d4aba3aa8a0c953bbe835f3d0f2370aca75e8dbb14bd4bab27958"
dependencies = [
"dpi",
"gtk",
@@ -4181,16 +4427,16 @@ dependencies = [
"serde",
"serde_json",
"tauri-utils",
- "thiserror",
+ "thiserror 2.0.6",
"url",
"windows",
]
[[package]]
name = "tauri-runtime-wry"
-version = "2.0.1"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e45e88aa0b11b302d836e6ea3e507a6359044c4a8bc86b865ba99868c695753d"
+checksum = "9f442a38863e10129ffe2cec7bd09c2dcf8a098a3a27801a476a304d5bb991d2"
dependencies = [
"gtk",
"http",
@@ -4214,9 +4460,9 @@ dependencies = [
[[package]]
name = "tauri-utils"
-version = "2.0.1"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c38b0230d6880cf6dd07b6d7dd7789a0869f98ac12146e0d18d1c1049215a045"
+checksum = "9271a88f99b4adea0dc71d0baca4505475a0bbd139fb135f62958721aaa8fe54"
dependencies = [
"brotli",
"cargo_metadata",
@@ -4224,6 +4470,7 @@ dependencies = [
"dunce",
"glob",
"html5ever",
+ "http",
"infer",
"json-patch",
"kuchikiki",
@@ -4240,8 +4487,8 @@ dependencies = [
"serde_json",
"serde_with",
"swift-rs",
- "thiserror",
- "toml 0.8.2",
+ "thiserror 2.0.6",
+ "toml 0.8.19",
"url",
"urlpattern",
"uuid",
@@ -4260,9 +4507,9 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.13.0"
+version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [
"cfg-if",
"fastrand",
@@ -4290,22 +4537,42 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c"
[[package]]
name = "thiserror"
-version = "1.0.64"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47"
+dependencies = [
+ "thiserror-impl 2.0.6",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.64"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
]
[[package]]
@@ -4320,12 +4587,12 @@ dependencies = [
[[package]]
name = "time"
-version = "0.3.36"
+version = "0.3.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
dependencies = [
"deranged",
- "itoa 1.0.11",
+ "itoa 1.0.14",
"num-conv",
"powerfmt",
"serde",
@@ -4341,9 +4608,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
-version = "0.2.18"
+version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
dependencies = [
"num-conv",
"time-core",
@@ -4359,25 +4626,20 @@ dependencies = [
]
[[package]]
-name = "tinyvec"
-version = "1.8.0"
+name = "tinystr"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
dependencies = [
- "tinyvec_macros",
+ "displaydoc",
+ "zerovec",
]
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
-
[[package]]
name = "tokio"
-version = "1.40.0"
+version = "1.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
+checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
dependencies = [
"backtrace",
"bytes",
@@ -4399,7 +4661,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -4414,20 +4676,19 @@ dependencies = [
[[package]]
name = "tokio-rustls"
-version = "0.26.0"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
dependencies = [
"rustls",
- "rustls-pki-types",
"tokio",
]
[[package]]
name = "tokio-util"
-version = "0.7.12"
+version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
+checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078"
dependencies = [
"bytes",
"futures-core",
@@ -4450,21 +4711,21 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.8.2"
+version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
- "toml_edit 0.20.2",
+ "toml_edit 0.22.22",
]
[[package]]
name = "toml_datetime"
-version = "0.6.3"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
@@ -4475,24 +4736,35 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
"serde",
"serde_spanned",
"toml_datetime",
- "winnow",
+ "winnow 0.5.40",
]
[[package]]
name = "toml_edit"
-version = "0.20.2"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
+checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
dependencies = [
- "indexmap 2.6.0",
+ "indexmap 2.7.0",
+ "toml_datetime",
+ "winnow 0.5.40",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap 2.7.0",
"serde",
"serde_spanned",
"toml_datetime",
- "winnow",
+ "winnow 0.6.20",
]
[[package]]
@@ -4503,9 +4775,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
-version = "0.1.40"
+version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
dependencies = [
"pin-project-lite",
"tracing-attributes",
@@ -4514,29 +4786,29 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.27"
+version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
name = "tracing-core"
-version = "0.1.32"
+version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
dependencies = [
"once_cell",
]
[[package]]
name = "tray-icon"
-version = "0.19.0"
+version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "533fc2d4105e0e3d96ce1c71f2d308c9fbbe2ef9c587cab63dd627ab5bde218f"
+checksum = "d48a05076dd272615d03033bf04f480199f7d1b66a8ac64d75c625fc4a70c06b"
dependencies = [
"core-graphics",
"crossbeam-channel",
@@ -4549,7 +4821,7 @@ dependencies = [
"once_cell",
"png",
"serde",
- "thiserror",
+ "thiserror 1.0.69",
"windows-sys 0.59.0",
]
@@ -4638,26 +4910,11 @@ dependencies = [
"unic-common",
]
-[[package]]
-name = "unicode-bidi"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
-
[[package]]
name = "unicode-ident"
-version = "1.0.13"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
-dependencies = [
- "tinyvec",
-]
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "unicode-segmentation"
@@ -4688,9 +4945,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
-version = "2.5.2"
+version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
dependencies = [
"form_urlencoded",
"idna",
@@ -4723,10 +4980,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
-name = "uuid"
-version = "1.10.0"
+name = "utf16_iter"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "uuid"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
dependencies = [
"getrandom 0.2.15",
"rand 0.8.5",
@@ -4736,13 +5005,13 @@ dependencies = [
[[package]]
name = "uuid-macro-internal"
-version = "1.10.0"
+version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee1cd046f83ea2c4e920d6ee9f7c3537ef928d75dce5d84a87c2c5d6b3999a3a"
+checksum = "6b91f57fe13a38d0ce9e28a03463d8d3c2468ed03d75375110ec71d93b449a08"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -4816,9 +5085,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
-version = "0.2.93"
+version = "0.2.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
dependencies = [
"cfg-if",
"once_cell",
@@ -4827,36 +5096,36 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.93"
+version = "0.2.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
dependencies = [
"bumpalo",
"log",
- "once_cell",
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.43"
+version = "0.4.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed"
+checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
dependencies = [
"cfg-if",
"js-sys",
+ "once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.93"
+version = "0.2.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -4864,28 +5133,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.93"
+version = "0.2.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.93"
+version = "0.2.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
[[package]]
name = "wasm-streams"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd"
+checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
dependencies = [
"futures-util",
"js-sys",
@@ -4910,9 +5179,9 @@ dependencies = [
[[package]]
name = "wayland-client"
-version = "0.31.6"
+version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3f45d1222915ef1fd2057220c1d9d9624b7654443ea35c3877f7a52bd0a5a2d"
+checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280"
dependencies = [
"bitflags 2.6.0",
"rustix",
@@ -4922,9 +5191,9 @@ dependencies = [
[[package]]
name = "wayland-protocols"
-version = "0.32.4"
+version = "0.32.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b5755d77ae9040bb872a25026555ce4cb0ae75fd923e90d25fba07d81057de0"
+checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e"
dependencies = [
"bitflags 2.6.0",
"wayland-backend",
@@ -4956,9 +5225,9 @@ dependencies = [
[[package]]
name = "web-sys"
-version = "0.3.70"
+version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -4966,9 +5235,9 @@ dependencies = [
[[package]]
name = "webbrowser"
-version = "1.0.2"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e5f07fb9bc8de2ddfe6b24a71a75430673fd679e568c48b52716cef1cfae923"
+checksum = "ea9fe1ebb156110ff855242c1101df158b822487e4957b0556d9ffce9db0f535"
dependencies = [
"block2",
"core-foundation 0.10.0",
@@ -5048,7 +5317,7 @@ checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -5057,7 +5326,7 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886"
dependencies = [
- "thiserror",
+ "thiserror 1.0.69",
"windows",
"windows-core 0.58.0",
]
@@ -5147,7 +5416,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -5158,7 +5427,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
]
[[package]]
@@ -5443,6 +5712,15 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "winreg"
version = "0.52.0"
@@ -5454,15 +5732,26 @@ dependencies = [
]
[[package]]
-name = "wry"
-version = "0.44.1"
+name = "write16"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "440600584cfbd8b0d28eace95c1f2c253db05dae43780b79380aa1e868f04c73"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
+[[package]]
+name = "wry"
+version = "0.47.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61ce51277d65170f6379d8cda935c80e3c2d1f0ff712a123c8bddb11b31a4b73"
dependencies = [
"base64 0.22.1",
- "block",
- "cocoa",
- "core-graphics",
+ "block2",
+ "cookie",
"crossbeam-channel",
"dpi",
"dunce",
@@ -5475,15 +5764,19 @@ dependencies = [
"kuchikiki",
"libc",
"ndk",
- "objc",
- "objc_id",
+ "objc2",
+ "objc2-app-kit",
+ "objc2-foundation",
+ "objc2-ui-kit",
+ "objc2-web-kit",
"once_cell",
"percent-encoding",
"raw-window-handle",
"sha2",
"soup3",
"tao-macros",
- "thiserror",
+ "thiserror 1.0.69",
+ "url",
"webkit2gtk",
"webkit2gtk-sys",
"webview2-com",
@@ -5525,10 +5818,34 @@ dependencies = [
]
[[package]]
-name = "zbus"
-version = "4.0.1"
+name = "yoke"
+version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030"
+checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+ "synstructure",
+]
+
+[[package]]
+name = "zbus"
+version = "4.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725"
dependencies = [
"async-broadcast",
"async-executor",
@@ -5540,7 +5857,6 @@ dependencies = [
"async-task",
"async-trait",
"blocking",
- "derivative",
"enumflags2",
"event-listener",
"futures-core",
@@ -5554,28 +5870,71 @@ dependencies = [
"serde_repr",
"sha1",
"static_assertions",
- "tokio",
"tracing",
"uds_windows",
"windows-sys 0.52.0",
"xdg-home",
- "zbus_macros",
- "zbus_names",
- "zvariant",
+ "zbus_macros 4.4.0",
+ "zbus_names 3.0.0",
+ "zvariant 4.2.0",
+]
+
+[[package]]
+name = "zbus"
+version = "5.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1162094dc63b1629fcc44150bcceeaa80798cd28bcbe7fa987b65a034c258608"
+dependencies = [
+ "async-broadcast",
+ "async-recursion",
+ "async-trait",
+ "enumflags2",
+ "event-listener",
+ "futures-core",
+ "futures-util",
+ "hex",
+ "nix",
+ "ordered-stream",
+ "serde",
+ "serde_repr",
+ "static_assertions",
+ "tokio",
+ "tracing",
+ "uds_windows",
+ "windows-sys 0.59.0",
+ "winnow 0.6.20",
+ "xdg-home",
+ "zbus_macros 5.1.1",
+ "zbus_names 4.1.0",
+ "zvariant 5.1.0",
]
[[package]]
name = "zbus_macros"
-version = "4.0.1"
+version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7a3e850ff1e7217a3b7a07eba90d37fe9bb9e89a310f718afcde5885ca9b6d7"
+checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e"
dependencies = [
- "proc-macro-crate 1.3.1",
+ "proc-macro-crate 3.2.0",
"proc-macro2",
"quote",
- "regex",
- "syn 1.0.109",
- "zvariant_utils",
+ "syn 2.0.90",
+ "zvariant_utils 2.1.0",
+]
+
+[[package]]
+name = "zbus_macros"
+version = "5.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2cd2dcdce3e2727f7d74b7e33b5a89539b3cc31049562137faf7ae4eb86cd16d"
+dependencies = [
+ "proc-macro-crate 3.2.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+ "zbus_names 4.1.0",
+ "zvariant 5.1.0",
+ "zvariant_utils 3.0.2",
]
[[package]]
@@ -5586,7 +5945,19 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
dependencies = [
"serde",
"static_assertions",
- "zvariant",
+ "zvariant 4.2.0",
+]
+
+[[package]]
+name = "zbus_names"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "856b7a38811f71846fd47856ceee8bccaec8399ff53fb370247e66081ace647b"
+dependencies = [
+ "serde",
+ "static_assertions",
+ "winnow 0.6.20",
+ "zvariant 5.1.0",
]
[[package]]
@@ -5607,7 +5978,28 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.79",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+ "synstructure",
]
[[package]]
@@ -5617,39 +6009,103 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
[[package]]
-name = "zvariant"
-version = "4.0.0"
+name = "zerovec"
+version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e09e8be97d44eeab994d752f341e67b3b0d80512a8b315a0671d47232ef1b65"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "zvariant"
+version = "4.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe"
+dependencies = [
+ "endi",
+ "enumflags2",
+ "serde",
+ "static_assertions",
+ "zvariant_derive 4.2.0",
+]
+
+[[package]]
+name = "zvariant"
+version = "5.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1200ee6ac32f1e5a312e455a949a4794855515d34f9909f4a3e082d14e1a56f"
dependencies = [
"endi",
"enumflags2",
"serde",
"static_assertions",
"url",
- "zvariant_derive",
+ "winnow 0.6.20",
+ "zvariant_derive 5.1.0",
+ "zvariant_utils 3.0.2",
]
[[package]]
name = "zvariant_derive"
-version = "4.0.0"
+version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72a5857e2856435331636a9fbb415b09243df4521a267c5bedcd5289b4d5799e"
+checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449"
dependencies = [
- "proc-macro-crate 1.3.1",
+ "proc-macro-crate 3.2.0",
"proc-macro2",
"quote",
- "syn 1.0.109",
- "zvariant_utils",
+ "syn 2.0.90",
+ "zvariant_utils 2.1.0",
+]
+
+[[package]]
+name = "zvariant_derive"
+version = "5.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "687e3b97fae6c9104fbbd36c73d27d149abf04fb874e2efbd84838763daa8916"
+dependencies = [
+ "proc-macro-crate 3.2.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.90",
+ "zvariant_utils 3.0.2",
]
[[package]]
name = "zvariant_utils"
-version = "1.1.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172"
+checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
dependencies = [
"proc-macro2",
"quote",
- "syn 1.0.109",
+ "syn 2.0.90",
+]
+
+[[package]]
+name = "zvariant_utils"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20d1d011a38f12360e5fcccceeff5e2c42a8eb7f27f0dcba97a0862ede05c9c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "serde",
+ "static_assertions",
+ "syn 2.0.90",
+ "winnow 0.6.20",
]
diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml
index 7c6483cf..bed70858 100644
--- a/desktop/src-tauri/Cargo.toml
+++ b/desktop/src-tauri/Cargo.toml
@@ -68,7 +68,7 @@ features = ["vendored"]
[dependencies.rustbreak]
version = "2"
-features = ["bin_enc"] # You can also use "yaml_enc" or "bin_enc"
+features = [] # You can also use "yaml_enc" or "bin_enc"
[dependencies.reqwest]
version = "0.12"
diff --git a/desktop/src-tauri/src/auth.rs b/desktop/src-tauri/src/auth.rs
index 82e8da17..61446a07 100644
--- a/desktop/src-tauri/src/auth.rs
+++ b/desktop/src-tauri/src/auth.rs
@@ -90,9 +90,7 @@ fn recieve_handshake_logic(app: &AppHandle, path: String) -> Result<(), RemoteAc
let path_chunks: Vec<&str> = path.split("/").collect();
if path_chunks.len() != 3 {
app.emit("auth/failed", ()).unwrap();
- return Err(RemoteAccessError::GenericErrror(
- "Invalid number of handshake chunks".to_string(),
- ));
+ return Err(RemoteAccessError::InvalidResponse);
}
let base_url = {
@@ -163,9 +161,7 @@ async fn auth_initiate_wrapper() -> Result<(), RemoteAccessError> {
let response = client.post(endpoint.to_string()).json(&body).send().await?;
if response.status() != 200 {
- return Err("Failed to create redirect URL. Please try again later."
- .to_string()
- .into());
+ return Err(RemoteAccessError::InvalidRedirect);
}
let redir_url = response.text().await?;
@@ -187,6 +183,18 @@ pub async fn auth_initiate<'a>() -> Result<(), String> {
Ok(())
}
+#[tauri::command]
+pub fn retry_connect(state: tauri::State<'_, Mutex
>) -> Result<(), ()> {
+ let (app_status, user) = setup()?;
+
+ let mut guard = state.lock().unwrap();
+ guard.status = app_status;
+ guard.user = user;
+ drop(guard);
+
+ Ok(())
+}
+
pub fn setup() -> Result<(AppStatus, Option), ()> {
let data = DB.borrow_data().unwrap();
diff --git a/desktop/src-tauri/src/db.rs b/desktop/src-tauri/src/db.rs
index ea7f922c..38b11fcf 100644
--- a/desktop/src-tauri/src/db.rs
+++ b/desktop/src-tauri/src/db.rs
@@ -6,8 +6,9 @@ use std::{
};
use directories::BaseDirs;
-use rustbreak::{deser::Bincode, PathDatabase};
-use serde::{Deserialize, Serialize};
+use log::debug;
+use rustbreak::{DeSerError, DeSerializer, PathDatabase};
+use serde::{de::DeserializeOwned, Deserialize, Serialize};
use url::Url;
use crate::DB;
@@ -20,21 +21,36 @@ pub struct DatabaseAuth {
pub client_id: String,
}
+// Strings are version names for a particular game
#[derive(Serialize, Clone, Deserialize)]
+#[serde(tag = "type")]
pub enum DatabaseGameStatus {
- Remote,
- Downloading,
- Installed,
- Updating,
+ Remote {},
+ Queued { version_name: String },
+ Downloading { version_name: String },
+ SetupRequired { version_name: String },
+ Installed { version_name: String },
+ Updating { version_name: String },
+ Uninstalling {},
+}
- Uninstalling,
+#[derive(Serialize, Deserialize, Clone)]
+#[serde(rename_all = "camelCase")]
+pub struct GameVersion {
+ pub version_index: usize,
+ pub version_name: String,
+ pub launch_command: String,
+ pub setup_command: String,
+ pub platform: String,
}
#[derive(Serialize, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DatabaseGames {
pub install_dirs: Vec,
+ // Guaranteed to exist if the game also exists in the app state map
pub games_statuses: HashMap,
+ pub game_versions: HashMap>,
}
#[derive(Serialize, Clone, Deserialize)]
@@ -47,8 +63,22 @@ pub struct Database {
pub static DATA_ROOT_DIR: LazyLock> =
LazyLock::new(|| Mutex::new(BaseDirs::new().unwrap().data_dir().join("drop")));
+// Custom JSON serializer to support everything we need
+#[derive(Debug, Default, Clone)]
+pub struct DropDatabaseSerializer;
+
+impl DeSerializer for DropDatabaseSerializer {
+ fn serialize(&self, val: &T) -> rustbreak::error::DeSerResult> {
+ serde_json::to_vec(val).map_err(|e| DeSerError::Internal(e.to_string()))
+ }
+
+ fn deserialize(&self, s: R) -> rustbreak::error::DeSerResult {
+ serde_json::from_reader(s).map_err(|e| DeSerError::Internal(e.to_string()))
+ }
+}
+
pub type DatabaseInterface =
- rustbreak::Database;
+ rustbreak::Database;
pub trait DatabaseImpls {
fn set_up_database() -> DatabaseInterface;
@@ -61,26 +91,31 @@ impl DatabaseImpls for DatabaseInterface {
let db_path = data_root_dir.join("drop.db");
let games_base_dir = data_root_dir.join("games");
- let default = Database {
- auth: None,
- base_url: "".to_string(),
- games: DatabaseGames {
- install_dirs: vec![games_base_dir.to_str().unwrap().to_string()],
- games_statuses: HashMap::new(),
- },
- };
+ debug!("Creating data directory at {:?}", data_root_dir);
+ create_dir_all(data_root_dir.clone()).unwrap();
+ debug!("Creating games directory");
+ create_dir_all(games_base_dir.clone()).unwrap();
+
#[allow(clippy::let_and_return)]
- let db = match fs::exists(db_path.clone()).unwrap() {
+ let exists = fs::exists(db_path.clone()).unwrap();
+
+ match exists {
true => PathDatabase::load_from_path(db_path).expect("Database loading failed"),
false => {
- create_dir_all(data_root_dir.clone()).unwrap();
- create_dir_all(games_base_dir.clone()).unwrap();
-
- PathDatabase::create_at_path(db_path, default).unwrap()
+ let default = Database {
+ auth: None,
+ base_url: "".to_string(),
+ games: DatabaseGames {
+ install_dirs: vec![games_base_dir.to_str().unwrap().to_string()],
+ games_statuses: HashMap::new(),
+ game_versions: HashMap::new(),
+ },
+ };
+ debug!("Creating database at path {}", db_path.as_os_str().to_str().unwrap());
+ PathDatabase::create_at_path(db_path, default)
+ .expect("Database could not be created")
}
- };
-
- db
+ }
}
fn database_is_set_up(&self) -> bool {
@@ -94,7 +129,7 @@ impl DatabaseImpls for DatabaseInterface {
}
#[tauri::command]
-pub fn add_new_download_dir(new_dir: String) -> Result<(), String> {
+pub fn add_download_dir(new_dir: String) -> Result<(), String> {
// Check the new directory is all good
let new_dir_path = Path::new(&new_dir);
if new_dir_path.exists() {
@@ -107,8 +142,8 @@ pub fn add_new_download_dir(new_dir: String) -> Result<(), String> {
let dir_contents = new_dir_path
.read_dir()
.map_err(|e| format!("Unable to check directory contents: {}", e))?;
- if dir_contents.count() == 0 {
- return Err("Path is not empty".to_string());
+ if dir_contents.count() != 0 {
+ return Err("Directory is not empty".to_string());
}
} else {
create_dir_all(new_dir_path)
@@ -117,8 +152,33 @@ pub fn add_new_download_dir(new_dir: String) -> Result<(), String> {
// Add it to the dictionary
let mut lock = DB.borrow_data_mut().unwrap();
+ if lock.games.install_dirs.contains(&new_dir) {
+ return Err("Download directory already used".to_string());
+ }
lock.games.install_dirs.push(new_dir);
drop(lock);
+ DB.save().unwrap();
Ok(())
}
+
+#[tauri::command]
+pub fn delete_download_dir(index: usize) -> Result<(), String> {
+ let mut lock = DB.borrow_data_mut().unwrap();
+ lock.games.install_dirs.remove(index);
+ drop(lock);
+ DB.save().unwrap();
+
+ Ok(())
+}
+
+// Will, in future, return disk/remaining size
+// Just returns the directories that have been set up
+#[tauri::command]
+pub fn fetch_download_dir_stats() -> Result, String> {
+ let lock = DB.borrow_data().unwrap();
+ let directories = lock.games.install_dirs.clone();
+ drop(lock);
+
+ Ok(directories)
+}
diff --git a/desktop/src-tauri/src/downloads/download_agent.rs b/desktop/src-tauri/src/downloads/download_agent.rs
index 9ae8ba81..52855cda 100644
--- a/desktop/src-tauri/src/downloads/download_agent.rs
+++ b/desktop/src-tauri/src/downloads/download_agent.rs
@@ -1,20 +1,24 @@
use crate::auth::generate_authorization_header;
use crate::db::DatabaseImpls;
use crate::downloads::manifest::{DropDownloadContext, DropManifest};
+use crate::downloads::progress_object::ProgressHandle;
use crate::remote::RemoteAccessError;
use crate::DB;
-use log::info;
+use log::{debug, error, info};
use rayon::ThreadPoolBuilder;
use std::fmt::{Display, Formatter};
use std::fs::{create_dir_all, File};
+use std::io;
use std::path::Path;
-use std::sync::Mutex;
+use std::sync::mpsc::Sender;
+use std::sync::{Arc, Mutex};
use urlencoding::encode;
#[cfg(target_os = "linux")]
use rustix::fs::{fallocate, FallocateFlags};
use super::download_logic::download_game_chunk;
+use super::download_manager::DownloadManagerSignal;
use super::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag};
use super::progress_object::ProgressObject;
@@ -25,51 +29,66 @@ pub struct GameDownloadAgent {
pub target_download_dir: usize,
contexts: Mutex>,
pub manifest: Mutex>,
- pub progress: ProgressObject,
+ pub progress: Arc,
+ sender: Sender,
}
#[derive(Debug)]
pub enum GameDownloadError {
- CommunicationError(RemoteAccessError),
- ChecksumError,
- SetupError(String),
- LockError,
+ Communication(RemoteAccessError),
+ Checksum,
+ Setup(SetupError),
+ Lock,
+ IoError(io::Error),
+ DownloadError,
+}
+
+#[derive(Debug)]
+pub enum SetupError {
+ Context,
}
impl Display for GameDownloadError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
- GameDownloadError::CommunicationError(error) => write!(f, "{}", error),
- GameDownloadError::SetupError(error) => write!(f, "{}", error),
- GameDownloadError::LockError => write!(f, "Failed to acquire lock. Something has gone very wrong internally. Please restart the application"),
- GameDownloadError::ChecksumError => write!(f, "Checksum failed to validate for download"),
+ GameDownloadError::Communication(error) => write!(f, "{}", error),
+ GameDownloadError::Setup(error) => write!(f, "{:?}", error),
+ GameDownloadError::Lock => write!(f, "Failed to acquire lock. Something has gone very wrong internally. Please restart the application"),
+ GameDownloadError::Checksum => write!(f, "Checksum failed to validate for download"),
+ GameDownloadError::IoError(error) => write!(f, "{}", error),
+ GameDownloadError::DownloadError => write!(f, "Download failed. See Download Manager status for specific error"),
}
}
}
impl GameDownloadAgent {
- pub fn new(id: String, version: String, target_download_dir: usize) -> Self {
+ pub fn new(
+ id: String,
+ version: String,
+ target_download_dir: usize,
+ sender: Sender,
+ ) -> Self {
// Don't run by default
- let status = DownloadThreadControl::new(DownloadThreadControlFlag::Stop);
+ let control_flag = DownloadThreadControl::new(DownloadThreadControlFlag::Stop);
Self {
id,
version,
- control_flag: status.clone(),
+ control_flag,
manifest: Mutex::new(None),
target_download_dir,
contexts: Mutex::new(Vec::new()),
- progress: ProgressObject::new(0, 0),
+ progress: Arc::new(ProgressObject::new(0, 0, sender.clone())),
+ sender,
}
}
// Blocking
- // Requires mutable self
- pub fn setup_download(&mut self) -> Result<(), GameDownloadError> {
+ pub fn setup_download(&self) -> Result<(), GameDownloadError> {
self.ensure_manifest_exists()?;
info!("Ensured manifest exists");
- self.generate_contexts()?;
- info!("Generated contexts");
+ self.ensure_contexts()?;
+ info!("Ensured contexts exists");
self.control_flag.set(DownloadThreadControlFlag::Go);
@@ -77,23 +96,23 @@ impl GameDownloadAgent {
}
// Blocking
- pub fn download(&mut self) -> Result<(), GameDownloadError> {
+ pub fn download(&self) -> Result<(), GameDownloadError> {
self.setup_download()?;
- self.run();
+ self.set_progress_object_params();
+ self.run().map_err(|_| GameDownloadError::DownloadError)?;
Ok(())
}
- pub fn ensure_manifest_exists(&mut self) -> Result<(), GameDownloadError> {
+ pub fn ensure_manifest_exists(&self) -> Result<(), GameDownloadError> {
if self.manifest.lock().unwrap().is_some() {
return Ok(());
}
- // Explicitly propagate error
self.download_manifest()
}
- fn download_manifest(&mut self) -> Result<(), GameDownloadError> {
+ fn download_manifest(&self) -> Result<(), GameDownloadError> {
let base_url = DB.fetch_base_url();
let manifest_url = base_url
.join(
@@ -115,35 +134,52 @@ impl GameDownloadAgent {
.unwrap();
if response.status() != 200 {
- return Err(GameDownloadError::CommunicationError(
- format!(
- "Failed to download game manifest: {} {}",
+ return Err(GameDownloadError::Communication(
+ RemoteAccessError::ManifestDownloadFailed(
response.status(),
- response.text().unwrap()
- )
- .into(),
+ response.text().unwrap(),
+ ),
));
}
let manifest_download = response.json::().unwrap();
- let length = manifest_download
- .values()
- .map(|chunk| {
- return chunk.lengths.iter().sum::();
- })
- .sum::();
- let chunk_count = manifest_download
- .values()
- .map(|chunk| chunk.lengths.len())
- .sum();
- self.progress = ProgressObject::new(length, chunk_count);
if let Ok(mut manifest) = self.manifest.lock() {
*manifest = Some(manifest_download);
return Ok(());
}
- Err(GameDownloadError::LockError)
+ Err(GameDownloadError::Lock)
+ }
+
+ fn set_progress_object_params(&self) {
+ // Avoid re-setting it
+ if self.progress.get_max() != 0 {
+ return;
+ }
+
+ let lock = self.contexts.lock().unwrap();
+ let length = lock.len();
+
+ let chunk_count = lock.iter().map(|chunk| chunk.length).sum();
+
+ debug!("Setting ProgressObject max to {}", chunk_count);
+ self.progress.set_max(chunk_count);
+ debug!("Setting ProgressObject size to {}", length);
+ self.progress.set_size(length);
+ debug!("Setting ProgressObject time to now");
+ self.progress.set_time_now();
+ }
+
+ pub fn ensure_contexts(&self) -> Result<(), GameDownloadError> {
+ let context_lock = self.contexts.lock().unwrap();
+ if !context_lock.is_empty() {
+ return Ok(());
+ }
+ drop(context_lock);
+
+ self.generate_contexts()?;
+ Ok(())
}
pub fn generate_contexts(&self) -> Result<(), GameDownloadError> {
@@ -152,7 +188,6 @@ impl GameDownloadAgent {
drop(db_lock);
let manifest = self.manifest.lock().unwrap().clone().unwrap();
- let version = self.version.clone();
let game_id = self.id.clone();
let data_base_dir_path = Path::new(&data_base_dir);
@@ -173,19 +208,20 @@ impl GameDownloadAgent {
for (index, length) in chunk.lengths.iter().enumerate() {
contexts.push(DropDownloadContext {
file_name: raw_path.to_string(),
- version: version.to_string(),
+ version: chunk.version_name.to_string(),
offset: running_offset,
index,
game_id: game_id.to_string(),
path: path.clone(),
checksum: chunk.checksums[index].clone(),
+ length: *length,
});
running_offset += *length as u64;
}
#[cfg(target_os = "linux")]
if running_offset > 0 {
- fallocate(file, FallocateFlags::empty(), 0, running_offset).unwrap();
+ let _ = fallocate(file, FallocateFlags::empty(), 0, running_offset);
}
}
@@ -194,35 +230,69 @@ impl GameDownloadAgent {
return Ok(());
}
- Err(GameDownloadError::SetupError(
- String::from("Failed to generate download contexts"),
- ))
+ Err(GameDownloadError::Setup(SetupError::Context))
}
- pub fn run(&self) {
- const DOWNLOAD_MAX_THREADS: usize = 4;
+ pub fn run(&self) -> Result<(), ()> {
+ info!("downloading game: {}", self.id);
+ const DOWNLOAD_MAX_THREADS: usize = 1;
let pool = ThreadPoolBuilder::new()
.num_threads(DOWNLOAD_MAX_THREADS)
.build()
.unwrap();
+ let completed_indexes = Arc::new(Mutex::new(Vec::new()));
+ let completed_indexes_loop_arc = completed_indexes.clone();
+
pool.scope(move |scope| {
let contexts = self.contexts.lock().unwrap();
for (index, context) in contexts.iter().enumerate() {
let context = context.clone();
let control_flag = self.control_flag.clone(); // Clone arcs
- let progress = self.progress.get(index);
+ let progress = self.progress.get(index); // Clone arcs
+ let progress_handle = ProgressHandle::new(progress, self.progress.clone());
+ let completed_indexes_ref = completed_indexes_loop_arc.clone();
scope.spawn(move |_| {
- info!(
- "starting download for file {} {}",
- context.file_name, context.index
- );
- download_game_chunk(context, control_flag, progress).unwrap();
+ match download_game_chunk(context.clone(), control_flag, progress_handle) {
+ Ok(res) => {
+ if res {
+ let mut lock = completed_indexes_ref.lock().unwrap();
+ lock.push(index);
+ }
+ }
+ Err(e) => {
+ error!("GameDownloadError: {}", e);
+ self.sender.send(DownloadManagerSignal::Error(e)).unwrap();
+ }
+ }
});
}
- })
+ });
+
+ let mut context_lock = self.contexts.lock().unwrap();
+ let mut completed_lock = completed_indexes.lock().unwrap();
+
+ // Sort desc so we don't have to modify indexes
+ completed_lock.sort_by(|a, b| b.cmp(a));
+
+ for index in completed_lock.iter() {
+ context_lock.remove(*index);
+ }
+
+ // If we're not out of contexts, we're not done, so we don't fire completed
+ if !context_lock.is_empty() {
+ info!("da for {} exited without completing", self.id.clone());
+ return Ok(());
+ }
+
+ // We've completed
+ self.sender
+ .send(DownloadManagerSignal::Completed(self.id.clone()))
+ .unwrap();
+
+ Ok(())
}
}
diff --git a/desktop/src-tauri/src/downloads/download_commands.rs b/desktop/src-tauri/src/downloads/download_commands.rs
index 54b93152..23b8bab8 100644
--- a/desktop/src-tauri/src/downloads/download_commands.rs
+++ b/desktop/src-tauri/src/downloads/download_commands.rs
@@ -1,53 +1,57 @@
-use std::sync::{Arc, Mutex};
+use std::sync::Mutex;
-use log::info;
-use rayon::spawn;
-
-use crate::{downloads::download_agent::GameDownloadAgent, AppState};
+use crate::AppState;
#[tauri::command]
pub fn download_game(
game_id: String,
game_version: String,
+ install_dir: usize,
state: tauri::State<'_, Mutex>,
) -> Result<(), String> {
- info!("beginning game download...");
-
- let mut download_agent = GameDownloadAgent::new(game_id.clone(), game_version.clone(), 0);
- // Setup download requires mutable
- download_agent.setup_download().unwrap();
-
- let mut lock: std::sync::MutexGuard<'_, AppState> = state.lock().unwrap();
- let download_agent_ref = Arc::new(download_agent);
- lock.game_downloads
- .insert(game_id, download_agent_ref.clone());
-
- // Run it in another thread
- spawn(move || {
- // Run doesn't require mutable
- download_agent_ref.clone().run();
- });
-
- Ok(())
+ state
+ .lock()
+ .unwrap()
+ .download_manager
+ .queue_game(game_id, game_version, install_dir)
+ .map_err(|_| "An error occurred while communicating with the download manager.".to_string())
}
#[tauri::command]
-pub fn get_game_download_progress(
- state: tauri::State<'_, Mutex>,
- game_id: String,
-) -> Result {
- let download_agent = use_download_agent(state, game_id)?;
-
- let progress = &download_agent.progress;
-
- Ok(progress.get_progress())
+pub fn pause_game_downloads(state: tauri::State<'_, Mutex>) {
+ state.lock().unwrap().download_manager.pause_downloads()
}
+#[tauri::command]
+pub fn resume_game_downloads(state: tauri::State<'_, Mutex>) {
+ state.lock().unwrap().download_manager.resume_downloads()
+}
+
+#[tauri::command]
+pub fn move_game_in_queue(
+ state: tauri::State<'_, Mutex>,
+ old_index: usize,
+ new_index: usize,
+) {
+ state
+ .lock()
+ .unwrap()
+ .download_manager
+ .rearrange(old_index, new_index)
+}
+
+/*
+#[tauri::command]
+pub fn get_current_write_speed(state: tauri::State<'_, Mutex>) {}
+*/
+
+/*
fn use_download_agent(
state: tauri::State<'_, Mutex>,
game_id: String,
) -> Result, String> {
let lock = state.lock().unwrap();
- let download_agent = lock.game_downloads.get(&game_id).ok_or("Invalid game ID")?;
+ let download_agent = lock.download_manager.get(&game_id).ok_or("Invalid game ID")?;
Ok(download_agent.clone()) // Clones the Arc, not the underlying data structure
}
+*/
diff --git a/desktop/src-tauri/src/downloads/download_logic.rs b/desktop/src-tauri/src/downloads/download_logic.rs
index 2a0c21f2..6735c56b 100644
--- a/desktop/src-tauri/src/downloads/download_logic.rs
+++ b/desktop/src-tauri/src/downloads/download_logic.rs
@@ -3,21 +3,21 @@ use crate::db::DatabaseImpls;
use crate::downloads::manifest::DropDownloadContext;
use crate::remote::RemoteAccessError;
use crate::DB;
+use log::warn;
use md5::{Context, Digest};
use reqwest::blocking::Response;
use std::io::Read;
-use std::sync::atomic::AtomicUsize;
use std::{
fs::{File, OpenOptions},
- io::{self, BufWriter, ErrorKind, Seek, SeekFrom, Write},
+ io::{self, BufWriter, Seek, SeekFrom, Write},
path::PathBuf,
- sync::Arc,
};
use urlencoding::encode;
use super::download_agent::GameDownloadError;
use super::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag};
+use super::progress_object::ProgressHandle;
pub struct DropWriter {
hasher: Context,
@@ -39,17 +39,19 @@ impl DropWriter {
// Write automatically pushes to file and hasher
impl Write for DropWriter {
fn write(&mut self, buf: &[u8]) -> io::Result {
+ /*
self.hasher.write_all(buf).map_err(|e| {
io::Error::new(
ErrorKind::Other,
format!("Unable to write to hasher: {}", e),
)
})?;
+ */
self.destination.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
- self.hasher.flush()?;
+ // self.hasher.flush()?;
self.destination.flush()
}
}
@@ -64,7 +66,7 @@ pub struct DropDownloadPipeline {
pub source: R,
pub destination: DropWriter,
pub control_flag: DownloadThreadControl,
- pub progress: Arc,
+ pub progress: ProgressHandle,
pub size: usize,
}
impl DropDownloadPipeline {
@@ -72,7 +74,7 @@ impl DropDownloadPipeline {
source: Response,
destination: DropWriter,
control_flag: DownloadThreadControl,
- progress: Arc,
+ progress: ProgressHandle,
size: usize,
) -> Self {
Self {
@@ -99,8 +101,7 @@ impl DropDownloadPipeline {
current_size += bytes_read;
buf_writer.write_all(©_buf[0..bytes_read])?;
- self.progress
- .fetch_add(bytes_read, std::sync::atomic::Ordering::Relaxed);
+ self.progress.add(bytes_read);
if current_size == self.size {
break;
@@ -119,10 +120,11 @@ impl DropDownloadPipeline {
pub fn download_game_chunk(
ctx: DropDownloadContext,
control_flag: DownloadThreadControl,
- progress: Arc,
+ progress: ProgressHandle,
) -> Result {
// If we're paused
if control_flag.get() == DownloadThreadControlFlag::Stop {
+ progress.set(0);
return Ok(false);
}
@@ -146,7 +148,14 @@ pub fn download_game_chunk(
.get(chunk_url)
.header("Authorization", header)
.send()
- .map_err(|e| GameDownloadError::CommunicationError(RemoteAccessError::FetchError(e)))?;
+ .map_err(|e| GameDownloadError::Communication(e.into()))?;
+
+ if response.status() != 200 {
+ warn!("{}", response.text().unwrap());
+ return Err(GameDownloadError::Communication(
+ RemoteAccessError::InvalidCodeError(400),
+ ));
+ }
let mut destination = DropWriter::new(ctx.path);
@@ -158,10 +167,8 @@ pub fn download_game_chunk(
let content_length = response.content_length();
if content_length.is_none() {
- return Err(GameDownloadError::CommunicationError(
- RemoteAccessError::GenericErrror(
- "Invalid download endpoint, missing Content-Length header.".to_owned(),
- ),
+ return Err(GameDownloadError::Communication(
+ RemoteAccessError::InvalidResponse,
));
}
@@ -173,17 +180,21 @@ pub fn download_game_chunk(
content_length.unwrap().try_into().unwrap(),
);
- let completed = pipeline.copy().unwrap();
+ let completed = pipeline.copy().map_err(GameDownloadError::IoError)?;
if !completed {
return Ok(false);
};
- let checksum = pipeline.finish().unwrap();
+ /*
+ let checksum = pipeline
+ .finish()
+ .map_err(|e| GameDownloadError::IoError(e))?;
let res = hex::encode(checksum.0);
if res != ctx.checksum {
- return Err(GameDownloadError::ChecksumError);
+ return Err(GameDownloadError::Checksum);
}
+ */
Ok(true)
}
diff --git a/desktop/src-tauri/src/downloads/download_manager.rs b/desktop/src-tauri/src/downloads/download_manager.rs
new file mode 100644
index 00000000..f04135fa
--- /dev/null
+++ b/desktop/src-tauri/src/downloads/download_manager.rs
@@ -0,0 +1,191 @@
+use std::{
+ any::Any,
+ collections::VecDeque,
+ fmt::Debug,
+ sync::{
+ mpsc::{SendError, Sender},
+ Arc, Mutex, MutexGuard,
+ },
+ thread::JoinHandle,
+};
+
+use log::info;
+use serde::Serialize;
+
+use super::{
+ download_agent::{GameDownloadAgent, GameDownloadError},
+ download_manager_builder::CurrentProgressObject,
+ progress_object::ProgressObject,
+ queue::Queue,
+};
+
+pub enum DownloadManagerSignal {
+ /// Resumes (or starts) the DownloadManager
+ Go,
+ /// Pauses the DownloadManager
+ Stop,
+ /// Called when a GameDownloadAgent has fully completed a download.
+ Completed(String),
+ /// Generates and appends a GameDownloadAgent
+ /// to the registry and queue
+ Queue(String, String, usize),
+ /// Tells the Manager to stop the current
+ /// download and return
+ Finish,
+ Cancel,
+ /// Any error which occurs in the agent
+ Error(GameDownloadError),
+ /// Pushes UI update
+ Update,
+}
+pub enum DownloadManagerStatus {
+ Downloading,
+ Paused,
+ Empty,
+ Error(GameDownloadError),
+}
+
+#[derive(Serialize, Clone)]
+pub enum GameDownloadStatus {
+ Queued,
+ Downloading,
+ Paused,
+ Error,
+}
+
+/// Accessible front-end for the DownloadManager
+///
+/// The system works entirely through signals, both internally and externally,
+/// all of which are accessible through the DownloadManagerSignal type, but
+/// should not be used directly. Rather, signals are abstracted through this
+/// interface.
+///
+/// The actual download queue may be accessed through the .edit() function,
+/// which provides raw access to the underlying queue.
+/// THIS EDITING IS BLOCKING!!!
+pub struct DownloadManager {
+ terminator: JoinHandle>,
+ download_queue: Queue,
+ progress: CurrentProgressObject,
+ command_sender: Sender,
+}
+pub struct GameDownloadAgentQueueStandin {
+ pub id: String,
+ pub status: Mutex,
+ pub progress: Arc,
+}
+impl From> for GameDownloadAgentQueueStandin {
+ fn from(value: Arc) -> Self {
+ Self {
+ id: value.id.clone(),
+ status: Mutex::from(GameDownloadStatus::Queued),
+ progress: value.progress.clone(),
+ }
+ }
+}
+impl Debug for GameDownloadAgentQueueStandin {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("GameDownloadAgentQueueStandin")
+ .field("id", &self.id)
+ .finish()
+ }
+}
+
+#[allow(dead_code)]
+impl DownloadManager {
+ pub fn new(
+ terminator: JoinHandle>,
+ download_queue: Queue,
+ progress: CurrentProgressObject,
+ command_sender: Sender,
+ ) -> Self {
+ Self {
+ terminator,
+ download_queue,
+ progress,
+ command_sender,
+ }
+ }
+
+ pub fn queue_game(
+ &self,
+ id: String,
+ version: String,
+ target_download_dir: usize,
+ ) -> Result<(), SendError> {
+ info!("Adding game id {}", id);
+ self.command_sender.send(DownloadManagerSignal::Queue(
+ id,
+ version,
+ target_download_dir,
+ ))?;
+ self.command_sender.send(DownloadManagerSignal::Go)
+ }
+ pub fn edit(&self) -> MutexGuard<'_, VecDeque>> {
+ self.download_queue.edit()
+ }
+ pub fn read_queue(&self) -> VecDeque> {
+ self.download_queue.read()
+ }
+ pub fn get_current_game_download_progress(&self) -> Option {
+ let progress_object = (*self.progress.lock().unwrap()).clone()?;
+ Some(progress_object.get_progress())
+ }
+ pub fn rearrange_string(&self, id: String, new_index: usize) {
+ let mut queue = self.edit();
+ let current_index = get_index_from_id(&mut queue, id).unwrap();
+ let to_move = queue.remove(current_index).unwrap();
+ queue.insert(new_index, to_move);
+ self.command_sender
+ .send(DownloadManagerSignal::Update)
+ .unwrap();
+ }
+ pub fn rearrange(&self, current_index: usize, new_index: usize) {
+ let needs_pause = current_index == 0 || new_index == 0;
+ if needs_pause {
+ self.command_sender
+ .send(DownloadManagerSignal::Cancel)
+ .unwrap();
+ }
+
+ info!("moving {} to {}", current_index, new_index);
+
+ let mut queue = self.edit();
+ let to_move = queue.remove(current_index).unwrap();
+ queue.insert(new_index, to_move);
+
+ info!("new queue: {:?}", queue);
+
+ if needs_pause {
+ self.command_sender.send(DownloadManagerSignal::Go).unwrap();
+ }
+ self.command_sender
+ .send(DownloadManagerSignal::Update)
+ .unwrap();
+ }
+ pub fn pause_downloads(&self) {
+ self.command_sender
+ .send(DownloadManagerSignal::Stop)
+ .unwrap();
+ }
+ pub fn resume_downloads(&self) {
+ self.command_sender.send(DownloadManagerSignal::Go).unwrap();
+ }
+ pub fn ensure_terminated(self) -> Result, Box> {
+ self.command_sender
+ .send(DownloadManagerSignal::Finish)
+ .unwrap();
+ self.terminator.join()
+ }
+}
+
+/// Takes in the locked value from .edit() and attempts to
+/// get the index of whatever game_id is passed in
+fn get_index_from_id(
+ queue: &mut MutexGuard<'_, VecDeque>>,
+ id: String,
+) -> Option {
+ queue
+ .iter()
+ .position(|download_agent| download_agent.id == id)
+}
diff --git a/desktop/src-tauri/src/downloads/download_manager_builder.rs b/desktop/src-tauri/src/downloads/download_manager_builder.rs
new file mode 100644
index 00000000..1b338533
--- /dev/null
+++ b/desktop/src-tauri/src/downloads/download_manager_builder.rs
@@ -0,0 +1,347 @@
+use std::{
+ collections::HashMap,
+ sync::{
+ mpsc::{channel, Receiver, Sender},
+ Arc, Mutex,
+ },
+ thread::{spawn, JoinHandle},
+};
+
+use log::{error, info};
+use tauri::{AppHandle, Emitter};
+
+use crate::{
+ db::DatabaseGameStatus,
+ library::{on_game_complete, GameUpdateEvent, QueueUpdateEvent, QueueUpdateEventQueueData},
+ DB,
+};
+
+use super::{
+ download_agent::{GameDownloadAgent, GameDownloadError},
+ download_manager::{
+ DownloadManager, DownloadManagerSignal, DownloadManagerStatus,
+ GameDownloadAgentQueueStandin, GameDownloadStatus,
+ },
+ download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag},
+ progress_object::ProgressObject,
+ queue::Queue,
+};
+
+/*
+
+Welcome to the download manager, the most overengineered, glorious piece of bullshit.
+
+The download manager takes a queue of game_ids and their associated
+GameDownloadAgents, and then, one-by-one, executes them. It provides an interface
+to interact with the currently downloading agent, and manage the queue.
+
+When the DownloadManager is initialised, it is designed to provide a reference
+which can be used to provide some instructions (the DownloadManagerInterface),
+but other than that, it runs without any sort of interruptions.
+
+It does this by opening up two data structures. Primarily is the command_receiver,
+and mpsc (multi-channel-single-producer) which allows commands to be sent from
+the Interface, and queued up for the Manager to process.
+
+These have been mapped in the DownloadManagerSignal docs.
+
+The other way to interact with the DownloadManager is via the donwload_queue,
+which is just a collection of ids which may be rearranged to suit
+whichever download queue order is required.
+
++----------------------------------------------------------------------------+
+| DO NOT ATTEMPT TO ADD OR REMOVE FROM THE QUEUE WITHOUT USING SIGNALS!! |
+| THIS WILL CAUSE A DESYNC BETWEEN THE DOWNLOAD AGENT REGISTRY AND THE QUEUE |
+| WHICH HAS NOT BEEN ACCOUNTED FOR |
++----------------------------------------------------------------------------+
+
+This download queue does not actually own any of the GameDownloadAgents. It is
+simply a id-based reference system. The actual Agents are stored in the
+download_agent_registry HashMap, as ordering is no issue here. This is why
+appending or removing from the download_queue must be done via signals.
+
+Behold, my madness - quexeky
+
+*/
+
+// Refactored to consolidate this type. It's a monster.
+pub type CurrentProgressObject = Arc>>>;
+
+pub struct DownloadManagerBuilder {
+ download_agent_registry: HashMap>,
+ download_queue: Queue,
+ command_receiver: Receiver,
+ sender: Sender,
+ progress: CurrentProgressObject,
+ status: Arc>,
+ app_handle: AppHandle,
+
+ current_download_agent: Option>, // Should be the only game download agent in the map with the "Go" flag
+ current_download_thread: Mutex>>,
+ active_control_flag: Option,
+}
+
+impl DownloadManagerBuilder {
+ pub fn build(app_handle: AppHandle) -> DownloadManager {
+ let queue = Queue::new();
+ let (command_sender, command_receiver) = channel();
+ let active_progress = Arc::new(Mutex::new(None));
+ let status = Arc::new(Mutex::new(DownloadManagerStatus::Empty));
+
+ let manager = Self {
+ download_agent_registry: HashMap::new(),
+ download_queue: queue.clone(),
+ command_receiver,
+ status: status.clone(),
+ sender: command_sender.clone(),
+ progress: active_progress.clone(),
+ app_handle,
+
+ current_download_agent: None,
+ current_download_thread: Mutex::new(None),
+ active_control_flag: None,
+ };
+
+ let terminator = spawn(|| manager.manage_queue());
+
+ DownloadManager::new(terminator, queue, active_progress, command_sender)
+ }
+
+ fn set_game_status(&self, id: String, status: DatabaseGameStatus) {
+ let mut db_handle = DB.borrow_data_mut().unwrap();
+ db_handle
+ .games
+ .games_statuses
+ .insert(id.clone(), status.clone());
+ drop(db_handle);
+ DB.save().unwrap();
+ self.app_handle
+ .emit(
+ &format!("update_game/{}", id),
+ GameUpdateEvent {
+ game_id: id,
+ status,
+ },
+ )
+ .unwrap();
+ }
+
+ fn push_manager_update(&self) {
+ let queue = self.download_queue.read();
+ let queue_objs: Vec = queue
+ .iter()
+ .map(|interface| QueueUpdateEventQueueData {
+ id: interface.id.clone(),
+ status: interface.status.lock().unwrap().clone(),
+ progress: interface.progress.get_progress(),
+ })
+ .collect();
+
+ let event_data = QueueUpdateEvent { queue: queue_objs };
+ self.app_handle.emit("update_queue", event_data).unwrap();
+ }
+
+ fn remove_and_cleanup_game(&mut self, game_id: &String) -> Arc {
+ self.download_queue.pop_front();
+ let download_agent = self.download_agent_registry.remove(game_id).unwrap();
+ self.cleanup_current_download();
+ download_agent
+ }
+
+ // CAREFUL WITH THIS FUNCTION
+ // Make sure the download thread is terminated
+ fn cleanup_current_download(&mut self) {
+ self.active_control_flag = None;
+ *self.progress.lock().unwrap() = None;
+ self.current_download_agent = None;
+
+ let mut download_thread_lock = self.current_download_thread.lock().unwrap();
+ *download_thread_lock = None;
+ drop(download_thread_lock);
+ }
+
+ fn manage_queue(mut self) -> Result<(), ()> {
+ loop {
+ let signal = match self.command_receiver.recv() {
+ Ok(signal) => signal,
+ Err(_) => return Err(()),
+ };
+
+ match signal {
+ DownloadManagerSignal::Go => {
+ self.manage_go_signal();
+ }
+ DownloadManagerSignal::Stop => {
+ self.manage_stop_signal();
+ }
+ DownloadManagerSignal::Completed(game_id) => {
+ self.manage_completed_signal(game_id);
+ }
+ DownloadManagerSignal::Queue(game_id, version, target_download_dir) => {
+ self.manage_queue_signal(game_id, version, target_download_dir);
+ }
+ DownloadManagerSignal::Finish => {
+ if let Some(active_control_flag) = self.active_control_flag {
+ active_control_flag.set(DownloadThreadControlFlag::Stop)
+ }
+ return Ok(());
+ }
+ DownloadManagerSignal::Error(e) => {
+ self.manage_error_signal(e);
+ }
+ DownloadManagerSignal::Cancel => {
+ self.manage_cancel_signal();
+ }
+ DownloadManagerSignal::Update => {
+ self.push_manager_update();
+ }
+ };
+ }
+ }
+
+ fn manage_stop_signal(&mut self) {
+ info!("Got signal 'Stop'");
+ if let Some(active_control_flag) = self.active_control_flag.clone() {
+ active_control_flag.set(DownloadThreadControlFlag::Stop);
+ }
+ }
+
+ fn manage_completed_signal(&mut self, game_id: String) {
+ info!("Got signal 'Completed'");
+ if let Some(interface) = &self.current_download_agent {
+ // When if let chains are stabilised, combine these two statements
+ if interface.id == game_id {
+ info!("Popping consumed data");
+ let download_agent = self.remove_and_cleanup_game(&game_id);
+
+ if let Err(error) =
+ on_game_complete(game_id, download_agent.version.clone(), &self.app_handle)
+ {
+ self.sender
+ .send(DownloadManagerSignal::Error(
+ GameDownloadError::Communication(error),
+ ))
+ .unwrap();
+ }
+ }
+ }
+ self.sender.send(DownloadManagerSignal::Update).unwrap();
+ self.sender.send(DownloadManagerSignal::Go).unwrap();
+ }
+
+ fn manage_queue_signal(&mut self, id: String, version: String, target_download_dir: usize) {
+ info!("Got signal Queue");
+ let download_agent = Arc::new(GameDownloadAgent::new(
+ id.clone(),
+ version,
+ target_download_dir,
+ self.sender.clone(),
+ ));
+ let agent_status = GameDownloadStatus::Queued;
+ let interface_data = GameDownloadAgentQueueStandin {
+ id: id.clone(),
+ status: Mutex::new(agent_status),
+ progress: download_agent.progress.clone(),
+ };
+ let version_name = download_agent.version.clone();
+ self.download_agent_registry
+ .insert(interface_data.id.clone(), download_agent);
+ self.download_queue.append(interface_data);
+
+ self.set_game_status(id, DatabaseGameStatus::Queued { version_name });
+ self.sender.send(DownloadManagerSignal::Update).unwrap();
+ }
+
+ fn manage_go_signal(&mut self) {
+ if !(!self.download_agent_registry.is_empty() && !self.download_queue.empty()) {
+ return;
+ }
+
+ if self.current_download_agent.is_some() {
+ info!("skipping go signal due to existing download job");
+ return;
+ }
+
+ info!("current download queue: {:?}", self.download_queue.read());
+ let agent_data = self.download_queue.read().front().unwrap().clone();
+ info!("starting download for {}", agent_data.id.clone());
+ let download_agent = self
+ .download_agent_registry
+ .get(&agent_data.id)
+ .unwrap()
+ .clone();
+ self.current_download_agent = Some(agent_data);
+ // Cloning option should be okay because it only clones the Arc inside, not the AgentInterfaceData
+ let agent_data = self.current_download_agent.clone().unwrap();
+
+ let version_name = download_agent.version.clone();
+
+ let progress_object = download_agent.progress.clone();
+ *self.progress.lock().unwrap() = Some(progress_object);
+
+ let active_control_flag = download_agent.control_flag.clone();
+ self.active_control_flag = Some(active_control_flag.clone());
+
+ let sender = self.sender.clone();
+
+ info!("Spawning download");
+ let mut download_thread_lock = self.current_download_thread.lock().unwrap();
+ *download_thread_lock = Some(spawn(move || {
+ match download_agent.download() {
+ // Returns once we've exited the download
+ // (not necessarily completed)
+ // The download agent will fire the completed event for us
+ Ok(_) => {}
+ // If an error occurred while *starting* the download
+ Err(err) => {
+ error!("error while managing download: {}", err);
+ sender.send(DownloadManagerSignal::Error(err)).unwrap();
+ }
+ };
+ }));
+
+ // Set status for game
+ let mut status_handle = agent_data.status.lock().unwrap();
+ *status_handle = GameDownloadStatus::Downloading;
+
+ // Set flags for download manager
+ active_control_flag.set(DownloadThreadControlFlag::Go);
+ self.set_status(DownloadManagerStatus::Downloading);
+ self.set_game_status(
+ self.current_download_agent.as_ref().unwrap().id.clone(),
+ DatabaseGameStatus::Downloading { version_name },
+ );
+ }
+ fn manage_error_signal(&mut self, error: GameDownloadError) {
+ let current_status = self.current_download_agent.clone().unwrap();
+
+ self.remove_and_cleanup_game(¤t_status.id); // Remove all the locks and shit
+
+ let mut lock = current_status.status.lock().unwrap();
+ *lock = GameDownloadStatus::Error;
+ self.set_status(DownloadManagerStatus::Error(error));
+
+ let game_id = self.current_download_agent.as_ref().unwrap().id.clone();
+ self.set_game_status(game_id, DatabaseGameStatus::Remote {});
+
+ self.sender.send(DownloadManagerSignal::Update).unwrap();
+ }
+ fn manage_cancel_signal(&mut self) {
+ if let Some(current_flag) = &self.active_control_flag {
+ current_flag.set(DownloadThreadControlFlag::Stop);
+ }
+
+ let mut download_thread_lock = self.current_download_thread.lock().unwrap();
+ if let Some(current_download_thread) = download_thread_lock.take() {
+ current_download_thread.join().unwrap();
+ }
+ drop(download_thread_lock);
+
+ info!("cancel waited for download to finish");
+
+ self.cleanup_current_download();
+ }
+ fn set_status(&self, status: DownloadManagerStatus) {
+ *self.status.lock().unwrap() = status;
+ }
+}
diff --git a/desktop/src-tauri/src/downloads/manifest.rs b/desktop/src-tauri/src/downloads/manifest.rs
index 2bb15520..d8158614 100644
--- a/desktop/src-tauri/src/downloads/manifest.rs
+++ b/desktop/src-tauri/src/downloads/manifest.rs
@@ -4,11 +4,13 @@ use std::path::PathBuf;
pub type DropManifest = HashMap;
#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
+#[serde(rename_all = "camelCase")]
pub struct DropChunk {
pub permissions: usize,
pub ids: Vec,
pub checksums: Vec,
pub lengths: Vec,
+ pub version_name: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@@ -20,4 +22,5 @@ pub struct DropDownloadContext {
pub game_id: String,
pub path: PathBuf,
pub checksum: String,
+ pub length: usize,
}
diff --git a/desktop/src-tauri/src/downloads/mod.rs b/desktop/src-tauri/src/downloads/mod.rs
index 9559d8a2..0102c33e 100644
--- a/desktop/src-tauri/src/downloads/mod.rs
+++ b/desktop/src-tauri/src/downloads/mod.rs
@@ -1,6 +1,9 @@
pub mod download_agent;
pub mod download_commands;
mod download_logic;
+pub mod download_manager;
+pub mod download_manager_builder;
mod download_thread_control_flag;
mod manifest;
-mod progress_object;
\ No newline at end of file
+mod progress_object;
+pub mod queue;
diff --git a/desktop/src-tauri/src/downloads/progress_object.rs b/desktop/src-tauri/src/downloads/progress_object.rs
index f3be4fbd..143656dd 100644
--- a/desktop/src-tauri/src/downloads/progress_object.rs
+++ b/desktop/src-tauri/src/downloads/progress_object.rs
@@ -1,33 +1,111 @@
-use std::sync::{
- atomic::{AtomicUsize, Ordering},
- Arc,
+use std::{
+ sync::{
+ atomic::{AtomicUsize, Ordering},
+ mpsc::Sender,
+ Arc, Mutex,
+ },
+ time::Instant,
};
+use log::info;
+
+use super::download_manager::DownloadManagerSignal;
+
#[derive(Clone)]
pub struct ProgressObject {
- max: usize,
- progress_instances: Arc>>,
+ max: Arc>,
+ progress_instances: Arc>>>,
+ start: Arc>,
+ sender: Sender,
+
+ points_towards_update: Arc,
+ points_to_push_update: Arc>,
}
-impl ProgressObject {
- pub fn new(max: usize, length: usize) -> Self {
- let arr = (0..length).map(|_| Arc::new(AtomicUsize::new(0))).collect();
+pub struct ProgressHandle {
+ progress: Arc,
+ progress_object: Arc,
+}
+
+impl ProgressHandle {
+ pub fn new(progress: Arc, progress_object: Arc) -> Self {
Self {
- max,
- progress_instances: Arc::new(arr),
+ progress,
+ progress_object,
}
}
+ pub fn set(&self, amount: usize) {
+ self.progress.store(amount, Ordering::Relaxed);
+ }
+ pub fn add(&self, amount: usize) {
+ self.progress
+ .fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
+ self.progress_object.check_push_update(amount);
+ }
+}
+
+static PROGRESS_UPDATES: usize = 100;
+
+impl ProgressObject {
+ pub fn new(max: usize, length: usize, sender: Sender) -> Self {
+ let arr = Mutex::new((0..length).map(|_| Arc::new(AtomicUsize::new(0))).collect());
+ // TODO: consolidate this calculation with the set_max function below
+ let points_to_push_update = max / PROGRESS_UPDATES;
+ Self {
+ max: Arc::new(Mutex::new(max)),
+ progress_instances: Arc::new(arr),
+ start: Arc::new(Mutex::new(Instant::now())),
+ sender,
+
+ points_towards_update: Arc::new(AtomicUsize::new(0)),
+ points_to_push_update: Arc::new(Mutex::new(points_to_push_update)),
+ }
+ }
+
+ pub fn check_push_update(&self, amount_added: usize) {
+ let current_amount = self
+ .points_towards_update
+ .fetch_add(amount_added, Ordering::Relaxed);
+
+ let to_update_handle = self.points_to_push_update.lock().unwrap();
+ let to_update = *to_update_handle;
+ drop(to_update_handle);
+
+ if current_amount < to_update {
+ return;
+ }
+ self.points_towards_update
+ .fetch_sub(to_update, Ordering::Relaxed);
+ self.sender.send(DownloadManagerSignal::Update).unwrap();
+ }
+
+ pub fn set_time_now(&self) {
+ *self.start.lock().unwrap() = Instant::now();
+ }
pub fn sum(&self) -> usize {
self.progress_instances
+ .lock()
+ .unwrap()
.iter()
.map(|instance| instance.load(Ordering::Relaxed))
.sum()
}
-
+ pub fn get_max(&self) -> usize {
+ *self.max.lock().unwrap()
+ }
+ pub fn set_max(&self, new_max: usize) {
+ *self.max.lock().unwrap() = new_max;
+ *self.points_to_push_update.lock().unwrap() = new_max / PROGRESS_UPDATES;
+ info!("points to push update: {}", new_max / PROGRESS_UPDATES);
+ }
+ pub fn set_size(&self, length: usize) {
+ *self.progress_instances.lock().unwrap() =
+ (0..length).map(|_| Arc::new(AtomicUsize::new(0))).collect();
+ }
pub fn get_progress(&self) -> f64 {
- self.sum() as f64 / self.max as f64
+ self.sum() as f64 / self.get_max() as f64
}
pub fn get(&self, index: usize) -> Arc {
- self.progress_instances[index].clone()
+ self.progress_instances.lock().unwrap()[index].clone()
}
}
diff --git a/desktop/src-tauri/src/downloads/queue.rs b/desktop/src-tauri/src/downloads/queue.rs
new file mode 100644
index 00000000..0ea65cae
--- /dev/null
+++ b/desktop/src-tauri/src/downloads/queue.rs
@@ -0,0 +1,73 @@
+use std::{
+ collections::VecDeque,
+ sync::{Arc, Mutex, MutexGuard},
+};
+
+use super::download_manager::GameDownloadAgentQueueStandin;
+
+#[derive(Clone)]
+pub struct Queue {
+ inner: Arc>>>,
+}
+
+#[allow(dead_code)]
+impl Queue {
+ pub fn new() -> Self {
+ Self {
+ inner: Arc::new(Mutex::new(VecDeque::new())),
+ }
+ }
+ pub fn read(&self) -> VecDeque> {
+ self.inner.lock().unwrap().clone()
+ }
+ pub fn edit(&self) -> MutexGuard<'_, VecDeque>> {
+ self.inner.lock().unwrap()
+ }
+ pub fn pop_front(&self) -> Option> {
+ self.edit().pop_front()
+ }
+ pub fn empty(&self) -> bool {
+ self.inner.lock().unwrap().len() == 0
+ }
+ /// Either inserts `interface` at the specified index, or appends to
+ /// the back of the deque if index is greater than the length of the deque
+ pub fn insert(&self, interface: GameDownloadAgentQueueStandin, index: usize) {
+ if self.read().len() > index {
+ self.append(interface);
+ } else {
+ self.edit().insert(index, Arc::new(interface));
+ }
+ }
+ pub fn append(&self, interface: GameDownloadAgentQueueStandin) {
+ self.edit().push_back(Arc::new(interface));
+ }
+ pub fn pop_front_if_equal(
+ &self,
+ game_id: String,
+ ) -> Option> {
+ let mut queue = self.edit();
+ let front = match queue.front() {
+ Some(front) => front,
+ None => return None,
+ };
+ if front.id == game_id {
+ return queue.pop_front();
+ }
+ None
+ }
+ pub fn get_by_id(&self, game_id: String) -> Option {
+ self.read().iter().position(|data| data.id == game_id)
+ }
+ pub fn move_to_index_by_id(&self, game_id: String, new_index: usize) -> Result<(), ()> {
+ let index = match self.get_by_id(game_id) {
+ Some(index) => index,
+ None => return Err(()),
+ };
+ let existing = match self.edit().remove(index) {
+ Some(existing) => existing,
+ None => return Err(()),
+ };
+ self.edit().insert(new_index, existing);
+ Ok(())
+ }
+}
diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs
index 0acc2290..f9b5ab26 100644
--- a/desktop/src-tauri/src/lib.rs
+++ b/desktop/src-tauri/src/lib.rs
@@ -2,21 +2,25 @@ mod auth;
mod db;
mod downloads;
mod library;
-mod p2p;
+// mod p2p;
mod remote;
mod settings;
#[cfg(test)]
mod tests;
use crate::db::DatabaseImpls;
-use crate::downloads::download_agent::GameDownloadAgent;
-use auth::{auth_initiate, generate_authorization_header, recieve_handshake};
-use db::{add_new_download_dir, DatabaseInterface, DATA_ROOT_DIR};
+use auth::{auth_initiate, generate_authorization_header, recieve_handshake, retry_connect};
+use db::{
+ add_download_dir, delete_download_dir, fetch_download_dir_stats, DatabaseInterface,
+ DATA_ROOT_DIR,
+};
use downloads::download_commands::*;
+use downloads::download_manager::DownloadManager;
+use downloads::download_manager_builder::DownloadManagerBuilder;
use http::{header::*, response::Builder as ResponseBuilder};
-use library::{fetch_game, fetch_library, Game};
-use log::{info, LevelFilter};
-use log4rs::append::console::{ConsoleAppender, Target};
+use library::{fetch_game, fetch_game_status, fetch_game_verion_options, fetch_library, Game};
+use log::{debug, info, LevelFilter};
+use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Root};
use log4rs::encode::pattern::PatternEncoder;
@@ -28,6 +32,7 @@ use std::{
collections::HashMap,
sync::{LazyLock, Mutex},
};
+use tauri::{AppHandle, Manager};
use tauri_plugin_deep_link::DeepLinkExt;
#[derive(Clone, Copy, Serialize)]
@@ -39,6 +44,7 @@ pub enum AppStatus {
SignedInNeedsReauth,
ServerUnavailable,
}
+
#[derive(Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct User {
@@ -57,7 +63,7 @@ pub struct AppState {
games: HashMap,
#[serde(skip_serializing)]
- game_downloads: HashMap>,
+ download_manager: Arc,
}
#[tauri::command]
@@ -68,14 +74,14 @@ fn fetch_state(state: tauri::State<'_, Mutex>) -> Result AppState {
+fn setup(handle: AppHandle) -> AppState {
let logfile = FileAppender::builder()
.encoder(Box::new(PatternEncoder::new("{t}|{l}|{f} - {m}{n}")))
.build(DATA_ROOT_DIR.lock().unwrap().join("./drop.log"))
.unwrap();
let console = ConsoleAppender::builder()
- .encoder(Box::new(PatternEncoder::new("{l} - {m}\n")))
+ .encoder(Box::new(PatternEncoder::new("{t}|{l}|{f} - {m}{n}\n")))
.build();
let config = Config::builder()
@@ -92,24 +98,28 @@ fn setup() -> AppState {
log4rs::init_config(config).unwrap();
- //env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
+ let games = HashMap::new();
+ let download_manager = Arc::new(DownloadManagerBuilder::build(handle));
+ debug!("Checking if database is set up");
let is_set_up = DB.database_is_set_up();
if !is_set_up {
return AppState {
status: AppStatus::NotConfigured,
user: None,
- games: HashMap::new(),
- game_downloads: HashMap::new(),
+ games,
+ download_manager,
};
}
+ debug!("Database is set up");
+
let (app_status, user) = auth::setup().unwrap();
AppState {
status: app_status,
user,
- games: HashMap::new(),
- game_downloads: HashMap::new(),
+ games,
+ download_manager,
}
}
@@ -117,9 +127,6 @@ pub static DB: LazyLock = LazyLock::new(DatabaseInterface::se
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
- let state = setup();
- info!("initialized drop client");
-
let mut builder = tauri::Builder::default().plugin(tauri_plugin_dialog::init());
#[cfg(desktop)]
@@ -132,25 +139,37 @@ pub fn run() {
builder
.plugin(tauri_plugin_deep_link::init())
- .manage(Mutex::new(state))
.invoke_handler(tauri::generate_handler![
// DB
fetch_state,
// Auth
auth_initiate,
+ retry_connect,
// Remote
use_remote,
gen_drop_url,
// Library
fetch_library,
fetch_game,
- add_new_download_dir,
+ add_download_dir,
+ delete_download_dir,
+ fetch_download_dir_stats,
+ fetch_game_status,
+ fetch_game_verion_options,
// Downloads
download_game,
- get_game_download_progress,
+ move_game_in_queue,
+ pause_game_downloads,
+ resume_game_downloads,
])
.plugin(tauri_plugin_shell::init())
+ .plugin(tauri_plugin_dialog::init())
.setup(|app| {
+ let handle = app.handle().clone();
+ let state = setup(handle);
+ info!("initialized drop client");
+ app.manage(Mutex::new(state));
+
#[cfg(any(target_os = "linux", all(debug_assertions, windows)))]
{
use tauri_plugin_deep_link::DeepLinkExt;
diff --git a/desktop/src-tauri/src/library.rs b/desktop/src-tauri/src/library.rs
index 65f9ec10..0e25c526 100644
--- a/desktop/src-tauri/src/library.rs
+++ b/desktop/src-tauri/src/library.rs
@@ -1,16 +1,19 @@
use std::sync::Mutex;
use serde::{Deserialize, Serialize};
-use serde_json::json;
+use tauri::Emitter;
use tauri::{AppHandle, Manager};
+use urlencoding::encode;
use crate::db::DatabaseGameStatus;
use crate::db::DatabaseImpls;
+use crate::db::GameVersion;
+use crate::downloads::download_manager::GameDownloadStatus;
use crate::remote::RemoteAccessError;
use crate::{auth::generate_authorization_header, AppState, DB};
#[derive(serde::Serialize)]
-struct FetchGameStruct {
+pub struct FetchGameStruct {
game: Game,
status: DatabaseGameStatus,
}
@@ -29,8 +32,38 @@ pub struct Game {
m_cover_id: String,
m_image_library: Vec,
}
+#[derive(serde::Serialize, Clone)]
+pub struct GameUpdateEvent {
+ pub game_id: String,
+ pub status: DatabaseGameStatus,
+}
-fn fetch_library_logic(app: AppHandle) -> Result {
+#[derive(Serialize, Clone)]
+pub struct QueueUpdateEventQueueData {
+ pub id: String,
+ pub status: GameDownloadStatus,
+ pub progress: f64,
+}
+
+#[derive(serde::Serialize, Clone)]
+pub struct QueueUpdateEvent {
+ pub queue: Vec,
+}
+
+// Game version with some fields missing and size information
+#[derive(serde::Deserialize, serde::Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct GameVersionOption {
+ version_index: usize,
+ version_name: String,
+ platform: String,
+ setup_command: String,
+ launch_command: String,
+ delta: bool,
+ // total_size: usize,
+}
+
+fn fetch_library_logic(app: AppHandle) -> Result, RemoteAccessError> {
let base_url = DB.fetch_base_url();
let library_url = base_url.join("/api/v1/client/user/library")?;
@@ -46,7 +79,7 @@ fn fetch_library_logic(app: AppHandle) -> Result {
return Err(response.status().as_u16().into());
}
- let games = response.json::>()?;
+ let games: Vec = response.json::>()?;
let state = app.state::>();
let mut handle = state.lock().unwrap();
@@ -59,31 +92,28 @@ fn fetch_library_logic(app: AppHandle) -> Result {
db_handle
.games
.games_statuses
- .insert(game.id.clone(), DatabaseGameStatus::Remote);
+ .insert(game.id.clone(), DatabaseGameStatus::Remote {});
}
}
drop(handle);
- Ok(json!(games.clone()).to_string())
+ Ok(games)
}
#[tauri::command]
-pub fn fetch_library(app: AppHandle) -> Result {
- let result = fetch_library_logic(app);
-
- if result.is_err() {
- return Err(result.err().unwrap().to_string());
- }
-
- Ok(result.unwrap())
+pub fn fetch_library(app: AppHandle) -> Result, String> {
+ fetch_library_logic(app).map_err(|e| e.to_string())
}
-fn fetch_game_logic(id: String, app: tauri::AppHandle) -> Result {
+fn fetch_game_logic(
+ id: String,
+ app: tauri::AppHandle,
+) -> Result {
let state = app.state::>();
- let handle = state.lock().unwrap();
+ let mut state_handle = state.lock().unwrap();
- let game = handle.games.get(&id);
+ let game = state_handle.games.get(&id);
if let Some(game) = game {
let db_handle = DB.borrow_data().unwrap();
@@ -97,15 +127,55 @@ fn fetch_game_logic(id: String, app: tauri::AppHandle) -> Result()?;
+ state_handle.games.insert(id.clone(), game.clone());
+
+ let mut db_handle = DB.borrow_data_mut().unwrap();
+
+ db_handle
+ .games
+ .games_statuses
+ .entry(id)
+ .or_insert(DatabaseGameStatus::Remote {});
+
+ let data = FetchGameStruct {
+ game: game.clone(),
+ status: db_handle
+ .games
+ .games_statuses
+ .get(&game.id)
+ .unwrap()
+ .clone(),
+ };
+
+ Ok(data)
}
#[tauri::command]
-pub fn fetch_game(id: String, app: tauri::AppHandle) -> Result {
+pub fn fetch_game(id: String, app: tauri::AppHandle) -> Result {
let result = fetch_game_logic(id, app);
if result.is_err() {
@@ -114,3 +184,107 @@ pub fn fetch_game(id: String, app: tauri::AppHandle) -> Result {
Ok(result.unwrap())
}
+
+#[tauri::command]
+pub fn fetch_game_status(id: String) -> Result {
+ let db_handle = DB.borrow_data().unwrap();
+ let status = db_handle
+ .games
+ .games_statuses
+ .get(&id)
+ .unwrap_or(&DatabaseGameStatus::Remote {})
+ .clone();
+ drop(db_handle);
+
+ Ok(status)
+}
+
+fn fetch_game_verion_options_logic(
+ game_id: String,
+) -> Result, RemoteAccessError> {
+ let base_url = DB.fetch_base_url();
+
+ let endpoint =
+ base_url.join(format!("/api/v1/client/metadata/versions?id={}", game_id).as_str())?;
+ let header = generate_authorization_header();
+
+ let client = reqwest::blocking::Client::new();
+ let response = client
+ .get(endpoint.to_string())
+ .header("Authorization", header)
+ .send()?;
+
+ if response.status() != 200 {
+ return Err(RemoteAccessError::InvalidCodeError(
+ response.status().into(),
+ ));
+ }
+
+ let data = response.json::>()?;
+
+ Ok(data)
+}
+
+#[tauri::command]
+pub fn fetch_game_verion_options(game_id: String) -> Result, String> {
+ fetch_game_verion_options_logic(game_id).map_err(|e| e.to_string())
+}
+
+pub fn on_game_complete(
+ game_id: String,
+ version_name: String,
+ app_handle: &AppHandle,
+) -> Result<(), RemoteAccessError> {
+ // Fetch game version information from remote
+ let base_url = DB.fetch_base_url();
+
+ let endpoint = base_url.join(
+ format!(
+ "/api/v1/client/metadata/version?id={}&version={}",
+ game_id,
+ encode(&version_name)
+ )
+ .as_str(),
+ )?;
+ let header = generate_authorization_header();
+
+ let client = reqwest::blocking::Client::new();
+ let response = client
+ .get(endpoint.to_string())
+ .header("Authorization", header)
+ .send()?;
+
+ let data = response.json::()?;
+
+ let mut handle = DB.borrow_data_mut().unwrap();
+ handle
+ .games
+ .game_versions
+ .entry(game_id.clone())
+ .or_default()
+ .insert(version_name.clone(), data.clone());
+ drop(handle);
+ DB.save().unwrap();
+
+ let status = if data.setup_command.is_empty() {
+ DatabaseGameStatus::Installed { version_name }
+ } else {
+ DatabaseGameStatus::SetupRequired { version_name }
+ };
+
+ let mut db_handle = DB.borrow_data_mut().unwrap();
+ db_handle
+ .games
+ .games_statuses
+ .insert(game_id.clone(), status.clone());
+ drop(db_handle);
+ DB.save().unwrap();
+ app_handle
+ .emit(
+ &format!("update_game/{}", game_id),
+ GameUpdateEvent { game_id, status },
+ )
+ .unwrap();
+
+ Ok(())
+}
diff --git a/desktop/src-tauri/src/p2p/registration.rs b/desktop/src-tauri/src/p2p/registration.rs
new file mode 100644
index 00000000..0926515e
--- /dev/null
+++ b/desktop/src-tauri/src/p2p/registration.rs
@@ -0,0 +1,17 @@
+use crate::{auth::generate_authorization_header, db::DatabaseImpls, remote::RemoteAccessError, DB};
+
+
+pub async fn register() -> Result {
+ let base_url = DB.fetch_base_url();
+ let registration_url = base_url.join("/api/v1/client/capability").unwrap();
+ let header = generate_authorization_header();
+
+
+ let client = reqwest::blocking::Client::new();
+ client
+ .post(registration_url)
+ .header("Authorization", header)
+ .send()?;
+
+ return Ok(String::new())
+}
\ No newline at end of file
diff --git a/desktop/src-tauri/src/remote.rs b/desktop/src-tauri/src/remote.rs
index e415c529..0a53c2b9 100644
--- a/desktop/src-tauri/src/remote.rs
+++ b/desktop/src-tauri/src/remote.rs
@@ -1,43 +1,53 @@
use std::{
fmt::{Display, Formatter},
- sync::Mutex,
+ sync::{Arc, Mutex},
};
+use http::StatusCode;
use log::{info, warn};
use serde::Deserialize;
use url::{ParseError, Url};
use crate::{AppState, AppStatus, DB};
-#[derive(Debug)]
+#[derive(Debug, Clone)]
pub enum RemoteAccessError {
- FetchError(reqwest::Error),
+ FetchError(Arc),
ParsingError(ParseError),
InvalidCodeError(u16),
- GenericErrror(String),
+ InvalidEndpoint,
+ HandshakeFailed,
+ GameNotFound,
+ InvalidResponse,
+ InvalidRedirect,
+ ManifestDownloadFailed(StatusCode, String),
}
impl Display for RemoteAccessError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
RemoteAccessError::FetchError(error) => write!(f, "{}", error),
- RemoteAccessError::GenericErrror(error) => write!(f, "{}", error),
RemoteAccessError::ParsingError(parse_error) => {
write!(f, "{}", parse_error)
}
RemoteAccessError::InvalidCodeError(error) => write!(f, "HTTP {}", error),
+ RemoteAccessError::InvalidEndpoint => write!(f, "Invalid drop endpoint"),
+ RemoteAccessError::HandshakeFailed => write!(f, "Failed to complete handshake"),
+ RemoteAccessError::GameNotFound => write!(f, "Could not find game on server"),
+ RemoteAccessError::InvalidResponse => write!(f, "Server returned an invalid response"),
+ RemoteAccessError::InvalidRedirect => write!(f, "Server redirect was invalid"),
+ RemoteAccessError::ManifestDownloadFailed(status, response) => write!(
+ f,
+ "Failed to download game manifest: {} {}",
+ status, response
+ ),
}
}
}
impl From for RemoteAccessError {
fn from(err: reqwest::Error) -> Self {
- RemoteAccessError::FetchError(err)
- }
-}
-impl From for RemoteAccessError {
- fn from(err: String) -> Self {
- RemoteAccessError::GenericErrror(err)
+ RemoteAccessError::FetchError(Arc::new(err))
}
}
impl From for RemoteAccessError {
@@ -74,7 +84,7 @@ async fn use_remote_logic<'a>(
if result.app_name != "Drop" {
warn!("user entered drop endpoint that connected, but wasn't identified as Drop");
- return Err("Not a valid Drop endpoint".to_string().into());
+ return Err(RemoteAccessError::InvalidEndpoint);
}
let mut app_state = state.lock().unwrap();
diff --git a/desktop/types.ts b/desktop/types.ts
index b63d9043..5702594c 100644
--- a/desktop/types.ts
+++ b/desktop/types.ts
@@ -1,4 +1,3 @@
-import type { User } from "@prisma/client";
import type { Component } from "vue";
export type NavigationItem = {
@@ -12,11 +11,31 @@ export type QuickActionNav = {
notifications?: number;
action: () => Promise;
};
+
+export type User = {
+ id: string;
+ username: string;
+ admin: boolean;
+ displayName: string;
+ profilePicture: string;
+};
+
export type AppState = {
status: AppStatus;
user?: User;
};
+export type Game = {
+ id: string;
+ mName: string;
+ mShortDescription: string;
+ mDescription: string;
+ mIconId: string;
+ mBannerId: string;
+ mCoverId: string;
+ mImageLibrary: string[];
+};
+
export enum AppStatus {
NotConfigured = "NotConfigured",
SignedOut = "SignedOut",
@@ -25,10 +44,17 @@ export enum AppStatus {
ServerUnavailable = "ServerUnavailable",
}
-export enum GameStatus {
+export enum GameStatusEnum {
Remote = "Remote",
+ Queued = "Queued",
Downloading = "Downloading",
Installed = "Installed",
Updating = "Updating",
Uninstalling = "Uninstalling",
+ SetupRequired = "SetupRequired",
}
+
+export type GameStatus = {
+ type: GameStatusEnum;
+ version_name?: string;
+};
diff --git a/desktop/yarn.lock b/desktop/yarn.lock
index da122f89..a4fa8b8d 100644
--- a/desktop/yarn.lock
+++ b/desktop/yarn.lock
@@ -1075,47 +1075,6 @@
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73"
integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==
-"@prisma/client@5.20.0":
- version "5.20.0"
- resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.20.0.tgz#4fc9f2b2341c9c997c139df4445688dd6b39663b"
- integrity sha512-CLv55ZuMuUawMsxoqxGtLT3bEZoa2W8L3Qnp6rDIFWy+ZBrUcOFKdoeGPSnbBqxc3SkdxJrF+D1veN/WNynZYA==
-
-"@prisma/debug@5.20.0":
- version "5.20.0"
- resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.20.0.tgz#c6d1cf6e3c6e9dba150347f13ca200b1d66cc9fc"
- integrity sha512-oCx79MJ4HSujokA8S1g0xgZUGybD4SyIOydoHMngFYiwEwYDQ5tBQkK5XoEHuwOYDKUOKRn/J0MEymckc4IgsQ==
-
-"@prisma/engines-version@5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284":
- version "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284"
- resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284.tgz#9a53b13cdcfd706ae54198111000f33c63655c39"
- integrity sha512-Lg8AS5lpi0auZe2Mn4gjuCg081UZf88k3cn0RCwHgR+6cyHHpttPZBElJTHf83ZGsRNAmVCZCfUGA57WB4u4JA==
-
-"@prisma/engines@5.20.0":
- version "5.20.0"
- resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.20.0.tgz#86fe407e55219d33d03ebc26dc829a422faed545"
- integrity sha512-DtqkP+hcZvPEbj8t8dK5df2b7d3B8GNauKqaddRRqQBBlgkbdhJkxhoJTrOowlS3vaRt2iMCkU0+CSNn0KhqAQ==
- dependencies:
- "@prisma/debug" "5.20.0"
- "@prisma/engines-version" "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284"
- "@prisma/fetch-engine" "5.20.0"
- "@prisma/get-platform" "5.20.0"
-
-"@prisma/fetch-engine@5.20.0":
- version "5.20.0"
- resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.20.0.tgz#b917880fb08f654981f14ca49923031b39683586"
- integrity sha512-JVcaPXC940wOGpCOwuqQRTz6I9SaBK0c1BAyC1pcz9xBi+dzFgUu3G/p9GV1FhFs9OKpfSpIhQfUJE9y00zhqw==
- dependencies:
- "@prisma/debug" "5.20.0"
- "@prisma/engines-version" "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284"
- "@prisma/get-platform" "5.20.0"
-
-"@prisma/get-platform@5.20.0":
- version "5.20.0"
- resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.20.0.tgz#c1a53a8d8af67f2b4a6b97dd4d25b1c603236804"
- integrity sha512-8/+CehTZZNzJlvuryRgc77hZCWrUDYd/PmlZ7p2yNXtmf2Una4BWnTbak3us6WVdqoz5wmptk6IhsXdG2v5fmA==
- dependencies:
- "@prisma/debug" "5.20.0"
-
"@rollup/plugin-alias@^5.1.0":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz#53601d88cda8b1577aa130b4a6e452283605bf26"
@@ -1376,10 +1335,10 @@
dependencies:
"@tauri-apps/api" "^2.0.0"
-"@tauri-apps/plugin-dialog@~2":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-dialog/-/plugin-dialog-2.0.0.tgz#f1e2840c7f824572a76b375fd1b538a36f28de14"
- integrity sha512-ApNkejXP2jpPBSifznPPcHTXxu9/YaRW+eJ+8+nYwqp0lLUtebFHG4QhxitM43wwReHE81WAV1DQ/b+2VBftOA==
+"@tauri-apps/plugin-dialog@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@tauri-apps/plugin-dialog/-/plugin-dialog-2.0.1.tgz#cca38f2ef361c6d92495f5aa12154492cf3fa779"
+ integrity sha512-fnUrNr6EfvTqdls/ufusU7h6UbNFzLKvHk/zTuOiBq01R3dTODqwctZlzakdbfSp/7pNwTKvgKTAgl/NAP/Z0Q==
dependencies:
"@tauri-apps/api" "^2.0.0"
@@ -2816,7 +2775,7 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-fsevents@2.3.3, fsevents@~2.3.2, fsevents@~2.3.3:
+fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
@@ -4345,15 +4304,6 @@ pretty-bytes@^6.1.1:
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-6.1.1.tgz#38cd6bb46f47afbf667c202cfc754bffd2016a3b"
integrity sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==
-prisma@^5.20.0:
- version "5.20.0"
- resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.20.0.tgz#f2ab266a0d59383506886e7acbff0dbf322f4c7e"
- integrity sha512-6obb3ucKgAnsGS9x9gLOe8qa51XxvJ3vLQtmyf52CTey1Qcez3A6W6ROH5HIz5Q5bW+0VpmZb8WBohieMFGpig==
- dependencies:
- "@prisma/engines" "5.20.0"
- optionalDependencies:
- fsevents "2.3.3"
-
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
@@ -4847,6 +4797,11 @@ smob@^1.0.0:
resolved "https://registry.yarnpkg.com/smob/-/smob-1.5.0.tgz#85d79a1403abf128d24d3ebc1cdc5e1a9548d3ab"
integrity sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==
+sortablejs@1.14.0:
+ version "1.14.0"
+ resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8"
+ integrity sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==
+
source-map-js@^1.0.1, source-map-js@^1.2.0, source-map-js@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
@@ -5553,6 +5508,13 @@ vue@^3.5.5, vue@latest:
"@vue/server-renderer" "3.5.11"
"@vue/shared" "3.5.11"
+vuedraggable@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/vuedraggable/-/vuedraggable-4.1.0.tgz#edece68adb8a4d9e06accff9dfc9040e66852270"
+ integrity sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==
+ dependencies:
+ sortablejs "1.14.0"
+
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"