diff --git a/.cargo/config b/.cargo/config deleted file mode 100644 index 441bc01..0000000 --- a/.cargo/config +++ /dev/null @@ -1,2 +0,0 @@ -[target.x86_64-pc-windows-msvc] -rustflags = ["-C", "target-feature=+crt-static"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d111fe..7801338 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,12 +54,6 @@ jobs: path: target key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('**/Cargo.lock') }} - - name: Remove Some Cache - if: matrix.os == 'windows-latest' - run: | - rm target/release/gn_root -Recurse -ErrorAction Ignore - rm target/debug/gn_root -Recurse -ErrorAction Ignore - - name: Install webkit2gtk if: matrix.os == 'ubuntu-latest' run: | @@ -83,3 +77,4 @@ jobs: target/release/libwebview_deno.dylib target/release/libwebview_deno.so target/release/webview_deno.dll + target/release/Webview2Loader.dll diff --git a/Cargo.lock b/Cargo.lock index 5e1ef90..b088fcc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,24 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "anyhow" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - [[package]] name = "cc" version = "1.0.58" @@ -27,254 +9,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" [[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "deno_core" -version = "0.87.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce58831bbc265e1ec6fb35f196299e390c138b4085827ad4649b0cf5c5550fe" -dependencies = [ - "anyhow", - "futures", - "indexmap", - "lazy_static", - "libc", - "log", - "pin-project", - "rusty_v8", - "serde", - "serde_json", - "serde_v8", - "url", -] - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "form_urlencoded" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "fslock" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b14c83e47c73f7d62d907ae24a1a98e9132df3c33eb6c54fcf4bce0dbc41d5af" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "futures" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" - -[[package]] -name = "futures-executor" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" - -[[package]] -name = "futures-macro" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" -dependencies = [ - "autocfg", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" - -[[package]] -name = "futures-task" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" - -[[package]] -name = "futures-util" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" -dependencies = [ - "autocfg", - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "proc-macro-hack", - "proc-macro-nested", - "slab", -] - -[[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" - -[[package]] -name = "idna" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itoa" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - -[[package]] -name = "memchr" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pin-project" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7509cc106041c40a4518d2af7a61530e1eed0e6285296a3d8c5472806ccc4a4" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c950132583b500556b1efd71d45b319029f2b71518d979fcc208e16b42426f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" - -[[package]] -name = "pin-utils" -version = "0.1.0" +name = "once_cell" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "pkg-config" @@ -282,157 +20,6 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" - -[[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rusty_v8" -version = "0.22.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda4f5a0179977a62af1a34eb5092e0a75069e9744709ed11617d6562778e6e9" -dependencies = [ - "bitflags", - "fslock", - "lazy_static", - "libc", - "which", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "serde" -version = "1.0.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_v8" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ea79d2b7783a267f4c5aeb3d751f9280c26ee72a99f29e879249dfed12a756" -dependencies = [ - "rusty_v8", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" - -[[package]] -name = "syn" -version = "1.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tinyvec" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", - "serde", -] - [[package]] name = "webview-official-sys" version = "0.1.2" @@ -445,50 +32,8 @@ dependencies = [ [[package]] name = "webview_deno" -version = "0.6.0-pre.0" -dependencies = [ - "deno_core", - "serde", - "webview_official", -] - -[[package]] -name = "webview_official" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b38277d3fa288b13db39eeb153f9b8ee3d8e3181648ade05264c1ba99e774999" +version = "0.7.0-pre.0" dependencies = [ + "once_cell", "webview-official-sys", ] - -[[package]] -name = "which" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe" -dependencies = [ - "either", - "libc", -] - -[[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-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 75e5a25..18d1619 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "webview_deno" -version = "0.6.0-pre.0" +version = "0.7.0-pre.0" authors = ["Elias Sjögreen", "Filippo Rossi"] edition = "2018" [lib] +path = "src/bindings.rs" crate-type = ["cdylib"] [dependencies] -deno_core = "0.87.0" -webview_official = "0.2.0" -serde = "1.0.125" +webview-official-sys = "0.1.2" +once_cell = "1.9.0" + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a388521 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +build: + cargo build + +example: + DEV=true deno run \ + -A \ + --unstable \ + --no-check \ + --config examples/ssr/tsconfig.json \ + examples/ssr/ssr.jsx + +fmt: + cargo fmt + deno fmt --ignore=target/ + +lint: + cargo clippy + deno lint --ignore=target/ + + diff --git a/README.md b/README.md index 17beef4..350a44f 100644 --- a/README.md +++ b/README.md @@ -36,13 +36,12 @@ const html = ` `; -const webview = new Webview( - { url: `data:text/html,${encodeURIComponent(html)}` }, -); -await webview.run(); +const webview = new Webview(); +webview.navigate(`data:text/html,${encodeURIComponent(html)}`); +webview.run(); ``` -you can run this example directly from the web: +You can run this example directly from the web: ```bash deno run -Ar --unstable https://deno.land/x/webview/examples/local.ts @@ -65,36 +64,18 @@ You can find the official documentation ### Prerequisites -For building webview_deno the same -[prerequisites](https://deno.land/std/manual.md#prerequisites) as for building -deno is required. - -A recommended dependency is [denon](https://github.com/denosaurs/denon) which is -used for the built in scripts found in the `denon.json` file. - -#### Linux dependencies +#### Linux - [webkit2gtk](https://webkitgtk.org/) (to install using apt: `sudo apt-get install libwebkit2gtk-4.0-dev`) ### Building -Building webview_deno can take a nontrivial amount of time depending on your -operating system. After the first build most files will be cached so building -time will be reduced. Building on Windows requires admin privileges. - -For a default build you can use the provided script: +Building on Windows requires admin privileges. ```bash -deno run --unstable -A scripts/build.ts -``` - -which internally runs: - -optionally you can use **mshtml**: - -```bash -deno run --unstable -A scripts/build.ts mshtml +make build +# OR cargo build ``` ### Running @@ -102,34 +83,22 @@ deno run --unstable -A scripts/build.ts mshtml To run webview_deno without automatically downloading the binaries from [releases](https://github.com/webview/webview_deno/releases) you will need to use the environment variable `PLUGIN_URL` and set it to the path where the built -binaries are located. This is usually `file://./target/release`. The process of -running and using local binaries can be easier to using the -[dev script](https://github.com/webview/webview_deno/tree/master/scripts/dev.ts): +binaries are located. This is usually `file://./target/release`. ```bash -deno run --unstable -A scripts/dev.ts examples/local.ts +$ make build +$ DEV=true deno run --unstable -A examples/local.ts ``` ## Environment variables -- `PLUGIN_URL` - The URL of the plugin Due to MSHTML (internet explorer) no - longer being enabled by default, the only way to enable it is to set the - `PLUGIN_URL` variable to the path of a binary build built with the - `--no-default-features` flag or using - `deno --unstable -A scripts/build.ts mshtml`. This is usually - `./target/release/` when developing locally. +- `PLUGIN_URL` - Set a custom library URL. Defaults to the latest release assets + on Github. - `DEBUG` - Disable cache and enable logs for `plug`. Used for debugging. ## Dependencies -### Deno - - [plug](https://deno.land/x/plug) - -### Rust - -- [deno_core](https://crates.io/crates/deno_core) -- [deno_json_op](https://github.com/denosaurs/deno_json_op) - [webview-sys](https://crates.io/crates/webview-sys) ## Other @@ -137,7 +106,7 @@ deno run --unstable -A scripts/dev.ts examples/local.ts ### Contribution Pull request, issues and feedback are very welcome. Code style is formatted with -`denon fmt` (which internally runs `deno fmt` and `cargo fmt`) and commit +`make fmt` (which internally runs `deno fmt` and `cargo fmt`) and commit messages are done following [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) spec. diff --git a/denon.json b/denon.json deleted file mode 100644 index dfb690f..0000000 --- a/denon.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "$schema": "https://deno.land/x/denon/schema.json", - "watch": false, - "unstable": true, - "allow": "all", - "scripts": { - "dev": { - "cmd": "deno run scripts/dev.ts", - "desc": "runs the dev command" - }, - "dev:blocking": { - "cmd": "deno run scripts/dev.ts examples/blocking.ts", - "desc": "run `blocking` example" - }, - "dev:external": { - "cmd": "deno run scripts/dev.ts examples/external.ts", - "desc": "run `external` example" - }, - "dev:local": { - "cmd": "deno run scripts/dev.ts examples/local.ts", - "desc": "run `local` example" - }, - "dev:multiple": { - "cmd": "deno run scripts/dev.ts examples/multiple.ts", - "desc": "run `multiple` example" - }, - "dev:perf": { - "cmd": "deno run scripts/dev.ts examples/perf.ts", - "desc": "run `perf` example" - }, - "dev:remote": { - "cmd": "deno run scripts/dev.ts examples/remote.ts", - "desc": "run `remote` example" - }, - "dev:server": { - "cmd": "deno run scripts/dev.ts examples/server.ts", - "desc": "run `server` example" - }, - "dev:user_agent": { - "cmd": "deno run scripts/dev.ts examples/user_agent.ts", - "desc": "run `user_agent` example" - }, - "dev:worker": { - "cmd": "deno run scripts/dev.ts examples/worker/runned.ts", - "desc": "run `worker` example" - }, - "fmt": { - "cmd": "deno run scripts/fmt.ts", - "desc": "prettify project" - }, - "lint": { - "cmd": "deno run scripts/lint.ts", - "desc": "lint project" - }, - "build": { - "cmd": "deno run scripts/build.ts", - "desc": "build crate" - } - } -} diff --git a/deps.ts b/deps.ts index ce61225..7865ff4 100644 --- a/deps.ts +++ b/deps.ts @@ -1,2 +1 @@ -export { delay } from "https://deno.land/std@0.96.0/async/mod.ts"; -export { Plug } from "https://deno.land/x/plug@0.3.0/mod.ts"; +export { CachePolicy, prepare, download } from "https://deno.land/x/plug@0.5.1/plug.ts"; diff --git a/examples/blocking.ts b/examples/blocking.ts deleted file mode 100644 index 3eea99d..0000000 --- a/examples/blocking.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Webview } from "../mod.ts"; - -const html = ` - - -

Hello from deno v${Deno.version.deno}

- - -`; - -const webview = new Webview( - { url: `data:text/html,${encodeURIComponent(html)}` }, -); - -setTimeout(() => { - console.log("Print from timeout after running"); -}, 1000); - -const promise = webview.run(); - -console.log("Print from top level after running"); - -// await closing of webview -await promise; diff --git a/examples/external.ts b/examples/external.ts deleted file mode 100644 index 6e7c7cd..0000000 --- a/examples/external.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Webview } from "../mod.ts"; - -const html = ` - - - - - - - -`; - -const webview = new Webview( - { url: `data:text/html,${encodeURIComponent(html)}` }, -); - -for await (const event of webview.iter()) { - webview.setTitle(event); -} - -// await webview.run((event) => webview.setTitle(event)); diff --git a/examples/local.ts b/examples/local.ts index 1208e2e..405577e 100644 --- a/examples/local.ts +++ b/examples/local.ts @@ -8,7 +8,6 @@ const html = ` `; -const webview = new Webview( - { url: `data:text/html,${encodeURIComponent(html)}` }, -); -await webview.run(); +const webview = new Webview(); +webview.navigate(`data:text/html,${encodeURIComponent(html)}`); +webview.run(); diff --git a/examples/multiple.ts b/examples/multiple.ts index a6fe60a..ca539c1 100644 --- a/examples/multiple.ts +++ b/examples/multiple.ts @@ -1,5 +1,12 @@ import { Webview } from "../mod.ts"; -const webview1 = new Webview({ url: "https://deno.land" }); -const webview2 = new Webview({ url: "https://wikipedia.org" }); -await Promise.all([webview1.run(), webview2.run()]); +const webview1 = new Webview(); +webview1.navigate("https://deno.land/"); + +const webview2 = new Webview(); +webview2.navigate("https://google.com/"); + +// NOTE: Due to design limitations, you can only have one webview +// instance **at a time** +webview1.run(); +webview2.run(); diff --git a/examples/perf.ts b/examples/perf.ts deleted file mode 100644 index 762f62b..0000000 --- a/examples/perf.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Webview } from "../mod.ts"; - -const html = ` - - - - - - -`; - -const webview = new Webview( - { url: `data:text/html,${encodeURIComponent(html)}` }, -); - -await webview.run((event) => { - switch (event) { - case "test": - console.time(); - webview.eval("test();"); - break; - case "finish": - console.timeEnd(); - break; - } -}); diff --git a/examples/remote.ts b/examples/remote.ts index b5bafba..505462f 100644 --- a/examples/remote.ts +++ b/examples/remote.ts @@ -1,4 +1,5 @@ import { Webview } from "../mod.ts"; -const webview = new Webview({ url: "https://deno.land" }); -await webview.run(); +const webview = new Webview(); +webview.navigate("https://deno.land/"); +webview.run(); diff --git a/examples/server.ts b/examples/server.ts index f4e680d..4f4ea63 100644 --- a/examples/server.ts +++ b/examples/server.ts @@ -1,14 +1,17 @@ -import { serve } from "https://deno.land/std@0.79.0/http/mod.ts"; +import { serve } from "https://deno.land/std@0.120.0/http/mod.ts"; import { Webview } from "../mod.ts"; -const webview = new Webview( - { url: `http://localhost:8080` }, -); -const promise = webview.run(); +const server = serve(() => + new Response("

Hello World

", { + headers: new Headers({ + "content-type": "text/html", + }), + }), { port: 8080 }); -const server = serve({ port: 8080 }); -for await (const req of server) { - req.respond({ body: "Hello World" }); -} +const webview = new Webview(); -await promise; +webview.navigate(`http://localhost:8080`); + +// FIXME: Blocks the main thread and +// no further requests can be served. +webview.run(); diff --git a/examples/ssr/ssr.jsx b/examples/ssr/ssr.jsx new file mode 100644 index 0000000..d2e9adb --- /dev/null +++ b/examples/ssr/ssr.jsx @@ -0,0 +1,29 @@ +import { dirname, join } from "https://deno.land/std@0.114.0/path/mod.ts"; +import { serve } from "https://deno.land/std@0.114.0/http/server.ts"; +import { h, ssr, tw } from "https://crux.land/nanossr@0.0.1"; + +const Hello = (props) => ( +
+

+ Hello {props.name}! +

+
+); + +const server = serve((req) => { + console.log(req); + const url = new URL(req.url); + const name = url.searchParams.get("name") ?? "world"; + return ssr(() => ); +}, { port: 8000 }); + +console.log("[runner] Listening on http://localhost:8000"); +console.log("[runner] worker started"); + +setTimeout(() => + new Worker( + join(dirname(import.meta.url), "worker.ts"), + { type: "module", deno: true }, + ), 1000); + +await server; diff --git a/examples/ssr/tsconfig.json b/examples/ssr/tsconfig.json new file mode 100644 index 0000000..bef9c78 --- /dev/null +++ b/examples/ssr/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "lib": ["dom", "dom.iterable", "deno.ns", "deno.unstable"], + "jsxFactory": "h" + } +} diff --git a/examples/ssr/worker.ts b/examples/ssr/worker.ts new file mode 100644 index 0000000..313c4a4 --- /dev/null +++ b/examples/ssr/worker.ts @@ -0,0 +1,12 @@ +import { Webview } from "../../mod.ts"; +const webview = new Webview(); + +webview.navigate("http://localhost:8000/"); +onmessage = (event) => { + if (event.data === "close") { + webview.terminate(); + self.close(); + } +}; + +webview.run(); diff --git a/examples/user_agent.ts b/examples/user_agent.ts index 25a5348..a3cd16a 100644 --- a/examples/user_agent.ts +++ b/examples/user_agent.ts @@ -3,12 +3,12 @@ import { Webview } from "../mod.ts"; const html = ` - + `; -const webview = new Webview( - { url: `data:text/html,${encodeURIComponent(html)}` }, -); -await webview.run(); +const webview = new Webview(); + +webview.navigate(`data:text/html,${encodeURIComponent(html)}`); +webview.run(); diff --git a/examples/worker/runner.ts b/examples/worker/runner.ts deleted file mode 100644 index 1bff1cb..0000000 --- a/examples/worker/runner.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { dirname, join } from "https://deno.land/std/path/mod.ts"; - -const worker = new Worker( - join(dirname(import.meta.url), "worker.ts"), - { type: "module", deno: true }, -); - -console.log("Worker is running, closing in 5 seconds"); -setTimeout(() => { - console.log("Closing worker"); - worker.postMessage("close"); -}, 5000); diff --git a/examples/worker/worker.ts b/examples/worker/worker.ts deleted file mode 100644 index 1f1e2df..0000000 --- a/examples/worker/worker.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Webview } from "../../mod.ts"; -import { unload } from "../../plugin.ts"; - -const html = ` - - -

Hello from deno worker!

- - -`; - -const webview = new Webview( - { url: `data:text/html,${encodeURIComponent(html)}` }, -); - -onmessage = (event) => { - if (event.data === "close") { - webview.drop(); - unload(); - self.close(); - } -}; - -webview.run(); diff --git a/mod.ts b/mod.ts index 755f952..89d4685 100644 --- a/mod.ts +++ b/mod.ts @@ -1,2 +1 @@ -import "./plugin.ts"; -export * from "./webview.ts"; +export * from "./src/webview.ts"; diff --git a/plugin.ts b/plugin.ts deleted file mode 100644 index 5a020de..0000000 --- a/plugin.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Plug } from "./deps.ts"; - -const VERSION = "0.6.0-pre.0"; -const POLICY = Deno.env.get("PLUGIN_URL") === undefined - ? Plug.CachePolicy.STORE - : Plug.CachePolicy.NONE; -const PLUGIN_URL = Deno.env.get("PLUGIN_URL") ?? - `https://github.com/webview/webview_deno/releases/download/${VERSION}/`; - -await Plug.prepare({ - name: "webview_deno", - url: PLUGIN_URL, - policy: POLICY, -}); diff --git a/scripts/_util.ts b/scripts/_util.ts deleted file mode 100644 index 5f15801..0000000 --- a/scripts/_util.ts +++ /dev/null @@ -1,30 +0,0 @@ -export async function requires(...executables: string[]) { - const where = Deno.build.os === "windows" ? "where" : "which"; - - for (const executable of executables) { - const process = Deno.run({ - cmd: [where, executable], - stderr: "null", - stdin: "null", - stdout: "null", - }); - - if (!(await process.status()).success) { - console.error(`Could not find required build tool ${executable}`); - } - } -} - -export async function run( - msg: string, - cmd: string[], - env?: { [key: string]: string }, -) { - console.log(msg); - - const process = Deno.run({ cmd, env }); - - if (!(await process.status()).success) { - console.error(`${msg} failed`); - } -} diff --git a/scripts/build.ts b/scripts/build.ts deleted file mode 100644 index 63e260c..0000000 --- a/scripts/build.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { requires, run } from "./_util.ts"; - -export async function build(mshtml: boolean) { - await requires("cargo"); - - const command = ["cargo", "build", "--release"]; - - if (mshtml) { - command.push("--no-default-features"); - } - - await run("building rust", command); -} - -if (import.meta.main) { - await build(Deno.args.includes("mshtml")); -} diff --git a/scripts/dev.ts b/scripts/dev.ts deleted file mode 100644 index bd780cb..0000000 --- a/scripts/dev.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { build } from "./build.ts"; -import { run } from "./run.ts"; - -export async function dev( - file: string, - mshtml: boolean, -) { - await build(mshtml); - await run(file); -} - -if (import.meta.main) { - await dev(Deno.args[0], Deno.args.includes("mshtml")); -} diff --git a/scripts/fmt.ts b/scripts/fmt.ts deleted file mode 100644 index a3b0c1f..0000000 --- a/scripts/fmt.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { requires, run } from "./_util.ts"; - -export async function fmt() { - await requires("cargo", "deno"); - - await run("formatting rust", ["cargo", "fmt"]); - await run("formatting deno", ["deno", "fmt"]); -} - -if (import.meta.main) { - fmt(); -} diff --git a/scripts/lint.ts b/scripts/lint.ts deleted file mode 100644 index 2377808..0000000 --- a/scripts/lint.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { requires, run } from "./_util.ts"; - -export async function lint() { - await requires("cargo", "deno"); - - await run("linting rust", ["cargo", "clippy"]); - await run("linting deno", ["deno", "--unstable", "lint"]); -} - -if (import.meta.main) { - lint(); -} diff --git a/scripts/run.ts b/scripts/run.ts deleted file mode 100644 index b5d0375..0000000 --- a/scripts/run.ts +++ /dev/null @@ -1,18 +0,0 @@ -import * as util from "./_util.ts"; - -export async function run(file: string) { - await util.requires("deno"); - - await util.run( - `running`, - ["deno", "run", "-Ar", "--unstable", file], - { - PLUGIN_URL: "./target/release", - DEBUG: "true", - }, - ); -} - -if (import.meta.main) { - await run(Deno.args[0]); -} diff --git a/src/bindings.rs b/src/bindings.rs new file mode 100644 index 0000000..5227322 --- /dev/null +++ b/src/bindings.rs @@ -0,0 +1,90 @@ +use once_cell::sync::Lazy; +use std::ffi::CStr; +use std::os::raw::c_char; +use std::os::raw::c_int; +use std::os::raw::c_void; +use std::sync::Mutex; +use webview_official_sys::webview_t; +use webview_official_sys::DispatchFn; + +static RECV: Lazy> = + Lazy::new(|| Mutex::new(("".to_string(), "".to_string()))); + +macro_rules! export { + ($rename: ident, fn $name:ident($( $arg:ident : $type:ty ),*) -> $ret:ty) => { + #[no_mangle] + #[doc = "# Safety"] + #[doc = ""] + #[doc = "This function is unsafe for obvious reasons."] + pub unsafe extern "C" fn $rename($( $arg : $type),*) -> $ret { + webview_official_sys::$name($( $arg ),*) + } + }; + ($rename: ident, fn $name:ident($( $arg:ident : $type:ty ),*)) => { + export!($rename, fn $name($( $arg : $type),*) -> ()); + } +} + +// https://github.com/rust-lang/rfcs/issues/2771 +export!(deno_webview_create, fn webview_create(debug: c_int, window: *mut c_void) -> webview_t); +export!(deno_webview_destroy, fn webview_destroy(w: webview_t)); +export!(deno_webview_run, fn webview_run(w: webview_t)); +export!(deno_webview_terminate, fn webview_terminate(w: webview_t)); +export!(deno_webview_dispatch, fn webview_dispatch(w: webview_t, fn_: Option, arg: *mut c_void)); +export!(deno_webview_get_window, fn webview_get_window(w: webview_t) -> *mut c_void); +export!(deno_webview_set_title, fn webview_set_title(w: webview_t, title: *const c_char)); +export!(deno_webview_set_size, fn webview_set_size(w: webview_t, width: c_int, height: c_int, hints: c_int)); +export!(deno_webview_navigate, fn webview_navigate(w: webview_t, url: *const c_char)); +export!(deno_webview_init, fn webview_init(w: webview_t, js: *const c_char)); +export!(deno_webview_eval, fn webview_eval(w: webview_t, js: *const c_char)); +export!(deno_webview_return, fn webview_return(w: webview_t, seq: *const c_char, status: c_int, result: *const c_char)); + +/// # Safety +/// +/// webview pointer must be non NULL. It must be obtained using +/// `webview_create`. +#[no_mangle] +pub unsafe extern "C" fn deno_webview_bind(w: webview_t, name: *const c_char) { + extern "C" fn callback( + seq: *const c_char, + req: *const c_char, + _userdata: *mut c_void, + ) { + let seq = unsafe { + CStr::from_ptr(seq) + .to_str() + .expect("No null bytes in parameter seq") + }; + let req = unsafe { + CStr::from_ptr(req) + .to_str() + .expect("No null bytes in parameter req") + }; + + let mut recv = RECV.lock().unwrap(); + recv.0 = seq.to_string(); + recv.1 = req.to_string(); + } + + webview_official_sys::webview_bind( + w, + name, + Some(callback), + std::ptr::null_mut(), + ) +} + +#[no_mangle] +pub extern "C" fn deno_webview_get_recv() -> *const u8 { + let recv = RECV.lock().unwrap(); + let mut recv_buf = Vec::new(); + recv_buf.extend_from_slice(&u32::to_be_bytes(recv.0.len() as u32)); + + recv_buf.extend_from_slice(recv.0.as_bytes()); + recv_buf.extend_from_slice(&u32::to_be_bytes(recv.1.len() as u32)); + recv_buf.extend_from_slice(recv.1.as_bytes()); + + let ptr = recv_buf.as_ptr(); + std::mem::forget(recv_buf); + ptr +} diff --git a/src/ffi.ts b/src/ffi.ts new file mode 100644 index 0000000..30be5da --- /dev/null +++ b/src/ffi.ts @@ -0,0 +1,83 @@ +import { CachePolicy, download, prepare } from "../deps.ts"; + +const version = "0.7.0-pre.0"; +const policy = Deno.env.get("PLUGIN_URL") === undefined + ? CachePolicy.STORE + : CachePolicy.NONE; +const url = Deno.env.get("PLUGIN_URL") ?? + `https://github.com/webview/webview_deno/releases/download/${version}/`; + +if (Deno.build.os === "windows") { + const webview2loader = await download(`${url}WebView2Loader.dll`); + await Deno.copyFile(webview2loader, "./WebView2Loader.dll"); + window.onunload = () => { + lib.close(); + Deno.removeSync("./WebView2Loader.dll"); + }; +} + +const lib = await prepare({ + name: "webview_deno", + url, + policy, +}, { + "deno_webview_create": { + parameters: ["i32", "pointer"], + result: "pointer", + }, + "deno_webview_destroy": { + parameters: ["pointer"], + result: "void", + }, + "deno_webview_run": { + parameters: ["pointer"], + result: "void", + }, + "deno_webview_terminate": { + parameters: ["pointer"], + result: "void", + }, + "deno_webview_dispatch": { + parameters: ["pointer", "pointer", "pointer"], + result: "void", + }, + "deno_webview_set_title": { + parameters: ["pointer", "pointer"], + result: "void", + }, + "deno_webview_get_window": { + parameters: ["pointer"], + result: "pointer", + }, + "deno_webview_set_size": { + parameters: ["pointer", "i32", "i32", "i32"], + result: "void", + }, + "deno_webview_navigate": { + parameters: ["pointer", "pointer"], + result: "void", + }, + "deno_webview_eval": { + parameters: ["pointer", "pointer"], + result: "void", + }, + "deno_webview_init": { + parameters: ["pointer", "pointer"], + result: "void", + }, + "deno_webview_bind": { + parameters: ["pointer", "pointer"], + result: "void", + }, + "deno_webview_return": { + parameters: ["pointer", "pointer", "i32", "pointer"], + result: "void", + }, + "deno_webview_get_recv": { + parameters: [], + result: "pointer", + nonblocking: true, + }, +}); + +export default lib; diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 4c2e62c..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,272 +0,0 @@ -use std::borrow::Cow; -use std::cell::RefCell; -use std::rc::Rc; - -use deno_core::error::anyhow; -use deno_core::error::bad_resource_id; -use deno_core::error::AnyError; -use deno_core::futures::channel::mpsc::channel; -use deno_core::futures::channel::mpsc::Receiver; -use deno_core::futures::channel::mpsc::Sender; -use deno_core::futures::StreamExt; -use deno_core::op_async; -use deno_core::op_sync; -use deno_core::serde::Deserialize; -use deno_core::Extension; -use deno_core::OpState; -use deno_core::Resource; -use deno_core::ResourceId; -use deno_core::ZeroCopyBuf; - -use webview_official::SizeHint; -use webview_official::Webview; -use webview_official::Window; - -type WebviewEvent = (String, String); - -struct WebviewResource { - inner: RefCell, - events_rx: RefCell>, - events_tx: RefCell>, -} - -impl WebviewResource { - fn new(debug: bool, window: Option<&mut Window>) -> Self { - let (tx, rx) = channel::<(String, String)>(256); - WebviewResource { - inner: RefCell::new(Webview::create(debug, window)), - events_rx: RefCell::new(rx), - events_tx: RefCell::new(tx), - } - } - - fn bind(&self, name: &str) { - let mut webview = self.inner.borrow_mut(); - - webview.bind(name, |seq, req| { - println!("{} {}", seq, req); - let _ = self - .events_tx - .borrow_mut() - .try_send((seq.to_string(), req.to_string())); - }) - } - - async fn next(&self) -> Option { - self.events_rx.borrow_mut().next().await - } -} - -impl Resource for WebviewResource { - fn name(&self) -> Cow { - "webview".into() - } -} - -#[derive(Deserialize)] -struct StringArgs(ResourceId, String); - -#[derive(Deserialize)] -struct SizeArgs { - rid: ResourceId, - width: i32, - height: i32, - size: i32, -} - -#[derive(Deserialize)] -struct ReturnArgs { - rid: ResourceId, - seq: String, - status: i32, - result: String, -} - -#[no_mangle] -pub fn init() -> Extension { - Extension::builder() - .ops(vec![ - ("webview_create", op_sync(webview_create)), - ("webview_run", op_sync(webview_run)), - ("webview_terminate", op_sync(webview_terminate)), - ("webview_set_title", op_sync(webview_set_title)), - ("webview_set_size", op_sync(webview_set_size)), - ("webview_navigate", op_sync(webview_navigate)), - ("webview_init", op_sync(webview_init)), - ("webview_eval", op_sync(webview_eval)), - ("webview_bind", op_sync(webview_bind)), - ("webview_return", op_sync(webview_return)), - ("webview_poll_next", op_async(webview_poll_next)), - ]) - .build() -} - -fn webview_create( - state: &mut OpState, - debug: bool, - _zero_copy: Option, -) -> Result { - Ok(state.resource_table.add(WebviewResource::new(debug, None))) -} - -fn webview_run( - state: &mut OpState, - rid: ResourceId, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(rid) - .ok_or_else(bad_resource_id)?; - - webview.inner.borrow_mut().run(); - - Ok(()) -} - -fn webview_terminate( - state: &mut OpState, - rid: ResourceId, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(rid) - .ok_or_else(bad_resource_id)?; - - webview.inner.borrow_mut().terminate(); - - Ok(()) -} - -fn webview_set_title( - state: &mut OpState, - args: StringArgs, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(args.0) - .ok_or_else(bad_resource_id)?; - - webview.inner.borrow_mut().set_title(&args.1); - - Ok(()) -} - -fn webview_set_size( - state: &mut OpState, - args: SizeArgs, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(args.rid) - .ok_or_else(bad_resource_id)?; - - webview.inner.borrow_mut().set_size( - args.width, - args.height, - match args.size { - 0 => SizeHint::NONE, - 1 => SizeHint::MIN, - 2 => SizeHint::MAX, - 3 => SizeHint::FIXED, - _ => return Err(anyhow!("Size hint needs to be in range 0..3")), - }, - ); - - Ok(()) -} - -fn webview_navigate( - state: &mut OpState, - args: StringArgs, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(args.0) - .ok_or_else(bad_resource_id)?; - - webview.inner.borrow_mut().navigate(&args.1); - - Ok(()) -} - -fn webview_init( - state: &mut OpState, - args: StringArgs, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(args.0) - .ok_or_else(bad_resource_id)?; - - webview.inner.borrow_mut().init(&args.1); - - Ok(()) -} - -fn webview_eval( - state: &mut OpState, - args: StringArgs, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(args.0) - .ok_or_else(bad_resource_id)?; - - webview.inner.borrow_mut().eval(&args.1); - - Ok(()) -} - -fn webview_bind( - state: &mut OpState, - args: StringArgs, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(args.0) - .ok_or_else(bad_resource_id)?; - - webview.bind(&args.1); - - Ok(()) -} - -fn webview_return( - state: &mut OpState, - args: ReturnArgs, - _zero_copy: Option, -) -> Result<(), AnyError> { - let webview = state - .resource_table - .get::(args.rid) - .ok_or_else(bad_resource_id)?; - - webview - .inner - .borrow_mut() - .r#return(&args.seq, args.status, &args.result); - - Ok(()) -} - -async fn webview_poll_next( - state: Rc>, - rid: ResourceId, - _zero_copy: Option, -) -> Result, AnyError> { - let webview = state - .borrow_mut() - .resource_table - .get::(rid) - .ok_or_else(bad_resource_id)?; - - Ok(webview.next().await) -} diff --git a/src/webview.ts b/src/webview.ts new file mode 100644 index 0000000..b685751 --- /dev/null +++ b/src/webview.ts @@ -0,0 +1,91 @@ +import sys from "./ffi.ts"; + +const encoder = new TextEncoder(); + +function encode(value: string) { + return encoder.encode(value + "\n"); +} + +export type SizeHint = 0 | 1 | 2 | 3; + +export const SizeHint = { + NONE: 0, + MIN: 1, + MAX: 2, + FIXED: 3, +} as const; + +export class Webview { + #handle: Deno.UnsafePointer | null = null; + #url?: string; + + get unsafeHandle() { + return this.#handle; + } + + get url(): string { + if (this.#url == undefined) throw new TypeError("Webview not initialized"); + return this.#url; + } + + constructor() { + this.#handle = sys.symbols.deno_webview_create( + 0, + null, + ) as Deno.UnsafePointer; + } + + terminate() { + sys.symbols.deno_webview_terminate(this.#handle); + sys.symbols.deno_webview_destroy(this.#handle); + this.#handle = null; + } + + navigate(url: string) { + this.#url = url; + } + + async run() { + if (this.#url == null) throw new TypeError("URL not initialized"); + sys.symbols.deno_webview_navigate(this.#handle, encode(this.#url)); + await sys.symbols.deno_webview_run(this.#handle); + } + + set title(title: string) { + sys.symbols.deno_webview_set_title(this.#handle, encode(title)); + } + + // TODO(@littledivy): Current design limitations prevent this from working + // We need Rust to call into V8 and Deno FFI callbacks *might* solve this. + bind(name: string, cb: (seq: string, recv: Deno.UnsafePointer) => void) { + sys.symbols.deno_webview_bind(this.#handle, encode(name)); + sys.symbols.deno_webview_get_recv().then((recv) => { + const ptr = new Deno.UnsafePointerView(recv as Deno.UnsafePointer); + const lengthBe = new Uint8Array(4); + const view = new DataView(lengthBe.buffer); + ptr.copyInto(lengthBe, 0); + const buf = new Uint8Array(view.getUint32(0)); + ptr.copyInto(buf, 4); + + const seq = new TextDecoder().decode(buf); + cb(seq, recv); + }); + } + + return(seq: string, status: number, result: string) { + sys.symbols.deno_webview_return( + this.#handle, + encode(seq), + status, + encode(result), + ); + } + + eval(source: string) { + sys.symbols.deno_webview_eval(this.#handle, encode(source)); + } + + init(source: string) { + sys.symbols.deno_webview_init(this.#handle, encode(source)); + } +} diff --git a/webview.ts b/webview.ts deleted file mode 100644 index 3c66bb8..0000000 --- a/webview.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { Plug } from "./deps.ts"; - -export type SizeHint = 0 | 1 | 2 | 3; - -export const SizeHint = { - NONE: 0, - MIN: 1, - MAX: 2, - FIXED: 3, -} as const; - -/** - * A Webview instance - */ -export class Webview { - readonly rid: number; - - constructor(debug = false) { - this.rid = Plug.core.opSync("webview_create", debug); - } - - run() { - Plug.core.opSync("webview_run", this.rid); - } - - terminate() { - Plug.core.opSync("webview_terminate", this.rid); - } - - setTitle(title: string) { - Plug.core.opSync("webview_set_title", [this.rid, title]); - } - - setSize(width: number, height: number, hints: SizeHint) { - Plug.core.opSync("webview_set_title", [this.rid, width, height, hints]); - } - - navigate(url: string) { - Plug.core.opSync("webview_navigate", [this.rid, url]); - } - - init(js: string) { - Plug.core.opSync("webview_init", [this.rid, js]); - } - - eval(js: string) { - Plug.core.opSync("webview_eval", [this.rid, js]); - } - - bind(name: string, callback: (seq: string, req: string) => void) { - Plug.core.opSync("webview_bind", [this.rid, name]); - - Plug.core.opAsync("webview_poll_next", this.rid).then((value) => { - if (value !== undefined) { - const [seq, req] = value as [string, string]; - - callback(seq, req); - } else { - throw new Error("Poll value is undefined"); - } - }); - } - - return(seq: string, status: number, result: string) { - Plug.core.opSync("webview_return", { - rid: this.rid, - seq, - status, - result, - }); - } -}