ChatGPT Codex 5.5 xhigh refactored even more
This commit is contained in:
Generated
+681
-685
@@ -77,9 +77,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.101"
|
version = "1.0.102"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
|
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
@@ -133,9 +133,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-lc-rs"
|
name = "aws-lc-rs"
|
||||||
version = "1.15.4"
|
version = "1.16.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256"
|
checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-sys",
|
"aws-lc-sys",
|
||||||
"untrusted 0.7.1",
|
"untrusted 0.7.1",
|
||||||
@@ -144,9 +144,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-lc-sys"
|
name = "aws-lc-sys"
|
||||||
version = "0.37.1"
|
version = "0.40.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549"
|
checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cmake",
|
"cmake",
|
||||||
@@ -166,6 +166,21 @@ version = "0.22.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
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]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@@ -174,9 +189,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.11.0"
|
version = "2.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
|
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
@@ -213,25 +228,26 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "borsh"
|
name = "borsh"
|
||||||
version = "1.6.0"
|
version = "1.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f"
|
checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh-derive",
|
"borsh-derive",
|
||||||
|
"bytes",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "borsh-derive"
|
name = "borsh-derive"
|
||||||
version = "1.6.0"
|
version = "1.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c"
|
checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro-crate 3.4.0",
|
"proc-macro-crate 3.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -257,9 +273,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.19.1"
|
version = "3.20.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byte-unit"
|
name = "byte-unit"
|
||||||
@@ -322,7 +338,7 @@ version = "0.18.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
|
checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"cairo-sys-rs",
|
"cairo-sys-rs",
|
||||||
"glib",
|
"glib",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -385,9 +401,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.56"
|
version = "1.2.61"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2"
|
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"jobserver",
|
"jobserver",
|
||||||
@@ -435,10 +451,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chacha20"
|
||||||
version = "0.4.43"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures 0.3.0",
|
||||||
|
"rand_core 0.10.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -448,9 +475,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cmake"
|
name = "cmake"
|
||||||
version = "0.1.57"
|
version = "0.1.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
|
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
@@ -474,12 +501,6 @@ dependencies = [
|
|||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "convert_case"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cookie"
|
name = "cookie"
|
||||||
version = "0.18.1"
|
version = "0.18.1"
|
||||||
@@ -508,11 +529,11 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-graphics"
|
name = "core-graphics"
|
||||||
version = "0.24.0"
|
version = "0.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
|
checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics-types",
|
"core-graphics-types",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
@@ -525,7 +546,7 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
|
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -539,6 +560,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc"
|
name = "crc"
|
||||||
version = "3.4.0"
|
version = "3.4.0"
|
||||||
@@ -550,9 +580,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc-catalog"
|
name = "crc-catalog"
|
||||||
version = "2.4.0"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
|
checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
@@ -599,19 +629,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cssparser"
|
name = "cssparser"
|
||||||
version = "0.29.6"
|
version = "0.36.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa"
|
checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cssparser-macros",
|
"cssparser-macros",
|
||||||
"dtoa-short",
|
"dtoa-short",
|
||||||
"itoa",
|
"itoa",
|
||||||
"matches",
|
"phf 0.13.1",
|
||||||
"phf 0.10.1",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -621,19 +647,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctor"
|
name = "ctor"
|
||||||
version = "0.2.9"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
|
checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"ctor-proc-macro",
|
||||||
"syn 2.0.116",
|
"dtor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ctor-proc-macro"
|
||||||
|
version = "0.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cuckoofilter"
|
name = "cuckoofilter"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -647,9 +679,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.21.3"
|
version = "0.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0"
|
checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"darling_macro",
|
"darling_macro",
|
||||||
@@ -657,34 +689,44 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_core"
|
name = "darling_core"
|
||||||
version = "0.21.3"
|
version = "0.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4"
|
checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fnv",
|
|
||||||
"ident_case",
|
"ident_case",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling_macro"
|
name = "darling_macro"
|
||||||
version = "0.21.3"
|
version = "0.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
|
checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbus"
|
||||||
|
version = "0.9.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b942602992bb7acfd1f51c49811c58a610ef9181b6e66f3e519d79b540a3bf73"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"libdbus-sys",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.5.6"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4"
|
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"powerfmt",
|
"powerfmt",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
@@ -692,15 +734,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "0.99.20"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f"
|
checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134"
|
||||||
|
dependencies = [
|
||||||
|
"derive_more-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more-impl"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"convert_case",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -734,19 +784,13 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dispatch"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dispatch2"
|
name = "dispatch2"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
|
checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"block2",
|
"block2",
|
||||||
"libc",
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
@@ -760,7 +804,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -783,7 +827,22 @@ checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
@@ -816,6 +875,21 @@ dependencies = [
|
|||||||
"dtoa",
|
"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]]
|
[[package]]
|
||||||
name = "dunce"
|
name = "dunce"
|
||||||
version = "1.0.5"
|
version = "1.0.5"
|
||||||
@@ -839,14 +913,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embed-resource"
|
name = "embed-resource"
|
||||||
version = "3.0.6"
|
version = "3.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e"
|
checksum = "c31a88c8d26de40ed18fe748c547845aa39de1db3afd958f8cb91579f3644bcb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"memchr",
|
"memchr",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"toml 0.9.12+spec-1.1.0",
|
"toml 1.1.2+spec-1.1.0",
|
||||||
"vswhom",
|
"vswhom",
|
||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
@@ -884,9 +958,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "erased-serde"
|
name = "erased-serde"
|
||||||
version = "0.4.9"
|
version = "0.4.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3"
|
checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
@@ -926,9 +1000,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.3.0"
|
version = "2.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
@@ -1021,7 +1095,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1051,16 +1125,6 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futf"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
|
|
||||||
dependencies = [
|
|
||||||
"mac",
|
|
||||||
"new_debug_unreachable",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures"
|
name = "futures"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
@@ -1128,7 +1192,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1160,15 +1224,6 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fxhash"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
|
|
||||||
dependencies = [
|
|
||||||
"byteorder",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gdk"
|
name = "gdk"
|
||||||
version = "0.18.2"
|
version = "0.18.2"
|
||||||
@@ -1318,19 +1373,20 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi",
|
"r-efi 5.3.0",
|
||||||
"wasip2",
|
"wasip2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
|
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi",
|
"r-efi 6.0.0",
|
||||||
|
"rand_core 0.10.1",
|
||||||
"wasip2",
|
"wasip2",
|
||||||
"wasip3",
|
"wasip3",
|
||||||
]
|
]
|
||||||
@@ -1373,7 +1429,7 @@ version = "0.18.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
|
checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-executor",
|
"futures-executor",
|
||||||
@@ -1401,7 +1457,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1480,7 +1536,7 @@ dependencies = [
|
|||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1511,9 +1567,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.16.1"
|
version = "0.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
"equivalent",
|
"equivalent",
|
||||||
@@ -1555,14 +1611,12 @@ checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "html5ever"
|
name = "html5ever"
|
||||||
version = "0.29.1"
|
version = "0.38.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c"
|
checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"mac",
|
|
||||||
"markup5ever",
|
"markup5ever",
|
||||||
"match_token",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1606,9 +1660,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.8.1"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11"
|
checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1619,7 +1673,6 @@ dependencies = [
|
|||||||
"httparse",
|
"httparse",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tokio",
|
"tokio",
|
||||||
"want",
|
"want",
|
||||||
@@ -1679,17 +1732,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371"
|
checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"png",
|
"png 0.17.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
|
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"potential_utf",
|
"potential_utf",
|
||||||
|
"utf8_iter",
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
@@ -1697,9 +1751,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_locale_core"
|
name = "icu_locale_core"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
|
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"litemap",
|
"litemap",
|
||||||
@@ -1710,9 +1764,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer"
|
name = "icu_normalizer"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
|
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_normalizer_data",
|
"icu_normalizer_data",
|
||||||
@@ -1724,15 +1778,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer_data"
|
name = "icu_normalizer_data"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
|
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties"
|
name = "icu_properties"
|
||||||
version = "2.1.2"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
|
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
@@ -1744,15 +1798,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties_data"
|
name = "icu_properties_data"
|
||||||
version = "2.1.2"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
|
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_provider"
|
name = "icu_provider"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
|
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
@@ -1788,9 +1842,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna_adapter"
|
name = "idna_adapter"
|
||||||
version = "1.2.1"
|
version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
|
checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_normalizer",
|
"icu_normalizer",
|
||||||
"icu_properties",
|
"icu_properties",
|
||||||
@@ -1825,12 +1879,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.13.0"
|
version = "2.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
|
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.17.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
@@ -1855,15 +1909,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.11.0"
|
version = "2.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iri-string"
|
name = "iri-string"
|
||||||
version = "0.7.10"
|
version = "0.7.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a"
|
checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1890,9 +1944,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.17"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "javascriptcore-rs"
|
name = "javascriptcore-rs"
|
||||||
@@ -1926,7 +1980,7 @@ dependencies = [
|
|||||||
"cesu8",
|
"cesu8",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"combine",
|
"combine",
|
||||||
"jni-sys",
|
"jni-sys 0.3.1",
|
||||||
"log",
|
"log",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
@@ -1935,9 +1989,31 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni-sys"
|
name = "jni-sys"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258"
|
||||||
|
dependencies = [
|
||||||
|
"jni-sys 0.4.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni-sys"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
|
||||||
|
dependencies = [
|
||||||
|
"jni-sys-macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni-sys-macros"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
@@ -1951,10 +2027,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.85"
|
version = "0.3.97"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
|
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"futures-util",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@@ -1987,23 +2065,11 @@ version = "0.7.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
|
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"serde",
|
"serde",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "kuchikiki"
|
|
||||||
version = "0.8.8-speedreader"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2"
|
|
||||||
dependencies = [
|
|
||||||
"cssparser",
|
|
||||||
"html5ever",
|
|
||||||
"indexmap 2.13.0",
|
|
||||||
"selectors",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lanspread-compat"
|
name = "lanspread-compat"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -2019,9 +2085,7 @@ dependencies = [
|
|||||||
name = "lanspread-db"
|
name = "lanspread-db"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
|
||||||
"eyre",
|
"eyre",
|
||||||
"semver",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -2034,8 +2098,6 @@ dependencies = [
|
|||||||
"eyre",
|
"eyre",
|
||||||
"log",
|
"log",
|
||||||
"mdns-sd",
|
"mdns-sd",
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2047,7 +2109,6 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"gethostname",
|
"gethostname",
|
||||||
"if-addrs",
|
"if-addrs",
|
||||||
"lanspread-compat",
|
|
||||||
"lanspread-db",
|
"lanspread-db",
|
||||||
"lanspread-mdns",
|
"lanspread-mdns",
|
||||||
"lanspread-proto",
|
"lanspread-proto",
|
||||||
@@ -2058,7 +2119,6 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
|
||||||
"uuid",
|
"uuid",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
@@ -2082,12 +2142,9 @@ dependencies = [
|
|||||||
"eyre",
|
"eyre",
|
||||||
"lanspread-compat",
|
"lanspread-compat",
|
||||||
"lanspread-db",
|
"lanspread-db",
|
||||||
"lanspread-mdns",
|
|
||||||
"lanspread-peer",
|
"lanspread-peer",
|
||||||
"log",
|
"log",
|
||||||
"mimalloc",
|
"mimalloc",
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
"tauri-plugin-dialog",
|
"tauri-plugin-dialog",
|
||||||
@@ -2141,9 +2198,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.182"
|
version = "0.2.186"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
|
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libdbus-sys"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043"
|
||||||
|
dependencies = [
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
@@ -2163,21 +2229,19 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libmimalloc-sys"
|
name = "libmimalloc-sys"
|
||||||
version = "0.1.44"
|
version = "0.1.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "667f4fec20f29dfc6bc7357c582d91796c169ad7e2fce709468aefeb2c099870"
|
checksum = "2d1eacfa31c33ec25e873c136ba5669f00f9866d0688bea7be4d3f7e43067df6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.12"
|
version = "0.1.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2194,15 +2258,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.11.0"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
|
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
|
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -2222,48 +2286,22 @@ dependencies = [
|
|||||||
"value-bag",
|
"value-bag",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mac"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever"
|
name = "markup5ever"
|
||||||
version = "0.14.1"
|
version = "0.38.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18"
|
checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"phf 0.11.3",
|
|
||||||
"phf_codegen 0.11.3",
|
|
||||||
"string_cache",
|
|
||||||
"string_cache_codegen",
|
|
||||||
"tendril",
|
"tendril",
|
||||||
|
"web_atoms",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "match_token"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 2.0.116",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "matches"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mdns-sd"
|
name = "mdns-sd"
|
||||||
version = "0.18.0"
|
version = "0.18.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c23fd301a08742925d79fd29bba538c9cb0408d67907905f8f9d4e5cd8bc816"
|
checksum = "d797ab3274a16f4940f9650a29838e940223aeff31773df5c2827ad82150182f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"flume",
|
"flume",
|
||||||
@@ -2291,9 +2329,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mimalloc"
|
name = "mimalloc"
|
||||||
version = "0.1.48"
|
version = "0.1.50"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1ee66a4b64c74f4ef288bcbb9192ad9c3feaad75193129ac8509af543894fd8"
|
checksum = "b3627c4272df786b9260cabaa46aec1d59c93ede723d4c3ef646c503816b0640"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libmimalloc-sys",
|
"libmimalloc-sys",
|
||||||
]
|
]
|
||||||
@@ -2316,9 +2354,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.1.1"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@@ -2328,9 +2366,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "muda"
|
name = "muda"
|
||||||
version = "0.17.1"
|
version = "0.19.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a"
|
checksum = "0ae8844f63b5b118e334e205585b8c5c17b984121dbdb179d44aeb087ffad3cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"dpi",
|
"dpi",
|
||||||
@@ -2341,10 +2379,10 @@ dependencies = [
|
|||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"png",
|
"png 0.18.1",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2353,8 +2391,8 @@ version = "0.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
|
checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"jni-sys",
|
"jni-sys 0.3.1",
|
||||||
"log",
|
"log",
|
||||||
"ndk-sys",
|
"ndk-sys",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
@@ -2362,19 +2400,13 @@ dependencies = [
|
|||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ndk-context"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ndk-sys"
|
name = "ndk-sys"
|
||||||
version = "0.6.0+11769913"
|
version = "0.6.0+11769913"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
|
checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jni-sys",
|
"jni-sys 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2383,17 +2415,11 @@ version = "1.0.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nodrop"
|
|
||||||
version = "0.1.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-conv"
|
name = "num-conv"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
|
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
@@ -2426,9 +2452,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum"
|
name = "num_enum"
|
||||||
version = "0.7.5"
|
version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
|
checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num_enum_derive",
|
"num_enum_derive",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
@@ -2436,14 +2462,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_enum_derive"
|
name = "num_enum_derive"
|
||||||
version = "0.7.5"
|
version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
|
checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 3.4.0",
|
"proc-macro-crate 3.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2457,9 +2483,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2"
|
name = "objc2"
|
||||||
version = "0.6.3"
|
version = "0.6.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05"
|
checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2-encode",
|
"objc2-encode",
|
||||||
"objc2-exception-helper",
|
"objc2-exception-helper",
|
||||||
@@ -2471,19 +2497,11 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
|
checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"block2",
|
"block2",
|
||||||
"libc",
|
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-cloud-kit",
|
|
||||||
"objc2-core-data",
|
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-core-graphics",
|
|
||||||
"objc2-core-image",
|
|
||||||
"objc2-core-text",
|
|
||||||
"objc2-core-video",
|
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"objc2-quartz-core",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2492,7 +2510,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
|
checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
@@ -2503,7 +2521,6 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa"
|
checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
@@ -2514,7 +2531,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"dispatch2",
|
"dispatch2",
|
||||||
"objc2",
|
"objc2",
|
||||||
]
|
]
|
||||||
@@ -2525,7 +2542,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
|
checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"dispatch2",
|
"dispatch2",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
@@ -2542,31 +2559,28 @@ dependencies = [
|
|||||||
"objc2-foundation",
|
"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]]
|
[[package]]
|
||||||
name = "objc2-core-text"
|
name = "objc2-core-text"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
|
checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "objc2-core-video"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.11.0",
|
|
||||||
"objc2",
|
|
||||||
"objc2-core-foundation",
|
|
||||||
"objc2-core-graphics",
|
|
||||||
"objc2-io-surface",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-encode"
|
name = "objc2-encode"
|
||||||
version = "4.1.0"
|
version = "4.1.0"
|
||||||
@@ -2588,7 +2602,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"block2",
|
"block2",
|
||||||
"libc",
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
@@ -2601,17 +2615,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
|
checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"objc2",
|
|
||||||
"objc2-core-foundation",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "objc2-javascript-core"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586"
|
|
||||||
dependencies = [
|
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
@@ -2622,32 +2626,40 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
|
checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "objc2-security"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.11.0",
|
|
||||||
"objc2",
|
|
||||||
"objc2-core-foundation",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-ui-kit"
|
name = "objc2-ui-kit"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
|
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
|
"block2",
|
||||||
"objc2",
|
"objc2",
|
||||||
|
"objc2-cloud-kit",
|
||||||
|
"objc2-core-data",
|
||||||
"objc2-core-foundation",
|
"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",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2657,27 +2669,25 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f"
|
checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"block2",
|
"block2",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"objc2-javascript-core",
|
|
||||||
"objc2-security",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.21.3"
|
version = "1.21.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "open"
|
name = "open"
|
||||||
version = "5.3.3"
|
version = "5.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc"
|
checksum = "9f3bab717c29a857abf75fcef718d441ec7cb2725f937343c734740a985d37fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"is-wsl",
|
"is-wsl",
|
||||||
@@ -2767,26 +2777,6 @@ version = "2.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12"
|
|
||||||
dependencies = [
|
|
||||||
"phf_shared 0.8.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf"
|
|
||||||
version = "0.10.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
|
|
||||||
dependencies = [
|
|
||||||
"phf_macros 0.10.0",
|
|
||||||
"phf_shared 0.10.0",
|
|
||||||
"proc-macro-hack",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf"
|
name = "phf"
|
||||||
version = "0.11.3"
|
version = "0.11.3"
|
||||||
@@ -2798,43 +2788,24 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_codegen"
|
name = "phf"
|
||||||
version = "0.8.0"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815"
|
checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator 0.8.0",
|
"phf_macros 0.13.1",
|
||||||
"phf_shared 0.8.0",
|
"phf_shared 0.13.1",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_codegen"
|
name = "phf_codegen"
|
||||||
version = "0.11.3"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a"
|
checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator 0.11.3",
|
"phf_generator 0.13.1",
|
||||||
"phf_shared 0.11.3",
|
"phf_shared 0.13.1",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_generator"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526"
|
|
||||||
dependencies = [
|
|
||||||
"phf_shared 0.8.0",
|
|
||||||
"rand 0.7.3",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "phf_generator"
|
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6"
|
|
||||||
dependencies = [
|
|
||||||
"phf_shared 0.10.0",
|
|
||||||
"rand 0.8.5",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2844,21 +2815,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_shared 0.11.3",
|
"phf_shared 0.11.3",
|
||||||
"rand 0.8.5",
|
"rand 0.8.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_macros"
|
name = "phf_generator"
|
||||||
version = "0.10.0"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0"
|
checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator 0.10.0",
|
"fastrand",
|
||||||
"phf_shared 0.10.0",
|
"phf_shared 0.13.1",
|
||||||
"proc-macro-hack",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2871,25 +2838,20 @@ dependencies = [
|
|||||||
"phf_shared 0.11.3",
|
"phf_shared 0.11.3",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "phf_shared"
|
name = "phf_macros"
|
||||||
version = "0.8.0"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7"
|
checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"siphasher 0.3.11",
|
"phf_generator 0.13.1",
|
||||||
]
|
"phf_shared 0.13.1",
|
||||||
|
"proc-macro2",
|
||||||
[[package]]
|
"quote",
|
||||||
name = "phf_shared"
|
"syn 2.0.117",
|
||||||
version = "0.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
|
|
||||||
dependencies = [
|
|
||||||
"siphasher 0.3.11",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2898,35 +2860,38 @@ version = "0.11.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"siphasher 1.0.2",
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.16"
|
version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-utils"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.32"
|
version = "0.3.33"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plist"
|
name = "plist"
|
||||||
version = "1.8.0"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07"
|
checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
"serde",
|
"serde",
|
||||||
"time",
|
"time",
|
||||||
@@ -2946,10 +2911,23 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "potential_utf"
|
name = "png"
|
||||||
version = "0.1.4"
|
version = "0.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
|
checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"crc32fast",
|
||||||
|
"fdeflate",
|
||||||
|
"flate2",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "potential_utf"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
@@ -2982,7 +2960,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3007,11 +2985,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "3.4.0"
|
version = "3.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
|
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"toml_edit 0.23.10+spec-1.0.0",
|
"toml_edit 0.25.11+spec-1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3038,12 +3016,6 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-hack"
|
|
||||||
version = "0.5.20+deprecated"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.106"
|
version = "1.0.106"
|
||||||
@@ -3075,18 +3047,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.38.4"
|
version = "0.39.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
|
checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.44"
|
version = "1.0.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -3097,6 +3069,12 @@ version = "5.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "radium"
|
name = "radium"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@@ -3114,14 +3092,13 @@ dependencies = [
|
|||||||
"rand_chacha 0.2.2",
|
"rand_chacha 0.2.2",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
"rand_hc",
|
"rand_hc",
|
||||||
"rand_pcg",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha 0.3.1",
|
"rand_chacha 0.3.1",
|
||||||
@@ -3130,12 +3107,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.9.2"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_chacha 0.9.0",
|
"chacha20",
|
||||||
"rand_core 0.9.5",
|
"getrandom 0.4.2",
|
||||||
|
"rand_core 0.10.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3158,16 +3136,6 @@ dependencies = [
|
|||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core 0.9.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -3188,12 +3156,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.9.5"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
|
||||||
dependencies = [
|
|
||||||
"getrandom 0.3.4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_hc"
|
name = "rand_hc"
|
||||||
@@ -3204,15 +3169,6 @@ dependencies = [
|
|||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_pcg"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core 0.5.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-window-handle"
|
name = "raw-window-handle"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
@@ -3225,7 +3181,7 @@ version = "0.5.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3256,7 +3212,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3284,9 +3240,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.9"
|
version = "0.8.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c"
|
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rend"
|
name = "rend"
|
||||||
@@ -3299,9 +3255,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.13.2"
|
version = "0.13.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801"
|
checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -3400,20 +3356,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust_decimal"
|
name = "rust_decimal"
|
||||||
version = "1.40.0"
|
version = "1.41.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0"
|
checksum = "2ce901f9a19d251159075a4c37af514c3b8ef99c22e02dd8c19161cf397ee94a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"borsh",
|
"borsh",
|
||||||
"bytes",
|
"bytes",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand 0.8.5",
|
"rand 0.8.6",
|
||||||
"rkyv",
|
"rkyv",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "2.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@@ -3425,11 +3388,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.1.3"
|
version = "1.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
|
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
@@ -3438,9 +3401,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.36"
|
version = "0.23.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b"
|
checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
"log",
|
"log",
|
||||||
@@ -3453,18 +3416,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pki-types"
|
name = "rustls-pki-types"
|
||||||
version = "1.14.0"
|
version = "1.14.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd"
|
checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.103.9"
|
version = "0.103.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
|
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
"ring",
|
"ring",
|
||||||
@@ -3486,9 +3449,9 @@ checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-codec"
|
name = "s2n-codec"
|
||||||
version = "0.74.0"
|
version = "0.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37a07f4fac48aa62fe8e70ee05eb8671d143689cbb950ad6cca2e7e52313a093"
|
checksum = "22bacdd8e47b929c10802a93070890d26b8c0e510857113b8f098fca002aecf4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -3497,17 +3460,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-quic"
|
name = "s2n-quic"
|
||||||
version = "1.74.0"
|
version = "1.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab472129b56875c4e42e055903ce95523291a142223b331d1544e3dd9a702293"
|
checksum = "82c23e80ef5205e7f197f6fb0922f3f66eb6599fd826cbf5eb0dc0edba17aee5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cuckoofilter",
|
"cuckoofilter",
|
||||||
"futures",
|
"futures",
|
||||||
"hash_hasher",
|
"hash_hasher",
|
||||||
"rand 0.9.2",
|
"rand 0.10.1",
|
||||||
"rand_chacha 0.9.0",
|
|
||||||
"s2n-codec",
|
"s2n-codec",
|
||||||
"s2n-quic-core",
|
"s2n-quic-core",
|
||||||
"s2n-quic-crypto",
|
"s2n-quic-crypto",
|
||||||
@@ -3522,9 +3484,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-quic-core"
|
name = "s2n-quic-core"
|
||||||
version = "0.74.0"
|
version = "0.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4f526ee912db4354dffc6229d283ac9d7cf297ec1bee8e495b786a7e520138b2"
|
checksum = "8b0d2cd0e789568ac5c374ea7fbf599e1a9d63362bd37baf2d45d386f5f3d25f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
@@ -3544,9 +3506,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-quic-crypto"
|
name = "s2n-quic-crypto"
|
||||||
version = "0.74.0"
|
version = "0.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aec6bbed663012d824ee279833959800837453a32d118d351d971da2ffc0f363"
|
checksum = "d0b6fdfaca6213006dc5163ad8788010f6b5861e6e41352b0a3b00e0fc0930d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@@ -3558,9 +3520,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-quic-platform"
|
name = "s2n-quic-platform"
|
||||||
version = "0.74.0"
|
version = "0.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7229151d4a48d17cec48d274c0c74c82220ddef932aae91fdc18d9beab7097bc"
|
checksum = "7c4742176bbbc522d78e415dfdd3fba84b09ce4744bce20b2f7a6e8ff0c62a3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -3573,9 +3535,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-quic-rustls"
|
name = "s2n-quic-rustls"
|
||||||
version = "0.74.0"
|
version = "0.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fff17e3c7bbde694b1cadacfb42aae93d43d57dbc77b726bdbd67518e51b2dd"
|
checksum = "201a367dbdadc85c9e1fda1be03205740bf2cc848f9436189f88d9b7f3807554"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"rustls",
|
"rustls",
|
||||||
@@ -3587,9 +3549,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-quic-tls"
|
name = "s2n-quic-tls"
|
||||||
version = "0.74.0"
|
version = "0.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64c35e1159a13fd9602905ea0e0c4c0a7d023d62680b8ea1ff73f9c1de1070f6"
|
checksum = "5368d27604ea26aab1dac1df1a84b676a519e139d7927d9afbd6a8137c9129b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"errno",
|
"errno",
|
||||||
@@ -3602,9 +3564,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-quic-tls-default"
|
name = "s2n-quic-tls-default"
|
||||||
version = "0.74.0"
|
version = "0.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c14d35fee2f8997241176e7a191d11cd928e0ff6638bd6aafddf4f3d8d24ff6c"
|
checksum = "e710c8e03558c1eaca90356f34821f6d3b01bf4bf9cc439935cb3002eab2e1d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"s2n-quic-rustls",
|
"s2n-quic-rustls",
|
||||||
"s2n-quic-tls",
|
"s2n-quic-tls",
|
||||||
@@ -3612,27 +3574,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-quic-transport"
|
name = "s2n-quic-transport"
|
||||||
version = "0.74.0"
|
version = "0.78.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5627b2561dba83b25908d49afa87ff27afd6f04a4cb3679731349db71967dc16"
|
checksum = "08db5b4830452c1fff9c9fa93a3fa030c1d7d38a9fc96815e0df98e407fae612"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.17.0",
|
||||||
"intrusive-collections",
|
"intrusive-collections",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"s2n-codec",
|
"s2n-codec",
|
||||||
"s2n-quic-core",
|
"s2n-quic-core",
|
||||||
"siphasher 1.0.2",
|
"siphasher",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-tls"
|
name = "s2n-tls"
|
||||||
version = "0.3.34"
|
version = "0.3.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "98ed0b0786afe33ad792aadf289629d39cb45edc7ab1250a6b6cdf71ebc1c026"
|
checksum = "5d22c36f207d0bb6a38272d5d1fa1cd99094335c70db1bfef54e0b8b672ae26f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -3643,9 +3605,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "s2n-tls-sys"
|
name = "s2n-tls-sys"
|
||||||
version = "0.3.34"
|
version = "0.3.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b1333e7ea5fbc8f36ef4c3c4aa0269441195cee56bef783f0d418151eebb9eac"
|
checksum = "bcf9e3b136cdd2c99f0cee2811d80b9f6bc44b5fd48c172857de32babb506f5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-lc-rs",
|
"aws-lc-rs",
|
||||||
"cc",
|
"cc",
|
||||||
@@ -3709,7 +3671,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde_derive_internals",
|
"serde_derive_internals",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3726,27 +3688,28 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.24.0"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416"
|
checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 2.11.1",
|
||||||
"cssparser",
|
"cssparser",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"fxhash",
|
|
||||||
"log",
|
"log",
|
||||||
"phf 0.8.0",
|
"new_debug_unreachable",
|
||||||
"phf_codegen 0.8.0",
|
"phf 0.13.1",
|
||||||
|
"phf_codegen",
|
||||||
"precomputed-hash",
|
"precomputed-hash",
|
||||||
|
"rustc-hash",
|
||||||
"servo_arc",
|
"servo_arc",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.27"
|
version = "1.0.28"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
|
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
@@ -3791,7 +3754,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3802,7 +3765,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3826,7 +3789,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3840,9 +3803,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "1.0.4"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
|
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
@@ -3861,15 +3824,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_with"
|
name = "serde_with"
|
||||||
version = "3.16.1"
|
version = "3.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7"
|
checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"chrono",
|
"chrono",
|
||||||
"hex",
|
"hex",
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"schemars 0.9.0",
|
"schemars 0.9.0",
|
||||||
"schemars 1.2.1",
|
"schemars 1.2.1",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
@@ -3880,14 +3843,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_with_macros"
|
name = "serde_with_macros"
|
||||||
version = "3.16.1"
|
version = "3.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c"
|
checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3909,16 +3872,15 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "servo_arc"
|
name = "servo_arc"
|
||||||
version = "0.2.0"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741"
|
checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nodrop",
|
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3929,7 +3891,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures 0.2.17",
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3983,9 +3945,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simd-adler32"
|
name = "simd-adler32"
|
||||||
version = "0.3.8"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
|
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simdutf8"
|
name = "simdutf8"
|
||||||
@@ -3993,12 +3955,6 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "siphasher"
|
|
||||||
version = "0.3.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -4030,12 +3986,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
|
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4124,7 +4080,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"hashbrown 0.15.5",
|
"hashbrown 0.15.5",
|
||||||
"hashlink",
|
"hashlink",
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -4149,7 +4105,7 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"sqlx-macros-core",
|
"sqlx-macros-core",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4170,7 +4126,7 @@ dependencies = [
|
|||||||
"sha2",
|
"sha2",
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"sqlx-sqlite",
|
"sqlx-sqlite",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
@@ -4207,25 +4163,24 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "string_cache"
|
name = "string_cache"
|
||||||
version = "0.8.9"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
|
checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"phf_shared 0.11.3",
|
"phf_shared 0.13.1",
|
||||||
"precomputed-hash",
|
"precomputed-hash",
|
||||||
"serde",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "string_cache_codegen"
|
name = "string_cache_codegen"
|
||||||
version = "0.5.4"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0"
|
checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_generator 0.11.3",
|
"phf_generator 0.13.1",
|
||||||
"phf_shared 0.11.3",
|
"phf_shared 0.13.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
]
|
]
|
||||||
@@ -4266,9 +4221,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.116"
|
version = "2.0.117"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb"
|
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -4292,7 +4247,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4310,35 +4265,35 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tao"
|
name = "tao"
|
||||||
version = "0.34.5"
|
version = "0.35.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7"
|
checksum = "1cf65722394c2ac443e80120064987f8914ee1d4e4e36e63cdf10f2990f01159"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"block2",
|
"block2",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"dispatch",
|
"dbus",
|
||||||
|
"dispatch2",
|
||||||
"dlopen2",
|
"dlopen2",
|
||||||
"dpi",
|
"dpi",
|
||||||
"gdkwayland-sys",
|
"gdkwayland-sys",
|
||||||
"gdkx11-sys",
|
"gdkx11-sys",
|
||||||
"gtk",
|
"gtk",
|
||||||
"jni",
|
"jni",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
"ndk-context",
|
|
||||||
"ndk-sys",
|
"ndk-sys",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
|
"objc2-ui-kit",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
|
"percent-encoding",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"scopeguard",
|
|
||||||
"tao-macros",
|
"tao-macros",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"url",
|
"url",
|
||||||
@@ -4356,7 +4311,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4373,9 +4328,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri"
|
name = "tauri"
|
||||||
version = "2.10.2"
|
version = "2.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "463ae8677aa6d0f063a900b9c41ecd4ac2b7ca82f0b058cc4491540e55b20129"
|
checksum = "d059f2527558d9dba6f186dec4772610e1aecfd3f94002397613e7e648752b66"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -4424,9 +4379,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-build"
|
name = "tauri-build"
|
||||||
version = "2.5.5"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ca7bd893329425df750813e95bd2b643d5369d929438da96d5bbb7cc2c918f74"
|
checksum = "be9aa8c59a894f76c29a002501c589de5eb4987a5913d62a6e0a47f320901988"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"cargo_toml",
|
"cargo_toml",
|
||||||
@@ -4440,29 +4395,28 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"tauri-winres",
|
"tauri-winres",
|
||||||
"toml 0.9.12+spec-1.1.0",
|
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-codegen"
|
name = "tauri-codegen"
|
||||||
version = "2.5.4"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aac423e5859d9f9ccdd32e3cf6a5866a15bedbf25aa6630bcb2acde9468f6ae3"
|
checksum = "d3e4e8230d565106aa19dfbaa01a7ed01abf78047fe0577a83377224bd1bf20e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"brotli",
|
"brotli",
|
||||||
"ico",
|
"ico",
|
||||||
"json-patch",
|
"json-patch",
|
||||||
"plist",
|
"plist",
|
||||||
"png",
|
"png 0.17.16",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"time",
|
"time",
|
||||||
@@ -4473,23 +4427,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-macros"
|
name = "tauri-macros"
|
||||||
version = "2.5.4"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b6a1bd2861ff0c8766b1d38b32a6a410f6dc6532d4ef534c47cfb2236092f59"
|
checksum = "bc8de2cddbbc33dbdf4c84f170121886595efdbcc9cb4b3d76342b79d082cedc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
"tauri-codegen",
|
"tauri-codegen",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin"
|
name = "tauri-plugin"
|
||||||
version = "2.5.3"
|
version = "2.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "692a77abd8b8773e107a42ec0e05b767b8d2b7ece76ab36c6c3947e34df9f53f"
|
checksum = "f8d5f58bfd0cdcfdbc0a68dc08b354eea2afc551b421de91b07b69e0dd769d57"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"glob",
|
"glob",
|
||||||
@@ -4498,15 +4452,14 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"toml 0.9.12+spec-1.1.0",
|
|
||||||
"walkdir",
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-dialog"
|
name = "tauri-plugin-dialog"
|
||||||
version = "2.6.0"
|
version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9204b425d9be8d12aa60c2a83a289cf7d1caae40f57f336ed1155b3a5c0e359b"
|
checksum = "65981abb771e74e571a38196c3baa11c459379164791eba0e67abc1a5fac9884"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@@ -4522,13 +4475,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-fs"
|
name = "tauri-plugin-fs"
|
||||||
version = "2.4.5"
|
version = "2.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed390cc669f937afeb8b28032ce837bac8ea023d975a2e207375ec05afaf1804"
|
checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"dunce",
|
"dunce",
|
||||||
"glob",
|
"glob",
|
||||||
|
"log",
|
||||||
|
"objc2-foundation",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"schemars 0.8.22",
|
"schemars 0.8.22",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -4538,7 +4493,7 @@ dependencies = [
|
|||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"tauri-utils",
|
"tauri-utils",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"toml 0.9.12+spec-1.1.0",
|
"toml 1.1.2+spec-1.1.0",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4587,9 +4542,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-store"
|
name = "tauri-plugin-store"
|
||||||
version = "2.4.2"
|
version = "2.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ca1a8ff83c269b115e98726ffc13f9e548a10161544a92ad121d6d0a96e16ea"
|
checksum = "6c72dda16786eb4a3f903e43a17b64d8d78dc0f00fe2aa4b757c28f617a8630b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -4603,9 +4558,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-runtime"
|
||||||
version = "2.10.0"
|
version = "2.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b885ffeac82b00f1f6fd292b6e5aabfa7435d537cef57d11e38a489956535651"
|
checksum = "1e42bbcb76237351fbaa02f08d808c537dc12eb5a6eabbf3e517b50056334d95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cookie",
|
"cookie",
|
||||||
"dpi",
|
"dpi",
|
||||||
@@ -4628,9 +4583,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime-wry"
|
name = "tauri-runtime-wry"
|
||||||
version = "2.10.0"
|
version = "2.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5204682391625e867d16584fedc83fc292fb998814c9f7918605c789cd876314"
|
checksum = "2cadb13dad0c681e1e0a2c49ae488f0e2906ded3d57e7a0017f4aaf46e387117"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
@@ -4638,7 +4593,6 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
"objc2-foundation",
|
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
@@ -4655,24 +4609,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-utils"
|
name = "tauri-utils"
|
||||||
version = "2.8.2"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fcd169fccdff05eff2c1033210b9b94acd07a47e6fa9a3431cf09cfd4f01c87e"
|
checksum = "55f61d2bf7188fbcf2b0ed095b67a6bc498f713c939314bb19eb700118a573b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"brotli",
|
"brotli",
|
||||||
"cargo_metadata",
|
"cargo_metadata",
|
||||||
"ctor",
|
"ctor",
|
||||||
|
"dom_query",
|
||||||
"dunce",
|
"dunce",
|
||||||
"glob",
|
"glob",
|
||||||
"html5ever",
|
|
||||||
"http",
|
"http",
|
||||||
"infer",
|
"infer",
|
||||||
"json-patch",
|
"json-patch",
|
||||||
"kuchikiki",
|
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"phf 0.11.3",
|
"phf 0.11.3",
|
||||||
|
"plist",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -4684,7 +4638,7 @@ dependencies = [
|
|||||||
"serde_with",
|
"serde_with",
|
||||||
"swift-rs",
|
"swift-rs",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"toml 0.9.12+spec-1.1.0",
|
"toml 1.1.2+spec-1.1.0",
|
||||||
"url",
|
"url",
|
||||||
"urlpattern",
|
"urlpattern",
|
||||||
"uuid",
|
"uuid",
|
||||||
@@ -4693,23 +4647,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-winres"
|
name = "tauri-winres"
|
||||||
version = "0.3.5"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1087b111fe2b005e42dbdc1990fc18593234238d47453b0c99b7de1c9ab2c1e0"
|
checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dunce",
|
"dunce",
|
||||||
"embed-resource",
|
"embed-resource",
|
||||||
"toml 0.9.12+spec-1.1.0",
|
"toml 1.1.2+spec-1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tendril"
|
name = "tendril"
|
||||||
version = "0.4.3"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
|
checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futf",
|
"new_debug_unreachable",
|
||||||
"mac",
|
|
||||||
"utf-8",
|
"utf-8",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -4739,7 +4692,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4750,7 +4703,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4788,9 +4741,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.2"
|
version = "0.8.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
|
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
@@ -4798,9 +4751,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.10.0"
|
version = "1.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"tinyvec_macros",
|
"tinyvec_macros",
|
||||||
]
|
]
|
||||||
@@ -4813,9 +4766,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.49.0"
|
version = "1.52.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -4830,13 +4783,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "2.6.0"
|
version = "2.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4881,13 +4834,28 @@ version = "0.9.12+spec-1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"serde_spanned 1.0.4",
|
"serde_spanned 1.1.1",
|
||||||
"toml_datetime 0.7.5+spec-1.1.0",
|
"toml_datetime 0.7.5+spec-1.1.0",
|
||||||
"toml_parser",
|
"toml_parser",
|
||||||
"toml_writer",
|
"toml_writer",
|
||||||
"winnow 0.7.14",
|
"winnow 0.7.15",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "1.1.2+spec-1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"serde_core",
|
||||||
|
"serde_spanned 1.1.1",
|
||||||
|
"toml_datetime 1.1.1+spec-1.1.0",
|
||||||
|
"toml_parser",
|
||||||
|
"toml_writer",
|
||||||
|
"winnow 1.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4908,13 +4876,22 @@ dependencies = [
|
|||||||
"serde_core",
|
"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]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.19.15"
|
version = "0.19.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"toml_datetime 0.6.3",
|
"toml_datetime 0.6.3",
|
||||||
"winnow 0.5.40",
|
"winnow 0.5.40",
|
||||||
]
|
]
|
||||||
@@ -4925,7 +4902,7 @@ version = "0.20.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned 0.6.9",
|
"serde_spanned 0.6.9",
|
||||||
"toml_datetime 0.6.3",
|
"toml_datetime 0.6.3",
|
||||||
@@ -4934,30 +4911,30 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.23.10+spec-1.0.0"
|
version = "0.25.11+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
|
checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"toml_datetime 0.7.5+spec-1.1.0",
|
"toml_datetime 1.1.1+spec-1.1.0",
|
||||||
"toml_parser",
|
"toml_parser",
|
||||||
"winnow 0.7.14",
|
"winnow 1.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_parser"
|
name = "toml_parser"
|
||||||
version = "1.0.9+spec-1.1.0"
|
version = "1.1.2+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
|
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winnow 0.7.14",
|
"winnow 1.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_writer"
|
name = "toml_writer"
|
||||||
version = "1.0.6+spec-1.1.0"
|
version = "1.1.1+spec-1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
|
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
@@ -4980,7 +4957,7 @@ version = "0.6.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
@@ -5024,7 +5001,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5038,9 +5015,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tray-icon"
|
name = "tray-icon"
|
||||||
version = "0.21.3"
|
version = "0.23.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c"
|
checksum = "15edbb0d80583e85ee8df283410038e17314df5cba30da2087a54a85216c0773"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"dirs",
|
"dirs",
|
||||||
@@ -5052,10 +5029,10 @@ dependencies = [
|
|||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"png",
|
"png 0.18.1",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
"windows-sys 0.60.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5072,9 +5049,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.19.0"
|
version = "1.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unic-char-property"
|
name = "unic-char-property"
|
||||||
@@ -5125,9 +5102,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-segmentation"
|
name = "unicode-segmentation"
|
||||||
version = "1.12.0"
|
version = "1.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
@@ -5192,11 +5169,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.21.0"
|
version = "1.23.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb"
|
checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.4.1",
|
"getrandom 0.4.2",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -5279,11 +5256,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasip2"
|
name = "wasip2"
|
||||||
version = "1.0.2+wasi-0.2.9"
|
version = "1.0.3+wasi-0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
|
checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wit-bindgen",
|
"wit-bindgen 0.57.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5292,14 +5269,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wit-bindgen",
|
"wit-bindgen 0.51.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.108"
|
version = "0.2.120"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
|
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -5310,23 +5287,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.58"
|
version = "0.4.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f"
|
checksum = "af934872acec734c2d80e6617bbb5ff4f12b052dd8e6332b0817bce889516084"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
|
||||||
"futures-util",
|
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"once_cell",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.108"
|
version = "0.2.120"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
|
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -5334,22 +5307,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.108"
|
version = "0.2.120"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
|
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.108"
|
version = "0.2.120"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
|
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -5371,7 +5344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"wasm-encoder",
|
"wasm-encoder",
|
||||||
"wasmparser",
|
"wasmparser",
|
||||||
]
|
]
|
||||||
@@ -5395,22 +5368,34 @@ version = "0.244.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"hashbrown 0.15.5",
|
"hashbrown 0.15.5",
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.85"
|
version = "0.3.97"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598"
|
checksum = "2eadbac71025cd7b0834f20d1fe8472e8495821b4e9801eb0a60bd1f19827602"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web_atoms"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d7cff6eef815df1834fd250e3a2ff436044d82a9f1bc1980ca1dbdf07effc538"
|
||||||
|
dependencies = [
|
||||||
|
"phf 0.13.1",
|
||||||
|
"phf_codegen",
|
||||||
|
"string_cache",
|
||||||
|
"string_cache_codegen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webkit2gtk"
|
name = "webkit2gtk"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
@@ -5477,7 +5462,7 @@ checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5636,7 +5621,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5647,7 +5632,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5987,9 +5972,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.14"
|
version = "0.7.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
|
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -6013,6 +6004,12 @@ dependencies = [
|
|||||||
"wit-bindgen-rust-macro",
|
"wit-bindgen-rust-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen"
|
||||||
|
version = "0.57.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen-core"
|
name = "wit-bindgen-core"
|
||||||
version = "0.51.0"
|
version = "0.51.0"
|
||||||
@@ -6032,9 +6029,9 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"prettyplease",
|
"prettyplease",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
"wasm-metadata",
|
"wasm-metadata",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-component",
|
"wit-component",
|
||||||
@@ -6050,7 +6047,7 @@ dependencies = [
|
|||||||
"prettyplease",
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
"wit-bindgen-core",
|
"wit-bindgen-core",
|
||||||
"wit-bindgen-rust",
|
"wit-bindgen-rust",
|
||||||
]
|
]
|
||||||
@@ -6062,8 +6059,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.1",
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
@@ -6082,7 +6079,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"id-arena",
|
"id-arena",
|
||||||
"indexmap 2.13.0",
|
"indexmap 2.14.0",
|
||||||
"log",
|
"log",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -6094,30 +6091,29 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "writeable"
|
name = "writeable"
|
||||||
version = "0.6.2"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
|
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wry"
|
name = "wry"
|
||||||
version = "0.54.2"
|
version = "0.55.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb26159b420aa77684589a744ae9a9461a95395b848764ad12290a14d960a11a"
|
checksum = "3013fd6116aac351dd2e18f349b28b2cfef3a5ff3253a9d0ce2d7193bb1b4429"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"block2",
|
"block2",
|
||||||
"cookie",
|
"cookie",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"dirs",
|
"dirs",
|
||||||
|
"dom_query",
|
||||||
"dpi",
|
"dpi",
|
||||||
"dunce",
|
"dunce",
|
||||||
"gdkx11",
|
"gdkx11",
|
||||||
"gtk",
|
"gtk",
|
||||||
"html5ever",
|
|
||||||
"http",
|
"http",
|
||||||
"javascriptcore-rs",
|
"javascriptcore-rs",
|
||||||
"jni",
|
"jni",
|
||||||
"kuchikiki",
|
|
||||||
"libc",
|
"libc",
|
||||||
"ndk",
|
"ndk",
|
||||||
"objc2",
|
"objc2",
|
||||||
@@ -6175,9 +6171,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
|
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"stable_deref_trait",
|
"stable_deref_trait",
|
||||||
"yoke-derive",
|
"yoke-derive",
|
||||||
@@ -6186,54 +6182,54 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke-derive"
|
name = "yoke-derive"
|
||||||
version = "0.8.1"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
|
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.39"
|
version = "0.8.48"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a"
|
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.39"
|
version = "0.8.48"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
|
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom"
|
name = "zerofrom"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
|
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerofrom-derive",
|
"zerofrom-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom-derive"
|
name = "zerofrom-derive"
|
||||||
version = "0.1.6"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -6254,14 +6250,14 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
|
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"yoke",
|
"yoke",
|
||||||
@@ -6270,9 +6266,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec"
|
name = "zerovec"
|
||||||
version = "0.11.5"
|
version = "0.11.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
|
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
@@ -6281,13 +6277,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec-derive"
|
name = "zerovec-derive"
|
||||||
version = "0.11.2"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
|
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.116",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -13,18 +13,14 @@ members = [
|
|||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
bytes = { version = "1", features = ["serde"] }
|
bytes = { version = "1", features = ["serde"] }
|
||||||
chrono = "0.4"
|
|
||||||
clap = { version = "4", features = ["derive"] }
|
|
||||||
eyre = "0.6"
|
eyre = "0.6"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
gethostname = "1"
|
gethostname = "1"
|
||||||
if-addrs = "0.15"
|
if-addrs = "0.15"
|
||||||
itertools = "0.14"
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mdns-sd = "0.18"
|
mdns-sd = "0.18"
|
||||||
mimalloc = { version = "0.1", features = ["secure"] }
|
mimalloc = { version = "0.1", features = ["secure"] }
|
||||||
s2n-quic = { version = "1", features = ["provider-event-tracing"] }
|
s2n-quic = { version = "1", features = ["provider-event-tracing"] }
|
||||||
semver = "1"
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
sqlx = { version = "0.8", default-features = false, features = [
|
sqlx = { version = "0.8", default-features = false, features = [
|
||||||
@@ -40,7 +36,6 @@ tauri-plugin-store = "2"
|
|||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tokio-util = { version = "0.7", features = ["codec"] }
|
tokio-util = { version = "0.7", features = ["codec"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
||||||
uuid = { version = "1", features = ["v7"] }
|
uuid = { version = "1", features = ["v7"] }
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
windows = { version = "0.62", features = [
|
windows = { version = "0.62", features = [
|
||||||
|
|||||||
@@ -19,3 +19,7 @@ eyre = { workspace = true }
|
|||||||
sqlx = { workspace = true }
|
sqlx = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
test = false
|
||||||
|
doctest = false
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ todo = "warn"
|
|||||||
unwrap_used = "warn"
|
unwrap_used = "warn"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# external
|
|
||||||
bytes = { workspace = true }
|
|
||||||
eyre = { workspace = true }
|
eyre = { workspace = true }
|
||||||
semver = { workspace = true }
|
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
||||||
|
|||||||
@@ -15,5 +15,7 @@ unwrap_used = "warn"
|
|||||||
eyre = { workspace = true }
|
eyre = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
mdns-sd = { workspace = true }
|
mdns-sd = { workspace = true }
|
||||||
tokio = { workspace = true }
|
|
||||||
tracing = { workspace = true }
|
[lib]
|
||||||
|
test = false
|
||||||
|
doctest = false
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ todo = "warn"
|
|||||||
unwrap_used = "warn"
|
unwrap_used = "warn"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# local
|
|
||||||
lanspread-compat = { path = "../lanspread-compat" }
|
|
||||||
lanspread-db = { path = "../lanspread-db" }
|
lanspread-db = { path = "../lanspread-db" }
|
||||||
lanspread-mdns = { path = "../lanspread-mdns" }
|
lanspread-mdns = { path = "../lanspread-mdns" }
|
||||||
lanspread-proto = { path = "../lanspread-proto" }
|
lanspread-proto = { path = "../lanspread-proto" }
|
||||||
@@ -28,6 +26,8 @@ serde = { workspace = true }
|
|||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
tokio-util = { workspace = true }
|
tokio-util = { workspace = true }
|
||||||
tracing = { workspace = true }
|
|
||||||
uuid = { workspace = true }
|
uuid = { workspace = true }
|
||||||
walkdir = { workspace = true }
|
walkdir = { workspace = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
//! UI event helpers used by peer command and service code.
|
||||||
|
|
||||||
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
|
use tokio::sync::{RwLock, mpsc::UnboundedSender};
|
||||||
|
|
||||||
|
use crate::{PeerEvent, peer_db::PeerGameDB};
|
||||||
|
|
||||||
|
pub fn send(tx_notify_ui: &UnboundedSender<PeerEvent>, event: PeerEvent, label: &str) {
|
||||||
|
if let Err(err) = tx_notify_ui.send(event) {
|
||||||
|
log::error!("Failed to send {label} event: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn emit_peer_game_list(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
) {
|
||||||
|
let games = { peer_game_db.read().await.get_all_games() };
|
||||||
|
send(tx_notify_ui, PeerEvent::ListGames(games), "ListGames");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn emit_peer_count(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
) {
|
||||||
|
let peer_count = { peer_game_db.read().await.get_peer_addresses().len() };
|
||||||
|
send(
|
||||||
|
tx_notify_ui,
|
||||||
|
PeerEvent::PeerCountUpdated(peer_count),
|
||||||
|
"PeerCountUpdated",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn emit_peer_discovered(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
) {
|
||||||
|
send(
|
||||||
|
tx_notify_ui,
|
||||||
|
PeerEvent::PeerDiscovered(peer_addr),
|
||||||
|
"PeerDiscovered",
|
||||||
|
);
|
||||||
|
emit_peer_count(peer_game_db, tx_notify_ui).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn emit_peer_lost(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
) {
|
||||||
|
send(tx_notify_ui, PeerEvent::PeerLost(peer_addr), "PeerLost");
|
||||||
|
emit_peer_count(peer_game_db, tx_notify_ui).await;
|
||||||
|
}
|
||||||
@@ -2,19 +2,24 @@
|
|||||||
|
|
||||||
use std::{net::SocketAddr, sync::Arc};
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
use lanspread_db::db::{Game, GameFileDescription};
|
use lanspread_db::db::GameFileDescription;
|
||||||
use tokio::sync::{RwLock, mpsc::UnboundedSender};
|
use tokio::sync::{RwLock, mpsc::UnboundedSender};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
PeerEvent,
|
PeerEvent,
|
||||||
context::Ctx,
|
context::Ctx,
|
||||||
download::download_game_files,
|
download::download_game_files,
|
||||||
|
events,
|
||||||
identity::FEATURE_LIBRARY_DELTA,
|
identity::FEATURE_LIBRARY_DELTA,
|
||||||
local_games::{
|
local_games::{
|
||||||
LocalLibraryScan, get_game_file_descriptions, local_download_available, scan_local_library,
|
LocalLibraryScan,
|
||||||
|
get_game_file_descriptions,
|
||||||
|
local_download_available,
|
||||||
|
scan_local_library,
|
||||||
},
|
},
|
||||||
network::{announce_games_to_peer, request_game_details_from_peer, send_library_delta},
|
network::{announce_games_to_peer, request_game_details_from_peer, send_library_delta},
|
||||||
peer_db::{PeerGameDB, PeerId},
|
peer_db::PeerGameDB,
|
||||||
|
remote_peer::ensure_peer_id_for_addr,
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -24,32 +29,7 @@ use crate::{
|
|||||||
/// Handles the `ListGames` command.
|
/// Handles the `ListGames` command.
|
||||||
pub async fn handle_list_games_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerEvent>) {
|
pub async fn handle_list_games_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerEvent>) {
|
||||||
log::info!("ListGames command received");
|
log::info!("ListGames command received");
|
||||||
emit_peer_game_list(&ctx.peer_game_db, tx_notify_ui).await;
|
events::emit_peer_game_list(&ctx.peer_game_db, tx_notify_ui).await;
|
||||||
}
|
|
||||||
|
|
||||||
/// Emits the aggregated game list to the UI.
|
|
||||||
pub async fn emit_peer_game_list(
|
|
||||||
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
|
||||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
|
||||||
) {
|
|
||||||
let all_games = { peer_game_db.read().await.get_all_games() };
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::ListGames(all_games)) {
|
|
||||||
log::error!("Failed to send ListGames event: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn ensure_peer_id_for_addr(
|
|
||||||
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
|
||||||
peer_addr: SocketAddr,
|
|
||||||
) -> PeerId {
|
|
||||||
let mut db = peer_game_db.write().await;
|
|
||||||
if let Some(peer_id) = db.peer_id_for_addr(&peer_addr).cloned() {
|
|
||||||
return peer_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
let legacy_id = format!("legacy-{peer_addr}");
|
|
||||||
db.upsert_peer(legacy_id.clone(), peer_addr);
|
|
||||||
legacy_id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to serve a game from local files.
|
/// Tries to serve a game from local files.
|
||||||
@@ -165,12 +145,10 @@ pub async fn handle_download_game_files_command(
|
|||||||
) {
|
) {
|
||||||
log::info!("Got PeerCommand::DownloadGameFiles");
|
log::info!("Got PeerCommand::DownloadGameFiles");
|
||||||
let games_folder = { ctx.game_dir.read().await.clone() };
|
let games_folder = { ctx.game_dir.read().await.clone() };
|
||||||
if games_folder.is_none() {
|
let Some(games_folder) = games_folder else {
|
||||||
log::error!("Cannot handle game file descriptions: games_folder is not set");
|
log::error!("Cannot handle game file descriptions: games_folder is not set");
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
|
|
||||||
let games_folder = games_folder.expect("checked above");
|
|
||||||
|
|
||||||
// Use majority validation to get trusted file descriptions and peer whitelist
|
// Use majority validation to get trusted file descriptions and peer whitelist
|
||||||
let (validated_descriptions, peer_whitelist, file_peer_map) = {
|
let (validated_descriptions, peer_whitelist, file_peer_map) = {
|
||||||
@@ -312,10 +290,7 @@ pub async fn handle_set_game_dir_command(
|
|||||||
/// Handles the `GetPeerCount` command.
|
/// Handles the `GetPeerCount` command.
|
||||||
pub async fn handle_get_peer_count_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerEvent>) {
|
pub async fn handle_get_peer_count_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerEvent>) {
|
||||||
log::info!("GetPeerCount command received");
|
log::info!("GetPeerCount command received");
|
||||||
let peer_count = { ctx.peer_game_db.read().await.get_peer_addresses().len() };
|
events::emit_peer_count(&ctx.peer_game_db, tx_notify_ui).await;
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerCountUpdated(peer_count)) {
|
|
||||||
log::error!("Failed to send PeerCountUpdated event: {e}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -348,11 +323,7 @@ pub async fn update_and_announce_games(
|
|||||||
*db_guard = Some(game_db.clone());
|
*db_guard = Some(game_db.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let all_games = game_db
|
let all_games = game_db.all_games().into_iter().cloned().collect::<Vec<_>>();
|
||||||
.all_games()
|
|
||||||
.into_iter()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<Game>>();
|
|
||||||
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::LocalGamesUpdated(all_games.clone())) {
|
if let Err(e) = tx_notify_ui.send(PeerEvent::LocalGamesUpdated(all_games.clone())) {
|
||||||
log::error!("Failed to send LocalGamesUpdated event: {e}");
|
log::error!("Failed to send LocalGamesUpdated event: {e}");
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ mod config;
|
|||||||
mod context;
|
mod context;
|
||||||
mod download;
|
mod download;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod events;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
mod identity;
|
mod identity;
|
||||||
mod library;
|
mod library;
|
||||||
@@ -24,6 +25,7 @@ mod network;
|
|||||||
mod path_validation;
|
mod path_validation;
|
||||||
mod peer;
|
mod peer;
|
||||||
mod peer_db;
|
mod peer_db;
|
||||||
|
mod remote_peer;
|
||||||
mod services;
|
mod services;
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|||||||
@@ -409,8 +409,8 @@ impl PeerGameDB {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn game_files_for(&self, game_id: &str) -> Vec<(SocketAddr, Vec<GameFileDescription>)> {
|
pub fn game_files_for(&self, game_id: &str) -> Vec<(SocketAddr, Vec<GameFileDescription>)> {
|
||||||
self.peers
|
self.peers
|
||||||
.iter()
|
.values()
|
||||||
.filter_map(|(_, peer)| {
|
.filter_map(|peer| {
|
||||||
peer.files
|
peer.files
|
||||||
.get(game_id)
|
.get(game_id)
|
||||||
.cloned()
|
.cloned()
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
//! Shared helpers for remote peer identity and legacy game announcements.
|
||||||
|
|
||||||
|
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
|
use lanspread_db::db::Game;
|
||||||
|
use lanspread_proto::{Availability, GameSummary};
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
library::compute_library_digest,
|
||||||
|
peer_db::{PeerGameDB, PeerId},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn ensure_peer_id_for_addr(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
) -> PeerId {
|
||||||
|
let mut db = peer_game_db.write().await;
|
||||||
|
if let Some(peer_id) = db.peer_id_for_addr(&peer_addr).cloned() {
|
||||||
|
return peer_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
let legacy_id = format!("legacy-{peer_addr}");
|
||||||
|
db.upsert_peer(legacy_id.clone(), peer_addr);
|
||||||
|
legacy_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn summary_from_game(game: &Game) -> GameSummary {
|
||||||
|
GameSummary {
|
||||||
|
id: game.id.clone(),
|
||||||
|
name: game.name.clone(),
|
||||||
|
size: game.size,
|
||||||
|
downloaded: game.downloaded,
|
||||||
|
installed: game.installed,
|
||||||
|
eti_version: game.eti_game_version.clone(),
|
||||||
|
manifest_hash: 0,
|
||||||
|
availability: Availability::Ready,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_peer_from_game_list(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
games: &[Game],
|
||||||
|
) -> Vec<Game> {
|
||||||
|
let summaries = games.iter().map(summary_from_game).collect::<Vec<_>>();
|
||||||
|
let mut by_id = HashMap::with_capacity(summaries.len());
|
||||||
|
for summary in &summaries {
|
||||||
|
by_id.insert(summary.id.clone(), summary.clone());
|
||||||
|
}
|
||||||
|
let digest = compute_library_digest(&by_id);
|
||||||
|
let peer_id = ensure_peer_id_for_addr(peer_game_db, peer_addr).await;
|
||||||
|
|
||||||
|
let mut db = peer_game_db.write().await;
|
||||||
|
db.update_peer_games(&peer_id, summaries);
|
||||||
|
let features = db.peer_features(&peer_id);
|
||||||
|
db.update_peer_library(&peer_id, 0, digest, features);
|
||||||
|
db.get_all_games()
|
||||||
|
}
|
||||||
@@ -1,1225 +1,18 @@
|
|||||||
//! Background services for the peer system.
|
//! Long-running peer services.
|
||||||
|
//!
|
||||||
use std::{
|
//! Each submodule owns one runtime concern. The public surface intentionally
|
||||||
collections::{HashMap, HashSet},
|
//! stays small because `lib.rs` only needs to start these four background tasks.
|
||||||
net::SocketAddr,
|
|
||||||
path::PathBuf,
|
mod advertise;
|
||||||
sync::Arc,
|
mod discovery;
|
||||||
time::Duration,
|
mod handshake;
|
||||||
};
|
mod legacy;
|
||||||
|
mod liveness;
|
||||||
use futures::{SinkExt, StreamExt};
|
mod local_monitor;
|
||||||
use lanspread_db::db::Game;
|
mod server;
|
||||||
use lanspread_mdns::{LANSPREAD_SERVICE_TYPE, MdnsAdvertiser, MdnsBrowser, MdnsService};
|
mod stream;
|
||||||
use lanspread_proto::{
|
|
||||||
Hello,
|
pub use discovery::run_peer_discovery;
|
||||||
HelloAck,
|
pub use liveness::run_ping_service;
|
||||||
LibraryDelta,
|
pub use local_monitor::run_local_game_monitor;
|
||||||
LibrarySnapshot,
|
pub use server::run_server_component;
|
||||||
Message,
|
|
||||||
PROTOCOL_VERSION,
|
|
||||||
Request,
|
|
||||||
Response,
|
|
||||||
};
|
|
||||||
use s2n_quic::{Connection, Server, provider::limits::Limits, stream::BidirectionalStream};
|
|
||||||
use tokio::{
|
|
||||||
sync::{RwLock, mpsc::UnboundedSender},
|
|
||||||
task::JoinHandle,
|
|
||||||
};
|
|
||||||
use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
PeerEvent,
|
|
||||||
config::{
|
|
||||||
CERT_PEM,
|
|
||||||
KEY_PEM,
|
|
||||||
LOCAL_GAME_MONITOR_INTERVAL_SECS,
|
|
||||||
PEER_PING_INTERVAL_SECS,
|
|
||||||
peer_stale_timeout,
|
|
||||||
},
|
|
||||||
context::{Ctx, PeerCtx},
|
|
||||||
error::PeerError,
|
|
||||||
handlers::{emit_peer_game_list, update_and_announce_games},
|
|
||||||
identity::default_features,
|
|
||||||
library::{
|
|
||||||
LocalLibraryState,
|
|
||||||
build_library_snapshot,
|
|
||||||
build_library_summary,
|
|
||||||
compute_library_digest,
|
|
||||||
},
|
|
||||||
local_games::{get_game_file_descriptions, scan_local_library},
|
|
||||||
network::{
|
|
||||||
exchange_hello,
|
|
||||||
fetch_games_from_peer,
|
|
||||||
ping_peer,
|
|
||||||
select_advertise_ip,
|
|
||||||
send_library_delta,
|
|
||||||
send_library_snapshot,
|
|
||||||
send_library_summary,
|
|
||||||
},
|
|
||||||
peer::{send_game_file_chunk, send_game_file_data},
|
|
||||||
peer_db::{PeerGameDB, PeerId, PeerUpsert},
|
|
||||||
};
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Server component
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
/// Runs the QUIC server and mDNS advertiser.
|
|
||||||
pub async fn run_server_component(
|
|
||||||
addr: SocketAddr,
|
|
||||||
ctx: PeerCtx,
|
|
||||||
tx_notify_ui: UnboundedSender<PeerEvent>,
|
|
||||||
) -> eyre::Result<()> {
|
|
||||||
let limits = Limits::default()
|
|
||||||
.with_max_handshake_duration(Duration::from_secs(3))?
|
|
||||||
.with_max_idle_timeout(Duration::from_secs(3))?;
|
|
||||||
|
|
||||||
let mut server = Server::builder()
|
|
||||||
.with_tls((CERT_PEM, KEY_PEM))?
|
|
||||||
.with_io(addr)?
|
|
||||||
.with_limits(limits)?
|
|
||||||
.start()?;
|
|
||||||
|
|
||||||
let server_addr = server.local_addr()?;
|
|
||||||
log::info!("Peer server listening on {server_addr}");
|
|
||||||
|
|
||||||
let advertise_ip = select_advertise_ip()?;
|
|
||||||
let advertise_addr = SocketAddr::new(advertise_ip, server_addr.port());
|
|
||||||
log::info!("Advertising peer via mDNS from {advertise_addr}");
|
|
||||||
{
|
|
||||||
let mut guard = ctx.local_peer_addr.write().await;
|
|
||||||
*guard = Some(advertise_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start mDNS advertising for peer discovery
|
|
||||||
let peer_id = ctx.peer_id.as_ref().clone();
|
|
||||||
let hostname = gethostname::gethostname();
|
|
||||||
let hostname_str = hostname.to_str().unwrap_or("");
|
|
||||||
|
|
||||||
// Calculate maximum hostname length that fits with UUID in 63 char limit
|
|
||||||
let max_hostname_len = 63usize.saturating_sub(peer_id.len() + 1);
|
|
||||||
let truncated_hostname = if hostname_str.len() > max_hostname_len {
|
|
||||||
hostname_str.get(..max_hostname_len).unwrap_or(hostname_str)
|
|
||||||
} else {
|
|
||||||
hostname_str
|
|
||||||
};
|
|
||||||
|
|
||||||
let combined_str = if truncated_hostname.is_empty() {
|
|
||||||
peer_id.clone()
|
|
||||||
} else {
|
|
||||||
format!("{truncated_hostname}-{peer_id}")
|
|
||||||
};
|
|
||||||
|
|
||||||
let (library_rev, library_digest) = {
|
|
||||||
let library_guard = ctx.local_library.read().await;
|
|
||||||
(library_guard.revision, library_guard.digest)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut properties = HashMap::new();
|
|
||||||
properties.insert("peer_id".to_string(), peer_id.clone());
|
|
||||||
properties.insert("proto_ver".to_string(), PROTOCOL_VERSION.to_string());
|
|
||||||
properties.insert("library_rev".to_string(), library_rev.to_string());
|
|
||||||
properties.insert("library_digest".to_string(), library_digest.to_string());
|
|
||||||
if !hostname_str.is_empty() {
|
|
||||||
properties.insert("hostname".to_string(), hostname_str.to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mdns = tokio::task::spawn_blocking(move || {
|
|
||||||
MdnsAdvertiser::new(
|
|
||||||
LANSPREAD_SERVICE_TYPE,
|
|
||||||
&combined_str,
|
|
||||||
advertise_addr,
|
|
||||||
Some(properties),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.await??;
|
|
||||||
|
|
||||||
// Monitor mDNS events
|
|
||||||
let _tx_notify_ui_mdns = tx_notify_ui.clone();
|
|
||||||
let hostname = truncated_hostname.to_string();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
log::info!("Registering mDNS service with hostname: {hostname}");
|
|
||||||
while let Ok(event) = mdns.monitor.recv() {
|
|
||||||
match event {
|
|
||||||
lanspread_mdns::DaemonEvent::Error(e) => {
|
|
||||||
log::error!("mDNS error: {e}");
|
|
||||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
log::trace!("mDNS event: {event:?}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
while let Some(connection) = server.accept().await {
|
|
||||||
let ctx = ctx.clone();
|
|
||||||
let tx_notify_ui = tx_notify_ui.clone();
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = handle_peer_connection(connection, ctx, tx_notify_ui).await {
|
|
||||||
log::error!("Peer connection error: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handles an incoming peer connection.
|
|
||||||
async fn handle_peer_connection(
|
|
||||||
mut connection: Connection,
|
|
||||||
ctx: PeerCtx,
|
|
||||||
tx_notify_ui: UnboundedSender<PeerEvent>,
|
|
||||||
) -> eyre::Result<()> {
|
|
||||||
let remote_addr = connection.remote_addr()?;
|
|
||||||
log::info!("{remote_addr} peer connected");
|
|
||||||
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerConnected(remote_addr)) {
|
|
||||||
log::error!("Failed to send PeerConnected event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle streams
|
|
||||||
while let Ok(Some(stream)) = connection.accept_bidirectional_stream().await {
|
|
||||||
let ctx = ctx.clone();
|
|
||||||
let remote_addr = Some(remote_addr);
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = handle_peer_stream(stream, ctx, remote_addr).await {
|
|
||||||
log::error!("{remote_addr:?} peer stream error: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerDisconnected(remote_addr)) {
|
|
||||||
log::error!("Failed to send PeerDisconnected event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LibraryUpdate {
|
|
||||||
Delta(LibraryDelta),
|
|
||||||
Snapshot(LibrarySnapshot),
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn build_hello_from_state(
|
|
||||||
peer_id: &str,
|
|
||||||
local_library: &Arc<RwLock<LocalLibraryState>>,
|
|
||||||
) -> Hello {
|
|
||||||
let library_guard = local_library.read().await;
|
|
||||||
Hello {
|
|
||||||
peer_id: peer_id.to_string(),
|
|
||||||
proto_ver: PROTOCOL_VERSION,
|
|
||||||
library_rev: library_guard.revision,
|
|
||||||
library_digest: library_guard.digest,
|
|
||||||
features: default_features(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn build_hello_ack(ctx: &PeerCtx) -> HelloAck {
|
|
||||||
let library_guard = ctx.local_library.read().await;
|
|
||||||
HelloAck {
|
|
||||||
peer_id: ctx.peer_id.as_ref().clone(),
|
|
||||||
proto_ver: PROTOCOL_VERSION,
|
|
||||||
library_rev: library_guard.revision,
|
|
||||||
library_digest: library_guard.digest,
|
|
||||||
features: default_features(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn select_library_update(
|
|
||||||
local_library: &Arc<RwLock<LocalLibraryState>>,
|
|
||||||
remote_rev: u64,
|
|
||||||
remote_digest: u64,
|
|
||||||
) -> Option<LibraryUpdate> {
|
|
||||||
let library_guard = local_library.read().await;
|
|
||||||
if library_guard.digest == remote_digest {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if remote_rev > library_guard.revision {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(delta) = library_guard.delta_since(remote_rev) {
|
|
||||||
return Some(LibraryUpdate::Delta(delta));
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(LibraryUpdate::Snapshot(build_library_snapshot(
|
|
||||||
&library_guard,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn ensure_peer_id_for_addr(
|
|
||||||
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
|
||||||
peer_addr: SocketAddr,
|
|
||||||
) -> PeerId {
|
|
||||||
let mut db = peer_game_db.write().await;
|
|
||||||
if let Some(peer_id) = db.peer_id_for_addr(&peer_addr).cloned() {
|
|
||||||
return peer_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
let legacy_id = format!("legacy-{peer_addr}");
|
|
||||||
db.upsert_peer(legacy_id.clone(), peer_addr);
|
|
||||||
legacy_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn summary_from_game(game: &Game) -> lanspread_proto::GameSummary {
|
|
||||||
lanspread_proto::GameSummary {
|
|
||||||
id: game.id.clone(),
|
|
||||||
name: game.name.clone(),
|
|
||||||
size: game.size,
|
|
||||||
downloaded: game.downloaded,
|
|
||||||
installed: game.installed,
|
|
||||||
eti_version: game.eti_game_version.clone(),
|
|
||||||
manifest_hash: 0,
|
|
||||||
availability: lanspread_proto::Availability::Ready,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn perform_handshake_with_peer(
|
|
||||||
peer_id: Arc<String>,
|
|
||||||
local_library: Arc<RwLock<LocalLibraryState>>,
|
|
||||||
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
|
||||||
tx_notify_ui: UnboundedSender<PeerEvent>,
|
|
||||||
peer_addr: SocketAddr,
|
|
||||||
peer_id_hint: Option<PeerId>,
|
|
||||||
) -> eyre::Result<()> {
|
|
||||||
let hello = build_hello_from_state(peer_id.as_ref(), &local_library).await;
|
|
||||||
let ack = exchange_hello(peer_addr, hello).await?;
|
|
||||||
|
|
||||||
if ack.proto_ver != PROTOCOL_VERSION {
|
|
||||||
log::warn!(
|
|
||||||
"Peer {peer_addr} uses incompatible protocol {} (expected {PROTOCOL_VERSION})",
|
|
||||||
ack.proto_ver
|
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ack.peer_id == *peer_id {
|
|
||||||
log::trace!("Ignoring handshake with self for {peer_addr}");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(expected) = peer_id_hint.as_ref()
|
|
||||||
&& expected != &ack.peer_id
|
|
||||||
{
|
|
||||||
log::warn!(
|
|
||||||
"Peer {peer_addr} id mismatch: mDNS advertised {expected}, hello ack returned {}",
|
|
||||||
ack.peer_id
|
|
||||||
);
|
|
||||||
let _ = peer_game_db.write().await.remove_peer(expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
let upsert = {
|
|
||||||
let mut db = peer_game_db.write().await;
|
|
||||||
let upsert = db.upsert_peer(ack.peer_id.clone(), peer_addr);
|
|
||||||
db.update_peer_library(
|
|
||||||
&ack.peer_id,
|
|
||||||
ack.library_rev,
|
|
||||||
ack.library_digest,
|
|
||||||
ack.features.clone(),
|
|
||||||
);
|
|
||||||
upsert
|
|
||||||
};
|
|
||||||
|
|
||||||
if upsert.is_new {
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerDiscovered(peer_addr)) {
|
|
||||||
log::error!("Failed to send PeerDiscovered event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_peer_count = { peer_game_db.read().await.get_peer_addresses().len() };
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerCountUpdated(current_peer_count)) {
|
|
||||||
log::error!("Failed to send PeerCountUpdated event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let summary = {
|
|
||||||
let library_guard = local_library.read().await;
|
|
||||||
build_library_summary(&library_guard)
|
|
||||||
};
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = send_library_summary(peer_addr, summary).await {
|
|
||||||
log::warn!("Failed to send library summary to {peer_addr}: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(update) =
|
|
||||||
select_library_update(&local_library, ack.library_rev, ack.library_digest).await
|
|
||||||
{
|
|
||||||
tokio::spawn(async move {
|
|
||||||
let result = match update {
|
|
||||||
LibraryUpdate::Delta(delta) => send_library_delta(peer_addr, delta).await,
|
|
||||||
LibraryUpdate::Snapshot(snapshot) => {
|
|
||||||
send_library_snapshot(peer_addr, snapshot).await
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = result {
|
|
||||||
log::warn!("Failed to send library update to {peer_addr}: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MdnsPeerInfo {
|
|
||||||
addr: SocketAddr,
|
|
||||||
peer_id: Option<PeerId>,
|
|
||||||
proto_ver: Option<u32>,
|
|
||||||
library_rev: u64,
|
|
||||||
library_digest: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_mdns_peer(service: &MdnsService) -> MdnsPeerInfo {
|
|
||||||
let peer_id = service.properties.get("peer_id").cloned();
|
|
||||||
let proto_ver = service
|
|
||||||
.properties
|
|
||||||
.get("proto_ver")
|
|
||||||
.and_then(|value| value.parse::<u32>().ok());
|
|
||||||
let library_rev = service
|
|
||||||
.properties
|
|
||||||
.get("library_rev")
|
|
||||||
.and_then(|value| value.parse::<u64>().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
let library_digest = service
|
|
||||||
.properties
|
|
||||||
.get("library_digest")
|
|
||||||
.and_then(|value| value.parse::<u64>().ok())
|
|
||||||
.unwrap_or(0);
|
|
||||||
|
|
||||||
MdnsPeerInfo {
|
|
||||||
addr: service.addr,
|
|
||||||
peer_id,
|
|
||||||
proto_ver,
|
|
||||||
library_rev,
|
|
||||||
library_digest,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn is_self_advertisement(info: &MdnsPeerInfo, ctx: &Ctx) -> bool {
|
|
||||||
let guard = ctx.local_peer_addr.read().await;
|
|
||||||
guard.as_ref().is_some_and(|addr| *addr == info.addr)
|
|
||||||
|| info
|
|
||||||
.peer_id
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|peer_id| peer_id == ctx.peer_id.as_ref())
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_discovered_peer(
|
|
||||||
info: MdnsPeerInfo,
|
|
||||||
ctx: &Ctx,
|
|
||||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
|
||||||
) {
|
|
||||||
let peer_id = info
|
|
||||||
.peer_id
|
|
||||||
.unwrap_or_else(|| format!("legacy-{}", info.addr));
|
|
||||||
let upsert = {
|
|
||||||
let mut db = ctx.peer_game_db.write().await;
|
|
||||||
let upsert = db.upsert_peer(peer_id.clone(), info.addr);
|
|
||||||
let features = db.peer_features(&peer_id);
|
|
||||||
if info.library_rev > 0 || info.library_digest > 0 {
|
|
||||||
db.update_peer_library(&peer_id, info.library_rev, info.library_digest, features);
|
|
||||||
}
|
|
||||||
upsert
|
|
||||||
};
|
|
||||||
|
|
||||||
if upsert.is_new {
|
|
||||||
log::info!("Discovered peer at: {}", info.addr);
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerDiscovered(info.addr)) {
|
|
||||||
log::error!("Failed to send PeerDiscovered event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_peer_count = ctx.peer_game_db.read().await.get_peer_addresses().len();
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerCountUpdated(current_peer_count)) {
|
|
||||||
log::error!("Failed to send PeerCountUpdated event: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if upsert.is_new || upsert.addr_changed {
|
|
||||||
let peer_id_arc = ctx.peer_id.clone();
|
|
||||||
let local_library = ctx.local_library.clone();
|
|
||||||
let peer_game_db = ctx.peer_game_db.clone();
|
|
||||||
let tx_notify_ui_clone = tx_notify_ui.clone();
|
|
||||||
let peer_id_hint = Some(peer_id.clone());
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
let handshake_result =
|
|
||||||
if info.proto_ver.is_none() || info.proto_ver == Some(PROTOCOL_VERSION) {
|
|
||||||
perform_handshake_with_peer(
|
|
||||||
peer_id_arc,
|
|
||||||
local_library,
|
|
||||||
peer_game_db.clone(),
|
|
||||||
tx_notify_ui_clone.clone(),
|
|
||||||
info.addr,
|
|
||||||
peer_id_hint.clone(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
} else {
|
|
||||||
Err(eyre::eyre!("Skipping hello for legacy peer"))
|
|
||||||
};
|
|
||||||
|
|
||||||
if handshake_result.is_err()
|
|
||||||
&& let Err(e) =
|
|
||||||
request_games_from_peer(info.addr, tx_notify_ui_clone, peer_game_db, 0).await
|
|
||||||
{
|
|
||||||
log::error!("Failed to request games from peer {}: {e}", info.addr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handles a bidirectional stream from a peer.
|
|
||||||
#[allow(clippy::too_many_lines)]
|
|
||||||
async fn handle_peer_stream(
|
|
||||||
stream: BidirectionalStream,
|
|
||||||
ctx: PeerCtx,
|
|
||||||
remote_addr: Option<SocketAddr>,
|
|
||||||
) -> eyre::Result<()> {
|
|
||||||
let (rx, tx) = stream.split();
|
|
||||||
let mut framed_rx = FramedRead::new(rx, LengthDelimitedCodec::new());
|
|
||||||
let mut framed_tx = FramedWrite::new(tx, LengthDelimitedCodec::new());
|
|
||||||
|
|
||||||
log::trace!("{remote_addr:?} peer stream opened");
|
|
||||||
|
|
||||||
// handle streams
|
|
||||||
loop {
|
|
||||||
match framed_rx.next().await {
|
|
||||||
Some(Ok(data)) => {
|
|
||||||
log::trace!(
|
|
||||||
"{:?} msg: (raw): {}",
|
|
||||||
remote_addr,
|
|
||||||
String::from_utf8_lossy(&data)
|
|
||||||
);
|
|
||||||
|
|
||||||
let request = Request::decode(data.freeze());
|
|
||||||
log::debug!("{remote_addr:?} msg: {request:?}");
|
|
||||||
|
|
||||||
if let Some(addr) = remote_addr {
|
|
||||||
ctx.peer_game_db
|
|
||||||
.write()
|
|
||||||
.await
|
|
||||||
.update_last_seen_by_addr(&addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
match request {
|
|
||||||
Request::Ping => {
|
|
||||||
if let Err(e) = framed_tx.send(Response::Pong.encode()).await {
|
|
||||||
log::error!("Failed to send pong: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::Hello(hello) => {
|
|
||||||
if hello.peer_id == *ctx.peer_id {
|
|
||||||
log::trace!("Ignoring hello from self");
|
|
||||||
let ack = build_hello_ack(&ctx).await;
|
|
||||||
if let Err(e) = framed_tx.send(Response::HelloAck(ack).encode()).await {
|
|
||||||
log::error!("Failed to send HelloAck: {e}");
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if hello.proto_ver != PROTOCOL_VERSION {
|
|
||||||
log::warn!(
|
|
||||||
"Incompatible protocol from {remote_addr:?}: {}",
|
|
||||||
hello.proto_ver
|
|
||||||
);
|
|
||||||
let ack = build_hello_ack(&ctx).await;
|
|
||||||
if let Err(e) = framed_tx.send(Response::HelloAck(ack).encode()).await {
|
|
||||||
log::error!("Failed to send HelloAck: {e}");
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let upsert = if let Some(addr) = remote_addr {
|
|
||||||
let mut db = ctx.peer_game_db.write().await;
|
|
||||||
let upsert = db.upsert_peer(hello.peer_id.clone(), addr);
|
|
||||||
db.update_peer_library(
|
|
||||||
&hello.peer_id,
|
|
||||||
hello.library_rev,
|
|
||||||
hello.library_digest,
|
|
||||||
hello.features.clone(),
|
|
||||||
);
|
|
||||||
upsert
|
|
||||||
} else {
|
|
||||||
PeerUpsert {
|
|
||||||
is_new: false,
|
|
||||||
addr_changed: false,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if upsert.is_new
|
|
||||||
&& let Some(addr) = remote_addr
|
|
||||||
{
|
|
||||||
if let Err(e) = ctx.tx_notify_ui.send(PeerEvent::PeerDiscovered(addr)) {
|
|
||||||
log::error!("Failed to send PeerDiscovered event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_peer_count =
|
|
||||||
{ ctx.peer_game_db.read().await.get_peer_addresses().len() };
|
|
||||||
if let Err(e) = ctx
|
|
||||||
.tx_notify_ui
|
|
||||||
.send(PeerEvent::PeerCountUpdated(current_peer_count))
|
|
||||||
{
|
|
||||||
log::error!("Failed to send PeerCountUpdated event: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ack = build_hello_ack(&ctx).await;
|
|
||||||
if let Err(e) = framed_tx.send(Response::HelloAck(ack).encode()).await {
|
|
||||||
log::error!("Failed to send HelloAck: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(addr) = remote_addr {
|
|
||||||
if upsert.is_new {
|
|
||||||
let summary = {
|
|
||||||
let library_guard = ctx.local_library.read().await;
|
|
||||||
build_library_summary(&library_guard)
|
|
||||||
};
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = send_library_summary(addr, summary).await {
|
|
||||||
log::warn!("Failed to send library summary to {addr}: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(update) = select_library_update(
|
|
||||||
&ctx.local_library,
|
|
||||||
hello.library_rev,
|
|
||||||
hello.library_digest,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
tokio::spawn(async move {
|
|
||||||
let result = match update {
|
|
||||||
LibraryUpdate::Delta(delta) => {
|
|
||||||
send_library_delta(addr, delta).await
|
|
||||||
}
|
|
||||||
LibraryUpdate::Snapshot(snapshot) => {
|
|
||||||
send_library_snapshot(addr, snapshot).await
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = result {
|
|
||||||
log::warn!("Failed to send library update to {addr}: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::ListGames => {
|
|
||||||
log::info!("Received ListGames request from peer");
|
|
||||||
let snapshot = {
|
|
||||||
let db_guard = ctx.local_game_db.read().await;
|
|
||||||
if let Some(ref db) = *db_guard {
|
|
||||||
db.all_games().into_iter().cloned().collect::<Vec<Game>>()
|
|
||||||
} else {
|
|
||||||
log::info!(
|
|
||||||
"Local game database not yet loaded, responding with empty game list"
|
|
||||||
);
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let games = if snapshot.is_empty() {
|
|
||||||
snapshot
|
|
||||||
} else {
|
|
||||||
let downloading = ctx.downloading_games.read().await;
|
|
||||||
snapshot
|
|
||||||
.into_iter()
|
|
||||||
.filter(|game| !downloading.contains(&game.id))
|
|
||||||
.collect()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = framed_tx.send(Response::ListGames(games).encode()).await {
|
|
||||||
log::error!("Failed to send ListGames response: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::LibrarySummary(summary) => {
|
|
||||||
if let Some(addr) = remote_addr {
|
|
||||||
let peer_id = ensure_peer_id_for_addr(&ctx.peer_game_db, addr).await;
|
|
||||||
let (previous_digest, previous_count, features) = {
|
|
||||||
let db = ctx.peer_game_db.read().await;
|
|
||||||
let (_, digest) = db.peer_library_state(&peer_id).unwrap_or((0, 0));
|
|
||||||
(
|
|
||||||
digest,
|
|
||||||
db.peer_game_count(&peer_id),
|
|
||||||
db.peer_features(&peer_id),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut db = ctx.peer_game_db.write().await;
|
|
||||||
db.update_peer_library(
|
|
||||||
&peer_id,
|
|
||||||
summary.library_rev,
|
|
||||||
summary.library_digest,
|
|
||||||
features,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if summary.library_digest != previous_digest || previous_count == 0 {
|
|
||||||
let peer_id_arc = ctx.peer_id.clone();
|
|
||||||
let local_library = ctx.local_library.clone();
|
|
||||||
let peer_game_db = ctx.peer_game_db.clone();
|
|
||||||
let tx_notify_ui = ctx.tx_notify_ui.clone();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = perform_handshake_with_peer(
|
|
||||||
peer_id_arc,
|
|
||||||
local_library,
|
|
||||||
peer_game_db,
|
|
||||||
tx_notify_ui,
|
|
||||||
addr,
|
|
||||||
Some(peer_id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
log::warn!("Failed to refresh library from {addr}: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::LibrarySnapshot(snapshot) => {
|
|
||||||
if let Some(addr) = remote_addr {
|
|
||||||
let peer_id = ensure_peer_id_for_addr(&ctx.peer_game_db, addr).await;
|
|
||||||
{
|
|
||||||
let mut db = ctx.peer_game_db.write().await;
|
|
||||||
db.apply_library_snapshot(&peer_id, snapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
emit_peer_game_list(&ctx.peer_game_db, &ctx.tx_notify_ui).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::LibraryDelta(delta) => {
|
|
||||||
if let Some(addr) = remote_addr {
|
|
||||||
let peer_id = ensure_peer_id_for_addr(&ctx.peer_game_db, addr).await;
|
|
||||||
let applied = {
|
|
||||||
let mut db = ctx.peer_game_db.write().await;
|
|
||||||
db.apply_library_delta(&peer_id, delta)
|
|
||||||
};
|
|
||||||
|
|
||||||
if applied {
|
|
||||||
emit_peer_game_list(&ctx.peer_game_db, &ctx.tx_notify_ui).await;
|
|
||||||
} else {
|
|
||||||
let peer_id_arc = ctx.peer_id.clone();
|
|
||||||
let local_library = ctx.local_library.clone();
|
|
||||||
let peer_game_db = ctx.peer_game_db.clone();
|
|
||||||
let tx_notify_ui = ctx.tx_notify_ui.clone();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
if let Err(e) = perform_handshake_with_peer(
|
|
||||||
peer_id_arc,
|
|
||||||
local_library,
|
|
||||||
peer_game_db,
|
|
||||||
tx_notify_ui,
|
|
||||||
addr,
|
|
||||||
Some(peer_id),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
log::warn!("Failed to resync library from {addr}: {e}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::GetGame { id } => {
|
|
||||||
log::info!("Received GetGame request for {id} from peer");
|
|
||||||
let downloading = ctx.downloading_games.read().await.contains(&id);
|
|
||||||
let response = if downloading {
|
|
||||||
log::info!(
|
|
||||||
"Declining to serve GetGame for {id} because download is in progress"
|
|
||||||
);
|
|
||||||
Response::GameNotFound(id)
|
|
||||||
} else if let Some(ref game_dir) = *ctx.game_dir.read().await {
|
|
||||||
if let Some(ref db) = *ctx.local_game_db.read().await {
|
|
||||||
if db.get_game_by_id(&id).is_some() {
|
|
||||||
match get_game_file_descriptions(&id, game_dir).await {
|
|
||||||
Ok(file_descriptions) => Response::GetGame {
|
|
||||||
id,
|
|
||||||
file_descriptions,
|
|
||||||
},
|
|
||||||
Err(PeerError::FileSizeDetermination { path, source }) => {
|
|
||||||
let error_msg = format!(
|
|
||||||
"Failed to determine file size for {path}: {source}"
|
|
||||||
);
|
|
||||||
log::error!(
|
|
||||||
"File size determination error for game {id}: {error_msg}"
|
|
||||||
);
|
|
||||||
Response::InternalPeerError(error_msg)
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!(
|
|
||||||
"Failed to get game file descriptions for {id}: {e}"
|
|
||||||
);
|
|
||||||
Response::GameNotFound(id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Response::GameNotFound(id)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Response::GameNotFound(id)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Response::GameNotFound(id)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = framed_tx.send(response.encode()).await {
|
|
||||||
log::error!("Failed to send GetGame response: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::GetGameFileData(desc) => {
|
|
||||||
log::info!(
|
|
||||||
"Received GetGameFileData request for {} from peer",
|
|
||||||
desc.relative_path
|
|
||||||
);
|
|
||||||
|
|
||||||
let maybe_game_dir = ctx.game_dir.read().await.clone();
|
|
||||||
if let Some(game_dir) = maybe_game_dir {
|
|
||||||
let base_dir = PathBuf::from(game_dir);
|
|
||||||
let mut tx = framed_tx.into_inner();
|
|
||||||
send_game_file_data(&desc, &mut tx, &base_dir).await;
|
|
||||||
framed_tx = FramedWrite::new(tx, LengthDelimitedCodec::new());
|
|
||||||
} else if let Err(e) = framed_tx
|
|
||||||
.send(
|
|
||||||
Response::InvalidRequest(
|
|
||||||
desc.relative_path.as_bytes().to_vec().into(),
|
|
||||||
"Game directory not set".to_string(),
|
|
||||||
)
|
|
||||||
.encode(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
log::error!("Failed to send GetGameFileData error: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::GetGameFileChunk {
|
|
||||||
game_id,
|
|
||||||
relative_path,
|
|
||||||
offset,
|
|
||||||
length,
|
|
||||||
} => {
|
|
||||||
log::info!(
|
|
||||||
"{remote_addr:?} received GetGameFileChunk request for {relative_path} (offset {offset}, length {length})"
|
|
||||||
);
|
|
||||||
|
|
||||||
let maybe_game_dir = ctx.game_dir.read().await.clone();
|
|
||||||
if let Some(game_dir) = maybe_game_dir {
|
|
||||||
let base_dir = PathBuf::from(game_dir);
|
|
||||||
let mut tx = framed_tx.into_inner();
|
|
||||||
send_game_file_chunk(
|
|
||||||
&game_id,
|
|
||||||
&relative_path,
|
|
||||||
offset,
|
|
||||||
length,
|
|
||||||
&mut tx,
|
|
||||||
&base_dir,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
framed_tx = FramedWrite::new(tx, LengthDelimitedCodec::new());
|
|
||||||
} else if let Err(e) = framed_tx
|
|
||||||
.send(
|
|
||||||
Response::InvalidRequest(
|
|
||||||
relative_path.as_bytes().to_vec().into(),
|
|
||||||
"Game directory not set".to_string(),
|
|
||||||
)
|
|
||||||
.encode(),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
log::error!("Failed to send GetGameFileChunk error: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::Goodbye { peer_id } => {
|
|
||||||
log::info!("Received Goodbye from peer {peer_id}");
|
|
||||||
let removed = { ctx.peer_game_db.write().await.remove_peer(&peer_id) };
|
|
||||||
if removed.is_some() {
|
|
||||||
if let Some(addr) = remote_addr {
|
|
||||||
if let Err(e) = ctx.tx_notify_ui.send(PeerEvent::PeerLost(addr)) {
|
|
||||||
log::error!("Failed to send PeerLost event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_peer_count =
|
|
||||||
{ ctx.peer_game_db.read().await.get_peer_addresses().len() };
|
|
||||||
if let Err(e) = ctx
|
|
||||||
.tx_notify_ui
|
|
||||||
.send(PeerEvent::PeerCountUpdated(current_peer_count))
|
|
||||||
{
|
|
||||||
log::error!("Failed to send PeerCountUpdated event: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emit_peer_game_list(&ctx.peer_game_db, &ctx.tx_notify_ui).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Request::Invalid(_, _) => {
|
|
||||||
log::error!("Received invalid request from peer");
|
|
||||||
}
|
|
||||||
Request::AnnounceGames(games) => {
|
|
||||||
log::info!(
|
|
||||||
"Received {} announced games from peer {remote_addr:?}",
|
|
||||||
games.len()
|
|
||||||
);
|
|
||||||
if let Some(addr) = remote_addr {
|
|
||||||
let peer_id = ensure_peer_id_for_addr(&ctx.peer_game_db, addr).await;
|
|
||||||
let summaries: Vec<_> = games.iter().map(summary_from_game).collect();
|
|
||||||
let mut map = HashMap::with_capacity(summaries.len());
|
|
||||||
for summary in &summaries {
|
|
||||||
map.insert(summary.id.clone(), summary.clone());
|
|
||||||
}
|
|
||||||
let digest = compute_library_digest(&map);
|
|
||||||
let aggregated_games = {
|
|
||||||
let mut db = ctx.peer_game_db.write().await;
|
|
||||||
db.update_peer_games(&peer_id, summaries);
|
|
||||||
let features = db.peer_features(&peer_id);
|
|
||||||
db.update_peer_library(&peer_id, 0, digest, features);
|
|
||||||
db.get_all_games()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = ctx
|
|
||||||
.tx_notify_ui
|
|
||||||
.send(PeerEvent::ListGames(aggregated_games))
|
|
||||||
{
|
|
||||||
log::error!("Failed to send ListGames event: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Err(e)) => {
|
|
||||||
log::error!("{remote_addr:?} peer stream error: {e}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
log::trace!("{remote_addr:?} peer stream closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Peer discovery
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
/// Runs the peer discovery service using mDNS.
|
|
||||||
pub async fn run_peer_discovery(tx_notify_ui: UnboundedSender<PeerEvent>, ctx: Ctx) {
|
|
||||||
log::info!("Starting peer discovery task");
|
|
||||||
|
|
||||||
let service_type = LANSPREAD_SERVICE_TYPE.to_string();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let (service_tx, mut service_rx) = tokio::sync::mpsc::unbounded_channel();
|
|
||||||
let service_type_clone = service_type.clone();
|
|
||||||
|
|
||||||
let worker_handle = tokio::task::spawn_blocking(move || -> eyre::Result<()> {
|
|
||||||
let browser = MdnsBrowser::new(&service_type_clone)?;
|
|
||||||
loop {
|
|
||||||
if let Some(service) = browser.next_service(None)? {
|
|
||||||
if service_tx.send(service).is_err() {
|
|
||||||
log::debug!("Peer discovery consumer dropped; stopping worker");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::warn!("mDNS browser closed; stopping peer discovery worker");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
|
|
||||||
while let Some(service) = service_rx.recv().await {
|
|
||||||
let info = parse_mdns_peer(&service);
|
|
||||||
if is_self_advertisement(&info, &ctx).await {
|
|
||||||
log::trace!("Ignoring self advertisement at {}", info.addr);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle_discovered_peer(info, &ctx, &tx_notify_ui).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
match worker_handle.await {
|
|
||||||
Ok(Ok(())) => {
|
|
||||||
log::warn!("Peer discovery worker exited; restarting shortly");
|
|
||||||
}
|
|
||||||
Ok(Err(e)) => {
|
|
||||||
log::error!("Peer discovery worker failed: {e}");
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Peer discovery worker join error: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Requests games from a peer with retry logic.
|
|
||||||
async fn request_games_from_peer(
|
|
||||||
peer_addr: SocketAddr,
|
|
||||||
tx_notify_ui: UnboundedSender<PeerEvent>,
|
|
||||||
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
|
||||||
mut retry_count: u32,
|
|
||||||
) -> eyre::Result<()> {
|
|
||||||
loop {
|
|
||||||
match fetch_games_from_peer(peer_addr).await {
|
|
||||||
Ok(games) => {
|
|
||||||
log::info!("Received {} games from peer {peer_addr}", games.len());
|
|
||||||
|
|
||||||
if games.is_empty() && retry_count < 1 {
|
|
||||||
log::info!("Received 0 games from peer {peer_addr}, scheduling retry in 5s");
|
|
||||||
tokio::time::sleep(Duration::from_secs(5)).await;
|
|
||||||
retry_count += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut map = HashMap::with_capacity(games.len());
|
|
||||||
let mut summaries = Vec::with_capacity(games.len());
|
|
||||||
for game in &games {
|
|
||||||
let summary = summary_from_game(game);
|
|
||||||
map.insert(summary.id.clone(), summary.clone());
|
|
||||||
summaries.push(summary);
|
|
||||||
}
|
|
||||||
let digest = compute_library_digest(&map);
|
|
||||||
let peer_id = ensure_peer_id_for_addr(&peer_game_db, peer_addr).await;
|
|
||||||
|
|
||||||
let aggregated_games = {
|
|
||||||
let mut db = peer_game_db.write().await;
|
|
||||||
db.update_peer_games(&peer_id, summaries);
|
|
||||||
let features = db.peer_features(&peer_id);
|
|
||||||
db.update_peer_library(&peer_id, 0, digest, features);
|
|
||||||
db.get_all_games()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::ListGames(aggregated_games)) {
|
|
||||||
log::error!("Failed to send ListGames event: {e}");
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Ping service
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
/// Runs the ping service to check peer liveness.
|
|
||||||
#[allow(clippy::too_many_lines)]
|
|
||||||
pub async fn run_ping_service(
|
|
||||||
tx_notify_ui: UnboundedSender<PeerEvent>,
|
|
||||||
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
|
||||||
downloading_games: Arc<RwLock<HashSet<String>>>,
|
|
||||||
active_downloads: Arc<RwLock<HashMap<String, JoinHandle<()>>>>,
|
|
||||||
) {
|
|
||||||
log::info!(
|
|
||||||
"Starting ping service ({PEER_PING_INTERVAL_SECS}s interval, \
|
|
||||||
{}s idle threshold, {}s timeout)",
|
|
||||||
crate::config::PEER_PING_IDLE_SECS,
|
|
||||||
peer_stale_timeout().as_secs()
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(PEER_PING_INTERVAL_SECS));
|
|
||||||
|
|
||||||
loop {
|
|
||||||
interval.tick().await;
|
|
||||||
|
|
||||||
let peer_snapshots = { peer_game_db.read().await.peer_liveness_snapshot() };
|
|
||||||
|
|
||||||
for (peer_id, peer_addr, last_seen) in peer_snapshots {
|
|
||||||
if last_seen.elapsed() < Duration::from_secs(crate::config::PEER_PING_IDLE_SECS) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let tx_notify_ui_clone = tx_notify_ui.clone();
|
|
||||||
let peer_game_db_clone = peer_game_db.clone();
|
|
||||||
let downloading_games_clone = downloading_games.clone();
|
|
||||||
let active_downloads_clone = active_downloads.clone();
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
|
||||||
match ping_peer(peer_addr).await {
|
|
||||||
Ok(is_alive) => {
|
|
||||||
if is_alive {
|
|
||||||
peer_game_db_clone.write().await.update_last_seen(&peer_id);
|
|
||||||
} else {
|
|
||||||
log::warn!("Peer {peer_addr} failed ping check");
|
|
||||||
let removed_peer =
|
|
||||||
peer_game_db_clone.write().await.remove_peer(&peer_id);
|
|
||||||
if let Some(peer) = removed_peer {
|
|
||||||
log::info!("Removed stale peer: {}", peer.addr);
|
|
||||||
if let Err(e) =
|
|
||||||
tx_notify_ui_clone.send(PeerEvent::PeerLost(peer.addr))
|
|
||||||
{
|
|
||||||
log::error!("Failed to send PeerLost event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_peer_count =
|
|
||||||
{ peer_game_db_clone.read().await.get_peer_addresses().len() };
|
|
||||||
if let Err(e) = tx_notify_ui_clone
|
|
||||||
.send(PeerEvent::PeerCountUpdated(current_peer_count))
|
|
||||||
{
|
|
||||||
log::error!("Failed to send PeerCountUpdated event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
emit_peer_game_list(&peer_game_db_clone, &tx_notify_ui_clone).await;
|
|
||||||
handle_active_downloads_without_peers(
|
|
||||||
&peer_game_db_clone,
|
|
||||||
&downloading_games_clone,
|
|
||||||
&active_downloads_clone,
|
|
||||||
&tx_notify_ui_clone,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Failed to ping peer {peer_addr}: {e}");
|
|
||||||
let removed_peer = peer_game_db_clone.write().await.remove_peer(&peer_id);
|
|
||||||
if let Some(peer) = removed_peer {
|
|
||||||
log::info!("Removed peer due to ping error: {}", peer.addr);
|
|
||||||
if let Err(e) = tx_notify_ui_clone.send(PeerEvent::PeerLost(peer.addr))
|
|
||||||
{
|
|
||||||
log::error!("Failed to send PeerLost event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let current_peer_count =
|
|
||||||
{ peer_game_db_clone.read().await.get_peer_addresses().len() };
|
|
||||||
if let Err(e) = tx_notify_ui_clone
|
|
||||||
.send(PeerEvent::PeerCountUpdated(current_peer_count))
|
|
||||||
{
|
|
||||||
log::error!("Failed to send PeerCountUpdated event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
emit_peer_game_list(&peer_game_db_clone, &tx_notify_ui_clone).await;
|
|
||||||
handle_active_downloads_without_peers(
|
|
||||||
&peer_game_db_clone,
|
|
||||||
&downloading_games_clone,
|
|
||||||
&active_downloads_clone,
|
|
||||||
&tx_notify_ui_clone,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also clean up stale peers
|
|
||||||
let stale_peers = {
|
|
||||||
peer_game_db
|
|
||||||
.read()
|
|
||||||
.await
|
|
||||||
.get_stale_peer_ids(peer_stale_timeout())
|
|
||||||
};
|
|
||||||
let mut removed_any = false;
|
|
||||||
for stale_peer_id in stale_peers {
|
|
||||||
let removed_peer = peer_game_db.write().await.remove_peer(&stale_peer_id);
|
|
||||||
if let Some(peer) = removed_peer {
|
|
||||||
log::info!("Removed stale peer: {}", peer.addr);
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerLost(peer.addr)) {
|
|
||||||
log::error!("Failed to send PeerLost event: {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send updated peer count
|
|
||||||
let current_peer_count = { peer_game_db.read().await.get_peer_addresses().len() };
|
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::PeerCountUpdated(current_peer_count)) {
|
|
||||||
log::error!("Failed to send PeerCountUpdated event: {e}");
|
|
||||||
}
|
|
||||||
removed_any = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if removed_any {
|
|
||||||
emit_peer_game_list(&peer_game_db, &tx_notify_ui).await;
|
|
||||||
handle_active_downloads_without_peers(
|
|
||||||
&peer_game_db,
|
|
||||||
&downloading_games,
|
|
||||||
&active_downloads,
|
|
||||||
&tx_notify_ui,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Handles downloads that no longer have peers available.
|
|
||||||
async fn handle_active_downloads_without_peers(
|
|
||||||
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
|
||||||
downloading_games: &Arc<RwLock<HashSet<String>>>,
|
|
||||||
active_downloads: &Arc<RwLock<HashMap<String, JoinHandle<()>>>>,
|
|
||||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
|
||||||
) {
|
|
||||||
let active_ids: Vec<String> = { downloading_games.read().await.iter().cloned().collect() };
|
|
||||||
if active_ids.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for id in active_ids {
|
|
||||||
let has_peers = {
|
|
||||||
let guard = peer_game_db.read().await;
|
|
||||||
!guard.peers_with_game(&id).is_empty()
|
|
||||||
};
|
|
||||||
|
|
||||||
if has_peers {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let removed_from_tracking = {
|
|
||||||
let mut guard = downloading_games.write().await;
|
|
||||||
guard.remove(&id)
|
|
||||||
};
|
|
||||||
|
|
||||||
if !removed_from_tracking {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(handle) = { active_downloads.write().await.remove(&id) } {
|
|
||||||
handle.abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) =
|
|
||||||
tx_notify_ui.send(PeerEvent::DownloadGameFilesAllPeersGone { id: id.clone() })
|
|
||||||
{
|
|
||||||
log::error!("Failed to send DownloadGameFilesAllPeersGone event: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Local game monitor
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
/// Monitors the local game directory for changes.
|
|
||||||
pub async fn run_local_game_monitor(tx_notify_ui: UnboundedSender<PeerEvent>, ctx: Ctx) {
|
|
||||||
log::info!(
|
|
||||||
"Starting local game directory monitor ({LOCAL_GAME_MONITOR_INTERVAL_SECS}s interval)"
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(LOCAL_GAME_MONITOR_INTERVAL_SECS));
|
|
||||||
|
|
||||||
loop {
|
|
||||||
interval.tick().await;
|
|
||||||
|
|
||||||
let game_dir = {
|
|
||||||
let guard = ctx.game_dir.read().await;
|
|
||||||
guard.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(ref game_dir) = game_dir {
|
|
||||||
match scan_local_library(game_dir).await {
|
|
||||||
Ok(scan) => {
|
|
||||||
update_and_announce_games(&ctx, &tx_notify_ui, scan).await;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Failed to scan local games directory: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
//! mDNS advertisement for the local peer server.
|
||||||
|
|
||||||
|
use std::{collections::HashMap, net::SocketAddr, time::Duration};
|
||||||
|
|
||||||
|
use lanspread_mdns::{LANSPREAD_SERVICE_TYPE, MdnsAdvertiser};
|
||||||
|
use lanspread_proto::PROTOCOL_VERSION;
|
||||||
|
|
||||||
|
use crate::{context::PeerCtx, network::select_advertise_ip};
|
||||||
|
|
||||||
|
pub(super) async fn start_mdns_advertiser(
|
||||||
|
ctx: &PeerCtx,
|
||||||
|
server_addr: SocketAddr,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let advertise_ip = select_advertise_ip()?;
|
||||||
|
let advertise_addr = SocketAddr::new(advertise_ip, server_addr.port());
|
||||||
|
log::info!("Advertising peer via mDNS from {advertise_addr}");
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut guard = ctx.local_peer_addr.write().await;
|
||||||
|
*guard = Some(advertise_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
let peer_id = ctx.peer_id.as_ref().clone();
|
||||||
|
let hostname = gethostname::gethostname().to_string_lossy().into_owned();
|
||||||
|
let advertised_name = advertised_service_name(&hostname, &peer_id);
|
||||||
|
let monitor_name = advertised_name.clone();
|
||||||
|
let properties = advertisement_properties(ctx, &hostname, &peer_id).await;
|
||||||
|
|
||||||
|
let mdns = tokio::task::spawn_blocking(move || {
|
||||||
|
MdnsAdvertiser::new(
|
||||||
|
LANSPREAD_SERVICE_TYPE,
|
||||||
|
&advertised_name,
|
||||||
|
advertise_addr,
|
||||||
|
Some(properties),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.await??;
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
log::info!("Registered mDNS service with name: {monitor_name}");
|
||||||
|
while let Ok(event) = mdns.monitor.recv() {
|
||||||
|
match event {
|
||||||
|
lanspread_mdns::DaemonEvent::Error(err) => {
|
||||||
|
log::error!("mDNS error: {err}");
|
||||||
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
log::trace!("mDNS event: {event:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn advertised_service_name(hostname: &str, peer_id: &str) -> String {
|
||||||
|
let max_hostname_len = 63usize.saturating_sub(peer_id.len() + 1);
|
||||||
|
let truncated_hostname = if hostname.len() > max_hostname_len {
|
||||||
|
hostname.get(..max_hostname_len).unwrap_or(hostname)
|
||||||
|
} else {
|
||||||
|
hostname
|
||||||
|
};
|
||||||
|
|
||||||
|
if truncated_hostname.is_empty() {
|
||||||
|
peer_id.to_string()
|
||||||
|
} else {
|
||||||
|
format!("{truncated_hostname}-{peer_id}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn advertisement_properties(
|
||||||
|
ctx: &PeerCtx,
|
||||||
|
hostname: &str,
|
||||||
|
peer_id: &str,
|
||||||
|
) -> HashMap<String, String> {
|
||||||
|
let (library_rev, library_digest) = {
|
||||||
|
let library_guard = ctx.local_library.read().await;
|
||||||
|
(library_guard.revision, library_guard.digest)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut properties = HashMap::new();
|
||||||
|
properties.insert("peer_id".to_string(), peer_id.to_string());
|
||||||
|
properties.insert("proto_ver".to_string(), PROTOCOL_VERSION.to_string());
|
||||||
|
properties.insert("library_rev".to_string(), library_rev.to_string());
|
||||||
|
properties.insert("library_digest".to_string(), library_digest.to_string());
|
||||||
|
if !hostname.is_empty() {
|
||||||
|
properties.insert("hostname".to_string(), hostname.to_string());
|
||||||
|
}
|
||||||
|
properties
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
//! mDNS peer discovery and discovery-time protocol negotiation.
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use lanspread_mdns::{LANSPREAD_SERVICE_TYPE, MdnsBrowser, MdnsService};
|
||||||
|
use lanspread_proto::PROTOCOL_VERSION;
|
||||||
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
PeerEvent,
|
||||||
|
context::Ctx,
|
||||||
|
events,
|
||||||
|
peer_db::PeerId,
|
||||||
|
services::{handshake::perform_handshake_with_peer, legacy::request_games_from_peer},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MdnsPeerInfo {
|
||||||
|
addr: std::net::SocketAddr,
|
||||||
|
peer_id: Option<PeerId>,
|
||||||
|
proto_ver: Option<u32>,
|
||||||
|
library_rev: u64,
|
||||||
|
library_digest: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs the peer discovery service using mDNS.
|
||||||
|
pub async fn run_peer_discovery(tx_notify_ui: UnboundedSender<PeerEvent>, ctx: Ctx) {
|
||||||
|
log::info!("Starting peer discovery task");
|
||||||
|
|
||||||
|
let service_type = LANSPREAD_SERVICE_TYPE.to_string();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let (service_tx, mut service_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
let service_type_clone = service_type.clone();
|
||||||
|
|
||||||
|
let worker_handle = tokio::task::spawn_blocking(move || -> eyre::Result<()> {
|
||||||
|
let browser = MdnsBrowser::new(&service_type_clone)?;
|
||||||
|
loop {
|
||||||
|
if let Some(service) = browser.next_service(None)? {
|
||||||
|
if service_tx.send(service).is_err() {
|
||||||
|
log::debug!("Peer discovery consumer dropped; stopping worker");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("mDNS browser closed; stopping peer discovery worker");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
while let Some(service) = service_rx.recv().await {
|
||||||
|
let info = parse_mdns_peer(&service);
|
||||||
|
if is_self_advertisement(&info, &ctx).await {
|
||||||
|
log::trace!("Ignoring self advertisement at {}", info.addr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_discovered_peer(info, &ctx, &tx_notify_ui).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
match worker_handle.await {
|
||||||
|
Ok(Ok(())) => {
|
||||||
|
log::warn!("Peer discovery worker exited; restarting shortly");
|
||||||
|
}
|
||||||
|
Ok(Err(err)) => {
|
||||||
|
log::error!("Peer discovery worker failed: {err}");
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Peer discovery worker join error: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_mdns_peer(service: &MdnsService) -> MdnsPeerInfo {
|
||||||
|
MdnsPeerInfo {
|
||||||
|
addr: service.addr,
|
||||||
|
peer_id: service.properties.get("peer_id").cloned(),
|
||||||
|
proto_ver: service
|
||||||
|
.properties
|
||||||
|
.get("proto_ver")
|
||||||
|
.and_then(|value| value.parse::<u32>().ok()),
|
||||||
|
library_rev: service
|
||||||
|
.properties
|
||||||
|
.get("library_rev")
|
||||||
|
.and_then(|value| value.parse::<u64>().ok())
|
||||||
|
.unwrap_or(0),
|
||||||
|
library_digest: service
|
||||||
|
.properties
|
||||||
|
.get("library_digest")
|
||||||
|
.and_then(|value| value.parse::<u64>().ok())
|
||||||
|
.unwrap_or(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_self_advertisement(info: &MdnsPeerInfo, ctx: &Ctx) -> bool {
|
||||||
|
let guard = ctx.local_peer_addr.read().await;
|
||||||
|
guard.as_ref().is_some_and(|addr| *addr == info.addr)
|
||||||
|
|| info
|
||||||
|
.peer_id
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|peer_id| peer_id == ctx.peer_id.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_discovered_peer(
|
||||||
|
info: MdnsPeerInfo,
|
||||||
|
ctx: &Ctx,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
) {
|
||||||
|
let peer_id = info
|
||||||
|
.peer_id
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| format!("legacy-{}", info.addr));
|
||||||
|
|
||||||
|
let upsert = {
|
||||||
|
let mut db = ctx.peer_game_db.write().await;
|
||||||
|
let upsert = db.upsert_peer(peer_id.clone(), info.addr);
|
||||||
|
let features = db.peer_features(&peer_id);
|
||||||
|
if info.library_rev > 0 || info.library_digest > 0 {
|
||||||
|
db.update_peer_library(&peer_id, info.library_rev, info.library_digest, features);
|
||||||
|
}
|
||||||
|
upsert
|
||||||
|
};
|
||||||
|
|
||||||
|
if upsert.is_new {
|
||||||
|
log::info!("Discovered peer at: {}", info.addr);
|
||||||
|
events::emit_peer_discovered(&ctx.peer_game_db, tx_notify_ui, info.addr).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if upsert.is_new || upsert.addr_changed {
|
||||||
|
spawn_protocol_negotiation(&info, ctx, tx_notify_ui.clone(), peer_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_protocol_negotiation(
|
||||||
|
info: &MdnsPeerInfo,
|
||||||
|
ctx: &Ctx,
|
||||||
|
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||||
|
peer_id: PeerId,
|
||||||
|
) {
|
||||||
|
let peer_addr = info.addr;
|
||||||
|
let proto_ver = info.proto_ver;
|
||||||
|
let peer_id_arc = ctx.peer_id.clone();
|
||||||
|
let local_library = ctx.local_library.clone();
|
||||||
|
let peer_game_db = ctx.peer_game_db.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let handshake_result = if proto_ver.is_none() || proto_ver == Some(PROTOCOL_VERSION) {
|
||||||
|
perform_handshake_with_peer(
|
||||||
|
peer_id_arc,
|
||||||
|
local_library,
|
||||||
|
peer_game_db.clone(),
|
||||||
|
tx_notify_ui.clone(),
|
||||||
|
peer_addr,
|
||||||
|
Some(peer_id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
Err(eyre::eyre!("Skipping hello for legacy peer"))
|
||||||
|
};
|
||||||
|
|
||||||
|
if handshake_result.is_err()
|
||||||
|
&& let Err(err) = request_games_from_peer(peer_addr, tx_notify_ui, peer_game_db).await
|
||||||
|
{
|
||||||
|
log::error!("Failed to request games from peer {peer_addr}: {err}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
//! Protocol handshakes and library synchronization between peers.
|
||||||
|
|
||||||
|
use std::{net::SocketAddr, sync::Arc};
|
||||||
|
|
||||||
|
use lanspread_proto::{Hello, HelloAck, LibraryDelta, LibrarySnapshot, PROTOCOL_VERSION};
|
||||||
|
use tokio::sync::{RwLock, mpsc::UnboundedSender};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
PeerEvent,
|
||||||
|
context::PeerCtx,
|
||||||
|
events,
|
||||||
|
identity::default_features,
|
||||||
|
library::{LocalLibraryState, build_library_snapshot, build_library_summary},
|
||||||
|
network::{exchange_hello, send_library_delta, send_library_snapshot, send_library_summary},
|
||||||
|
peer_db::{PeerGameDB, PeerId, PeerUpsert},
|
||||||
|
};
|
||||||
|
|
||||||
|
enum LibraryUpdate {
|
||||||
|
Delta(LibraryDelta),
|
||||||
|
Snapshot(LibrarySnapshot),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn build_hello_ack(ctx: &PeerCtx) -> HelloAck {
|
||||||
|
let library_guard = ctx.local_library.read().await;
|
||||||
|
HelloAck {
|
||||||
|
peer_id: ctx.peer_id.as_ref().clone(),
|
||||||
|
proto_ver: PROTOCOL_VERSION,
|
||||||
|
library_rev: library_guard.revision,
|
||||||
|
library_digest: library_guard.digest,
|
||||||
|
features: default_features(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn build_hello_from_state(
|
||||||
|
peer_id: &str,
|
||||||
|
local_library: &Arc<RwLock<LocalLibraryState>>,
|
||||||
|
) -> Hello {
|
||||||
|
let library_guard = local_library.read().await;
|
||||||
|
Hello {
|
||||||
|
peer_id: peer_id.to_string(),
|
||||||
|
proto_ver: PROTOCOL_VERSION,
|
||||||
|
library_rev: library_guard.revision,
|
||||||
|
library_digest: library_guard.digest,
|
||||||
|
features: default_features(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn perform_handshake_with_peer(
|
||||||
|
peer_id: Arc<String>,
|
||||||
|
local_library: Arc<RwLock<LocalLibraryState>>,
|
||||||
|
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
||||||
|
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
peer_id_hint: Option<PeerId>,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let hello = build_hello_from_state(peer_id.as_ref(), &local_library).await;
|
||||||
|
let ack = exchange_hello(peer_addr, hello).await?;
|
||||||
|
|
||||||
|
if ack.proto_ver != PROTOCOL_VERSION {
|
||||||
|
log::warn!(
|
||||||
|
"Peer {peer_addr} uses incompatible protocol {} (expected {PROTOCOL_VERSION})",
|
||||||
|
ack.proto_ver
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ack.peer_id == *peer_id {
|
||||||
|
log::trace!("Ignoring handshake with self for {peer_addr}");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(expected) = peer_id_hint.as_ref()
|
||||||
|
&& expected != &ack.peer_id
|
||||||
|
{
|
||||||
|
log::warn!(
|
||||||
|
"Peer {peer_addr} id mismatch: mDNS advertised {expected}, hello ack returned {}",
|
||||||
|
ack.peer_id
|
||||||
|
);
|
||||||
|
let _ = peer_game_db.write().await.remove_peer(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
let upsert = record_remote_library(
|
||||||
|
&peer_game_db,
|
||||||
|
ack.peer_id.clone(),
|
||||||
|
peer_addr,
|
||||||
|
ack.library_rev,
|
||||||
|
ack.library_digest,
|
||||||
|
ack.features.clone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
after_peer_library_recorded(
|
||||||
|
upsert,
|
||||||
|
peer_addr,
|
||||||
|
ack.library_rev,
|
||||||
|
ack.library_digest,
|
||||||
|
&local_library,
|
||||||
|
&peer_game_db,
|
||||||
|
&tx_notify_ui,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn accept_inbound_hello(
|
||||||
|
ctx: &PeerCtx,
|
||||||
|
remote_addr: Option<SocketAddr>,
|
||||||
|
hello: Hello,
|
||||||
|
) -> HelloAck {
|
||||||
|
if hello.peer_id == *ctx.peer_id {
|
||||||
|
log::trace!("Ignoring hello from self");
|
||||||
|
return build_hello_ack(ctx).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if hello.proto_ver != PROTOCOL_VERSION {
|
||||||
|
log::warn!(
|
||||||
|
"Incompatible protocol from {remote_addr:?}: {}",
|
||||||
|
hello.proto_ver
|
||||||
|
);
|
||||||
|
return build_hello_ack(ctx).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(addr) = remote_addr {
|
||||||
|
let upsert = record_remote_library(
|
||||||
|
&ctx.peer_game_db,
|
||||||
|
hello.peer_id.clone(),
|
||||||
|
addr,
|
||||||
|
hello.library_rev,
|
||||||
|
hello.library_digest,
|
||||||
|
hello.features.clone(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
after_peer_library_recorded(
|
||||||
|
upsert,
|
||||||
|
addr,
|
||||||
|
hello.library_rev,
|
||||||
|
hello.library_digest,
|
||||||
|
&ctx.local_library,
|
||||||
|
&ctx.peer_game_db,
|
||||||
|
&ctx.tx_notify_ui,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
build_hello_ack(ctx).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn spawn_library_resync(
|
||||||
|
peer_id: Arc<String>,
|
||||||
|
local_library: Arc<RwLock<LocalLibraryState>>,
|
||||||
|
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
||||||
|
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
peer_id_hint: PeerId,
|
||||||
|
reason: &'static str,
|
||||||
|
) {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(err) = perform_handshake_with_peer(
|
||||||
|
peer_id,
|
||||||
|
local_library,
|
||||||
|
peer_game_db,
|
||||||
|
tx_notify_ui,
|
||||||
|
peer_addr,
|
||||||
|
Some(peer_id_hint),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log::warn!("Failed to {reason} library from {peer_addr}: {err}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn record_remote_library(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
peer_id: PeerId,
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
library_rev: u64,
|
||||||
|
library_digest: u64,
|
||||||
|
features: Vec<String>,
|
||||||
|
) -> PeerUpsert {
|
||||||
|
let mut db = peer_game_db.write().await;
|
||||||
|
let upsert = db.upsert_peer(peer_id.clone(), peer_addr);
|
||||||
|
db.update_peer_library(&peer_id, library_rev, library_digest, features);
|
||||||
|
upsert
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn after_peer_library_recorded(
|
||||||
|
upsert: PeerUpsert,
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
remote_library_rev: u64,
|
||||||
|
remote_library_digest: u64,
|
||||||
|
local_library: &Arc<RwLock<LocalLibraryState>>,
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
) {
|
||||||
|
if upsert.is_new {
|
||||||
|
events::emit_peer_discovered(peer_game_db, tx_notify_ui, peer_addr).await;
|
||||||
|
send_local_library_summary(peer_addr, local_library).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_local_library_update_if_needed(
|
||||||
|
peer_addr,
|
||||||
|
local_library,
|
||||||
|
remote_library_rev,
|
||||||
|
remote_library_digest,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_local_library_summary(
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
local_library: &Arc<RwLock<LocalLibraryState>>,
|
||||||
|
) {
|
||||||
|
let summary = {
|
||||||
|
let library_guard = local_library.read().await;
|
||||||
|
build_library_summary(&library_guard)
|
||||||
|
};
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(err) = send_library_summary(peer_addr, summary).await {
|
||||||
|
log::warn!("Failed to send library summary to {peer_addr}: {err}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_local_library_update_if_needed(
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
local_library: &Arc<RwLock<LocalLibraryState>>,
|
||||||
|
remote_rev: u64,
|
||||||
|
remote_digest: u64,
|
||||||
|
) {
|
||||||
|
if let Some(update) = select_library_update(local_library, remote_rev, remote_digest).await {
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let result = match update {
|
||||||
|
LibraryUpdate::Delta(delta) => send_library_delta(peer_addr, delta).await,
|
||||||
|
LibraryUpdate::Snapshot(snapshot) => {
|
||||||
|
send_library_snapshot(peer_addr, snapshot).await
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = result {
|
||||||
|
log::warn!("Failed to send library update to {peer_addr}: {err}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn select_library_update(
|
||||||
|
local_library: &Arc<RwLock<LocalLibraryState>>,
|
||||||
|
remote_rev: u64,
|
||||||
|
remote_digest: u64,
|
||||||
|
) -> Option<LibraryUpdate> {
|
||||||
|
let library_guard = local_library.read().await;
|
||||||
|
if library_guard.digest == remote_digest || remote_rev > library_guard.revision {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(delta) = library_guard.delta_since(remote_rev) {
|
||||||
|
return Some(LibraryUpdate::Delta(delta));
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(LibraryUpdate::Snapshot(build_library_snapshot(
|
||||||
|
&library_guard,
|
||||||
|
)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
//! Compatibility path for peers that only support the original game-list protocol.
|
||||||
|
|
||||||
|
use std::{net::SocketAddr, sync::Arc, time::Duration};
|
||||||
|
|
||||||
|
use tokio::sync::{RwLock, mpsc::UnboundedSender};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
PeerEvent,
|
||||||
|
events,
|
||||||
|
network::fetch_games_from_peer,
|
||||||
|
peer_db::PeerGameDB,
|
||||||
|
remote_peer::update_peer_from_game_list,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(super) async fn request_games_from_peer(
|
||||||
|
peer_addr: SocketAddr,
|
||||||
|
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||||
|
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let mut retry_count = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let games = fetch_games_from_peer(peer_addr).await?;
|
||||||
|
log::info!("Received {} games from peer {peer_addr}", games.len());
|
||||||
|
|
||||||
|
if games.is_empty() && retry_count < 1 {
|
||||||
|
log::info!("Received 0 games from peer {peer_addr}, scheduling retry in 5s");
|
||||||
|
tokio::time::sleep(Duration::from_secs(5)).await;
|
||||||
|
retry_count += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let aggregated_games = update_peer_from_game_list(&peer_game_db, peer_addr, &games).await;
|
||||||
|
events::send(
|
||||||
|
&tx_notify_ui,
|
||||||
|
PeerEvent::ListGames(aggregated_games),
|
||||||
|
"ListGames",
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
//! Peer liveness checks and stale-peer cleanup.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
sync::Arc,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
use tokio::{
|
||||||
|
sync::{RwLock, mpsc::UnboundedSender},
|
||||||
|
task::JoinHandle,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
PeerEvent,
|
||||||
|
config::{PEER_PING_IDLE_SECS, PEER_PING_INTERVAL_SECS, peer_stale_timeout},
|
||||||
|
events,
|
||||||
|
network::ping_peer,
|
||||||
|
peer_db::{PeerGameDB, PeerId},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Runs the ping service to check peer liveness.
|
||||||
|
pub async fn run_ping_service(
|
||||||
|
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||||
|
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
||||||
|
downloading_games: Arc<RwLock<HashSet<String>>>,
|
||||||
|
active_downloads: Arc<RwLock<HashMap<String, JoinHandle<()>>>>,
|
||||||
|
) {
|
||||||
|
log::info!(
|
||||||
|
"Starting ping service ({PEER_PING_INTERVAL_SECS}s interval, \
|
||||||
|
{}s idle threshold, {}s timeout)",
|
||||||
|
PEER_PING_IDLE_SECS,
|
||||||
|
peer_stale_timeout().as_secs()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(PEER_PING_INTERVAL_SECS));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
ping_idle_peers(
|
||||||
|
&peer_game_db,
|
||||||
|
&downloading_games,
|
||||||
|
&active_downloads,
|
||||||
|
&tx_notify_ui,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
prune_stale_peers(
|
||||||
|
&peer_game_db,
|
||||||
|
&downloading_games,
|
||||||
|
&active_downloads,
|
||||||
|
&tx_notify_ui,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn ping_idle_peers(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
downloading_games: &Arc<RwLock<HashSet<String>>>,
|
||||||
|
active_downloads: &Arc<RwLock<HashMap<String, JoinHandle<()>>>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
) {
|
||||||
|
let peer_snapshots = { peer_game_db.read().await.peer_liveness_snapshot() };
|
||||||
|
|
||||||
|
for (peer_id, peer_addr, last_seen) in peer_snapshots {
|
||||||
|
if last_seen.elapsed() < Duration::from_secs(PEER_PING_IDLE_SECS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tx_notify_ui = tx_notify_ui.clone();
|
||||||
|
let peer_game_db = peer_game_db.clone();
|
||||||
|
let downloading_games = downloading_games.clone();
|
||||||
|
let active_downloads = active_downloads.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
match ping_peer(peer_addr).await {
|
||||||
|
Ok(true) => {
|
||||||
|
peer_game_db.write().await.update_last_seen(&peer_id);
|
||||||
|
}
|
||||||
|
Ok(false) => {
|
||||||
|
log::warn!("Peer {peer_addr} failed ping check");
|
||||||
|
remove_peer_and_refresh(
|
||||||
|
&peer_game_db,
|
||||||
|
&downloading_games,
|
||||||
|
&active_downloads,
|
||||||
|
&tx_notify_ui,
|
||||||
|
peer_id,
|
||||||
|
"Removed stale peer",
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to ping peer {peer_addr}: {err}");
|
||||||
|
remove_peer_and_refresh(
|
||||||
|
&peer_game_db,
|
||||||
|
&downloading_games,
|
||||||
|
&active_downloads,
|
||||||
|
&tx_notify_ui,
|
||||||
|
peer_id,
|
||||||
|
"Removed peer due to ping error",
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn prune_stale_peers(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
downloading_games: &Arc<RwLock<HashSet<String>>>,
|
||||||
|
active_downloads: &Arc<RwLock<HashMap<String, JoinHandle<()>>>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
) {
|
||||||
|
let stale_peers = {
|
||||||
|
peer_game_db
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.get_stale_peer_ids(peer_stale_timeout())
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut removed_any = false;
|
||||||
|
for peer_id in stale_peers {
|
||||||
|
removed_any |= remove_peer(peer_game_db, tx_notify_ui, peer_id, "Removed stale peer").await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if removed_any {
|
||||||
|
events::emit_peer_game_list(peer_game_db, tx_notify_ui).await;
|
||||||
|
handle_active_downloads_without_peers(
|
||||||
|
peer_game_db,
|
||||||
|
downloading_games,
|
||||||
|
active_downloads,
|
||||||
|
tx_notify_ui,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_peer_and_refresh(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
downloading_games: &Arc<RwLock<HashSet<String>>>,
|
||||||
|
active_downloads: &Arc<RwLock<HashMap<String, JoinHandle<()>>>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
peer_id: PeerId,
|
||||||
|
log_label: &str,
|
||||||
|
) {
|
||||||
|
if remove_peer(peer_game_db, tx_notify_ui, peer_id, log_label).await {
|
||||||
|
events::emit_peer_game_list(peer_game_db, tx_notify_ui).await;
|
||||||
|
handle_active_downloads_without_peers(
|
||||||
|
peer_game_db,
|
||||||
|
downloading_games,
|
||||||
|
active_downloads,
|
||||||
|
tx_notify_ui,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn remove_peer(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
peer_id: PeerId,
|
||||||
|
log_label: &str,
|
||||||
|
) -> bool {
|
||||||
|
let removed_peer = { peer_game_db.write().await.remove_peer(&peer_id) };
|
||||||
|
let Some(peer) = removed_peer else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
log::info!("{log_label}: {}", peer.addr);
|
||||||
|
events::emit_peer_lost(peer_game_db, tx_notify_ui, peer.addr).await;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_active_downloads_without_peers(
|
||||||
|
peer_game_db: &Arc<RwLock<PeerGameDB>>,
|
||||||
|
downloading_games: &Arc<RwLock<HashSet<String>>>,
|
||||||
|
active_downloads: &Arc<RwLock<HashMap<String, JoinHandle<()>>>>,
|
||||||
|
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||||
|
) {
|
||||||
|
let active_ids = {
|
||||||
|
downloading_games
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
};
|
||||||
|
if active_ids.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in active_ids {
|
||||||
|
if peers_still_have_game(peer_game_db, &id).await {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let removed_from_tracking = {
|
||||||
|
let mut guard = downloading_games.write().await;
|
||||||
|
guard.remove(&id)
|
||||||
|
};
|
||||||
|
|
||||||
|
if !removed_from_tracking {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(handle) = { active_downloads.write().await.remove(&id) } {
|
||||||
|
handle.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
events::send(
|
||||||
|
tx_notify_ui,
|
||||||
|
PeerEvent::DownloadGameFilesAllPeersGone { id },
|
||||||
|
"DownloadGameFilesAllPeersGone",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn peers_still_have_game(peer_game_db: &Arc<RwLock<PeerGameDB>>, game_id: &str) -> bool {
|
||||||
|
let guard = peer_game_db.read().await;
|
||||||
|
!guard.peers_with_game(game_id).is_empty()
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//! Local game directory monitor.
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
PeerEvent,
|
||||||
|
config::LOCAL_GAME_MONITOR_INTERVAL_SECS,
|
||||||
|
context::Ctx,
|
||||||
|
handlers::update_and_announce_games,
|
||||||
|
local_games::scan_local_library,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Monitors the local game directory for changes.
|
||||||
|
pub async fn run_local_game_monitor(tx_notify_ui: UnboundedSender<PeerEvent>, ctx: Ctx) {
|
||||||
|
log::info!(
|
||||||
|
"Starting local game directory monitor ({LOCAL_GAME_MONITOR_INTERVAL_SECS}s interval)"
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut interval = tokio::time::interval(Duration::from_secs(LOCAL_GAME_MONITOR_INTERVAL_SECS));
|
||||||
|
|
||||||
|
loop {
|
||||||
|
interval.tick().await;
|
||||||
|
|
||||||
|
let game_dir = { ctx.game_dir.read().await.clone() };
|
||||||
|
if let Some(game_dir) = game_dir {
|
||||||
|
match scan_local_library(&game_dir).await {
|
||||||
|
Ok(scan) => {
|
||||||
|
update_and_announce_games(&ctx, &tx_notify_ui, scan).await;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to scan local games directory: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
//! QUIC server accept loop.
|
||||||
|
|
||||||
|
use std::{net::SocketAddr, time::Duration};
|
||||||
|
|
||||||
|
use s2n_quic::{Connection, Server, provider::limits::Limits};
|
||||||
|
use tokio::sync::mpsc::UnboundedSender;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
PeerEvent,
|
||||||
|
config::{CERT_PEM, KEY_PEM},
|
||||||
|
context::PeerCtx,
|
||||||
|
events,
|
||||||
|
services::{advertise::start_mdns_advertiser, stream::handle_peer_stream},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Runs the QUIC server and mDNS advertiser.
|
||||||
|
pub async fn run_server_component(
|
||||||
|
addr: SocketAddr,
|
||||||
|
ctx: PeerCtx,
|
||||||
|
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let limits = Limits::default()
|
||||||
|
.with_max_handshake_duration(Duration::from_secs(3))?
|
||||||
|
.with_max_idle_timeout(Duration::from_secs(3))?;
|
||||||
|
|
||||||
|
let mut server = Server::builder()
|
||||||
|
.with_tls((CERT_PEM, KEY_PEM))?
|
||||||
|
.with_io(addr)?
|
||||||
|
.with_limits(limits)?
|
||||||
|
.start()?;
|
||||||
|
|
||||||
|
let server_addr = server.local_addr()?;
|
||||||
|
log::info!("Peer server listening on {server_addr}");
|
||||||
|
|
||||||
|
start_mdns_advertiser(&ctx, server_addr).await?;
|
||||||
|
|
||||||
|
while let Some(connection) = server.accept().await {
|
||||||
|
let ctx = ctx.clone();
|
||||||
|
let tx_notify_ui = tx_notify_ui.clone();
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(err) = handle_peer_connection(connection, ctx, tx_notify_ui).await {
|
||||||
|
log::error!("Peer connection error: {err}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_peer_connection(
|
||||||
|
mut connection: Connection,
|
||||||
|
ctx: PeerCtx,
|
||||||
|
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let remote_addr = connection.remote_addr()?;
|
||||||
|
log::info!("{remote_addr} peer connected");
|
||||||
|
events::send(
|
||||||
|
&tx_notify_ui,
|
||||||
|
PeerEvent::PeerConnected(remote_addr),
|
||||||
|
"PeerConnected",
|
||||||
|
);
|
||||||
|
|
||||||
|
while let Ok(Some(stream)) = connection.accept_bidirectional_stream().await {
|
||||||
|
let ctx = ctx.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(err) = handle_peer_stream(stream, ctx, Some(remote_addr)).await {
|
||||||
|
log::error!("{remote_addr:?} peer stream error: {err}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
events::send(
|
||||||
|
&tx_notify_ui,
|
||||||
|
PeerEvent::PeerDisconnected(remote_addr),
|
||||||
|
"PeerDisconnected",
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -0,0 +1,397 @@
|
|||||||
|
//! Request dispatch for a single bidirectional QUIC stream.
|
||||||
|
|
||||||
|
use std::{net::SocketAddr, path::PathBuf};
|
||||||
|
|
||||||
|
use futures::{SinkExt, StreamExt};
|
||||||
|
use lanspread_db::db::{Game, GameFileDescription};
|
||||||
|
use lanspread_proto::{LibraryDelta, LibrarySnapshot, LibrarySummary, Message, Request, Response};
|
||||||
|
use s2n_quic::stream::{BidirectionalStream, SendStream};
|
||||||
|
use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
PeerEvent,
|
||||||
|
context::PeerCtx,
|
||||||
|
error::PeerError,
|
||||||
|
events,
|
||||||
|
local_games::get_game_file_descriptions,
|
||||||
|
peer::{send_game_file_chunk, send_game_file_data},
|
||||||
|
remote_peer::{ensure_peer_id_for_addr, update_peer_from_game_list},
|
||||||
|
services::handshake::{
|
||||||
|
accept_inbound_hello,
|
||||||
|
perform_handshake_with_peer,
|
||||||
|
spawn_library_resync,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type ResponseWriter = FramedWrite<SendStream, LengthDelimitedCodec>;
|
||||||
|
|
||||||
|
/// Handles a bidirectional stream from a peer.
|
||||||
|
pub(super) async fn handle_peer_stream(
|
||||||
|
stream: BidirectionalStream,
|
||||||
|
ctx: PeerCtx,
|
||||||
|
remote_addr: Option<SocketAddr>,
|
||||||
|
) -> eyre::Result<()> {
|
||||||
|
let (rx, tx) = stream.split();
|
||||||
|
let mut framed_rx = FramedRead::new(rx, LengthDelimitedCodec::new());
|
||||||
|
let mut framed_tx = FramedWrite::new(tx, LengthDelimitedCodec::new());
|
||||||
|
|
||||||
|
log::trace!("{remote_addr:?} peer stream opened");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match framed_rx.next().await {
|
||||||
|
Some(Ok(data)) => {
|
||||||
|
log::trace!(
|
||||||
|
"{:?} msg: (raw): {}",
|
||||||
|
remote_addr,
|
||||||
|
String::from_utf8_lossy(&data)
|
||||||
|
);
|
||||||
|
|
||||||
|
let request = Request::decode(data.freeze());
|
||||||
|
log::debug!("{remote_addr:?} msg: {request:?}");
|
||||||
|
note_peer_activity(&ctx, remote_addr).await;
|
||||||
|
framed_tx = dispatch_request(&ctx, remote_addr, request, framed_tx).await;
|
||||||
|
}
|
||||||
|
Some(Err(err)) => {
|
||||||
|
log::error!("{remote_addr:?} peer stream error: {err}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
log::trace!("{remote_addr:?} peer stream closed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn dispatch_request(
|
||||||
|
ctx: &PeerCtx,
|
||||||
|
remote_addr: Option<SocketAddr>,
|
||||||
|
request: Request,
|
||||||
|
framed_tx: ResponseWriter,
|
||||||
|
) -> ResponseWriter {
|
||||||
|
match request {
|
||||||
|
Request::Ping => send_response(framed_tx, Response::Pong, "pong").await,
|
||||||
|
Request::Hello(hello) => {
|
||||||
|
let ack = accept_inbound_hello(ctx, remote_addr, hello).await;
|
||||||
|
send_response(framed_tx, Response::HelloAck(ack), "HelloAck").await
|
||||||
|
}
|
||||||
|
Request::ListGames => handle_list_games(ctx, framed_tx).await,
|
||||||
|
Request::LibrarySummary(summary) => {
|
||||||
|
handle_library_summary(ctx, remote_addr, summary).await;
|
||||||
|
framed_tx
|
||||||
|
}
|
||||||
|
Request::LibrarySnapshot(snapshot) => {
|
||||||
|
handle_library_snapshot(ctx, remote_addr, snapshot).await;
|
||||||
|
framed_tx
|
||||||
|
}
|
||||||
|
Request::LibraryDelta(delta) => {
|
||||||
|
handle_library_delta(ctx, remote_addr, delta).await;
|
||||||
|
framed_tx
|
||||||
|
}
|
||||||
|
Request::GetGame { id } => handle_get_game(ctx, id, framed_tx).await,
|
||||||
|
Request::GetGameFileData(desc) => handle_file_data_request(ctx, desc, framed_tx).await,
|
||||||
|
Request::GetGameFileChunk {
|
||||||
|
game_id,
|
||||||
|
relative_path,
|
||||||
|
offset,
|
||||||
|
length,
|
||||||
|
} => {
|
||||||
|
handle_file_chunk_request(ctx, game_id, relative_path, offset, length, framed_tx).await
|
||||||
|
}
|
||||||
|
Request::Goodbye { peer_id } => {
|
||||||
|
handle_goodbye(ctx, remote_addr, peer_id).await;
|
||||||
|
framed_tx
|
||||||
|
}
|
||||||
|
Request::Invalid(_, _) => {
|
||||||
|
log::error!("Received invalid request from peer");
|
||||||
|
framed_tx
|
||||||
|
}
|
||||||
|
Request::AnnounceGames(games) => {
|
||||||
|
handle_announce_games(ctx, remote_addr, games).await;
|
||||||
|
framed_tx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn note_peer_activity(ctx: &PeerCtx, remote_addr: Option<SocketAddr>) {
|
||||||
|
if let Some(addr) = remote_addr {
|
||||||
|
ctx.peer_game_db
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.update_last_seen_by_addr(&addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_response(
|
||||||
|
mut framed_tx: ResponseWriter,
|
||||||
|
response: Response,
|
||||||
|
label: &str,
|
||||||
|
) -> ResponseWriter {
|
||||||
|
if let Err(err) = framed_tx.send(response.encode()).await {
|
||||||
|
log::error!("Failed to send {label} response: {err}");
|
||||||
|
}
|
||||||
|
framed_tx
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_list_games(ctx: &PeerCtx, framed_tx: ResponseWriter) -> ResponseWriter {
|
||||||
|
log::info!("Received ListGames request from peer");
|
||||||
|
let snapshot = {
|
||||||
|
let db_guard = ctx.local_game_db.read().await;
|
||||||
|
if let Some(db) = db_guard.as_ref() {
|
||||||
|
db.all_games().into_iter().cloned().collect::<Vec<Game>>()
|
||||||
|
} else {
|
||||||
|
log::info!("Local game database not yet loaded, responding with empty game list");
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let games = if snapshot.is_empty() {
|
||||||
|
snapshot
|
||||||
|
} else {
|
||||||
|
let downloading = ctx.downloading_games.read().await;
|
||||||
|
snapshot
|
||||||
|
.into_iter()
|
||||||
|
.filter(|game| !downloading.contains(&game.id))
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
send_response(framed_tx, Response::ListGames(games), "ListGames").await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_library_summary(
|
||||||
|
ctx: &PeerCtx,
|
||||||
|
remote_addr: Option<SocketAddr>,
|
||||||
|
summary: LibrarySummary,
|
||||||
|
) {
|
||||||
|
let Some(addr) = remote_addr else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let peer_id = ensure_peer_id_for_addr(&ctx.peer_game_db, addr).await;
|
||||||
|
let (previous_digest, previous_count, features) = {
|
||||||
|
let db = ctx.peer_game_db.read().await;
|
||||||
|
let (_, digest) = db.peer_library_state(&peer_id).unwrap_or((0, 0));
|
||||||
|
(
|
||||||
|
digest,
|
||||||
|
db.peer_game_count(&peer_id),
|
||||||
|
db.peer_features(&peer_id),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut db = ctx.peer_game_db.write().await;
|
||||||
|
db.update_peer_library(
|
||||||
|
&peer_id,
|
||||||
|
summary.library_rev,
|
||||||
|
summary.library_digest,
|
||||||
|
features,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if summary.library_digest != previous_digest || previous_count == 0 {
|
||||||
|
tokio::spawn({
|
||||||
|
let peer_id_arc = ctx.peer_id.clone();
|
||||||
|
let local_library = ctx.local_library.clone();
|
||||||
|
let peer_game_db = ctx.peer_game_db.clone();
|
||||||
|
let tx_notify_ui = ctx.tx_notify_ui.clone();
|
||||||
|
async move {
|
||||||
|
if let Err(err) = perform_handshake_with_peer(
|
||||||
|
peer_id_arc,
|
||||||
|
local_library,
|
||||||
|
peer_game_db,
|
||||||
|
tx_notify_ui,
|
||||||
|
addr,
|
||||||
|
Some(peer_id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
log::warn!("Failed to refresh library from {addr}: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_library_snapshot(
|
||||||
|
ctx: &PeerCtx,
|
||||||
|
remote_addr: Option<SocketAddr>,
|
||||||
|
snapshot: LibrarySnapshot,
|
||||||
|
) {
|
||||||
|
if let Some(addr) = remote_addr {
|
||||||
|
let peer_id = ensure_peer_id_for_addr(&ctx.peer_game_db, addr).await;
|
||||||
|
{
|
||||||
|
let mut db = ctx.peer_game_db.write().await;
|
||||||
|
db.apply_library_snapshot(&peer_id, snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
events::emit_peer_game_list(&ctx.peer_game_db, &ctx.tx_notify_ui).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_library_delta(ctx: &PeerCtx, remote_addr: Option<SocketAddr>, delta: LibraryDelta) {
|
||||||
|
let Some(addr) = remote_addr else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let peer_id = ensure_peer_id_for_addr(&ctx.peer_game_db, addr).await;
|
||||||
|
let applied = {
|
||||||
|
let mut db = ctx.peer_game_db.write().await;
|
||||||
|
db.apply_library_delta(&peer_id, delta)
|
||||||
|
};
|
||||||
|
|
||||||
|
if applied {
|
||||||
|
events::emit_peer_game_list(&ctx.peer_game_db, &ctx.tx_notify_ui).await;
|
||||||
|
} else {
|
||||||
|
spawn_library_resync(
|
||||||
|
ctx.peer_id.clone(),
|
||||||
|
ctx.local_library.clone(),
|
||||||
|
ctx.peer_game_db.clone(),
|
||||||
|
ctx.tx_notify_ui.clone(),
|
||||||
|
addr,
|
||||||
|
peer_id,
|
||||||
|
"resync",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_get_game(ctx: &PeerCtx, id: String, framed_tx: ResponseWriter) -> ResponseWriter {
|
||||||
|
log::info!("Received GetGame request for {id} from peer");
|
||||||
|
let response = get_game_response(ctx, id).await;
|
||||||
|
send_response(framed_tx, response, "GetGame").await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_game_response(ctx: &PeerCtx, id: String) -> Response {
|
||||||
|
let downloading = ctx.downloading_games.read().await.contains(&id);
|
||||||
|
if downloading {
|
||||||
|
log::info!("Declining to serve GetGame for {id} because download is in progress");
|
||||||
|
return Response::GameNotFound(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(game_dir) = ctx.game_dir.read().await.clone() else {
|
||||||
|
return Response::GameNotFound(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
let has_game = {
|
||||||
|
let db_guard = ctx.local_game_db.read().await;
|
||||||
|
db_guard
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|db| db.get_game_by_id(&id).is_some())
|
||||||
|
};
|
||||||
|
|
||||||
|
if !has_game {
|
||||||
|
return Response::GameNotFound(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
match get_game_file_descriptions(&id, &game_dir).await {
|
||||||
|
Ok(file_descriptions) => Response::GetGame {
|
||||||
|
id,
|
||||||
|
file_descriptions,
|
||||||
|
},
|
||||||
|
Err(PeerError::FileSizeDetermination { path, source }) => {
|
||||||
|
let error_msg = format!("Failed to determine file size for {path}: {source}");
|
||||||
|
log::error!("File size determination error for game {id}: {error_msg}");
|
||||||
|
Response::InternalPeerError(error_msg)
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to get game file descriptions for {id}: {err}");
|
||||||
|
Response::GameNotFound(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_file_data_request(
|
||||||
|
ctx: &PeerCtx,
|
||||||
|
desc: GameFileDescription,
|
||||||
|
framed_tx: ResponseWriter,
|
||||||
|
) -> ResponseWriter {
|
||||||
|
log::info!(
|
||||||
|
"Received GetGameFileData request for {} from peer",
|
||||||
|
desc.relative_path
|
||||||
|
);
|
||||||
|
|
||||||
|
let Some(game_dir) = ctx.game_dir.read().await.clone() else {
|
||||||
|
return send_invalid_request(
|
||||||
|
framed_tx,
|
||||||
|
desc.relative_path.as_bytes().to_vec(),
|
||||||
|
"Game directory not set",
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
};
|
||||||
|
|
||||||
|
let base_dir = PathBuf::from(game_dir);
|
||||||
|
let mut tx = framed_tx.into_inner();
|
||||||
|
send_game_file_data(&desc, &mut tx, &base_dir).await;
|
||||||
|
FramedWrite::new(tx, LengthDelimitedCodec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_file_chunk_request(
|
||||||
|
ctx: &PeerCtx,
|
||||||
|
game_id: String,
|
||||||
|
relative_path: String,
|
||||||
|
offset: u64,
|
||||||
|
length: u64,
|
||||||
|
framed_tx: ResponseWriter,
|
||||||
|
) -> ResponseWriter {
|
||||||
|
log::info!(
|
||||||
|
"Received GetGameFileChunk request for {relative_path} (offset {offset}, length {length})"
|
||||||
|
);
|
||||||
|
|
||||||
|
let Some(game_dir) = ctx.game_dir.read().await.clone() else {
|
||||||
|
return send_invalid_request(
|
||||||
|
framed_tx,
|
||||||
|
relative_path.as_bytes().to_vec(),
|
||||||
|
"Game directory not set",
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
};
|
||||||
|
|
||||||
|
let base_dir = PathBuf::from(game_dir);
|
||||||
|
let mut tx = framed_tx.into_inner();
|
||||||
|
send_game_file_chunk(&game_id, &relative_path, offset, length, &mut tx, &base_dir).await;
|
||||||
|
FramedWrite::new(tx, LengthDelimitedCodec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_invalid_request(
|
||||||
|
framed_tx: ResponseWriter,
|
||||||
|
raw_request: Vec<u8>,
|
||||||
|
message: &str,
|
||||||
|
) -> ResponseWriter {
|
||||||
|
send_response(
|
||||||
|
framed_tx,
|
||||||
|
Response::InvalidRequest(raw_request.into(), message.to_string()),
|
||||||
|
"InvalidRequest",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_goodbye(ctx: &PeerCtx, remote_addr: Option<SocketAddr>, peer_id: String) {
|
||||||
|
log::info!("Received Goodbye from peer {peer_id}");
|
||||||
|
let removed = { ctx.peer_game_db.write().await.remove_peer(&peer_id) };
|
||||||
|
if removed.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(addr) = remote_addr {
|
||||||
|
events::emit_peer_lost(&ctx.peer_game_db, &ctx.tx_notify_ui, addr).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
events::emit_peer_game_list(&ctx.peer_game_db, &ctx.tx_notify_ui).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_announce_games(ctx: &PeerCtx, remote_addr: Option<SocketAddr>, games: Vec<Game>) {
|
||||||
|
log::info!(
|
||||||
|
"Received {} announced games from peer {remote_addr:?}",
|
||||||
|
games.len()
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(addr) = remote_addr {
|
||||||
|
let aggregated_games = update_peer_from_game_list(&ctx.peer_game_db, addr, &games).await;
|
||||||
|
events::send(
|
||||||
|
&ctx.tx_notify_ui,
|
||||||
|
PeerEvent::ListGames(aggregated_games),
|
||||||
|
"ListGames",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,3 +20,7 @@ bytes = { workspace = true }
|
|||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
test = false
|
||||||
|
doctest = false
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ edition = "2024"
|
|||||||
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
||||||
name = "lanspread_tauri_deno_ts_lib"
|
name = "lanspread_tauri_deno_ts_lib"
|
||||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
test = false
|
||||||
|
doctest = false
|
||||||
|
|
||||||
[lints.clippy]
|
[lints.clippy]
|
||||||
pedantic = { level = "warn", priority = -1 }
|
pedantic = { level = "warn", priority = -1 }
|
||||||
@@ -27,7 +29,6 @@ tauri-build = { version = "2", features = [] }
|
|||||||
# local
|
# local
|
||||||
lanspread-peer = { path = "../../lanspread-peer" }
|
lanspread-peer = { path = "../../lanspread-peer" }
|
||||||
lanspread-db = { path = "../../lanspread-db" }
|
lanspread-db = { path = "../../lanspread-db" }
|
||||||
lanspread-mdns = { path = "../../lanspread-mdns" }
|
|
||||||
lanspread-compat = { path = "../../lanspread-compat" }
|
lanspread-compat = { path = "../../lanspread-compat" }
|
||||||
|
|
||||||
# external
|
# external
|
||||||
@@ -35,8 +36,6 @@ base64 = { workspace = true }
|
|||||||
eyre = { workspace = true }
|
eyre = { workspace = true }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
mimalloc = { workspace = true }
|
mimalloc = { workspace = true }
|
||||||
serde = { workspace = true }
|
|
||||||
serde_json = { workspace = true }
|
|
||||||
tauri = { workspace = true }
|
tauri = { workspace = true }
|
||||||
tauri-plugin-log = { workspace = true }
|
tauri-plugin-log = { workspace = true }
|
||||||
tauri-plugin-shell = { workspace = true }
|
tauri-plugin-shell = { workspace = true }
|
||||||
|
|||||||
@@ -895,7 +895,7 @@ pub fn run() {
|
|||||||
log::info!("Peer system initialized successfully with games directory");
|
log::info!("Peer system initialized successfully with games directory");
|
||||||
|
|
||||||
// Wait a moment for local game database to be loaded before starting discovery
|
// Wait a moment for local game database to be loaded before starting discovery
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(2000)).await;
|
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
|
||||||
|
|
||||||
// Start peer discovery and request games from other peers
|
// Start peer discovery and request games from other peers
|
||||||
if let Err(e) = request_games(state).await {
|
if let Err(e) = request_games(state).await {
|
||||||
|
|||||||
@@ -11,4 +11,6 @@ pedantic = { level = "warn", priority = -1 }
|
|||||||
todo = "warn"
|
todo = "warn"
|
||||||
unwrap_used = "warn"
|
unwrap_used = "warn"
|
||||||
|
|
||||||
[dependencies]
|
[lib]
|
||||||
|
test = false
|
||||||
|
doctest = false
|
||||||
|
|||||||
Reference in New Issue
Block a user