From 7b7a3d079c0b2ac7ca3dfacb676af7b7837b85df Mon Sep 17 00:00:00 2001 From: Andi Date: Tue, 31 May 2022 11:33:14 +0200 Subject: [PATCH 1/2] add wasm code from andipabst/magic-wormhole-wasm --- .github/workflows/push.yml | 36 +++++- Cargo.lock | 218 +++++++++++++++++++++++++++---------- Cargo.toml | 2 +- wasm/Cargo.toml | 46 ++++++++ wasm/src/event.rs | 80 ++++++++++++++ wasm/src/lib.rs | 180 ++++++++++++++++++++++++++++++ 6 files changed, 504 insertions(+), 58 deletions(-) create mode 100644 wasm/Cargo.toml create mode 100644 wasm/src/event.rs create mode 100644 wasm/src/lib.rs diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 014d0fd7..3f0bb0e8 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -2,9 +2,9 @@ name: Rust on: push: - branches: [master, dev] + branches: [ master, dev ] pull_request: - branches: [master, dev] + branches: [ master, dev ] jobs: format: @@ -152,6 +152,38 @@ jobs: ./target/release/wormhole-rs.exe if-no-files-found: error + wasm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - name: Add wasm-pack + uses: jetli/wasm-pack-action@v0.3.0 + - name: Cache ~/.cargo + uses: actions/cache@v1 + with: + path: ~/.cargo + key: ${{ runner.os }}-wasm-dotcargo + - name: Cache cargo build + uses: actions/cache@v1 + with: + path: target + key: ${{ runner.os }}-test-wasm-target + - name: Build wasm + run: wasm-pack build ./wasm + - name: Pack wasm for npm + run: wasm-pack pack ./wasm + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: wormhole-wasm-${{ github.sha }} + path: ./wasm/pkg/magic-wormhole-wasm-*.tgz + if-no-files-found: error + coverage: runs-on: ubuntu-latest steps: diff --git a/Cargo.lock b/Cargo.lock index f474b17b..848906fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,7 +132,7 @@ checksum = "cf2c06e30a24e8c78a3987d07f0930edf76ef35e027e7bdb063fccafdad1f60c" dependencies = [ "async-io", "blocking", - "cfg-if", + "cfg-if 1.0.0", "event-listener", "futures-lite", "libc", @@ -246,7 +246,7 @@ checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" dependencies = [ "addr2line", "cc", - "cfg-if", + "cfg-if 1.0.0", "libc", "miniz_oxide", "object", @@ -346,6 +346,12 @@ version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -401,6 +407,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clear_on_drop" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38508a63f4979f0048febc9966fadbd48e5dab31fd0ec6a3f151bbf4a74f7423" +dependencies = [ + "cc", +] + [[package]] name = "cli-clipboard" version = "0.2.1" @@ -476,6 +491,16 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -512,7 +537,7 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] @@ -715,7 +740,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "winapi 0.3.9", @@ -904,10 +929,11 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -916,7 +942,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", @@ -1072,7 +1098,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -1086,9 +1112,9 @@ checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "js-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] @@ -1126,11 +1152,11 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "value-bag", ] @@ -1187,6 +1213,27 @@ dependencies = [ "xsalsa20poly1305", ] +[[package]] +name = "magic-wormhole-wasm" +version = "0.1.0" +dependencies = [ + "clear_on_drop", + "console_error_panic_hook", + "futures-util", + "getrandom 0.1.16", + "js-sys", + "log", + "magic-wormhole", + "serde", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test", + "wasm-logger", + "web-sys", + "wee_alloc", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -1223,6 +1270,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1246,7 +1299,7 @@ checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf" dependencies = [ "bitflags", "cc", - "cfg-if", + "cfg-if 1.0.0", "libc", "memoffset", ] @@ -1259,7 +1312,7 @@ checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" dependencies = [ "bitflags", "cc", - "cfg-if", + "cfg-if 1.0.0", "libc", "memoffset", ] @@ -1271,7 +1324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f17df307904acd05aa8e32e97bb20f2a0df1728bbc2d771ae8f9a90463441e9" dependencies = [ "bitflags", - "cfg-if", + "cfg-if 1.0.0", "libc", ] @@ -1420,7 +1473,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "instant", "libc", "redox_syscall", @@ -1478,7 +1531,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "log", "wepoll-ffi", @@ -1528,11 +1581,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1725,6 +1778,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "scoped-tls" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" + [[package]] name = "scopeguard" version = "1.1.0" @@ -1755,18 +1814,18 @@ checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -1790,7 +1849,7 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.3", ] @@ -1807,7 +1866,7 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.3", ] @@ -1920,13 +1979,13 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1946,7 +2005,7 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "libc", "redox_syscall", @@ -2055,7 +2114,7 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "pin-project-lite", "tracing-core", ] @@ -2165,6 +2224,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -2180,12 +2245,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - [[package]] name = "universal-hash" version = "0.4.1" @@ -2229,9 +2288,9 @@ checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "value-bag" -version = "1.0.0-alpha.8" +version = "1.0.0-alpha.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79923f7731dc61ebfba3633098bf3ac533bbd35ccd8c57e7088d9a5eebe0263f" +checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" dependencies = [ "ctor", "version_check", @@ -2263,19 +2322,21 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", + "serde", + "serde_json", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static", @@ -2288,11 +2349,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.29" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -2300,9 +2361,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2310,9 +2371,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -2323,9 +2384,44 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + +[[package]] +name = "wasm-bindgen-test" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4464b3f74729a25f42b1a0cd9e6a515d2f25001f3535a6cfaf35d34a4de3bab" +dependencies = [ + "console_error_panic_hook", + "js-sys", + "scoped-tls", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", +] + +[[package]] +name = "wasm-bindgen-test-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77c5a6f82cc6093a321ca5fb3dc9327fe51675d477b3799b4a9375bac3b7b4c" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasm-logger" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718" +dependencies = [ + "log", + "wasm-bindgen", + "web-sys", +] [[package]] name = "wasm-timer" @@ -2403,9 +2499,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", @@ -2430,6 +2526,18 @@ dependencies = [ "webpki", ] +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi 0.3.9", +] + [[package]] name = "wepoll-ffi" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index cc0b0276..a46f5706 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,5 +88,5 @@ strip = "debuginfo" lto = "thin" [workspace] -members = [".", "cli"] +members = [".", "cli", "wasm"] default-members = ["cli"] diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml new file mode 100644 index 00000000..8f09e266 --- /dev/null +++ b/wasm/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "magic-wormhole-wasm" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["wee_alloc"] + +[dependencies] +serde = { version = "1.0.137", features = ["derive"] } +wasm-bindgen = { version = "0.2.80", features = ["serde-serialize"] } +wasm-bindgen-futures = "0.4.30" +wasm-logger = "0.2.0" +log = "0.4.17" + +getrandom = { version = "0.1", features = ["wasm-bindgen"] } +url = { version = "2.2.2", features = ["serde"] } +clear_on_drop = { version = "0.2.5", features = ["no_cc"] } +magic-wormhole = { path = ".." } +web-sys = { version = "0.3.57", features = ["Blob"] } +js-sys = "0.3.57" +futures-util = "0.3.21" + +# The `console_error_panic_hook` crate provides better debugging of panics by +# logging them with `console.error`. This is great for development, but requires +# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for +# code size when deploying. +console_error_panic_hook = { version = "0.1.6", optional = true } + +# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size +# compared to the default allocator's ~10K. It is slower than the default +# allocator, however. +# +# Unfortunately, `wee_alloc` requires nightly Rust when targeting wasm for now. +wee_alloc = { version = "0.4.5", optional = true } + +[dev-dependencies] +wasm-bindgen-test = "0.3.13" + +[profile.release] +# Tell `rustc` to optimize for small code size. +opt-level = "s" +lto = true diff --git a/wasm/src/event.rs b/wasm/src/event.rs new file mode 100644 index 00000000..d1fdbff6 --- /dev/null +++ b/wasm/src/event.rs @@ -0,0 +1,80 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +#[repr(u8)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +/// Type of an event. Used to determine the fields that are present in the [Event] +pub enum EventType { + None = 0, + Progress = 1, + ServerWelcome = 2, + FileMetadata = 3, + ConnectedToRelay = 4, + Code = 5, +} + +impl Default for EventType { + fn default() -> Self { + EventType::None + } +} + +#[derive(Default, serde::Serialize, serde::Deserialize)] +#[wasm_bindgen] +/// Event structure with all possible data fields. +/// Only the fields relevant for the [EventType] will be filled. +pub struct Event { + event_type: EventType, + server_welcome_message: String, + file_name: String, + file_size: u64, + progress_current: u64, + progress_total: u64, + code: String, +} + +/// Event for a server welcome message (should be shown if not empty). +pub fn server_welcome(server_welcome_message: String) -> Event { + Event { + event_type: EventType::ServerWelcome, + server_welcome_message, + ..Event::default() + } +} + +/// Event for file metadata (name & size). +pub fn file_metadata(file_name: String, file_size: u64) -> Event { + Event { + event_type: EventType::FileMetadata, + file_name, + file_size, + ..Event::default() + } +} + +// Event for establishing the connection to the relay. +pub fn connected() -> Event { + Event { + event_type: EventType::ConnectedToRelay, + ..Event::default() + } +} + +/// Event for the progress of a file transfer (send/receive). +pub fn progress(progress_current: u64, progress_total: u64) -> Event { + Event { + event_type: EventType::Progress, + progress_current, + progress_total, + ..Event::default() + } +} + +/// Event for a wormhole code (e.g. 15-foo-bar). +pub fn code(code: String) -> Event { + Event { + event_type: EventType::Code, + code, + ..Event::default() + } +} diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs new file mode 100644 index 00000000..e1cf617e --- /dev/null +++ b/wasm/src/lib.rs @@ -0,0 +1,180 @@ +use std::{error::Error, path::PathBuf, rc::Rc}; + +use futures_util::future::FutureExt; +use log::Level; +use magic_wormhole::{transfer, transit, Code, Wormhole}; +use wasm_bindgen::prelude::*; + +mod event; + +#[cfg(feature = "wee_alloc")] +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +/// convert an error to a string for using it as a [JsValue] +fn stringify(e: impl Error) -> String { + format!("error code: {}", e) +} + +#[wasm_bindgen] +/// Configuration for the wormhole communication. +pub struct WormholeConfig { + rendezvous_url: String, + relay_url: String, +} + +#[wasm_bindgen] +impl WormholeConfig { + /// Create a new wormhole configuration. + /// * `rendezvous_url` - A string with the websocket address for the rendezvous server + /// * `relay_url` - A string with the websocket address for the relay server + /// + /// **Attention**: To use the wasm-library on an https page, please use a secure websocket url + /// (i.e. `wss://...`) + pub fn new(rendezvous_url: String, relay_url: String) -> WormholeConfig { + wasm_logger::init(wasm_logger::Config::new(Level::Info)); + + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); + + WormholeConfig { + rendezvous_url, + relay_url, + } + } +} + +#[wasm_bindgen] +/// Send a file via wormhole. +/// * `config` - The configuration object for the wormhole, created by [WormholeConfig::new] +/// * `file` - The Blob with the file to send +/// * `file_name` - The name of the file to send +/// * `cancel` - A promise that cancels the transfer, if it is resolved +/// * `event_handler` - A callback function that receives [event::Event] objects with updates about +/// the sending status and progress +pub async fn send_file( + config: WormholeConfig, + file: web_sys::Blob, + file_name: String, + cancel: js_sys::Promise, + event_handler: js_sys::Function, +) -> Result { + let event_handler_wrap = Rc::new(Box::new(move |e: event::Event| { + event_handler + .call1(&JsValue::null(), &JsValue::from_serde(&e).unwrap()) + .expect("progress_handler call should succeed"); + }) as Box); + + let file_content = wasm_bindgen_futures::JsFuture::from(file.array_buffer()).await?; + let array = js_sys::Uint8Array::new(&file_content); + let len = array.byte_length() as u64; + let data_to_send: Vec = array.to_vec(); + + let (server_welcome, connector) = Wormhole::connect_without_code( + transfer::APP_CONFIG.rendezvous_url(config.rendezvous_url.into()), + 2, + ) + .await + .map_err(stringify)?; + + event_handler_wrap(event::code(server_welcome.code.0)); + + let ph = event_handler_wrap.clone(); + let wormhole = connector.await.map_err(stringify)?; + transfer::send_file( + wormhole, + url::Url::parse(&config.relay_url).unwrap(), + &mut &data_to_send[..], + PathBuf::from(file_name), + len, + transit::Abilities::FORCE_RELAY, + |_info, _address| { + event_handler_wrap(event::connected()); + }, + move |cur, total| { + ph(event::progress(cur, total)); + }, + wasm_bindgen_futures::JsFuture::from(cancel).map(|_x| ()), + ) + .await + .map_err(stringify)?; + + Ok("".into()) +} + +#[derive(serde::Serialize, serde::Deserialize)] +/// A structure of receiving a file +pub struct ReceiveResult { + data: Vec, + filename: String, + filesize: u64, +} + +#[wasm_bindgen] +/// Receive a file via wormhole. +/// * `config` - The configuration object for the wormhole, created by [WormholeConfig::new] +/// * `code` - The wormhole code (e.g. 15-foo-bar) +/// * `cancel` - A promise that cancels the transfer, if it is resolved +/// * `event_handler` - A callback function that receives [event::Event] objects with updates about +/// the receiving status and progress +/// +/// The returned promise resolves with a [ReceiveResult], containing the file contents and file metadata +pub async fn receive_file( + config: WormholeConfig, + code: String, + cancel: js_sys::Promise, + progress_handler: js_sys::Function, +) -> Result { + let event_handler = Rc::new(Box::new(move |e: event::Event| { + progress_handler + .call1(&JsValue::null(), &JsValue::from_serde(&e).unwrap()) + .expect("progress_handler call should succeed"); + }) as Box); + + let (server_welcome, wormhole) = Wormhole::connect_with_code( + transfer::APP_CONFIG.rendezvous_url(config.rendezvous_url.into()), + Code(code), + ) + .await + .map_err(stringify)?; + + event_handler(event::server_welcome( + server_welcome.welcome.unwrap_or_default(), + )); + + let req = transfer::request_file( + wormhole, + url::Url::parse(&config.relay_url).unwrap(), + transit::Abilities::FORCE_RELAY, + wasm_bindgen_futures::JsFuture::from(cancel.clone()).map(|_x| ()), + ) + .await + .map_err(stringify)? + .ok_or("")?; + + let filename = req.filename.to_str().unwrap_or_default().to_string(); + let filesize = req.filesize; + event_handler(event::file_metadata(filename.clone(), filesize)); + + let ph = event_handler.clone(); + let mut file: Vec = Vec::new(); + req.accept( + |_info, _address| { + event_handler(event::connected()); + }, + move |cur, total| { + ph(event::progress(cur, total)); + }, + &mut file, + wasm_bindgen_futures::JsFuture::from(cancel).map(|_x| ()), + ) + .await + .map_err(stringify)?; + + let result = ReceiveResult { + data: file, + filename, + filesize, + }; + Ok(JsValue::from_serde(&result).unwrap()) +} From 8ad1a386bda2d13b5b2c44f97dcb8f1472a2781c Mon Sep 17 00:00:00 2001 From: Andi Date: Wed, 1 Jun 2022 23:01:40 +0200 Subject: [PATCH 2/2] refactoring: associate event creation methods to event::Event --- wasm/src/event.rs | 72 ++++++++++++++++++++++++----------------------- wasm/src/lib.rs | 23 +++++++-------- 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/wasm/src/event.rs b/wasm/src/event.rs index d1fdbff6..c42c5b01 100644 --- a/wasm/src/event.rs +++ b/wasm/src/event.rs @@ -33,48 +33,50 @@ pub struct Event { code: String, } -/// Event for a server welcome message (should be shown if not empty). -pub fn server_welcome(server_welcome_message: String) -> Event { - Event { - event_type: EventType::ServerWelcome, - server_welcome_message, - ..Event::default() +impl Event { + /// Event for a server welcome message (should be shown if not empty). + pub fn server_welcome(server_welcome_message: String) -> Event { + Event { + event_type: EventType::ServerWelcome, + server_welcome_message, + ..Event::default() + } } -} -/// Event for file metadata (name & size). -pub fn file_metadata(file_name: String, file_size: u64) -> Event { - Event { - event_type: EventType::FileMetadata, - file_name, - file_size, - ..Event::default() + /// Event for file metadata (name & size). + pub fn file_metadata(file_name: String, file_size: u64) -> Event { + Event { + event_type: EventType::FileMetadata, + file_name, + file_size, + ..Event::default() + } } -} -// Event for establishing the connection to the relay. -pub fn connected() -> Event { - Event { - event_type: EventType::ConnectedToRelay, - ..Event::default() + // Event for establishing the connection to the relay. + pub fn connected() -> Event { + Event { + event_type: EventType::ConnectedToRelay, + ..Event::default() + } } -} -/// Event for the progress of a file transfer (send/receive). -pub fn progress(progress_current: u64, progress_total: u64) -> Event { - Event { - event_type: EventType::Progress, - progress_current, - progress_total, - ..Event::default() + /// Event for the progress of a file transfer (send/receive). + pub fn progress(progress_current: u64, progress_total: u64) -> Event { + Event { + event_type: EventType::Progress, + progress_current, + progress_total, + ..Event::default() + } } -} -/// Event for a wormhole code (e.g. 15-foo-bar). -pub fn code(code: String) -> Event { - Event { - event_type: EventType::Code, - code, - ..Event::default() + /// Event for a wormhole code (e.g. 15-foo-bar). + pub fn code(code: String) -> Event { + Event { + event_type: EventType::Code, + code, + ..Event::default() + } } } diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index e1cf617e..7be5d28a 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -6,6 +6,7 @@ use magic_wormhole::{transfer, transit, Code, Wormhole}; use wasm_bindgen::prelude::*; mod event; +use event::Event; #[cfg(feature = "wee_alloc")] #[global_allocator] @@ -59,11 +60,11 @@ pub async fn send_file( cancel: js_sys::Promise, event_handler: js_sys::Function, ) -> Result { - let event_handler_wrap = Rc::new(Box::new(move |e: event::Event| { + let event_handler_wrap = Rc::new(Box::new(move |e: Event| { event_handler .call1(&JsValue::null(), &JsValue::from_serde(&e).unwrap()) .expect("progress_handler call should succeed"); - }) as Box); + }) as Box); let file_content = wasm_bindgen_futures::JsFuture::from(file.array_buffer()).await?; let array = js_sys::Uint8Array::new(&file_content); @@ -77,7 +78,7 @@ pub async fn send_file( .await .map_err(stringify)?; - event_handler_wrap(event::code(server_welcome.code.0)); + event_handler_wrap(Event::code(server_welcome.code.0)); let ph = event_handler_wrap.clone(); let wormhole = connector.await.map_err(stringify)?; @@ -89,10 +90,10 @@ pub async fn send_file( len, transit::Abilities::FORCE_RELAY, |_info, _address| { - event_handler_wrap(event::connected()); + event_handler_wrap(Event::connected()); }, move |cur, total| { - ph(event::progress(cur, total)); + ph(Event::progress(cur, total)); }, wasm_bindgen_futures::JsFuture::from(cancel).map(|_x| ()), ) @@ -125,11 +126,11 @@ pub async fn receive_file( cancel: js_sys::Promise, progress_handler: js_sys::Function, ) -> Result { - let event_handler = Rc::new(Box::new(move |e: event::Event| { + let event_handler = Rc::new(Box::new(move |e: Event| { progress_handler .call1(&JsValue::null(), &JsValue::from_serde(&e).unwrap()) .expect("progress_handler call should succeed"); - }) as Box); + }) as Box); let (server_welcome, wormhole) = Wormhole::connect_with_code( transfer::APP_CONFIG.rendezvous_url(config.rendezvous_url.into()), @@ -138,7 +139,7 @@ pub async fn receive_file( .await .map_err(stringify)?; - event_handler(event::server_welcome( + event_handler(Event::server_welcome( server_welcome.welcome.unwrap_or_default(), )); @@ -154,16 +155,16 @@ pub async fn receive_file( let filename = req.filename.to_str().unwrap_or_default().to_string(); let filesize = req.filesize; - event_handler(event::file_metadata(filename.clone(), filesize)); + event_handler(Event::file_metadata(filename.clone(), filesize)); let ph = event_handler.clone(); let mut file: Vec = Vec::new(); req.accept( |_info, _address| { - event_handler(event::connected()); + event_handler(Event::connected()); }, move |cur, total| { - ph(event::progress(cur, total)); + ph(Event::progress(cur, total)); }, &mut file, wasm_bindgen_futures::JsFuture::from(cancel).map(|_x| ()),