diff --git a/Cargo.lock b/Cargo.lock index c65ddcc3..43d67547 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -838,16 +838,6 @@ dependencies = [ "winx", ] -[[package]] -name = "cap-rand" -version = "3.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8144c22e24bbcf26ade86cb6501a0916c46b7e4787abdb0045a467eb1645a1d" -dependencies = [ - "ambient-authority", - "rand 0.8.5", -] - [[package]] name = "cap-std" version = "3.4.5" @@ -1268,21 +1258,21 @@ dependencies = [ [[package]] name = "cranelift-assembler-x64" -version = "0.131.0" +version = "0.132.0" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.131.0" +version = "0.132.0" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.131.0" +version = "0.132.0" dependencies = [ "cranelift-entity", "wasmtime-internal-core", @@ -1290,7 +1280,7 @@ dependencies = [ [[package]] name = "cranelift-bitset" -version = "0.131.0" +version = "0.132.0" dependencies = [ "serde", "serde_derive", @@ -1299,7 +1289,7 @@ dependencies = [ [[package]] name = "cranelift-codegen" -version = "0.131.0" +version = "0.132.0" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -1311,7 +1301,7 @@ dependencies = [ "cranelift-entity", "cranelift-isle", "gimli", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "libm", "log", "pulley-interpreter", @@ -1325,7 +1315,7 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.131.0" +version = "0.132.0" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -1336,18 +1326,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.131.0" +version = "0.132.0" [[package]] name = "cranelift-control" -version = "0.131.0" +version = "0.132.0" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.131.0" +version = "0.132.0" dependencies = [ "cranelift-bitset", "serde", @@ -1357,7 +1347,7 @@ dependencies = [ [[package]] name = "cranelift-frontend" -version = "0.131.0" +version = "0.132.0" dependencies = [ "cranelift-codegen", "log", @@ -1367,11 +1357,11 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.131.0" +version = "0.132.0" [[package]] name = "cranelift-native" -version = "0.131.0" +version = "0.132.0" dependencies = [ "cranelift-codegen", "libc", @@ -1380,7 +1370,7 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.131.0" +version = "0.132.0" [[package]] name = "crc" @@ -2922,6 +2912,9 @@ name = "hashbrown" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +dependencies = [ + "foldhash 0.2.0", +] [[package]] name = "headers" @@ -3627,9 +3620,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libfuzzer-sys" @@ -4384,6 +4377,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63944c133d03f44e75866bbd160b95af0ec3f6a13d936d69d31c81078cbc5baf" +dependencies = [ + "crc32fast", + "hashbrown 0.16.1", + "indexmap", + "memchr", +] + [[package]] name = "oid-registry" version = "0.7.1" @@ -5015,7 +5020,7 @@ dependencies = [ [[package]] name = "pulley-interpreter" -version = "44.0.0" +version = "45.0.0" dependencies = [ "cranelift-bitset", "log", @@ -5025,7 +5030,7 @@ dependencies = [ [[package]] name = "pulley-macros" -version = "44.0.0" +version = "45.0.0" dependencies = [ "proc-macro2", "quote", @@ -5145,8 +5150,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "libc", - "rand_chacha 0.3.1", "rand_core 0.6.4", ] @@ -5156,31 +5159,21 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.5", ] [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20 0.10.0", "getrandom 0.4.2", "rand_core 0.10.0", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.9.0" @@ -5253,7 +5246,7 @@ dependencies = [ "paste", "profiling", "rand 0.9.2", - "rand_chacha 0.9.0", + "rand_chacha", "simd_helpers", "thiserror 2.0.18", "v_frame", @@ -5375,13 +5368,13 @@ dependencies = [ [[package]] name = "regalloc2" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952ddbfc6f9f64d006c3efd8c9851a6ba2f2b944ba94730db255d55006e0ffda" +checksum = "de2c52737737f8609e94f975dee22854a2d5c125772d4b1cf292120f4d45c186" dependencies = [ "allocator-api2", "bumpalo", - "hashbrown 0.15.5", + "hashbrown 0.17.0", "log", "rustc-hash", "smallvec", @@ -6791,8 +6784,12 @@ checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", + "rustls", + "rustls-pki-types", "tokio", + "tokio-rustls", "tungstenite", + "webpki-roots 0.26.11", ] [[package]] @@ -7042,6 +7039,8 @@ dependencies = [ "httparse", "log", "rand 0.9.2", + "rustls", + "rustls-pki-types", "sha1", "thiserror 2.0.18", ] @@ -7268,12 +7267,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi-common" -version = "44.0.0" +version = "45.0.0" dependencies = [ "async-trait", "bitflags 2.11.0", "cap-fs-ext", - "cap-rand", "cap-std", "cap-time-ext", "fs-set-times", @@ -7281,6 +7279,7 @@ dependencies = [ "io-lifetimes", "libc", "log", + "rand 0.10.1", "rustix 1.1.4", "system-interface", "thiserror 2.0.18", @@ -7415,12 +7414,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.245.1" +version = "0.246.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9dca005e69bf015e45577e415b9af8c67e8ee3c0e38b5b0add5aa92581ed5c" +checksum = "61fb705ce81adde29d2a8e99d87995e39a6e927358c91398f374474746070ef7" dependencies = [ "leb128fmt", - "wasmparser 0.245.1", + "wasmparser 0.246.2", ] [[package]] @@ -7459,19 +7458,6 @@ dependencies = [ "semver", ] -[[package]] -name = "wasmparser" -version = "0.245.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f08c9adee0428b7bddf3890fc27e015ac4b761cc608c822667102b8bfd6995e" -dependencies = [ - "bitflags 2.11.0", - "hashbrown 0.16.1", - "indexmap", - "semver", - "serde", -] - [[package]] name = "wasmparser" version = "0.246.2" @@ -7487,18 +7473,18 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.245.1" +version = "0.246.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41517a3716fbb8ccf46daa9c1325f760fcbff5168e75c7392288e410b91ac8" +checksum = "6e41f7493ba994b8a779430a4c25ff550fd5a40d291693af43a6ef48688f00e3" dependencies = [ "anyhow", "termcolor", - "wasmparser 0.245.1", + "wasmparser 0.246.2", ] [[package]] name = "wasmtime" -version = "44.0.0" +version = "45.0.0" dependencies = [ "addr2line", "async-trait", @@ -7512,7 +7498,7 @@ dependencies = [ "log", "mach2", "memfd", - "object", + "object 0.39.0", "once_cell", "postcard", "pulley-interpreter", @@ -7523,7 +7509,7 @@ dependencies = [ "serde_derive", "smallvec", "target-lexicon 0.13.5", - "wasmparser 0.245.1", + "wasmparser 0.246.2", "wasmtime-environ", "wasmtime-internal-cache", "wasmtime-internal-component-macro", @@ -7541,7 +7527,7 @@ dependencies = [ [[package]] name = "wasmtime-environ" -version = "44.0.0" +version = "45.0.0" dependencies = [ "anyhow", "cpp_demangle", @@ -7549,10 +7535,10 @@ dependencies = [ "cranelift-bitset", "cranelift-entity", "gimli", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "indexmap", "log", - "object", + "object 0.39.0", "postcard", "rustc-demangle", "semver", @@ -7561,8 +7547,8 @@ dependencies = [ "sha2", "smallvec", "target-lexicon 0.13.5", - "wasm-encoder 0.245.1", - "wasmparser 0.245.1", + "wasm-encoder 0.246.2", + "wasmparser 0.246.2", "wasmprinter", "wasmtime-internal-component-util", "wasmtime-internal-core", @@ -7570,7 +7556,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-cache" -version = "44.0.0" +version = "45.0.0" dependencies = [ "base64", "directories-next", @@ -7588,7 +7574,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-component-macro" -version = "44.0.0" +version = "45.0.0" dependencies = [ "anyhow", "proc-macro2", @@ -7596,26 +7582,26 @@ dependencies = [ "syn 2.0.117", "wasmtime-internal-component-util", "wasmtime-internal-wit-bindgen", - "wit-parser 0.245.1", + "wit-parser 0.246.2", ] [[package]] name = "wasmtime-internal-component-util" -version = "44.0.0" +version = "45.0.0" [[package]] name = "wasmtime-internal-core" -version = "44.0.0" +version = "45.0.0" dependencies = [ "anyhow", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "libm", "serde", ] [[package]] name = "wasmtime-internal-cranelift" -version = "44.0.0" +version = "45.0.0" dependencies = [ "cfg-if", "cranelift-codegen", @@ -7626,12 +7612,12 @@ dependencies = [ "gimli", "itertools 0.14.0", "log", - "object", + "object 0.39.0", "pulley-interpreter", "smallvec", "target-lexicon 0.13.5", "thiserror 2.0.18", - "wasmparser 0.245.1", + "wasmparser 0.246.2", "wasmtime-environ", "wasmtime-internal-core", "wasmtime-internal-unwinder", @@ -7640,7 +7626,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-debugger" -version = "44.0.0" +version = "45.0.0" dependencies = [ "async-trait", "log", @@ -7652,7 +7638,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-fiber" -version = "44.0.0" +version = "45.0.0" dependencies = [ "cc", "cfg-if", @@ -7665,7 +7651,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-debug" -version = "44.0.0" +version = "45.0.0" dependencies = [ "cc", "wasmtime-internal-versioned-export-macros", @@ -7673,7 +7659,7 @@ dependencies = [ [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "44.0.0" +version = "45.0.0" dependencies = [ "cfg-if", "libc", @@ -7683,18 +7669,18 @@ dependencies = [ [[package]] name = "wasmtime-internal-unwinder" -version = "44.0.0" +version = "45.0.0" dependencies = [ "cfg-if", "cranelift-codegen", "log", - "object", + "object 0.39.0", "wasmtime-environ", ] [[package]] name = "wasmtime-internal-versioned-export-macros" -version = "44.0.0" +version = "45.0.0" dependencies = [ "proc-macro2", "quote", @@ -7703,14 +7689,14 @@ dependencies = [ [[package]] name = "wasmtime-internal-winch" -version = "44.0.0" +version = "45.0.0" dependencies = [ "cranelift-codegen", "gimli", "log", - "object", + "object 0.39.0", "target-lexicon 0.13.5", - "wasmparser 0.245.1", + "wasmparser 0.246.2", "wasmtime-environ", "wasmtime-internal-cranelift", "winch-codegen", @@ -7718,31 +7704,31 @@ dependencies = [ [[package]] name = "wasmtime-internal-wit-bindgen" -version = "44.0.0" +version = "45.0.0" dependencies = [ "anyhow", "bitflags 2.11.0", "heck 0.5.0", "indexmap", - "wit-parser 0.245.1", + "wit-parser 0.246.2", ] [[package]] name = "wasmtime-wasi" -version = "44.0.0" +version = "45.0.0" dependencies = [ "async-trait", "bitflags 2.11.0", "bytes", "cap-fs-ext", "cap-net-ext", - "cap-rand", "cap-std", "cap-time-ext", "fs-set-times", "futures", "io-extras", "io-lifetimes", + "rand 0.10.1", "rustix 1.1.4", "system-interface", "thiserror 2.0.18", @@ -7756,7 +7742,7 @@ dependencies = [ [[package]] name = "wasmtime-wasi-io" -version = "44.0.0" +version = "45.0.0" dependencies = [ "async-trait", "bytes", @@ -7767,10 +7753,10 @@ dependencies = [ [[package]] name = "wasmtime-wasi-threads" -version = "44.0.0" +version = "45.0.0" dependencies = [ "log", - "rand 0.8.5", + "rand 0.10.1", "wasi-common", "wasmtime", "wasmtime-wasi", @@ -8017,6 +8003,24 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webrogue" version = "0.1.0" @@ -8078,11 +8082,13 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", - "object", + "object 0.38.1", "postcard", + "semver", "serde", "wasmtime", "wasmtime-environ", + "webrogue-cli-goodies", "webrogue-icons", "webrogue-lld", "webrogue-wrapp", @@ -8114,19 +8120,18 @@ dependencies = [ "async-trait", "blake3", "clap", - "crossterm", "futures-util", - "inquire", - "rand 0.10.0", + "rand 0.10.1", + "rustls", "serde", "serde_json", - "spinners", "tokio", "tokio-tungstenite", "tokio-util", "tracing", "tracing-subscriber", "webrogue-aot-compiler", + "webrogue-cli-goodies", "webrogue-debugger", "webrogue-gfx", "webrogue-gfx-winit", @@ -8137,6 +8142,16 @@ dependencies = [ "webrogue-wrapp", ] +[[package]] +name = "webrogue-cli-goodies" +version = "0.1.0" +dependencies = [ + "anyhow", + "crossterm", + "inquire", + "spinners", +] + [[package]] name = "webrogue-debugger" version = "0.1.0" @@ -8318,8 +8333,9 @@ dependencies = [ "http", "json-escape", "lazy_static", - "rand 0.10.0", + "rand 0.10.1", "reqwest", + "rustls", "serde", "serde_json", "tokio", @@ -8402,10 +8418,9 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "cap-rand", "getrandom 0.4.2", "io-extras", - "rand 0.10.0", + "rand 0.10.1", "rand_core 0.10.0", "rustix 1.1.4", "wasi-common", @@ -8696,7 +8711,7 @@ dependencies = [ [[package]] name = "wiggle" -version = "44.0.0" +version = "45.0.0" dependencies = [ "bitflags 2.11.0", "thiserror 2.0.18", @@ -8708,7 +8723,7 @@ dependencies = [ [[package]] name = "wiggle-generate" -version = "44.0.0" +version = "45.0.0" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -8720,7 +8735,7 @@ dependencies = [ [[package]] name = "wiggle-macro" -version = "44.0.0" +version = "45.0.0" dependencies = [ "proc-macro2", "quote", @@ -8761,7 +8776,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winch-codegen" -version = "44.0.0" +version = "45.0.0" dependencies = [ "cranelift-assembler-x64", "cranelift-codegen", @@ -8770,7 +8785,7 @@ dependencies = [ "smallvec", "target-lexicon 0.13.5", "thiserror 2.0.18", - "wasmparser 0.245.1", + "wasmparser 0.246.2", "wasmtime-environ", "wasmtime-internal-core", "wasmtime-internal-cranelift", @@ -9627,9 +9642,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.245.1" +version = "0.246.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330698718e82983499419494dd1e3d7811a457a9bf9f69734e8c5f07a2547929" +checksum = "fd979042b5ff288607ccf3b314145435453f20fc67173195f91062d2289b204d" dependencies = [ "anyhow", "hashbrown 0.16.1", @@ -9641,7 +9656,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.245.1", + "wasmparser 0.246.2", ] [[package]] @@ -9664,9 +9679,9 @@ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "wry" -version = "0.55.0" +version = "0.54.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3013fd6116aac351dd2e18f349b28b2cfef3a5ff3253a9d0ce2d7193bb1b4429" +checksum = "e5a8135d8676225e5744de000d4dff5a082501bf7db6a1c1495034f8c314edbc" dependencies = [ "base64", "block2", diff --git a/Cargo.toml b/Cargo.toml index d5d76998..746deb8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ members = [ "crates/aot-data", "crates/aot-lib", "crates/cli", + "crates/cli-goodies", "crates/debugger", "crates/events", "crates/events-apigen", @@ -85,6 +86,7 @@ exclude = [ webrogue-aot-compiler = { path = "crates/aot-compiler", default-features=false } webrogue-aot-data = { path = "crates/aot-data" } webrogue-cli = { path = "crates/cli" } +webrogue-cli-goodies = { path = "crates/cli-goodies" } webrogue-events = { path = "crates/events" } webrogue-events-macro = { path = "crates/events-macro" } webrogue-debugger = { path = "crates/debugger" } @@ -142,7 +144,7 @@ rustix = { version = "1.0.8", default-features = false } cfg_aliases = { version = "0.2.1" } windows-sys = { version = "0.61.2", default-features = false } windows = { version = "0.62.2", default-features = false } -wry = { version = "0.55", default-features = false } +wry = { version = "0.54", default-features = false } tao = { version = "0.34.5", default-features = false } winit = { version = "0.31.0-beta.2", default-features = false } winit-android = { version = "0.31.0-beta.2", default-features = false } @@ -180,7 +182,6 @@ wasm-bindgen-futures = "0.4" web-sys = "0.3.91" parking_lot = "0.12.5" getrandom = { version = "0.4.2", default-features = false } -cap-rand = { version = "3.4.5", features = ["small_rng"] } reqwest = { version = "0.13" } zip-extract = { version = "0.4.1" } wasm_thread = { git = "https://github.com/webrogue-runtime/wasm_thread.git", rev = "daa98f6", default-features = false } @@ -193,6 +194,7 @@ crossterm = "0.29" spinners = "4.2.0" headers = "0.4" axum-extra = { version = "0.12" } +rustls = { version = "0.23", default-features = false } [profile.dev] panic = "abort" @@ -219,10 +221,18 @@ strip = "debuginfo" inherits = "release" debug = true +[profile.dev.package.hashbrown] +opt-level = 3 +codegen-units = 1 + [profile.dev.package.cranelift-codegen] opt-level = 3 codegen-units = 1 +[profile.dev.package.regalloc2] +opt-level = 3 +codegen-units = 1 + [profile.dev.package.gimli] opt-level = 3 codegen-units = 1 diff --git a/android/runtime/build_native_code.sh b/android/runtime/build_native_code.sh index 7a281400..ec2863f9 100644 --- a/android/runtime/build_native_code.sh +++ b/android/runtime/build_native_code.sh @@ -17,8 +17,8 @@ rm -rf runner/src/main/jniLibs cargo install cargo-ndk # CARGO_TARGET_VAR="-C link-arg=-Wl,--no-allow-shlib-undefined -C link-arg=-Wl,--no-undefined" -# export CARGO_TARGET_AARCH64_LINUX_ANDROID_RUSTFLAGS="$CARGO_TARGET_VAR" -# export CARGO_TARGET_X86_64_LINUX_ANDROID_RUSTFLAGS="$CARGO_TARGET_VAR" +# export CARGO_TARGET_AARCH64_LINUX_ANDROID_RUSTFLAGS="$CARGO_TARGET_VAR" +# export CARGO_TARGET_X86_64_LINUX_ANDROID_RUSTFLAGS="$CARGO_TARGET_VAR" # rm -f ../process_dump/p.* # STRACE_COMMAND="strace -s 1000 -o ../process_dump/p -ff" diff --git a/android/runtime/launcher/src/lib.rs b/android/runtime/launcher/src/lib.rs index 0b193e10..1e63f10b 100644 --- a/android/runtime/launcher/src/lib.rs +++ b/android/runtime/launcher/src/lib.rs @@ -1,7 +1,3 @@ -use jni::{ - objects::{JClass, JString}, - JNIEnv, -}; use lazy_static::lazy_static; use std::{ path::PathBuf, @@ -12,9 +8,7 @@ use tao::{ event_loop::{ControlFlow, EventLoop, EventLoopProxy, EventLoopWindowTarget}, window::WindowBuilder, }; -use tokio::io::AsyncRead; use webrogue_launcher::{LauncherConfig, MailboxInternal}; -use webrogue_wrapp::RealVFSBuilder; use wry::WebView; #[cfg(target_os = "android")] @@ -146,11 +140,12 @@ lazy_static! { Mutex::new(None); } +#[cfg(target_os = "android")] #[no_mangle] unsafe extern "C" fn Java_dev_webrogue_launcher_DebugEventBroadcastReceiver_onData<'local>( - mut env: JNIEnv<'local>, - class: JClass<'local>, - data: JString, + mut env: jni::JNIEnv<'local>, + class: jni::objects::JClass<'local>, + data: jni::objects::JString, ) { let data = env.get_string(&data).unwrap().to_str().unwrap().to_owned(); SDP_ANSWER_SENDER diff --git a/apple/runtime/ios/runner/aot.arm64.iphoneos.o b/apple/runtime/ios/runner/aot.arm64.iphoneos.o index 068e5d92..f12e0f8a 100644 Binary files a/apple/runtime/ios/runner/aot.arm64.iphoneos.o and b/apple/runtime/ios/runner/aot.arm64.iphoneos.o differ diff --git a/apple/runtime/ios/runner/aot.arm64.iphonesimulator.o b/apple/runtime/ios/runner/aot.arm64.iphonesimulator.o index d84956f3..7c92a190 100644 Binary files a/apple/runtime/ios/runner/aot.arm64.iphonesimulator.o and b/apple/runtime/ios/runner/aot.arm64.iphonesimulator.o differ diff --git a/apple/runtime/ios/runner/aot.x86_64.iphonesimulator.o b/apple/runtime/ios/runner/aot.x86_64.iphonesimulator.o index f3c1293c..116e8f9f 100644 Binary files a/apple/runtime/ios/runner/aot.x86_64.iphonesimulator.o and b/apple/runtime/ios/runner/aot.x86_64.iphonesimulator.o differ diff --git a/apple/runtime/macos/runner/aot.arm64.macosx.o b/apple/runtime/macos/runner/aot.arm64.macosx.o index ac3bcdf6..f193852f 100644 Binary files a/apple/runtime/macos/runner/aot.arm64.macosx.o and b/apple/runtime/macos/runner/aot.arm64.macosx.o differ diff --git a/apple/runtime/macos/runner/aot.x86_64.macosx.o b/apple/runtime/macos/runner/aot.x86_64.macosx.o index c49093f8..8741ae25 100644 Binary files a/apple/runtime/macos/runner/aot.x86_64.macosx.o and b/apple/runtime/macos/runner/aot.x86_64.macosx.o differ diff --git a/crates/aot-compiler/Cargo.toml b/crates/aot-compiler/Cargo.toml index f208b548..5b1ac96b 100644 --- a/crates/aot-compiler/Cargo.toml +++ b/crates/aot-compiler/Cargo.toml @@ -22,3 +22,5 @@ wasmtime-environ = { workspace = true, default-features = false } postcard = { workspace = true, default-features = false, features = ['alloc'] } serde = { workspace = true, features = ['derive'] } zip = { workspace = true, default-features = false, features = ['deflate'] } +webrogue-cli-goodies = { workspace = true } +semver = { workspace = true, default-features = false } diff --git a/crates/aot-compiler/src/android/gradle/icons.rs b/crates/aot-compiler/src/android/gradle/icons.rs index 2e9b4906..11bf153d 100644 --- a/crates/aot-compiler/src/android/gradle/icons.rs +++ b/crates/aot-compiler/src/android/gradle/icons.rs @@ -1,3 +1,5 @@ +use webrogue_cli_goodies::step; + pub fn build( build_dir: &std::path::Path, vfs_builder: &mut VFSBuilder, @@ -5,7 +7,9 @@ pub fn build( ) -> anyhow::Result { let new_stamp = webrogue_icons::IconsData::from_vfs_builder(vfs_builder)?; if old_stamp != Some(&new_stamp) { - webrogue_icons::android::generate_icons(build_dir, &new_stamp)?; + step("Generating icons".to_owned(), || { + webrogue_icons::android::generate_icons(build_dir, &new_stamp) + })?; } Ok(new_stamp) } diff --git a/crates/aot-compiler/src/android/gradle/mod.rs b/crates/aot-compiler/src/android/gradle/mod.rs index d25d59a3..c02de337 100644 --- a/crates/aot-compiler/src/android/gradle/mod.rs +++ b/crates/aot-compiler/src/android/gradle/mod.rs @@ -1,5 +1,8 @@ use anyhow::Context as _; +use semver::Version; use std::io::Write; +use webrogue_cli_goodies::{note, step, warning}; +use webrogue_wrapp::config::Config; mod icons; mod types; @@ -15,6 +18,49 @@ pub enum Signing { }, } +#[allow(clippy::too_many_arguments)] +pub fn build( + sdk_env: Option<&std::path::PathBuf>, + java_home_env: Option<&std::path::PathBuf>, + container_path: &std::path::PathBuf, + build_dir: &std::path::PathBuf, + signing: Signing, + debug: bool, + output: Option, + cache: Option<&std::path::PathBuf>, +) -> anyhow::Result<()> { + if webrogue_wrapp::is_path_a_wrapp(container_path).with_context(|| { + format!( + "Unable to determine file type for {}", + container_path.display() + ) + })? { + build_using_vfs( + || webrogue_wrapp::WrappVFSBuilder::from_file_path(container_path), + sdk_env, + java_home_env, + container_path, + build_dir, + signing, + debug, + output, + cache, + ) + } else { + build_using_vfs( + || webrogue_wrapp::RealVFSBuilder::from_config_path(container_path), + sdk_env, + java_home_env, + container_path, + build_dir, + signing, + debug, + output, + cache, + ) + } +} + #[allow(clippy::too_many_arguments)] fn build_using_vfs( vfs_builder_factory: impl Fn() -> anyhow::Result, @@ -28,6 +74,7 @@ fn build_using_vfs( cache: Option<&std::path::PathBuf>, ) -> anyhow::Result<()> { let mut vfs_builder = vfs_builder_factory()?; + let config = vfs_builder.config()?.clone(); let mut artifacts = crate::utils::Artifacts::new().with_context(|| "Error opening artifacts library")?; let template_id = artifacts.get_data("android_gradle/template_id")?; @@ -35,15 +82,18 @@ fn build_using_vfs( if old_stamp.as_ref().map(|stamp| &stamp.template_id) != Some(&template_id) { old_stamp = None; - println!("(Re)creating Android Gradle project..."); - if build_dir.exists() { - anyhow::ensure!(build_dir.is_dir(), "build_dir can't be a file"); - std::fs::remove_dir_all(build_dir)?; // TODO we need to somehow ensure user doesn't removes something important - } - artifacts.extract_dir(build_dir, "android_gradle/template")?; + + step("(Re)creating Android Gradle project".to_owned(), || { + if build_dir.exists() { + anyhow::ensure!(build_dir.is_dir(), "build_dir can't be a file"); + std::fs::remove_dir_all(build_dir)?; // TODO we need to somehow ensure user doesn't removes something important + } + artifacts.extract_dir(build_dir, "android_gradle/template")?; + anyhow::Ok(()) + })?; } - let object_file = crate::utils::TemporalFile::for_tmp_object(build_dir.join("aarch64"))?; + let object_file = crate::utils::TemporaryFile::for_tmp_object(build_dir.join("aarch64"))?; let assets_path = build_dir .join("app") @@ -53,11 +103,12 @@ fn build_using_vfs( if !std::fs::exists(assets_path.clone())? { std::fs::create_dir(assets_path.clone())?; }; - println!("Generating stripped WRAPP file..."); - let version = vfs_builder.config()?.version.clone(); - - webrogue_wrapp::WRAPPWriter::new(vfs_builder_factory()?) - .write(&mut std::fs::File::create(assets_path.join("aot.swrapp"))?)?; + let version = config.version.clone(); + step("Generating stripped WRAPP file".to_owned(), || { + webrogue_wrapp::WRAPPWriter::new(vfs_builder_factory()?) + .write(&mut std::fs::File::create(assets_path.join("aot.swrapp"))?)?; + anyhow::Ok(()) + })?; let icons_stamp = icons::build( build_dir, @@ -65,30 +116,66 @@ fn build_using_vfs( old_stamp.as_ref().map(|stamp| &stamp.icons), )?; - println!("Compiling AOT object..."); - crate::compile::compile_wrapp_to_object( - container_path, - object_file.path(), - crate::Target::ARM64LinuxAndroid, - cache, - true, - true, - )?; + step("Compiling AOT object".to_owned(), || { + crate::compile::compile_wrapp_to_object( + container_path, + object_file.path(), + crate::Target::ARM64LinuxAndroid, + cache, + true, + true, + ) + })?; - crate::android::link::link( - &object_file, - crate::Target::ARM64LinuxAndroid, - &build_dir - .join("app") - .join("src") - .join("main") - .join("jniLibs") - .join("arm64-v8a") - .join("libwebrogue_aot.so"), - )?; + step("Linking native library".to_owned(), || { + crate::android::link::link( + &object_file, + crate::Target::ARM64LinuxAndroid, + &build_dir + .join("app") + .join("src") + .join("main") + .join("jniLibs") + .join("arm64-v8a") + .join("libwebrogue_aot.so"), + ) + })?; drop(object_file); - println!("Building Android project..."); + let copied_apk_dir = step("Building Android project".to_owned(), || { + gradle_build( + sdk_env, + java_home_env, + build_dir, + signing, + debug, + output, + config, + version, + ) + })?; + note(&format!("APK saved to {}", copied_apk_dir.display())); + + let new_stamp = types::Stamp { + template_id, + icons: icons_stamp, + }; + if old_stamp.as_ref() != Some(&new_stamp) { + write_stamp(new_stamp, build_dir)?; + } + Ok(()) +} + +fn gradle_build( + sdk_env: Option<&std::path::PathBuf>, + java_home_env: Option<&std::path::PathBuf>, + build_dir: &std::path::PathBuf, + signing: Signing, + debug: bool, + output: Option, + config: Config, + version: Version, +) -> anyhow::Result { #[cfg(target_os = "windows")] let (gradle_shell, gradle_script) = ("cmd", "gradlew.bat"); #[cfg(not(target_os = "windows"))] @@ -112,12 +199,12 @@ fn build_using_vfs( set_gradle_property( &mut properties_file, "webrogueApplicationId", - vfs_builder.config()?.id.to_ascii_lowercase(), + config.id.to_ascii_lowercase(), )?; set_gradle_property( &mut properties_file, "webrogueApplicationName", - vfs_builder.config()?.name.clone(), + config.name.clone(), )?; if let Signing::Signed { keystore_path, @@ -140,9 +227,9 @@ fn build_using_vfs( set_gradle_property(&mut properties_file, "webrogueKeyPassword", key_password)?; set_gradle_property(&mut properties_file, "webrogueKeyAlias", key_alias)?; } else if !debug { - eprintln!( - "warning: Using debug signature. Specify --keystore-path, --store-password, --key-password & --key-alias arguments to use release signature", - ); + warning( + "warning: Using debug signature. Specify --keystore-path, --store-password, --key-password & --key-alias arguments to use release signature", + ); } drop(properties_file); let mut command = std::process::Command::new(gradle_shell); @@ -195,7 +282,7 @@ fn build_using_vfs( } }; - let output_apk_filename = vfs_builder.config()?.name.clone().replace(' ', "_") + ".apk"; + let output_apk_filename = config.name.clone().replace(' ', "_") + ".apk"; let copied_apk_dir = if let Some(output) = output { if output.is_dir() { @@ -207,59 +294,7 @@ fn build_using_vfs( build_dir.join(output_apk_filename) }; std::fs::rename(gradle_apk_path, &copied_apk_dir)?; - println!("APK saved to {}", copied_apk_dir.display()); - - let new_stamp = types::Stamp { - template_id, - icons: icons_stamp, - }; - if old_stamp.as_ref() != Some(&new_stamp) { - write_stamp(new_stamp, build_dir)?; - } - Ok(()) -} - -#[allow(clippy::too_many_arguments)] -pub fn build( - sdk_env: Option<&std::path::PathBuf>, - java_home_env: Option<&std::path::PathBuf>, - container_path: &std::path::PathBuf, - build_dir: &std::path::PathBuf, - signing: Signing, - debug: bool, - output: Option, - cache: Option<&std::path::PathBuf>, -) -> anyhow::Result<()> { - if webrogue_wrapp::is_path_a_wrapp(container_path).with_context(|| { - format!( - "Unable to determine file type for {}", - container_path.display() - ) - })? { - build_using_vfs( - || webrogue_wrapp::WrappVFSBuilder::from_file_path(container_path), - sdk_env, - java_home_env, - container_path, - build_dir, - signing, - debug, - output, - cache, - ) - } else { - build_using_vfs( - || webrogue_wrapp::RealVFSBuilder::from_config_path(container_path), - sdk_env, - java_home_env, - container_path, - build_dir, - signing, - debug, - output, - cache, - ) - } + anyhow::Ok(copied_apk_dir) } fn read_stamp(build_dir: &std::path::Path) -> anyhow::Result { diff --git a/crates/aot-compiler/src/android/link.rs b/crates/aot-compiler/src/android/link.rs index a109ab8e..60a9f15c 100644 --- a/crates/aot-compiler/src/android/link.rs +++ b/crates/aot-compiler/src/android/link.rs @@ -1,7 +1,7 @@ use crate::utils::path_to_arg; pub fn link( - object_file: &crate::utils::TemporalFile, + object_file: &crate::utils::TemporaryFile, target: crate::Target, output_path: &std::path::PathBuf, ) -> anyhow::Result<()> { diff --git a/crates/aot-compiler/src/cli.rs b/crates/aot-compiler/src/cli.rs index dfcba43a..29b2a14b 100644 --- a/crates/aot-compiler/src/cli.rs +++ b/crates/aot-compiler/src/cli.rs @@ -63,7 +63,7 @@ pub enum Commands { /// Don't add vk_swiftshader.dll. /// SwiftShader is used as a fallback renderer on system that have no Vulkan drivers installed. /// Webrogue places SwiftShader in the same directory resulting executable is in. - /// It's recommended to keep SwiftShader in most cases, but you can use this option to skip this + /// It's recommended to keep SwiftShader in most cases, but you can use this option to skip this /// step, so you app will fail to start if hardware-accelerated rendering is unavailable. #[arg(long)] no_swiftshader: bool, @@ -118,7 +118,7 @@ impl Commands { target, } => { let target = crate::Target::from_name(target)?; - let object_file = crate::utils::TemporalFile::for_tmp_object(out_path)?; + let object_file = crate::utils::TemporaryFile::for_tmp_object(out_path)?; crate::compile::compile_wrapp_to_object( wrapp_path, object_file.path(), diff --git a/crates/aot-compiler/src/linux/link.rs b/crates/aot-compiler/src/linux/link.rs index da0cac51..b96bf8d5 100644 --- a/crates/aot-compiler/src/linux/link.rs +++ b/crates/aot-compiler/src/linux/link.rs @@ -1,7 +1,7 @@ #[allow(unreachable_code)] #[allow(unused_variables)] pub fn link_musl( - object_file: &crate::utils::TemporalFile, + object_file: &crate::utils::TemporaryFile, output_file_path: &std::path::PathBuf, vulkan: bool, ) -> anyhow::Result<()> { @@ -59,7 +59,7 @@ pub fn link_musl( } pub fn link_glibc( - object_file: &crate::utils::TemporalFile, + object_file: &crate::utils::TemporaryFile, output_file_path: &std::path::PathBuf, vulkan: bool, ) -> anyhow::Result<()> { diff --git a/crates/aot-compiler/src/linux/mod.rs b/crates/aot-compiler/src/linux/mod.rs index 61e66eed..f085b75d 100644 --- a/crates/aot-compiler/src/linux/mod.rs +++ b/crates/aot-compiler/src/linux/mod.rs @@ -3,6 +3,7 @@ mod link; use std::io::{Seek, Write}; use anyhow::Context as _; +use webrogue_cli_goodies::step; use crate::utils::extract_config; @@ -30,70 +31,74 @@ pub fn build_linux( libc: LibC, cache: Option<&std::path::PathBuf>, ) -> anyhow::Result<()> { - let object_file = crate::utils::TemporalFile::for_tmp_object(output_file_path)?; + let object_file = crate::utils::TemporaryFile::for_tmp_object(output_file_path)?; let config = extract_config(wrapp_file_path)?; let vulkan = config.vulkan_requirement().to_bool_option().unwrap_or(true); match libc { LibC::GLibC => { - println!("Compiling AOT object..."); - crate::compile::compile_wrapp_to_object( - wrapp_file_path, - object_file.path(), - crate::Target::X86_64LinuxGNU, - cache, - false, - false, - )?; - - println!("Linking native binary..."); - link::link_glibc(&object_file, output_file_path, vulkan)?; + step("Compiling AOT object".to_owned(), || { + crate::compile::compile_wrapp_to_object( + wrapp_file_path, + object_file.path(), + crate::Target::X86_64LinuxGNU, + cache, + false, + false, + ) + })?; + step("Linking native binary".to_owned(), || { + link::link_glibc(&object_file, output_file_path, vulkan) + })?; } LibC::Musl => { - println!("Compiling AOT object..."); - crate::compile::compile_wrapp_to_object( - wrapp_file_path, - object_file.path(), - crate::Target::X86_64LinuxMUSL, - cache, - true, - false, - )?; - - println!("Linking native binary..."); - link::link_musl(&object_file, output_file_path, vulkan)?; + step("Compiling AOT object".to_owned(), || { + crate::compile::compile_wrapp_to_object( + wrapp_file_path, + object_file.path(), + crate::Target::X86_64LinuxMUSL, + cache, + true, + false, + ) + })?; + step("Linking native binary".to_owned(), || { + link::link_musl(&object_file, output_file_path, vulkan) + })?; } } drop(object_file); - println!("Embedding stripped WRAPP file..."); - let mut output_file: std::fs::File = std::fs::OpenOptions::new() - .append(true) - .create(false) - .open(output_file_path)?; + step("Embedding stripped WRAPP file".to_owned(), || { + let mut output_file: std::fs::File = std::fs::OpenOptions::new() + .append(true) + .create(false) + .open(output_file_path)?; - let original_size = output_file.seek(std::io::SeekFrom::End(0))?; + let original_size = output_file.seek(std::io::SeekFrom::End(0))?; - if webrogue_wrapp::is_path_a_wrapp(wrapp_file_path).with_context(|| { - format!( - "Unable to determine file type for {}", - wrapp_file_path.display() - ) - })? { - webrogue_wrapp::WRAPPWriter::new(webrogue_wrapp::WrappVFSBuilder::from_file_path( - wrapp_file_path, - )?) - .write(&mut output_file)?; - } else { - webrogue_wrapp::WRAPPWriter::new(webrogue_wrapp::RealVFSBuilder::from_config_path( - wrapp_file_path, - )?) - .write(&mut output_file)?; - } - let new_size = output_file.seek(std::io::SeekFrom::End(0))?; + if webrogue_wrapp::is_path_a_wrapp(wrapp_file_path).with_context(|| { + format!( + "Unable to determine file type for {}", + wrapp_file_path.display() + ) + })? { + webrogue_wrapp::WRAPPWriter::new(webrogue_wrapp::WrappVFSBuilder::from_file_path( + wrapp_file_path, + )?) + .write(&mut output_file)?; + } else { + webrogue_wrapp::WRAPPWriter::new(webrogue_wrapp::RealVFSBuilder::from_config_path( + wrapp_file_path, + )?) + .write(&mut output_file)?; + } + let new_size = output_file.seek(std::io::SeekFrom::End(0))?; - let wrapp_size: u64 = new_size - original_size; - output_file.write_all(&wrapp_size.to_le_bytes())?; + let wrapp_size: u64 = new_size - original_size; + output_file.write_all(&wrapp_size.to_le_bytes())?; + anyhow::Ok(()) + })?; anyhow::Ok(()) } diff --git a/crates/aot-compiler/src/utils/artifacts.rs b/crates/aot-compiler/src/utils/artifacts.rs index 59984122..3fca237c 100644 --- a/crates/aot-compiler/src/utils/artifacts.rs +++ b/crates/aot-compiler/src/utils/artifacts.rs @@ -41,8 +41,8 @@ impl Artifacts { &mut self, base_path: P, file: &str, - ) -> anyhow::Result { - let result = super::TemporalFile::for_tmp(base_path.as_ref(), file.replace("/", "_"))?; + ) -> anyhow::Result { + let result = super::TemporaryFile::for_tmp(base_path.as_ref(), file.replace("/", "_"))?; self.inner .extract(result.path(), file) .with_context(|| format!("Unable to extract {} from archive", file))?; diff --git a/crates/aot-compiler/src/utils/mod.rs b/crates/aot-compiler/src/utils/mod.rs index 958acdf8..1b12afc2 100644 --- a/crates/aot-compiler/src/utils/mod.rs +++ b/crates/aot-compiler/src/utils/mod.rs @@ -20,11 +20,11 @@ macro_rules! lld { pub(crate) use lld; use webrogue_wrapp::{config::Config, IVFSBuilder as _}; -pub struct TemporalFile { +pub struct TemporaryFile { path: std::path::PathBuf, } -impl TemporalFile { +impl TemporaryFile { pub fn for_tmp_object>(base_path: P) -> anyhow::Result { Ok(Self { path: base_path @@ -65,7 +65,7 @@ impl TemporalFile { } } -impl Display for TemporalFile { +impl Display for TemporaryFile { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, @@ -75,7 +75,7 @@ impl Display for TemporalFile { } } -impl Drop for TemporalFile { +impl Drop for TemporaryFile { fn drop(&mut self) { let _ = std::fs::remove_file(&self.path); } diff --git a/crates/aot-compiler/src/windows/mingw.rs b/crates/aot-compiler/src/windows/mingw.rs deleted file mode 100644 index c6a4abc1..00000000 --- a/crates/aot-compiler/src/windows/mingw.rs +++ /dev/null @@ -1,63 +0,0 @@ -// No MinGW support, sorry - -pub fn build( - wrapp_file_path: &std::path::PathBuf, - output_file_path: &std::path::PathBuf, -) -> anyhow::Result<()> { - let object_file = crate::utils::TemporalFile::for_tmp_object(output_file_path)?; - let copied_wrapp_path = output_file_path - .parent() - .ok_or(anyhow::anyhow!("Path error"))? - .join("aot.wrapp"); - - crate::compile::compile_wrapp_to_object( - wrapp_file_path, - object_file.path(), - crate::Target::x86_64WindowsGNU, - false, // TODO check - )?; - - link(&object_file, output_file_path)?; - drop(object_file); - - std::fs::copy(wrapp_file_path, copied_wrapp_path)?; - std::fs::copy( - "aot_artifacts/x86_64-windows-gnu/libEGL.dll", - output_file_path - .parent() - .ok_or(anyhow::anyhow!("Path error"))? - .join("libEGL.dll"), - )?; - std::fs::copy( - "aot_artifacts/x86_64-windows-gnu/libGLESv2.dll", - output_file_path - .parent() - .ok_or(anyhow::anyhow!("Path error"))? - .join("libGLESv2.dll"), - )?; - - anyhow::Ok(()) -} - -fn link( - object_file_path: &crate::utils::TemporalFile, - output_file_path: &std::path::PathBuf, -) -> anyhow::Result<()> { - use crate::utils::path_to_arg; - - crate::utils::lld!( - "ld.lld", - "-m", - "i386pep", - "-Bdynamic", - "-o", - path_to_arg(&output_file_path)?, - // "--stack=16777216", - "aot_artifacts/x86_64-windows-gnu/crt2.o", - "aot_artifacts/x86_64-windows-gnu/crtbegin.o", - "aot_artifacts/x86_64-windows-gnu/main.o", - "aot_artifacts/x86_64-windows-gnu/libwebrogue_aot_lib.a", - object_file_path, - "aot_artifacts/x86_64-windows-gnu/crtend.o", - ) -} diff --git a/crates/aot-compiler/src/windows/mod.rs b/crates/aot-compiler/src/windows/mod.rs index eb099974..d8fda050 100644 --- a/crates/aot-compiler/src/windows/mod.rs +++ b/crates/aot-compiler/src/windows/mod.rs @@ -1,8 +1,9 @@ use std::io::{Seek as _, Write as _}; use anyhow::Context as _; +use webrogue_cli_goodies::step; -use crate::utils::TemporalFile; +use crate::utils::TemporaryFile; pub fn build( wrapp_file_path: &std::path::PathBuf, @@ -48,18 +49,19 @@ fn build_using_vfs( let mut vfs_builder = vfs_builder_factory()?; let config = vfs_builder.config()?.clone(); let icons_config = webrogue_icons::IconsData::from_vfs_builder(&mut vfs_builder)?; - let object_file = crate::utils::TemporalFile::for_tmp_object(output_file_path)?; + let object_file = crate::utils::TemporaryFile::for_tmp_object(output_file_path)?; let vulkan = config.vulkan_requirement().to_bool_option().unwrap_or(true); - println!("Compiling AOT object..."); - crate::compile::compile_wrapp_to_object( - wrapp_file_path, - object_file.path(), - crate::Target::x86_64WindowsMSVC, - cache, - false, // TODO check - false, - )?; + step("Compiling AOT object".to_owned(), || { + crate::compile::compile_wrapp_to_object( + wrapp_file_path, + object_file.path(), + crate::Target::x86_64WindowsMSVC, + cache, + false, // TODO check + false, + ) + })?; let mut artifacts = crate::utils::Artifacts::new()?; let build_dir = output_file_path @@ -67,51 +69,56 @@ fn build_using_vfs( .ok_or_else(|| anyhow::anyhow!("Path error"))? .to_path_buf(); - println!("Generating icon..."); - let res_tmp = TemporalFile::for_tmp(&build_dir, "resources.res".to_string())?; - webrogue_icons::windows::generate_res(icons_config.clone(), &mut res_tmp.create_file()?)?; - - println!("Linking native binary..."); - link_windows_msvc( - &object_file, - output_file_path, - &mut artifacts, - &build_dir, - res_tmp.path(), - is_console, - vulkan, - )?; + let res_tmp = step("Generating icon".to_owned(), || { + let res_tmp = TemporaryFile::for_tmp(&build_dir, "resources.res".to_string())?; + webrogue_icons::windows::generate_res(icons_config.clone(), &mut res_tmp.create_file()?)?; + anyhow::Ok(res_tmp) + })?; + + step("Linking native binary".to_owned(), || { + link_windows_msvc( + &object_file, + output_file_path, + &mut artifacts, + &build_dir, + res_tmp.path(), + is_console, + vulkan, + ) + })?; drop(object_file); - println!("Embedding stripped WRAPP file..."); - let mut output_file: std::fs::File = std::fs::OpenOptions::new() - .append(true) - .create(false) - .open(output_file_path)?; + step("Embedding stripped WRAPP file".to_owned(), || { + let mut output_file: std::fs::File = std::fs::OpenOptions::new() + .append(true) + .create(false) + .open(output_file_path)?; - let original_size = output_file.seek(std::io::SeekFrom::End(0))?; + let original_size = output_file.seek(std::io::SeekFrom::End(0))?; - webrogue_wrapp::WRAPPWriter::new(vfs_builder).write(&mut output_file)?; + webrogue_wrapp::WRAPPWriter::new(vfs_builder).write(&mut output_file)?; - let new_size = output_file.seek(std::io::SeekFrom::End(0))?; + let new_size = output_file.seek(std::io::SeekFrom::End(0))?; - let wrapp_size = new_size - original_size; - output_file.write_all(&wrapp_size.to_le_bytes())?; - if with_swiftshader && vulkan { - artifacts.extract( - std::path::absolute(output_file_path)? - .parent() - .ok_or_else(|| anyhow::anyhow!("Path error"))? - .join("vk_swiftshader.dll"), - "x86_64-windows-msvc/vk_swiftshader.dll", - )?; - } + let wrapp_size = new_size - original_size; + output_file.write_all(&wrapp_size.to_le_bytes())?; + if with_swiftshader && vulkan { + artifacts.extract( + std::path::absolute(output_file_path)? + .parent() + .ok_or_else(|| anyhow::anyhow!("Path error"))? + .join("vk_swiftshader.dll"), + "x86_64-windows-msvc/vk_swiftshader.dll", + )?; + } + anyhow::Ok(()) + })?; anyhow::Ok(()) } fn link_windows_msvc( - object_file_path: &crate::utils::TemporalFile, + object_file_path: &crate::utils::TemporaryFile, output_file_path: &std::path::Path, artifacts: &mut crate::utils::Artifacts, build_dir: &std::path::Path, diff --git a/crates/aot-compiler/src/xcode/build.rs b/crates/aot-compiler/src/xcode/build.rs index 798a4269..6081b6c9 100644 --- a/crates/aot-compiler/src/xcode/build.rs +++ b/crates/aot-compiler/src/xcode/build.rs @@ -1,3 +1,5 @@ +use webrogue_cli_goodies::step; + use super::types::{Configuration, Destination}; use std::io::BufRead as _; @@ -7,114 +9,115 @@ pub fn build( destination: Destination, wrapp_builder: &mut impl webrogue_wrapp::IVFSBuilder, ) -> anyhow::Result<()> { - let configuration_name = match configuration { - Configuration::Debug => "Debug", - Configuration::Release => "Release", - Configuration::ReleaseLocal => "ReleaseLocal", - }; - let scheme_destination_name = match destination { - Destination::MacOS => "MacOS", - Destination::Ios | Destination::IOSSim => "iOS", - }; + let message = step("Building Xcode project".to_owned(), || { + let configuration_name = match configuration { + Configuration::Debug => "Debug", + Configuration::Release => "Release", + Configuration::ReleaseLocal => "ReleaseLocal", + }; + let scheme_destination_name = match destination { + Destination::MacOS => "MacOS", + Destination::Ios | Destination::IOSSim => "iOS", + }; - println!("Building Xcode project..."); - let mut build_settings_command = std::process::Command::new("xcodebuild"); - let mut xcbuild_command = std::process::Command::new("xcodebuild"); - for command in [&mut build_settings_command, &mut xcbuild_command] { - command - .arg("-project") - .arg(build_dir.join("webrogue.xcodeproj")) - .arg("-scheme") - .arg(format!( - "{}_{}", - scheme_destination_name, configuration_name - )) - .arg("-configuration") - .arg(configuration_name); - match destination { - Destination::MacOS => {} - Destination::Ios => { - command.arg("-destination").arg("generic/platform=iOS"); - } - Destination::IOSSim => { - command - .arg("-destination") - .arg("generic/platform=iOS Simulator"); + let mut build_settings_command = std::process::Command::new("xcodebuild"); + let mut xcbuild_command = std::process::Command::new("xcodebuild"); + for command in [&mut build_settings_command, &mut xcbuild_command] { + command + .arg("-project") + .arg(build_dir.join("webrogue.xcodeproj")) + .arg("-scheme") + .arg(format!( + "{}_{}", + scheme_destination_name, configuration_name + )) + .arg("-configuration") + .arg(configuration_name); + match destination { + Destination::MacOS => {} + Destination::Ios => { + command.arg("-destination").arg("generic/platform=iOS"); + } + Destination::IOSSim => { + command + .arg("-destination") + .arg("generic/platform=iOS Simulator"); + } } } - } - let build_settings_output = build_settings_command.arg("-showBuildSettings").output()?; - anyhow::ensure!( - build_settings_output.status.success(), - "Xcodebuild failed with exit code {}.\n\nStdout: {}\n\nStderr: {}", - build_settings_output - .status - .code() - .map(|code| format!("{}", code)) - .unwrap_or_else(|| "unknown".to_owned()), - std::str::from_utf8(&build_settings_output.stdout)?, - std::str::from_utf8(&build_settings_output.stderr)? - ); - let build_settings_dir = build_settings_output - .stdout - .lines() - .map(|l| l.unwrap().trim_start().to_owned()) - .find(|line| line.find("BUILD_DIR = ") == Some(0)) - .ok_or_else(|| anyhow::anyhow!("BUILD_DIR value not found in xcodebuild output"))? - .strip_prefix("BUILD_DIR = ") - .unwrap() - .to_owned(); + let build_settings_output = build_settings_command.arg("-showBuildSettings").output()?; + anyhow::ensure!( + build_settings_output.status.success(), + "Xcodebuild failed with exit code {}.\n\nStdout: {}\n\nStderr: {}", + build_settings_output + .status + .code() + .map(|code| format!("{}", code)) + .unwrap_or_else(|| "unknown".to_owned()), + std::str::from_utf8(&build_settings_output.stdout)?, + std::str::from_utf8(&build_settings_output.stderr)? + ); + let build_settings_dir = build_settings_output + .stdout + .lines() + .map(|l| l.unwrap().trim_start().to_owned()) + .find(|line| line.find("BUILD_DIR = ") == Some(0)) + .ok_or_else(|| anyhow::anyhow!("BUILD_DIR value not found in xcodebuild output"))? + .strip_prefix("BUILD_DIR = ") + .unwrap() + .to_owned(); - let appdir_filename = wrapp_builder.config()?.name.clone() + ".app"; + let appdir_filename = wrapp_builder.config()?.name.clone() + ".app"; - let product_dir_name = match destination { - Destination::MacOS => configuration_name.to_owned(), - Destination::Ios => configuration_name.to_owned() + "-iphoneos", - Destination::IOSSim => configuration_name.to_owned() + "-iphonesimulator", - }; + let product_dir_name = match destination { + Destination::MacOS => configuration_name.to_owned(), + Destination::Ios => configuration_name.to_owned() + "-iphoneos", + Destination::IOSSim => configuration_name.to_owned() + "-iphonesimulator", + }; - let built_appdir_path = std::path::PathBuf::from(build_settings_dir) - .join(product_dir_name) - .join(&appdir_filename); + let built_appdir_path = std::path::PathBuf::from(build_settings_dir) + .join(product_dir_name) + .join(&appdir_filename); - let xcodebuild_output = xcbuild_command.output()?; - anyhow::ensure!( - xcodebuild_output.status.success(), - "Xcodebuild failed with exit code {}.\n\nStdout: {}\n\nStderr: {}", - xcodebuild_output - .status - .code() - .map(|code| format!("{}", code)) - .unwrap_or_else(|| "unknown".to_owned()), - std::str::from_utf8(&xcodebuild_output.stdout)?, - std::str::from_utf8(&xcodebuild_output.stderr)? - ); + let xcodebuild_output = xcbuild_command.output()?; + anyhow::ensure!( + xcodebuild_output.status.success(), + "Xcodebuild failed with exit code {}.\n\nStdout: {}\n\nStderr: {}", + xcodebuild_output + .status + .code() + .map(|code| format!("{}", code)) + .unwrap_or_else(|| "unknown".to_owned()), + std::str::from_utf8(&xcodebuild_output.stdout)?, + std::str::from_utf8(&xcodebuild_output.stderr)? + ); - anyhow::ensure!( - built_appdir_path.is_dir(), - "Built app not found at {}", - built_appdir_path.display() - ); + anyhow::ensure!( + built_appdir_path.is_dir(), + "Built app not found at {}", + built_appdir_path.display() + ); - let output_appdir = build_dir.join(&appdir_filename); + let output_appdir = build_dir.join(&appdir_filename); - if output_appdir.is_dir() { - std::fs::remove_dir_all(&output_appdir)?; - } - std::fs::rename(built_appdir_path, &output_appdir)?; - - let pretty_destination_name = match destination { - Destination::MacOS => "macOS", - Destination::Ios => "iOS", - Destination::IOSSim => "iOS Simulator", - }; + if output_appdir.is_dir() { + std::fs::remove_dir_all(&output_appdir)?; + } + std::fs::rename(built_appdir_path, &output_appdir)?; - println!( - "{} app saved to {}", - pretty_destination_name, - output_appdir.display() - ); + let pretty_destination_name = match destination { + Destination::MacOS => "macOS", + Destination::Ios => "iOS", + Destination::IOSSim => "iOS Simulator", + }; + anyhow::Ok(format!( + "{} app saved at '{}'", + pretty_destination_name, + output_appdir.display() + )) + })?; + webrogue_cli_goodies::note(&message); Ok(()) } diff --git a/crates/aot-compiler/src/xcode/icons.rs b/crates/aot-compiler/src/xcode/icons.rs index 610499f4..79ea75c5 100644 --- a/crates/aot-compiler/src/xcode/icons.rs +++ b/crates/aot-compiler/src/xcode/icons.rs @@ -1,3 +1,5 @@ +use webrogue_cli_goodies::step; + pub fn build( build_dir: &std::path::Path, wrapp_builder: &mut impl webrogue_wrapp::IVFSBuilder, @@ -5,7 +7,9 @@ pub fn build( ) -> anyhow::Result { let new_stamp = webrogue_icons::IconsData::from_vfs_builder(wrapp_builder)?; if old_stamp != Some(&new_stamp) { - webrogue_icons::xcode::generate_icons(build_dir, &new_stamp)?; + step("Generating icons".to_owned(), || { + webrogue_icons::xcode::generate_icons(build_dir, &new_stamp) + })?; } Ok(new_stamp) } diff --git a/crates/aot-compiler/src/xcode/mod.rs b/crates/aot-compiler/src/xcode/mod.rs index 8aa2f5c2..e8be3e1e 100644 --- a/crates/aot-compiler/src/xcode/mod.rs +++ b/crates/aot-compiler/src/xcode/mod.rs @@ -1,6 +1,7 @@ use anyhow::Context as _; use clap::Subcommand; use std::{fs::File, io::Write as _}; +use webrogue_cli_goodies::step; use webrogue_wrapp::config::Requirement; mod build; @@ -73,56 +74,58 @@ fn run_using_vfs( || old_config != Some(&wrapp_config) { old_stamp = None; - println!("(Re)generating Xcode project..."); - if args.build_dir.exists() { - anyhow::ensure!(args.build_dir.is_dir(), "build_dir can't be a file"); - std::fs::remove_dir_all(args.build_dir)?; // TODO we need to somehow ensure user doesn't removes something important - } - artifacts.extract_dir(args.build_dir, "apple_xcode/template")?; - - for platform in ["macos", "iphoneos", "iphonesimulator"] { - let is_vulkan_needed = wrapp_config - .vulkan_requirement() - .to_bool_option() - .unwrap_or(platform != "iphonesimulator"); - - let bin_dir = args.build_dir.join("bin").join(platform); - let impl_lib_name = "libGFXStreamImpl.a"; - let stub_lib_name = "libGFXStreamStub.a"; - let (used_lib_name, unused_lib_name) = if is_vulkan_needed { - (impl_lib_name, stub_lib_name) - } else { - (stub_lib_name, impl_lib_name) - }; - std::fs::rename(bin_dir.join(used_lib_name), bin_dir.join("libGFXStream.a"))?; - std::fs::remove_file(bin_dir.join(unused_lib_name))?; - } + step("(Re)generating Xcode project".to_owned(), || { + if args.build_dir.exists() { + anyhow::ensure!(args.build_dir.is_dir(), "build_dir can't be a file"); + std::fs::remove_dir_all(args.build_dir)?; // TODO we need to somehow ensure user doesn't removes something important + } + artifacts.extract_dir(args.build_dir, "apple_xcode/template")?; + + for platform in ["macos", "iphoneos", "iphonesimulator"] { + let is_vulkan_needed = wrapp_config + .vulkan_requirement() + .to_bool_option() + .unwrap_or(platform != "iphonesimulator"); + + let bin_dir = args.build_dir.join("bin").join(platform); + let impl_lib_name = "libGFXStreamImpl.a"; + let stub_lib_name = "libGFXStreamStub.a"; + let (used_lib_name, unused_lib_name) = if is_vulkan_needed { + (impl_lib_name, stub_lib_name) + } else { + (stub_lib_name, impl_lib_name) + }; + std::fs::rename(bin_dir.join(used_lib_name), bin_dir.join("libGFXStream.a"))?; + std::fs::remove_file(bin_dir.join(unused_lib_name))?; + } - if !is_simulator_supported { - std::fs::remove_dir_all(args.build_dir.join("bin").join("iphonesimulator"))?; - File::create(args.build_dir.join("bin").join("iphonesimulator"))? - .write_all(NO_VULKAN_ON_SIM_ERROR.as_bytes())?; - } + if !is_simulator_supported { + std::fs::remove_dir_all(args.build_dir.join("bin").join("iphonesimulator"))?; + File::create(args.build_dir.join("bin").join("iphonesimulator"))? + .write_all(NO_VULKAN_ON_SIM_ERROR.as_bytes())?; + } - let mut id_parts = wrapp_config - .id - .split(".") - .map(|s| s.to_owned()) - .collect::>(); + let mut id_parts = wrapp_config + .id + .split(".") + .map(|s| s.to_owned()) + .collect::>(); - let last_part = id_parts.last_mut().unwrap(); - let mut chars = (*last_part).chars().collect::>(); - *chars.first_mut().unwrap() = chars.first().unwrap().to_ascii_uppercase(); - *last_part = chars.iter().copied().collect(); - let id = id_parts.join("."); + let last_part = id_parts.last_mut().unwrap(); + let mut chars = (*last_part).chars().collect::>(); + *chars.first_mut().unwrap() = chars.first().unwrap().to_ascii_uppercase(); + *last_part = chars.iter().copied().collect(); + let id = id_parts.join("."); - std::fs::File::create(args.build_dir.join("aot.xcconfig"))?.write_fmt(format_args!( - "WEBROGUE_APPLICATION_NAME = {} + std::fs::File::create(args.build_dir.join("aot.xcconfig"))?.write_fmt(format_args!( + "WEBROGUE_APPLICATION_NAME = {} WEBROGUE_APPLICATION_ID = {} WEBROGUE_APPLICATION_VERSION = {} ", - wrapp_config.name, id, wrapp_config.version - ))?; + wrapp_config.name, id, wrapp_config.version + ))?; + anyhow::Ok(()) + })?; } let icons_stamp = icons::build( @@ -131,14 +134,16 @@ WEBROGUE_APPLICATION_VERSION = {} old_stamp.as_ref().map(|stamp| &stamp.icons), )?; - println!("Generating stripped WRAPP file..."); - let aot_dir = args.build_dir.join("aot"); - if !aot_dir.exists() { - std::fs::create_dir(&aot_dir)?; - } - webrogue_wrapp::WRAPPWriter::new(vfs_builder_factory()?).write(&mut std::fs::File::create( - args.build_dir.join("aot.swrapp"), - )?)?; + step("Generating stripped WRAPP file".to_owned(), || { + let aot_dir = args.build_dir.join("aot"); + if !aot_dir.exists() { + std::fs::create_dir(&aot_dir)?; + } + webrogue_wrapp::WRAPPWriter::new(vfs_builder_factory()?).write( + &mut std::fs::File::create(args.build_dir.join("aot.swrapp"))?, + )?; + anyhow::Ok(()) + })?; match command { XcodeCommands::Macos { config } => { @@ -193,13 +198,13 @@ WEBROGUE_APPLICATION_VERSION = {} args.cache, )?; } else { - eprintln!("warning: {}", NO_VULKAN_ON_SIM_ERROR); + webrogue_cli_goodies::warning(NO_VULKAN_ON_SIM_ERROR); } - println!( - "Xcode project saved to {}", + webrogue_cli_goodies::note(&format!( + "Xcode project saved to '{}'", args.build_dir.join("webrogue.xcodeproj").display() - ); + )); } } diff --git a/crates/aot-compiler/src/xcode/object.rs b/crates/aot-compiler/src/xcode/object.rs index 61a5b173..de840a27 100644 --- a/crates/aot-compiler/src/xcode/object.rs +++ b/crates/aot-compiler/src/xcode/object.rs @@ -1,3 +1,5 @@ +use webrogue_cli_goodies::step; + use super::types::Destination; pub fn compile( @@ -9,54 +11,65 @@ pub fn compile( let aot_dir = build_dir.join("aot"); match destination { Destination::MacOS => { - println!("Compiling AOT object for x86_64 macOS..."); - crate::compile::compile_wrapp_to_object( - wrapp_path, - &aot_dir.join("aot.x86_64.macosx.o"), - crate::Target::x86_64AppleDarwin, - cache, - true, // TODO check - false, - )?; - println!("Compiling AOT object for AArch64 macOS..."); - crate::compile::compile_wrapp_to_object( - wrapp_path, - &aot_dir.join("aot.arm64.macosx.o"), - crate::Target::ARM64AppleDarwin, - cache, - true, // TODO check - false, - )?; + step("Compiling AOT object for x86_64 macOS".to_owned(), || { + crate::compile::compile_wrapp_to_object( + wrapp_path, + &aot_dir.join("aot.x86_64.macosx.o"), + crate::Target::x86_64AppleDarwin, + cache, + true, // TODO check + false, + ) + })?; + step("Compiling AOT object for AArch64 macOS".to_owned(), || { + crate::compile::compile_wrapp_to_object( + wrapp_path, + &aot_dir.join("aot.arm64.macosx.o"), + crate::Target::ARM64AppleDarwin, + cache, + true, // TODO check + false, + ) + })?; } Destination::Ios => { - println!("Compiling AOT object for AArch64 iOS..."); - crate::compile::compile_wrapp_to_object( - wrapp_path, - &aot_dir.join("aot.arm64.iphoneos.o"), - crate::Target::ARM64AppleIOS, - cache, - true, // TODO check - false, - )?; + step("Compiling AOT object for AArch64 iOS".to_owned(), || { + crate::compile::compile_wrapp_to_object( + wrapp_path, + &aot_dir.join("aot.arm64.iphoneos.o"), + crate::Target::ARM64AppleIOS, + cache, + true, // TODO check + false, + ) + })?; } Destination::IOSSim => { - println!("Compiling AOT object for AArch64 iOS simulator..."); - crate::compile::compile_wrapp_to_object( - wrapp_path, - &aot_dir.join("aot.arm64.iphonesimulator.o"), - crate::Target::ARM64AppleIOSSIM, - cache, - true, // TODO check - false, + step( + "Compiling AOT object for AArch64 iOS simulator".to_owned(), + || { + crate::compile::compile_wrapp_to_object( + wrapp_path, + &aot_dir.join("aot.arm64.iphonesimulator.o"), + crate::Target::ARM64AppleIOSSIM, + cache, + true, // TODO check + false, + ) + }, )?; - println!("Compiling AOT object for x86_64 iOS simulator..."); - crate::compile::compile_wrapp_to_object( - wrapp_path, - &aot_dir.join("aot.x86_64.iphonesimulator.o"), - crate::Target::X86_64AppleIOSSIM, - cache, - true, // TODO check - false, + step( + "Compiling AOT object for x86_64 iOS simulator".to_owned(), + || { + crate::compile::compile_wrapp_to_object( + wrapp_path, + &aot_dir.join("aot.x86_64.iphonesimulator.o"), + crate::Target::X86_64AppleIOSSIM, + cache, + true, // TODO check + false, + ) + }, )?; } } diff --git a/crates/cli-goodies/Cargo.toml b/crates/cli-goodies/Cargo.toml new file mode 100644 index 00000000..92fcf44c --- /dev/null +++ b/crates/cli-goodies/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "webrogue-cli-goodies" +version.workspace = true +authors.workspace = true +license.workspace = true +edition.workspace = true + +[dependencies] +crossterm = { workspace = true } +spinners = { workspace = true } +inquire = { workspace = true } +anyhow = { workspace = true } diff --git a/crates/cli-goodies/src/lib.rs b/crates/cli-goodies/src/lib.rs new file mode 100644 index 00000000..e45f6a3e --- /dev/null +++ b/crates/cli-goodies/src/lib.rs @@ -0,0 +1,85 @@ +use crossterm::{ + style::{Color, Stylize as _}, + terminal::ClearType, +}; +use std::{ + io::{stderr, stdin, stdout, IsTerminal, Write}, + sync::atomic::{AtomicBool, Ordering}, +}; +mod select; +mod step; + +pub use inquire; +pub use select::select; +pub use step::{step, step_async}; + +pub fn write_error(err: &str) { + if is_tty() { + let _ = crossterm::execute!( + stderr(), + crossterm::style::PrintStyledContent(crossterm::style::StyledContent::new( + crossterm::style::ContentStyle::new().red(), + err + )) + ); + let _ = crossterm::execute!(stderr(), crossterm::cursor::MoveToNextLine(1)); + } else { + eprintln!("{}", err); + } +} + +pub fn warning(message: &str) { + print_message("warning", message, Color::Red); +} +pub fn note(message: &str) { + print_message("note", message, Color::Cyan); +} + +fn print_message(label: &str, message: &str, color: Color) { + if is_tty() { + let mut style = crossterm::style::ContentStyle::new(); + style.foreground_color = Some(color); + let _ = crossterm::queue!(stderr(), crossterm::terminal::Clear(ClearType::CurrentLine)); + let _ = crossterm::queue!(stderr(), crossterm::cursor::MoveToColumn(0)); + let _ = crossterm::queue!( + stderr(), + crossterm::style::PrintStyledContent(crossterm::style::StyledContent::new( + style, label + )) + ); + let _ = crossterm::queue!( + stderr(), + crossterm::style::Print(format!(": {}\n", message)) + ); + let _ = stderr().flush(); + } else { + if step::is_step() && !step::is_dirty() { + eprintln!(""); + } + eprintln!("{}: {}", label, message); + } + step::set_dirty(); +} + +pub fn disable_raw_mode() { + let _ = crossterm::terminal::disable_raw_mode(); +} + +static IS_INITED: AtomicBool = AtomicBool::new(false); + +fn check_init() { + if IS_INITED.fetch_or(true, Ordering::SeqCst) { + return; + } + // TODO use update_hook when it is standardized + // https://github.com/rust-lang/rust/issues/92649 + let old_handler = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |info| { + disable_raw_mode(); + old_handler(info) + })); +} + +pub fn is_tty() -> bool { + stdin().is_terminal() && stdout().is_terminal() && stderr().is_terminal() +} diff --git a/crates/cli-goodies/src/select.rs b/crates/cli-goodies/src/select.rs new file mode 100644 index 00000000..9a09e439 --- /dev/null +++ b/crates/cli-goodies/src/select.rs @@ -0,0 +1,21 @@ +use std::fmt::Display; + +pub fn select( + message: &str, + options: Vec, + initial_index: Option, +) -> anyhow::Result<(T, usize)> { + anyhow::ensure!( + crate::is_tty(), + "Can't interactively select an item on a non-TTY stdin/stdout/stderr" + ); + crate::check_init(); + let mut select = inquire::Select::new(message, options); + if let Some(index) = initial_index { + select = select.with_starting_cursor(index); + } + let result = select.raw_prompt(); + crate::disable_raw_mode(); + let result = result?; + Ok((result.value, result.index)) +} diff --git a/crates/cli-goodies/src/step.rs b/crates/cli-goodies/src/step.rs new file mode 100644 index 00000000..2f610029 --- /dev/null +++ b/crates/cli-goodies/src/step.rs @@ -0,0 +1,88 @@ +use std::{ + future::Future, + io::{stdout, Write}, + sync::atomic::{AtomicBool, Ordering}, + time::Instant, +}; + +use spinners::{Spinner, Spinners}; + +static IS_DIRTY: AtomicBool = AtomicBool::new(false); +static IS_STEP: AtomicBool = AtomicBool::new(true); + +struct StepState { + message: String, + start_time: Instant, + spinner: Option, +} + +pub fn step(message: String, func: impl FnOnce() -> Result) -> Result { + let state = step_start(message); + let result = func(); + step_stop(state, result.is_ok()); + result +} + +pub async fn step_async>>( + message: String, + func: impl FnOnce() -> Fut, +) -> Result { + let state = step_start(message); + let result = func().await; + step_stop(state, result.is_ok()); + result +} + +fn step_start(message: String) -> StepState { + let start_time = Instant::now(); + let spinner = if crate::is_tty() { + // let _ = crossterm::execute!(stdout(), crossterm::cursor::Hide); + Some(Spinner::new(Spinners::Dots10, format!("{}...", message))) + } else { + print!("{}...", message); + let _ = stdout().flush(); + None + }; + IS_STEP.store(true, Ordering::SeqCst); + IS_DIRTY.store(false, Ordering::SeqCst); + StepState { + message, + spinner, + start_time, + } +} + +fn step_stop(state: StepState, is_ok: bool) { + let time = state.start_time.elapsed().as_secs_f64(); + let time = if time < 5.0 { + format!("{:.1}", time) + } else { + format!("{:.0}", time) + }; + let time = format!("{} in {}s", if is_ok { "done" } else { "failed" }, time); + IS_STEP.store(false, Ordering::SeqCst); + let is_dirty = IS_DIRTY.fetch_and(false, Ordering::SeqCst); + crate::check_init(); + if let Some(mut spinner) = state.spinner { + spinner.stop_and_persist( + if is_ok { "✓" } else { "✗" }, + format!("{}...{}", state.message, time), + ); + } else { + if is_dirty { + print!("{}...", state.message); + } + println!("{}", time); + }; + crate::disable_raw_mode(); +} + +pub(crate) fn set_dirty() { + IS_DIRTY.fetch_or(true, Ordering::SeqCst); +} +pub(crate) fn is_dirty() -> bool { + IS_DIRTY.load(Ordering::SeqCst) +} +pub(crate) fn is_step() -> bool { + IS_STEP.load(Ordering::SeqCst) +} diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 18185507..fb03c3b6 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -29,13 +29,13 @@ hub = [ "dep:serde_json", "dep:serde", "dep:rand", - "dep:inquire", - "dep:crossterm", - "dep:spinners", - "dep:webrogue-hub-debuggee" + "dep:webrogue-cli-goodies", + "dep:webrogue-hub-debuggee", + "__rustls", ] llvm = ["webrogue-aot-compiler/llvm"] appended_artifacts = ["webrogue-aot-compiler/appended_artifacts"] +__rustls = ["dep:rustls"] [dependencies] anyhow = { workspace = true } @@ -54,16 +54,15 @@ webrogue-hub-debuggee = { workspace = true, optional = true } webrogue-debugger = { workspace = true, optional = true } tokio = { workspace = true, features = ["macros", "net", "rt-multi-thread"], optional = true } blake3 = { workspace = true, optional = true } -tokio-tungstenite = { workspace = true, optional = true } +tokio-tungstenite = { workspace = true, optional = true, features = ["rustls-tls-webpki-roots"] } futures-util = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } serde = { workspace = true, optional = true } rand = { workspace = true, optional = true } async-trait = { workspace = true, optional = true } tokio-util = { workspace = true, features = ["rt", "io"], optional = true } -inquire = { workspace = true, optional = true } -crossterm = { workspace = true, optional = true } -spinners = { workspace = true, optional = true } +webrogue-cli-goodies = { workspace = true, optional = true } +rustls = { workspace = true, optional = true, features = ["aws_lc_rs"] } [target.'cfg(target_os = "macos")'.dependencies] webrogue-gfx-winit = { workspace = true, features = ["static-vk"], optional = true } diff --git a/crates/cli/src/hub.rs b/crates/cli/src/hub.rs index 4df6fd1a..0ea0638d 100644 --- a/crates/cli/src/hub.rs +++ b/crates/cli/src/hub.rs @@ -1,7 +1,7 @@ -use std::{fmt::Display, io::stdout, path::PathBuf}; +use std::{fmt::Display, path::PathBuf}; +use anyhow::Context; use clap::Subcommand; -use crossterm::style::Stylize; use webrogue_hub_client::HTTP_BASE_ADDR; mod debug; #[cfg(feature = "run")] @@ -31,6 +31,8 @@ pub enum HubCommand { /// ID of device to run on #[arg(long)] device: Option, + #[arg(long)] + gdb_port: u16, }, } @@ -63,7 +65,9 @@ impl HubCommand { wrapp_path, api_key, device, + gdb_port, } => { + let gdb_port = *gdb_port; tokio::runtime::Builder::new_current_thread() .enable_all() .build()? @@ -71,10 +75,14 @@ impl HubCommand { let device = if let Some(device) = device { device.clone() } else { - select_device(api_key).await? + anyhow::ensure!( + webrogue_cli_goodies::is_tty(), + "No device has been specified. Use --device option or run in a terminal to select device interactively" + ); + select_device(api_key).await.context("An error occurred while trying to select device interactively. Note that this step can be bypassed by specifying --device option")? }; - crate::hub::debug::debug(wrapp_path, &device, api_key).await?; + crate::hub::debug::debug(wrapp_path, &device, api_key, gdb_port).await?; anyhow::Ok(()) })?; Ok(()) @@ -110,20 +118,23 @@ async fn select_device(api_key: &String) -> anyhow::Result { let response = if let Some(response) = maybe_response.as_mut() { response } else { - let mut spinner = spinners::Spinner::new( - spinners::Spinners::Dots11, + let response = webrogue_cli_goodies::step_async( "Fetching device list".to_string(), - ); - let mut configuration = - webrogue_hub_client::openapi::apis::configuration::Configuration::new(); - configuration.bearer_access_token = Some(api_key.clone()); - configuration.base_path = HTTP_BASE_ADDR.to_owned(); - let response = - webrogue_hub_client::openapi::apis::default_api::list_devices(&configuration) - .await; - spinner.stop_with_symbol(if response.is_ok() { "✅" } else { "❌" }); - drop(spinner); - maybe_response.insert(response?) + async || { + let mut configuration = + webrogue_hub_client::openapi::apis::configuration::Configuration::new(); + configuration.bearer_access_token = Some(api_key.clone()); + configuration.base_path = HTTP_BASE_ADDR.to_owned(); + webrogue_hub_client::openapi::apis::default_api::list_devices( + &configuration, + ) + .await + }, + ) + .await + .context("Unable to fetch list of devices")?; + + maybe_response.insert(response) }; // response.devices.first().unwrap(). let mut device_list: Vec = response @@ -141,31 +152,15 @@ async fn select_device(api_key: &String) -> anyhow::Result { is_reload: true, }); let device = tokio::task::spawn_blocking(move || { - let mut select = inquire::Select::new("Select device:", device_list); - if let Some(index) = index { - select = select.with_starting_cursor(index); - } - let result = select.raw_prompt(); - result + webrogue_cli_goodies::select("Select device:", device_list, index) }) .await??; - index = Some(device.index); - let device = device.value; + index = Some(device.1); + let device = device.0; if device.is_reload { maybe_response = None; - // crossterm::execute!(stdout(), crossterm::cursor::MoveUp(1))?; - // crossterm::execute!(stdout(), crossterm::terminal::Clear(crossterm::terminal::ClearType::CurrentLine))?; } else if !device.is_online { - // crossterm::execute!(stdout(), crossterm::cursor::MoveUp(1))?; - // crossterm::execute!(stdout(), crossterm::terminal::Clear(crossterm::terminal::ClearType::CurrentLine))?; - crossterm::execute!( - stdout(), - crossterm::style::PrintStyledContent(crossterm::style::StyledContent::new( - crossterm::style::ContentStyle::new().red(), - "This device is offline" - )) - )?; - crossterm::execute!(stdout(), crossterm::cursor::MoveToNextLine(1))?; + webrogue_cli_goodies::write_error("This device is offline"); } else { break device; } @@ -174,6 +169,5 @@ async fn select_device(api_key: &String) -> anyhow::Result { anyhow::Ok(device.name) } .await; - crossterm::terminal::disable_raw_mode()?; result } diff --git a/crates/cli/src/hub/debug.rs b/crates/cli/src/hub/debug.rs index 38d7b76d..35c9e874 100644 --- a/crates/cli/src/hub/debug.rs +++ b/crates/cli/src/hub/debug.rs @@ -25,6 +25,7 @@ pub async fn debug( wrapp_path: &std::path::Path, device_name: &str, api_key: &str, + gdb_port: u16, ) -> Result<(), anyhow::Error> { let (done_tx, mut done_rx) = tokio::sync::mpsc::channel(1); let mut connection = OutgoingDebugConnection::new(done_tx).await?; @@ -84,9 +85,8 @@ pub async fn debug( .await?; } - let port = 8012; - let tcp_listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", port)).await?; - eprintln!("Awaiting for incoming GDB Remote connection on port {port}"); + let tcp_listener = tokio::net::TcpListener::bind(format!("127.0.0.1:{}", gdb_port)).await?; + eprintln!("Awaiting for incoming GDB Remote connection on port {gdb_port}"); let (mut tcp_stream, _addr) = tcp_listener.accept().await?; eprintln!("GDB Remote connection accepted!"); diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index d16547ed..1ce94d4e 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -47,6 +47,9 @@ enum Cli { pub fn main() -> anyhow::Result<()> { #[cfg(debug_assertions)] tracing_subscriber::fmt().init(); + #[cfg(feature = "__rustls")] + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + let args = Cli::parse(); match args { #[cfg(feature = "run")] diff --git a/crates/debugger/src/code_runner_loop.rs b/crates/debugger/src/code_runner_loop.rs index c2eeaf44..3ce17a65 100644 --- a/crates/debugger/src/code_runner_loop.rs +++ b/crates/debugger/src/code_runner_loop.rs @@ -70,7 +70,7 @@ pub fn runner( .unwrap() .debug_index_in_engine() as u32, - function_index_and_pc.1, + function_index_and_pc.1.raw(), ) { let mut stack = Vec::new(); for index in 0..frame.num_stacks(&mut store)? { @@ -234,7 +234,7 @@ pub fn runner( let mut breakpoints_per_stores: BTreeMap< u64, - BTreeSet, + BTreeSet, > = BTreeMap::new(); for breakpoint in store.as_context().breakpoints().unwrap() { diff --git a/crates/debugger/src/communication.rs b/crates/debugger/src/communication.rs index 7078e0c8..dc2ba5ef 100644 --- a/crates/debugger/src/communication.rs +++ b/crates/debugger/src/communication.rs @@ -63,6 +63,6 @@ pub struct ReadWasmMessage { } pub struct EditBreakpointMessage { - pub breakpoints: BTreeMap>, // (module, offset) + pub breakpoints: BTreeMap>, // (module, offset) pub sender: tokio::sync::mpsc::UnboundedSender, } diff --git a/crates/debugger/src/connection.rs b/crates/debugger/src/connection.rs index f1219dd7..55587002 100644 --- a/crates/debugger/src/connection.rs +++ b/crates/debugger/src/connection.rs @@ -42,10 +42,10 @@ impl Connection { pub fn flush(&mut self) -> anyhow::Result<()> { if self.needs_flush { - // eprintln!(""); - // eprintln!("-> to client"); - // eprintln!("{}", String::from_utf8_lossy(&self.buffer)); - // eprintln!("<- from client"); + eprintln!(""); + eprintln!("-> to client"); + eprintln!("{}", String::from_utf8_lossy(&self.buffer)); + eprintln!("<- from client"); tokio::runtime::Handle::current() .block_on(async { self.sender.send(&self.buffer).await })?; diff --git a/crates/debugger/src/gdb_stub_loop.rs b/crates/debugger/src/gdb_stub_loop.rs index 9bdb7cd7..8c04ecb6 100644 --- a/crates/debugger/src/gdb_stub_loop.rs +++ b/crates/debugger/src/gdb_stub_loop.rs @@ -78,7 +78,7 @@ pub fn run( async fn receive_byte(receiver: &mut BoxedPacketReceiver) -> anyhow::Result { let byte = receiver.read_u8().await?; - // eprint!("{}", byte as char); + eprint!("{}", byte as char); std::io::stderr().flush().unwrap(); Ok(byte) } diff --git a/crates/debugger/src/gdb_stub_target.rs b/crates/debugger/src/gdb_stub_target.rs index 0820f2e5..eb984817 100644 --- a/crates/debugger/src/gdb_stub_target.rs +++ b/crates/debugger/src/gdb_stub_target.rs @@ -30,7 +30,7 @@ pub(crate) enum StopReason { pub(crate) struct Wasm32Target { receiver: tokio::sync::mpsc::UnboundedReceiver, threads: BTreeMap, - breakpoints: BTreeMap>, + breakpoints: BTreeMap>, default_resume_type: Option, skip_stale_threads: bool, } @@ -86,12 +86,12 @@ impl Wasm32Target { thread_info.stopped = Some(stop_info.stopped_thread); let reason = if stop_info.is_step { - gdbstub::stub::MultiThreadStopReason::DoneStep - // or maybe - // gdbstub::stub::MultiThreadStopReason::SignalWithThread { - // tid: tid.try_into().unwrap(), - // signal: gdbstub::common::Signal::SIGTRAP, - // } + // For some reason gdbstub::stub::MultiThreadStopReason::DoneStep + // makes LLDB behave oddly. But SIGTRAP is perfectly fine + gdbstub::stub::MultiThreadStopReason::SignalWithThread { + tid: tid.try_into().unwrap(), + signal: gdbstub::common::Signal::SIGTRAP, + } } else { gdbstub::stub::MultiThreadStopReason::SwBreak(NonZero::try_from(tid).unwrap()) }; @@ -315,21 +315,15 @@ impl gdbstub::target::ext::breakpoints::SwBreakpoint for Wasm32Target { let module_index = wasm_addr.module_index() as u64; let pc = wasm_addr.offset(); - let old_breakpoints = self.breakpoints.clone(); - if let Some(breakpoints) = self.breakpoints.get_mut(&module_index) { - breakpoints.insert(pc); + breakpoints.insert(wasmtime::ModulePC::new(pc)); } else { let mut breakpoints = BTreeSet::new(); - breakpoints.insert(pc); + breakpoints.insert(wasmtime::ModulePC::new(pc)); self.breakpoints.insert(module_index, breakpoints); } let is_ok = self.edit_breakpoint()?; - if !is_ok { - self.breakpoints = old_breakpoints; - self.edit_breakpoint()?; - } Ok(is_ok) } @@ -352,12 +346,12 @@ impl gdbstub::target::ext::breakpoints::SwBreakpoint for Wasm32Target { let Some(breakpoints) = self.breakpoints.get_mut(&module_index) else { return Ok(true); }; - if !breakpoints.remove(&pc) { + if !breakpoints.remove(&wasmtime::ModulePC::new(pc)) { return Ok(true); } - self.edit_breakpoint()?; - Ok(true) + let is_ok = self.edit_breakpoint()?; + Ok(is_ok) } } diff --git a/crates/debugger/src/handler.rs b/crates/debugger/src/handler.rs deleted file mode 100644 index b197d8ff..00000000 --- a/crates/debugger/src/handler.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[async_trait::async_trait] -pub trait EventHandler { - async fn handle(&self); -} diff --git a/crates/debugger/src/lib.rs b/crates/debugger/src/lib.rs index 75f43545..3d64c0ed 100644 --- a/crates/debugger/src/lib.rs +++ b/crates/debugger/src/lib.rs @@ -36,37 +36,30 @@ pub async fn debug { + let (receiver, sender) = connection_factory().await?; + rt_handle + .spawn_blocking(|| gdb_stub_loop::run(receiver, sender, target)) + .await? } - - return Err(wasi_main_join_handle - .await? - .err() - .map(|err| err.into()) - .unwrap_or(debugger_error)); - } - + Err(error) => Err(error), + }; for thread in threads.lock().unwrap().iter() { thread.trap(); } - - Ok(wasi_main_join_handle.await??) + let wasi_main_error = wasi_main_join_handle.await?; + match (wasi_main_error, debugger_error) { + (Ok(result), Ok(_)) => Ok(result), + (Ok(_), Err(err)) => Err(err), + (Err(err), Ok(_)) => Err(err), + (Err(wasi_main_error), Err(debugger_error)) => { + if wasi_main_error.root_cause().to_string() == "Debugger disconnected" { + Err(debugger_error) + } else { + Err(wasi_main_error) + } + } + } } diff --git a/crates/gfx-winit/src/window_registry.rs b/crates/gfx-winit/src/window_registry.rs index 875a7548..c906ae62 100644 --- a/crates/gfx-winit/src/window_registry.rs +++ b/crates/gfx-winit/src/window_registry.rs @@ -28,4 +28,8 @@ impl WindowRegistry { pub(crate) fn get_window(&mut self, id: WindowId) -> Option<&WinitWindowInternal> { self.windows.get(&id) } + + pub fn clean(&mut self) { + self.windows.clear(); + } } diff --git a/crates/hub-client/Cargo.toml b/crates/hub-client/Cargo.toml index 6be2ed8e..f967756c 100644 --- a/crates/hub-client/Cargo.toml +++ b/crates/hub-client/Cargo.toml @@ -6,7 +6,7 @@ license.workspace = true edition.workspace = true [dependencies] -webrogue-hub-client-openapi = { workspace = true, default-features = false } +webrogue-hub-client-openapi = { workspace = true, default-features = false, features = ["rustls"] } clap = { workspace = true, features = ["derive"] } anyhow = { workspace = true } webrtc = { workspace = true } diff --git a/crates/hub-client/openapi/.openapi-generator/FILES b/crates/hub-client/openapi/.openapi-generator/FILES index 9dcd71a9..c7299314 100644 --- a/crates/hub-client/openapi/.openapi-generator/FILES +++ b/crates/hub-client/openapi/.openapi-generator/FILES @@ -4,10 +4,8 @@ Cargo.toml README.md docs/AuthLoginRequest.md docs/AuthLoginResponse.md -docs/AuthSignupRequest.md -docs/AuthSignupResponse.md -docs/AuthVerifyEmailRequest.md -docs/AuthVerifyEmailResponse.md +docs/CheckEmailRequest.md +docs/CheckEmailResponse.md docs/ConnectDeviceWsCommand.md docs/ConnectDeviceWsEvent.md docs/DebugDeviceWsCommand.md @@ -24,10 +22,8 @@ src/apis/mod.rs src/lib.rs src/models/auth_login_request.rs src/models/auth_login_response.rs -src/models/auth_signup_request.rs -src/models/auth_signup_response.rs -src/models/auth_verify_email_request.rs -src/models/auth_verify_email_response.rs +src/models/check_email_request.rs +src/models/check_email_response.rs src/models/connect_device_ws_command.rs src/models/connect_device_ws_event.rs src/models/debug_device_ws_command.rs diff --git a/crates/hub-client/openapi/README.md b/crates/hub-client/openapi/README.md index 8dfe526f..3b706d5c 100644 --- a/crates/hub-client/openapi/README.md +++ b/crates/hub-client/openapi/README.md @@ -27,8 +27,7 @@ All URIs are relative to *https://api.hub.example.com/v1* Class | Method | HTTP request | Description ------------ | ------------- | ------------- | ------------- *DefaultApi* | [**auth_login**](docs/DefaultApi.md#auth_login) | **POST** /api/v1/auth/login | User login -*DefaultApi* | [**auth_signup**](docs/DefaultApi.md#auth_signup) | **POST** /api/v1/auth/signup | User signup (registration) -*DefaultApi* | [**auth_verify_email**](docs/DefaultApi.md#auth_verify_email) | **POST** /api/v1/verify_email | Verify Email with OTP +*DefaultApi* | [**check_email**](docs/DefaultApi.md#check_email) | **POST** /api/v1/auth/check_email | Check if email is taken *DefaultApi* | [**get_current_user**](docs/DefaultApi.md#get_current_user) | **GET** /api/v1/users/me | Get current user data *DefaultApi* | [**list_devices**](docs/DefaultApi.md#list_devices) | **GET** /api/v1/devices | List user devices @@ -37,10 +36,8 @@ Class | Method | HTTP request | Description - [AuthLoginRequest](docs/AuthLoginRequest.md) - [AuthLoginResponse](docs/AuthLoginResponse.md) - - [AuthSignupRequest](docs/AuthSignupRequest.md) - - [AuthSignupResponse](docs/AuthSignupResponse.md) - - [AuthVerifyEmailRequest](docs/AuthVerifyEmailRequest.md) - - [AuthVerifyEmailResponse](docs/AuthVerifyEmailResponse.md) + - [CheckEmailRequest](docs/CheckEmailRequest.md) + - [CheckEmailResponse](docs/CheckEmailResponse.md) - [ConnectDeviceWsCommand](docs/ConnectDeviceWsCommand.md) - [ConnectDeviceWsEvent](docs/ConnectDeviceWsEvent.md) - [DebugDeviceWsCommand](docs/DebugDeviceWsCommand.md) diff --git a/crates/hub-client/openapi/docs/AuthLoginRequest.md b/crates/hub-client/openapi/docs/AuthLoginRequest.md index d3895a4a..c1e59db1 100644 --- a/crates/hub-client/openapi/docs/AuthLoginRequest.md +++ b/crates/hub-client/openapi/docs/AuthLoginRequest.md @@ -4,7 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**username_or_email** | **String** | | +**email** | **String** | | +**is_signup** | **bool** | | **password** | **String** | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/crates/hub-client/openapi/docs/AuthLoginResponse.md b/crates/hub-client/openapi/docs/AuthLoginResponse.md index dd8402b6..66e1eb43 100644 --- a/crates/hub-client/openapi/docs/AuthLoginResponse.md +++ b/crates/hub-client/openapi/docs/AuthLoginResponse.md @@ -5,6 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **token** | **String** | | +**needs_email_verification** | **bool** | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/crates/hub-client/openapi/docs/CheckEmail500Response.md b/crates/hub-client/openapi/docs/CheckEmail500Response.md new file mode 100644 index 00000000..cfbccf5c --- /dev/null +++ b/crates/hub-client/openapi/docs/CheckEmail500Response.md @@ -0,0 +1,11 @@ +# CheckEmail500Response + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**error** | **serde_json::Value** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/hub-client/openapi/docs/CheckEmailRequest.md b/crates/hub-client/openapi/docs/CheckEmailRequest.md new file mode 100644 index 00000000..724debb9 --- /dev/null +++ b/crates/hub-client/openapi/docs/CheckEmailRequest.md @@ -0,0 +1,11 @@ +# CheckEmailRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**email** | **String** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/hub-client/openapi/docs/CheckEmailResponse.md b/crates/hub-client/openapi/docs/CheckEmailResponse.md new file mode 100644 index 00000000..af6250ce --- /dev/null +++ b/crates/hub-client/openapi/docs/CheckEmailResponse.md @@ -0,0 +1,11 @@ +# CheckEmailResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**is_taken** | **bool** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/crates/hub-client/openapi/docs/DefaultApi.md b/crates/hub-client/openapi/docs/DefaultApi.md index 66dfc09f..163450f4 100644 --- a/crates/hub-client/openapi/docs/DefaultApi.md +++ b/crates/hub-client/openapi/docs/DefaultApi.md @@ -5,8 +5,7 @@ All URIs are relative to *https://api.hub.example.com/v1* Method | HTTP request | Description ------------- | ------------- | ------------- [**auth_login**](DefaultApi.md#auth_login) | **POST** /api/v1/auth/login | User login -[**auth_signup**](DefaultApi.md#auth_signup) | **POST** /api/v1/auth/signup | User signup (registration) -[**auth_verify_email**](DefaultApi.md#auth_verify_email) | **POST** /api/v1/verify_email | Verify Email with OTP +[**check_email**](DefaultApi.md#check_email) | **POST** /api/v1/auth/check_email | Check if email is taken [**get_current_user**](DefaultApi.md#get_current_user) | **GET** /api/v1/users/me | Get current user data [**list_devices**](DefaultApi.md#list_devices) | **GET** /api/v1/devices | List user devices @@ -42,53 +41,23 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -## auth_signup +## check_email -> models::AuthSignupResponse auth_signup(auth_signup_request) -User signup (registration) +> models::CheckEmailResponse check_email(check_email_request) +Check if email is taken -Register a new user account. May require email verifyation +Check if a user is registered for this email ### Parameters Name | Type | Description | Required | Notes ------------- | ------------- | ------------- | ------------- | ------------- -**auth_signup_request** | [**AuthSignupRequest**](AuthSignupRequest.md) | | [required] | +**check_email_request** | [**CheckEmailRequest**](CheckEmailRequest.md) | | [required] | ### Return type -[**models::AuthSignupResponse**](AuthSignupResponse.md) - -### Authorization - -No authorization required - -### HTTP request headers - -- **Content-Type**: application/json -- **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - - -## auth_verify_email - -> models::AuthVerifyEmailResponse auth_verify_email(auth_verify_email_request) -Verify Email with OTP - -Verify user registration using OTP code sent to email - -### Parameters - - -Name | Type | Description | Required | Notes -------------- | ------------- | ------------- | ------------- | ------------- -**auth_verify_email_request** | [**AuthVerifyEmailRequest**](AuthVerifyEmailRequest.md) | | [required] | - -### Return type - -[**models::AuthVerifyEmailResponse**](AuthVerifyEmailResponse.md) +[**models::CheckEmailResponse**](CheckEmailResponse.md) ### Authorization diff --git a/crates/hub-client/openapi/docs/ErrorResponse.md b/crates/hub-client/openapi/docs/ErrorResponse.md index 1b2770f5..47a006c1 100644 --- a/crates/hub-client/openapi/docs/ErrorResponse.md +++ b/crates/hub-client/openapi/docs/ErrorResponse.md @@ -5,7 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **error** | **String** | | -**error_code** | Option<**ErrorCode**> | (enum: USERNAME_INVALID, EMAIL_INVALID, LOGIN_INVALID, PASSWORD_INVALID) | +**error_code** | Option<**ErrorCode**> | (enum: WEAK_PASSWORD, WRONG_PASSWORD) | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/crates/hub-client/openapi/docs/UserResponse.md b/crates/hub-client/openapi/docs/UserResponse.md index f89122dc..bf21065c 100644 --- a/crates/hub-client/openapi/docs/UserResponse.md +++ b/crates/hub-client/openapi/docs/UserResponse.md @@ -4,7 +4,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**username** | **String** | | **email** | **String** | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/crates/hub-client/openapi/src/apis/default_api.rs b/crates/hub-client/openapi/src/apis/default_api.rs index 14fe495a..00b84dde 100644 --- a/crates/hub-client/openapi/src/apis/default_api.rs +++ b/crates/hub-client/openapi/src/apis/default_api.rs @@ -19,24 +19,17 @@ use super::{Error, configuration, ContentType}; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum AuthLoginError { - Status401(models::ErrorResponse), - UnknownValue(serde_json::Value), -} - -/// struct for typed errors of method [`auth_signup`] -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum AuthSignupError { Status400(models::ErrorResponse), + Status401(models::ErrorResponse), Status500(models::ErrorResponse), UnknownValue(serde_json::Value), } -/// struct for typed errors of method [`auth_verify_email`] +/// struct for typed errors of method [`check_email`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] -pub enum AuthVerifyEmailError { - Status401(models::ErrorResponse), +pub enum CheckEmailError { + Status500(models::ErrorResponse), UnknownValue(serde_json::Value), } @@ -95,56 +88,18 @@ pub async fn auth_login(configuration: &configuration::Configuration, auth_login } } -/// Register a new user account. May require email verifyation -pub async fn auth_signup(configuration: &configuration::Configuration, auth_signup_request: models::AuthSignupRequest) -> Result> { - // add a prefix to parameters to efficiently prevent name collisions - let p_body_auth_signup_request = auth_signup_request; - - let uri_str = format!("{}/api/v1/auth/signup", configuration.base_path); - let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str); - - if let Some(ref user_agent) = configuration.user_agent { - req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); - } - req_builder = req_builder.json(&p_body_auth_signup_request); - - let req = req_builder.build()?; - let resp = configuration.client.execute(req).await?; - - let status = resp.status(); - let content_type = resp - .headers() - .get("content-type") - .and_then(|v| v.to_str().ok()) - .unwrap_or("application/octet-stream"); - let content_type = super::ContentType::from(content_type); - - if !status.is_client_error() && !status.is_server_error() { - let content = resp.text().await?; - match content_type { - ContentType::Json => serde_json::from_str(&content).map_err(Error::from), - ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::AuthSignupResponse`"))), - ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::AuthSignupResponse`")))), - } - } else { - let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); - Err(Error::ResponseError(ResponseContent { status, content, entity })) - } -} - -/// Verify user registration using OTP code sent to email -pub async fn auth_verify_email(configuration: &configuration::Configuration, auth_verify_email_request: models::AuthVerifyEmailRequest) -> Result> { +/// Check if a user is registered for this email +pub async fn check_email(configuration: &configuration::Configuration, check_email_request: models::CheckEmailRequest) -> Result> { // add a prefix to parameters to efficiently prevent name collisions - let p_body_auth_verify_email_request = auth_verify_email_request; + let p_body_check_email_request = check_email_request; - let uri_str = format!("{}/api/v1/verify_email", configuration.base_path); + let uri_str = format!("{}/api/v1/auth/check_email", configuration.base_path); let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str); if let Some(ref user_agent) = configuration.user_agent { req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone()); } - req_builder = req_builder.json(&p_body_auth_verify_email_request); + req_builder = req_builder.json(&p_body_check_email_request); let req = req_builder.build()?; let resp = configuration.client.execute(req).await?; @@ -161,12 +116,12 @@ pub async fn auth_verify_email(configuration: &configuration::Configuration, aut let content = resp.text().await?; match content_type { ContentType::Json => serde_json::from_str(&content).map_err(Error::from), - ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::AuthVerifyEmailResponse`"))), - ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::AuthVerifyEmailResponse`")))), + ContentType::Text => return Err(Error::from(serde_json::Error::custom("Received `text/plain` content type response that cannot be converted to `models::CheckEmailResponse`"))), + ContentType::Unsupported(unknown_type) => return Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::CheckEmailResponse`")))), } } else { let content = resp.text().await?; - let entity: Option = serde_json::from_str(&content).ok(); + let entity: Option = serde_json::from_str(&content).ok(); Err(Error::ResponseError(ResponseContent { status, content, entity })) } } diff --git a/crates/hub-client/openapi/src/models/auth_login_request.rs b/crates/hub-client/openapi/src/models/auth_login_request.rs index 9bf8d829..4ed93ac1 100644 --- a/crates/hub-client/openapi/src/models/auth_login_request.rs +++ b/crates/hub-client/openapi/src/models/auth_login_request.rs @@ -13,16 +13,19 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct AuthLoginRequest { - #[serde(rename = "username_or_email")] - pub username_or_email: String, + #[serde(rename = "email")] + pub email: String, + #[serde(rename = "is_signup")] + pub is_signup: bool, #[serde(rename = "password")] pub password: String, } impl AuthLoginRequest { - pub fn new(username_or_email: String, password: String) -> AuthLoginRequest { + pub fn new(email: String, is_signup: bool, password: String) -> AuthLoginRequest { AuthLoginRequest { - username_or_email, + email, + is_signup, password, } } diff --git a/crates/hub-client/openapi/src/models/auth_login_response.rs b/crates/hub-client/openapi/src/models/auth_login_response.rs index 67cc2ff2..9fbbc16e 100644 --- a/crates/hub-client/openapi/src/models/auth_login_response.rs +++ b/crates/hub-client/openapi/src/models/auth_login_response.rs @@ -15,12 +15,15 @@ use serde::{Deserialize, Serialize}; pub struct AuthLoginResponse { #[serde(rename = "token")] pub token: String, + #[serde(rename = "needs_email_verification")] + pub needs_email_verification: bool, } impl AuthLoginResponse { - pub fn new(token: String) -> AuthLoginResponse { + pub fn new(token: String, needs_email_verification: bool) -> AuthLoginResponse { AuthLoginResponse { token, + needs_email_verification, } } } diff --git a/crates/hub-client/openapi/src/models/check_email_500_response.rs b/crates/hub-client/openapi/src/models/check_email_500_response.rs new file mode 100644 index 00000000..9a9e3078 --- /dev/null +++ b/crates/hub-client/openapi/src/models/check_email_500_response.rs @@ -0,0 +1,27 @@ +/* + * Hub API + * + * API for Hub authentication and user management + * + * The version of the OpenAPI document: 1.0.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct CheckEmail500Response { + #[serde(rename = "error")] + pub error: serde_json::Value, +} + +impl CheckEmail500Response { + pub fn new(error: serde_json::Value) -> CheckEmail500Response { + CheckEmail500Response { + error, + } + } +} + diff --git a/crates/hub-client/openapi/src/models/check_email_request.rs b/crates/hub-client/openapi/src/models/check_email_request.rs new file mode 100644 index 00000000..8028922a --- /dev/null +++ b/crates/hub-client/openapi/src/models/check_email_request.rs @@ -0,0 +1,27 @@ +/* + * Hub API + * + * API for Hub authentication and user management + * + * The version of the OpenAPI document: 1.0.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct CheckEmailRequest { + #[serde(rename = "email")] + pub email: String, +} + +impl CheckEmailRequest { + pub fn new(email: String) -> CheckEmailRequest { + CheckEmailRequest { + email, + } + } +} + diff --git a/crates/hub-client/openapi/src/models/check_email_response.rs b/crates/hub-client/openapi/src/models/check_email_response.rs new file mode 100644 index 00000000..81ba1212 --- /dev/null +++ b/crates/hub-client/openapi/src/models/check_email_response.rs @@ -0,0 +1,27 @@ +/* + * Hub API + * + * API for Hub authentication and user management + * + * The version of the OpenAPI document: 1.0.0 + * + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct CheckEmailResponse { + #[serde(rename = "is_taken")] + pub is_taken: bool, +} + +impl CheckEmailResponse { + pub fn new(is_taken: bool) -> CheckEmailResponse { + CheckEmailResponse { + is_taken, + } + } +} + diff --git a/crates/hub-client/openapi/src/models/error_response.rs b/crates/hub-client/openapi/src/models/error_response.rs index cf068f1f..3a76c7b9 100644 --- a/crates/hub-client/openapi/src/models/error_response.rs +++ b/crates/hub-client/openapi/src/models/error_response.rs @@ -30,19 +30,15 @@ impl ErrorResponse { /// #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] pub enum ErrorCode { - #[serde(rename = "USERNAME_INVALID")] - UsernameInvalid, - #[serde(rename = "EMAIL_INVALID")] - EmailInvalid, - #[serde(rename = "LOGIN_INVALID")] - LoginInvalid, - #[serde(rename = "PASSWORD_INVALID")] - PasswordInvalid, + #[serde(rename = "WEAK_PASSWORD")] + WeakPassword, + #[serde(rename = "WRONG_PASSWORD")] + WrongPassword, } impl Default for ErrorCode { fn default() -> ErrorCode { - Self::UsernameInvalid + Self::WeakPassword } } diff --git a/crates/hub-client/openapi/src/models/mod.rs b/crates/hub-client/openapi/src/models/mod.rs index 36f6c9ae..bbe4d4ac 100644 --- a/crates/hub-client/openapi/src/models/mod.rs +++ b/crates/hub-client/openapi/src/models/mod.rs @@ -2,14 +2,10 @@ pub mod auth_login_request; pub use self::auth_login_request::AuthLoginRequest; pub mod auth_login_response; pub use self::auth_login_response::AuthLoginResponse; -pub mod auth_signup_request; -pub use self::auth_signup_request::AuthSignupRequest; -pub mod auth_signup_response; -pub use self::auth_signup_response::AuthSignupResponse; -pub mod auth_verify_email_request; -pub use self::auth_verify_email_request::AuthVerifyEmailRequest; -pub mod auth_verify_email_response; -pub use self::auth_verify_email_response::AuthVerifyEmailResponse; +pub mod check_email_request; +pub use self::check_email_request::CheckEmailRequest; +pub mod check_email_response; +pub use self::check_email_response::CheckEmailResponse; pub mod connect_device_ws_command; pub use self::connect_device_ws_command::ConnectDeviceWsCommand; pub mod connect_device_ws_event; diff --git a/crates/hub-client/openapi/src/models/user_response.rs b/crates/hub-client/openapi/src/models/user_response.rs index 4ca65a5a..fcc0edf8 100644 --- a/crates/hub-client/openapi/src/models/user_response.rs +++ b/crates/hub-client/openapi/src/models/user_response.rs @@ -13,16 +13,13 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct UserResponse { - #[serde(rename = "username")] - pub username: String, #[serde(rename = "email")] pub email: String, } impl UserResponse { - pub fn new(username: String, email: String) -> UserResponse { + pub fn new(email: String) -> UserResponse { UserResponse { - username, email, } } diff --git a/crates/hub-client/src/lib.rs b/crates/hub-client/src/lib.rs index 90e86875..b54f9445 100644 --- a/crates/hub-client/src/lib.rs +++ b/crates/hub-client/src/lib.rs @@ -4,5 +4,5 @@ pub mod ws_messages; pub use webrogue_hub_client_openapi as openapi; -pub static WS_BASE_ADDR: &str = "ws://localhost:8080"; -pub static HTTP_BASE_ADDR: &str = "http://localhost:8080"; +pub static WS_BASE_ADDR: &str = "wss://api.webrogue.dev"; +pub static HTTP_BASE_ADDR: &str = "https://api.webrogue.dev"; diff --git a/crates/hub-debuggee/src/lib.rs b/crates/hub-debuggee/src/lib.rs index 3a224c70..8d7741f5 100644 --- a/crates/hub-debuggee/src/lib.rs +++ b/crates/hub-debuggee/src/lib.rs @@ -146,7 +146,7 @@ impl HubDebuggee { data_channel.on_close(Box::new(move || { let done_tx = done_tx.clone(); Box::pin(async move { - let _ = done_tx.send(Ok(())).await.unwrap(); + let _ = done_tx.send(Ok(())).await; }) })); }) diff --git a/crates/icons/src/android.rs b/crates/icons/src/android.rs index 4478942b..f2e888b7 100644 --- a/crates/icons/src/android.rs +++ b/crates/icons/src/android.rs @@ -27,7 +27,6 @@ pub fn generate_icons( build_dir: &std::path::Path, icons_data: &crate::IconsData, ) -> anyhow::Result<()> { - println!("Generating icons..."); for dir in [ "drawable", "mipmap-anydpi-v26", diff --git a/crates/icons/src/xcode.rs b/crates/icons/src/xcode.rs index 44d2850a..853dc55c 100644 --- a/crates/icons/src/xcode.rs +++ b/crates/icons/src/xcode.rs @@ -4,8 +4,6 @@ pub fn generate_icons( build_dir: &std::path::Path, icons_data: &crate::IconsData, ) -> anyhow::Result<()> { - println!("Generating icons..."); - generate_icon(build_dir, icons_data)?; generate_ios_splash_screen(build_dir, icons_data)?; diff --git a/crates/launcher-dev/src/main.rs b/crates/launcher-dev/src/main.rs index 700c1bfb..66302e17 100644 --- a/crates/launcher-dev/src/main.rs +++ b/crates/launcher-dev/src/main.rs @@ -1,6 +1,7 @@ use winit::event_loop::EventLoop; fn main() { + webrogue_launcher::install_default_crypto_provider(); #[cfg(target_os = "linux")] let event_loop = { use winit_x11::EventLoopBuilderExtX11; diff --git a/crates/launcher/Cargo.toml b/crates/launcher/Cargo.toml index 948fd763..0873863f 100644 --- a/crates/launcher/Cargo.toml +++ b/crates/launcher/Cargo.toml @@ -38,9 +38,10 @@ webrogue-gfx-winit = { workspace = true, optional = true } webrogue-gfxstream = { workspace = true, optional = true } headers = { workspace = true } rand = { workspace = true } -tokio-tungstenite = { workspace = true } +tokio-tungstenite = { workspace = true, features = ["rustls-tls-webpki-roots"] } tokio-util = { workspace = true, features = ["rt"] } webrogue-hub-debuggee = { workspace = true } +rustls = { workspace = true, features = ["aws_lc_rs"] } [target.'cfg(target_os = "linux")'.dependencies] gtk = "0.18" diff --git a/crates/launcher/server-openapi/README.md b/crates/launcher/server-openapi/README.md index 36418389..9e8f990e 100644 --- a/crates/launcher/server-openapi/README.md +++ b/crates/launcher/server-openapi/README.md @@ -12,7 +12,7 @@ server, you can easily generate a server stub. To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 1.0.0 -- Build date: 2026-04-08T11:52:17.343060709-04:00[America/New_York] +- Build date: 2026-04-26T12:54:23.826273+03:00[Europe/Minsk] - Generator version: 7.21.0 diff --git a/crates/launcher/src/api_base_path.rs b/crates/launcher/src/api_base_path.rs index 8d003110..c4e91a9a 100644 --- a/crates/launcher/src/api_base_path.rs +++ b/crates/launcher/src/api_base_path.rs @@ -9,8 +9,8 @@ fn localhost_api_addr_port() -> &'static str { } fn use_localhost_api() -> bool { - cfg!(debug_assertions) - // false + // cfg!(debug_assertions) + false } fn use_localhost_ui() -> bool { @@ -37,9 +37,9 @@ pub fn ws_api_url() -> String { pub fn assets_url() -> &'static str { if use_localhost_ui() { if cfg!(target_os = "android") { - "http://10.0.2.2:5202/" + "http://10.0.2.2:5173/" } else { - "http://localhost:5202/" + "http://localhost:5173/" } } else { "wrlauncher://asset/" diff --git a/crates/launcher/src/debug_connection.rs b/crates/launcher/src/debug_connection.rs index 3a0e5ead..53c28d13 100644 --- a/crates/launcher/src/debug_connection.rs +++ b/crates/launcher/src/debug_connection.rs @@ -116,7 +116,7 @@ impl DebugConnection { .await; if let Err(err) = result { - eprintln!("{:#}", err) + eprintln!("Error: {:#}", err) } tokio::time::sleep(Duration::from_secs(5)).await; diff --git a/crates/launcher/src/lib.rs b/crates/launcher/src/lib.rs index 2d461695..aba5ac7a 100644 --- a/crates/launcher/src/lib.rs +++ b/crates/launcher/src/lib.rs @@ -18,3 +18,7 @@ pub use winit_app::*; mod winit_mailbox; #[cfg(feature = "winit")] pub use winit_mailbox::*; + +pub fn install_default_crypto_provider() { + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); +} diff --git a/crates/launcher/src/winit_app.rs b/crates/launcher/src/winit_app.rs index 59056a5a..5e1cabf1 100644 --- a/crates/launcher/src/winit_app.rs +++ b/crates/launcher/src/winit_app.rs @@ -1,10 +1,11 @@ use crate::{LauncherConfig, WinitMailbox}; use dpi::{PhysicalPosition, PhysicalSize}; #[cfg(target_os = "linux")] -use std::sync::{ - atomic::{AtomicBool, Ordering}, +use std::sync::atomic::{AtomicBool, Ordering}; +use std::{ + path::PathBuf, + sync::{Arc, Mutex}, }; -use std::{path::PathBuf, sync::{Arc, Mutex}}; use webrogue_gfx_winit::{WindowRegistry, WinitProxy}; use webrogue_hub_debuggee::{HubDebuggee, HubDebuggeeGFX, HubDebuggeeProxiedWinitGFX}; use winit::{ @@ -20,6 +21,8 @@ use crate::build_webview; struct LauncherConfigImpl { storage_path: PathBuf, hub_debuggee: HubDebuggee, + event_loop_proxy: EventLoopProxy, + launch_finish_indicator: Arc>>, } impl LauncherConfigImpl { @@ -27,6 +30,7 @@ impl LauncherConfigImpl { storage_path: PathBuf, proxy_container: Arc>>, event_loop_proxy: EventLoopProxy, + launch_finish_indicator: Arc>>, ) -> Self { Self { storage_path: storage_path.clone(), @@ -34,9 +38,11 @@ impl LauncherConfigImpl { storage_path.clone(), HubDebuggeeGFX::ProxiedWinit(HubDebuggeeProxiedWinitGFX { proxy_container, - event_loop_proxy, + event_loop_proxy: event_loop_proxy.clone(), }), ), + event_loop_proxy, + launch_finish_indicator, } } } @@ -52,7 +58,14 @@ impl LauncherConfig for LauncherConfigImpl { sdp_offer: String, on_sdp_answer: Box, ) -> anyhow::Result<()> { - self.hub_debuggee.launch(sdp_offer, on_sdp_answer).await + let result = self.hub_debuggee.launch(sdp_offer, on_sdp_answer).await; + let old_indicator = self.launch_finish_indicator.lock().unwrap().replace(()); + debug_assert!( + old_indicator.is_none(), + "Trying to set launch_finish_indicator, but it's already set" + ); + self.event_loop_proxy.wake_up(); + result } } @@ -66,6 +79,7 @@ pub struct App { storage_path: std::path::PathBuf, proxy_container: Arc>>, window_registry: WindowRegistry, + launch_finish_indicator: Arc>>, } impl App { @@ -80,6 +94,7 @@ impl App { storage_path, proxy_container: Arc::new(Mutex::new(None)), window_registry: WindowRegistry::new(), + launch_finish_indicator: Arc::new(Mutex::new(None)), } } } @@ -90,7 +105,7 @@ impl ApplicationHandler for App { gtk::init().unwrap(); let window = event_loop - .create_window(WindowAttributes::default()) + .create_window(WindowAttributes::default().with_title("Webrogue")) .unwrap(); let event_loop_proxy = event_loop.create_proxy(); let (webview, mailbox) = build_webview( @@ -100,6 +115,7 @@ impl ApplicationHandler for App { self.storage_path.clone(), self.proxy_container.clone(), event_loop.create_proxy(), + self.launch_finish_indicator.clone(), )), |internal| WinitMailbox::new(event_loop_proxy, internal), ) @@ -207,6 +223,9 @@ impl ApplicationHandler for App { mailbox.proxy_wake_up(webview); } } + if let Some(_) = self.launch_finish_indicator.lock().unwrap().take() { + self.window_registry.clean(); + } } } diff --git a/crates/wasip1/Cargo.toml b/crates/wasip1/Cargo.toml index 20744100..780dbee8 100644 --- a/crates/wasip1/Cargo.toml +++ b/crates/wasip1/Cargo.toml @@ -16,7 +16,6 @@ async-trait = { workspace = true } rand_core = { workspace = true } rand = { workspace = true, default-features = false, features = ["sys_rng", "thread_rng"] } getrandom = { workspace = true, default-features = false, features = ["wasm_js"] } -cap-rand = { workspace = true } [target.'cfg(unix)'.dependencies] rustix = { workspace = true, features = ["pipe"] } diff --git a/crates/wasip1/src/lib.rs b/crates/wasip1/src/lib.rs index f31a0d71..f09ab90a 100644 --- a/crates/wasip1/src/lib.rs +++ b/crates/wasip1/src/lib.rs @@ -1,31 +1,6 @@ -use cap_rand::Rng as _; -use cap_rand::SeedableRng as _; -use rand::Rng as _; - mod fs; mod stdout; -struct RandomCtx {} - -impl cap_rand::RngCore for RandomCtx { - fn next_u32(&mut self) -> u32 { - rand::random() - } - - fn next_u64(&mut self) -> u64 { - rand::random() - } - - fn fill_bytes(&mut self, dst: &mut [u8]) { - rand::rng().fill_bytes(dst); - } - - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), cap_rand::Error> { - self.fill_bytes(dest); - Ok(()) - } -} - pub fn make_ctx( handle: VFSHandle, config: &webrogue_wrapp::config::Config, diff --git a/crates/wasmtime/src/runtime.rs b/crates/wasmtime/src/runtime.rs index 98dcc609..58f19803 100644 --- a/crates/wasmtime/src/runtime.rs +++ b/crates/wasmtime/src/runtime.rs @@ -98,7 +98,6 @@ impl Runtime { self.wasmtime_config .wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable); - self.wasmtime_config.epoch_interruption(true); #[cfg(feature = "cache")] if let Some(cache_config) = self.jit_cache_config { diff --git a/crates/wrapp/Cargo.toml b/crates/wrapp/Cargo.toml index ae0d9a39..ea468c1a 100644 --- a/crates/wrapp/Cargo.toml +++ b/crates/wrapp/Cargo.toml @@ -15,4 +15,4 @@ anyhow = { workspace = true } zstd-safe = { workspace = true, features = ["seekable", "std"] } zstd = { workspace = true } image = { workspace = true, optional = true, default-features = false, features = ["png", "rayon"] } -semver = { workspace = true, default-features = false, features = ["serde"] } +semver = { workspace = true, default-features = false, features = ["serde"] } diff --git a/external/wasmtime b/external/wasmtime index 5e398470..919db44e 160000 --- a/external/wasmtime +++ b/external/wasmtime @@ -1 +1 @@ -Subproject commit 5e398470be261bb9aa0e77b965e88224681fb100 +Subproject commit 919db44e2d4e35673762acef5e23da4dcd268242