feat: add unified Tauri desktop client and secure web access

This commit is contained in:
lbl
2026-08-22 04:09:44 +08:00
parent 0ccd045e78
commit cd5b4431dc
62 changed files with 5018 additions and 500 deletions
+5 -1
View File
@@ -6,4 +6,8 @@ vnt_current_config.txt
logs/*
/.tools/
node_modules
vnt-web/ui/dist
vnt-web/ui/dist
vnt-desktop/dist
vnt-desktop/src-tauri/gen
vnt-desktop/src-tauri/icons/android
vnt-desktop/src-tauri/icons/ios
+5
View File
@@ -0,0 +1,5 @@
/node_modules/
/vnt-desktop/node_modules/
/vnt-web/ui/node_modules/
/vnt-desktop/dist/
/vnt-web/static/
Generated
+3278 -48
View File
@@ -2,6 +2,12 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "adler2"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
[[package]]
name = "ahash"
version = "0.7.8"
@@ -22,6 +28,21 @@ dependencies = [
"memchr",
]
[[package]]
name = "alloc-no-stdlib"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
[[package]]
name = "alloc-stdlib"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
dependencies = [
"alloc-no-stdlib",
]
[[package]]
name = "android_system_properties"
version = "0.1.5"
@@ -120,7 +141,7 @@ checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
"synstructure",
]
@@ -132,7 +153,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -169,6 +190,38 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "async-executor"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
dependencies = [
"async-task",
"concurrent-queue",
"fastrand",
"futures-lite",
"pin-project-lite",
"slab",
]
[[package]]
name = "async-io"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
dependencies = [
"autocfg",
"cfg-if",
"concurrent-queue",
"futures-io",
"futures-lite",
"parking",
"polling",
"rustix",
"slab",
"windows-sys 0.61.2",
]
[[package]]
name = "async-lock"
version = "3.4.2"
@@ -180,6 +233,35 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "async-process"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
dependencies = [
"async-channel",
"async-io",
"async-lock",
"async-signal",
"async-task",
"blocking",
"cfg-if",
"event-listener",
"futures-lite",
"rustix",
]
[[package]]
name = "async-recursion"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "async-scoped"
version = "0.9.0"
@@ -191,6 +273,24 @@ dependencies = [
"tokio",
]
[[package]]
name = "async-signal"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485"
dependencies = [
"async-io",
"async-lock",
"atomic-waker",
"cfg-if",
"futures-core",
"futures-io",
"rustix",
"signal-hook-registry",
"slab",
"windows-sys 0.61.2",
]
[[package]]
name = "async-task"
version = "4.7.1"
@@ -205,7 +305,30 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
name = "atk"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b"
dependencies = [
"atk-sys",
"glib",
"libc",
]
[[package]]
name = "atk-sys"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
@@ -272,12 +395,33 @@ dependencies = [
"tracing",
]
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bit-set"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -289,6 +433,9 @@ name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
dependencies = [
"serde_core",
]
[[package]]
name = "block-buffer"
@@ -308,6 +455,15 @@ dependencies = [
"hybrid-array",
]
[[package]]
name = "block2"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5"
dependencies = [
"objc2",
]
[[package]]
name = "blocking"
version = "1.6.2"
@@ -321,12 +477,48 @@ dependencies = [
"piper",
]
[[package]]
name = "brotli"
version = "8.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
"brotli-decompressor",
]
[[package]]
name = "brotli-decompressor"
version = "5.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
]
[[package]]
name = "bs58"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
dependencies = [
"tinyvec",
]
[[package]]
name = "bumpalo"
version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "bytemuck"
version = "1.25.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -338,6 +530,9 @@ name = "bytes"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
dependencies = [
"serde",
]
[[package]]
name = "c2rust-bitfields"
@@ -356,7 +551,74 @@ checksum = "3b457277798202ccd365b9c112ebee08ddd57f1033916c8b8ea52f222e5b715d"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
name = "cairo-rs"
version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
dependencies = [
"bitflags 2.10.0",
"cairo-sys-rs",
"glib",
"libc",
"once_cell",
"thiserror 1.0.69",
]
[[package]]
name = "cairo-sys-rs"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "camino"
version = "1.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d"
dependencies = [
"serde_core",
]
[[package]]
name = "cargo-platform"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
dependencies = [
"serde",
]
[[package]]
name = "cargo_metadata"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
"thiserror 2.0.18",
]
[[package]]
name = "cargo_toml"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77"
dependencies = [
"serde",
"toml 0.9.11+spec-1.1.0",
]
[[package]]
@@ -375,6 +637,27 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cfb"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f"
dependencies = [
"byteorder",
"fnv",
"uuid",
]
[[package]]
name = "cfg-expr"
version = "0.15.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
dependencies = [
"smallvec",
"target-lexicon",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
@@ -406,6 +689,7 @@ checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
dependencies = [
"iana-time-zone",
"num-traits",
"serde",
"windows-link 0.2.1",
]
@@ -437,10 +721,10 @@ version = "4.5.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
dependencies = [
"heck",
"heck 0.5.0",
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -469,7 +753,7 @@ checksum = "9f7c1b60bae2c3d45228dfb096046aa51ef6c300de70b658d7a13fcb0c4f832e"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -516,6 +800,16 @@ version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
[[package]]
name = "cookie"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87"
dependencies = [
"time",
"version_check",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
@@ -542,6 +836,30 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "core-graphics"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
dependencies = [
"bitflags 2.10.0",
"core-foundation 0.10.1",
"core-graphics-types",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [
"bitflags 2.10.0",
"core-foundation 0.10.1",
"libc",
]
[[package]]
name = "cpufeatures"
version = "0.2.17"
@@ -560,6 +878,24 @@ dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.12"
@@ -594,6 +930,29 @@ dependencies = [
"hybrid-array",
]
[[package]]
name = "cssparser"
version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
dependencies = [
"cssparser-macros",
"dtoa-short",
"itoa",
"phf",
"smallvec",
]
[[package]]
name = "cssparser-macros"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
"syn 2.0.114",
]
[[package]]
name = "csv"
version = "1.4.0"
@@ -615,6 +974,56 @@ dependencies = [
"memchr",
]
[[package]]
name = "ctor"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98"
dependencies = [
"ctor-proc-macro",
"dtor",
]
[[package]]
name = "ctor-proc-macro"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
[[package]]
name = "darling"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
dependencies = [
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.114",
]
[[package]]
name = "darling_macro"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
dependencies = [
"darling_core",
"quote",
"syn 2.0.114",
]
[[package]]
name = "dashmap"
version = "6.1.0"
@@ -635,6 +1044,48 @@ version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
[[package]]
name = "dbus"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e"
dependencies = [
"libc",
"libdbus-sys",
"windows-sys 0.61.2",
]
[[package]]
name = "defmt"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1"
dependencies = [
"bitflags 1.3.2",
"defmt-macros",
]
[[package]]
name = "defmt-macros"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8"
dependencies = [
"defmt-parser",
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "defmt-parser"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e"
dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "der-parser"
version = "10.0.0"
@@ -656,6 +1107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
dependencies = [
"powerfmt",
"serde_core",
]
[[package]]
@@ -676,7 +1128,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version",
"syn",
"syn 2.0.114",
"unicode-xid",
]
@@ -717,6 +1169,39 @@ dependencies = [
"crypto-common 0.2.2",
]
[[package]]
name = "dirs"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.61.2",
]
[[package]]
name = "dispatch2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
dependencies = [
"bitflags 2.10.0",
"block2",
"libc",
"objc2",
]
[[package]]
name = "displaydoc"
version = "0.2.5"
@@ -725,7 +1210,30 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
name = "dlopen2"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4"
dependencies = [
"dlopen2_derive",
"libc",
"once_cell",
"winapi",
]
[[package]]
name = "dlopen2_derive"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
@@ -738,6 +1246,66 @@ dependencies = [
"quick-error",
]
[[package]]
name = "dom_query"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89"
dependencies = [
"bit-set",
"cssparser",
"foldhash 0.2.0",
"html5ever",
"precomputed-hash",
"selectors",
"tendril",
]
[[package]]
name = "dpi"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
dependencies = [
"serde",
]
[[package]]
name = "dtoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590"
[[package]]
name = "dtoa-short"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87"
dependencies = [
"dtoa",
]
[[package]]
name = "dtor"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4"
dependencies = [
"dtor-proc-macro",
]
[[package]]
name = "dtor-proc-macro"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
[[package]]
name = "dunce"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "dyn-clone"
version = "1.0.20"
@@ -750,6 +1318,26 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "embed-resource"
version = "3.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd"
dependencies = [
"cc",
"memchr",
"rustc_version",
"toml 1.0.6+spec-1.1.0",
"vswhom",
"winreg",
]
[[package]]
name = "embed_plist"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
[[package]]
name = "encode_unicode"
version = "1.0.0"
@@ -765,12 +1353,50 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "endi"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
[[package]]
name = "enumflags2"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
dependencies = [
"enumflags2_derive",
"serde",
]
[[package]]
name = "enumflags2_derive"
version = "0.7.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "erased-serde"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec"
dependencies = [
"serde",
"serde_core",
"typeid",
]
[[package]]
name = "errno"
version = "0.3.14"
@@ -811,6 +1437,25 @@ dependencies = [
"getrandom 0.2.17",
]
[[package]]
name = "fdeflate"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
dependencies = [
"simd-adler32",
]
[[package]]
name = "field-offset"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
dependencies = [
"memoffset",
"rustc_version",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@@ -823,6 +1468,16 @@ version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "flate2"
version = "1.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "flume"
version = "0.12.0"
@@ -847,6 +1502,39 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
[[package]]
name = "foldhash"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
[[package]]
name = "foreign-types"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
dependencies = [
"foreign-types-macros",
"foreign-types-shared",
]
[[package]]
name = "foreign-types-macros"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]]
name = "foreign-types-shared"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
@@ -910,7 +1598,10 @@ version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
dependencies = [
"fastrand",
"futures-core",
"futures-io",
"parking",
"pin-project-lite",
]
@@ -922,7 +1613,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -955,6 +1646,105 @@ dependencies = [
"slab",
]
[[package]]
name = "gdk"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691"
dependencies = [
"cairo-rs",
"gdk-pixbuf",
"gdk-sys",
"gio",
"glib",
"libc",
"pango",
]
[[package]]
name = "gdk-pixbuf"
version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec"
dependencies = [
"gdk-pixbuf-sys",
"gio",
"glib",
"libc",
"once_cell",
]
[[package]]
name = "gdk-pixbuf-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7"
dependencies = [
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "gdk-sys"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"pkg-config",
"system-deps",
]
[[package]]
name = "gdkwayland-sys"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69"
dependencies = [
"gdk-sys",
"glib-sys",
"gobject-sys",
"libc",
"pkg-config",
"system-deps",
]
[[package]]
name = "gdkx11"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe"
dependencies = [
"gdk",
"gdkx11-sys",
"gio",
"glib",
"libc",
"x11",
]
[[package]]
name = "gdkx11-sys"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d"
dependencies = [
"gdk-sys",
"glib-sys",
"libc",
"system-deps",
"x11",
]
[[package]]
name = "generator"
version = "0.7.5"
@@ -1028,12 +1818,154 @@ dependencies = [
"rand_core 0.10.1",
]
[[package]]
name = "gio"
version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-util",
"gio-sys",
"glib",
"libc",
"once_cell",
"pin-project-lite",
"smallvec",
"thiserror 1.0.69",
]
[[package]]
name = "gio-sys"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
"winapi",
]
[[package]]
name = "glib"
version = "0.18.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
dependencies = [
"bitflags 2.10.0",
"futures-channel",
"futures-core",
"futures-executor",
"futures-task",
"futures-util",
"gio-sys",
"glib-macros",
"glib-sys",
"gobject-sys",
"libc",
"memchr",
"once_cell",
"smallvec",
"thiserror 1.0.69",
]
[[package]]
name = "glib-macros"
version = "0.18.5"
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-error",
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "glib-sys"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898"
dependencies = [
"libc",
"system-deps",
]
[[package]]
name = "glob"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]]
name = "gobject-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44"
dependencies = [
"glib-sys",
"libc",
"system-deps",
]
[[package]]
name = "gtk"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a"
dependencies = [
"atk",
"cairo-rs",
"field-offset",
"futures-channel",
"gdk",
"gdk-pixbuf",
"gio",
"glib",
"gtk-sys",
"gtk3-macros",
"libc",
"pango",
"pkg-config",
]
[[package]]
name = "gtk-sys"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414"
dependencies = [
"atk-sys",
"cairo-sys-rs",
"gdk-pixbuf-sys",
"gdk-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"pango-sys",
"system-deps",
]
[[package]]
name = "gtk3-macros"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@@ -1055,7 +1987,7 @@ version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
dependencies = [
"foldhash",
"foldhash 0.1.5",
]
[[package]]
@@ -1064,12 +1996,24 @@ version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
[[package]]
name = "hex"
version = "0.4.3"
@@ -1087,6 +2031,16 @@ dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "html5ever"
version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
dependencies = [
"log",
"markup5ever",
]
[[package]]
name = "http"
version = "1.4.0"
@@ -1172,6 +2126,7 @@ dependencies = [
"pin-utils",
"smallvec",
"tokio",
"want",
]
[[package]]
@@ -1180,13 +2135,21 @@ version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-channel",
"futures-util",
"http",
"http-body",
"hyper",
"ipnet",
"libc",
"percent-encoding",
"pin-project-lite",
"socket2 0.6.2",
"tokio",
"tower-service",
"tracing",
]
[[package]]
@@ -1213,6 +2176,137 @@ dependencies = [
"cc",
]
[[package]]
name = "ico"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371"
dependencies = [
"byteorder",
"png 0.17.16",
]
[[package]]
name = "icu_collections"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513"
dependencies = [
"displaydoc",
"potential_utf",
"utf8_iter",
"yoke",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb"
dependencies = [
"displaydoc",
"litemap",
"tinystr",
"writeable",
"zerovec",
]
[[package]]
name = "icu_normalizer"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f"
dependencies = [
"icu_collections",
"icu_normalizer_data",
"icu_properties",
"icu_provider",
"smallvec",
"zerovec",
]
[[package]]
name = "icu_normalizer_data"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0"
[[package]]
name = "icu_properties"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148"
dependencies = [
"displaydoc",
"icu_collections",
"icu_locale_core",
"icu_properties_data",
"icu_provider",
"zerotrie",
"zerovec",
]
[[package]]
name = "icu_properties_data"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa"
[[package]]
name = "icu_provider"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73"
dependencies = [
"displaydoc",
"icu_locale_core",
"writeable",
"yoke",
"zerofrom",
"zerotrie",
"zerovec",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
dependencies = [
"idna_adapter",
"smallvec",
"utf8_iter",
]
[[package]]
name = "idna_adapter"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
dependencies = [
"icu_normalizer",
"icu_properties",
]
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
name = "indexmap"
version = "2.13.0"
@@ -1221,6 +2315,17 @@ checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
dependencies = [
"equivalent",
"hashbrown 0.16.1",
"serde",
"serde_core",
]
[[package]]
name = "infer"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7"
dependencies = [
"cfb",
]
[[package]]
@@ -1241,6 +2346,25 @@ dependencies = [
"serde",
]
[[package]]
name = "is-docker"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
dependencies = [
"once_cell",
]
[[package]]
name = "is-wsl"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
dependencies = [
"is-docker",
"once_cell",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
@@ -1262,6 +2386,82 @@ version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "javascriptcore-rs"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc"
dependencies = [
"bitflags 1.3.2",
"glib",
"javascriptcore-rs-sys",
]
[[package]]
name = "javascriptcore-rs-sys"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "jiff"
version = "0.2.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc"
dependencies = [
"defmt",
"jiff-core",
"jiff-static",
"jiff-tzdb-platform",
"log",
"portable-atomic",
"portable-atomic-util",
"serde_core",
"windows-link 0.2.1",
]
[[package]]
name = "jiff-core"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09"
dependencies = [
"defmt",
]
[[package]]
name = "jiff-static"
version = "0.2.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204"
dependencies = [
"jiff-core",
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "jiff-tzdb"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e"
[[package]]
name = "jiff-tzdb-platform"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
dependencies = [
"jiff-tzdb",
]
[[package]]
name = "jni"
version = "0.21.1"
@@ -1294,18 +2494,94 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json-patch"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08"
dependencies = [
"jsonptr",
"serde",
"serde_json",
"thiserror 1.0.69",
]
[[package]]
name = "jsonptr"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "keyboard-types"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
dependencies = [
"bitflags 2.10.0",
"serde",
"unicode-segmentation",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libappindicator"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a"
dependencies = [
"glib",
"gtk",
"gtk-sys",
"libappindicator-sys",
"log",
]
[[package]]
name = "libappindicator-sys"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf"
dependencies = [
"gtk-sys",
"libloading 0.7.4",
"once_cell",
]
[[package]]
name = "libc"
version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "libdbus-sys"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043"
dependencies = [
"pkg-config",
]
[[package]]
name = "libloading"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "libloading"
version = "0.9.0"
@@ -1322,12 +2598,27 @@ version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d0a00925a9f930d679b6789b721e3a7f9ed110f41b86d2497caa780c3a070a"
dependencies = [
"libc",
]
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litemap"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae"
[[package]]
name = "lock_api"
version = "0.4.14"
@@ -1429,6 +2720,17 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "markup5ever"
version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862"
dependencies = [
"log",
"tendril",
"web_atoms",
]
[[package]]
name = "matchers"
version = "0.2.0"
@@ -1481,6 +2783,16 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
dependencies = [
"adler2",
"simd-adler32",
]
[[package]]
name = "mio"
version = "1.1.1"
@@ -1498,12 +2810,57 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dce6dd36094cac388f119d2e9dc82dc730ef91c32a6222170d630e5414b956e6"
[[package]]
name = "muda"
version = "0.19.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878"
dependencies = [
"crossbeam-channel",
"dpi",
"gtk",
"keyboard-types",
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-foundation",
"once_cell",
"png 0.18.1",
"serde",
"thiserror 2.0.18",
"windows-sys 0.61.2",
]
[[package]]
name = "multimap"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084"
[[package]]
name = "ndk"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
dependencies = [
"bitflags 2.10.0",
"jni-sys",
"log",
"ndk-sys",
"num_enum",
"raw-window-handle",
"thiserror 1.0.69",
]
[[package]]
name = "ndk-sys"
version = "0.6.0+11769913"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
dependencies = [
"jni-sys",
]
[[package]]
name = "netconfig-rs"
version = "0.1.5"
@@ -1595,6 +2952,12 @@ dependencies = [
"log",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "nix"
version = "0.30.1"
@@ -1696,10 +3059,10 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
dependencies = [
"proc-macro-crate",
"proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -1711,6 +3074,201 @@ dependencies = [
"libc",
]
[[package]]
name = "objc2"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
dependencies = [
"objc2-encode",
"objc2-exception-helper",
]
[[package]]
name = "objc2-app-kit"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
dependencies = [
"bitflags 2.10.0",
"block2",
"objc2",
"objc2-core-foundation",
"objc2-foundation",
]
[[package]]
name = "objc2-cloud-kit"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
dependencies = [
"bitflags 2.10.0",
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-core-data"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa"
dependencies = [
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-core-foundation"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
dependencies = [
"bitflags 2.10.0",
"dispatch2",
"objc2",
]
[[package]]
name = "objc2-core-graphics"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
dependencies = [
"bitflags 2.10.0",
"dispatch2",
"objc2",
"objc2-core-foundation",
"objc2-io-surface",
]
[[package]]
name = "objc2-core-image"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006"
dependencies = [
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-core-location"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
dependencies = [
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-core-text"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
dependencies = [
"bitflags 2.10.0",
"objc2",
"objc2-core-foundation",
"objc2-core-graphics",
]
[[package]]
name = "objc2-encode"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
[[package]]
name = "objc2-exception-helper"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a"
dependencies = [
"cc",
]
[[package]]
name = "objc2-foundation"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
dependencies = [
"bitflags 2.10.0",
"block2",
"objc2",
"objc2-core-foundation",
]
[[package]]
name = "objc2-io-surface"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
dependencies = [
"bitflags 2.10.0",
"objc2",
"objc2-core-foundation",
]
[[package]]
name = "objc2-quartz-core"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
dependencies = [
"bitflags 2.10.0",
"objc2",
"objc2-core-foundation",
"objc2-foundation",
]
[[package]]
name = "objc2-ui-kit"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
dependencies = [
"bitflags 2.10.0",
"block2",
"objc2",
"objc2-cloud-kit",
"objc2-core-data",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-core-image",
"objc2-core-location",
"objc2-core-text",
"objc2-foundation",
"objc2-quartz-core",
"objc2-user-notifications",
]
[[package]]
name = "objc2-user-notifications"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
dependencies = [
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-web-kit"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f"
dependencies = [
"bitflags 2.10.0",
"block2",
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-foundation",
]
[[package]]
name = "oid-registry"
version = "0.8.1"
@@ -1732,12 +3290,29 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "open"
version = "5.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9cfef937e9c486488c7e3d949ae31c0f1d06bdacd75b99c086cb35356e30408"
dependencies = [
"dunce",
"is-wsl",
"libc",
]
[[package]]
name = "openssl-probe"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordered-float"
version = "2.10.1"
@@ -1747,6 +3322,41 @@ dependencies = [
"num-traits",
]
[[package]]
name = "ordered-stream"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
dependencies = [
"futures-core",
"pin-project-lite",
]
[[package]]
name = "pango"
version = "0.18.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4"
dependencies = [
"gio",
"glib",
"libc",
"once_cell",
"pango-sys",
]
[[package]]
name = "pango-sys"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "parking"
version = "2.2.1"
@@ -1813,7 +3423,7 @@ version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
dependencies = [
"base64",
"base64 0.22.1",
"serde_core",
]
@@ -1831,7 +3441,60 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
dependencies = [
"fixedbitset",
"hashbrown 0.15.5",
"indexmap",
"indexmap 2.13.0",
]
[[package]]
name = "phf"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
dependencies = [
"phf_macros",
"phf_shared",
"serde",
]
[[package]]
name = "phf_codegen"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
dependencies = [
"fastrand",
"phf_shared",
]
[[package]]
name = "phf_macros"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "phf_shared"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
dependencies = [
"siphasher",
]
[[package]]
@@ -1851,7 +3514,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -1877,6 +3540,25 @@ dependencies = [
"futures-io",
]
[[package]]
name = "pkg-config"
version = "0.3.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548"
[[package]]
name = "plist"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85"
dependencies = [
"base64 0.22.1",
"indexmap 2.13.0",
"quick-xml",
"serde",
"time",
]
[[package]]
name = "pnet_base"
version = "0.35.0"
@@ -1895,7 +3577,7 @@ dependencies = [
"proc-macro2",
"quote",
"regex",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -1919,6 +3601,70 @@ dependencies = [
"pnet_macros_support",
]
[[package]]
name = "png"
version = "0.17.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
dependencies = [
"bitflags 1.3.2",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "png"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
dependencies = [
"bitflags 2.10.0",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide",
]
[[package]]
name = "polling"
version = "3.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
dependencies = [
"cfg-if",
"concurrent-queue",
"hermit-abi",
"pin-project-lite",
"rustix",
"windows-sys 0.61.2",
]
[[package]]
name = "portable-atomic"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85"
[[package]]
name = "portable-atomic-util"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618"
dependencies = [
"portable-atomic",
]
[[package]]
name = "potential_utf"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661"
dependencies = [
"zerovec",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
@@ -1934,6 +3680,12 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "precomputed-hash"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
[[package]]
name = "prettyplease"
version = "0.2.37"
@@ -1941,7 +3693,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn",
"syn 2.0.114",
]
[[package]]
name = "proc-macro-crate"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
dependencies = [
"once_cell",
"toml_edit 0.19.15",
]
[[package]]
name = "proc-macro-crate"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24"
dependencies = [
"toml_datetime 0.6.3",
"toml_edit 0.20.2",
]
[[package]]
@@ -1950,7 +3722,31 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
dependencies = [
"toml_edit",
"toml_edit 0.23.10+spec-1.0.0",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
@@ -1978,7 +3774,7 @@ version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7"
dependencies = [
"heck",
"heck 0.5.0",
"itertools",
"log",
"multimap",
@@ -1987,7 +3783,7 @@ dependencies = [
"prost",
"prost-types",
"regex",
"syn",
"syn 2.0.114",
"tempfile",
]
@@ -2001,7 +3797,7 @@ dependencies = [
"itertools",
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -2083,6 +3879,15 @@ version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quick-xml"
version = "0.41.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1"
dependencies = [
"memchr",
]
[[package]]
name = "quinn"
version = "0.11.9"
@@ -2211,6 +4016,12 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "raw-window-handle"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "rcgen"
version = "0.14.7"
@@ -2243,6 +4054,17 @@ dependencies = [
"bitflags 2.10.0",
]
[[package]]
name = "redox_users"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
dependencies = [
"getrandom 0.2.17",
"libredox",
"thiserror 2.0.18",
]
[[package]]
name = "reed-solomon-erasure"
version = "6.0.0"
@@ -2256,6 +4078,26 @@ dependencies = [
"spin",
]
[[package]]
name = "ref-cast"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]]
name = "regex"
version = "1.12.3"
@@ -2285,6 +4127,40 @@ version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c"
[[package]]
name = "reqwest"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-core",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"js-sys",
"log",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"sync_wrapper",
"tokio",
"tokio-util",
"tower",
"tower-http 0.6.11",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
]
[[package]]
name = "ring"
version = "0.17.14"
@@ -2333,7 +4209,7 @@ dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"syn 2.0.114",
"walkdir",
]
@@ -2489,6 +4365,57 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "schemars"
version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615"
dependencies = [
"dyn-clone",
"indexmap 1.9.3",
"schemars_derive",
"serde",
"serde_json",
"url",
"uuid",
]
[[package]]
name = "schemars"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f"
dependencies = [
"dyn-clone",
"ref-cast",
"serde",
"serde_json",
]
[[package]]
name = "schemars"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a"
dependencies = [
"dyn-clone",
"ref-cast",
"serde",
"serde_json",
]
[[package]]
name = "schemars_derive"
version = "0.8.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.114",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
@@ -2524,11 +4451,34 @@ dependencies = [
"libc",
]
[[package]]
name = "selectors"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c"
dependencies = [
"bitflags 2.10.0",
"cssparser",
"derive_more",
"log",
"new_debug_unreachable",
"phf",
"phf_codegen",
"precomputed-hash",
"rustc-hash",
"servo_arc",
"smallvec",
]
[[package]]
name = "semver"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
dependencies = [
"serde",
"serde_core",
]
[[package]]
name = "serde"
@@ -2540,6 +4490,18 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde-untagged"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058"
dependencies = [
"erased-serde",
"serde",
"serde_core",
"typeid",
]
[[package]]
name = "serde-value"
version = "0.7.0"
@@ -2567,7 +4529,18 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
name = "serde_derive_internals"
version = "0.29.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
@@ -2594,6 +4567,26 @@ dependencies = [
"serde_core",
]
[[package]]
name = "serde_repr"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]]
name = "serde_spanned"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "1.0.4"
@@ -2615,19 +4608,83 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "3.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a"
dependencies = [
"base64 0.22.1",
"bs58",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.13.0",
"jiff",
"schemars 0.9.0",
"schemars 1.2.2",
"serde_core",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8705578779c2b6bd90d84d66eb2e206b708b1a4d7b9f17641b293545bf1c7e46"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"indexmap 2.13.0",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "serialize-to-javascript"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5"
dependencies = [
"serde",
"serde_json",
"serialize-to-javascript-impl",
]
[[package]]
name = "serialize-to-javascript-impl"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "servo_arc"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930"
dependencies = [
"stable_deref_trait",
]
[[package]]
name = "sha1"
version = "0.11.0"
@@ -2686,6 +4743,18 @@ dependencies = [
"libc",
]
[[package]]
name = "simd-adler32"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
[[package]]
name = "siphasher"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
[[package]]
name = "slab"
version = "0.4.12"
@@ -2718,6 +4787,54 @@ dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "softbuffer"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3"
dependencies = [
"bytemuck",
"js-sys",
"ndk",
"objc2",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation",
"objc2-quartz-core",
"raw-window-handle",
"redox_syscall 0.5.18",
"tracing",
"wasm-bindgen",
"web-sys",
"windows-sys 0.61.2",
]
[[package]]
name = "soup3"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f"
dependencies = [
"futures-channel",
"gio",
"glib",
"libc",
"soup3-sys",
]
[[package]]
name = "soup3-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27"
dependencies = [
"gio-sys",
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
]
[[package]]
name = "spin"
version = "0.9.8"
@@ -2727,6 +4844,36 @@ dependencies = [
"lock_api",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "string_cache"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901"
dependencies = [
"new_debug_unreachable",
"parking_lot 0.12.5",
"phf_shared",
"precomputed-hash",
]
[[package]]
name = "string_cache_codegen"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
]
[[package]]
name = "strsim"
version = "0.11.1"
@@ -2758,6 +4905,27 @@ version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "swift-rs"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e45c444e496845d3f2a351146bff59aae4975b2280238df1dfaa0c7d1846f38e"
dependencies = [
"base64 0.21.7",
"serde",
"serde_json",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.114"
@@ -2769,11 +4937,25 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "syn"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
dependencies = [
"futures-core",
]
[[package]]
name = "synstructure"
@@ -2783,7 +4965,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -2796,6 +4978,19 @@ dependencies = [
"libc",
]
[[package]]
name = "system-deps"
version = "6.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349"
dependencies = [
"cfg-expr",
"heck 0.5.0",
"pkg-config",
"toml 0.8.2",
"version-compare",
]
[[package]]
name = "tachyonix"
version = "0.3.1"
@@ -2809,6 +5004,330 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "tao"
version = "0.35.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9"
dependencies = [
"bitflags 2.10.0",
"block2",
"core-foundation 0.10.1",
"core-graphics",
"crossbeam-channel",
"dbus",
"dispatch2",
"dlopen2",
"dpi",
"gdkwayland-sys",
"gdkx11-sys",
"gtk",
"jni",
"libc",
"log",
"ndk",
"ndk-sys",
"objc2",
"objc2-app-kit",
"objc2-foundation",
"objc2-ui-kit",
"once_cell",
"parking_lot 0.12.5",
"percent-encoding",
"raw-window-handle",
"tao-macros",
"unicode-segmentation",
"url",
"windows 0.61.3",
"windows-core 0.61.2",
"windows-version",
"x11-dl",
]
[[package]]
name = "tao-macros"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "target-lexicon"
version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tauri"
version = "2.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5"
dependencies = [
"anyhow",
"bytes",
"cookie",
"dirs",
"dunce",
"embed_plist",
"getrandom 0.3.4",
"glob",
"gtk",
"heck 0.5.0",
"http",
"jni",
"libc",
"log",
"mime",
"muda",
"objc2",
"objc2-app-kit",
"objc2-foundation",
"objc2-ui-kit",
"objc2-web-kit",
"percent-encoding",
"plist",
"raw-window-handle",
"reqwest",
"serde",
"serde_json",
"serde_repr",
"serialize-to-javascript",
"swift-rs",
"tauri-build",
"tauri-macros",
"tauri-runtime",
"tauri-runtime-wry",
"tauri-utils",
"thiserror 2.0.18",
"tokio",
"tray-icon",
"url",
"webkit2gtk",
"webview2-com",
"window-vibrancy",
"windows 0.61.3",
]
[[package]]
name = "tauri-build"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632"
dependencies = [
"anyhow",
"cargo_toml",
"dirs",
"glob",
"heck 0.5.0",
"json-patch",
"schemars 0.8.22",
"semver",
"serde",
"serde_json",
"tauri-utils",
"tauri-winres",
"walkdir",
]
[[package]]
name = "tauri-codegen"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5"
dependencies = [
"base64 0.22.1",
"brotli",
"ico",
"json-patch",
"plist",
"png 0.17.16",
"proc-macro2",
"quote",
"semver",
"serde",
"serde_json",
"sha2 0.10.9",
"syn 2.0.114",
"tauri-utils",
"thiserror 2.0.18",
"time",
"url",
"uuid",
"walkdir",
]
[[package]]
name = "tauri-macros"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.114",
"tauri-codegen",
"tauri-utils",
]
[[package]]
name = "tauri-plugin"
version = "2.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020"
dependencies = [
"anyhow",
"glob",
"plist",
"schemars 0.8.22",
"serde",
"serde_json",
"tauri-utils",
"walkdir",
]
[[package]]
name = "tauri-plugin-opener"
version = "2.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17e1bea14edce6b793a04e2417e3fd924b9bc4faae83cdee7d714156cceeed29"
dependencies = [
"dunce",
"glob",
"objc2-app-kit",
"objc2-foundation",
"open",
"schemars 0.8.22",
"serde",
"serde_json",
"tauri",
"tauri-plugin",
"thiserror 2.0.18",
"url",
"windows 0.61.3",
"zbus",
]
[[package]]
name = "tauri-plugin-single-instance"
version = "2.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3214becf9ef5783c0ae99a3bb25adf5353a7a16ebf53e74b909e29205735c6c"
dependencies = [
"serde",
"serde_json",
"tauri",
"thiserror 2.0.18",
"tokio",
"tracing",
"windows-sys 0.60.2",
"zbus",
]
[[package]]
name = "tauri-runtime"
version = "2.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8"
dependencies = [
"cookie",
"dpi",
"gtk",
"http",
"jni",
"objc2",
"objc2-ui-kit",
"objc2-web-kit",
"raw-window-handle",
"serde",
"serde_json",
"tauri-utils",
"thiserror 2.0.18",
"url",
"webkit2gtk",
"webview2-com",
"windows 0.61.3",
]
[[package]]
name = "tauri-runtime-wry"
version = "2.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f"
dependencies = [
"gtk",
"http",
"jni",
"log",
"objc2",
"objc2-app-kit",
"once_cell",
"percent-encoding",
"raw-window-handle",
"softbuffer",
"tao",
"tauri-runtime",
"tauri-utils",
"url",
"webkit2gtk",
"webview2-com",
"windows 0.61.3",
"wry",
]
[[package]]
name = "tauri-utils"
version = "2.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887"
dependencies = [
"anyhow",
"brotli",
"cargo_metadata",
"ctor",
"dom_query",
"dunce",
"glob",
"http",
"infer",
"json-patch",
"log",
"memchr",
"phf",
"plist",
"proc-macro2",
"quote",
"regex",
"schemars 0.8.22",
"semver",
"serde",
"serde-untagged",
"serde_json",
"serde_with",
"swift-rs",
"thiserror 2.0.18",
"toml 1.0.6+spec-1.1.0",
"url",
"urlpattern",
"uuid",
"walkdir",
]
[[package]]
name = "tauri-winres"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6"
dependencies = [
"dunce",
"embed-resource",
"toml 1.0.6+spec-1.1.0",
]
[[package]]
name = "tcp_ip"
version = "0.2.2"
@@ -2840,6 +5359,15 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "tendril"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08"
dependencies = [
"new_debug_unreachable",
]
[[package]]
name = "termcolor"
version = "1.4.1"
@@ -2875,7 +5403,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -2886,7 +5414,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -2941,6 +5469,16 @@ dependencies = [
"time-core",
]
[[package]]
name = "tinystr"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "tinyvec"
version = "1.10.0"
@@ -2981,7 +5519,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -3019,19 +5557,55 @@ dependencies = [
"tokio",
]
[[package]]
name = "toml"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
dependencies = [
"serde",
"serde_spanned 0.6.9",
"toml_datetime 0.6.3",
"toml_edit 0.20.2",
]
[[package]]
name = "toml"
version = "0.9.11+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
dependencies = [
"indexmap",
"indexmap 2.13.0",
"serde_core",
"serde_spanned",
"toml_datetime",
"serde_spanned 1.0.4",
"toml_datetime 0.7.5+spec-1.1.0",
"toml_parser",
"toml_writer",
"winnow",
"winnow 0.7.14",
]
[[package]]
name = "toml"
version = "1.0.6+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "399b1124a3c9e16766831c6bba21e50192572cdd98706ea114f9502509686ffc"
dependencies = [
"indexmap 2.13.0",
"serde_core",
"serde_spanned 1.0.4",
"toml_datetime 1.1.1+spec-1.1.0",
"toml_parser",
"toml_writer",
"winnow 0.7.14",
]
[[package]]
name = "toml_datetime"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
dependencies = [
"serde",
]
[[package]]
@@ -3043,25 +5617,58 @@ dependencies = [
"serde_core",
]
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_edit"
version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap 2.13.0",
"toml_datetime 0.6.3",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
dependencies = [
"indexmap 2.13.0",
"serde",
"serde_spanned 0.6.9",
"toml_datetime 0.6.3",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.23.10+spec-1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
dependencies = [
"indexmap",
"toml_datetime",
"indexmap 2.13.0",
"toml_datetime 0.7.5+spec-1.1.0",
"toml_parser",
"winnow",
"winnow 0.7.14",
]
[[package]]
name = "toml_parser"
version = "1.0.6+spec-1.1.0"
version = "1.1.3+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
dependencies = [
"winnow",
"winnow 1.0.4",
]
[[package]]
@@ -3086,6 +5693,24 @@ dependencies = [
"tracing",
]
[[package]]
name = "tower-http"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"
dependencies = [
"bitflags 2.10.0",
"bytes",
"futures-util",
"http",
"http-body",
"pin-project-lite",
"tower",
"tower-layer",
"tower-service",
"url",
]
[[package]]
name = "tower-http"
version = "0.7.0"
@@ -3144,7 +5769,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -3186,6 +5811,34 @@ dependencies = [
"tracing-log",
]
[[package]]
name = "tray-icon"
version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e"
dependencies = [
"crossbeam-channel",
"dirs",
"libappindicator",
"muda",
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-core-graphics",
"objc2-foundation",
"once_cell",
"png 0.18.1",
"serde",
"thiserror 2.0.18",
"windows-sys 0.61.2",
]
[[package]]
name = "try-lock"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tun-rs"
version = "2.8.1"
@@ -3202,7 +5855,7 @@ dependencies = [
"getifaddrs",
"ipnet",
"libc",
"libloading",
"libloading 0.9.0",
"log",
"netconfig-rs",
"nix 0.31.1",
@@ -3236,6 +5889,12 @@ version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c"
[[package]]
name = "typeid"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
[[package]]
name = "typemap-ors"
version = "1.0.0"
@@ -3251,6 +5910,58 @@ version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]]
name = "uds_windows"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
dependencies = [
"memoffset",
"tempfile",
"windows-sys 0.61.2",
]
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-ucd-ident"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]]
name = "unicase"
version = "2.9.0"
@@ -3302,6 +6013,37 @@ version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "url"
version = "2.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
"serde_derive",
]
[[package]]
name = "urlpattern"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d"
dependencies = [
"regex",
"serde",
"unic-ucd-ident",
"url",
]
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "utf8parse"
version = "0.2.2"
@@ -3316,6 +6058,7 @@ checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f"
dependencies = [
"getrandom 0.3.4",
"js-sys",
"serde_core",
"wasm-bindgen",
]
@@ -3325,6 +6068,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
[[package]]
name = "version-compare"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e"
[[package]]
name = "version_check"
version = "0.9.5"
@@ -3375,6 +6124,25 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "vnt-desktop"
version = "2.0.0"
dependencies = [
"anyhow",
"log",
"serde",
"serde_json",
"tauri",
"tauri-build",
"tauri-plugin-opener",
"tauri-plugin-single-instance",
"tokio",
"tokio-util",
"toml 0.9.11+spec-1.1.0",
"vnt-web",
"vnt2",
]
[[package]]
name = "vnt-ipc"
version = "2.0.0"
@@ -3420,14 +6188,17 @@ dependencies = [
"log",
"mime_guess",
"parking_lot 0.12.5",
"rand 0.9.2",
"route_manager",
"rust-embed",
"serde",
"serde_json",
"time",
"tokio",
"toml",
"tower-http",
"tokio-util",
"toml 0.9.11+spec-1.1.0",
"tower",
"tower-http 0.7.0",
"vnt-core",
]
@@ -3444,11 +6215,31 @@ dependencies = [
"route_manager",
"serde",
"tokio",
"toml",
"toml 0.9.11+spec-1.1.0",
"vnt-ipc",
"vnt-web",
]
[[package]]
name = "vswhom"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b"
dependencies = [
"libc",
"vswhom-sys",
]
[[package]]
name = "vswhom-sys"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "waker-fn"
version = "1.2.0"
@@ -3465,6 +6256,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "want"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
dependencies = [
"try-lock",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
@@ -3493,6 +6293,20 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f"
dependencies = [
"cfg-if",
"futures-util",
"js-sys",
"once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.108"
@@ -3512,7 +6326,7 @@ dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
"wasm-bindgen-shared",
]
@@ -3525,6 +6339,29 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-streams"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb"
dependencies = [
"futures-util",
"js-sys",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "web-sys"
version = "0.3.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "web-time"
version = "1.1.0"
@@ -3535,6 +6372,98 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "web_atoms"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba8b815c1b593dc0baf78dd0f4fc8fdb2de53198fb1163738093e9a311c33fb3"
dependencies = [
"phf",
"phf_codegen",
"string_cache",
"string_cache_codegen",
]
[[package]]
name = "webkit2gtk"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793"
dependencies = [
"bitflags 1.3.2",
"cairo-rs",
"gdk",
"gdk-sys",
"gio",
"gio-sys",
"glib",
"glib-sys",
"gobject-sys",
"gtk",
"gtk-sys",
"javascriptcore-rs",
"libc",
"once_cell",
"soup3",
"webkit2gtk-sys",
]
[[package]]
name = "webkit2gtk-sys"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5"
dependencies = [
"bitflags 1.3.2",
"cairo-sys-rs",
"gdk-sys",
"gio-sys",
"glib-sys",
"gobject-sys",
"gtk-sys",
"javascriptcore-rs-sys",
"libc",
"pkg-config",
"soup3-sys",
"system-deps",
]
[[package]]
name = "webview2-com"
version = "0.38.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a"
dependencies = [
"webview2-com-macros",
"webview2-com-sys",
"windows 0.61.3",
"windows-core 0.61.2",
"windows-implement",
"windows-interface",
]
[[package]]
name = "webview2-com-macros"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
]
[[package]]
name = "webview2-com-sys"
version = "0.38.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c"
dependencies = [
"thiserror 2.0.18",
"windows 0.61.3",
"windows-core 0.61.2",
]
[[package]]
name = "widestring"
version = "1.2.1"
@@ -3572,6 +6501,21 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "window-vibrancy"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
dependencies = [
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-foundation",
"raw-window-handle",
"windows-sys 0.59.0",
"windows-version",
]
[[package]]
name = "windows"
version = "0.48.0"
@@ -3648,7 +6592,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -3659,7 +6603,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
@@ -3848,6 +6792,15 @@ dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows-version"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631"
dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@@ -4028,6 +6981,15 @@ version = "0.53.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
version = "0.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
dependencies = [
"memchr",
]
[[package]]
name = "winnow"
version = "0.7.14"
@@ -4037,6 +6999,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "winnow"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81"
dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.55.0"
@@ -4053,6 +7024,77 @@ version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
[[package]]
name = "writeable"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
[[package]]
name = "wry"
version = "0.55.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514"
dependencies = [
"base64 0.22.1",
"block2",
"cookie",
"crossbeam-channel",
"dirs",
"dom_query",
"dpi",
"dunce",
"gdkx11",
"gtk",
"http",
"javascriptcore-rs",
"jni",
"libc",
"ndk",
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-foundation",
"objc2-ui-kit",
"objc2-web-kit",
"once_cell",
"percent-encoding",
"raw-window-handle",
"sha2 0.10.9",
"soup3",
"tao-macros",
"thiserror 2.0.18",
"url",
"webkit2gtk",
"webkit2gtk-sys",
"webview2-com",
"windows 0.61.3",
"windows-core 0.61.2",
"windows-version",
"x11-dl",
]
[[package]]
name = "x11"
version = "2.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e"
dependencies = [
"libc",
"pkg-config",
]
[[package]]
name = "x11-dl"
version = "2.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
dependencies = [
"libc",
"once_cell",
"pkg-config",
]
[[package]]
name = "x509-parser"
version = "0.18.1"
@@ -4080,6 +7122,99 @@ dependencies = [
"time",
]
[[package]]
name = "yoke"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5"
dependencies = [
"stable_deref_trait",
"yoke-derive",
"zerofrom",
]
[[package]]
name = "yoke-derive"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
"synstructure",
]
[[package]]
name = "zbus"
version = "5.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5db4be7c075cb421e4b7ee645541604239bd243ba7c357511f4ff3a74b555907"
dependencies = [
"async-broadcast",
"async-executor",
"async-io",
"async-lock",
"async-process",
"async-recursion",
"async-task",
"async-trait",
"blocking",
"enumflags2",
"event-listener",
"futures-core",
"futures-lite",
"hex",
"libc",
"ordered-stream",
"rustix",
"serde",
"serde_repr",
"tracing",
"uds_windows",
"uuid",
"windows-sys 0.61.2",
"winnow 1.0.4",
"zbus_macros",
"zbus_names",
"zvariant",
]
[[package]]
name = "zbus_macros"
version = "5.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2990635d09ade6df1868f72f8cac69a876a90981e8bd3c40b1be413f8dc88f40"
dependencies = [
"proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
"syn 3.0.3",
"zbus_names",
"zvariant",
"zvariant_utils",
]
[[package]]
name = "zbus_names"
version = "4.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e"
dependencies = [
"serde",
"winnow 1.0.4",
"zvariant",
]
[[package]]
name = "zcheapstr"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1afec51604565183aeb5c54c20aeab286120d4e4460f7f76e3e8bb8c0d99473"
dependencies = [
"serde",
]
[[package]]
name = "zerocopy"
version = "0.8.39"
@@ -4097,7 +7232,28 @@ checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.114",
]
[[package]]
name = "zerofrom"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.114",
"synstructure",
]
[[package]]
@@ -4106,8 +7262,82 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
[[package]]
name = "zerotrie"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f"
dependencies = [
"displaydoc",
"yoke",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8"
dependencies = [
"yoke",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da"
dependencies = [
"proc-macro2",
"quote",
"syn 3.0.3",
]
[[package]]
name = "zmij"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445"
[[package]]
name = "zvariant"
version = "5.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1d34c27cc6cdd1f458427519dd6b8612f7b7e3f7b9a0b2355d041dda9869147"
dependencies = [
"endi",
"enumflags2",
"serde",
"winnow 1.0.4",
"zcheapstr",
"zvariant_derive",
"zvariant_utils",
]
[[package]]
name = "zvariant_derive"
version = "5.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864155e69b4352db0c7f374917bf45d1e0c8d17659c8b3dbf9795f3673f8c497"
dependencies = [
"proc-macro-crate 3.4.0",
"proc-macro2",
"quote",
"syn 3.0.3",
"zvariant_utils",
]
[[package]]
name = "zvariant_utils"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad0294361a320b694a328460dc73add56c306150f5cb6bfafc44446120008a3"
dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 3.0.3",
"winnow 1.0.4",
]
+2 -2
View File
@@ -6,7 +6,7 @@ edition = "2024"
[dependencies]
vnt-ipc = { path = "vnt-ipc", optional = true }
vnt-web = { path = "vnt-web", optional = true }
clap = { version = "4.5", features = ["derive"] }
clap = { version = "4.5", features = ["derive", "env"] }
tokio = { workspace = true, features = ["full"] }
@@ -43,7 +43,7 @@ path = "src/main_web.rs"
required-features = ["vnt-web"]
[workspace]
members = ["vnt-web", "vnt-ipc", "vnt-core", "vnt-jni"]
members = ["vnt-web", "vnt-ipc", "vnt-core", "vnt-jni", "vnt-desktop/src-tauri"]
[workspace.dependencies]
vnt-core = { path = "vnt-core" }
+17 -4
View File
@@ -8,6 +8,7 @@
1. vnt2_cli 是一个纯命令行组网工具,可以从命令行参数或配置文件快速启动组网
2. vnt2_ctrl 和vnt2_cli搭配使用,vnt2_cli后台运行时,可以用vnt2_ctrl来获取组网状态
3. vnt2_web 是一个集成web服务的组网工具,带web页面,可以在页面上操作组网
4. `vnt-desktop` 是基于 Tauri 2 的 PC 客户端,内置组网服务、桌面工作台和系统托盘
## 使用vnt2_cli组网
@@ -30,20 +31,32 @@
# 启动程序
./vnt2_web
```
2. 浏览器打开 http://127.0.0.1:19099
2. 从启动日志复制带 `?token=...` 的 Web 访问地址;也可以通过 `--token` 或 `VNT_WEB_TOKEN` 指定固定令牌
3. 在页面上添加组网配置,再启动组网
## 前端构建
web 前端源码位于 `vnt-web/ui/`(Vite + Vue 3 + Pinia + Tailwind CSS v4),构建产物输出到 `vnt-web/static/`,由 RustEmbed 嵌入二进制。
项目使用根级 pnpm workspace 统一管理 Web 与桌面前端依赖:
```
cd vnt-web/ui
pnpm install
pnpm build
pnpm build:web
```
开发调试使用 `pnpm dev`,Vite dev server 会将 `/api` 代理到 `127.0.0.1:19099`(需先启动 vnt2_web)
开发调试使用 `pnpm dev:web`Vite dev server 会将 `/api` 代理到 `127.0.0.1:19099`。启动 `vnt2_web` 时应指定令牌,并在浏览器登录页输入相同令牌
## PC 客户端
桌面客户端源码位于 `vnt-desktop/`Tauri 2 + Vue 3)。桌面工作台通过 Tauri IPC 直接调用进程内 `vnt-core`;需要浏览器访问时,可在“Web 访问”中按需启用同进程 HTTP 服务,无需单独运行 `vnt2_web`。Tauri 与 Web 端统一使用 `vnt-web/ui/src/` 下的同一套响应式前端代码。
```
pnpm install
pnpm dev:desktop
```
构建安装包使用 `pnpm build:desktop`。更多说明见 `vnt-desktop/README.md`。
# VNT2.0新特性
+13
View File
@@ -0,0 +1,13 @@
{
"name": "vnt-workspace",
"private": true,
"packageManager": "[email protected]",
"scripts": {
"dev:web": "pnpm --filter vnt-web-ui dev",
"build:web": "pnpm --filter vnt-web-ui build",
"dev:desktop-ui": "pnpm --filter vnt-desktop dev",
"dev:desktop": "pnpm --filter vnt-desktop tauri dev",
"build:desktop-ui": "pnpm --filter vnt-desktop build",
"build:desktop": "pnpm --filter vnt-desktop tauri build"
}
}
+193 -8
View File
@@ -4,31 +4,88 @@ settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
catalogs:
default:
'@tailwindcss/vite':
specifier: ^4.1.12
version: 4.3.3
'@vitejs/plugin-vue':
specifier: ^6.0.1
version: 6.0.8
pinia:
specifier: ^3.0.3
version: 3.0.4
tailwindcss:
specifier: ^4.1.12
version: 4.3.3
vite:
specifier: ^7.1.3
version: 7.3.6
vue:
specifier: ^3.5.18
version: 3.5.41
vue-router:
specifier: ^4.5.1
version: 4.6.4
importers:
.:
.: {}
vnt-desktop:
dependencies:
'@tauri-apps/api':
specifier: ^2.8.0
version: 2.11.1
pinia:
specifier: ^3.0.3
specifier: 'catalog:'
version: 3.0.4([email protected])
vue:
specifier: ^3.5.18
specifier: 'catalog:'
version: 3.5.41
vue-router:
specifier: ^4.5.1
specifier: 'catalog:'
version: 4.6.4([email protected])
devDependencies:
'@tailwindcss/vite':
specifier: ^4.1.12
specifier: 'catalog:'
version: 4.3.3([email protected]([email protected])([email protected]))
'@tauri-apps/cli':
specifier: ^2.8.4
version: 2.11.4
'@vitejs/plugin-vue':
specifier: ^6.0.1
specifier: 'catalog:'
version: 6.0.8([email protected]([email protected])([email protected]))([email protected])
tailwindcss:
specifier: ^4.1.12
specifier: 'catalog:'
version: 4.3.3
vite:
specifier: ^7.1.3
specifier: 'catalog:'
version: 7.3.6([email protected])([email protected])
vnt-web/ui:
dependencies:
pinia:
specifier: 'catalog:'
version: 3.0.4([email protected])
vue:
specifier: 'catalog:'
version: 3.5.41
vue-router:
specifier: 'catalog:'
version: 4.6.4([email protected])
devDependencies:
'@tailwindcss/vite':
specifier: 'catalog:'
version: 4.3.3([email protected]([email protected])([email protected]))
'@vitejs/plugin-vue':
specifier: 'catalog:'
version: 6.0.8([email protected]([email protected])([email protected]))([email protected])
tailwindcss:
specifier: 'catalog:'
version: 4.3.3
vite:
specifier: 'catalog:'
version: 7.3.6([email protected])([email protected])
packages:
@@ -464,6 +521,85 @@ packages:
peerDependencies:
vite: ^5.2.0 || ^6 || ^7 || ^8
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==}
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==}
engines: {node: '>= 10'}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@tauri-apps/[email protected]':
resolution: {integrity: sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==}
engines: {node: '>= 10'}
hasBin: true
'@types/[email protected]':
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
@@ -1019,6 +1155,55 @@ snapshots:
tailwindcss: 4.3.3
vite: 7.3.6([email protected])([email protected])
'@tauri-apps/[email protected]': {}
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optional: true
'@tauri-apps/[email protected]':
optionalDependencies:
'@tauri-apps/cli-darwin-arm64': 2.11.4
'@tauri-apps/cli-darwin-x64': 2.11.4
'@tauri-apps/cli-linux-arm-gnueabihf': 2.11.4
'@tauri-apps/cli-linux-arm64-gnu': 2.11.4
'@tauri-apps/cli-linux-arm64-musl': 2.11.4
'@tauri-apps/cli-linux-riscv64-gnu': 2.11.4
'@tauri-apps/cli-linux-x64-gnu': 2.11.4
'@tauri-apps/cli-linux-x64-musl': 2.11.4
'@tauri-apps/cli-win32-arm64-msvc': 2.11.4
'@tauri-apps/cli-win32-ia32-msvc': 2.11.4
'@tauri-apps/cli-win32-x64-msvc': 2.11.4
'@types/[email protected]': {}
'@vitejs/[email protected]([email protected]([email protected])([email protected]))([email protected])':
+12
View File
@@ -0,0 +1,12 @@
packages:
- "vnt-web/ui"
- "vnt-desktop"
catalog:
"@tailwindcss/vite": ^4.1.12
"@vitejs/plugin-vue": ^6.0.1
pinia: ^3.0.3
tailwindcss: ^4.1.12
vite: ^7.1.3
vue: ^3.5.18
vue-router: ^4.5.1
+17 -1
View File
@@ -15,6 +15,9 @@ struct Args {
/// 加载vnt配置路径,配置内容参考web端的配置格式
#[clap(long)]
conf: Option<PathBuf>,
/// Web API 访问令牌;未指定时会生成随机令牌并输出到日志
#[clap(long, env = "VNT_WEB_TOKEN")]
token: Option<String>,
}
#[tokio::main]
@@ -31,6 +34,19 @@ async fn main0() -> anyhow::Result<()> {
#[cfg(windows)]
extract_wintun_dll::extract_wintun();
let addr = args.addr.unwrap_or("127.0.0.1:19099".parse()?);
vnt_web::run_http_server(addr, args.conf).await?;
let token = args.token.unwrap_or_else(vnt_web::generate_access_token);
let browser_host = if addr.ip().is_unspecified() {
"127.0.0.1".to_string()
} else {
addr.ip().to_string()
};
log::info!("Web access token: {}", token);
log::info!(
"Web access URL: http://{}:{}/?token={}",
browser_host,
addr.port(),
token
);
vnt_web::run_http_server(addr, args.conf, token).await?;
Ok(())
}
+59
View File
@@ -0,0 +1,59 @@
# VNT Desktop
基于 Tauri 2 + Vue 3 的 VNT PC 客户端。桌面端直接内置 `vnt-web` 的服务能力,不需要另行启动 `vnt2_web`
桌面端与 Web 端共用 `vnt-web/ui/src/` 下的同一套 Vue 应用、路由、状态、组件和样式。`vnt-desktop/src/main.js` 只负责注册 Tauri IPC 桥接,不维护第二套界面代码。
## 功能
- 桌面工作台:总览、实例、在线设备、路由和配置管理
- 多实例启动、停止、重启及启动日志
- 表单 / TOML 双模式配置编辑
- 原生窗口、系统托盘、单实例运行
- 关闭主窗口时隐藏到托盘,托盘菜单可彻底退出
- 深浅主题与 `Ctrl/Cmd + 1~5` 页面快捷键
- 响应式布局:桌面侧栏、移动端顶部栏和抽屉导航
- 桌面工作台通过 Tauri IPC 直接调用进程内 `vnt-core`,不监听本地 API 端口
- 可选 Web 访问:启停、端口、本机/局域网监听范围、访问令牌、打开浏览器
- Web API 强制使用 Bearer 令牌鉴权,令牌可在桌面端重新生成
桌面数据存放在系统应用数据目录的 `com.vnt.desktop` 下,包括 `vnt_config`、自启动记录、`web_access.toml`、日志及 Windows 下的 `wintun.dll`
## 开发
要求:Rust、Node.js、pnpm,以及 Tauri 2 对应的系统依赖。
依赖由仓库根目录的 pnpm workspace 统一管理:
```powershell
pnpm install
pnpm dev:desktop
```
只验证前端:
```powershell
pnpm build:desktop-ui
```
验证 Rust 桌面模块:
```powershell
cargo check -p vnt-desktop
```
## 打包
```powershell
pnpm build:desktop
```
Windows 使用虚拟网卡模式时,可能需要以管理员身份运行。
## 应用图标
图标母版保存在 `vnt-desktop/assets/vnt-icon-master.png`。需要重新生成各平台图标时,在仓库根目录执行:
```powershell
pnpm --filter vnt-desktop tauri icon assets/vnt-icon-master.png --ios-color '#4F46E5'
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 988 KiB

+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#07111f" />
<title>VNT Desktop</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
+24
View File
@@ -0,0 +1,24 @@
{
"name": "vnt-desktop",
"private": true,
"version": "2.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"tauri": "tauri"
},
"dependencies": {
"@tauri-apps/api": "^2.8.0",
"pinia": "catalog:",
"vue": "catalog:",
"vue-router": "catalog:"
},
"devDependencies": {
"@tailwindcss/vite": "catalog:",
"@tauri-apps/cli": "^2.8.4",
"@vitejs/plugin-vue": "catalog:",
"tailwindcss": "catalog:",
"vite": "catalog:"
}
}
+26
View File
@@ -0,0 +1,26 @@
[package]
name = "vnt-desktop"
version = "2.0.0"
description = "VNT virtual network desktop client"
edition = "2024"
[lib]
name = "vnt_desktop_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.6.3", features = [] }
[dependencies]
tauri = { version = "2.11.5", features = ["tray-icon"] }
tauri-plugin-single-instance = "2.4.3"
tauri-plugin-opener = "2"
vnt-web = { path = "../../vnt-web" }
vnt2 = { path = "../.." }
log.workspace = true
tokio = { workspace = true, features = ["full"] }
tokio-util.workspace = true
serde.workspace = true
serde_json.workspace = true
toml.workspace = true
anyhow.workspace = true
+3
View File
@@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}
@@ -0,0 +1,16 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "desktop-capability",
"description": "VNT Desktop main window permissions",
"windows": ["main"],
"permissions": [
"core:default",
"core:window:allow-close",
"core:window:allow-minimize",
"core:window:allow-maximize",
"core:window:allow-unmaximize",
"core:window:allow-is-maximized",
"core:window:allow-start-dragging",
"opener:allow-open-url"
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

+322
View File
@@ -0,0 +1,322 @@
use serde::{Deserialize, Serialize};
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use tauri::menu::{Menu, MenuItem};
use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
use tauri::{AppHandle, Manager, WindowEvent};
use tauri_plugin_opener::OpenerExt;
use tokio_util::sync::CancellationToken;
use vnt_web::VntService;
#[cfg(windows)]
mod wintun;
static EXITING: AtomicBool = AtomicBool::new(false);
const WEB_ACCESS_CONFIG: &str = "web_access.toml";
#[derive(Clone, Deserialize, Serialize)]
#[serde(default)]
struct WebAccessConfig {
enabled: bool,
port: u16,
global: bool,
token: String,
}
impl Default for WebAccessConfig {
fn default() -> Self {
Self {
enabled: false,
port: 19099,
global: false,
token: vnt_web::generate_access_token(),
}
}
}
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct WebAccessStatus {
enabled: bool,
running: bool,
port: u16,
global: bool,
token: String,
url: String,
listen_address: String,
}
struct WebRuntime {
config: WebAccessConfig,
cancellation: Option<CancellationToken>,
handle: Option<tokio::task::JoinHandle<anyhow::Result<()>>>,
}
struct DesktopState {
service: VntService,
web: tokio::sync::Mutex<WebRuntime>,
config_path: PathBuf,
}
fn load_web_config(path: &Path) -> WebAccessConfig {
let mut config: WebAccessConfig = std::fs::read_to_string(path)
.ok()
.and_then(|text| toml::from_str(&text).ok())
.unwrap_or_default();
if config.port == 0 {
config.port = 19099;
}
if config.token.len() < 16 {
config.token = vnt_web::generate_access_token();
}
config
}
fn save_web_config(path: &Path, config: &WebAccessConfig) -> anyhow::Result<()> {
std::fs::write(path, toml::to_string_pretty(config)?)?;
Ok(())
}
fn listen_addr(config: &WebAccessConfig) -> SocketAddr {
let ip = if config.global {
IpAddr::V4(Ipv4Addr::UNSPECIFIED)
} else {
IpAddr::V4(Ipv4Addr::LOCALHOST)
};
SocketAddr::new(ip, config.port)
}
fn lan_ip() -> Option<IpAddr> {
let socket = UdpSocket::bind((Ipv4Addr::UNSPECIFIED, 0)).ok()?;
socket.connect((Ipv4Addr::new(8, 8, 8, 8), 80)).ok()?;
Some(socket.local_addr().ok()?.ip())
}
fn access_url(config: &WebAccessConfig) -> String {
let host = if config.global {
lan_ip().unwrap_or(IpAddr::V4(Ipv4Addr::LOCALHOST))
} else {
IpAddr::V4(Ipv4Addr::LOCALHOST)
};
format!("http://{}:{}/?token={}", host, config.port, config.token)
}
async fn stop_web(runtime: &mut WebRuntime) {
if let Some(cancellation) = runtime.cancellation.take() {
cancellation.cancel();
}
if let Some(handle) = runtime.handle.take() {
match handle.await {
Ok(Ok(())) => {}
Ok(Err(error)) => log::warn!("Web service stopped with error: {error:#}"),
Err(error) if !error.is_cancelled() => log::warn!("Web service task failed: {error}"),
Err(_) => {}
}
}
}
async fn start_web(service: &VntService, runtime: &mut WebRuntime) -> anyhow::Result<()> {
if !runtime.config.enabled {
return Ok(());
}
let cancellation = CancellationToken::new();
let handle = service
.start_http(
listen_addr(&runtime.config),
runtime.config.token.clone(),
cancellation.clone(),
)
.await?;
runtime.cancellation = Some(cancellation);
runtime.handle = Some(handle);
Ok(())
}
#[tauri::command]
async fn api_request(
state: tauri::State<'_, DesktopState>,
method: String,
path: String,
body: Option<String>,
) -> Result<serde_json::Value, String> {
if !path.starts_with("/api/") {
return Err("只允许调用 VNT API".to_string());
}
state
.service
.request(&method, &path, body)
.await
.map_err(|error| format!("{error:#}"))
}
fn web_status(runtime: &WebRuntime) -> WebAccessStatus {
WebAccessStatus {
enabled: runtime.config.enabled,
running: runtime
.handle
.as_ref()
.is_some_and(|handle| !handle.is_finished()),
port: runtime.config.port,
global: runtime.config.global,
token: runtime.config.token.clone(),
url: access_url(&runtime.config),
listen_address: listen_addr(&runtime.config).to_string(),
}
}
#[tauri::command]
async fn web_access_status(
state: tauri::State<'_, DesktopState>,
) -> Result<WebAccessStatus, String> {
let runtime = state.web.lock().await;
Ok(web_status(&runtime))
}
#[tauri::command]
async fn update_web_access(
state: tauri::State<'_, DesktopState>,
config: WebAccessConfig,
) -> Result<WebAccessStatus, String> {
if config.port == 0 {
return Err("监听端口必须在 1-65535 之间".to_string());
}
if config.token.len() < 16 {
return Err("访问令牌至少需要 16 个字符".to_string());
}
let mut runtime = state.web.lock().await;
stop_web(&mut runtime).await;
let previous = runtime.config.clone();
runtime.config = config;
if let Err(error) = start_web(&state.service, &mut runtime).await {
runtime.config = previous;
if let Err(restore_error) = start_web(&state.service, &mut runtime).await {
log::error!("Failed to restore Web service: {restore_error:#}");
}
return Err(format!("无法启动 Web 服务:{error:#}"));
}
save_web_config(&state.config_path, &runtime.config)
.map_err(|error| format!("保存 Web 访问设置失败:{error:#}"))?;
Ok(web_status(&runtime))
}
#[tauri::command]
fn generate_web_token() -> String {
vnt_web::generate_access_token()
}
#[tauri::command]
fn open_web_url(app: AppHandle, url: String) -> Result<(), String> {
if !url.starts_with("http://") && !url.starts_with("https://") {
return Err("只允许打开 HTTP(S) 地址".to_string());
}
app.opener()
.open_url(url, None::<&str>)
.map_err(|error| error.to_string())
}
fn show_main_window(app: &AppHandle) {
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.unminimize();
let _ = window.set_focus();
}
}
fn toggle_main_window(app: &AppHandle) {
if let Some(window) = app.get_webview_window("main") {
match window.is_visible() {
Ok(true) => {
let _ = window.hide();
}
_ => show_main_window(app),
}
}
}
pub fn run() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![
api_request,
web_access_status,
update_web_access,
generate_web_token,
open_web_url
])
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
show_main_window(app);
}))
.setup(|app| {
let data_dir = app.path().app_data_dir()?;
std::fs::create_dir_all(&data_dir)?;
std::env::set_current_dir(&data_dir)?;
vnt2::log::log_init("vnt-desktop");
#[cfg(windows)]
wintun::ensure_wintun(&data_dir)?;
let config_path = data_dir.join(WEB_ACCESS_CONFIG);
let config = load_web_config(&config_path);
save_web_config(&config_path, &config)?;
let service = tauri::async_runtime::block_on(VntService::new(None))?;
let mut web = WebRuntime {
config,
cancellation: None,
handle: None,
};
if let Err(error) = tauri::async_runtime::block_on(start_web(&service, &mut web)) {
log::error!("Failed to restore Web access service: {error:#}");
web.config.enabled = false;
save_web_config(&config_path, &web.config)?;
}
app.manage(DesktopState {
service,
web: tokio::sync::Mutex::new(web),
config_path,
});
let show = MenuItem::with_id(app, "show", "显示主窗口", true, None::<&str>)?;
let quit = MenuItem::with_id(app, "quit", "退出 VNT", true, None::<&str>)?;
let menu = Menu::with_items(app, &[&show, &quit])?;
let mut tray = TrayIconBuilder::with_id("vnt-tray")
.tooltip("VNT Desktop")
.menu(&menu)
.show_menu_on_left_click(false)
.on_menu_event(|app, event| match event.id.as_ref() {
"show" => show_main_window(app),
"quit" => {
EXITING.store(true, Ordering::SeqCst);
app.exit(0);
}
_ => {}
})
.on_tray_icon_event(|tray, event| {
if let TrayIconEvent::Click {
button: MouseButton::Left,
button_state: MouseButtonState::Up,
..
} = event
{
toggle_main_window(tray.app_handle());
}
});
if let Some(icon) = app.default_window_icon() {
tray = tray.icon(icon.clone());
}
tray.build(app)?;
Ok(())
})
.on_window_event(|window, event| {
if let WindowEvent::CloseRequested { api, .. } = event
&& !EXITING.load(Ordering::SeqCst)
{
api.prevent_close();
let _ = window.hide();
}
})
.run(tauri::generate_context!())
.expect("error while running VNT Desktop");
}
+3
View File
@@ -0,0 +1,3 @@
fn main() {
vnt_desktop_lib::run();
}
+20
View File
@@ -0,0 +1,20 @@
use std::io;
use std::path::Path;
#[cfg(target_arch = "x86_64")]
const WINTUN_DLL: &[u8] = include_bytes!("../../../dll/amd64/wintun.dll");
#[cfg(target_arch = "x86")]
const WINTUN_DLL: &[u8] = include_bytes!("../../../dll/x86/wintun.dll");
#[cfg(target_arch = "aarch64")]
const WINTUN_DLL: &[u8] = include_bytes!("../../../dll/arm64/wintun.dll");
#[cfg(target_arch = "arm")]
const WINTUN_DLL: &[u8] = include_bytes!("../../../dll/arm/wintun.dll");
pub fn ensure_wintun(data_dir: &Path) -> io::Result<()> {
let target = data_dir.join("wintun.dll");
let current = std::fs::read(&target).unwrap_or_default();
if current != WINTUN_DLL {
std::fs::write(target, WINTUN_DLL)?;
}
Ok(())
}
+49
View File
@@ -0,0 +1,49 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "VNT Desktop",
"version": "2.0.0",
"identifier": "com.vnt.desktop",
"build": {
"beforeDevCommand": "pnpm dev",
"devUrl": "http://127.0.0.1:1420",
"beforeBuildCommand": "pnpm build",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"label": "main",
"title": "VNT Desktop",
"width": 1180,
"height": 760,
"minWidth": 820,
"minHeight": 600,
"center": true,
"decorations": true,
"resizable": true,
"shadow": true
}
],
"security": {
"csp": "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' asset: data:; connect-src 'self' ipc: http://ipc.localhost http://127.0.0.1:*"
}
},
"bundle": {
"active": true,
"targets": "all",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/[email protected]",
"icons/icon.icns",
"icons/icon.ico"
],
"category": "Utility",
"shortDescription": "轻量、高效的虚拟局域网桌面客户端",
"longDescription": "VNT Desktop 用于创建和管理安全、快速的虚拟局域网连接。",
"windows": {
"wix": { "language": "zh-CN" },
"nsis": { "displayLanguageSelector": false }
}
}
}
+14
View File
@@ -0,0 +1,14 @@
import { invoke } from "@tauri-apps/api/core";
globalThis.__VNT_DESKTOP__ = true;
globalThis.__VNT_IPC_REQUEST__ = ({ method, path, body }) =>
invoke("api_request", { method, path, body });
globalThis.__VNT_WEB_ACCESS__ = {
status: () => invoke("web_access_status"),
update: (config) => invoke("update_web_access", { config }),
generateToken: () => invoke("generate_web_token"),
openUrl: (url) => invoke("open_web_url", { url }),
};
// Tauri 与 Web 端共用同一个 Vue 应用,这里只负责平台初始化。
await import("@shared/main.js");
+24
View File
@@ -0,0 +1,24 @@
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import tailwindcss from "@tailwindcss/vite";
const sharedUi = fileURLToPath(new URL("../vnt-web/ui/src", import.meta.url));
const desktopRoot = fileURLToPath(new URL(".", import.meta.url));
export default defineConfig({
plugins: [vue(), tailwindcss()],
resolve: {
alias: {
"@shared": sharedUi,
},
},
server: {
port: 1420,
strictPort: true,
host: "127.0.0.1",
fs: { allow: [desktopRoot, sharedUi] },
watch: { ignored: ["**/src-tauri/**"] },
},
clearScreen: false,
});
+3
View File
@@ -8,6 +8,7 @@ vnt-core.workspace = true
tokio = { workspace = true, features = ["full"] }
axum = "0.8.8"
tower-http = { version = "0.7", features = ["fs", "cors", "trace"] }
tower = { version = "0.5", features = ["util"] }
serde.workspace = true
serde_json.workspace = true
@@ -21,3 +22,5 @@ rust-embed = "8.0"
mime_guess = "2.0"
parking_lot.workspace = true
time = { workspace = true, features = ["local-offset", "formatting", "macros"] }
tokio-util.workspace = true
rand = "0.9"
+1 -1
View File
@@ -1,6 +1,6 @@
mod service_http;
pub use service_http::run_http_server;
pub use service_http::{VntService, generate_access_token, run_http_server};
struct ScopeGuard<F: FnOnce()>(Option<F>);
+165 -35
View File
@@ -1,7 +1,7 @@
use crate::defer;
use anyhow::{Context, anyhow, bail};
use axum::body::Body;
use axum::http::{HeaderMap, HeaderValue, StatusCode, Uri, header};
use axum::body::{Body, to_bytes};
use axum::http::{HeaderMap, HeaderValue, Method, StatusCode, Uri, header};
use axum::response::IntoResponse;
use axum::{
Json, Router,
@@ -13,6 +13,7 @@ use axum::{
use ipnet::Ipv4Net;
use mime_guess::from_path;
use parking_lot::Mutex;
use rand::Rng;
use rust_embed::RustEmbed;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
@@ -23,6 +24,8 @@ use std::time::{Instant, SystemTime, UNIX_EPOCH};
use time::{OffsetDateTime, format_description};
use tokio::fs;
use tokio::net::TcpListener;
use tokio_util::sync::CancellationToken;
use tower::ServiceExt;
use tower_http::cors::{Any, CorsLayer};
use vnt_core::api::VntApi;
use vnt_core::context::config::Config as CoreConfig;
@@ -465,37 +468,86 @@ async fn logging_middleware(req: Request, next: axum::middleware::Next) -> Respo
#[folder = "static/"]
struct Asset;
pub async fn run_http_server(
addr: SocketAddr,
start_config_file_name: Option<PathBuf>,
) -> anyhow::Result<()> {
fs::create_dir_all(CONFIG_DIR)
.await
.context("Failed to create config directory")?;
/// 进程内 VNT 业务服务。HTTP 和 Tauri IPC 共用同一组 handler 与状态。
#[derive(Clone)]
pub struct VntService {
router: Router,
}
let state = HttpAppState {
inner: Arc::new(Default::default()),
};
impl VntService {
pub async fn new(start_config_file_name: Option<PathBuf>) -> anyhow::Result<Self> {
fs::create_dir_all(CONFIG_DIR)
.await
.context("Failed to create config directory")?;
// 自动启动逻辑
let auto_start_files = determine_auto_start_files(start_config_file_name).await;
let state = HttpAppState {
inner: Arc::new(Default::default()),
};
for (file_name, path) in auto_start_files {
log::info!("Auto starting VNT with config: {:?}", path);
let state_clone = state.clone();
tokio::spawn(async move {
if let Err(e) = start_vnt_internal(&state_clone, file_name, path).await {
log::error!("Auto start failed: {:?}", e);
}
});
for (file_name, path) in determine_auto_start_files(start_config_file_name).await {
log::info!("Auto starting VNT with config: {:?}", path);
let state_clone = state.clone();
tokio::spawn(async move {
if let Err(e) = start_vnt_internal(&state_clone, file_name, path).await {
log::error!("Auto start failed: {:?}", e);
}
});
}
Ok(Self {
router: api_router(state),
})
}
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);
/// 由 Tauri command 调用,不经过 TCP/HTTP 监听端口。
pub async fn request(
&self,
method: &str,
path: &str,
body: Option<String>,
) -> anyhow::Result<serde_json::Value> {
let method = Method::from_bytes(method.as_bytes()).context("Invalid request method")?;
let request = axum::http::Request::builder()
.method(method)
.uri(path)
.header(header::CONTENT_TYPE, "application/json")
.body(Body::from(body.unwrap_or_default()))?;
let response = self.router.clone().oneshot(request).await?;
let status = response.status();
let bytes = to_bytes(response.into_body(), 8 * 1024 * 1024).await?;
let value: serde_json::Value = serde_json::from_slice(&bytes)
.with_context(|| format!("Invalid service response ({status})"))?;
Ok(value)
}
let app = Router::new()
/// 在当前进程中按需开放带令牌鉴权的 Web 服务。
pub async fn start_http(
&self,
addr: SocketAddr,
token: String,
cancellation: CancellationToken,
) -> anyhow::Result<tokio::task::JoinHandle<anyhow::Result<()>>> {
let listener = TcpListener::bind(addr).await?;
let actual_addr = listener.local_addr()?;
let app = http_router(self.router.clone(), token);
log::info!("HTTP API Listening on http://{}", actual_addr);
Ok(tokio::spawn(async move {
axum::serve(listener, app)
.with_graceful_shutdown(cancellation.cancelled_owned())
.await?;
Ok(())
}))
}
}
pub fn generate_access_token() -> String {
let mut bytes = [0_u8; 24];
rand::rng().fill(&mut bytes);
bytes.iter().map(|byte| format!("{byte:02x}")).collect()
}
fn api_router(state: HttpAppState) -> Router {
Router::new()
.route("/api/version", get(get_version))
.route("/api/info", get(get_info))
.route("/api/peers", get(get_peers))
@@ -511,17 +563,56 @@ pub async fn run_http_server(
"/api/config",
get(get_config).post(save_config).delete(delete_config),
)
.with_state(state)
}
async fn token_auth_middleware(
State(token): State<String>,
req: Request,
next: axum::middleware::Next,
) -> Response {
let authorized = req
.headers()
.get(header::AUTHORIZATION)
.and_then(|value| value.to_str().ok())
.and_then(|value| value.strip_prefix("Bearer "))
.is_some_and(|provided| provided == token);
if !authorized {
return (
StatusCode::UNAUTHORIZED,
Json(ApiResponse::<()>::error("访问令牌无效或已过期")),
)
.into_response();
}
next.run(req).await
}
fn http_router(api: Router, token: String) -> Router {
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);
Router::new()
.merge(api.layer(middleware::from_fn_with_state(
token,
token_auth_middleware,
)))
.fallback(static_handler)
.layer(cors)
.layer(middleware::from_fn(logging_middleware))
.with_state(state)
.fallback(static_handler);
log::info!("HTTP API Listening on http://{}", addr);
let listener = TcpListener::bind(addr).await?;
axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal())
.await?;
}
pub async fn run_http_server(
addr: SocketAddr,
start_config_file_name: Option<PathBuf>,
token: String,
) -> anyhow::Result<()> {
let service = VntService::new(start_config_file_name).await?;
let cancellation = CancellationToken::new();
let handle = service.start_http(addr, token, cancellation.clone()).await?;
shutdown_signal().await;
cancellation.cancel();
handle.await??;
Ok(())
}
@@ -1498,6 +1589,45 @@ async fn get_routes(
mod tests {
use super::*;
#[tokio::test]
async fn test_ipc_request_uses_in_process_router() {
let service = VntService {
router: api_router(new_test_state()),
};
let response = service.request("GET", "/api/version", None).await.unwrap();
assert_eq!(response["code"], 0);
assert!(response["data"].as_str().is_some_and(|value| !value.is_empty()));
}
#[tokio::test]
async fn test_http_api_requires_bearer_token() {
let token = "test-token-with-enough-entropy".to_string();
let app = http_router(api_router(new_test_state()), token.clone());
let unauthorized = app
.clone()
.oneshot(
axum::http::Request::builder()
.uri("/api/version")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(unauthorized.status(), StatusCode::UNAUTHORIZED);
let authorized = app
.oneshot(
axum::http::Request::builder()
.uri("/api/version")
.header(header::AUTHORIZATION, format!("Bearer {token}"))
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(authorized.status(), StatusCode::OK);
}
#[test]
fn test_normalize_config_file_name() {
// 无扩展名补 .toml
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+2 -2
View File
@@ -19,8 +19,8 @@
if (dark) document.documentElement.classList.add("dark");
})();
</script>
<script type="module" crossorigin src="/assets/index-DM6YOQ55.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-xUGHQxai.css">
<script type="module" crossorigin src="/assets/index-BxCqIugQ.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BgNGjSZS.css">
</head>
<body>
<div id="app"></div>
+7 -7
View File
@@ -8,14 +8,14 @@
"build": "vite build"
},
"dependencies": {
"pinia": "^3.0.3",
"vue": "^3.5.18",
"vue-router": "^4.5.1"
"pinia": "catalog:",
"vue": "catalog:",
"vue-router": "catalog:"
},
"devDependencies": {
"@tailwindcss/vite": "^4.1.12",
"@vitejs/plugin-vue": "^6.0.1",
"tailwindcss": "^4.1.12",
"vite": "^7.1.3"
"@tailwindcss/vite": "catalog:",
"@vitejs/plugin-vue": "catalog:",
"tailwindcss": "catalog:",
"vite": "catalog:"
}
}
+93 -215
View File
@@ -1,203 +1,116 @@
<script setup>
import { ref, provide } from "vue";
import { computed, onBeforeUnmount, onMounted, provide, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import { useAppStore } from "./stores/app";
import { useStartLogStore } from "./stores/startLog";
import { visibleNavItems } from "./navigation";
import AppSidebar from "./components/AppSidebar.vue";
import AppModal from "./components/AppModal.vue";
import ToastHost from "./components/ToastHost.vue";
import ConfirmHost from "./components/ConfirmHost.vue";
import StatusDot from "./components/StatusDot.vue";
import AppTooltip from "./components/AppTooltip.vue";
import ConfirmHost from "./components/ConfirmHost.vue";
import ToastHost from "./components/ToastHost.vue";
import AccessGate from "./components/AccessGate.vue";
import { authorized, isDesktop } from "./auth";
const app = useAppStore();
const startLog = useStartLogStore();
const route = useRoute();
const router = useRouter();
const tooltipRef = ref(null);
provide("peerTooltip", tooltipRef);
// :localStorage ,
const isDark = ref(document.documentElement.classList.contains("dark"));
const mobileNavOpen = ref(false);
const items = visibleNavItems();
const pageMeta = computed(() => items.find((item) => item.to === route.path) || items[0]);
const savedTheme = localStorage.getItem("vnt-theme");
const isDark = ref(savedTheme
? savedTheme === "dark"
: window.matchMedia("(prefers-color-scheme: dark)").matches);
const applyTheme = () => document.documentElement.classList.toggle("dark", isDark.value);
const toggleTheme = () => {
isDark.value = !isDark.value;
document.documentElement.classList.toggle("dark", isDark.value);
localStorage.setItem("vnt-theme", isDark.value ? "dark" : "light");
applyTheme();
};
applyTheme();
watch(() => route.path, () => { mobileNavOpen.value = false; });
const handleKeydown = (event) => {
if (!(event.ctrlKey || event.metaKey) || event.altKey) return;
const index = Number(event.key) - 1;
if (index >= 0 && index < items.length) {
event.preventDefault();
router.push(items[index].to);
}
};
const mobileNavOpen = ref(false);
const closeMobileNav = () => {
mobileNavOpen.value = false;
};
const navItems = [
{
to: "/",
label: "总览",
exact: true,
icon: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6",
},
{
to: "/instances",
label: "实例",
icon: "M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01",
},
{
to: "/config",
label: "配置",
icon: "M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z",
icon2: "M15 12a3 3 0 11-6 0 3 3 0 016 0z",
},
{
to: "/peers",
label: "设备列表",
icon: "M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z",
},
{
to: "/routes",
label: "路由",
icon: "M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 01-.806-.98l-3.747-1.874M12 7v13m3-13v13m-3 0l3 3",
},
];
onMounted(() => window.addEventListener("keydown", handleKeydown));
onBeforeUnmount(() => window.removeEventListener("keydown", handleKeydown));
</script>
<template>
<div class="flex min-h-screen flex-col">
<!-- 顶部导航栏 -->
<header
class="sticky top-0 z-30 border-b border-slate-200 bg-white/80 backdrop-blur dark:border-slate-800 dark:bg-slate-900/80"
>
<div class="mx-auto flex h-14 max-w-6xl items-center gap-3 px-4 lg:px-8">
<!-- 移动端汉堡 -->
<AccessGate v-if="!isDesktop && !authorized" />
<div v-else class="flex h-[100dvh] min-h-0 overflow-hidden bg-slate-50 text-slate-700 dark:bg-slate-950 dark:text-slate-200">
<aside class="hidden w-60 shrink-0 border-r border-slate-200 dark:border-slate-800 lg:block">
<AppSidebar />
</aside>
<transition name="drawer">
<div v-if="mobileNavOpen" class="fixed inset-0 z-40 lg:hidden">
<button class="absolute inset-0 bg-slate-950/45 backdrop-blur-[2px]" aria-label="关闭导航" @click="mobileNavOpen = false"></button>
<aside class="drawer-panel relative h-full w-[min(82vw,288px)] border-r border-slate-200 shadow-2xl dark:border-slate-700">
<AppSidebar @navigate="mobileNavOpen = false" />
</aside>
</div>
</transition>
<div class="flex min-w-0 flex-1 flex-col">
<header class="flex h-16 shrink-0 items-center gap-3 border-b border-slate-200 bg-white/90 px-4 backdrop-blur lg:px-6 dark:border-slate-800 dark:bg-slate-900/90">
<button
class="rounded-lg p-1.5 text-slate-500 hover:bg-slate-100 hover:text-slate-900 lg:hidden dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-white"
@click="mobileNavOpen = !mobileNavOpen"
class="grid h-9 w-9 shrink-0 place-items-center rounded-lg text-slate-500 hover:bg-slate-100 hover:text-slate-900 lg:hidden dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-white"
aria-label="打开导航"
@click="mobileNavOpen = true"
>
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
<svg class="h-5 w-5 fill-none stroke-current" viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h16" stroke-linecap="round" stroke-width="2" /></svg>
</button>
<!-- Logo -->
<router-link to="/" class="flex items-center gap-2" @click="closeMobileNav">
<span class="text-lg font-bold tracking-wide text-indigo-600 dark:text-indigo-400">VNT</span>
<span class="text-sm font-medium text-slate-400 dark:text-slate-500">Web</span>
</router-link>
<div class="min-w-0">
<h1 class="truncate text-lg font-bold text-slate-900 dark:text-white">{{ pageMeta.label }}</h1>
<p class="hidden text-xs text-slate-400 sm:block">VNT 虚拟局域网管理</p>
</div>
<!-- 桌面导航 -->
<nav class="ml-6 hidden h-14 items-stretch gap-1 lg:flex">
<router-link
v-for="item in navItems"
:key="item.to"
:to="item.to"
custom
v-slot="{ navigate, isActive, isExactActive }"
>
<button
@click="navigate"
class="relative flex items-center px-3 text-sm font-medium transition-colors"
:class="
(item.exact ? isExactActive : isActive)
? 'text-indigo-600 dark:text-indigo-400'
: 'text-slate-500 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white'
"
>
{{ item.label }}
<span
v-if="item.exact ? isExactActive : isActive"
class="absolute inset-x-3 bottom-0 h-0.5 rounded-full bg-indigo-600 dark:bg-indigo-400"
></span>
</button>
</router-link>
</nav>
<div class="ml-auto flex items-center gap-3">
<!-- 全局状态点 -->
<div
class="flex items-center gap-2 rounded-full border border-slate-200 bg-white px-3 py-1 dark:border-slate-700 dark:bg-slate-800"
:title="app.headerStatusText"
>
<StatusDot
:status="app.runningCount > 0 ? 'running' : app.startingCount > 0 ? 'starting' : 'stopped'"
/>
<span class="hidden text-xs font-medium text-slate-600 sm:inline dark:text-slate-300">{{
app.headerStatusText
}}</span>
<div class="ml-auto flex items-center gap-2">
<div class="flex h-8 items-center gap-2 rounded-lg border border-slate-200 bg-white px-2.5 text-xs font-medium text-slate-500 sm:px-3 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300">
<span
class="h-1.5 w-1.5 rounded-full"
:class="app.runningCount > 0 ? 'bg-green-500' : app.startingCount > 0 ? 'animate-pulse bg-amber-400' : 'bg-slate-300 dark:bg-slate-600'"
></span>
<span class="hidden sm:inline">{{ app.headerStatusText }}</span>
</div>
<span class="hidden text-xs text-slate-400 md:inline dark:text-slate-500"
>v{{ app.version || "-" }}</span
>
<!-- 主题切换 -->
<button
class="rounded-lg border border-slate-200 bg-white p-1.5 text-slate-500 shadow-sm transition-colors hover:bg-slate-50 hover:text-slate-900 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:bg-slate-700 dark:hover:text-white"
:title="isDark ? '切换浅色模式' : '切换深色模式'"
class="grid h-8 w-8 place-items-center rounded-lg border border-slate-200 bg-white text-slate-500 hover:border-indigo-300 hover:text-indigo-600 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-400 dark:hover:border-indigo-500 dark:hover:text-indigo-400"
:title="isDark ? '切换浅色模式' : '切换深色模式'"
:aria-label="isDark ? '切换浅色模式' : '切换深色模式'"
@click="toggleTheme"
>
<svg v-if="isDark" class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
/>
</svg>
<svg v-else class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
/>
</svg>
<svg v-if="isDark" class="h-4 w-4 fill-none stroke-current" viewBox="0 0 24 24"><circle cx="12" cy="12" r="4"/><path d="M12 2v2m0 16v2M4.9 4.9l1.4 1.4m11.4 11.4 1.4 1.4M2 12h2m16 0h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" stroke-linecap="round" stroke-width="1.7"/></svg>
<svg v-else class="h-4 w-4 fill-none stroke-current" viewBox="0 0 24 24"><path d="M20.5 15.2A8.5 8.5 0 0 1 8.8 3.5 8.5 8.5 0 1 0 20.5 15.2Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.7"/></svg>
</button>
</div>
</div>
</header>
<!-- 移动端下拉导航 -->
<transition name="navdrop">
<nav
v-if="mobileNavOpen"
class="border-t border-slate-200 bg-white px-4 py-2 lg:hidden dark:border-slate-800 dark:bg-slate-900"
>
<router-link
v-for="item in navItems"
:key="item.to"
:to="item.to"
custom
v-slot="{ navigate, isActive, isExactActive }"
>
<button
@click="
navigate();
closeMobileNav();
"
class="flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium transition-colors"
:class="
(item.exact ? isExactActive : isActive)
? 'bg-indigo-50 text-indigo-600 dark:bg-indigo-500/10 dark:text-indigo-400'
: 'text-slate-500 hover:bg-slate-50 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-white'
"
>
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" :d="item.icon" />
<path v-if="item.icon2" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" :d="item.icon2" />
</svg>
{{ item.label }}
</button>
</router-link>
</nav>
</transition>
</header>
<main class="custom-scrollbar min-h-0 flex-1 overflow-x-hidden overflow-y-auto">
<div class="mx-auto w-full max-w-7xl px-4 py-5 sm:px-5 lg:px-7 lg:py-6">
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in"><component :is="Component" /></transition>
</router-view>
</div>
</main>
</div>
<!-- 内容区 -->
<main class="flex-1 overflow-x-hidden">
<div class="mx-auto w-full max-w-6xl px-4 py-6 lg:px-8">
<router-view v-slot="{ Component }">
<transition name="fade" mode="out-in">
<component :is="Component" />
</transition>
</router-view>
</div>
</main>
<!-- 启动日志弹窗 (全局) -->
<AppModal
:show="startLog.showStartLog"
:mask-closable="startLog.startStatus !== 'starting'"
@@ -206,66 +119,31 @@ const navItems = [
@close="startLog.close"
>
<template #header>
<div class="flex items-center gap-3">
<div
v-if="startLog.startStatus === 'starting'"
class="h-3 w-3 animate-ping rounded-full bg-blue-500"
></div>
<div v-else-if="startLog.startStatus === 'running'" class="h-3 w-3 rounded-full bg-green-500"></div>
<div v-else class="h-3 w-3 rounded-full bg-red-500"></div>
<h3 class="text-lg font-bold text-slate-900 dark:text-white">
{{
startLog.startStatus === "starting"
? "正在启动组网..."
: startLog.startStatus === "running"
? "启动成功"
: "启动失败"
}}
<div class="flex min-w-0 items-center gap-3">
<span
class="h-2 w-2 shrink-0 rounded-full"
:class="startLog.startStatus === 'starting' ? 'animate-pulse bg-amber-400' : startLog.startStatus === 'running' ? 'bg-green-500' : 'bg-red-500'"
></span>
<h3 class="truncate text-base font-bold text-slate-900 sm:text-lg dark:text-white">
{{ startLog.startStatus === "starting" ? "正在建立虚拟网络" : startLog.startStatus === "running" ? "网络已连接" : "连接未完成" }}
</h3>
</div>
<div class="flex items-center gap-3">
<span
class="max-w-[200px] truncate text-sm font-medium text-indigo-600 dark:text-indigo-400"
:title="startLog.logFileName"
>{{ startLog.logConfigName }}</span
>
<span class="font-mono text-xs uppercase tracking-widest text-slate-400">{{
startLog.startStatus
}}</span>
</div>
<span class="max-w-[40%] truncate font-mono text-xs text-indigo-600 dark:text-indigo-400">{{ startLog.logConfigName }}</span>
</template>
<template #body>
<div
:ref="(el) => (startLog.logContainer = el)"
class="scrollbar-hide h-80 space-y-2 overflow-y-auto bg-slate-50 p-6 font-mono text-sm dark:bg-black/20"
class="custom-scrollbar h-64 space-y-2 overflow-y-auto border-y border-slate-200 bg-slate-50 p-4 font-mono text-xs text-slate-600 sm:h-80 sm:p-6 dark:border-slate-800 dark:bg-slate-950 dark:text-slate-300"
>
<div v-for="(log, idx) in startLog.startLogs" :key="idx" class="flex gap-3">
<span class="shrink-0 text-indigo-500 dark:text-indigo-400">>>></span>
<span class="break-all text-slate-600 dark:text-slate-300">{{ log }}</span>
</div>
<div v-if="startLog.startStatus === 'starting'" class="mt-4 animate-pulse italic text-blue-500">
等待后续步骤...
</div>
<div
v-if="startLog.startStatus === 'stopped' && startLog.startLogs.length > 0"
class="mt-4 rounded-lg border border-red-200 bg-red-50 p-3 text-red-600 dark:border-red-900/50 dark:bg-red-900/20 dark:text-red-400"
>
<strong>启动失败:</strong>
请检查配置或网络连接
<span class="text-indigo-600 dark:text-indigo-400"></span><span class="break-all">{{ log }}</span>
</div>
<div v-if="startLog.startStatus === 'starting'" class="animate-pulse text-indigo-600 dark:text-indigo-400">等待下一阶段</div>
</div>
</template>
<template #footer>
<button v-if="startLog.startStatus === 'starting'" class="btn-ghost" @click="startLog.cancelStart">
取消组网
</button>
<button
v-if="startLog.startStatus === 'stopped' || startLog.startStatus === 'running'"
class="btn-primary"
@click="startLog.close"
>
关闭窗口
</button>
<button v-if="startLog.startStatus === 'starting'" class="btn-ghost" @click="startLog.cancelStart">取消连接</button>
<button v-else class="btn-primary" @click="startLog.close">完成</button>
</template>
</AppModal>
+19 -3
View File
@@ -1,7 +1,23 @@
// fetch 封装:统一解包 ApiResponse{code,msg,data},code!==0 抛出带 msg 的错误
const request = async (url, options) => {
const res = await fetch(url, options);
import { clearAccessToken, getAccessToken } from "../auth";
// HTTP 与 Tauri IPC 共用相同的 ApiResponse{code,msg,data} 协议。
const request = async (url, options = {}) => {
if (globalThis.__VNT_IPC_REQUEST__) {
const json = await globalThis.__VNT_IPC_REQUEST__({
method: options.method || "GET",
path: url,
body: options.body || null,
});
if (json.code !== 0) throw new Error(json.msg || "请求失败");
return json.data;
}
const headers = new Headers(options.headers || {});
const token = getAccessToken();
if (token) headers.set("Authorization", `Bearer ${token}`);
const res = await fetch(url, { ...options, headers });
const json = await res.json();
if (res.status === 401) clearAccessToken();
if (json.code !== 0) {
throw new Error(json.msg || "请求失败");
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

+32
View File
@@ -0,0 +1,32 @@
import { ref } from "vue";
const STORAGE_KEY = "vnt-web-access-token";
export const isDesktop = Boolean(globalThis.__VNT_DESKTOP__);
const url = new URL(window.location.href);
const tokenFromUrl = url.searchParams.get("token") || "";
if (tokenFromUrl) {
localStorage.setItem(STORAGE_KEY, tokenFromUrl);
url.searchParams.delete("token");
window.history.replaceState({}, "", `${url.pathname}${url.search}${url.hash}`);
}
export const accessToken = ref(
isDesktop ? "" : tokenFromUrl || localStorage.getItem(STORAGE_KEY) || "",
);
export const authorized = ref(isDesktop || Boolean(accessToken.value));
export const getAccessToken = () => accessToken.value;
export const saveAccessToken = (token) => {
const normalized = token.trim();
localStorage.setItem(STORAGE_KEY, normalized);
accessToken.value = normalized;
authorized.value = Boolean(normalized);
};
export const clearAccessToken = () => {
localStorage.removeItem(STORAGE_KEY);
accessToken.value = "";
authorized.value = false;
};
+30
View File
@@ -0,0 +1,30 @@
<script setup>
import { ref } from "vue";
import { saveAccessToken } from "../auth";
import vntIcon from "../assets/vnt-icon.png";
const token = ref("");
const submit = () => {
if (!token.value.trim()) return;
saveAccessToken(token.value);
window.location.reload();
};
</script>
<template>
<main class="grid h-[100dvh] place-items-center overflow-y-auto bg-slate-50 p-4 text-slate-700 dark:bg-slate-950 dark:text-slate-200">
<form class="w-full max-w-md rounded-2xl border border-slate-200 bg-white p-6 shadow-sm sm:p-8 dark:border-slate-800 dark:bg-slate-900" @submit.prevent="submit">
<div class="mb-7 flex items-center gap-3">
<img :src="vntIcon" alt="" class="h-10 w-10 shrink-0" />
<div>
<h1 class="text-lg font-bold text-slate-900 dark:text-white">访问 VNT 控制台</h1>
<p class="mt-0.5 text-xs text-slate-400">请输入桌面端 Web 访问设置中的令牌</p>
</div>
</div>
<label class="mb-2 block text-sm font-medium text-slate-700 dark:text-slate-200" for="access-token">访问令牌</label>
<input id="access-token" v-model="token" class="input font-mono" type="password" autocomplete="current-password" autofocus placeholder="粘贴访问令牌" />
<button class="btn-primary mt-5 w-full" type="submit" :disabled="!token.trim()">进入控制台</button>
<p class="mt-5 text-center text-xs leading-5 text-slate-400">令牌只保存在当前浏览器中可随时在桌面端重新生成</p>
</form>
</main>
</template>
+60
View File
@@ -0,0 +1,60 @@
<script setup>
import { useRoute } from "vue-router";
import { useAppStore } from "../stores/app";
import { visibleNavItems } from "../navigation";
import vntIcon from "../assets/vnt-icon.png";
defineEmits(["navigate"]);
const route = useRoute();
const app = useAppStore();
const items = visibleNavItems();
</script>
<template>
<div class="flex h-full min-h-0 flex-col bg-white dark:bg-slate-900">
<div class="flex h-16 shrink-0 items-center gap-3 border-b border-slate-200 px-5 dark:border-slate-800">
<img :src="vntIcon" alt="" class="h-8 w-8 shrink-0" />
<div>
<div class="text-sm font-bold tracking-wide text-slate-900 dark:text-white">VNT</div>
<div class="text-[9px] font-semibold tracking-[0.18em] text-slate-400">CONTROL CENTER</div>
</div>
</div>
<div class="mx-3 mt-4 flex items-center gap-3 rounded-xl border border-slate-200 bg-slate-50 px-3 py-3 dark:border-slate-700 dark:bg-slate-800/60">
<span
class="h-2.5 w-2.5 shrink-0 rounded-full"
:class="app.runningCount > 0 ? 'bg-green-500' : app.startingCount > 0 ? 'animate-pulse bg-amber-400' : 'bg-slate-300 dark:bg-slate-600'"
></span>
<div class="min-w-0">
<div class="text-[9px] font-semibold tracking-wider text-slate-400">虚拟网络</div>
<div class="mt-0.5 truncate text-xs font-medium text-slate-700 dark:text-slate-200">{{ app.headerStatusText }}</div>
</div>
</div>
<nav class="mt-4 flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto px-3" aria-label="主导航">
<router-link
v-for="item in items"
:key="item.to"
:to="item.to"
class="flex min-h-10 items-center gap-3 rounded-lg px-3 text-sm font-medium transition-colors"
:class="route.path === item.to
? 'bg-indigo-50 text-indigo-700 dark:bg-indigo-500/10 dark:text-indigo-300'
: 'text-slate-500 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-white'"
@click="$emit('navigate')"
>
<svg class="h-[18px] w-[18px] shrink-0 fill-none stroke-current" viewBox="0 0 24 24">
<path :d="item.icon" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.7" />
</svg>
<span>{{ item.label }}</span>
</router-link>
</nav>
<div class="mx-3 mt-3 shrink-0 border-t border-slate-200 px-1 py-4 dark:border-slate-800">
<div class="flex items-center gap-2 text-xs text-slate-400">
<span class="h-1.5 w-1.5 rounded-full" :class="app.version ? 'bg-green-500' : 'bg-amber-400'"></span>
<span>{{ app.version ? "本地服务正常" : "正在连接服务…" }}</span>
<span class="ml-auto font-mono text-[10px]">v{{ app.version || "2.0" }}</span>
</div>
</div>
</div>
</template>
+7
View File
@@ -2,6 +2,13 @@ import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
import router from "./router";
import vntIcon from "./assets/vnt-icon.png";
import "./style.css";
const favicon = document.querySelector('link[rel~="icon"]') || document.createElement("link");
favicon.rel = "icon";
favicon.type = "image/png";
favicon.href = vntIcon;
document.head.appendChild(favicon);
createApp(App).use(createPinia()).use(router).mount("#app");
+42
View File
@@ -0,0 +1,42 @@
export const navItems = [
{
to: "/",
label: "网络总览",
shortLabel: "总览",
icon: "M4 4h6v6H4V4Zm10 0h6v6h-6V4ZM4 14h6v6H4v-6Zm10 0h6v6h-6v-6Z",
},
{
to: "/instances",
label: "运行实例",
shortLabel: "实例",
icon: "M4 18V8m5 10V4m6 14v-7m5 7V6",
},
{
to: "/peers",
label: "在线设备",
shortLabel: "设备",
icon: "M15 19a6 6 0 0 0-12 0m18 0a5 5 0 0 0-5-5m-7-3a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm8 0a3 3 0 1 0 0-6",
},
{
to: "/routes",
label: "路由表",
shortLabel: "路由",
icon: "M6 8a2 2 0 1 0 0-4 2 2 0 0 0 0 4Zm12 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4ZM8 6h6a4 4 0 0 1 4 4v2m-3-3 3 3 3-3M16 18h-6a4 4 0 0 1-4-4v-2",
},
{
to: "/config",
label: "组网配置",
shortLabel: "配置",
icon: "M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7Zm7.4-.5a1.7 1.7 0 0 0 .3 1.9l.1.1-2.8 2.8-.1-.1a1.7 1.7 0 0 0-1.9-.3A1.7 1.7 0 0 0 14 21v.2h-4V21a1.7 1.7 0 0 0-1-1.6 1.7 1.7 0 0 0-1.9.3l-.1.1L4.2 17l.1-.1a1.7 1.7 0 0 0 .3-1.9A1.7 1.7 0 0 0 3 14h-.2v-4H3a1.7 1.7 0 0 0 1.6-1 1.7 1.7 0 0 0-.3-1.9L4.2 7 7 4.2l.1.1A1.7 1.7 0 0 0 9 4.6 1.7 1.7 0 0 0 10 3v-.2h4V3a1.7 1.7 0 0 0 1 1.6 1.7 1.7 0 0 0 1.9-.3l.1-.1L19.8 7l-.1.1a1.7 1.7 0 0 0-.3 1.9 1.7 1.7 0 0 0 1.6 1h.2v4H21a1.7 1.7 0 0 0-1.6 1Z",
},
{
to: "/web-access",
label: "Web 访问",
shortLabel: "Web",
desktopOnly: true,
icon: "M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Zm0 0c2.2-2.5 3.3-5.5 3.3-9S14.2 5.5 12 3m0 18c-2.2-2.5-3.3-5.5-3.3-9S9.8 5.5 12 3M3.5 9h17m-17 6h17",
},
];
export const visibleNavItems = () =>
navItems.filter((item) => !item.desktopOnly || globalThis.__VNT_DESKTOP__);
+2
View File
@@ -4,6 +4,7 @@ import InstancesView from "../views/InstancesView.vue";
import ConfigView from "../views/ConfigView.vue";
import PeersView from "../views/PeersView.vue";
import RoutesView from "../views/RoutesView.vue";
import WebAccessView from "../views/WebAccessView.vue";
const routes = [
{ path: "/", component: DashboardView },
@@ -13,6 +14,7 @@ const routes = [
{ path: "/config", component: ConfigView },
{ path: "/peers", component: PeersView },
{ path: "/routes", component: RoutesView },
{ path: "/web-access", component: WebAccessView },
];
export default createRouter({
+2
View File
@@ -12,6 +12,7 @@ import {
} from "../api";
import { useUiStore } from "./ui";
import { useStartLogStore } from "./startLog";
import { getAccessToken, isDesktop } from "../auth";
export const useAppStore = defineStore("app", () => {
const ui = useUiStore();
@@ -217,6 +218,7 @@ export const useAppStore = defineStore("app", () => {
startLog.bindApp({ fetchInstances, instanceList, configList });
const init = async () => {
if (!isDesktop && !getAccessToken()) return;
document.addEventListener("visibilitychange", visibilityHandler);
fetchVersion();
await fetchInstances();
+38 -3
View File
@@ -1,4 +1,5 @@
@import "tailwindcss";
@source "./**/*.{vue,js}";
@custom-variant dark (&:where(.dark, .dark *));
@@ -12,6 +13,13 @@ body {
@apply bg-slate-50 text-slate-700 antialiased dark:bg-slate-950 dark:text-slate-200;
}
html,
body,
#app {
height: 100%;
overflow: hidden;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
@@ -123,6 +131,27 @@ body {
transform: translateY(-6px);
}
/* 移动端侧栏抽屉 */
.drawer-enter-active,
.drawer-leave-active {
transition: opacity 0.2s ease;
}
.drawer-enter-active .drawer-panel,
.drawer-leave-active .drawer-panel {
transition: transform 0.2s ease;
}
.drawer-enter-from,
.drawer-leave-to {
opacity: 0;
}
.drawer-enter-from .drawer-panel,
.drawer-leave-to .drawer-panel {
transform: translateX(-100%);
}
@utility btn {
@apply inline-flex items-center justify-center gap-1.5 px-4 py-2 rounded-lg text-sm font-medium
transition-all duration-150 active:scale-95 cursor-pointer
@@ -232,9 +261,15 @@ body {
@apply text-2xl font-bold text-slate-900 dark:text-white;
}
.page-subtitle {
@apply mt-1 text-sm text-slate-500 dark:text-slate-400;
}
.page-subtitle {
@apply mt-1 text-sm text-slate-500 dark:text-slate-400;
}
/* 页面名称由统一外壳标题栏展示,视图只保留自身操作按钮。 */
.page-title,
.page-subtitle {
display: none;
}
/* 弱文本 */
.muted {
+20 -1
View File
@@ -111,7 +111,7 @@ onMounted(() => app.fetchConfigList());
</p>
</div>
</div>
<div class="mt-4 flex justify-end opacity-0 transition-opacity group-hover:opacity-100">
<div class="config-card-actions mt-4 flex justify-end transition-opacity">
<button
class="mr-4 text-sm text-indigo-600 hover:text-indigo-500 dark:text-indigo-400"
@click.stop="openEditor(cfg.file_name)"
@@ -133,3 +133,22 @@ onMounted(() => app.fetchConfigList());
/>
</div>
</template>
<style scoped>
/* 触屏和窄屏设备没有可靠的 hover,操作按钮必须直接可见。 */
.config-card-actions {
opacity: 1;
}
/* 只有宽屏且确实支持精细悬停的设备才使用移入显示。 */
@media (min-width: 640px) and (hover: hover) and (pointer: fine) {
.config-card-actions {
opacity: 0;
}
.group:hover .config-card-actions,
.group:focus-within .config-card-actions {
opacity: 1;
}
}
</style>
+211
View File
@@ -0,0 +1,211 @@
<script setup>
import { onMounted, reactive, ref } from "vue";
const bridge = globalThis.__VNT_WEB_ACCESS__;
const draft = reactive({ enabled: false, port: 19099, global: false, token: "" });
const status = ref(null);
const loading = ref(true);
const saving = ref(false);
const notice = ref("");
const error = ref("");
const sync = (value) => {
status.value = value;
Object.assign(draft, {
enabled: value.enabled,
port: value.port,
global: value.global,
token: value.token,
});
};
const load = async () => {
loading.value = true;
error.value = "";
try {
if (!bridge) throw new Error("Web 访问设置仅在桌面客户端中提供");
sync(await bridge.status());
} catch (err) {
error.value = err.message || String(err);
} finally {
loading.value = false;
}
};
const update = async (changes, successMessage) => {
saving.value = true;
error.value = "";
notice.value = "";
try {
sync(await bridge.update({
...draft,
...changes,
port: Number(changes.port ?? draft.port),
}));
notice.value = successMessage;
} catch (err) {
const message = err.message || String(err);
try {
sync(await bridge.status());
} catch {
//
}
error.value = message;
} finally {
saving.value = false;
}
};
const toggleService = async () => {
const enabled = !draft.enabled;
await update(
{ enabled },
enabled ? "Web 服务已启动" : "Web 服务已关闭",
);
};
const regenerate = async () => {
const token = await bridge.generateToken();
await update(
{ token },
draft.enabled ? "新令牌已生效,Web 服务已重新加载" : "新令牌已生成",
);
};
const saveNetworkSettings = async () => {
if (draft.enabled) return;
await update({}, "监听设置已自动保存");
};
const copyToken = async () => {
await navigator.clipboard.writeText(draft.token);
notice.value = "访问令牌已复制";
};
const copyUrl = async () => {
await navigator.clipboard.writeText(status.value.url);
notice.value = "访问地址已复制";
};
const openBrowser = async () => {
await bridge.openUrl(status.value.url);
};
onMounted(load);
</script>
<template>
<div class="mx-auto max-w-4xl space-y-5">
<div class="page-title">
<div>
<h2>Web 访问</h2>
<p>从浏览器访问当前 VNT 进程API 请求由持久访问令牌保护</p>
</div>
</div>
<div v-if="loading" class="card text-sm text-slate-400">正在读取 Web 服务状态</div>
<div v-else-if="!bridge" class="card border-red-200 text-sm text-red-600 dark:border-red-900 dark:text-red-300">{{ error }}</div>
<template v-else>
<section class="card space-y-6">
<div class="flex items-start justify-between gap-5">
<div>
<h3 class="text-sm font-semibold text-slate-900 dark:text-white">启用 Web 服务</h3>
<p class="mt-1 text-xs leading-5 text-slate-400">服务内置于桌面客户端不会启动单独的 vnt2_web 进程</p>
</div>
<button
type="button"
role="switch"
aria-label="启用 Web 服务"
:aria-checked="draft.enabled"
:disabled="saving"
class="web-switch transition-colors disabled:opacity-50"
:class="draft.enabled ? 'bg-indigo-600 dark:bg-indigo-500' : 'bg-slate-300 dark:bg-slate-600'"
@click="toggleService"
>
<span class="web-switch-knob bg-white shadow-sm" :class="{ 'web-switch-knob-on': draft.enabled }"></span>
</button>
</div>
<div class="grid gap-5 sm:grid-cols-2">
<label class="block">
<span class="mb-2 block text-sm font-medium text-slate-700 dark:text-slate-200">监听端口</span>
<input v-model.number="draft.port" class="input font-mono" type="number" min="1" max="65535" :disabled="saving || draft.enabled" @change="saveNetworkSettings" />
</label>
<label class="block">
<span class="mb-2 block text-sm font-medium text-slate-700 dark:text-slate-200">监听范围</span>
<select v-model="draft.global" class="input" :disabled="saving || draft.enabled" @change="saveNetworkSettings">
<option :value="false">仅本机推荐</option>
<option :value="true">局域网内所有设备</option>
</select>
</label>
</div>
<p class="-mt-3 text-xs text-slate-400">端口和监听范围会自动保存需要修改时请先关闭 Web 服务</p>
<div>
<div class="mb-2 flex items-center justify-between gap-3">
<span class="text-sm font-medium text-slate-700 dark:text-slate-200">访问令牌</span>
<button class="text-xs font-medium text-indigo-600 hover:text-indigo-500 disabled:opacity-50 dark:text-indigo-400" type="button" :disabled="saving" @click="regenerate">更换令牌</button>
</div>
<div class="flex items-center gap-2">
<code class="min-w-0 flex-1 truncate rounded-lg border border-slate-200 bg-slate-50 px-3 py-2.5 text-xs text-slate-600 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-300">{{ draft.token }}</code>
<button class="btn-ghost shrink-0" type="button" :disabled="saving" @click="copyToken">复制令牌</button>
</div>
<p class="mt-2 text-xs text-slate-400">更换令牌后已登录的浏览器需要使用新令牌重新鉴权</p>
</div>
<div v-if="notice || error" class="border-t border-slate-200 pt-5 dark:border-slate-800">
<span v-if="notice" class="text-xs text-green-600 dark:text-green-400">{{ notice }}</span>
<span v-if="error" class="text-xs text-red-600 dark:text-red-400">{{ error }}</span>
</div>
</section>
<section class="card">
<div class="flex items-start gap-3">
<span class="mt-1 h-2.5 w-2.5 shrink-0 rounded-full" :class="status?.running ? 'bg-green-500' : 'bg-slate-300 dark:bg-slate-600'"></span>
<div class="min-w-0 flex-1">
<div class="text-sm font-semibold text-slate-900 dark:text-white">{{ status?.running ? "运行中" : "未运行" }}</div>
<div class="mt-1 text-xs text-slate-400">监听地址{{ status?.listenAddress }}</div>
<div v-if="status?.running" class="mt-4 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2.5 font-mono text-xs text-slate-600 dark:border-slate-700 dark:bg-slate-950 dark:text-slate-300">
<span class="block truncate">{{ status.url }}</span>
</div>
<div v-if="status?.running" class="mt-3 flex flex-wrap gap-2">
<button class="btn-primary btn-sm" type="button" @click="openBrowser">打开浏览器</button>
<button class="btn-ghost btn-sm" type="button" @click="copyUrl">复制访问地址</button>
</div>
</div>
</div>
</section>
</template>
</div>
</template>
<style scoped>
.web-switch {
position: relative;
display: inline-flex;
flex: 0 0 44px;
align-items: center;
width: 44px;
min-width: 44px;
height: 24px;
min-height: 24px;
padding: 2px;
border: 0;
border-radius: 9999px;
cursor: pointer;
}
.web-switch-knob {
display: block;
width: 20px;
min-width: 20px;
height: 20px;
border-radius: 9999px;
transform: translateX(0);
transition: transform 160ms ease;
}
.web-switch-knob-on {
transform: translateX(20px);
}
</style>