From 3c7e91c28c433250fb8e425abbe9bcfaf569f6ab Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:14:19 +0900 Subject: [PATCH 1/5] workspace deps sorting --- Cargo.toml | 6 ++++++ dash-frontend/Cargo.toml | 25 +++++++++++++++---------- uidev/Cargo.toml | 19 ++++++++++--------- uidev/src/testbed/testbed_generic.rs | 1 + wayvr-ipc/Cargo.toml | 10 +++++----- wayvr/Cargo.toml | 22 +++++++++++----------- wayvrctl/Cargo.toml | 8 +++++--- wlx-capture/Cargo.toml | 2 +- wlx-common/Cargo.toml | 17 ++++++++++------- 9 files changed, 64 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bfd05042..4214b9c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,11 +15,14 @@ members = [ [workspace.dependencies] anyhow = "1.0.100" bytes = { version = "1.11.1" } +chrono = "0.4.42" clap = { version = "4.5.53", features = ["derive"] } dbus = { version = "0.9.12" } glam = { version = "0.30.9", features = ["mint", "serde"] } idmap = "0.2.2" idmap-derive = "0.2.22" +interprocess = { version = "2.2.3" } +libc = "0.2.178" log = "0.4.29" pipewire = { version = "0.10", features = ["v0_3_33", "v0_3_65"] } regex = "1.12.2" @@ -31,6 +34,8 @@ slotmap = "1.1.1" smallvec = "1.15.2" smol = "2.0.2" strum = { version = "0.27.2", features = ["derive"] } +tokio = "1.48.0" # TODO: switch to smol for ipc +tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } uuid = { version = "1.19.0", features = ["fast-rng", "serde", "v4"] } vulkano = { version = "0.35.2", @@ -43,6 +48,7 @@ vulkano-shaders = "0.35.0" wayland-client = { version = "0.31" } wayland-protocols = { version = "0.32" } wayland-protocols-misc = { version = "0.3.12" } +winit = "0.30.12" xdg = "3.0.0" [patch.crates-io] diff --git a/dash-frontend/Cargo.toml b/dash-frontend/Cargo.toml index 6b72aebc..2f5206c3 100644 --- a/dash-frontend/Cargo.toml +++ b/dash-frontend/Cargo.toml @@ -8,27 +8,32 @@ authors = ["galister", "oo8dev"] repository = "https://github.com/wlx-team/wayvr" [dependencies] +wayvr-ipc = { path = "../wayvr-ipc", default-features = false } +wgui = { path = "../wgui/" } +wlx-common = { path = "../wlx-common" } + anyhow.workspace = true -async-native-tls = "0.5.0" -chrono = "0.4.42" +chrono.workspace = true glam = { workspace = true, features = ["mint", "serde"] } -http-body-util = "0.1.3" -hyper = { version = "1.8.1", features = ["client", "http1", "http2"] } -keyvalues-parser = { git = "https://codeberg.org/CosmicHarper/vdf-rs.git", rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" } log.workspace = true -lz4_flex = { version = "0.13.1", features = ["frame"] } rust-embed.workspace = true serde = { workspace = true, features = ["rc"] } serde_json.workspace = true smol = { workspace = true } -smol-hyper = "0.1.1" strum.workspace = true uuid.workspace = true -wayvr-ipc = { path = "../wayvr-ipc", default-features = false } -wgui = { path = "../wgui/" } -wlx-common = { path = "../wlx-common" } xdg.workspace = true +async-native-tls = "0.5.0" +http-body-util = "0.1.3" +hyper = { version = "1.8.1", features = ["client", "http1", "http2"] } +keyvalues-parser = { + git = "https://codeberg.org/CosmicHarper/vdf-rs.git", + rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" +} +lz4_flex = { version = "0.13.1", features = ["frame"] } +smol-hyper = "0.1.1" + [features] default = ["monado"] monado = [] diff --git a/uidev/Cargo.toml b/uidev/Cargo.toml index 3c658de4..6c5f059d 100644 --- a/uidev/Cargo.toml +++ b/uidev/Cargo.toml @@ -8,14 +8,15 @@ authors = ["galister", "oo8dev"] repository = "https://github.com/wlx-team/wayvr" [dependencies] -anyhow = { workspace = true } -glam = { workspace = true } -log = { workspace = true } -rust-embed = "8.9.0" -tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } -wgui = { path = "../wgui/" } -winit = "0.30.12" -vulkano = { workspace = true } -vulkano-shaders = { workspace = true } dash-frontend = { path = "../dash-frontend/" } +wgui = { path = "../wgui/" } wlx-common = { path = "../wlx-common" } + +anyhow.workspace = true +glam.workspace = true +log.workspace = true +rust-embed.workspace = true +tracing-subscriber.workspace = true +vulkano.workspace = true +vulkano-shaders.workspace = true +winit.workspace = true diff --git a/uidev/src/testbed/testbed_generic.rs b/uidev/src/testbed/testbed_generic.rs index e64baf79..ceba38ed 100644 --- a/uidev/src/testbed/testbed_generic.rs +++ b/uidev/src/testbed/testbed_generic.rs @@ -119,6 +119,7 @@ impl TestbedGeneric { rect.params.color = color; })), dev_mode: false, + ..Default::default() }; let (layout, parser_state) = wgui::parser::new_layout_from_assets( diff --git a/wayvr-ipc/Cargo.toml b/wayvr-ipc/Cargo.toml index bc3fee03..2efa2896 100644 --- a/wayvr-ipc/Cargo.toml +++ b/wayvr-ipc/Cargo.toml @@ -8,16 +8,16 @@ authors = ["galister", "oo8dev"] repository = "https://github.com/wlx-team/wayvr" [dependencies] -anyhow = "1.0.93" +anyhow.workspace = true bytes.workspace = true -log = "0.4.22" +log.workspace = true serde.workspace = true -smallvec = "1.13.2" +smallvec.workspace = true # client-only deps -interprocess = { version = "2.2.2", features = ["tokio"], optional = true } +interprocess = { workspace = true, features = ["tokio"], optional = true } serde_json.workspace = true -tokio = { version = "1.43.1", features = ["macros"], optional = true } +tokio = { workspace = true, features = ["macros"], optional = true } tokio-util = { version = "0.7.13", optional = true } [features] diff --git a/wayvr/Cargo.toml b/wayvr/Cargo.toml index e734b8e1..78fb5da9 100644 --- a/wayvr/Cargo.toml +++ b/wayvr/Cargo.toml @@ -27,11 +27,14 @@ wlx-capture = { path = "../wlx-capture" } wlx-common = { path = "../wlx-common" } anyhow.workspace = true +chrono = { workspace = true, features = ["unstable-locales"] } clap.workspace = true dbus.workspace = true glam = { workspace = true, features = ["mint", "serde"] } idmap = { workspace = true, features = ["serde"] } idmap-derive.workspace = true +interprocess.workspace = true +libc.workspace = true log.workspace = true pipewire = { workspace = true, optional = true } regex.workspace = true @@ -40,14 +43,21 @@ serde = { workspace = true, features = ["rc"] } serde_json.workspace = true serde_json5.workspace = true slotmap.workspace = true +smallvec.workspace = true +smol = { workspace = true } strum.workspace = true +tracing-subscriber.workspace = true +uuid = { workspace = true } vulkano.workspace = true vulkano-shaders.workspace = true +wayland-client = { workspace = true } +wayland-protocols = { workspace = true } +wayland-protocols-misc = { workspace = true } +winit = { workspace = true, optional = true } xdg.workspace = true ash = "^0.38.0" # must match vulkano bytes = { workspace = true } -chrono = { version = "0.4.42", features = ["unstable-locales"] } chrono-tz = "0.10.4" config = "0.15.19" futures = "0.3.31" @@ -59,10 +69,8 @@ image_dds = { ] } input-linux = "0.7.1" -interprocess = { version = "2.2.3" } json = { version = "0.12.4", optional = true } json5 = "1.3.0" -libc = "0.2.178" libmonado = { git = "https://github.com/wayvr-org/libmonado-rs.git", rev = "6f66b26930c24a8a2fc57ddcd85704784894c750", @@ -85,7 +93,6 @@ pure-rust-locales = "0.8.2" rosc = { version = "0.11.4", optional = true } serde_yaml = "0.9.34" signal-hook = "0.3.18" -smallvec = "1.15.1" smithay = { version = "0.7.0", default-features = false, @@ -97,17 +104,10 @@ smithay = { ] } smithay-clipboard = "0.7.3" -smol = { workspace = true } sysinfo = { version = "0.37" } thiserror = "2.0" tracing = "0.1.43" -tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } -uuid = { workspace = true } -wayland-client = { workspace = true } -wayland-protocols = { workspace = true } -wayland-protocols-misc = { workspace = true } whisper-rs = { version = "0.16.0", features = ["vulkan"], optional = true } -winit = { version = "0.30.12", optional = true } xcb = { version = "1.6.0", features = [ diff --git a/wayvrctl/Cargo.toml b/wayvrctl/Cargo.toml index 1ac441e4..87b97a5d 100644 --- a/wayvrctl/Cargo.toml +++ b/wayvrctl/Cargo.toml @@ -8,12 +8,14 @@ authors = ["galister", "oo8dev"] repository = "https://github.com/wlx-team/wayvr" [dependencies] +wayvr-ipc = { path = "../wayvr-ipc" } + anyhow.workspace = true -log.workspace = true clap.workspace = true +log.workspace = true serde.workspace = true serde_json.workspace = true +tokio.workspace = true + env_logger = "0.11.8" -tokio = "1.48.0" -wayvr-ipc = { path = "../wayvr-ipc" } shell-words = "1.1.1" diff --git a/wlx-capture/Cargo.toml b/wlx-capture/Cargo.toml index da9a0411..899d7bb4 100644 --- a/wlx-capture/Cargo.toml +++ b/wlx-capture/Cargo.toml @@ -13,6 +13,7 @@ license = "GPL-3.0-only" [dependencies] dbus = { workspace = true, features = ["futures"], optional = true } idmap = { workspace = true } +libc.workspace = true log = { workspace = true } pipewire = { workspace = true, optional = true } slotmap.workspace = true @@ -29,7 +30,6 @@ wayland-protocols = { } drm-fourcc = "2.2.0" -libc = "0.2.178" rxscreen = { version = "0.1.7", features = [ diff --git a/wlx-common/Cargo.toml b/wlx-common/Cargo.toml index da4f3665..920cf779 100644 --- a/wlx-common/Cargo.toml +++ b/wlx-common/Cargo.toml @@ -7,11 +7,11 @@ license = "GPL-3.0-only" authors = ["galister", "oo8dev"] repository = "https://github.com/wlx-team/wayvr" - [dependencies] wayvr-ipc = { path = "../wayvr-ipc", default-features = false } anyhow.workspace = true +chrono.workspace = true glam.workspace = true idmap = { workspace = true, features = ["serde"] } idmap-derive.workspace = true @@ -19,14 +19,17 @@ log.workspace = true serde = { workspace = true, features = ["rc"] } serde_json.workspace = true serde_json5.workspace = true +smol.workspace = true strum.workspace = true xdg.workspace = true -chrono = "0.4.42" -smol = { workspace = true } -wgui = { path = "../wgui/" } -rodio = { version = "0.22.2", default-features = false, features = ["playback", "mp3", "hound", "recording"] } glob = "0.3.3" -walkdir = "2.5.0" -rust-ini = "0.21.3" identicons-svg = "0.1.0" +rodio = { + version = "0.22.2", + default-features = false, + features = ["hound", "mp3", "playback", "recording"] +} +rust-ini = "0.21.3" +walkdir = "2.5.0" +wgui = { path = "../wgui/" } From d7bd243c41e66e1d77e5ae8fb8ecf8fc95e45387 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sat, 11 Jul 2026 23:21:54 +0900 Subject: [PATCH 2/5] update deps --- Cargo.lock | 173 +++++++++++---------------------------- dash-frontend/Cargo.toml | 4 +- wayvr-ipc/Cargo.toml | 2 +- wayvr/Cargo.toml | 26 +++--- wayvrctl/Cargo.toml | 2 +- wgui/Cargo.toml | 2 +- 6 files changed, 66 insertions(+), 143 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc2a291c..e1f665b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -362,13 +362,13 @@ dependencies = [ [[package]] name = "async-native-tls" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9343dc5acf07e79ff82d0c37899f079db3534d99f189a1837c8e549c99405bec" +checksum = "37dd6b179962fe4048a6f81d4c0d7ed419a21fdf49204b4c6b04971693358e79" dependencies = [ "futures-util", "native-tls", - "thiserror 1.0.69", + "thiserror 2.0.18", "url", ] @@ -623,7 +623,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -911,7 +911,7 @@ dependencies = [ "num-traits", "pure-rust-locales", "wasm-bindgen", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -1211,7 +1211,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows 0.62.2", + "windows", ] [[package]] @@ -2089,7 +2089,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ "rustix 1.1.4", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -2387,7 +2387,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -2773,7 +2773,7 @@ dependencies = [ "simd_cesu8", "thiserror 2.0.18", "walkdir", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -2929,7 +2929,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -2939,7 +2939,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ "cfg-if", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -3071,9 +3071,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.18.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" +checksum = "0b6180140927ee907000b0aa540091f6ea512ead4447c92b8fc35bc72788a5a6" dependencies = [ "hashbrown 0.17.1", ] @@ -3654,6 +3654,17 @@ dependencies = [ "objc2-foundation 0.3.2", ] +[[package]] +name = "objc2-open-directory" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb82bed227edf5201dfedf072bba4015a33d3d4a98519837295a90f0a23f676d" +dependencies = [ + "objc2 0.6.4", + "objc2-core-foundation", + "objc2-foundation 0.3.2", +] + [[package]] name = "objc2-quartz-core" version = "0.2.2" @@ -3927,7 +3938,7 @@ dependencies = [ "libc", "redox_syscall 0.5.18", "smallvec", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -5130,9 +5141,9 @@ checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "signal-hook" -version = "0.3.18" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +checksum = "b2a0c28ca5908dbdbcd52e6fdaa00358ab88637f8ab33e1f188dd510eb44b53d" dependencies = [ "libc", "signal-hook-registry", @@ -5575,16 +5586,17 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.37.2" +version = "0.39.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f" +checksum = "d2071df9448915b71c4fe6d25deaf1c22f12bd234f01540b77312bb8e41361e6" dependencies = [ "libc", "memchr", "ntapi", "objc2-core-foundation", "objc2-io-kit", - "windows 0.61.3", + "objc2-open-directory", + "windows", ] [[package]] @@ -6678,38 +6690,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections 0.2.0", - "windows-core 0.61.2", - "windows-future 0.2.1", - "windows-link 0.1.3", - "windows-numerics 0.2.0", -] - [[package]] name = "windows" version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-collections 0.3.2", - "windows-core 0.62.2", - "windows-future 0.3.2", - "windows-numerics 0.3.1", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", ] [[package]] @@ -6718,20 +6708,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-core 0.62.2", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-core", ] [[package]] @@ -6742,20 +6719,9 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", - "windows-threading 0.1.0", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] @@ -6764,9 +6730,9 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", - "windows-threading 0.2.1", + "windows-core", + "windows-link", + "windows-threading", ] [[package]] @@ -6791,45 +6757,20 @@ dependencies = [ "syn 2.0.118", ] -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", -] - [[package]] name = "windows-numerics" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" dependencies = [ - "windows-core 0.62.2", - "windows-link 0.2.1", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", + "windows-core", + "windows-link", ] [[package]] @@ -6838,16 +6779,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -6856,7 +6788,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -6892,7 +6824,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -6926,22 +6858,13 @@ dependencies = [ "windows_x86_64_msvc 0.52.6", ] -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows-threading" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] diff --git a/dash-frontend/Cargo.toml b/dash-frontend/Cargo.toml index 2f5206c3..f1ce3c0c 100644 --- a/dash-frontend/Cargo.toml +++ b/dash-frontend/Cargo.toml @@ -24,9 +24,9 @@ strum.workspace = true uuid.workspace = true xdg.workspace = true -async-native-tls = "0.5.0" +async-native-tls = "0.6.0" http-body-util = "0.1.3" -hyper = { version = "1.8.1", features = ["client", "http1", "http2"] } +hyper = { version = "1.10.1", features = ["client", "http1", "http2"] } keyvalues-parser = { git = "https://codeberg.org/CosmicHarper/vdf-rs.git", rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" diff --git a/wayvr-ipc/Cargo.toml b/wayvr-ipc/Cargo.toml index 2efa2896..04a0338f 100644 --- a/wayvr-ipc/Cargo.toml +++ b/wayvr-ipc/Cargo.toml @@ -18,7 +18,7 @@ smallvec.workspace = true interprocess = { workspace = true, features = ["tokio"], optional = true } serde_json.workspace = true tokio = { workspace = true, features = ["macros"], optional = true } -tokio-util = { version = "0.7.13", optional = true } +tokio-util = { version = "0.7.18", optional = true } [features] default = ["client"] diff --git a/wayvr/Cargo.toml b/wayvr/Cargo.toml index 78fb5da9..2c9f0f62 100644 --- a/wayvr/Cargo.toml +++ b/wayvr/Cargo.toml @@ -59,8 +59,8 @@ xdg.workspace = true ash = "^0.38.0" # must match vulkano bytes = { workspace = true } chrono-tz = "0.10.4" -config = "0.15.19" -futures = "0.3.31" +config = "0.15.25" +futures = "0.3.32" image_dds = { version = "0.7.2", default-features = false, @@ -70,7 +70,7 @@ image_dds = { } input-linux = "0.7.1" json = { version = "0.12.4", optional = true } -json5 = "1.3.0" +json5 = "1.3.1" libmonado = { git = "https://github.com/wayvr-org/libmonado-rs.git", rev = "6f66b26930c24a8a2fc57ddcd85704784894c750", @@ -78,7 +78,7 @@ libmonado = { } log-panics = { version = "2.1.0", features = ["with-backtrace"] } mint = "0.5.9" -openxr = { version = "0.21.0", features = ["linked", "mint"], optional = true } +openxr = { version = "0.21.1", features = ["linked", "mint"], optional = true } ovr_overlay = { git = "https://github.com/galister/ovr_overlay_oyasumi", rev = "e477bd2a9e04293ea68c1e7529ef2cb131f32acc", @@ -88,11 +88,11 @@ ovr_overlay = { ], optional = true } -prost = { version = "0.14.3", optional = true } +prost = { version = "0.14.4", optional = true } pure-rust-locales = "0.8.2" rosc = { version = "0.11.4", optional = true } -serde_yaml = "0.9.34" -signal-hook = "0.3.18" +serde_yaml = "0.9.33" +signal-hook = "0.4.4" smithay = { version = "0.7.0", default-features = false, @@ -104,12 +104,12 @@ smithay = { ] } smithay-clipboard = "0.7.3" -sysinfo = { version = "0.37" } -thiserror = "2.0" -tracing = "0.1.43" +sysinfo = { version = "0.39.6" } +thiserror = "2.0.18" +tracing = "0.1.44" whisper-rs = { version = "0.16.0", features = ["vulkan"], optional = true } xcb = { - version = "1.6.0", + version = "1.7.0", features = [ "as-raw-xcb-connection", ], @@ -119,8 +119,8 @@ xkbcommon = { version = "0.8.0" } # 0.9.0 breaks keymap import on some distros -calloop = { version = "0.14", optional = true } -calloop-wayland-source = { version = "0.4", optional = true } +calloop = { version = "0.14.4", optional = true } +calloop-wayland-source = { version = "0.4.1", optional = true } [build-dependencies] regex.workspace = true diff --git a/wayvrctl/Cargo.toml b/wayvrctl/Cargo.toml index 87b97a5d..fbd982f6 100644 --- a/wayvrctl/Cargo.toml +++ b/wayvrctl/Cargo.toml @@ -17,5 +17,5 @@ serde.workspace = true serde_json.workspace = true tokio.workspace = true -env_logger = "0.11.8" +env_logger = "0.11.11" shell-words = "1.1.1" diff --git a/wgui/Cargo.toml b/wgui/Cargo.toml index ced960d2..2d52477c 100644 --- a/wgui/Cargo.toml +++ b/wgui/Cargo.toml @@ -34,7 +34,7 @@ image = { "webp", ] } -lru = "0.18.0" +lru = "0.18.1" ouroboros = "0.18.5" parking_lot = "0.12.5" resvg = { version = "0.47.0", default-features = false } From 2e7a528857dfdbc2661e0e6fe3e8c436ab01c2ee Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:06:24 +0900 Subject: [PATCH 3/5] swich tokio to smol --- Cargo.lock | 47 ++------------------- Cargo.toml | 3 +- wayvr-ipc/Cargo.toml | 8 ++-- wayvr-ipc/src/client.rs | 76 +++++++++++++++++++--------------- wayvr-ipc/src/util/notifier.rs | 24 ++++++----- wayvrctl/Cargo.toml | 2 +- wayvrctl/src/main.rs | 51 ++++++++++++----------- 7 files changed, 93 insertions(+), 118 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1f665b3..557029a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2662,10 +2662,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "069323743400cb7ab06a8fe5c1ed911d36b6919ec531661d034c89083629595b" dependencies = [ "doctest-file", - "futures-core", "libc", "recvmsg", - "tokio", "widestring", "windows-sys 0.61.2", ] @@ -3175,17 +3173,6 @@ version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" -[[package]] -name = "mio" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.61.2", -] - [[package]] name = "moveit" version = "0.6.0" @@ -5414,16 +5401,6 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" -[[package]] -name = "socket2" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -5823,23 +5800,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ "bytes", - "libc", - "mio", "pin-project-lite", - "socket2", - "tokio-macros", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.118", ] [[package]] @@ -6550,14 +6511,14 @@ name = "wayvr-ipc" version = "0.1.0" dependencies = [ "anyhow", + "async-channel", + "async-io", "bytes", - "interprocess", "log", "serde", "serde_json", "smallvec", - "tokio", - "tokio-util", + "smol", ] [[package]] @@ -6571,7 +6532,7 @@ dependencies = [ "serde", "serde_json", "shell-words", - "tokio", + "smol", "wayvr-ipc", ] diff --git a/Cargo.toml b/Cargo.toml index 4214b9c0..b57a0502 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,8 @@ members = [ [workspace.dependencies] anyhow = "1.0.100" +async-channel = "2.3" +async-io = "2.1" bytes = { version = "1.11.1" } chrono = "0.4.42" clap = { version = "4.5.53", features = ["derive"] } @@ -34,7 +36,6 @@ slotmap = "1.1.1" smallvec = "1.15.2" smol = "2.0.2" strum = { version = "0.27.2", features = ["derive"] } -tokio = "1.48.0" # TODO: switch to smol for ipc tracing-subscriber = { version = "0.3.22", features = ["env-filter"] } uuid = { version = "1.19.0", features = ["fast-rng", "serde", "v4"] } vulkano = { diff --git a/wayvr-ipc/Cargo.toml b/wayvr-ipc/Cargo.toml index 04a0338f..47520dd3 100644 --- a/wayvr-ipc/Cargo.toml +++ b/wayvr-ipc/Cargo.toml @@ -9,17 +9,17 @@ repository = "https://github.com/wlx-team/wayvr" [dependencies] anyhow.workspace = true +async-channel.workspace = true +async-io.workspace = true bytes.workspace = true log.workspace = true serde.workspace = true smallvec.workspace = true # client-only deps -interprocess = { workspace = true, features = ["tokio"], optional = true } serde_json.workspace = true -tokio = { workspace = true, features = ["macros"], optional = true } -tokio-util = { version = "0.7.18", optional = true } +smol = { workspace = true, optional = true } [features] default = ["client"] -client = ["dep:interprocess", "dep:tokio", "dep:tokio-util"] +client = ["dep:smol"] diff --git a/wayvr-ipc/src/client.rs b/wayvr-ipc/src/client.rs index a1a6cb0c..e16c9ada 100644 --- a/wayvr-ipc/src/client.rs +++ b/wayvr-ipc/src/client.rs @@ -1,16 +1,11 @@ use bytes::BufMut; -use interprocess::local_socket::{ - self, GenericNamespaced, - tokio::{Stream, prelude::*}, -}; use serde::Serialize; use smallvec::SmallVec; +use smol::io::AsyncReadExt; +use smol::io::AsyncWriteExt; +use smol::lock::Mutex; +use smol::net::unix::UnixStream; use std::sync::{Arc, Weak}; -use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, - sync::Mutex, -}; -use tokio_util::sync::CancellationToken; use crate::{ gen_id, @@ -43,10 +38,10 @@ type SignalFunc = Box bool + Send>; pub struct WayVRClient { receiver: ReceiverMutex, sender: SenderMutex, - cancel_token: CancellationToken, + cancel_tx: async_channel::Sender<()>, exiting: bool, queued_packets: QueuedPacketVec, - pub auth: Option, // Some if authenticated + pub auth: Option, pub on_signal: Option, } @@ -67,8 +62,8 @@ pub async fn send_packet(sender: &SenderMutex, data: &[u8]) -> anyhow::Result<() pub type WayVRClientMutex = Arc>; pub type WayVRClientWeak = Weak>; -type ReceiverMutex = Arc>; -type SenderMutex = Arc>; +type ReceiverMutex = Arc>; +type SenderMutex = Arc>; async fn client_runner(client: WayVRClientMutex) -> anyhow::Result<()> { loop { @@ -79,7 +74,7 @@ async fn client_runner(client: WayVRClientMutex) -> anyhow::Result<()> { type Payload = SmallVec<[u8; 64]>; async fn read_payload( - conn: &mut local_socket::tokio::RecvHalf, + conn: &mut smol::net::unix::UnixStream, size: u32, ) -> anyhow::Result { let mut payload = Payload::new(); @@ -122,32 +117,29 @@ impl WayVRClient { pub async fn new(client_name: &str) -> anyhow::Result { let printname = "/tmp/wayvr_ipc.sock"; - let name = printname.to_ns_name::()?; - let stream = match Stream::connect(name).await { + let stream = match UnixStream::connect(printname).await { Ok(c) => c, Err(e) => { anyhow::bail!("Failed to connect to the WayVR IPC: {}", e) } }; - let (receiver, sender) = stream.split(); + let receiver = Arc::new(Mutex::new(stream.clone())); + let sender = Arc::new(Mutex::new(stream)); - let receiver = Arc::new(Mutex::new(receiver)); - let sender = Arc::new(Mutex::new(sender)); - - let cancel_token = CancellationToken::new(); + let (cancel_tx, cancel_rx) = async_channel::bounded(1); let client = Arc::new(Mutex::new(Self { receiver, sender: sender.clone(), + cancel_tx, exiting: false, - cancel_token: cancel_token.clone(), queued_packets: QueuedPacketVec::new(), auth: None, on_signal: None, })); - WayVRClient::start_runner(client.clone(), cancel_token); + WayVRClient::start_runner(client.clone(), cancel_rx); // Send handshake to the server send_packet( @@ -163,17 +155,31 @@ impl WayVRClient { Ok(client) } - fn start_runner(client: WayVRClientMutex, cancel_token: CancellationToken) { - tokio::spawn(async move { - tokio::select! { - _ = cancel_token.cancelled() => { - log::info!("Exiting IPC runner gracefully"); - } - e = client_runner(client.clone()) => { - log::info!("IPC Runner failed: {:?}", e); + fn start_runner(client: WayVRClientMutex, cancel_rx: async_channel::Receiver<()>) { + smol::spawn(async move { + let cancel_fut = async { + cancel_rx + .recv() + .await + .map_err(|_| anyhow::anyhow!("cancelled")) + }; + + let result = smol::future::race(client_runner(client.clone()), cancel_fut).await; + + match result { + Ok(()) => { + log::info!("IPC Runner completed"); + } + Err(e) => { + if e.to_string() == "cancelled" { + log::info!("Exiting IPC runner gracefully"); + } else { + log::info!("IPC Runner failed: {:?}", e); } + } } - }); + }) + .detach(); } async fn tick(client_mtx: WayVRClientMutex) -> anyhow::Result<()> { @@ -185,7 +191,9 @@ impl WayVRClient { // read packet let packet = { let mut receiver = receiver.lock().await; - let packet_size = receiver.read_u32().await?; + let mut size_buf = [0u8; 4]; + receiver.read_exact(&mut size_buf).await?; + let packet_size = u32::from_be_bytes(size_buf); log::trace!("packet size {}", packet_size); if packet_size > 128 * 1024 { anyhow::bail!("packet size too large (> 128 KiB)"); @@ -442,6 +450,6 @@ impl WayVRClient { impl Drop for WayVRClient { fn drop(&mut self) { self.exiting = true; - self.cancel_token.cancel(); + let _ = self.cancel_tx.try_send(()); } } diff --git a/wayvr-ipc/src/util/notifier.rs b/wayvr-ipc/src/util/notifier.rs index b985cc5c..38acefc7 100644 --- a/wayvr-ipc/src/util/notifier.rs +++ b/wayvr-ipc/src/util/notifier.rs @@ -1,25 +1,29 @@ -use std::sync::Arc; - -use tokio::sync::Notify; +use async_channel::{Receiver, Sender}; // Copyable wrapped Notify struct for easier usage -#[derive(Default, Clone)] +#[derive(Clone)] pub struct Notifier { - notifier: Arc, + sender: Sender<()>, + receiver: Receiver<()>, } impl Notifier { pub fn new() -> Self { - Self { - notifier: Arc::new(Notify::new()), - } + let (sender, receiver) = async_channel::bounded(1); + Self { sender, receiver } } pub fn notify(&self) { - self.notifier.notify_waiters(); + let _ = self.sender.try_send(()); } pub async fn wait(&self) { - self.notifier.notified().await; + let _ = self.receiver.recv().await; + } +} + +impl Default for Notifier { + fn default() -> Self { + Self::new() } } diff --git a/wayvrctl/Cargo.toml b/wayvrctl/Cargo.toml index fbd982f6..659ef4b3 100644 --- a/wayvrctl/Cargo.toml +++ b/wayvrctl/Cargo.toml @@ -15,7 +15,7 @@ clap.workspace = true log.workspace = true serde.workspace = true serde_json.workspace = true -tokio.workspace = true +smol.workspace = true env_logger = "0.11.11" shell-words = "1.1.1" diff --git a/wayvrctl/src/main.rs b/wayvrctl/src/main.rs index 7b08c0b2..ed3e7994 100644 --- a/wayvrctl/src/main.rs +++ b/wayvrctl/src/main.rs @@ -22,37 +22,38 @@ use crate::helper::{ mod helper; mod types; -#[tokio::main(flavor = "current_thread")] -async fn main() -> ExitCode { +fn main() -> ExitCode { env_logger::init_from_env(Env::default().default_filter_or("info")); let args = Args::parse(); - let mut state = WayVRClientState { - wayvr_client: WayVRClient::new(&format!("wayvrctl-{}", process::id())) - .await - .inspect_err(|e| { - log::error!("Failed to initialize WayVR connection: {e:?}"); - process::exit(1); - }) - .unwrap(), - serial_generator: ipc::SerialGenerator::new(), - pretty_print: args.pretty, - }; + smol::block_on(async move { + let mut state = WayVRClientState { + wayvr_client: WayVRClient::new(&format!("wayvrctl-{}", process::id())) + .await + .inspect_err(|e| { + log::error!("Failed to initialize WayVR connection: {e:?}"); + process::exit(1); + }) + .unwrap(), + serial_generator: ipc::SerialGenerator::new(), + pretty_print: args.pretty, + }; - let maybe_err = if let Subcommands::Batch { fail_fast } = args.command { - run_batch(&mut state, fail_fast).await - } else { - run_once(&mut state, args).await - }; + let maybe_err = if let Subcommands::Batch { fail_fast } = args.command { + run_batch(&mut state, fail_fast).await + } else { + run_once(&mut state, args).await + }; - if let Err(e) = maybe_err { - log::error!("{e:?}"); - return ExitCode::FAILURE; - } else { - std::thread::sleep(Duration::from_millis(20)); - } + if let Err(e) = maybe_err { + log::error!("{e:?}"); + return ExitCode::FAILURE; + } else { + std::thread::sleep(Duration::from_millis(20)); + } - ExitCode::SUCCESS + ExitCode::SUCCESS + }) } async fn run_batch(state: &mut WayVRClientState, fail_fast: bool) -> anyhow::Result<()> { From 867c343c9be5e5f1f4b12a1e290325be94c74d18 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:06:24 +0900 Subject: [PATCH 4/5] swich tokio to smol --- Cargo.lock | 1 + wayvr-ipc/Cargo.toml | 1 + wayvr-ipc/src/client.rs | 40 +++++++++++++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 557029a7..b5beedfa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6514,6 +6514,7 @@ dependencies = [ "async-channel", "async-io", "bytes", + "interprocess", "log", "serde", "serde_json", diff --git a/wayvr-ipc/Cargo.toml b/wayvr-ipc/Cargo.toml index 47520dd3..a39eeb4e 100644 --- a/wayvr-ipc/Cargo.toml +++ b/wayvr-ipc/Cargo.toml @@ -12,6 +12,7 @@ anyhow.workspace = true async-channel.workspace = true async-io.workspace = true bytes.workspace = true +interprocess.workspace = true log.workspace = true serde.workspace = true smallvec.workspace = true diff --git a/wayvr-ipc/src/client.rs b/wayvr-ipc/src/client.rs index e16c9ada..3ca1106c 100644 --- a/wayvr-ipc/src/client.rs +++ b/wayvr-ipc/src/client.rs @@ -1,10 +1,11 @@ use bytes::BufMut; +use interprocess::local_socket::{self, ToNsName}; use serde::Serialize; use smallvec::SmallVec; use smol::io::AsyncReadExt; use smol::io::AsyncWriteExt; use smol::lock::Mutex; -use smol::net::unix::UnixStream; +use std::os::unix::net::UnixStream as StdUnixStream; use std::sync::{Arc, Weak}; use crate::{ @@ -65,6 +66,24 @@ pub type WayVRClientWeak = Weak>; type ReceiverMutex = Arc>; type SenderMutex = Arc>; +fn interprocess_stream_to_async( + stream: local_socket::Stream, +) -> anyhow::Result { + use std::os::unix::io::OwnedFd; + + let uds_stream: interprocess::os::unix::uds_local_socket::Stream = match stream { + local_socket::Stream::UdSocket(s) => s, + #[allow(unreachable_patterns)] + _ => anyhow::bail!("Unsupported socket type"), + }; + + let owned_fd: OwnedFd = uds_stream.into(); + let std_stream = StdUnixStream::from(owned_fd); + + smol::net::unix::UnixStream::try_from(std_stream) + .map_err(|e| anyhow::anyhow!("Failed to wrap socket for async I/O: {}", e)) +} + async fn client_runner(client: WayVRClientMutex) -> anyhow::Result<()> { loop { WayVRClient::tick(client.clone()).await?; @@ -118,14 +137,17 @@ impl WayVRClient { pub async fn new(client_name: &str) -> anyhow::Result { let printname = "/tmp/wayvr_ipc.sock"; - let stream = match UnixStream::connect(printname).await { - Ok(c) => c, - Err(e) => { - anyhow::bail!("Failed to connect to the WayVR IPC: {}", e) - } - }; - let receiver = Arc::new(Mutex::new(stream.clone())); - let sender = Arc::new(Mutex::new(stream)); + let name = printname + .to_ns_name::() + .map_err(|e| anyhow::anyhow!("Failed to create socket name: {}", e))?; + let opts = local_socket::ConnectOptions::new().name(name); + let ip_stream = opts + .connect_sync() + .map_err(|e| anyhow::anyhow!("Failed to connect to the WayVR IPC: {}", e))?; + + let async_stream = interprocess_stream_to_async(ip_stream)?; + let receiver = Arc::new(Mutex::new(async_stream.clone())); + let sender = Arc::new(Mutex::new(async_stream)); let (cancel_tx, cancel_rx) = async_channel::bounded(1); From 40430ea94e0a7c92066f99c6ed22492247868a62 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Sun, 12 Jul 2026 20:48:19 +0900 Subject: [PATCH 5/5] switch downloader from hyper to urec --- Cargo.lock | 171 ++++--- dash-frontend/Cargo.toml | 2 +- dash-frontend/src/util/cached_fetcher.rs | 18 +- .../src/util/networking/http_client.rs | 426 ++++++++---------- .../src/util/networking/image_fetch.rs | 9 +- .../src/util/networking/skymap_catalog.rs | 6 +- dash-frontend/src/views/download_file.rs | 55 +-- dash-frontend/src/views/game_cover.rs | 9 +- dash-frontend/src/views/game_launcher.rs | 6 +- dash-frontend/src/views/remote_skymap_list.rs | 22 +- uidev/Cargo.toml | 1 + 11 files changed, 344 insertions(+), 381 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5beedfa..6b64d32d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1415,7 +1415,6 @@ dependencies = [ "chrono", "glam", "http-body-util", - "hyper", "keyvalues-parser", "log", "lz4_flex", @@ -1425,6 +1424,7 @@ dependencies = [ "smol", "smol-hyper", "strum", + "ureq", "uuid", "wayvr-ipc", "wgui", @@ -2176,25 +2176,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b40ca9252762c466af32d0b1002e91e4e1bc5398f77455e55474deb466355ff5" -[[package]] -name = "h2" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.14.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.7.1" @@ -2360,19 +2341,10 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ - "atomic-waker", "bytes", - "futures-channel", - "futures-core", - "h2", "http", "http-body", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", "tokio", - "want", ] [[package]] @@ -4713,6 +4685,20 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rodio" version = "0.22.2" @@ -4874,6 +4860,41 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "rustls" +version = "0.23.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2c118cb077cca2822033836dfb1b975355dfb784b5e8da48f7b6c5db74e60e" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -5449,6 +5470,12 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "svgtypes" version = "0.16.1" @@ -5799,23 +5826,9 @@ version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" dependencies = [ - "bytes", "pin-project-lite", ] -[[package]] -name = "tokio-util" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - [[package]] name = "toml" version = "1.1.2+spec-1.1.0" @@ -5929,12 +5942,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "ttf-parser" version = "0.25.1" @@ -5978,6 +5985,7 @@ dependencies = [ "log", "rust-embed", "tracing-subscriber", + "ureq", "vulkano", "vulkano-shaders", "wgui", @@ -6033,6 +6041,41 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" +dependencies = [ + "base64", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pki-types", + "ureq-proto", + "utf8-zero", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + [[package]] name = "url" version = "2.5.8" @@ -6067,6 +6110,12 @@ dependencies = [ "xmlwriter", ] +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -6201,15 +6250,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -6557,6 +6597,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "weezl" version = "0.1.12" @@ -7247,6 +7296,12 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + [[package]] name = "zerotrie" version = "0.2.4" diff --git a/dash-frontend/Cargo.toml b/dash-frontend/Cargo.toml index f1ce3c0c..bfe5064b 100644 --- a/dash-frontend/Cargo.toml +++ b/dash-frontend/Cargo.toml @@ -26,13 +26,13 @@ xdg.workspace = true async-native-tls = "0.6.0" http-body-util = "0.1.3" -hyper = { version = "1.10.1", features = ["client", "http1", "http2"] } keyvalues-parser = { git = "https://codeberg.org/CosmicHarper/vdf-rs.git", rev = "fc6dcbea9eb13cacb98dea40063f6f56cde6e145" } lz4_flex = { version = "0.13.1", features = ["frame"] } smol-hyper = "0.1.1" +ureq = "3.3.0" [features] default = ["monado"] diff --git a/dash-frontend/src/util/cached_fetcher.rs b/dash-frontend/src/util/cached_fetcher.rs index 2671a748..54d55d31 100644 --- a/dash-frontend/src/util/cached_fetcher.rs +++ b/dash-frontend/src/util/cached_fetcher.rs @@ -1,14 +1,14 @@ use crate::util::{networking::http_client, steam_utils::AppID}; use anyhow::Context; use serde::Deserialize; -use wlx_common::{async_executor::AsyncExecutor, cache_dir}; +use wlx_common::cache_dir; pub struct CoverArt { // can be empty in case if data couldn't be fetched (use a fallback image then) pub compressed_image_data: Vec, } -pub async fn request_image(executor: AsyncExecutor, app_id: AppID) -> anyhow::Result { +pub async fn request_image(app_id: AppID) -> anyhow::Result { let cache_file_path = format!("cover_arts/{}.bin", app_id); // check if file already exists in cache directory @@ -23,7 +23,7 @@ pub async fn request_image(executor: AsyncExecutor, app_id: AppID) -> anyhow::Re app_id ); - match http_client::get_simple(&executor, &url).await { + match http_client::get_simple(&url).await { Ok(response) => { log::info!("Success"); cache_dir::set_data(&cache_file_path, &response.data).await?; @@ -55,11 +55,7 @@ pub struct AppDetailsJSONData { pub developers: Vec, // ["Valve"] } -async fn get_app_details_json_internal( - executor: AsyncExecutor, - cache_file_path: &str, - app_id: AppID, -) -> anyhow::Result { +async fn get_app_details_json_internal(cache_file_path: &str, app_id: AppID) -> anyhow::Result { // check if file already exists in cache directory if let Some(data) = cache_dir::get_data(cache_file_path).await { return Ok(serde_json::from_value(serde_json::from_slice(&data)?)?); @@ -68,7 +64,7 @@ async fn get_app_details_json_internal( // Fetch from Steam API log::info!("Fetching app detail ID {}", app_id); let url = format!("https://store.steampowered.com/api/appdetails?appids={}", app_id); - let response = http_client::get_simple(&executor, &url).await?; + let response = http_client::get_simple(&url).await?; let res_utf8 = String::from_utf8(response.data)?; let root = serde_json::from_str::(&res_utf8)?; let body = root.get(&app_id).context("invalid body")?; @@ -88,10 +84,10 @@ async fn get_app_details_json_internal( Ok(app_details) } -pub async fn get_app_details_json(executor: AsyncExecutor, app_id: AppID) -> Option { +pub async fn get_app_details_json(app_id: AppID) -> Option { let cache_file_path = format!("app_details/{}.json", app_id); - match get_app_details_json_internal(executor, &cache_file_path, app_id).await { + match get_app_details_json_internal(&cache_file_path, app_id).await { Ok(r) => Some(r), Err(e) => { log::error!("Failed to get app details: {:?}", e); diff --git a/dash-frontend/src/util/networking/http_client.rs b/dash-frontend/src/util/networking/http_client.rs index 0b8bd75c..ea5b2b34 100644 --- a/dash-frontend/src/util/networking/http_client.rs +++ b/dash-frontend/src/util/networking/http_client.rs @@ -1,19 +1,15 @@ -// -// example smol+hyper usage derived from -// https://github.com/smol-rs/smol/blob/master/examples/hyper-client.rs -// under Apache-2.0 + MIT license. -// Repository URL: https://github.com/smol-rs/smol -// - use anyhow::Context as _; -use async_native_tls::TlsStream; -use http_body_util::{BodyStream, Empty}; -use hyper::Request; -use smol::{net::TcpStream, prelude::*}; -use std::convert::TryInto; -use std::pin::Pin; -use std::task::{Context, Poll}; -use wlx_common::async_executor::AsyncExecutor; +use smol::{ + Task, + channel::{Receiver, bounded}, + io::AsyncWriteExt as _, +}; +use std::{io::Read as _, path::Path, str, sync::OnceLock}; + +const IO_BUFFER_SIZE: usize = 256 * 1024; +const CHANNEL_CAPACITY: usize = 4; +const MAX_INITIAL_ALLOCATION: usize = 8 * 1024 * 1024; + pub struct HttpClientResponse { pub data: Vec, } @@ -21,276 +17,224 @@ pub struct HttpClientResponse { impl HttpClientResponse { pub fn into_json(self) -> anyhow::Result where - T: for<'a> serde::Deserialize<'a>, + T: serde::de::DeserializeOwned, { let utf8 = str::from_utf8(&self.data)?; - Ok(serde_json::from_str::(utf8)?) + Ok(serde_json::from_str(utf8)?) } } +#[derive(Debug, Clone, Copy)] pub struct ProgressFuncData { pub bytes_downloaded: u64, pub file_size: u64, } -pub type ProgressFunc = Box; +pub type ProgressFunc<'a> = Box; pub struct GetParams<'a> { - pub executor: &'a AsyncExecutor, pub url: &'a str, - pub on_progress: Option, + pub on_progress: Option>, } -pub async fn get(params: GetParams<'_>) -> anyhow::Result { - let url: hyper::Uri = params.url.try_into()?; - let req = Request::builder() - .header( - hyper::header::HOST, - url.authority().context("invalid authority")?.clone().as_str(), - ) - .uri(url) - .body(Empty::new())?; - - let resp = fetch_and_follow_redirects(params.executor, req, params.on_progress, ¶ms.url).await?; - - Ok(resp) +struct DownloadStream { + file_size: u64, + chunks: Receiver>, + worker: Task>, } -async fn fetch_and_follow_redirects( - executor: &AsyncExecutor, - req: hyper::Request>, - mut on_progress: Option, - initial_url: &str, -) -> anyhow::Result { - log::info!("fetching URL \"{}\"", initial_url); +static HTTP_AGENT: OnceLock = OnceLock::new(); - let resp = fetch(executor, req.clone()).await?; - let status = resp.status(); +fn http_agent() -> &'static ureq::Agent { + HTTP_AGENT.get_or_init(|| { + ureq::Agent::config_builder() + .max_redirects(10) + .http_status_as_error(false) + .build() + .new_agent() + }) +} - if status.is_redirection() { - let next_req = follow_single_redirect(&req, &resp).await?; +/// Starts a blocking HTTP request and streams its body through a bounded +/// asynchronous channel. +/// +/// The request, TLS operations, and all BodyReader reads remain inside one +/// blocking worker. Only owned byte chunks cross back to the async task. +async fn start_download(url: &str, allow_missing_content_length: bool) -> anyhow::Result { + let url = url.to_owned(); + let agent = http_agent().clone(); - let max_redirects = 10; - let mut current_req = next_req; - let mut redirects = 0; - loop { - let resp = fetch(executor, current_req.clone()).await?; - let resp_status = resp.status(); + let (metadata_tx, metadata_rx) = bounded::(1); - if resp_status.is_success() { - let (parts, body) = resp.into_parts(); + let (chunk_tx, chunk_rx) = bounded::>(CHANNEL_CAPACITY); - let mut bytes_downloaded: u64 = 0; - let mut file_size: u64 = 1; + let worker = smol::unblock(move || -> anyhow::Result<()> { + log::info!("fetching URL \"{}\"", url); - if let Some(val) = parts.headers.get("Content-Length") - && let Ok(str) = val.to_str() - && let Ok(s) = str.parse() - { - file_size = s; - } + let response = agent + .get(&url) + .header("Accept-Encoding", "identity") + .call() + .with_context(|| format!("failed to fetch URL \"{url}\""))?; - let data = BodyStream::new(body) - .try_fold(Vec::new(), |mut body, chunk| { - if let Some(chunk) = chunk.data_ref() { - bytes_downloaded += chunk.len() as u64; - body.extend_from_slice(chunk); + if !response.status().is_success() { + anyhow::bail!("non-200 HTTP response: {}", response.status().as_u16(),); + } - if let Some(on_progress) = &mut on_progress { - on_progress(ProgressFuncData { - bytes_downloaded, - file_size, - }) - } - } - Ok(body) - }) - .await?; + let file_size = match response.body().content_length() { + Some(file_size) => file_size, - return Ok(HttpClientResponse { data }); - } else if resp_status.is_redirection() { - redirects += 1; - if redirects >= max_redirects { - anyhow::bail!("too many redirects"); - } - current_req = follow_single_redirect(¤t_req, &resp).await?; - } else { - anyhow::bail!("non-200 HTTP response: {}", resp_status.as_str()); + None if allow_missing_content_length => 0, + + None => { + anyhow::bail!("HTTP response has no Content-Length header"); } + }; + + if metadata_tx.send_blocking(file_size).is_err() { + return Ok(()); + } + + drop(metadata_tx); + + let mut reader = response.into_body().into_reader(); + let mut buffer = [0_u8; IO_BUFFER_SIZE]; + + loop { + let count = reader.read(&mut buffer).with_context(|| { + format!( + "failed while reading HTTP response body \ + from \"{url}\"" + ) + })?; + + if count == 0 { + break; + } + + let chunk = buffer[..count].to_vec(); + + if chunk_tx.send_blocking(chunk).is_err() { + return Ok(()); + } + } + + Ok(()) + }); + + let file_size = match metadata_rx.recv().await { + Ok(file_size) => file_size, + + Err(_) => { + worker.await?; + + anyhow::bail!("HTTP worker stopped before providing response metadata"); + } + }; + + Ok(DownloadStream { + file_size, + chunks: chunk_rx, + worker, + }) +} + +/// Downloads a response into memory. +/// +/// This fails if the server does not provide a Content-Length header. +pub async fn get(mut params: GetParams<'_>) -> anyhow::Result { + let DownloadStream { + file_size, + chunks, + worker, + } = start_download(params.url, false).await?; + + let initial_capacity = usize::try_from(file_size).unwrap_or(0).min(MAX_INITIAL_ALLOCATION); + + let mut data = Vec::with_capacity(initial_capacity); + let mut bytes_downloaded = 0_u64; + + while let Ok(chunk) = chunks.recv().await { + bytes_downloaded += chunk.len() as u64; + data.extend_from_slice(&chunk); + + if let Some(on_progress) = params.on_progress.as_mut() { + on_progress(ProgressFuncData { + bytes_downloaded, + file_size, + }); } } - if !resp.status().is_success() { - // non-200 HTTP response - anyhow::bail!("non-200 HTTP response: {}", resp.status().as_str()); + worker.await?; + + if bytes_downloaded != file_size { + anyhow::bail!( + "HTTP response size mismatch: expected {} bytes, received {}", + file_size, + bytes_downloaded, + ); } - let mut bytes_downloaded: u64 = 0; - let mut file_size: u64 = 1; - - let (parts, body) = resp.into_parts(); - - // that's a pretty interesting way to get file size :] - if let Some(val) = parts.headers.get("Content-Length") - && let Ok(str) = val.to_str() - && let Ok(s) = str.parse() - { - file_size = s; - } - - let data = BodyStream::new(body) - .try_fold(Vec::new(), |mut body, chunk| { - if let Some(chunk) = chunk.data_ref() { - bytes_downloaded += chunk.len() as u64; - body.extend_from_slice(chunk); - - if let Some(on_progress) = &mut on_progress { - on_progress(ProgressFuncData { - bytes_downloaded, - file_size, - }) - } - } - Ok(body) - }) - .await?; - Ok(HttpClientResponse { data }) } -fn uri_try_from_str(s: &str) -> anyhow::Result { - use std::convert::TryInto; - let uri: hyper::Uri = s.try_into().context("invalid URI")?; - uri - .path_and_query() - .ok_or_else(|| anyhow::anyhow!("URI has no path and query component")) - .cloned() -} +/// Downloads a response directly to a file. +/// +/// Unlike `get`, this permits responses without a Content-Length header. In +/// that case, `ProgressFuncData::file_size` is zero. +/// +/// An existing file is truncated. If the download fails after the file is +/// created, a partial file may remain at `path`. +pub async fn download_to_file(mut params: GetParams<'_>, path: impl AsRef) -> anyhow::Result<()> { + let path = path.as_ref().to_owned(); -async fn follow_single_redirect( - req: &hyper::Request>, - resp: &hyper::Response, -) -> anyhow::Result>> { - let location = resp - .headers() - .get(hyper::header::LOCATION) - .ok_or_else(|| anyhow::anyhow!("redirect response has no Location header"))?; + let DownloadStream { + file_size, + chunks, + worker, + } = start_download(params.url, true).await?; - let location_str = location.to_str().context("invalid redirect location header")?; + let mut file = smol::fs::File::create(&path) + .await + .with_context(|| format!("failed to create download file {:?}", path,))?; - // resolve relative urls against the original url. - let original_uri = req.uri().clone(); - let next_url: hyper::Uri = if location_str.starts_with("http://") || location_str.starts_with("https://") { - hyper::Uri::try_from(location_str).context("invalid redirect location")? - } else { - let mut parts = original_uri.into_parts(); - parts.path_and_query = uri_try_from_str(location_str) - .context("invalid redirect location")? - .into(); - hyper::Uri::from_parts(parts).context("failed to construct redirect URI")? - }; + let mut bytes_downloaded = 0_u64; - log::info!("redirecting to \"{}\"", next_url); + while let Ok(chunk) = chunks.recv().await { + file + .write_all(&chunk) + .await + .with_context(|| format!("failed to write download file {:?}", path,))?; - let next_req = Request::builder() - .header( - hyper::header::HOST, - next_url.authority().context("invalid authority")?.as_str(), - ) - .uri(next_url) - .body(Empty::new())?; + bytes_downloaded += chunk.len() as u64; - Ok(next_req) -} - -pub async fn get_simple(executor: &AsyncExecutor, url: &str) -> anyhow::Result { - get(GetParams { - executor, - url, - on_progress: None, - }) - .await -} - -async fn fetch( - ex: &AsyncExecutor, - req: hyper::Request>, -) -> anyhow::Result> { - let io = { - let host = req.uri().host().context("cannot parse host")?; - - match req.uri().scheme_str() { - Some("http") => { - let stream = { - let port = req.uri().port_u16().unwrap_or(80); - smol::net::TcpStream::connect((host, port)).await? - }; - SmolStream::Plain(stream) - } - Some("https") => { - // In case of HTTPS, establish a secure TLS connection first. - let stream = { - let port = req.uri().port_u16().unwrap_or(443); - smol::net::TcpStream::connect((host, port)).await? - }; - let stream = async_native_tls::connect(host, stream).await?; - SmolStream::Tls(stream) - } - scheme => anyhow::bail!("unsupported scheme: {:?}", scheme), - } - }; - - // Spawn the HTTP/1 connection. - let (mut sender, conn) = hyper::client::conn::http1::handshake(smol_hyper::rt::FuturesIo::new(io)).await?; - ex.spawn(async move { - if let Err(e) = conn.await { - println!("Connection failed: {:?}", e); - } - }) - .detach(); - - // Get the result - let result = sender.send_request(req).await?; - Ok(result) -} - -/// A TCP or TCP+TLS connection. -enum SmolStream { - /// A plain TCP connection. - Plain(TcpStream), - - /// A TCP connection secured by TLS. - Tls(TlsStream), -} - -impl AsyncRead for SmolStream { - fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll> { - match &mut *self { - SmolStream::Plain(stream) => Pin::new(stream).poll_read(cx, buf), - SmolStream::Tls(stream) => Pin::new(stream).poll_read(cx, buf), - } - } -} - -impl AsyncWrite for SmolStream { - fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll> { - match &mut *self { - SmolStream::Plain(stream) => Pin::new(stream).poll_write(cx, buf), - SmolStream::Tls(stream) => Pin::new(stream).poll_write(cx, buf), + if let Some(on_progress) = params.on_progress.as_mut() { + on_progress(ProgressFuncData { + bytes_downloaded, + file_size, + }); } } - fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match &mut *self { - SmolStream::Plain(stream) => Pin::new(stream).poll_close(cx), - SmolStream::Tls(stream) => Pin::new(stream).poll_close(cx), - } + worker.await?; + + file + .flush() + .await + .with_context(|| format!("failed to flush download file {:?}", path,))?; + + if file_size != 0 && bytes_downloaded != file_size { + anyhow::bail!( + "HTTP response size mismatch: expected {} bytes, received {}", + file_size, + bytes_downloaded, + ); } - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - match &mut *self { - SmolStream::Plain(stream) => Pin::new(stream).poll_flush(cx), - SmolStream::Tls(stream) => Pin::new(stream).poll_flush(cx), - } - } + Ok(()) +} + +pub async fn get_simple(url: &str) -> anyhow::Result { + get(GetParams { url, on_progress: None }).await } diff --git a/dash-frontend/src/util/networking/image_fetch.rs b/dash-frontend/src/util/networking/image_fetch.rs index 75d7c892..91039cd3 100644 --- a/dash-frontend/src/util/networking/image_fetch.rs +++ b/dash-frontend/src/util/networking/image_fetch.rs @@ -1,16 +1,11 @@ use std::rc::Rc; use wgui::{globals::WguiGlobals, renderer_vk::text::custom_glyph::CustomGlyphData}; -use wlx_common::async_executor::AsyncExecutor; use crate::util::networking::http_client; -pub async fn fetch_to_glyph_data( - globals: &WguiGlobals, - executor: &AsyncExecutor, - url: &str, -) -> anyhow::Result<(CustomGlyphData, Rc>)> { - let res = http_client::get_simple(executor, url).await?; +pub async fn fetch_to_glyph_data(globals: &WguiGlobals, url: &str) -> anyhow::Result<(CustomGlyphData, Rc>)> { + let res = http_client::get_simple(url).await?; let glyph_data = CustomGlyphData::from_bytes_raster(globals, url, &res.data)?; Ok((glyph_data, Rc::new(res.data))) } diff --git a/dash-frontend/src/util/networking/skymap_catalog.rs b/dash-frontend/src/util/networking/skymap_catalog.rs index 02af4612..44f21a45 100644 --- a/dash-frontend/src/util/networking/skymap_catalog.rs +++ b/dash-frontend/src/util/networking/skymap_catalog.rs @@ -1,7 +1,7 @@ use crate::util::networking::{self, WAYVR_SKYMAPS_ROOT, http_client}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; -use wlx_common::{async_executor::AsyncExecutor, config_io}; +use wlx_common::config_io; pub type SkymapUuid = uuid::Uuid; #[derive(Copy, Clone, Serialize, Deserialize, Debug)] @@ -160,10 +160,10 @@ impl SkymapCatalog { } } -pub async fn request_catalog(executor: &AsyncExecutor) -> anyhow::Result { +pub async fn request_catalog() -> anyhow::Result { log::info!("Fetching skymap list"); - let res = http_client::get_simple(executor, &format!("{}/catalog.json", networking::WAYVR_SKYMAPS_ROOT)).await?; + let res = http_client::get_simple(&format!("{}/catalog.json", networking::WAYVR_SKYMAPS_ROOT)).await?; let catalog = res.into_json::()?; catalog.validate()?; diff --git a/dash-frontend/src/views/download_file.rs b/dash-frontend/src/views/download_file.rs index fb5d51e3..be80b3c6 100644 --- a/dash-frontend/src/views/download_file.rs +++ b/dash-frontend/src/views/download_file.rs @@ -69,13 +69,7 @@ impl ViewTrait for View { if let Some(on_downloaded) = self.on_downloaded.take() { self .executor - .spawn(View::download( - self.tasks.clone(), - self.executor.clone(), - url, - path, - on_downloaded, - )) + .spawn(View::download(self.tasks.clone(), url, path, on_downloaded)) .detach(); } } @@ -189,37 +183,12 @@ impl View { async fn download( tasks: Tasks, - executor: AsyncExecutor, url: String, target_path: PathBuf, on_downloaded: Box, ) -> Option<()> { tasks.push(Task::SetStatusText(String::from("Connecting to the server..."))); - // start downloading from the server with progress reporting - let res = handle_async_result( - "Download failed", - &tasks, - http_client::get(http_client::GetParams { - executor: &executor, - url: &url, - on_progress: Some(Box::new({ - let tasks = tasks.clone(); - move |data: ProgressFuncData| { - tasks.push(Task::SetStatusText(format!( - "{}/{} KiB ({}%)", - data.bytes_downloaded / 1024, - data.file_size / 1024, - (data.bytes_downloaded as f32 / data.file_size as f32 * 100.0).round() - ))) - } - })), - }) - .await, - )?; - - tasks.push(Task::SetStatusText(String::from("Writing to file..."))); - // create parent directory if it doesn't exist yet if let Some(parent) = target_path.parent() { handle_async_result( @@ -229,10 +198,28 @@ impl View { )?; } + // start downloading from the server with progress reporting handle_async_result( - "File write failed", + "Download failed", &tasks, - smol::fs::write(target_path, res.data).await, + http_client::download_to_file( + http_client::GetParams { + url: &url, + on_progress: Some(Box::new({ + let tasks = tasks.clone(); + move |data: ProgressFuncData| { + tasks.push(Task::SetStatusText(format!( + "{}/{} MiB ({}%)", + data.bytes_downloaded / 1024 / 1024, + data.file_size / 1024 / 1024, + (data.bytes_downloaded as f32 / data.file_size as f32 * 100.0).round() + ))) + } + })), + }, + &target_path, + ) + .await, )?; tasks.push(Task::SetStatusText(String::from("Download finished"))); diff --git a/dash-frontend/src/views/game_cover.rs b/dash-frontend/src/views/game_cover.rs index eb902df5..e2700e19 100644 --- a/dash-frontend/src/views/game_cover.rs +++ b/dash-frontend/src/views/game_cover.rs @@ -61,12 +61,8 @@ const GAME_COVER_SIZE_X: f32 = 140.0; const GAME_COVER_SIZE_Y: f32 = 210.0; impl View { - async fn request_cover_image( - executor: AsyncExecutor, - manifest: steam_utils::AppManifest, - on_loaded: Box, - ) { - let cover_art = match cached_fetcher::request_image(executor, manifest.app_id.clone()).await { + async fn request_cover_image(manifest: steam_utils::AppManifest, on_loaded: Box) { + let cover_art = match cached_fetcher::request_image(manifest.app_id.clone()).await { Ok(cover_art) => cover_art, Err(e) => { log::error!("request_cover_image failed: {:?}", e); @@ -285,7 +281,6 @@ impl View { params .executor .spawn(View::request_cover_image( - params.executor.clone(), params.manifest.clone(), Box::new(params.on_loaded), )) diff --git a/dash-frontend/src/views/game_launcher.rs b/dash-frontend/src/views/game_launcher.rs index 2ffe4059..f10163e3 100644 --- a/dash-frontend/src/views/game_launcher.rs +++ b/dash-frontend/src/views/game_launcher.rs @@ -75,8 +75,8 @@ impl ViewTrait for View { } impl View { - async fn fetch_details(executor: AsyncExecutor, tasks: Tasks, app_id: AppID) { - let Some(details) = cached_fetcher::get_app_details_json(executor, app_id).await else { + async fn fetch_details(tasks: Tasks, app_id: AppID) { + let Some(details) = cached_fetcher::get_app_details_json(app_id).await else { return; }; @@ -103,7 +103,7 @@ impl View { let tasks = Tasks::new(); // fetch details from the web - let fut = View::fetch_details(params.executor.clone(), tasks.clone(), params.manifest.app_id.clone()); + let fut = View::fetch_details(tasks.clone(), params.manifest.app_id.clone()); params.executor.spawn(fut).detach(); let id_cover_art_parent = state.get_widget_id("cover_art_parent")?; diff --git a/dash-frontend/src/views/remote_skymap_list.rs b/dash-frontend/src/views/remote_skymap_list.rs index d834b5ed..aa52cd1b 100644 --- a/dash-frontend/src/views/remote_skymap_list.rs +++ b/dash-frontend/src/views/remote_skymap_list.rs @@ -119,8 +119,8 @@ impl ViewTrait for View { } impl View { - async fn skymap_catalog_request_wrapper(tasks: Tasks, executor: AsyncExecutor) { - let res = networking::skymap_catalog::request_catalog(&executor).await; + async fn skymap_catalog_request_wrapper(tasks: Tasks) { + let res = networking::skymap_catalog::request_catalog().await; tasks.push(Task::SetSkymapCatalog(Rc::new(res))) } @@ -131,7 +131,7 @@ impl View { with_text: true, })?; let tasks = Tasks::::new(); - let fut = View::skymap_catalog_request_wrapper(tasks.clone(), par.executor.clone()); + let fut = View::skymap_catalog_request_wrapper(tasks.clone()); par.executor.spawn(fut).detach(); Ok(Self { id_parent: par.parent_id, @@ -147,15 +147,10 @@ impl View { }) } - async fn request_skymap_preview( - globals: WguiGlobals, - executor: AsyncExecutor, - entry: SkymapCatalogEntry, - tasks: Tasks, - ) { + async fn request_skymap_preview(globals: WguiGlobals, entry: SkymapCatalogEntry, tasks: Tasks) { tasks.push(Task::SetSkymapPreview(( entry.uuid, - networking::image_fetch::fetch_to_glyph_data(&globals, &executor, &entry.files.get_url_preview()) + networking::image_fetch::fetch_to_glyph_data(&globals, &entry.files.get_url_preview()) .await .ok(), ))); @@ -192,12 +187,7 @@ impl View { let id_list = parser_state.fetch_widget(&layout.state, "list")?.id; for entry in &catalog.entries { - let task = View::request_skymap_preview( - self.globals.clone(), - self.executor.clone(), - entry.clone(), - self.tasks.clone(), - ); + let task = View::request_skymap_preview(self.globals.clone(), entry.clone(), self.tasks.clone()); let skymap_uuid = entry.uuid; diff --git a/uidev/Cargo.toml b/uidev/Cargo.toml index 6c5f059d..6f6c3c1c 100644 --- a/uidev/Cargo.toml +++ b/uidev/Cargo.toml @@ -20,3 +20,4 @@ tracing-subscriber.workspace = true vulkano.workspace = true vulkano-shaders.workspace = true winit.workspace = true +ureq = "3.3.0"