diff --git a/.cargo/config.toml b/.cargo/config.toml index be7648c..c5c812f 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,6 @@ [build] -target="wasm32-wasi" -rustflags="-C target-feature=+bulk-memory" +target = "wasm32-wasi" +rustflags = "-C target-feature=+bulk-memory" [target.wasm32-wasi] -runner="wasmedge --dir=.:. " \ No newline at end of file +runner = "wasmedge --dir=.:. " diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index d0d1ffe..366d5be 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -32,12 +32,13 @@ jobs: - name: Install WasmEdge run: | - VERSION=0.11.2 - curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -e all --version=$VERSION --tf-version=$VERSION --tf-deps-version=$VERSION --tf-tools-version=$VERSION --image-version=$VERSION -p /usr/local - curl -sLO https://github.com/WasmEdge/WasmEdge/releases/download/0.12.0-alpha.1/WasmEdge-plugin-wasi_nn-tensorflowlite-0.12.0-alpha.1-ubuntu20.04_x86_64.tar.gz - tar -zxf WasmEdge-plugin-wasi_nn-tensorflowlite-*-ubuntu20.04_x86_64.tar.gz - rm -f WasmEdge-plugin-wasi_nn-tensorflowlite-*-ubuntu20.04_x86_64.tar.gz - sudo mv libwasmedgePluginWasiNN.so /usr/local/lib/wasmedge/ + VERSION=0.13.4 + curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -e all --version=$VERSION --plugins=wasi_nn-tensorflowlite -p /usr/local + wget https://github.com/WasmEdge/WasmEdge/releases/download/$VERSION/WasmEdge-plugin-wasmedge_rustls-$VERSION-ubuntu20.04_x86_64.tar.gz + sudo chmod +x /usr/local/lib/wasmedge + + tar -zxf WasmEdge-plugin-wasmedge_rustls-*-ubuntu20.04_x86_64.tar.gz + sudo mv libwasmedge_rustls.so /usr/local/lib/wasmedge/ - uses: actions/setup-node@v2 with: @@ -74,6 +75,11 @@ jobs: cargo build --target wasm32-wasi --release wasmedge --dir .:. target/wasm32-wasi/release/wasmedge_quickjs.wasm example_js/wasi_http_echo.js & + - name: Https fetch example + run: | + cargo build --target wasm32-wasi --release + wasmedge --dir .:. target/wasm32-wasi/release/wasmedge_quickjs.wasm example_js/wasi_https_fetch.js + - name: ES6 module run: | cargo build --target wasm32-wasi --release @@ -152,11 +158,6 @@ jobs: resp=$(curl http://localhost:8003) echo "$resp" - - name: Tensorflow example - run: | - cargo build --target wasm32-wasi --release --features=tensorflow - wasmedge-tensorflow-lite --dir .:. target/wasm32-wasi/release/wasmedge_quickjs.wasm example_js/tensorflow_lite_demo/main.js - - name: WASI-NN example (TensorflowLite) run: | cargo build --target wasm32-wasi --release --features=wasi_nn @@ -186,7 +187,7 @@ jobs: wasmedge --dir .:. target/wasm32-wasi/release/examples/js_extend.wasm - name: Node fs module test - #timeout-minutes: 10 + timeout-minutes: 60 run: | cargo test test_fs --target=wasm32-wasi --release diff --git a/Cargo.lock b/Cargo.lock index e05a0a3..8effea5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph_rasterizer" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "363b9b88fad3af3be80bc8f762c9a3f9dfe906fd0327b8e92f1c12e5ae1b8bbb" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "adler32" @@ -14,6 +14,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + [[package]] name = "argparse" version = "0.2.2" @@ -32,11 +41,17 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" + [[package]] name = "bytemuck" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" @@ -44,6 +59,18 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -76,9 +103,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -86,9 +113,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -97,26 +124,24 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.10" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", - "once_cell", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", - "once_cell", ] [[package]] @@ -135,11 +160,21 @@ dependencies = [ "byteorder", ] +[[package]] +name = "dns-parser" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" +dependencies = [ + "byteorder", + "quick-error", +] + [[package]] name = "either" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encoding" @@ -205,11 +240,45 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -222,23 +291,37 @@ checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "getrandom" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ + "cfg-if", "libc", + "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -270,13 +353,24 @@ dependencies = [ "image", "itertools", "num 0.3.1", - "rand", + "rand 0.7.3", "rand_distr", "rayon", "rulinalg", "rusttype", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.9.0" @@ -300,9 +394,31 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.132" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matrixmultiply" @@ -313,11 +429,17 @@ dependencies = [ "rawpointer", ] +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + [[package]] name = "memoffset" -version = "0.6.5" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -331,6 +453,19 @@ dependencies = [ "adler32", ] +[[package]] +name = "mio_wasi" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c72a987b9a838ae32dc0b1035835e3f00b5a3bb4ff698da463f8b540ce6647d" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasmedge_wasi_socket", + "windows-sys 0.45.0", +] + [[package]] name = "num" version = "0.1.42" @@ -411,43 +546,66 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] [[package]] -name = "once_cell" -version = "1.14.0" +name = "owned_ttf_parser" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" +checksum = "05e6affeb1632d6ff6a23d2cd40ffed138e82f1532571a26f527c8a284bb2fbb" +dependencies = [ + "ttf-parser", +] [[package]] -name = "owned_ttf_parser" -version = "0.6.0" +name = "parking_lot" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ - "ttf-parser", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.1", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project-lite" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "png" @@ -455,7 +613,7 @@ version = "0.16.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "crc32fast", "deflate", "miniz_oxide", @@ -463,9 +621,33 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] [[package]] name = "rand" @@ -473,13 +655,24 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.16", "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.2.2", + "rand_core 0.5.1", "rand_hc", ] +[[package]] +name = "rand" +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", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -487,7 +680,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", +] + +[[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]] @@ -496,7 +699,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.10", ] [[package]] @@ -505,7 +717,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2" dependencies = [ - "rand", + "rand 0.7.3", ] [[package]] @@ -514,7 +726,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", ] [[package]] @@ -525,21 +737,19 @@ checksum = "ebac11a9d2e11f2af219b8b8d833b76b1ea0e054aa0e8d8e9e4cbde353bdf019" [[package]] name = "rayon" -version = "1.5.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ - "autocfg", - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.9.3" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -547,6 +757,44 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + [[package]] name = "rulinalg" version = "0.4.2" @@ -557,11 +805,24 @@ dependencies = [ "num 0.1.42", ] +[[package]] +name = "rustix" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "rusttype" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" +checksum = "3ff8374aa04134254b7995b63ad3dc41c7f7236f69528b28553da7d72efaa967" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -569,9 +830,54 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "socket2" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] [[package]] name = "tinyvec" @@ -584,36 +890,74 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio-macros" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio_wasi" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3a7120cdbe4719425355a0f6b59191c67ab5ed4eebc64bdb12ea3bc8776adf" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio_wasi", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "wasmedge_wasi_socket", + "windows-sys 0.45.0", +] [[package]] name = "ttf-parser" -version = "0.6.2" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" +checksum = "7b3e06c9b9d80ed6b745c7159c40b311ad2916abb34a49e9be2653b90db0d8dd" [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -626,15 +970,210 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasmedge_quickjs" -version = "0.4.0-alpha" +version = "0.5.0-alpha" dependencies = [ "argparse", "encoding", + "env_logger", "image", "imageproc", "lazy_static", "libc", + "log", + "tokio_wasi", "url", + "wasmedge_rustls_api", + "wasmedge_wasi_socket", +] + +[[package]] +name = "wasmedge_rustls_api" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65061f066893c0173981dd57f9f6aa6c85009e8c4b39471d471303f8e9ae63d0" +dependencies = [ + "tokio_wasi", ] + +[[package]] +name = "wasmedge_wasi_socket" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900a4c17690ef5efcccbdc833853b3e48f2a0de589427a609ddb5e866e1cb91f" +dependencies = [ + "bytes", + "dns-parser", + "libc", + "rand 0.8.5", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/Cargo.toml b/Cargo.toml index bccc6b9..4e664b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,17 @@ libc = "0.2" url = "2.2.2" lazy_static = "1.4" encoding = "0.2" +wasmedge_wasi_socket = { version = "0.5", features = ["wasi_poll"] } +tokio_wasi = { version = "1.25.2", features = ["full"] } +log = "0.4.19" +env_logger = "0.10.0" +wasmedge_rustls_api = { version = "0.1.1", features = [ + "tokio_async", +], optional = true } [features] -default = [] +default = ["tls"] +tls = ["wasmedge_rustls_api"] img = ["image", "imageproc"] tensorflow = ["img"] wasi_nn = ["img"] diff --git a/example_js/hello.js b/example_js/hello.js index 3ee3ba8..276594b 100644 --- a/example_js/hello.js +++ b/example_js/hello.js @@ -4,11 +4,53 @@ import * as process from 'process' args = args.slice(1); print('Hello', ...args); + +let id = setTimeout(() => { + print('setTimeout 2s cancel'); +}, 2000); + +print(id); +clearTimeout(id); + setTimeout(() => { - print('timeout 2s'); + print('setTimeout 2s'); }, 2000); let env = process.env -for(var k in env){ - print(k,'=',env[k]) +for (var k in env) { + print(k, '=', env[k]) +} + +let thenable = { + data: 1, + then(onFulfilled, onRejected) { + print("then:") + onFulfilled(2) + } +} + + + +async function xx() { + let p = new Promise((r) => { + nextTick(() => { + print("nextTick") + r(1) + }) + }) + + let a = sleep(() => { + print('timeout 1s'); + }, 1000).then((v) => { + return thenable; + }); + let x = await p; + print("end await p", x); + let v = await a; + print("end xx", v); } + +xx() + +print('end main') + diff --git a/example_js/wasi_https_fetch.js b/example_js/wasi_https_fetch.js new file mode 100644 index 0000000..44519c4 --- /dev/null +++ b/example_js/wasi_https_fetch.js @@ -0,0 +1,36 @@ +import { fetch } from 'http' + +async function test_fetch() { + try { + let r = await fetch('https://httpbin.org/get?id=1') + print('test_fetch\n', await r.text()) + } catch (e) { + print(e) + } +} +test_fetch() + +async function test_fetch_post() { + try { + let r = await fetch("https://httpbin.org/post", { method: 'post', 'body': 'post_body' }) + print('test_fetch_post\n', await r.text()) + } catch (e) { + print(e) + } +} +test_fetch_post() + +async function test_fetch_put() { + try { + let r = await fetch("https://httpbin.org/put", + { + method: "put", + body: JSON.stringify({ a: 1 }), + headers: { 'Context-type': 'application/json' } + }) + print('test_fetch_put\n', await r.text()) + } catch (e) { + print(e) + } +} +test_fetch_put() \ No newline at end of file diff --git a/example_js/wasi_net_echo.js b/example_js/wasi_net_echo.js index 3e32579..bf5ecb1 100644 --- a/example_js/wasi_net_echo.js +++ b/example_js/wasi_net_echo.js @@ -37,7 +37,7 @@ server_start(); async function connect_test() { try { - let ss = await net.WasiTcpConn.connect('127.0.0.1:8000') + let ss = await net.WasiTcpConn.connect('127.0.0.1', 8000) ss.write('hello'); let msg = await ss.read() || ""; print('client recv:', new TextDecoder().decode(msg)); diff --git a/examples/js_extend.rs b/examples/js_extend.rs index 5c93754..dc75af6 100644 --- a/examples/js_extend.rs +++ b/examples/js_extend.rs @@ -96,7 +96,7 @@ impl ExtendsJsClassDef for ClassB { type BaseDef = ClassA; - const CLASS_NAME: &'static str = "ClassB"; + const EXT_CLASS_NAME: &'static str = "ClassB"; const CONSTRUCTOR_ARGC: u8 = 1; diff --git a/lib/binding.rs b/lib/binding.rs index 409b5ea..655d20d 100644 --- a/lib/binding.rs +++ b/lib/binding.rs @@ -1,164 +1,5 @@ -/* automatically generated by rust-bindgen 0.59.1 */ +/* automatically generated by rust-bindgen 0.66.1 */ -pub const _STDIO_H: u32 = 1; -pub const _FEATURES_H: u32 = 1; -pub const _DEFAULT_SOURCE: u32 = 1; -pub const __USE_ISOC11: u32 = 1; -pub const __USE_ISOC99: u32 = 1; -pub const __USE_ISOC95: u32 = 1; -pub const __USE_POSIX_IMPLICITLY: u32 = 1; -pub const _POSIX_SOURCE: u32 = 1; -pub const _POSIX_C_SOURCE: u32 = 200809; -pub const __USE_POSIX: u32 = 1; -pub const __USE_POSIX2: u32 = 1; -pub const __USE_POSIX199309: u32 = 1; -pub const __USE_POSIX199506: u32 = 1; -pub const __USE_XOPEN2K: u32 = 1; -pub const __USE_XOPEN2K8: u32 = 1; -pub const _ATFILE_SOURCE: u32 = 1; -pub const __USE_MISC: u32 = 1; -pub const __USE_ATFILE: u32 = 1; -pub const __USE_FORTIFY_LEVEL: u32 = 0; -pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; -pub const _STDC_PREDEF_H: u32 = 1; -pub const __STDC_IEC_559__: u32 = 1; -pub const __STDC_IEC_559_COMPLEX__: u32 = 1; -pub const __STDC_ISO_10646__: u32 = 201706; -pub const __STDC_NO_THREADS__: u32 = 1; -pub const __GNU_LIBRARY__: u32 = 6; -pub const __GLIBC__: u32 = 2; -pub const __GLIBC_MINOR__: u32 = 27; -pub const _SYS_CDEFS_H: u32 = 1; -pub const __glibc_c99_flexarr_available: u32 = 1; -pub const __WORDSIZE: u32 = 64; -pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; -pub const __SYSCALL_WORDSIZE: u32 = 64; -pub const __HAVE_GENERIC_SELECTION: u32 = 1; -pub const __GLIBC_USE_LIB_EXT2: u32 = 0; -pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 0; -pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 0; -pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 0; -pub const _BITS_TYPES_H: u32 = 1; -pub const _BITS_TYPESIZES_H: u32 = 1; -pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; -pub const __INO_T_MATCHES_INO64_T: u32 = 1; -pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; -pub const __FD_SETSIZE: u32 = 1024; -pub const ____FILE_defined: u32 = 1; -pub const __FILE_defined: u32 = 1; -pub const _BITS_LIBIO_H: u32 = 1; -pub const _BITS_G_CONFIG_H: u32 = 1; -pub const ____mbstate_t_defined: u32 = 1; -pub const _G_HAVE_MMAP: u32 = 1; -pub const _G_HAVE_MREMAP: u32 = 1; -pub const _G_IO_IO_FILE_VERSION: u32 = 131073; -pub const _G_BUFSIZ: u32 = 8192; -pub const _IO_BUFSIZ: u32 = 8192; -pub const __GNUC_VA_LIST: u32 = 1; -pub const _IO_UNIFIED_JUMPTABLES: u32 = 1; -pub const EOF: i32 = -1; -pub const _IOS_INPUT: u32 = 1; -pub const _IOS_OUTPUT: u32 = 2; -pub const _IOS_ATEND: u32 = 4; -pub const _IOS_APPEND: u32 = 8; -pub const _IOS_TRUNC: u32 = 16; -pub const _IOS_NOCREATE: u32 = 32; -pub const _IOS_NOREPLACE: u32 = 64; -pub const _IOS_BIN: u32 = 128; -pub const _IO_MAGIC: u32 = 4222418944; -pub const _OLD_STDIO_MAGIC: u32 = 4206624768; -pub const _IO_MAGIC_MASK: u32 = 4294901760; -pub const _IO_USER_BUF: u32 = 1; -pub const _IO_UNBUFFERED: u32 = 2; -pub const _IO_NO_READS: u32 = 4; -pub const _IO_NO_WRITES: u32 = 8; -pub const _IO_EOF_SEEN: u32 = 16; -pub const _IO_ERR_SEEN: u32 = 32; -pub const _IO_DELETE_DONT_CLOSE: u32 = 64; -pub const _IO_LINKED: u32 = 128; -pub const _IO_IN_BACKUP: u32 = 256; -pub const _IO_LINE_BUF: u32 = 512; -pub const _IO_TIED_PUT_GET: u32 = 1024; -pub const _IO_CURRENTLY_PUTTING: u32 = 2048; -pub const _IO_IS_APPENDING: u32 = 4096; -pub const _IO_IS_FILEBUF: u32 = 8192; -pub const _IO_BAD_SEEN: u32 = 16384; -pub const _IO_USER_LOCK: u32 = 32768; -pub const _IO_FLAGS2_MMAP: u32 = 1; -pub const _IO_FLAGS2_NOTCANCEL: u32 = 2; -pub const _IO_FLAGS2_USER_WBUF: u32 = 8; -pub const _IO_SKIPWS: u32 = 1; -pub const _IO_LEFT: u32 = 2; -pub const _IO_RIGHT: u32 = 4; -pub const _IO_INTERNAL: u32 = 8; -pub const _IO_DEC: u32 = 16; -pub const _IO_OCT: u32 = 32; -pub const _IO_HEX: u32 = 64; -pub const _IO_SHOWBASE: u32 = 128; -pub const _IO_SHOWPOINT: u32 = 256; -pub const _IO_UPPERCASE: u32 = 512; -pub const _IO_SHOWPOS: u32 = 1024; -pub const _IO_SCIENTIFIC: u32 = 2048; -pub const _IO_FIXED: u32 = 4096; -pub const _IO_UNITBUF: u32 = 8192; -pub const _IO_STDIO: u32 = 16384; -pub const _IO_DONT_CLOSE: u32 = 32768; -pub const _IO_BOOLALPHA: u32 = 65536; -pub const _IOFBF: u32 = 0; -pub const _IOLBF: u32 = 1; -pub const _IONBF: u32 = 2; -pub const BUFSIZ: u32 = 8192; -pub const SEEK_SET: u32 = 0; -pub const SEEK_CUR: u32 = 1; -pub const SEEK_END: u32 = 2; -pub const P_tmpdir: &'static [u8; 5usize] = b"/tmp\0"; -pub const _BITS_STDIO_LIM_H: u32 = 1; -pub const L_tmpnam: u32 = 20; -pub const TMP_MAX: u32 = 238328; -pub const FILENAME_MAX: u32 = 4096; -pub const L_ctermid: u32 = 9; -pub const FOPEN_MAX: u32 = 16; -pub const _STDINT_H: u32 = 1; -pub const _BITS_WCHAR_H: u32 = 1; -pub const _BITS_STDINT_INTN_H: u32 = 1; -pub const _BITS_STDINT_UINTN_H: u32 = 1; -pub const INT8_MIN: i32 = -128; -pub const INT16_MIN: i32 = -32768; -pub const INT32_MIN: i32 = -2147483648; -pub const INT8_MAX: u32 = 127; -pub const INT16_MAX: u32 = 32767; -pub const INT32_MAX: u32 = 2147483647; -pub const UINT8_MAX: u32 = 255; -pub const UINT16_MAX: u32 = 65535; -pub const UINT32_MAX: u32 = 4294967295; -pub const INT_LEAST8_MIN: i32 = -128; -pub const INT_LEAST16_MIN: i32 = -32768; -pub const INT_LEAST32_MIN: i32 = -2147483648; -pub const INT_LEAST8_MAX: u32 = 127; -pub const INT_LEAST16_MAX: u32 = 32767; -pub const INT_LEAST32_MAX: u32 = 2147483647; -pub const UINT_LEAST8_MAX: u32 = 255; -pub const UINT_LEAST16_MAX: u32 = 65535; -pub const UINT_LEAST32_MAX: u32 = 4294967295; -pub const INT_FAST8_MIN: i32 = -128; -pub const INT_FAST16_MIN: i64 = -9223372036854775808; -pub const INT_FAST32_MIN: i64 = -9223372036854775808; -pub const INT_FAST8_MAX: u32 = 127; -pub const INT_FAST16_MAX: u64 = 9223372036854775807; -pub const INT_FAST32_MAX: u64 = 9223372036854775807; -pub const UINT_FAST8_MAX: u32 = 255; -pub const UINT_FAST16_MAX: i32 = -1; -pub const UINT_FAST32_MAX: i32 = -1; -pub const INTPTR_MIN: i64 = -9223372036854775808; -pub const INTPTR_MAX: u64 = 9223372036854775807; -pub const UINTPTR_MAX: i32 = -1; -pub const PTRDIFF_MIN: i64 = -9223372036854775808; -pub const PTRDIFF_MAX: u64 = 9223372036854775807; -pub const SIG_ATOMIC_MIN: i32 = -2147483648; -pub const SIG_ATOMIC_MAX: u32 = 2147483647; -pub const SIZE_MAX: i32 = -1; -pub const WINT_MIN: u32 = 0; -pub const WINT_MAX: u32 = 4294967295; pub const JS_PROP_CONFIGURABLE: u32 = 1; pub const JS_PROP_WRITABLE: u32 = 2; pub const JS_PROP_ENUMERABLE: u32 = 4; @@ -216,715 +57,7 @@ pub const JS_DEF_PROP_DOUBLE: u32 = 6; pub const JS_DEF_PROP_UNDEFINED: u32 = 7; pub const JS_DEF_OBJECT: u32 = 8; pub const JS_DEF_ALIAS: u32 = 9; -pub type __u_char = ::std::os::raw::c_uchar; -pub type __u_short = ::std::os::raw::c_ushort; -pub type __u_int = ::std::os::raw::c_uint; -pub type __u_long = ::std::os::raw::c_ulong; -pub type __int8_t = ::std::os::raw::c_schar; -pub type __uint8_t = ::std::os::raw::c_uchar; -pub type __int16_t = ::std::os::raw::c_short; -pub type __uint16_t = ::std::os::raw::c_ushort; -pub type __int32_t = ::std::os::raw::c_int; -pub type __uint32_t = ::std::os::raw::c_uint; -pub type __int64_t = ::std::os::raw::c_long; -pub type __uint64_t = ::std::os::raw::c_ulong; -pub type __quad_t = ::std::os::raw::c_long; -pub type __u_quad_t = ::std::os::raw::c_ulong; -pub type __intmax_t = ::std::os::raw::c_long; -pub type __uintmax_t = ::std::os::raw::c_ulong; -pub type __dev_t = ::std::os::raw::c_ulong; -pub type __uid_t = ::std::os::raw::c_uint; -pub type __gid_t = ::std::os::raw::c_uint; -pub type __ino_t = ::std::os::raw::c_ulong; -pub type __ino64_t = ::std::os::raw::c_ulong; -pub type __mode_t = ::std::os::raw::c_uint; -pub type __nlink_t = ::std::os::raw::c_ulong; -pub type __off_t = ::std::os::raw::c_long; -pub type __off64_t = ::std::os::raw::c_long; -pub type __pid_t = ::std::os::raw::c_int; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __fsid_t { - pub __val: [::std::os::raw::c_int; 2usize], -} -pub type __clock_t = ::std::os::raw::c_long; -pub type __rlim_t = ::std::os::raw::c_ulong; -pub type __rlim64_t = ::std::os::raw::c_ulong; -pub type __id_t = ::std::os::raw::c_uint; -pub type __time_t = ::std::os::raw::c_long; -pub type __useconds_t = ::std::os::raw::c_uint; -pub type __suseconds_t = ::std::os::raw::c_long; -pub type __daddr_t = ::std::os::raw::c_int; -pub type __key_t = ::std::os::raw::c_int; -pub type __clockid_t = ::std::os::raw::c_int; -pub type __timer_t = *mut ::std::os::raw::c_void; -pub type __blksize_t = ::std::os::raw::c_long; -pub type __blkcnt_t = ::std::os::raw::c_long; -pub type __blkcnt64_t = ::std::os::raw::c_long; -pub type __fsblkcnt_t = ::std::os::raw::c_ulong; -pub type __fsblkcnt64_t = ::std::os::raw::c_ulong; -pub type __fsfilcnt_t = ::std::os::raw::c_ulong; -pub type __fsfilcnt64_t = ::std::os::raw::c_ulong; -pub type __fsword_t = ::std::os::raw::c_long; -pub type __ssize_t = ::std::os::raw::c_long; -pub type __syscall_slong_t = ::std::os::raw::c_long; -pub type __syscall_ulong_t = ::std::os::raw::c_ulong; -pub type __loff_t = __off64_t; -pub type __caddr_t = *mut ::std::os::raw::c_char; -pub type __intptr_t = ::std::os::raw::c_long; -pub type __socklen_t = ::std::os::raw::c_uint; -pub type __sig_atomic_t = ::std::os::raw::c_int; -pub type __FILE = _IO_FILE; -pub type FILE = _IO_FILE; -#[repr(C)] -#[derive(Copy, Clone)] -pub struct __mbstate_t { - pub __count: ::std::os::raw::c_int, - pub __value: __mbstate_t__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union __mbstate_t__bindgen_ty_1 { - pub __wch: ::std::os::raw::c_uint, - pub __wchb: [::std::os::raw::c_char; 4usize], -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct _G_fpos_t { - pub __pos: __off_t, - pub __state: __mbstate_t, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct _G_fpos64_t { - pub __pos: __off64_t, - pub __state: __mbstate_t, -} -pub type va_list = __builtin_va_list; -pub type __gnuc_va_list = __builtin_va_list; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _IO_jump_t { - _unused: [u8; 0], -} -pub type _IO_lock_t = ::std::os::raw::c_void; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _IO_marker { - pub _next: *mut _IO_marker, - pub _sbuf: *mut _IO_FILE, - pub _pos: ::std::os::raw::c_int, -} -pub const __codecvt_result___codecvt_ok: __codecvt_result = 0; -pub const __codecvt_result___codecvt_partial: __codecvt_result = 1; -pub const __codecvt_result___codecvt_error: __codecvt_result = 2; -pub const __codecvt_result___codecvt_noconv: __codecvt_result = 3; -pub type __codecvt_result = ::std::os::raw::c_uint; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _IO_FILE { - pub _flags: ::std::os::raw::c_int, - pub _IO_read_ptr: *mut ::std::os::raw::c_char, - pub _IO_read_end: *mut ::std::os::raw::c_char, - pub _IO_read_base: *mut ::std::os::raw::c_char, - pub _IO_write_base: *mut ::std::os::raw::c_char, - pub _IO_write_ptr: *mut ::std::os::raw::c_char, - pub _IO_write_end: *mut ::std::os::raw::c_char, - pub _IO_buf_base: *mut ::std::os::raw::c_char, - pub _IO_buf_end: *mut ::std::os::raw::c_char, - pub _IO_save_base: *mut ::std::os::raw::c_char, - pub _IO_backup_base: *mut ::std::os::raw::c_char, - pub _IO_save_end: *mut ::std::os::raw::c_char, - pub _markers: *mut _IO_marker, - pub _chain: *mut _IO_FILE, - pub _fileno: ::std::os::raw::c_int, - pub _flags2: ::std::os::raw::c_int, - pub _old_offset: __off_t, - pub _cur_column: ::std::os::raw::c_ushort, - pub _vtable_offset: ::std::os::raw::c_schar, - pub _shortbuf: [::std::os::raw::c_char; 1usize], - pub _lock: *mut _IO_lock_t, - pub _offset: __off64_t, - pub __pad1: *mut ::std::os::raw::c_void, - pub __pad2: *mut ::std::os::raw::c_void, - pub __pad3: *mut ::std::os::raw::c_void, - pub __pad4: *mut ::std::os::raw::c_void, - pub __pad5: usize, - pub _mode: ::std::os::raw::c_int, - pub _unused2: [::std::os::raw::c_char; 20usize], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _IO_FILE_plus { - _unused: [u8; 0], -} -extern "C" { - pub static mut _IO_2_1_stdin_: _IO_FILE_plus; -} -extern "C" { - pub static mut _IO_2_1_stdout_: _IO_FILE_plus; -} -extern "C" { - pub static mut _IO_2_1_stderr_: _IO_FILE_plus; -} -pub type __io_read_fn = ::std::option::Option< - unsafe extern "C" fn( - __cookie: *mut ::std::os::raw::c_void, - __buf: *mut ::std::os::raw::c_char, - __nbytes: usize, - ) -> __ssize_t, ->; -pub type __io_write_fn = ::std::option::Option< - unsafe extern "C" fn( - __cookie: *mut ::std::os::raw::c_void, - __buf: *const ::std::os::raw::c_char, - __n: usize, - ) -> __ssize_t, ->; -pub type __io_seek_fn = ::std::option::Option< - unsafe extern "C" fn( - __cookie: *mut ::std::os::raw::c_void, - __pos: *mut __off64_t, - __w: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int, ->; -pub type __io_close_fn = ::std::option::Option< - unsafe extern "C" fn(__cookie: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int, ->; -extern "C" { - pub fn __underflow(arg1: *mut _IO_FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn __uflow(arg1: *mut _IO_FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn __overflow(arg1: *mut _IO_FILE, arg2: ::std::os::raw::c_int) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_getc(__fp: *mut _IO_FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_putc(__c: ::std::os::raw::c_int, __fp: *mut _IO_FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_feof(__fp: *mut _IO_FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_ferror(__fp: *mut _IO_FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_peekc_locked(__fp: *mut _IO_FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_flockfile(arg1: *mut _IO_FILE); -} -extern "C" { - pub fn _IO_funlockfile(arg1: *mut _IO_FILE); -} -extern "C" { - pub fn _IO_ftrylockfile(arg1: *mut _IO_FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_vfscanf( - arg1: *mut _IO_FILE, - arg2: *const ::std::os::raw::c_char, - arg3: *mut __va_list_tag, - arg4: *mut ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_vfprintf( - arg1: *mut _IO_FILE, - arg2: *const ::std::os::raw::c_char, - arg3: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn _IO_padn(arg1: *mut _IO_FILE, arg2: ::std::os::raw::c_int, arg3: __ssize_t) - -> __ssize_t; -} -extern "C" { - pub fn _IO_sgetn(arg1: *mut _IO_FILE, arg2: *mut ::std::os::raw::c_void, arg3: usize) -> usize; -} -extern "C" { - pub fn _IO_seekoff( - arg1: *mut _IO_FILE, - arg2: __off64_t, - arg3: ::std::os::raw::c_int, - arg4: ::std::os::raw::c_int, - ) -> __off64_t; -} -extern "C" { - pub fn _IO_seekpos( - arg1: *mut _IO_FILE, - arg2: __off64_t, - arg3: ::std::os::raw::c_int, - ) -> __off64_t; -} -extern "C" { - pub fn _IO_free_backup_area(arg1: *mut _IO_FILE); -} -pub type off_t = __off_t; -pub type fpos_t = _G_fpos_t; -extern "C" { - pub static mut stdin: *mut _IO_FILE; -} -extern "C" { - pub static mut stdout: *mut _IO_FILE; -} -extern "C" { - pub static mut stderr: *mut _IO_FILE; -} -extern "C" { - pub fn remove(__filename: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn rename( - __old: *const ::std::os::raw::c_char, - __new: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn renameat( - __oldfd: ::std::os::raw::c_int, - __old: *const ::std::os::raw::c_char, - __newfd: ::std::os::raw::c_int, - __new: *const ::std::os::raw::c_char, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn tmpfile() -> *mut FILE; -} -extern "C" { - pub fn tmpnam(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; -} -extern "C" { - pub fn tmpnam_r(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; -} -extern "C" { - pub fn tempnam( - __dir: *const ::std::os::raw::c_char, - __pfx: *const ::std::os::raw::c_char, - ) -> *mut ::std::os::raw::c_char; -} -extern "C" { - pub fn fclose(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fflush(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fflush_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fopen( - __filename: *const ::std::os::raw::c_char, - __modes: *const ::std::os::raw::c_char, - ) -> *mut FILE; -} -extern "C" { - pub fn freopen( - __filename: *const ::std::os::raw::c_char, - __modes: *const ::std::os::raw::c_char, - __stream: *mut FILE, - ) -> *mut FILE; -} -extern "C" { - pub fn fdopen(__fd: ::std::os::raw::c_int, __modes: *const ::std::os::raw::c_char) - -> *mut FILE; -} -extern "C" { - pub fn fmemopen( - __s: *mut ::std::os::raw::c_void, - __len: usize, - __modes: *const ::std::os::raw::c_char, - ) -> *mut FILE; -} -extern "C" { - pub fn open_memstream( - __bufloc: *mut *mut ::std::os::raw::c_char, - __sizeloc: *mut usize, - ) -> *mut FILE; -} -extern "C" { - pub fn setbuf(__stream: *mut FILE, __buf: *mut ::std::os::raw::c_char); -} -extern "C" { - pub fn setvbuf( - __stream: *mut FILE, - __buf: *mut ::std::os::raw::c_char, - __modes: ::std::os::raw::c_int, - __n: usize, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn setbuffer(__stream: *mut FILE, __buf: *mut ::std::os::raw::c_char, __size: usize); -} -extern "C" { - pub fn setlinebuf(__stream: *mut FILE); -} -extern "C" { - pub fn fprintf( - __stream: *mut FILE, - __format: *const ::std::os::raw::c_char, - ... - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn printf(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn sprintf( - __s: *mut ::std::os::raw::c_char, - __format: *const ::std::os::raw::c_char, - ... - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn vfprintf( - __s: *mut FILE, - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn vprintf( - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn vsprintf( - __s: *mut ::std::os::raw::c_char, - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn snprintf( - __s: *mut ::std::os::raw::c_char, - __maxlen: ::std::os::raw::c_ulong, - __format: *const ::std::os::raw::c_char, - ... - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn vsnprintf( - __s: *mut ::std::os::raw::c_char, - __maxlen: ::std::os::raw::c_ulong, - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn vdprintf( - __fd: ::std::os::raw::c_int, - __fmt: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn dprintf( - __fd: ::std::os::raw::c_int, - __fmt: *const ::std::os::raw::c_char, - ... - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fscanf( - __stream: *mut FILE, - __format: *const ::std::os::raw::c_char, - ... - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn scanf(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn sscanf( - __s: *const ::std::os::raw::c_char, - __format: *const ::std::os::raw::c_char, - ... - ) -> ::std::os::raw::c_int; -} -extern "C" { - #[link_name = "\u{1}__isoc99_fscanf"] - pub fn fscanf1( - __stream: *mut FILE, - __format: *const ::std::os::raw::c_char, - ... - ) -> ::std::os::raw::c_int; -} -extern "C" { - #[link_name = "\u{1}__isoc99_scanf"] - pub fn scanf1(__format: *const ::std::os::raw::c_char, ...) -> ::std::os::raw::c_int; -} -extern "C" { - #[link_name = "\u{1}__isoc99_sscanf"] - pub fn sscanf1( - __s: *const ::std::os::raw::c_char, - __format: *const ::std::os::raw::c_char, - ... - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn vfscanf( - __s: *mut FILE, - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn vscanf( - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn vsscanf( - __s: *const ::std::os::raw::c_char, - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - #[link_name = "\u{1}__isoc99_vfscanf"] - pub fn vfscanf1( - __s: *mut FILE, - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - #[link_name = "\u{1}__isoc99_vscanf"] - pub fn vscanf1( - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - #[link_name = "\u{1}__isoc99_vsscanf"] - pub fn vsscanf1( - __s: *const ::std::os::raw::c_char, - __format: *const ::std::os::raw::c_char, - __arg: *mut __va_list_tag, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fgetc(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn getc(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn getchar() -> ::std::os::raw::c_int; -} -extern "C" { - pub fn getc_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn getchar_unlocked() -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fgetc_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fputc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn putc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn putchar(__c: ::std::os::raw::c_int) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fputc_unlocked(__c: ::std::os::raw::c_int, __stream: *mut FILE) - -> ::std::os::raw::c_int; -} -extern "C" { - pub fn putc_unlocked(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn putchar_unlocked(__c: ::std::os::raw::c_int) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn getw(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn putw(__w: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fgets( - __s: *mut ::std::os::raw::c_char, - __n: ::std::os::raw::c_int, - __stream: *mut FILE, - ) -> *mut ::std::os::raw::c_char; -} -extern "C" { - pub fn __getdelim( - __lineptr: *mut *mut ::std::os::raw::c_char, - __n: *mut usize, - __delimiter: ::std::os::raw::c_int, - __stream: *mut FILE, - ) -> __ssize_t; -} -extern "C" { - pub fn getdelim( - __lineptr: *mut *mut ::std::os::raw::c_char, - __n: *mut usize, - __delimiter: ::std::os::raw::c_int, - __stream: *mut FILE, - ) -> __ssize_t; -} -extern "C" { - pub fn getline( - __lineptr: *mut *mut ::std::os::raw::c_char, - __n: *mut usize, - __stream: *mut FILE, - ) -> __ssize_t; -} -extern "C" { - pub fn fputs(__s: *const ::std::os::raw::c_char, __stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn puts(__s: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn ungetc(__c: ::std::os::raw::c_int, __stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fread( - __ptr: *mut ::std::os::raw::c_void, - __size: usize, - __n: usize, - __stream: *mut FILE, - ) -> usize; -} -extern "C" { - pub fn fwrite( - __ptr: *const ::std::os::raw::c_void, - __size: usize, - __n: usize, - __s: *mut FILE, - ) -> usize; -} -extern "C" { - pub fn fread_unlocked( - __ptr: *mut ::std::os::raw::c_void, - __size: usize, - __n: usize, - __stream: *mut FILE, - ) -> usize; -} -extern "C" { - pub fn fwrite_unlocked( - __ptr: *const ::std::os::raw::c_void, - __size: usize, - __n: usize, - __stream: *mut FILE, - ) -> usize; -} -extern "C" { - pub fn fseek( - __stream: *mut FILE, - __off: ::std::os::raw::c_long, - __whence: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn ftell(__stream: *mut FILE) -> ::std::os::raw::c_long; -} -extern "C" { - pub fn rewind(__stream: *mut FILE); -} -extern "C" { - pub fn fseeko( - __stream: *mut FILE, - __off: __off_t, - __whence: ::std::os::raw::c_int, - ) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn ftello(__stream: *mut FILE) -> __off_t; -} -extern "C" { - pub fn fgetpos(__stream: *mut FILE, __pos: *mut fpos_t) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fsetpos(__stream: *mut FILE, __pos: *const fpos_t) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn clearerr(__stream: *mut FILE); -} -extern "C" { - pub fn feof(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn ferror(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn clearerr_unlocked(__stream: *mut FILE); -} -extern "C" { - pub fn feof_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn ferror_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn perror(__s: *const ::std::os::raw::c_char); -} -extern "C" { - pub static mut sys_nerr: ::std::os::raw::c_int; -} -extern "C" { - pub static mut sys_errlist: [*const ::std::os::raw::c_char; 0usize]; -} -extern "C" { - pub fn fileno(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn fileno_unlocked(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn popen( - __command: *const ::std::os::raw::c_char, - __modes: *const ::std::os::raw::c_char, - ) -> *mut FILE; -} -extern "C" { - pub fn pclose(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn ctermid(__s: *mut ::std::os::raw::c_char) -> *mut ::std::os::raw::c_char; -} -extern "C" { - pub fn flockfile(__stream: *mut FILE); -} -extern "C" { - pub fn ftrylockfile(__stream: *mut FILE) -> ::std::os::raw::c_int; -} -extern "C" { - pub fn funlockfile(__stream: *mut FILE); -} -pub type int_least8_t = ::std::os::raw::c_schar; -pub type int_least16_t = ::std::os::raw::c_short; -pub type int_least32_t = ::std::os::raw::c_int; -pub type int_least64_t = ::std::os::raw::c_long; -pub type uint_least8_t = ::std::os::raw::c_uchar; -pub type uint_least16_t = ::std::os::raw::c_ushort; -pub type uint_least32_t = ::std::os::raw::c_uint; -pub type uint_least64_t = ::std::os::raw::c_ulong; -pub type int_fast8_t = ::std::os::raw::c_schar; -pub type int_fast16_t = ::std::os::raw::c_long; -pub type int_fast32_t = ::std::os::raw::c_long; -pub type int_fast64_t = ::std::os::raw::c_long; -pub type uint_fast8_t = ::std::os::raw::c_uchar; -pub type uint_fast16_t = ::std::os::raw::c_ulong; -pub type uint_fast32_t = ::std::os::raw::c_ulong; -pub type uint_fast64_t = ::std::os::raw::c_ulong; -pub type intmax_t = __intmax_t; -pub type uintmax_t = __uintmax_t; + #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct JSRuntime { @@ -947,23 +80,23 @@ pub struct JSClass { } pub type JSClassID = u32; pub type JSAtom = u32; -pub const JS_TAG_FIRST: ::std::os::raw::c_int = -11; -pub const JS_TAG_BIG_DECIMAL: ::std::os::raw::c_int = -11; -pub const JS_TAG_BIG_INT: ::std::os::raw::c_int = -10; -pub const JS_TAG_BIG_FLOAT: ::std::os::raw::c_int = -9; -pub const JS_TAG_SYMBOL: ::std::os::raw::c_int = -8; -pub const JS_TAG_STRING: ::std::os::raw::c_int = -7; -pub const JS_TAG_MODULE: ::std::os::raw::c_int = -3; -pub const JS_TAG_FUNCTION_BYTECODE: ::std::os::raw::c_int = -2; -pub const JS_TAG_OBJECT: ::std::os::raw::c_int = -1; -pub const JS_TAG_INT: ::std::os::raw::c_int = 0; -pub const JS_TAG_BOOL: ::std::os::raw::c_int = 1; -pub const JS_TAG_NULL: ::std::os::raw::c_int = 2; -pub const JS_TAG_UNDEFINED: ::std::os::raw::c_int = 3; -pub const JS_TAG_UNINITIALIZED: ::std::os::raw::c_int = 4; -pub const JS_TAG_CATCH_OFFSET: ::std::os::raw::c_int = 5; -pub const JS_TAG_EXCEPTION: ::std::os::raw::c_int = 6; -pub const JS_TAG_FLOAT64: ::std::os::raw::c_int = 7; +pub const JS_TAG_FIRST: _bindgen_ty_1 = -11; +pub const JS_TAG_BIG_DECIMAL: _bindgen_ty_1 = -11; +pub const JS_TAG_BIG_INT: _bindgen_ty_1 = -10; +pub const JS_TAG_BIG_FLOAT: _bindgen_ty_1 = -9; +pub const JS_TAG_SYMBOL: _bindgen_ty_1 = -8; +pub const JS_TAG_STRING: _bindgen_ty_1 = -7; +pub const JS_TAG_MODULE: _bindgen_ty_1 = -3; +pub const JS_TAG_FUNCTION_BYTECODE: _bindgen_ty_1 = -2; +pub const JS_TAG_OBJECT: _bindgen_ty_1 = -1; +pub const JS_TAG_INT: _bindgen_ty_1 = 0; +pub const JS_TAG_BOOL: _bindgen_ty_1 = 1; +pub const JS_TAG_NULL: _bindgen_ty_1 = 2; +pub const JS_TAG_UNDEFINED: _bindgen_ty_1 = 3; +pub const JS_TAG_UNINITIALIZED: _bindgen_ty_1 = 4; +pub const JS_TAG_CATCH_OFFSET: _bindgen_ty_1 = 5; +pub const JS_TAG_EXCEPTION: _bindgen_ty_1 = 6; +pub const JS_TAG_FLOAT64: _bindgen_ty_1 = 7; pub type _bindgen_ty_1 = ::std::os::raw::c_int; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -1249,12 +382,7 @@ pub struct JSMemoryUsage { pub binary_object_count: i64, pub binary_object_size: i64, } -extern "C" { - pub fn JS_ComputeMemoryUsage(rt: *mut JSRuntime, s: *mut JSMemoryUsage); -} -extern "C" { - pub fn JS_DumpMemoryUsage(fp: *mut FILE, s: *const JSMemoryUsage, rt: *mut JSRuntime); -} + extern "C" { pub fn JS_NewAtomLen( ctx: *mut JSContext, @@ -1462,12 +590,6 @@ extern "C" { extern "C" { pub fn JS_ThrowOutOfMemory(ctx: *mut JSContext) -> JSValue; } -extern "C" { - pub fn __JS_FreeValue(ctx: *mut JSContext, v: JSValue); -} -extern "C" { - pub fn __JS_FreeValueRT(rt: *mut JSRuntime, v: JSValue); -} extern "C" { pub fn JS_ToBool(ctx: *mut JSContext, val: JSValue) -> ::std::os::raw::c_int; } @@ -2021,19 +1143,19 @@ extern "C" { filename: *const ::std::os::raw::c_char, ) -> *mut JSModuleDef; } -pub const JSCFunctionEnum_JS_CFUNC_generic: JSCFunctionEnum = 0; -pub const JSCFunctionEnum_JS_CFUNC_generic_magic: JSCFunctionEnum = 1; -pub const JSCFunctionEnum_JS_CFUNC_constructor: JSCFunctionEnum = 2; -pub const JSCFunctionEnum_JS_CFUNC_constructor_magic: JSCFunctionEnum = 3; -pub const JSCFunctionEnum_JS_CFUNC_constructor_or_func: JSCFunctionEnum = 4; -pub const JSCFunctionEnum_JS_CFUNC_constructor_or_func_magic: JSCFunctionEnum = 5; -pub const JSCFunctionEnum_JS_CFUNC_f_f: JSCFunctionEnum = 6; -pub const JSCFunctionEnum_JS_CFUNC_f_f_f: JSCFunctionEnum = 7; -pub const JSCFunctionEnum_JS_CFUNC_getter: JSCFunctionEnum = 8; -pub const JSCFunctionEnum_JS_CFUNC_setter: JSCFunctionEnum = 9; -pub const JSCFunctionEnum_JS_CFUNC_getter_magic: JSCFunctionEnum = 10; -pub const JSCFunctionEnum_JS_CFUNC_setter_magic: JSCFunctionEnum = 11; -pub const JSCFunctionEnum_JS_CFUNC_iterator_next: JSCFunctionEnum = 12; +pub const JS_CFUNC_generic: JSCFunctionEnum = 0; +pub const JS_CFUNC_generic_magic: JSCFunctionEnum = 1; +pub const JS_CFUNC_constructor: JSCFunctionEnum = 2; +pub const JS_CFUNC_constructor_magic: JSCFunctionEnum = 3; +pub const JS_CFUNC_constructor_or_func: JSCFunctionEnum = 4; +pub const JS_CFUNC_constructor_or_func_magic: JSCFunctionEnum = 5; +pub const JS_CFUNC_f_f: JSCFunctionEnum = 6; +pub const JS_CFUNC_f_f_f: JSCFunctionEnum = 7; +pub const JS_CFUNC_getter: JSCFunctionEnum = 8; +pub const JS_CFUNC_setter: JSCFunctionEnum = 9; +pub const JS_CFUNC_getter_magic: JSCFunctionEnum = 10; +pub const JS_CFUNC_setter_magic: JSCFunctionEnum = 11; +pub const JS_CFUNC_iterator_next: JSCFunctionEnum = 12; pub type JSCFunctionEnum = ::std::os::raw::c_uint; #[repr(C)] #[derive(Copy, Clone)] @@ -2093,6 +1215,11 @@ pub union JSCFunctionType { ) -> JSValue, >, } +impl ::std::fmt::Debug for JSCFunctionType { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "JSCFunctionType {{ union }}") + } +} extern "C" { pub fn JS_NewCFunction2( ctx: *mut JSContext, @@ -2144,12 +1271,30 @@ pub struct JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_1 { pub cproto: u8, pub cfunc: JSCFunctionType, } +impl ::std::fmt::Debug for JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_1 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_1 {{ cfunc: {:?} }}", + self.cfunc + ) + } +} #[repr(C)] #[derive(Copy, Clone)] pub struct JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_2 { pub get: JSCFunctionType, pub set: JSCFunctionType, } +impl ::std::fmt::Debug for JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_2 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_2 {{ get: {:?}, set: {:?} }}", + self.get, self.set + ) + } +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_3 { @@ -2162,6 +1307,20 @@ pub struct JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_4 { pub tab: *const JSCFunctionListEntry, pub len: ::std::os::raw::c_int, } +impl ::std::fmt::Debug for JSCFunctionListEntry__bindgen_ty_1 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "JSCFunctionListEntry__bindgen_ty_1 {{ union }}") + } +} +impl ::std::fmt::Debug for JSCFunctionListEntry { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "JSCFunctionListEntry {{ name: {:?}, u: {:?} }}", + self.name, self.u + ) + } +} extern "C" { pub fn JS_SetPropertyFunctionList( ctx: *mut JSContext, @@ -2358,6 +1517,9 @@ extern "C" { extern "C" { pub fn JS_GetPromiseResult_real(ctx: *mut JSContext, this_val: JSValue) -> JSValue; } +extern "C" { + pub fn JS_GetPromiseState(ctx: *mut JSContext, this_val: JSValue) -> ::std::os::raw::c_int; +} extern "C" { pub fn JS_ToUint32_real( ctx: *mut JSContext, @@ -2400,13 +1562,6 @@ extern "C" { eval_flags: ::std::os::raw::c_int, ) -> ::std::os::raw::c_int; } -extern "C" { - pub fn memcpy( - str1: *mut ::std::os::raw::c_void, - str2: *const ::std::os::raw::c_void, - n: ::std::os::raw::c_ulong, - ) -> *mut ::std::os::raw::c_void; -} extern "C" { pub fn js_require(ctx: *mut JSContext, specifier: JSValue) -> JSValue; } @@ -2419,12 +1574,3 @@ extern "C" { extern "C" { pub fn js_null() -> JSValue; } -pub type __builtin_va_list = [__va_list_tag; 1usize]; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct __va_list_tag { - pub gp_offset: ::std::os::raw::c_uint, - pub fp_offset: ::std::os::raw::c_uint, - pub overflow_arg_area: *mut ::std::os::raw::c_void, - pub reg_save_area: *mut ::std::os::raw::c_void, -} diff --git a/lib/libquickjs.a b/lib/libquickjs.a index 22fd9ac..208194f 100644 Binary files a/lib/libquickjs.a and b/lib/libquickjs.a differ diff --git a/modules/http.js b/modules/http.js index 2cf07f2..0b3bf60 100644 --- a/modules/http.js +++ b/modules/http.js @@ -200,9 +200,13 @@ export async function fetch(input, init = {}) { headers['Host'] = url.host } - let addr = net.nsloopup(url.host, `${url.port}`)[0]; + var s; + if (url.scheme == 'https' && net.WasiTlsConn) { + s = await net.WasiTlsConn.connect(url.host, url.port); + } else { + s = await net.WasiTcpConn.connect(url.host, url.port); + } - let s = await net.WasiTcpConn.connect(addr) let req = new httpx.WasiRequest() req.version = init.version || 'HTTP/1.1' req.headers = headers diff --git a/src/event_loop/mod.rs b/src/event_loop/mod.rs index 7c30ce5..c1332eb 100644 --- a/src/event_loop/mod.rs +++ b/src/event_loop/mod.rs @@ -2,16 +2,18 @@ mod poll; pub mod wasi_fs; mod wasi_sock; -use crate::event_loop::poll::{Eventtype, Subscription}; -use crate::{quickjs_sys as qjs, Context, JsValue}; +use crate::{quickjs_sys as qjs, Context, JsClassTool, JsValue}; use std::borrow::BorrowMut; use std::cell::RefCell; use std::collections::{HashMap, LinkedList}; -use std::io; +use std::io::{self, Read, Write}; use std::mem::ManuallyDrop; use std::net::{SocketAddr, SocketAddrV4}; use std::ops::Add; +use std::os::fd::{AsRawFd, FromRawFd}; +use std::sync::atomic::AtomicUsize; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; pub use wasi_sock::nslookup; pub(crate) enum NetPollEvent { @@ -20,676 +22,196 @@ pub(crate) enum NetPollEvent { Connect, } -pub struct AsyncTcpServer(wasi_sock::Socket); +pub struct AsyncTcpServer(pub(crate) tokio::net::TcpListener); impl AsyncTcpServer { - pub fn async_accept( + pub fn bind(port: u16) -> io::Result { + let listener = wasmedge_wasi_socket::TcpListener::bind(("0.0.0.0", port), true)?; + let async_listener = tokio::net::TcpListener::from_std(listener)?; + Ok(AsyncTcpServer(async_listener)) + } + + pub async fn accept( &mut self, - event_loop: &mut EventLoop, - callback: Box, + ctx: &mut Context, timeout: Option, - ) { - let s = self.0 .0; - if let Some(timeout) = timeout { - let ddl = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .add(timeout) - .as_nanos(); - event_loop - .io_selector - .add_task(PollTask::SocketTimeout(SocketTimeoutTask { - s, - event: NetPollEvent::Accept, - timeout: ddl, - callback, - })); + ) -> Result { + if let Some(duration) = timeout { + match tokio::time::timeout(duration, self.0.accept()).await { + Ok(Ok((conn, addr))) => { + log::trace!("tcp accept a socket[{addr}]"); + Ok(AsyncTcpConn::wrap_obj(ctx, AsyncTcpConn(conn))) + } + Ok(Err(e)) => { + log::trace!("tcp accept error: {e}"); + Err(ctx.new_error(e.to_string().as_str())) + } + Err(e) => { + let err = std::io::Error::new(std::io::ErrorKind::TimedOut, e.to_string()); + Err(ctx.new_error(err.to_string().as_str()).into()) + } + } } else { - event_loop - .io_selector - .add_task(PollTask::Socket(SocketTask { - s, - event: NetPollEvent::Accept, - callback, - })); + match self.0.accept().await { + Ok((conn, addr)) => { + log::trace!("tcp accept a socket[{addr}]"); + Ok(AsyncTcpConn::wrap_obj(ctx, AsyncTcpConn(conn))) + } + Err(e) => { + log::trace!("tcp accept error: {e}"); + Err(ctx.new_error(e.to_string().as_str())) + } + } } } } -pub struct AsyncTcpConn(wasi_sock::Socket); +pub struct AsyncTcpConn(pub(crate) tokio::net::TcpStream); impl AsyncTcpConn { - pub fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.send(buf) + pub async fn async_connect(addr: R) -> io::Result { + tokio::net::TcpStream::connect(addr) + .await + .map(|conn| AsyncTcpConn(conn)) } - pub fn read(&mut self) -> io::Result> { - let mut buff = [0u8; 1024]; + pub async fn async_read_all(&mut self) -> io::Result> { let mut data = vec![]; + let mut buff = [0u8; 1024 * 4]; + + log::trace!("tcp read_all"); + loop { - match self.0.recv(&mut buff) { + match self.0.read(&mut buff).await { Ok(0) => { + log::trace!("tcp read: 0"); return Ok(data); } Ok(n) => { + log::trace!("tcp read: {n}"); data.extend_from_slice(&buff[0..n]); + if n < buff.len() { + return Ok(data); + } } Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + log::trace!("tcp read: WouldBlock"); return Ok(data); } Err(e) => { + log::trace!("tcp read: {e}"); return Err(e); } } } } - pub fn async_read( - &mut self, - event_loop: &mut EventLoop, - callback: Box, - timeout: Option, - ) { - if let Some(timeout) = timeout { - let ddl = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .add(timeout) - .as_nanos(); - - event_loop - .io_selector - .add_task(PollTask::SocketTimeout(SocketTimeoutTask { - s: self.0 .0, - event: NetPollEvent::Read, - timeout: ddl, - callback, - })); - } else { - event_loop - .io_selector - .add_task(PollTask::Socket(SocketTask { - s: self.0 .0, - event: NetPollEvent::Read, - callback, - })); - } - } - - pub fn flush(&mut self) -> io::Result<()> { - Ok(()) + pub async fn async_write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.0.write_all(buf).await } pub fn local(&self) -> io::Result { - self.0.get_local() + self.0.local_addr() } pub fn peer(&self) -> io::Result { - self.0.get_peer() + self.0.peer_addr() } } -pub enum PollResult { - Timeout, - Accept(AsyncTcpConn), - Read(Vec), - Connect(AsyncTcpConn), - Error(io::Error), - Write(usize), -} +#[cfg(feature = "tls")] +pub struct AsyncTlsConn( + pub(crate) wasmedge_rustls_api::stream::async_stream::TlsStream, +); -struct TimeoutTask { - timeout: u128, - callback: Box, -} - -impl TimeoutTask { - fn as_subscription(&self, index: usize) -> Subscription { - let nanoseconds = self.timeout; - poll::Subscription { - userdata: index as u64, - u: poll::SubscriptionU { - tag: poll::EVENTTYPE_CLOCK, - u: poll::SubscriptionUU { - clock: poll::SubscriptionClock { - id: poll::CLOCKID_REALTIME, - timeout: nanoseconds as u64, - precision: 0, - flags: poll::SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME, - }, - }, - }, - } +#[cfg(feature = "tls")] +impl AsyncTlsConn { + pub async fn async_connect>( + addr: R, + domain: S, + ) -> io::Result { + use wasmedge_rustls_api::stream::async_stream::TlsStream; + use wasmedge_rustls_api::ClientConfig; + let io = tokio::net::TcpStream::connect(addr).await?; + let config = ClientConfig::default(); + let conn = TlsStream::connect(&config, domain, io) + .await + .map_err(|(e, _)| e)?; + Ok(Self(conn)) } -} -struct SocketTask { - s: wasi_sock::RawSocket, - event: NetPollEvent, - callback: Box, -} - -impl SocketTask { - fn as_subscription(&self, index: usize) -> Subscription { - match self.event { - NetPollEvent::Accept | NetPollEvent::Read => poll::Subscription { - userdata: index as u64, - u: poll::SubscriptionU { - tag: poll::EVENTTYPE_FD_READ, - u: poll::SubscriptionUU { - fd_read: poll::SubscriptionFdReadwrite { - file_descriptor: self.s as u32, - }, - }, - }, - }, - NetPollEvent::Connect => poll::Subscription { - userdata: index as u64, - u: poll::SubscriptionU { - tag: poll::EVENTTYPE_FD_WRITE, - u: poll::SubscriptionUU { - fd_read: poll::SubscriptionFdReadwrite { - file_descriptor: self.s as u32, - }, - }, - }, - }, - } - } -} + pub async fn async_read_all(&mut self) -> io::Result> { + let mut data = vec![]; + let mut buff = [0u8; 1024 * 4]; -struct SocketTimeoutTask { - s: wasi_sock::RawSocket, - event: NetPollEvent, - timeout: u128, - callback: Box, -} + log::trace!("tls read_all"); -impl SocketTimeoutTask { - fn as_subscription(&self, index: usize) -> (Subscription, Subscription) { - let socket_task = match self.event { - NetPollEvent::Accept | NetPollEvent::Read => poll::Subscription { - userdata: index as u64, - u: poll::SubscriptionU { - tag: poll::EVENTTYPE_FD_READ, - u: poll::SubscriptionUU { - fd_read: poll::SubscriptionFdReadwrite { - file_descriptor: self.s as u32, - }, - }, - }, - }, - NetPollEvent::Connect => poll::Subscription { - userdata: index as u64, - u: poll::SubscriptionU { - tag: poll::EVENTTYPE_FD_WRITE, - u: poll::SubscriptionUU { - fd_read: poll::SubscriptionFdReadwrite { - file_descriptor: self.s as u32, - }, - }, - }, - }, - }; - let timeout_task = { - let nanoseconds = self.timeout; - poll::Subscription { - userdata: index as u64, - u: poll::SubscriptionU { - tag: poll::EVENTTYPE_CLOCK, - u: poll::SubscriptionUU { - clock: poll::SubscriptionClock { - id: poll::CLOCKID_REALTIME, - timeout: nanoseconds as u64, - precision: 0, - flags: poll::SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME, - }, - }, - }, + loop { + match self.0.read(&mut buff).await { + Ok(0) => { + log::trace!("tls read: 0"); + return Ok(data); + } + Ok(n) => { + log::trace!("tls read: {n}"); + data.extend_from_slice(&buff[0..n]); + if n < buff.len() { + return Ok(data); + } + } + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + log::trace!("tls read: WouldBlock"); + return Ok(data); + } + Err(e) => { + log::trace!("tls read: {e}"); + return Err(e); + } } - }; - (socket_task, timeout_task) - } -} - -struct FdReadTask { - fd: std::os::wasi::io::RawFd, - pos: i64, - len: u64, - callback: Box, -} - -impl FdReadTask { - fn as_subscription(&self, index: usize) -> Subscription { - poll::Subscription { - userdata: index as u64, - u: poll::SubscriptionU { - tag: poll::EVENTTYPE_FD_READ, - u: poll::SubscriptionUU { - fd_read: poll::SubscriptionFdReadwrite { - file_descriptor: self.fd as u32, - }, - }, - }, } } -} - -struct FdWriteTask { - fd: std::os::wasi::io::RawFd, - pos: i64, - buf: Vec, - callback: Box, -} - -impl FdWriteTask { - fn as_subscription(&self, index: usize) -> Subscription { - poll::Subscription { - userdata: index as u64, - u: poll::SubscriptionU { - tag: poll::EVENTTYPE_FD_WRITE, - u: poll::SubscriptionUU { - fd_write: poll::SubscriptionFdReadwrite { - file_descriptor: self.fd as u32, - }, - }, - }, - } - } -} -enum PollTask { - Timeout(TimeoutTask), - Socket(SocketTask), - SocketTimeout(SocketTimeoutTask), - FdRead(FdReadTask), - FdWrite(FdWriteTask), -} - -#[derive(Default)] -struct IoSelector { - tasks: Vec>, -} - -impl IoSelector { - pub fn add_task(&mut self, task: PollTask) -> usize { - let mut n = 0; - for t in &mut self.tasks { - if t.is_none() { - t.insert(task); - return n; - } - n += 1; - } - self.tasks.push(Some(task)); - n + pub async fn async_write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.0.write_all(buf).await } - pub fn delete_task(&mut self, id: usize) -> Option { - self.tasks.get_mut(id)?.take() + pub fn local(&self) -> io::Result { + self.0.get_ref().0.local_addr() } - pub fn poll(&mut self, ctx: &mut qjs::Context) -> io::Result { - let mut subscription_vec = Vec::with_capacity(self.tasks.len()); - for (i, timeout) in self.tasks.iter().enumerate() { - if let Some(task) = timeout { - match task { - PollTask::Timeout(task) => { - subscription_vec.push(task.as_subscription(i)); - } - PollTask::Socket(task) => { - subscription_vec.push(task.as_subscription(i)); - } - PollTask::SocketTimeout(task) => { - let (task1, task2) = task.as_subscription(i); - subscription_vec.push(task1); - subscription_vec.push(task2); - } - PollTask::FdRead(task) => { - subscription_vec.push(task.as_subscription(i)); - } - PollTask::FdWrite(task) => { - subscription_vec.push(task.as_subscription(i)); - } - } - } - } - - if subscription_vec.is_empty() { - return Ok(0); - } - let mut revent = vec![ - poll::Event { - userdata: 0, - error: 0, - type_: 0, - fd_readwrite: poll::EventFdReadwrite { - nbytes: 0, - flags: 0, - }, - }; - subscription_vec.len() - ]; - - let n = unsafe { - poll::poll_oneoff( - subscription_vec.as_ptr(), - revent.as_mut_ptr(), - subscription_vec.len(), - ) - }?; - - for i in 0..n { - let event = revent[i]; - let index = event.userdata as usize; - if let Some(task) = self.delete_task(index) { - match (task, event.type_) { - (PollTask::Timeout(TimeoutTask { callback, .. }), poll::EVENTTYPE_CLOCK) => { - callback(ctx, PollResult::Timeout); - } - ( - PollTask::SocketTimeout(SocketTimeoutTask { callback, .. }), - poll::EVENTTYPE_CLOCK, - ) => { - callback(ctx, PollResult::Timeout); - } - ( - PollTask::SocketTimeout(SocketTimeoutTask { - s, - event: net_event, - callback, - .. - }) - | PollTask::Socket(SocketTask { - s, - event: net_event, - callback, - .. - }), - poll::EVENTTYPE_FD_READ | poll::EVENTTYPE_FD_WRITE, - ) => { - if event.error > 0 { - let e = io::Error::from_raw_os_error(event.error as i32); - callback(ctx, PollResult::Error(e)); - continue; - } - - match net_event { - NetPollEvent::Accept => { - let s = std::mem::ManuallyDrop::new(wasi_sock::Socket(s)); - match s.accept(true) { - Ok(cs) => callback(ctx, PollResult::Accept(AsyncTcpConn(cs))), - Err(e) => callback(ctx, PollResult::Error(e)), - } - } - NetPollEvent::Read => { - let mut s = - std::mem::ManuallyDrop::new(AsyncTcpConn(wasi_sock::Socket(s))); - match s.read() { - Ok(data) => callback(ctx, PollResult::Read(data)), - Err(e) => callback(ctx, PollResult::Error(e)), - } - } - NetPollEvent::Connect => { - if event.fd_readwrite.flags & poll::EVENTRWFLAGS_FD_READWRITE_HANGUP - > 0 - { - let e = io::Error::from(io::ErrorKind::ConnectionAborted); - callback(ctx, PollResult::Error(e)); - } else { - let s = AsyncTcpConn(wasi_sock::Socket(s)); - callback(ctx, PollResult::Connect(s)); - } - } - }; - } - ( - PollTask::FdRead(FdReadTask { - fd, - pos, - len, - callback, - }), - poll::EVENTTYPE_FD_READ, - ) => { - if event.error > 0 { - let e = io::Error::from_raw_os_error(event.error as i32); - callback(ctx, PollResult::Error(e)); - continue; - } - let len = len as usize; // len.min(event.fd_readwrite.nbytes) as usize; - let mut buf = vec![0u8; len]; - let res = if pos >= 0 { - unsafe { - wasi_fs::fd_pread( - fd as u32, - &[wasi_fs::Iovec { - buf: buf.as_mut_ptr(), - buf_len: len, - }], - pos as u64, - ) - } - } else { - unsafe { - wasi_fs::fd_read( - fd as u32, - &[wasi_fs::Iovec { - buf: buf.as_mut_ptr(), - buf_len: len, - }], - ) - } - }; - callback( - ctx, - match res { - Ok(rlen) => { - buf.resize(rlen, 0); - PollResult::Read(buf) - } - Err(e) => { - PollResult::Error(io::Error::from_raw_os_error(e.raw() as i32)) - } - }, - ); - } - ( - PollTask::FdWrite(FdWriteTask { - fd, - pos, - buf, - callback, - }), - poll::EVENTTYPE_FD_WRITE, - ) => { - if event.error > 0 { - let e = io::Error::from_raw_os_error(event.error as i32); - callback(ctx, PollResult::Error(e)); - continue; - } - if pos != -1 { - let res = - unsafe { wasi_fs::fd_seek(fd as u32, pos, wasi_fs::WHENCE_SET) }; - if let Err(e) = res { - callback( - ctx, - PollResult::Error(io::Error::from_raw_os_error(e.raw() as i32)), - ); - continue; - } - } - let res = unsafe { - wasi_fs::fd_write( - fd as u32, - &[wasi_fs::Ciovec { - buf: buf.as_ptr(), - buf_len: buf.len(), - }], - ) - }; - callback( - ctx, - match res { - Ok(len) => PollResult::Write(len), - Err(e) => { - PollResult::Error(io::Error::from_raw_os_error(e.raw() as i32)) - } - }, - ); - } - (_, _) => {} - } - } - } - Ok(n) + pub fn peer(&self) -> io::Result { + self.0.get_ref().0.peer_addr() } } #[derive(Default)] pub struct EventLoop { - next_tick_queue: LinkedList>, - io_selector: IoSelector, + next_tick_queue: LinkedList>, + immediate_queue: LinkedList>, + pub(crate) waker: Option, + pub(crate) sub_tasks: LinkedList>, } impl EventLoop { - pub fn run_once(&mut self, ctx: &mut qjs::Context) -> io::Result { - let n = self.run_tick_task(ctx); - if n > 0 { - Ok(n) - } else { - self.io_selector.poll(ctx) - } + pub fn add_immediate_task(&mut self, callback: Box) { + self.immediate_queue.push_back(callback); } - fn run_tick_task(&mut self, ctx: &mut qjs::Context) -> usize { + pub fn run_tick_task(&mut self) -> usize { let mut i = 0; + let mut cb_vec = LinkedList::new(); while let Some(f) = self.next_tick_queue.pop_front() { - f(ctx); + cb_vec.push_back(f); + } + while let Some(f) = self.immediate_queue.pop_front() { + cb_vec.push_back(f); + } + while let Some(f) = cb_vec.pop_front() { + f(); i += 1; } i } - pub fn set_timeout( - &mut self, - callback: qjs::JsFunction, - timeout: std::time::Duration, - args: Option>, - ) -> usize { - let ddl = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .add(timeout) - .as_nanos(); - - let timeout_task = PollTask::Timeout(TimeoutTask { - timeout: ddl, - callback: Box::new(move |_ctx, _res| { - match args { - Some(argv) => callback.call(&argv), - None => callback.call(&[]), - }; - }), - }); - self.io_selector.add_task(timeout_task) - } - - pub fn clear_timeout(&mut self, timeout_id: usize) { - if let Some(t) = self.io_selector.tasks.get_mut(timeout_id) { - if let Some(PollTask::Timeout(_)) = t { - t.take(); - }; - }; - } - - pub fn set_next_tick(&mut self, callback: Box) { + pub fn set_next_tick(&mut self, callback: Box) { self.next_tick_queue.push_back(callback); } - - pub fn tcp_listen(&mut self, port: u16) -> io::Result { - let addr = format!("0.0.0.0:{}", port) - .parse() - .map_err(|_e| io::Error::from(io::ErrorKind::InvalidInput))?; - - let s = wasi_sock::Socket::new( - wasi_sock::AddressFamily::Inet4, - wasi_sock::SocketType::Stream, - )?; - s.set_nonblocking(true)?; - s.bind(&addr)?; - s.listen(1024)?; - Ok(AsyncTcpServer(s)) - } - - pub fn tcp_connect( - &mut self, - addr: &SocketAddr, - callback: Box, - timeout: Option, - ) -> io::Result<()> { - let s = wasi_sock::Socket::new( - wasi_sock::AddressFamily::Inet4, - wasi_sock::SocketType::Stream, - )?; - s.set_nonblocking(true)?; - if let Err(e) = s.connect(addr) { - // Operation in progress - if e.raw_os_error() != Some(26) { - return Err(e); - } - } - - if let Some(timeout) = timeout { - let ddl = std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .add(timeout) - .as_nanos(); - - self.io_selector - .add_task(PollTask::SocketTimeout(SocketTimeoutTask { - s: s.0, - event: NetPollEvent::Connect, - timeout: ddl, - callback, - })); - } else { - self.io_selector.add_task(PollTask::Socket(SocketTask { - s: s.0, - event: NetPollEvent::Connect, - callback, - })); - } - std::mem::forget(s); - Ok(()) - } - - pub fn fd_read( - &mut self, - fd: std::os::wasi::io::RawFd, - pos: i64, - len: u64, - callback: Box, - ) { - self.io_selector.add_task(PollTask::FdRead(FdReadTask { - fd, - pos, - len, - callback, - })); - } - - pub fn fd_write( - &mut self, - fd: std::os::wasi::io::RawFd, - pos: i64, - buf: Vec, - callback: Box, - ) { - self.io_selector.add_task(PollTask::FdWrite(FdWriteTask { - fd, - pos, - buf, - callback, - })); - } } diff --git a/src/event_loop/poll.rs b/src/event_loop/poll.rs index 2325aef..e6828f3 100644 --- a/src/event_loop/poll.rs +++ b/src/event_loop/poll.rs @@ -1,106 +1 @@ -// copy from https://github.com/bytecodealliance/wasi/blob/main/src/lib_generated.rs -pub type Fd = u32; -pub type Filesize = u64; -pub type Timestamp = u64; -pub type Errno = u16; - -pub type Clockid = u32; - -pub const CLOCKID_REALTIME: Clockid = 0; -pub const CLOCKID_MONOTONIC: Clockid = 1; -pub const CLOCKID_PROCESS_CPUTIME_ID: Clockid = 2; -pub const CLOCKID_THREAD_CPUTIME_ID: Clockid = 3; - -pub type Userdata = u64; -pub type Eventtype = u8; - -pub const EVENTTYPE_CLOCK: Eventtype = 0; -pub const EVENTTYPE_FD_READ: Eventtype = 1; -pub const EVENTTYPE_FD_WRITE: Eventtype = 2; - -pub type Eventrwflags = u16; - -/// The peer of this socket has closed or disconnected. -pub const EVENTRWFLAGS_FD_READWRITE_HANGUP: Eventrwflags = 1 << 0; - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct EventFdReadwrite { - pub nbytes: Filesize, - pub flags: Eventrwflags, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct Event { - pub userdata: Userdata, - pub error: Errno, - pub type_: Eventtype, - pub fd_readwrite: EventFdReadwrite, -} - -pub type Subclockflags = u16; - -pub const SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME: Subclockflags = 1 << 0; - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct SubscriptionClock { - pub id: Clockid, - pub timeout: Timestamp, - pub precision: Timestamp, - pub flags: Subclockflags, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug)] -pub struct SubscriptionFdReadwrite { - pub file_descriptor: Fd, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub union SubscriptionUU { - pub clock: SubscriptionClock, - pub fd_read: SubscriptionFdReadwrite, - pub fd_write: SubscriptionFdReadwrite, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct SubscriptionU { - pub tag: u8, - pub u: SubscriptionUU, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct Subscription { - pub userdata: Userdata, - pub u: SubscriptionU, -} - -mod wasi { - #[link(wasm_import_module = "wasi_snapshot_preview1")] - extern "C" { - pub fn poll_oneoff(arg0: i32, arg1: i32, arg2: i32, arg3: i32) -> i32; - } -} - -pub unsafe fn poll_oneoff( - in_: *const Subscription, - out: *mut Event, - nsubscriptions: usize, -) -> std::io::Result { - let mut rp0 = 0_usize; - let ret = wasi::poll_oneoff( - in_ as i32, - out as i32, - nsubscriptions as i32, - (&mut rp0) as *mut usize as i32, - ); - match ret { - 0 => Ok(rp0), - _ => Err(std::io::Error::from_raw_os_error(ret)), - } -} +pub use wasmedge_wasi_socket::wasi_poll::*; diff --git a/src/event_loop/wasi_sock.rs b/src/event_loop/wasi_sock.rs index 8a302d6..8b1a47c 100644 --- a/src/event_loop/wasi_sock.rs +++ b/src/event_loop/wasi_sock.rs @@ -1,654 +1,4 @@ -use std::ffi::CString; -use std::io; -use std::io::{Read, Write}; -use std::net::{ - IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs, -}; -use std::os::wasi::prelude::{AsRawFd, RawFd}; - -#[derive(Copy, Clone, Debug)] -#[repr(u8, align(1))] -pub enum AddressFamily { - Unspec, - Inet4, - Inet6, -} - -impl From<&SocketAddr> for AddressFamily { - fn from(addr: &SocketAddr) -> Self { - match addr { - SocketAddr::V4(_) => AddressFamily::Inet4, - SocketAddr::V6(_) => AddressFamily::Inet6, - } - } -} - -impl AddressFamily { - pub fn is_v4(&self) -> bool { - matches!(*self, AddressFamily::Inet4) - } - - pub fn is_v6(&self) -> bool { - matches!(*self, AddressFamily::Inet6) - } -} - -#[derive(Copy, Clone, Debug)] -#[repr(u8, align(1))] -pub enum SocketType { - Any, - Datagram, - Stream, -} - -#[derive(Copy, Clone)] -#[repr(u8, align(1))] -pub enum SocketOptLevel { - SolSocket = 0, -} - -#[derive(Copy, Clone)] -#[repr(u8, align(1))] -pub enum SocketOptName { - SoReuseaddr = 0, - SoType = 1, - SoError = 2, - SoDontroute = 3, - SoBroadcast = 4, - SoSndbuf = 5, - SoRcvbuf = 6, - SoKeepalive = 7, - SoOobinline = 8, - SoLinger = 9, - SoRcvlowat = 10, - SoRcvtimeo = 11, - SoSndtimeo = 12, - SoAcceptconn = 13, -} - -#[derive(Copy, Clone)] -#[repr(C)] -pub struct WasiAddress { - pub buf: *const u8, - pub size: usize, -} - -unsafe impl Send for WasiAddress {} - -#[derive(Copy, Clone, Debug)] -#[repr(u16, align(2))] -pub enum AiFlags { - AiPassive, - AiCanonname, - AiNumericHost, - AiNumericServ, - AiV4Mapped, - AiAll, - AiAddrConfig, -} - -#[derive(Copy, Clone, Debug)] -#[repr(u8, align(1))] -pub enum AiProtocol { - IPProtoIP, - IPProtoTCP, - IPProtoUDP, -} - -#[derive(Debug, Clone)] -#[repr(C)] -pub struct WasiSockaddr { - pub family: AddressFamily, - pub sa_data_len: u32, - pub sa_data: *mut u8, -} - -impl WasiSockaddr { - pub fn new(family: AddressFamily, sa_data: &mut [u8]) -> WasiSockaddr { - WasiSockaddr { - family, - sa_data_len: 14, - sa_data: sa_data.as_mut_ptr(), - } - } -} - -impl Default for WasiSockaddr { - fn default() -> WasiSockaddr { - WasiSockaddr { - family: AddressFamily::Inet4, - sa_data_len: 14, - sa_data: std::ptr::null_mut(), - } - } -} - -#[repr(C)] -pub struct IovecRead { - pub buf: *mut u8, - pub size: usize, -} - -#[repr(C)] -pub struct IovecWrite { - pub buf: *const u8, - pub size: usize, -} - +use std::os::wasi::prelude::RawFd; +pub use wasmedge_wasi_socket::nslookup; +pub use wasmedge_wasi_socket::socket::*; pub type RawSocket = RawFd; - -#[derive(Debug)] -pub struct Socket(pub RawSocket); - -impl Drop for Socket { - fn drop(&mut self) { - self.shutdown(Shutdown::Both); - unsafe { libc::close(self.0) }; - } -} - -impl AsRawFd for Socket { - fn as_raw_fd(&self) -> RawFd { - self.0 - } -} - -macro_rules! syscall { - ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{ - #[allow(unused_unsafe)] - let res = unsafe { libc::$fn($($arg, )*) }; - if res == -1 { - Err(std::io::Error::last_os_error()) - } else { - Ok(res) - } - }}; - } - -fn fcntl_add(fd: RawFd, get_cmd: i32, set_cmd: i32, flag: i32) -> io::Result<()> { - let previous = syscall!(fcntl(fd, get_cmd))?; - let new = previous | flag; - if new != previous { - syscall!(fcntl(fd, set_cmd, new)).map(|_| ()) - } else { - // Flag was already set. - Ok(()) - } -} - -/// Remove `flag` to the current set flags of `F_GETFD`. -fn fcntl_remove(fd: RawFd, get_cmd: i32, set_cmd: i32, flag: i32) -> io::Result<()> { - let previous = syscall!(fcntl(fd, get_cmd))?; - let new = previous & !flag; - if new != previous { - syscall!(fcntl(fd, set_cmd, new)).map(|_| ()) - } else { - // Flag was already set. - Ok(()) - } -} - -impl Socket { - pub fn new(addr_family: AddressFamily, sock_kind: SocketType) -> io::Result { - unsafe { - let mut fd = 0; - let res = sock_open(addr_family as u8, sock_kind as u8, &mut fd); - if res == 0 { - Ok(Socket(fd as RawSocket)) - } else { - Err(io::Error::from_raw_os_error(res as i32)) - } - } - } - - pub fn send(&self, buf: &[u8]) -> io::Result { - unsafe { - let mut send_len: u32 = 0; - let vec = IovecWrite { - buf: buf.as_ptr(), - size: buf.len(), - }; - let res = sock_send(self.as_raw_fd() as u32, &vec, 1, 0, &mut send_len); - if res == 0 { - Ok(send_len as usize) - } else { - Err(io::Error::from_raw_os_error(res as i32)) - } - } - } - - pub fn recv(&self, buf: &mut [u8]) -> io::Result { - let flags = 0; - let mut recv_len: usize = 0; - let mut oflags: usize = 0; - let mut vec = IovecRead { - buf: buf.as_mut_ptr(), - size: buf.len(), - }; - - unsafe { - let res = sock_recv( - self.as_raw_fd() as u32, - &mut vec, - 1, - flags, - &mut recv_len, - &mut oflags, - ); - if res == 0 { - Ok(recv_len) - } else { - Err(io::Error::from_raw_os_error(res as i32)) - } - } - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let fd = self.as_raw_fd(); - if nonblocking { - fcntl_add(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK) - } else { - fcntl_remove(fd, libc::F_GETFL, libc::F_SETFL, libc::O_NONBLOCK) - } - } - - pub fn connect(&self, addrs: &SocketAddr) -> io::Result<()> { - let fd = self.as_raw_fd(); - let mut vaddr: [u8; 4] = [0; 4]; - let mut port: u16 = 0; - if let SocketAddr::V4(addrs) = addrs { - vaddr = addrs.ip().octets(); - port = addrs.port(); - } - let mut addr = WasiAddress { - buf: vaddr.as_ptr(), - size: 4, - }; - - unsafe { - let res = sock_connect(fd as u32, &mut addr, port as u32); - if res != 0 { - Err(io::Error::from_raw_os_error(res as i32)) - } else { - Ok(()) - } - } - } - - pub fn bind(&self, addrs: &SocketAddr) -> io::Result<()> { - unsafe { - let fd = self.as_raw_fd(); - - let opt_reuse = 1; - let opt_reuse_ptr: *const i32 = &opt_reuse; - sock_setsockopt( - fd as u32, - SocketOptLevel::SolSocket as i32, - SocketOptName::SoReuseaddr as i32, - opt_reuse_ptr, - std::mem::size_of::() as u32, - ); - - let mut vaddr: [u8; 16] = [0; 16]; - let port; - let size; - match addrs { - SocketAddr::V4(addr) => { - let ip = addr.ip().octets(); - (&mut vaddr[0..4]).clone_from_slice(&ip); - port = addr.port(); - size = 4; - } - SocketAddr::V6(addr) => { - let ip = addr.ip().octets(); - vaddr.clone_from_slice(&ip); - port = addr.port(); - size = 16; - } - } - let mut addr = WasiAddress { - buf: vaddr.as_ptr(), - size, - }; - let res = sock_bind(fd as u32, &mut addr, port as u32); - if res != 0 { - Err(io::Error::from_raw_os_error(res as i32)) - } else { - Ok(()) - } - } - } - - pub fn listen(&self, backlog: i32) -> io::Result<()> { - unsafe { - let fd = self.as_raw_fd(); - let res = sock_listen(fd as u32, backlog as u32); - if res != 0 { - Err(io::Error::from_raw_os_error(res as i32)) - } else { - Ok(()) - } - } - } - - pub fn accept(&self, nonblocking: bool) -> io::Result { - unsafe { - let mut fd: u32 = 0; - let res = sock_accept(self.as_raw_fd() as u32, &mut fd); - if res != 0 { - Err(io::Error::from_raw_os_error(res as i32)) - } else { - let s = Socket(fd as i32); - s.set_nonblocking(nonblocking)?; - Ok(s) - } - } - } - - pub fn get_local(&self) -> io::Result { - unsafe { - let fd = self.0; - let addr_buf = [0u8; 16]; - let mut addr = WasiAddress { - buf: addr_buf.as_ptr(), - size: 16, - }; - let mut addr_type = 0; - let mut port = 0; - let res = sock_getlocaladdr(fd as u32, &mut addr, &mut addr_type, &mut port); - if res != 0 { - Err(io::Error::from_raw_os_error(res as i32)) - } else { - if addr_type == 4 { - let ip_addr = Ipv4Addr::new(addr_buf[0], addr_buf[1], addr_buf[2], addr_buf[3]); - Ok(SocketAddr::V4(SocketAddrV4::new(ip_addr, port as u16))) - } else if addr_type == 6 { - let ip_addr = Ipv6Addr::from(addr_buf); - Ok(SocketAddr::V6(SocketAddrV6::new( - ip_addr, - port as u16, - 0, - 0, - ))) - } else { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - } - } - } - - pub fn get_peer(&self) -> io::Result { - unsafe { - let fd = self.0; - let addr_buf = [0u8; 16]; - let mut addr = WasiAddress { - buf: addr_buf.as_ptr(), - size: 16, - }; - let mut addr_type = 0; - let mut port = 0; - let res = sock_getpeeraddr(fd as u32, &mut addr, &mut addr_type, &mut port); - if res != 0 { - Err(io::Error::from_raw_os_error(res as i32)) - } else { - if addr_type == 4 { - let ip_addr = Ipv4Addr::new(addr_buf[0], addr_buf[1], addr_buf[2], addr_buf[3]); - Ok(SocketAddr::V4(SocketAddrV4::new(ip_addr, port as u16))) - } else if addr_type == 6 { - let ip_addr = Ipv6Addr::from(addr_buf); - Ok(SocketAddr::V6(SocketAddrV6::new( - ip_addr, - port as u16, - 0, - 0, - ))) - } else { - Err(io::Error::from(io::ErrorKind::Unsupported)) - } - } - } - } - - pub fn take_error(&self) -> io::Result<()> { - unsafe { - let fd = self.0; - let mut error = 0; - let mut len = std::mem::size_of::() as u32; - let res = sock_getsockopt( - fd as u32, - SocketOptLevel::SolSocket as i32, - SocketOptName::SoError as i32, - &mut error, - &mut len, - ); - if res == 0 && error == 0 { - Ok(()) - } else if res == 0 && error != 0 { - Err(io::Error::from_raw_os_error(error)) - } else { - Err(io::Error::from_raw_os_error(res as i32)) - } - } - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - unsafe { - let flags = match how { - Shutdown::Read => 1, - Shutdown::Write => 2, - Shutdown::Both => 3, - }; - let res = sock_shutdown(self.as_raw_fd() as u32, flags); - if res == 0 { - Ok(()) - } else { - Err(io::Error::from_raw_os_error(res as i32)) - } - } - } -} - -impl<'a> Read for &'a Socket { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.recv(buf) - } -} - -impl<'a> Write for &'a Socket { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.send(buf) - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[derive(Debug, Clone)] -#[repr(C, packed(4))] -pub struct WasiAddrinfo { - pub ai_flags: AiFlags, - pub ai_family: AddressFamily, - pub ai_socktype: SocketType, - pub ai_protocol: AiProtocol, - pub ai_addrlen: u32, - pub ai_addr: *mut WasiSockaddr, - pub ai_canonname: *mut u8, - pub ai_canonnamelen: u32, - pub ai_next: *mut WasiAddrinfo, -} - -impl WasiAddrinfo { - pub fn default() -> WasiAddrinfo { - WasiAddrinfo { - ai_flags: AiFlags::AiPassive, - ai_family: AddressFamily::Inet4, - ai_socktype: SocketType::Stream, - ai_protocol: AiProtocol::IPProtoTCP, - ai_addr: std::ptr::null_mut(), - ai_addrlen: 0, - ai_canonname: std::ptr::null_mut(), - ai_canonnamelen: 0, - ai_next: std::ptr::null_mut(), - } - } - - /// Get Address Information - /// - /// As calling FFI, use buffer as parameter in order to avoid memory leak. - pub fn get_addrinfo( - node: &str, - service: &str, - hints: &WasiAddrinfo, - max_reslen: usize, - sockaddr: &mut Vec, - sockbuff: &mut Vec<[u8; 26]>, - ai_canonname: &mut Vec, - ) -> io::Result> { - let mut node = node.to_string(); - let mut service = service.to_string(); - - if !node.ends_with('\0') { - node.push('\0'); - } - - if !service.ends_with('\0') { - service.push('\0'); - } - - let mut res_len: u32 = 0; - sockbuff.resize(max_reslen, [0u8; 26]); - ai_canonname.resize(max_reslen, String::with_capacity(30)); - sockaddr.resize(max_reslen, WasiSockaddr::default()); - let mut wasiaddrinfo_array: Vec = vec![WasiAddrinfo::default(); max_reslen]; - - for i in 0..max_reslen { - sockaddr[i].sa_data = sockbuff[i].as_mut_ptr(); - wasiaddrinfo_array[i].ai_addr = &mut sockaddr[i]; - wasiaddrinfo_array[i].ai_canonname = ai_canonname[i].as_mut_ptr(); - if i > 0 { - wasiaddrinfo_array[i - 1].ai_next = &mut wasiaddrinfo_array[i]; - } - } - let mut res = wasiaddrinfo_array.as_mut_ptr() as u32; - - unsafe { - let return_code = sock_getaddrinfo( - node.as_ptr(), - node.len() as u32, - service.as_ptr(), - service.len() as u32, - hints as *const WasiAddrinfo, - &mut res, - max_reslen as u32, - &mut res_len, - ); - match return_code { - 0 => Ok(wasiaddrinfo_array[..res_len as usize].to_vec()), - _ => Err(std::io::Error::last_os_error()), - } - } - } -} - -pub fn nslookup(node: &str, service: &str) -> std::io::Result> { - let hints: WasiAddrinfo = WasiAddrinfo::default(); - let mut sockaddrs = Vec::new(); - let mut sockbuffs = Vec::new(); - let mut ai_canonnames = Vec::new(); - let addrinfos = WasiAddrinfo::get_addrinfo( - &node, - &service, - &hints, - 10, - &mut sockaddrs, - &mut sockbuffs, - &mut ai_canonnames, - )?; - - let mut r_addrs = vec![]; - for i in 0..addrinfos.len() { - let addrinfo = &addrinfos[i]; - let sockaddr = &sockaddrs[i]; - let sockbuff = &sockbuffs[i]; - - if addrinfo.ai_addrlen == 0 { - continue; - } - - let addr = match sockaddr.family { - AddressFamily::Inet4 => { - let port_buf = [sockbuff[0], sockbuff[1]]; - let port = u16::from_be_bytes(port_buf); - let ip = Ipv4Addr::new(sockbuff[2], sockbuff[3], sockbuff[4], sockbuff[5]); - SocketAddr::V4(SocketAddrV4::new(ip, port)) - } - AddressFamily::Inet6 => { - // unimplemented!("not support IPv6") - continue; - } - AddressFamily::Unspec => { - // unimplemented!("not support Unspec") - continue; - } - }; - - r_addrs.push(addr); - } - Ok(r_addrs) -} - -#[link(wasm_import_module = "wasi_snapshot_preview1")] -extern "C" { - pub fn sock_open(addr_family: u8, sock_type: u8, fd: *mut u32) -> u32; - pub fn sock_bind(fd: u32, addr: *mut WasiAddress, port: u32) -> u32; - pub fn sock_listen(fd: u32, backlog: u32) -> u32; - pub fn sock_accept(fd: u32, new_fd: *mut u32) -> u32; - pub fn sock_connect(fd: u32, addr: *mut WasiAddress, port: u32) -> u32; - pub fn sock_recv( - fd: u32, - buf: *const IovecRead, - buf_len: usize, - flags: u16, - recv_len: *mut usize, - oflags: *mut usize, - ) -> u32; - pub fn sock_send( - fd: u32, - buf: *const IovecWrite, - buf_len: u32, - flags: u16, - send_len: *mut u32, - ) -> u32; - pub fn sock_shutdown(fd: u32, flags: u8) -> u32; - pub fn sock_getsockopt( - fd: u32, - level: i32, - name: i32, - flag: *mut i32, - flag_size: *mut u32, - ) -> u32; - pub fn sock_setsockopt(fd: u32, level: i32, name: i32, flag: *const i32, flag_size: u32) - -> u32; - pub fn sock_getlocaladdr( - fd: u32, - addr: *mut WasiAddress, - addr_type: *mut u32, - port: *mut u32, - ) -> u32; - pub fn sock_getpeeraddr( - fd: u32, - addr: *mut WasiAddress, - addr_type: *mut u32, - port: *mut u32, - ) -> u32; - pub fn sock_getaddrinfo( - node: *const u8, - node_len: u32, - server: *const u8, - server_len: u32, - hint: *const WasiAddrinfo, - res: *mut u32, - max_len: u32, - res_len: *mut u32, - ) -> u32; -} diff --git a/src/internal_module/core.rs b/src/internal_module/core.rs index c8c82a9..5aad1f0 100644 --- a/src/internal_module/core.rs +++ b/src/internal_module/core.rs @@ -1,32 +1,95 @@ use crate::quickjs_sys::*; use crate::EventLoop; use std::string::FromUtf8Error; +use std::sync::Arc; + +#[derive(Debug, Clone)] +struct TimeoutId(Arc); +impl TimeoutId { + pub fn new() -> Self { + TimeoutId(Arc::new(tokio::sync::Notify::new())) + } +} + +impl JsClassDef for TimeoutId { + type RefType = TimeoutId; + + const CLASS_NAME: &'static str = "TimeoutId"; + + const CONSTRUCTOR_ARGC: u8 = 0; + + const FIELDS: &'static [JsClassField] = &[]; + + const METHODS: &'static [JsClassMethod] = &[]; + + unsafe fn mut_class_id_ptr() -> &'static mut u32 { + static mut CLASS_ID: u32 = 0; + &mut CLASS_ID + } + + fn constructor_fn(_ctx: &mut Context, _argv: &[JsValue]) -> Result { + Err(JsValue::UnDefined) + } +} fn set_timeout(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { let callback = argv.get(0); let timeout = argv.get(1); let rest_args = argv.get(2..).map(|args| args.to_vec()); - if let (Some(JsValue::Function(callback)), Some(JsValue::Int(timeout)), Some(event_loop)) = - (callback, timeout, ctx.event_loop()) - { - let n = event_loop.set_timeout( - callback.clone(), - std::time::Duration::from_millis((*timeout) as u64), - rest_args, - ); - JsValue::Int(n as i32) + if let (Some(JsValue::Function(callback)), Some(JsValue::Int(timeout))) = (callback, timeout) { + let timeout = *timeout as u64; + let callback = callback.clone(); + + if timeout == 0 { + ctx.event_loop().map(|event_loop| { + event_loop.add_immediate_task(Box::new(move || { + if let Some(rest_args) = rest_args { + callback.call(&rest_args); + } else { + callback.call(&[]); + } + })) + }); + JsValue::UnDefined + } else { + let timeout = std::time::Duration::from_millis(timeout); + + let id = TimeoutId::new(); + let id_ = id.clone(); + + ctx.future_to_promise(async move { + log::trace!("async wait timeout {timeout:?}"); + match tokio::time::timeout(timeout, id_.0.notified()).await { + Ok(_) => { + log::trace!("timer cancel"); + Err(JsValue::UnDefined) + } + Err(_) => { + log::trace!("timer timeout"); + if let Some(rest_args) = rest_args { + callback.call(&rest_args); + } else { + callback.call(&[]); + }; + Ok(JsValue::UnDefined) + } + } + }); + TimeoutId::wrap_obj(ctx, id) + } } else { JsValue::UnDefined } } -fn set_immediate(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { +fn set_immediate(ctx: &mut Context, this_val: JsValue, argv: &[JsValue]) -> JsValue { let callback = argv.get(0); - let args = argv.get(1..).map(|v| v.to_vec()); - if let (Some(JsValue::Function(callback)), Some(event_loop)) = (callback, ctx.event_loop()) { + let rest_args = argv.get(1..).map(|v| v.to_vec()); + if let Some(JsValue::Function(callback)) = callback { let callback = callback.clone(); - let n = event_loop.set_timeout(callback, std::time::Duration::from_secs(0), args); - JsValue::Int(n as i32) + let mut argv = vec![JsValue::Function(callback), JsValue::Int(0)]; + argv.extend(rest_args.unwrap_or_default()); + set_timeout(ctx, this_val, &argv) } else { JsValue::UnDefined } @@ -37,7 +100,7 @@ fn next_tick(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue let args = argv.get(1..).map(|v| v.to_vec()); if let (Some(JsValue::Function(callback)), Some(event_loop)) = (callback, ctx.event_loop()) { let callback = callback.clone(); - event_loop.set_next_tick(Box::new(move |_ctx| { + event_loop.set_next_tick(Box::new(move || { match args { Some(args) => callback.call(&args), None => callback.call(&[]), @@ -47,6 +110,27 @@ fn next_tick(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue JsValue::UnDefined } +fn sleep(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { + let callback = argv.get(0).cloned(); + let timeout = argv.get(1); + let rest_args = argv.get(2..).map(|args| args.to_vec()); + if let (Some(JsValue::Function(callback)), Some(JsValue::Int(timeout))) = (callback, timeout) { + let timeout = *timeout; + ctx.future_to_promise(async move { + tokio::time::sleep(std::time::Duration::from_millis(timeout as u64)).await; + if let Some(rest_args) = rest_args { + callback.call(&rest_args); + } else { + callback.call(&[]); + }; + + Ok(JsValue::UnDefined) + }) + } else { + JsValue::UnDefined + } +} + fn os_exit(_ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { let code = if let Some(JsValue::Int(c)) = argv.get(0) { *c @@ -57,24 +141,26 @@ fn os_exit(_ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue std::process::exit(code) } -struct ClearTimeout; -impl JsFn for ClearTimeout { - fn call(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { - let timeout_id = argv.get(0); - if let (Some(JsValue::Int(timeout_id)), Some(event_loop)) = (timeout_id, ctx.event_loop()) { - event_loop.clear_timeout((*timeout_id) as usize); +fn clear_timeout(_ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { + let timeout_id = argv.get(0); + if let Some(timeout_id) = timeout_id { + let id = TimeoutId::opaque(&timeout_id); + if let Some(id) = id { + id.0.notify_one() } - JsValue::UnDefined } + JsValue::UnDefined } pub fn init_ext_function(_ctx: &mut Context) {} pub fn init_global_function(ctx: &mut Context) { + register_class::(ctx); + let mut global = ctx.get_global(); global.set( "clearTimeout", - ctx.new_function::("clearTimeout").into(), + ctx.wrap_function("clearTimeout", clear_timeout).into(), ); global.set( "setTimeout", @@ -84,6 +170,7 @@ pub fn init_global_function(ctx: &mut Context) { "setImmediate", ctx.wrap_function("setImmediate", set_immediate).into(), ); + global.set("sleep", ctx.wrap_function("sleep", sleep).into()); global.set("nextTick", ctx.wrap_function("nextTick", next_tick).into()); global.set("exit", ctx.wrap_function("exit", os_exit).into()); global.set("env", env_object(ctx).into()); diff --git a/src/internal_module/fs.rs b/src/internal_module/fs.rs index 83f2a6c..ee57a07 100644 --- a/src/internal_module/fs.rs +++ b/src/internal_module/fs.rs @@ -1,5 +1,4 @@ use crate::event_loop::wasi_fs; -use crate::event_loop::PollResult; use crate::quickjs_sys::*; use std::convert::TryInto; use std::fs; @@ -599,28 +598,54 @@ fn fread(ctx: &mut Context, _this_val: JsValue, arg: &[JsValue]) -> JsValue { if let Some(position) = get_js_number(arg.get(1)) { if let Some(JsValue::Int(length)) = arg.get(2) { let (promise, ok, error) = ctx.new_promise(); + let nctx = ctx.clone(); + let len = *length as usize; // len.min(event.fd_readwrite.nbytes) as usize; + let fd = *fd; + if let Some(event_loop) = ctx.event_loop() { - event_loop.fd_read( - *fd, - position, - *length as u64, - Box::new(move |ctx, res| match res { - PollResult::Read(data) => { - let buf = ctx.new_array_buffer(&data); + event_loop.add_immediate_task(Box::new(move || { + let mut ctx = nctx; + let pos = position; + let mut buf = vec![0u8; len]; + let res = if pos >= 0 { + unsafe { + wasi_fs::fd_pread( + fd as u32, + &[wasi_fs::Iovec { + buf: buf.as_mut_ptr(), + buf_len: len, + }], + pos as u64, + ) + } + } else { + unsafe { + wasi_fs::fd_read( + fd as u32, + &[wasi_fs::Iovec { + buf: buf.as_mut_ptr(), + buf_len: len, + }], + ) + } + }; + match res { + Ok(rlen) => { + let buf = ctx.new_array_buffer(&buf[0..rlen]); if let JsValue::Function(resolve) = ok { resolve.call(&[JsValue::ArrayBuffer(buf)]); } } - PollResult::Error(e) => { + Err(e) => { if let JsValue::Function(reject) = error { - reject.call(&[err_to_js_object(ctx, e)]); + reject.call(&[errno_to_js_object(&mut ctx, e)]); } } - _ => {} - }), - ); - return promise; + }; + })) } + + return promise; } } } @@ -767,35 +792,34 @@ fn readlink_sync(ctx: &mut Context, _this_val: JsValue, arg: &[JsValue]) -> JsVa } fn fwrite(ctx: &mut Context, _this_val: JsValue, arg: &[JsValue]) -> JsValue { - if let Some(JsValue::Int(fd)) = arg.get(0) { - if let Some(position) = get_js_number(arg.get(1)) { - if let Some(JsValue::ArrayBuffer(buf)) = arg.get(2) { - let (promise, ok, error) = ctx.new_promise(); - if let Some(event_loop) = ctx.event_loop() { - event_loop.fd_write( - *fd, - position, - buf.to_vec(), - Box::new(move |ctx, res| match res { - PollResult::Write(len) => { - if let JsValue::Function(resolve) = ok { - resolve.call(&[JsValue::Int(len as i32)]); - } - } - PollResult::Error(e) => { - if let JsValue::Function(reject) = error { - reject.call(&[err_to_js_object(ctx, e)]); - } - } - _ => {} - }), - ); - return promise; + let (promise, ok, error) = ctx.new_promise(); + let nctx = ctx.clone(); + let arg = arg.to_vec(); + if let Some(event_loop) = ctx.event_loop() { + event_loop.add_immediate_task(Box::new(move || { + let mut ctx = nctx; + let r = fwrite_sync(&mut ctx, _this_val, &arg); + match r { + JsValue::UnDefined => { + if let JsValue::Function(resolve) = ok { + resolve.call(&[JsValue::UnDefined]); + }; } - } - } + JsValue::Int(len) => { + if let JsValue::Function(resolve) = ok { + resolve.call(&[JsValue::Int(len)]); + }; + } + other => { + if let JsValue::Function(reject) = error { + reject.call(&[other]); + }; + } + }; + })) } - return JsValue::UnDefined; + + promise } fn fwrite_sync(ctx: &mut Context, _this_val: JsValue, arg: &[JsValue]) -> JsValue { @@ -850,7 +874,10 @@ fn freaddir_sync(ctx: &mut Context, _this_val: JsValue, arg: &[JsValue]) -> JsVa let mut dir_next = 0; while (idx + s) < len.min(4096) { let dir = unsafe { - *(&buf[idx..(idx + s)] as *const [u8] as *const wasi_fs::Dirent) + (&buf[idx..(idx + s)] as *const [u8] as *const wasi_fs::Dirent) + .as_ref() + .unwrap() + .clone() }; idx += s; if (idx + dir.d_namlen as usize) > len.min(4096) { diff --git a/src/internal_module/wasi_net_module.rs b/src/internal_module/wasi_net_module.rs index 92392b2..3991f33 100644 --- a/src/internal_module/wasi_net_module.rs +++ b/src/internal_module/wasi_net_module.rs @@ -1,72 +1,63 @@ -use crate::event_loop::{AsyncTcpConn, AsyncTcpServer, PollResult}; +use std::io::Write; + +use crate::event_loop::{AsyncTcpConn, AsyncTcpServer, AsyncTlsConn}; use crate::*; -impl AsyncTcpConn { - pub fn connect(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { - let addr = argv.get(0); - let timeout = argv.get(1); - let (p, ok, error) = ctx.new_promise(); - let event_loop = ctx.event_loop(); - if let (Some(JsValue::String(addr)), Some(event_loop)) = (addr, event_loop) { +#[cfg(feature = "tls")] +impl AsyncTlsConn { + pub fn js_connect(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { + use wasmedge_wasi_socket::ToSocketAddrs; + let host = argv.get(0); + let port = argv.get(1); + let timeout = argv.get(2); + + let nctx = ctx.clone(); + + if let (Some(JsValue::String(host)), Some(JsValue::Int(port))) = (host, port) { let timeout = if let Some(JsValue::Int(timeout)) = timeout { Some(std::time::Duration::from_millis((*timeout) as u64)) } else { None }; - let addr = addr.to_string().parse(); - match addr { - Ok(addr) => { - if let Err(e) = event_loop.tcp_connect( - &addr, - Box::new(move |ctx, event| match event { - PollResult::Connect(cs) => { - if let JsValue::Function(ok) = ok { - let cs = AsyncTcpConn::wrap_obj(ctx, cs); - ok.call(&[cs]); - } - } - PollResult::Error(e) => { - let err_msg = e.to_string(); - let e = ctx.new_error(err_msg.as_str()); - if let JsValue::Function(error) = error { - error.call(&[e]); - } - } - PollResult::Timeout => { - let e = std::io::Error::from(std::io::ErrorKind::TimedOut); - let e = ctx.new_error(e.to_string().as_str()); - if let JsValue::Function(error) = error { - error.call(&[e]); - } - } - _ => { - let e = std::io::Error::from(std::io::ErrorKind::Unsupported); - let e = ctx.new_error(e.to_string().as_str()); - if let JsValue::Function(error) = error { - error.call(&[e]); - } - } - }), - timeout, - ) { - let e = ctx.throw_internal_type_error(e.to_string().as_str()); - return e.into(); - }; - } - Err(e) => { - let e = ctx.throw_internal_type_error(e.to_string().as_str()); - return e.into(); - } - } - p + let host = host.to_string(); + let port = *port as u16; + + let pp = if let Some(duration) = timeout { + ctx.future_to_promise(async move { + let mut ctx = nctx; + match tokio::time::timeout( + duration, + AsyncTlsConn::async_connect((host.as_str(), port), &host), + ) + .await + { + Ok(Ok(conn)) => Ok(Self::wrap_obj(&mut ctx, conn)), + Ok(Err(e)) => Err(ctx.new_error(e.to_string().as_str())), + Err(e) => { + let err = + std::io::Error::new(std::io::ErrorKind::TimedOut, e.to_string()); + Err(ctx.new_error(err.to_string().as_str()).into()) + } + } + }) + } else { + ctx.future_to_promise(async move { + let mut ctx = nctx; + match AsyncTlsConn::async_connect((host.as_str(), port), &host).await { + Ok(conn) => Ok(Self::wrap_obj(&mut ctx, conn)), + Err(e) => Err(ctx.new_error(e.to_string().as_str())), + } + }) + }; + pp } else { JsValue::UnDefined } } pub fn on( - _this_val: &mut AsyncTcpConn, + _this_val: &mut Self, _this_obj: &mut JsObject, _ctx: &mut Context, _argv: &[JsValue], @@ -75,82 +66,297 @@ impl AsyncTcpConn { } pub fn js_read( - this_val: &mut AsyncTcpConn, - _this_obj: &mut JsObject, + _this_val: &mut Self, + this_obj: &mut JsObject, ctx: &mut Context, argv: &[JsValue], ) -> JsValue { - let (p, ok, error) = ctx.new_promise(); - if let Some(event_poll) = ctx.event_loop() { - let timeout = if let Some(JsValue::Int(timeout)) = argv.get(0) { + let mut js_obj = this_obj.clone().into(); + let n_ctx = ctx.clone(); + if let Some(JsValue::Int(timeout)) = argv.get(0) { + let duration = std::time::Duration::from_millis((*timeout) as u64); + ctx.future_to_promise(async move { + let mut ctx = n_ctx; + let this_val = Self::opaque_mut(&mut js_obj).unwrap(); + match tokio::time::timeout(duration, this_val.async_read_all()).await { + Ok(Ok(data)) => { + if data.len() > 0 { + let buff = ctx.new_array_buffer(data.as_slice()); + Ok(JsValue::ArrayBuffer(buff)) + } else { + Ok(JsValue::UnDefined) + } + } + Ok(Err(err)) => Err(ctx.new_error(err.to_string().as_str()).into()), + Err(e) => { + let err = std::io::Error::new(std::io::ErrorKind::TimedOut, e.to_string()); + Err(ctx.new_error(err.to_string().as_str()).into()) + } + } + }) + } else { + ctx.future_to_promise(async move { + let mut ctx = n_ctx; + let this_val = Self::opaque_mut(&mut js_obj).unwrap(); + match this_val.async_read_all().await { + Ok(data) => { + if data.len() > 0 { + let buff = ctx.new_array_buffer(data.as_slice()); + log::trace!("async_read_all return ArrayBuffer"); + Ok(JsValue::ArrayBuffer(buff)) + } else { + Ok(JsValue::UnDefined) + } + } + Err(err) => Err(ctx.new_error(err.to_string().as_str()).into()), + } + }) + } + } + + pub fn js_write( + _this_val: &mut AsyncTlsConn, + this_obj: &mut JsObject, + ctx: &mut Context, + argv: &[JsValue], + ) -> JsValue { + let mut js_obj = JsValue::Object(this_obj.clone()); + match argv.get(0) { + Some(JsValue::String(s)) => { + let data = s.to_string(); + ctx.future_to_promise(async move { + let this_val = Self::opaque_mut(&mut js_obj).unwrap(); + this_val.async_write_all(data.as_bytes()).await; + Ok(JsValue::UnDefined) + }); + } + Some(JsValue::ArrayBuffer(buff)) => { + let data = buff.to_vec(); + ctx.future_to_promise(async move { + let this_val = Self::opaque_mut(&mut js_obj).unwrap(); + this_val.async_write_all(&data).await; + Ok(JsValue::UnDefined) + }); + } + Some(JsValue::Object(o)) => { + let data = o.to_string(); + ctx.future_to_promise(async move { + let this_val = Self::opaque_mut(&mut js_obj).unwrap(); + this_val.async_write_all(data.as_bytes()).await; + Ok(JsValue::UnDefined) + }); + } + Some(JsValue::Symbol(s)) => { + let data = format!("{:?}", s); + ctx.future_to_promise(async move { + let this_val = Self::opaque_mut(&mut js_obj).unwrap(); + this_val.async_write_all(data.as_bytes()).await; + Ok(JsValue::UnDefined) + }); + } + _ => {} + }; + JsValue::Bool(true) + } + + pub fn js_local( + this_val: &mut Self, + _this_obj: &mut JsObject, + ctx: &mut Context, + _argv: &[JsValue], + ) -> JsValue { + match this_val.local() { + Ok(addr) => ctx.new_string(addr.to_string().as_str()).into(), + Err(e) => ctx.throw_internal_type_error(e.to_string().as_str()).into(), + } + } + + pub fn js_peer( + this_val: &mut Self, + _this_obj: &mut JsObject, + ctx: &mut Context, + _argv: &[JsValue], + ) -> JsValue { + match this_val.peer() { + Ok(addr) => ctx.new_string(addr.to_string().as_str()).into(), + Err(e) => ctx.throw_internal_type_error(e.to_string().as_str()).into(), + } + } +} + +#[cfg(feature = "tls")] +impl JsClassDef for AsyncTlsConn { + type RefType = AsyncTlsConn; + const CLASS_NAME: &'static str = "WasiTlsConn"; + const CONSTRUCTOR_ARGC: u8 = 0; + + const FIELDS: &'static [JsClassField] = &[]; + + const METHODS: &'static [JsClassMethod] = &[ + ("on", 1, Self::on), + ("read", 0, Self::js_read), + ("write", 1, Self::js_write), + ("end", 1, Self::js_write), + ("local", 0, Self::js_local), + ("peer", 0, Self::js_peer), + ]; + + unsafe fn mut_class_id_ptr() -> &'static mut u32 { + static mut CLASS_ID: u32 = 0; + &mut CLASS_ID + } + + fn constructor_fn(_ctx: &mut Context, _argv: &[JsValue]) -> Result { + Err(JsValue::Null) + } +} + +impl AsyncTcpConn { + pub fn js_connect(ctx: &mut Context, _this_val: JsValue, argv: &[JsValue]) -> JsValue { + use wasmedge_wasi_socket::ToSocketAddrs; + let host = argv.get(0); + let port = argv.get(1); + let timeout = argv.get(2); + + let nctx = ctx.clone(); + + if let (Some(JsValue::String(host)), Some(JsValue::Int(port))) = (host, port) { + let timeout = if let Some(JsValue::Int(timeout)) = timeout { Some(std::time::Duration::from_millis((*timeout) as u64)) } else { None }; - this_val.async_read( - event_poll, - Box::new(move |ctx, event| match event { - PollResult::Read(data) => { - if let JsValue::Function(ok) = ok { - let ret = if data.len() > 0 { - let buff = ctx.new_array_buffer(data.as_slice()); - JsValue::ArrayBuffer(buff) - } else { - JsValue::UnDefined - }; - ok.call(&[ret]); + + let host = host.to_string(); + let port = *port as u16; + + let pp = if let Some(duration) = timeout { + ctx.future_to_promise(async move { + let mut ctx = nctx; + match tokio::time::timeout(duration, AsyncTcpConn::async_connect((host, port))) + .await + { + Ok(Ok(conn)) => Ok(Self::wrap_obj(&mut ctx, conn)), + Ok(Err(e)) => Err(ctx.new_error(e.to_string().as_str())), + Err(e) => { + let err = + std::io::Error::new(std::io::ErrorKind::TimedOut, e.to_string()); + Err(ctx.new_error(err.to_string().as_str()).into()) } } - PollResult::Error(e) => { - let err_msg = e.to_string(); - let e = ctx.new_error(err_msg.as_str()); - if let JsValue::Function(error) = error { - error.call(&[e]); - } + }) + } else { + ctx.future_to_promise(async move { + let mut ctx = nctx; + match AsyncTcpConn::async_connect((host, port)).await { + Ok(conn) => Ok(Self::wrap_obj(&mut ctx, conn)), + Err(e) => Err(ctx.new_error(e.to_string().as_str())), } - PollResult::Timeout => { - let e = std::io::Error::from(std::io::ErrorKind::TimedOut); - let e = ctx.new_error(e.to_string().as_str()); - if let JsValue::Function(error) = error { - error.call(&[e]); + }) + }; + pp + } else { + JsValue::UnDefined + } + } + + pub fn on( + _this_val: &mut AsyncTcpConn, + _this_obj: &mut JsObject, + _ctx: &mut Context, + _argv: &[JsValue], + ) -> JsValue { + JsValue::UnDefined + } + + pub fn js_read( + _this_val: &mut AsyncTcpConn, + this_obj: &mut JsObject, + ctx: &mut Context, + argv: &[JsValue], + ) -> JsValue { + let mut js_obj = this_obj.clone().into(); + let n_ctx = ctx.clone(); + if let Some(JsValue::Int(timeout)) = argv.get(0) { + let duration = std::time::Duration::from_millis((*timeout) as u64); + ctx.future_to_promise(async move { + let mut ctx = n_ctx; + let this_val = Self::opaque_mut(&mut js_obj).unwrap(); + match tokio::time::timeout(duration, this_val.async_read_all()).await { + Ok(Ok(data)) => { + if data.len() > 0 { + let buff = ctx.new_array_buffer(data.as_slice()); + Ok(JsValue::ArrayBuffer(buff)) + } else { + Ok(JsValue::UnDefined) } } - _ => { - let e = std::io::Error::from(std::io::ErrorKind::Unsupported); - let e = ctx.new_error(e.to_string().as_str()); - if let JsValue::Function(error) = error { - error.call(&[e]); - } + Ok(Err(err)) => Err(ctx.new_error(err.to_string().as_str()).into()), + Err(e) => { + let err = std::io::Error::new(std::io::ErrorKind::TimedOut, e.to_string()); + Err(ctx.new_error(err.to_string().as_str()).into()) } - }), - timeout, - ); - p + } + }) } else { - JsValue::UnDefined + ctx.future_to_promise(async move { + let mut ctx = n_ctx; + let this_val = Self::opaque_mut(&mut js_obj).unwrap(); + match this_val.async_read_all().await { + Ok(data) => { + if data.len() > 0 { + let buff = ctx.new_array_buffer(data.as_slice()); + log::trace!("async_read_all return ArrayBuffer"); + Ok(JsValue::ArrayBuffer(buff)) + } else { + Ok(JsValue::UnDefined) + } + } + Err(err) => Err(ctx.new_error(err.to_string().as_str()).into()), + } + }) } } pub fn js_write( - this_val: &mut AsyncTcpConn, - _this_obj: &mut JsObject, - _ctx: &mut Context, + _this_val: &mut AsyncTcpConn, + this_obj: &mut JsObject, + ctx: &mut Context, argv: &[JsValue], ) -> JsValue { - let data = argv.get(0); - match data { + let mut js_obj = JsValue::Object(this_obj.clone()); + match argv.get(0) { Some(JsValue::String(s)) => { - this_val.write(s.to_string().as_bytes()); + let data = s.to_string(); + ctx.future_to_promise(async move { + let this_val = AsyncTcpConn::opaque_mut(&mut js_obj).unwrap(); + this_val.async_write_all(data.as_bytes()).await; + Ok(JsValue::UnDefined) + }); } Some(JsValue::ArrayBuffer(buff)) => { - this_val.write(buff.as_ref()); + let data = buff.to_vec(); + ctx.future_to_promise(async move { + let this_val = AsyncTcpConn::opaque_mut(&mut js_obj).unwrap(); + this_val.async_write_all(&data).await; + Ok(JsValue::UnDefined) + }); } Some(JsValue::Object(o)) => { - this_val.write(o.to_string().as_bytes()); + let data = o.to_string(); + ctx.future_to_promise(async move { + let this_val = AsyncTcpConn::opaque_mut(&mut js_obj).unwrap(); + this_val.async_write_all(data.as_bytes()).await; + Ok(JsValue::UnDefined) + }); } Some(JsValue::Symbol(s)) => { let data = format!("{:?}", s); - this_val.write(data.as_bytes()); + ctx.future_to_promise(async move { + let this_val = AsyncTcpConn::opaque_mut(&mut js_obj).unwrap(); + this_val.async_write_all(data.as_bytes()).await; + Ok(JsValue::UnDefined) + }); } _ => {} }; @@ -211,7 +417,7 @@ impl JsClassDef for AsyncTcpConn { impl AsyncTcpServer { pub fn js_accept( &mut self, - _this: &mut JsObject, + this: &mut JsObject, ctx: &mut Context, argv: &[JsValue], ) -> JsValue { @@ -220,45 +426,13 @@ impl AsyncTcpServer { } else { None }; - let (p, ok, error) = ctx.new_promise(); - if let Some(event_loop) = ctx.event_loop() { - self.async_accept( - event_loop, - Box::new(move |ctx, r| match r { - PollResult::Accept(cs) => { - let cs = AsyncTcpConn::wrap_obj(ctx, cs); - if let JsValue::Function(ok) = ok { - ok.call(&[cs]); - } - } - PollResult::Error(e) => { - let err_msg = e.to_string(); - let e = ctx.new_error(err_msg.as_str()); - if let JsValue::Function(error) = error { - error.call(&[e]); - } - } - PollResult::Timeout => { - if let JsValue::Function(error) = error { - let e = std::io::Error::from(std::io::ErrorKind::TimedOut); - let e = ctx.new_error(e.to_string().as_str()); - error.call(&[e]); - } - } - _ => { - if let JsValue::Function(error) = error { - let e = std::io::Error::from(std::io::ErrorKind::Unsupported); - let e = ctx.new_error(e.to_string().as_str()); - error.call(&[e]); - } - } - }), - timeout, - ); - p - } else { - JsValue::UnDefined - } + let n_ctx = ctx.clone(); + let mut js_obj = this.clone().into(); + ctx.future_to_promise(async move { + let this = Self::opaque_mut(&mut js_obj).unwrap(); + let mut ctx = n_ctx; + this.accept(&mut ctx, timeout).await + }) } } @@ -279,10 +453,13 @@ impl JsClassDef for AsyncTcpServer { fn constructor_fn(ctx: &mut Context, argv: &[JsValue]) -> Result { let port = argv.get(0).ok_or_else(|| JsValue::UnDefined)?; - if let (JsValue::Int(port), Some(event_loop)) = (port, ctx.event_loop()) { - match event_loop.tcp_listen(*port as u16) { + if let JsValue::Int(port) = port { + match Self::bind(*port as u16) { Ok(tcp_server) => Ok(tcp_server), - Err(e) => Err(ctx.throw_internal_type_error(e.to_string().as_str()).into()), + Err(e) => { + log::trace!("tcp_listen err: {e}"); + Err(ctx.throw_internal_type_error(e.to_string().as_str()).into()) + } } } else { Err(JsValue::UnDefined) @@ -291,14 +468,15 @@ impl JsClassDef for AsyncTcpServer { } fn js_nsloopup(ctx: &mut Context, _this: JsValue, param: &[JsValue]) -> JsValue { + use wasmedge_wasi_socket::ToSocketAddrs; let node = param.get(0); let service = param.get(1); if let (Some(JsValue::String(node)), Some(JsValue::String(service))) = (node, service) { - let r = event_loop::nslookup(node.as_str(), service.as_str()); + let r = format!("{}:{}", node.as_str(), service.as_str()).to_socket_addrs(); match r { Ok(addr_vec) => { let mut array = ctx.new_array(); - for (i, addr) in addr_vec.iter().enumerate() { + for (i, addr) in addr_vec.enumerate() { array.put(i, ctx.new_string(addr.to_string().as_str()).into()); } array.into() @@ -316,7 +494,8 @@ pub fn init_module(ctx: &mut Context) { &[ AsyncTcpServer::CLASS_NAME, AsyncTcpConn::CLASS_NAME, - "connect", + #[cfg(feature = "tls")] + AsyncTlsConn::CLASS_NAME, "nsloopup", ], |ctx, m| { @@ -325,12 +504,21 @@ pub fn init_module(ctx: &mut Context) { let mut class_ctor = register_class::(ctx); if let JsValue::Function(tcp_conn_ctor) = &mut class_ctor { - let conn = ctx.wrap_function("connect", AsyncTcpConn::connect); + let conn = ctx.wrap_function("connect", AsyncTcpConn::js_connect); tcp_conn_ctor.set("connect", conn.into()); } - m.add_export(AsyncTcpConn::CLASS_NAME, class_ctor); + #[cfg(feature = "tls")] + { + let mut class_ctor = register_class::(ctx); + if let JsValue::Function(tls_conn_ctor) = &mut class_ctor { + let conn = ctx.wrap_function("tls_connect", AsyncTlsConn::js_connect); + tls_conn_ctor.set("connect", conn.into()); + } + m.add_export(AsyncTlsConn::CLASS_NAME, class_ctor); + } + let f = ctx.wrap_function("nsloopup", js_nsloopup); m.add_export("nsloopup", f.into()); }, diff --git a/src/main.rs b/src/main.rs index e867e69..23f82b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,22 +19,29 @@ fn args_parse() -> (String, Vec) { (file_path, res_args) } -fn main() { +#[tokio::main(flavor = "current_thread")] +async fn main() { use wasmedge_quickjs as q; + env_logger::init(); + let mut rt = q::Runtime::new(); - rt.run_with_context(|ctx| { - let (file_path, mut rest_arg) = args_parse(); - let code = std::fs::read_to_string(&file_path); - match code { - Ok(code) => { - rest_arg.insert(0, file_path.clone()); - ctx.put_args(rest_arg); - ctx.eval_module_str(code, &file_path); - } - Err(e) => { - eprintln!("{}", e.to_string()); + + let r = rt + .async_run_with_context(Box::new(|ctx| { + let (file_path, mut rest_arg) = args_parse(); + let code = std::fs::read_to_string(&file_path); + match code { + Ok(code) => { + rest_arg.insert(0, file_path.clone()); + ctx.put_args(rest_arg); + ctx.eval_buf(code.into_bytes(), &file_path, 1) + } + Err(e) => { + eprintln!("{}", e.to_string()); + JsValue::UnDefined + } } - } - ctx.js_loop().unwrap(); - }); + })) + .await; + log::info!("{r:?}"); } diff --git a/src/quickjs_sys/js_class.rs b/src/quickjs_sys/js_class.rs index 7a19bf1..f4b2509 100644 --- a/src/quickjs_sys/js_class.rs +++ b/src/quickjs_sys/js_class.rs @@ -128,7 +128,7 @@ fn into_proto_function_list(p: JsClassProto) -> &'static [JSCFu u: JSCFunctionListEntry__bindgen_ty_1 { func: JSCFunctionListEntry__bindgen_ty_1__bindgen_ty_1 { length: argc, - cproto: JSCFunctionEnum_JS_CFUNC_generic_magic as u8, + cproto: JS_CFUNC_generic_magic as u8, cfunc: JSCFunctionType { generic_magic: Some(js_method_magic_trampoline::), }, @@ -199,7 +199,7 @@ pub trait ExtendsJsClassDef { type BaseDef: JsClassDef; - const CLASS_NAME: &'static str; + const EXT_CLASS_NAME: &'static str; const CONSTRUCTOR_ARGC: u8; const FIELDS: &'static [JsClassField]; const METHODS: &'static [JsClassMethod]; @@ -216,7 +216,7 @@ pub trait ExtendsJsClassDef { impl JsClassDef for S { type RefType = ::RefType; - const CLASS_NAME: &'static str = ::CLASS_NAME; + const CLASS_NAME: &'static str = ::EXT_CLASS_NAME; const CONSTRUCTOR_ARGC: u8 = ::CONSTRUCTOR_ARGC; @@ -563,7 +563,7 @@ pub fn register_class(ctx: &mut Context) -> JsValue { Some(constructor::), class_name.as_ptr().cast(), Def::CONSTRUCTOR_ARGC as i32, - JSCFunctionEnum_JS_CFUNC_constructor, + JS_CFUNC_constructor, 0, ); diff --git a/src/quickjs_sys/js_promise.rs b/src/quickjs_sys/js_promise.rs new file mode 100644 index 0000000..c3dbc18 --- /dev/null +++ b/src/quickjs_sys/js_promise.rs @@ -0,0 +1,106 @@ +use std::{future::Future, sync::atomic::Ordering, task::Poll}; + +use crate::{quickjs_sys::qjs::JS_ExecutePendingJob, Context, EventLoop, JsValue, Runtime}; + +use super::{ + qjs::{js_std_dump_error, JSContext, JS_GetRuntimeOpaque}, + RuntimeResult, +}; + +impl Context { + pub fn future_to_promise( + &mut self, + f: impl Future> + std::marker::Send + 'static, + ) -> JsValue { + let waker = self + .event_loop() + .and_then(|event_loop| event_loop.waker.clone()); + + let (promise, resolve, reject) = self.new_promise(); + + let handle = tokio::task::spawn(async move { + match f.await { + Ok(value) => { + if let JsValue::Function(f) = resolve { + f.call(&[value]); + } + } + Err(err) => { + if let JsValue::Function(f) = reject { + f.call(&[err]); + } + } + } + log::trace!("rt {:?} wake", waker); + waker.map(|waker| waker.wake()); + }); + + self.event_loop().map(|event_loop| { + event_loop.sub_tasks.push_back(handle); + }); + promise + } +} +impl Future for Runtime { + type Output = (); + + fn poll( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll { + unsafe { + let rt = self.rt.0; + let event_loop = { (JS_GetRuntimeOpaque(rt) as *mut EventLoop).as_mut() }; + if let Some(event_loop) = event_loop { + let waker = cx.waker().clone(); + event_loop.waker.insert(waker); + + if self.run_loop_without_io() < 0 { + return Poll::Ready(()); + } + loop { + match event_loop.sub_tasks.pop_front() { + Some(task) => { + if task.is_finished() { + continue; + } else { + event_loop.sub_tasks.push_front(task); + return Poll::Pending; + } + } + None => { + return Poll::Ready(()); + } + } + } + } else { + Poll::Ready(()) + } + } + } +} + +impl<'rt> Future for RuntimeResult<'rt> { + type Output = Result; + + fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { + let me = self.get_mut(); + if me.result.is_none() && me.box_fn.is_some() { + unsafe { + let rt = me.rt.rt.0; + let event_loop = { (JS_GetRuntimeOpaque(rt) as *mut EventLoop).as_mut() }; + if let Some(event_loop) = event_loop { + event_loop.waker.insert(cx.waker().clone()); + } else { + return Poll::Ready(Err(())); + } + let f = me.box_fn.take().unwrap(); + me.result = Some(f(&mut me.rt.ctx)); + } + } + let rt = &mut me.rt; + tokio::pin!(rt); + std::task::ready!(rt.poll(cx)); + Poll::Ready(me.result.take().ok_or(())) + } +} diff --git a/src/quickjs_sys/mod.rs b/src/quickjs_sys/mod.rs index 789a1dd..cff2634 100644 --- a/src/quickjs_sys/mod.rs +++ b/src/quickjs_sys/mod.rs @@ -2,6 +2,7 @@ mod macros; pub mod js_class; pub mod js_module; +pub mod js_promise; use std::collections::HashMap; @@ -142,13 +143,28 @@ unsafe extern "C" fn module_loader( m.cast() } -pub struct Runtime(*mut JSRuntime); +struct InnerRuntime(*mut JSRuntime); +impl Drop for InnerRuntime { + fn drop(&mut self) { + unsafe { JS_FreeRuntime(self.0) }; + } +} +pub struct Runtime { + ctx: Context, + rt: InnerRuntime, +} impl Runtime { pub fn new() -> Self { unsafe { - let mut rt = Runtime(JS_NewRuntime()); - JS_SetModuleLoaderFunc(rt.0, None, Some(module_loader), std::ptr::null_mut()); + let raw_rt = JS_NewRuntime(); + let ctx = Context::new_with_rt(raw_rt); + JS_SetModuleLoaderFunc(raw_rt, None, Some(module_loader), std::ptr::null_mut()); + + let mut rt = Runtime { + ctx, + rt: InnerRuntime(raw_rt), + }; rt.init_event_loop(); rt } @@ -158,12 +174,12 @@ impl Runtime { unsafe { let event_loop = Box::new(super::EventLoop::default()); let event_loop_ptr: &'static mut super::EventLoop = Box::leak(event_loop); - JS_SetRuntimeOpaque(self.0, (event_loop_ptr as *mut super::EventLoop).cast()); + JS_SetRuntimeOpaque(self.rt.0, (event_loop_ptr as *mut super::EventLoop).cast()); } } fn drop_event_loop(&mut self) { unsafe { - let event_loop = JS_GetRuntimeOpaque(self.0) as *mut super::EventLoop; + let event_loop = JS_GetRuntimeOpaque(self.rt.0) as *mut super::EventLoop; if !event_loop.is_null() { Box::from_raw(event_loop); // drop } @@ -171,17 +187,61 @@ impl Runtime { } pub fn run_with_context R, R>(&mut self, mut f: F) -> R { - unsafe { - let mut ctx = Context::new_with_rt(self.0); - f(&mut ctx) + f(&mut self.ctx) + } + + unsafe fn run_loop_without_io(&mut self) -> i32 { + log::trace!("Runtime run loop without io"); + use crate::EventLoop; + use qjs::JS_ExecutePendingJob; + + let rt = self.rt.0; + let event_loop = { (JS_GetRuntimeOpaque(rt) as *mut EventLoop).as_mut() }.unwrap(); + let mut pctx: *mut JSContext = 0 as *mut JSContext; + + loop { + 'pending: loop { + log::trace!("Runtime JS_ExecutePendingJob"); + let err = JS_ExecutePendingJob(rt, (&mut pctx) as *mut *mut JSContext); + if err <= 0 { + if err < 0 { + js_std_dump_error(pctx); + return err; + } + break 'pending; + } + } + + if event_loop.run_tick_task() == 0 { + break; + } + log::trace!("Runtime JS_ExecutePendingJob continue"); + } + 0 + } + + pub fn async_run_with_context( + &mut self, + box_fn: Box JsValue>, + ) -> RuntimeResult { + let box_fn = Some(box_fn); + RuntimeResult { + box_fn, + result: None, + rt: self, } } } +pub struct RuntimeResult<'rt> { + box_fn: Option JsValue>>, + result: Option, + rt: &'rt mut Runtime, +} + impl Drop for Runtime { fn drop(&mut self) { self.drop_event_loop(); - unsafe { JS_FreeRuntime(self.0) }; } } @@ -239,6 +299,8 @@ pub struct Context { ctx: *mut JSContext, } +unsafe impl Send for Context {} + fn get_file_name(ctx: &mut Context, n_stack_levels: usize) -> JsValue { unsafe { let basename = JS_GetScriptOrModuleName(ctx.ctx, n_stack_levels as i32); @@ -294,18 +356,6 @@ impl Context { unsafe { (JS_GetRuntimeOpaque(self.rt()) as *mut super::EventLoop).as_mut() } } - fn event_loop_run_once(&mut self) -> std::io::Result { - unsafe { - if let Some(event_loop) = - (JS_GetRuntimeOpaque(self.rt()) as *mut super::EventLoop).as_mut() - { - event_loop.run_once(self) - } else { - Ok(0) - } - } - } - #[inline] unsafe fn rt(&mut self) -> *mut JSRuntime { JS_GetRuntime(self.ctx) @@ -415,7 +465,6 @@ impl Context { pub fn eval_module_str(&mut self, code: String, filename: &str) { self.eval_buf(code.into_bytes(), filename, JS_EVAL_TYPE_MODULE); - self.promise_loop_poll(); } pub fn new_function(&mut self, name: &str) -> JsFunction { @@ -552,44 +601,14 @@ impl Context { } } + #[deprecated] pub fn promise_loop_poll(&mut self) { - unsafe { - let rt = self.rt(); - let mut pctx: *mut JSContext = 0 as *mut JSContext; - - loop { - let err = JS_ExecutePendingJob(rt, (&mut pctx) as *mut *mut JSContext); - if err <= 0 { - if err < 0 { - js_std_dump_error(pctx); - } - break; - } - } - } + todo!() } + #[deprecated] pub fn js_loop(&mut self) -> std::io::Result<()> { - unsafe { - let rt = self.rt(); - - let mut pctx: *mut JSContext = 0 as *mut JSContext; - loop { - 'pending: loop { - let err = JS_ExecutePendingJob(rt, (&mut pctx) as *mut *mut JSContext); - if err <= 0 { - if err < 0 { - js_std_dump_error(pctx); - return Err(std::io::Error::from(std::io::ErrorKind::Other)); - } - break 'pending; - } - } - if self.event_loop_run_once()? == 0 { - return Ok(()); - } - } - } + todo!() } } @@ -601,6 +620,14 @@ impl Drop for Context { } } +impl Clone for Context { + fn clone(&self) -> Self { + Context { + ctx: unsafe { JS_DupContext(self.ctx) }, + } + } +} + unsafe fn to_u32(ctx: *mut JSContext, v: JSValue) -> Result { if JS_VALUE_GET_NORM_TAG_real(v) == JS_TAG_INT { let mut r = 0u32; @@ -672,6 +699,7 @@ impl Drop for JsRef { } } +unsafe impl Send for JsRef {} pub trait AsObject { fn js_ref(&self) -> &JsRef; @@ -823,6 +851,12 @@ impl JsPromise { } } +impl AsObject for JsPromise { + fn js_ref(&self) -> &JsRef { + &self.0 + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct JsArray(JsRef); diff --git a/test/fs/test-fs-access.js b/test/fs/test-fs-access.js index 957c6a2..355d806 100644 --- a/test/fs/test-fs-access.js +++ b/test/fs/test-fs-access.js @@ -62,19 +62,19 @@ const throwNextTick = (e) => { process.nextTick(() => { throw e; }); }; let __filename = args[0]; -fs.access(__filename, common.mustCall(function(...args) { +fs.access(__filename, common.mustCall(function (...args) { assert.deepStrictEqual(args, [null]); })); fs.promises.access(__filename) .then(common.mustCall()) .catch(throwNextTick); -fs.access(__filename, fs.R_OK, common.mustCall(function(...args) { +fs.access(__filename, fs.R_OK, common.mustCall(function (...args) { assert.deepStrictEqual(args, [null]); })); fs.promises.access(__filename, fs.R_OK) .then(common.mustCall()) .catch(throwNextTick); -fs.access(readOnlyFile, fs.R_OK, common.mustCall(function(...args) { +fs.access(readOnlyFile, fs.R_OK, common.mustCall(function (...args) { assert.deepStrictEqual(args, [null]); })); fs.promises.access(readOnlyFile, fs.R_OK) diff --git a/test/fs/test-fs-cp.js b/test/fs/test-fs-cp.js index b1047d4..468d7ae 100644 --- a/test/fs/test-fs-cp.js +++ b/test/fs/test-fs-cp.js @@ -21,6 +21,7 @@ import { pathToFileURL } from 'url'; import process from 'process'; const setTimeoutAsync = (timeout, val) => { + print("setTimeoutAsync", timeout) return new Promise((res, rej) => { setTimeout(() => { res(val); @@ -336,7 +337,7 @@ if (!isWindows && false) { assert.throws(() => { cpSync(src, dest, { filter: async (path) => { - await setTimeoutAsync(5, 'done'); + await setTimeoutAsync(500, 'done'); const pathStat = statSync(path); return pathStat.isDirectory() || path.endsWith('.js'); }, diff --git a/tests/test-fs.rs b/tests/test-fs.rs index 0f8250f..ff04c1a 100644 --- a/tests/test-fs.rs +++ b/tests/test-fs.rs @@ -5,31 +5,59 @@ use wasmedge_quickjs::*; fn test_js_file(file_path: &str) { use wasmedge_quickjs as q; - let mut rt = q::Runtime::new(); - rt.run_with_context(|ctx| { - let code = std::fs::read_to_string(&file_path); - match code { - Ok(code) => { - ctx.put_args(vec![file_path.clone()]); - ctx.eval_module_str(code, &file_path); - } - Err(e) => { - eprintln!("{}", e.to_string()); - assert!(false, "run js test file fail"); + + env_logger::builder() + // .filter_level(log::LevelFilter::Trace) + .is_test(true) + .try_init(); + + let tokio_rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + tokio_rt.block_on(async { + let mut rt = q::Runtime::new(); + let file_path = file_path.to_string(); + rt.async_run_with_context(Box::new(move |ctx| { + let code = std::fs::read_to_string(&file_path); + match code { + Ok(code) => { + ctx.put_args(vec![file_path.clone()]); + ctx.eval_module_str(code, &file_path); + } + Err(e) => { + eprintln!("{}", e.to_string()); + assert!(false, "run js test file fail"); + } } - } - ctx.js_loop().unwrap(); - if let JsValue::Function(func) = ctx.get_global().get("_onExit") { - func.call(&[]); - } - ctx.js_loop().unwrap(); - if let JsValue::Function(func) = ctx.get_global().get("commonExitCheck") { - func.call(&[]); - } - ctx.js_loop().unwrap(); - if let JsValue::Bool(false) = ctx.get_global().get("assertPass") { - assert!(false, "js assert fail"); - } + JsValue::UnDefined + })) + .await; + rt.async_run_with_context(Box::new(|ctx| { + log::trace!("try _onExit"); + if let JsValue::Function(func) = ctx.get_global().get("_onExit") { + func.call(&[]); + }; + JsValue::UnDefined + })) + .await; + rt.async_run_with_context(Box::new(|ctx| { + log::trace!("try commonExitCheck"); + if let JsValue::Function(func) = ctx.get_global().get("commonExitCheck") { + func.call(&[]); + }; + JsValue::UnDefined + })) + .await; + rt.async_run_with_context(Box::new(|ctx| { + log::trace!("try assertPass"); + if let JsValue::Function(func) = ctx.get_global().get("assertPass") { + func.call(&[]); + }; + JsValue::UnDefined + })) + .await; }); std::fs::remove_dir_all("./test/.tmp.0"); } diff --git a/tests/test-path.rs b/tests/test-path.rs index 084d565..c4cd20a 100644 --- a/tests/test-path.rs +++ b/tests/test-path.rs @@ -5,8 +5,10 @@ use wasmedge_quickjs::*; fn test_js_file(file_path: &str) { use wasmedge_quickjs as q; + + let file_path = file_path.to_string(); let mut rt = q::Runtime::new(); - rt.run_with_context(|ctx| { + let fut = rt.async_run_with_context(Box::new(move |ctx| { let code = std::fs::read_to_string(&file_path); match code { Ok(code) => { @@ -21,8 +23,14 @@ fn test_js_file(file_path: &str) { assert!(false, "run js test file fail"); } } - ctx.js_loop().unwrap(); - }); + JsValue::UnDefined + })); + let tokio_rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + tokio_rt.block_on(fut); } #[test]