initial import of main veilid core
This commit is contained in:
11
veilid-wasm/.appveyor.yml
Normal file
11
veilid-wasm/.appveyor.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
install:
|
||||
- appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
- if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- rustc -V
|
||||
- cargo -V
|
||||
|
||||
build: false
|
||||
|
||||
test_script:
|
||||
- cargo test --locked
|
0
veilid-wasm/.cargo-ok
Normal file
0
veilid-wasm/.cargo-ok
Normal file
6
veilid-wasm/.gitignore
vendored
Normal file
6
veilid-wasm/.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
bin/
|
||||
pkg/
|
||||
wasm-pack.log
|
69
veilid-wasm/.travis.yml
Normal file
69
veilid-wasm/.travis.yml
Normal file
@@ -0,0 +1,69 @@
|
||||
language: rust
|
||||
sudo: false
|
||||
|
||||
cache: cargo
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
# Builds with wasm-pack.
|
||||
- rust: beta
|
||||
env: RUST_BACKTRACE=1
|
||||
addons:
|
||||
firefox: latest
|
||||
chrome: stable
|
||||
before_script:
|
||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
||||
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
|
||||
- cargo install-update -a
|
||||
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
|
||||
script:
|
||||
- cargo generate --git . --name testing
|
||||
# Having a broken Cargo.toml (in that it has curlies in fields) anywhere
|
||||
# in any of our parent dirs is problematic.
|
||||
- mv Cargo.toml Cargo.toml.tmpl
|
||||
- cd testing
|
||||
- wasm-pack build
|
||||
- wasm-pack test --chrome --firefox --headless
|
||||
|
||||
# Builds on nightly.
|
||||
- rust: nightly
|
||||
env: RUST_BACKTRACE=1
|
||||
before_script:
|
||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
||||
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
|
||||
- cargo install-update -a
|
||||
- rustup target add wasm32-unknown-unknown
|
||||
script:
|
||||
- cargo generate --git . --name testing
|
||||
- mv Cargo.toml Cargo.toml.tmpl
|
||||
- cd testing
|
||||
- cargo check
|
||||
- cargo check --target wasm32-unknown-unknown
|
||||
- cargo check --no-default-features
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features
|
||||
- cargo check --no-default-features --features console_error_panic_hook
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
|
||||
- cargo check --no-default-features --features "console_error_panic_hook wee_alloc"
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features --features "console_error_panic_hook wee_alloc"
|
||||
|
||||
# Builds on beta.
|
||||
- rust: beta
|
||||
env: RUST_BACKTRACE=1
|
||||
before_script:
|
||||
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
||||
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
|
||||
- cargo install-update -a
|
||||
- rustup target add wasm32-unknown-unknown
|
||||
script:
|
||||
- cargo generate --git . --name testing
|
||||
- mv Cargo.toml Cargo.toml.tmpl
|
||||
- cd testing
|
||||
- cargo check
|
||||
- cargo check --target wasm32-unknown-unknown
|
||||
- cargo check --no-default-features
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features
|
||||
- cargo check --no-default-features --features console_error_panic_hook
|
||||
- cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
|
||||
# Note: no enabling the `wee_alloc` feature here because it requires
|
||||
# nightly for now.
|
27
veilid-wasm/Cargo.toml
Normal file
27
veilid-wasm/Cargo.toml
Normal file
@@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "veilid-wasm"
|
||||
version = "0.1.0"
|
||||
authors = ["John Smith <jsmith@example.com>"]
|
||||
edition = "2018"
|
||||
license = "LGPL-2.0-or-later OR MPL-2.0 OR (MIT AND BSD-3-Clause)"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = "^0"
|
||||
console_error_panic_hook = "^0"
|
||||
wee_alloc = "^0"
|
||||
wasm-logger = "^0"
|
||||
log = "^0"
|
||||
veilid-core = { path = "../veilid-core" }
|
||||
cfg-if = "^1"
|
||||
wasm-bindgen-futures = "^0"
|
||||
js-sys = "^0"
|
||||
|
||||
[dev-dependencies]
|
||||
wasm-bindgen-test = "^0"
|
||||
|
||||
[profile.release]
|
||||
# Tell `rustc` to optimize for small code size.
|
||||
opt-level = "s"
|
176
veilid-wasm/LICENSE_APACHE
Normal file
176
veilid-wasm/LICENSE_APACHE
Normal file
@@ -0,0 +1,176 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
25
veilid-wasm/LICENSE_MIT
Normal file
25
veilid-wasm/LICENSE_MIT
Normal file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2018 John Smith <jsmith@example.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
69
veilid-wasm/README.md
Normal file
69
veilid-wasm/README.md
Normal file
@@ -0,0 +1,69 @@
|
||||
<div align="center">
|
||||
|
||||
<h1><code>wasm-pack-template</code></h1>
|
||||
|
||||
<strong>A template for kick starting a Rust and WebAssembly project using <a href="https://github.com/rustwasm/wasm-pack">wasm-pack</a>.</strong>
|
||||
|
||||
<p>
|
||||
<a href="https://travis-ci.org/rustwasm/wasm-pack-template"><img src="https://img.shields.io/travis/rustwasm/wasm-pack-template.svg?style=flat-square" alt="Build Status" /></a>
|
||||
</p>
|
||||
|
||||
<h3>
|
||||
<a href="https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html">Tutorial</a>
|
||||
<span> | </span>
|
||||
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
|
||||
</h3>
|
||||
|
||||
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
|
||||
</div>
|
||||
|
||||
## About
|
||||
|
||||
[**📚 Read this template tutorial! 📚**][template-docs]
|
||||
|
||||
This template is designed for compiling Rust libraries into WebAssembly and
|
||||
publishing the resulting package to NPM.
|
||||
|
||||
Be sure to check out [other `wasm-pack` tutorials online][tutorials] for other
|
||||
templates and usages of `wasm-pack`.
|
||||
|
||||
[tutorials]: https://rustwasm.github.io/docs/wasm-pack/tutorials/index.html
|
||||
[template-docs]: https://rustwasm.github.io/docs/wasm-pack/tutorials/npm-browser-packages/index.html
|
||||
|
||||
## 🚴 Usage
|
||||
|
||||
### 🐑 Use `cargo generate` to Clone this Template
|
||||
|
||||
[Learn more about `cargo generate` here.](https://github.com/ashleygwilliams/cargo-generate)
|
||||
|
||||
```
|
||||
cargo generate --git https://github.com/rustwasm/wasm-pack-template.git --name my-project
|
||||
cd my-project
|
||||
```
|
||||
|
||||
### 🛠️ Build with `wasm-pack build`
|
||||
|
||||
```
|
||||
wasm-pack build
|
||||
```
|
||||
|
||||
### 🔬 Test in Headless Browsers with `wasm-pack test`
|
||||
|
||||
```
|
||||
wasm-pack test --headless --firefox
|
||||
```
|
||||
|
||||
### 🎁 Publish to NPM with `wasm-pack publish`
|
||||
|
||||
```
|
||||
wasm-pack publish
|
||||
```
|
||||
|
||||
## 🔋 Batteries Included
|
||||
|
||||
* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating
|
||||
between WebAssembly and JavaScript.
|
||||
* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook)
|
||||
for logging panic messages to the developer console.
|
||||
* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized
|
||||
for small code size.
|
285
veilid-wasm/src/js_veilid_core.rs
Normal file
285
veilid-wasm/src/js_veilid_core.rs
Normal file
@@ -0,0 +1,285 @@
|
||||
use crate::*;
|
||||
pub use wasm_bindgen_futures::*;
|
||||
|
||||
#[wasm_bindgen(js_name = VeilidStateChange)]
|
||||
pub struct JsVeilidStateChange {
|
||||
kind: String, // "attachment" => AttachmentState(String)
|
||||
from: JsValue,
|
||||
to: JsValue,
|
||||
}
|
||||
#[wasm_bindgen(js_name = VeilidState)]
|
||||
pub struct JsVeilidState {
|
||||
kind: String, // "attachment" => AttachmentState(String)
|
||||
state: JsValue,
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = VeilidCore)]
|
||||
pub struct JsVeilidCore {
|
||||
core: VeilidCore,
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_class = VeilidCore)]
|
||||
impl JsVeilidCore {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
set_panic_hook();
|
||||
JsVeilidCore {
|
||||
core: VeilidCore::new(),
|
||||
}
|
||||
}
|
||||
fn value_to_string(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
Ok(Box::new(val.as_string().ok_or(())?))
|
||||
}
|
||||
fn value_to_option_string(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
if val.is_null() || val.is_undefined() {
|
||||
return Ok(Box::new(Option::<String>::None));
|
||||
}
|
||||
Ok(Box::new(Some(val.as_string().ok_or(())?)))
|
||||
}
|
||||
fn value_to_bool(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
Ok(Box::new(val.is_truthy()))
|
||||
}
|
||||
fn value_to_u8(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
Ok(Box::new(f64_try_to_unsigned::<u8>(
|
||||
val.as_f64().ok_or(())?,
|
||||
)?))
|
||||
}
|
||||
fn value_to_u32(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
Ok(Box::new(f64_try_to_unsigned::<u32>(
|
||||
val.as_f64().ok_or(())?,
|
||||
)?))
|
||||
}
|
||||
fn value_to_u64(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
Ok(Box::new(f64_try_to_unsigned::<u64>(
|
||||
val.as_f64().ok_or(())?,
|
||||
)?))
|
||||
}
|
||||
fn value_to_option_u64(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
if val.is_null() || val.is_undefined() {
|
||||
return Ok(Box::new(Option::<u64>::None));
|
||||
}
|
||||
|
||||
Ok(Box::new(Some(f64_try_to_unsigned::<u64>(
|
||||
val.as_f64().ok_or(())?,
|
||||
)?)))
|
||||
}
|
||||
fn value_to_dht_key(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
Ok(Box::new(
|
||||
DHTKey::try_decode(val.as_string().ok_or(())?.as_str()).map_err(drop)?,
|
||||
))
|
||||
}
|
||||
fn value_to_dht_key_secret(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
Ok(Box::new(
|
||||
DHTKeySecret::try_decode(val.as_string().ok_or(())?.as_str()).map_err(drop)?,
|
||||
))
|
||||
}
|
||||
fn value_to_vec_string(val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
let arrval = val.dyn_into::<Array>().map_err(drop)?.to_vec();
|
||||
let mut out = Vec::<String>::with_capacity(arrval.len());
|
||||
for v in arrval {
|
||||
out.push(v.as_string().ok_or(())?);
|
||||
}
|
||||
Ok(Box::new(out))
|
||||
}
|
||||
|
||||
fn translate_config_callback(key: &str, val: JsValue) -> Result<Box<dyn core::any::Any>, ()> {
|
||||
match key {
|
||||
// xxx: lots of missing keys here
|
||||
"namespace" => Self::value_to_string(val),
|
||||
"capabilities.protocol_udp" => Self::value_to_bool(val),
|
||||
"capabilities.protocol_connect_tcp" => Self::value_to_bool(val),
|
||||
"capabilities.protocol_accept_tcp" => Self::value_to_bool(val),
|
||||
"capabilities.protocol_connect_ws" => Self::value_to_bool(val),
|
||||
"capabilities.protocol_accept_ws" => Self::value_to_bool(val),
|
||||
"capabilities.protocol_connect_wss" => Self::value_to_bool(val),
|
||||
"capabilities.protocol_accept_wss" => Self::value_to_bool(val),
|
||||
"tablestore.directory" => Self::value_to_string(val),
|
||||
"network.max_connections" => Self::value_to_u32(val),
|
||||
"network.node_id" => Self::value_to_dht_key(val),
|
||||
"network.node_id_secret" => Self::value_to_dht_key_secret(val),
|
||||
"network.bootstrap" => Self::value_to_vec_string(val),
|
||||
"network.rpc.concurrency" => Self::value_to_u32(val),
|
||||
"network.rpc.queue_size" => Self::value_to_u32(val),
|
||||
"network.rpc.max_timestamp_behind" => Self::value_to_option_u64(val),
|
||||
"network.rpc.max_timestamp_ahead" => Self::value_to_option_u64(val),
|
||||
"network.rpc.timeout" => Self::value_to_u64(val),
|
||||
"network.rpc.max_route_hop_count" => Self::value_to_u8(val),
|
||||
"network.dht.resolve_node_timeout" => Self::value_to_option_u64(val),
|
||||
"network.dht.resolve_node_count" => Self::value_to_u32(val),
|
||||
"network.dht.resolve_node_fanout" => Self::value_to_u32(val),
|
||||
"network.dht.max_find_node_count" => Self::value_to_u32(val),
|
||||
"network.dht.get_value_timeout" => Self::value_to_option_u64(val),
|
||||
"network.dht.get_value_count" => Self::value_to_u32(val),
|
||||
"network.dht.get_value_fanout" => Self::value_to_u32(val),
|
||||
"network.dht.set_value_timeout" => Self::value_to_option_u64(val),
|
||||
"network.dht.set_value_count" => Self::value_to_u32(val),
|
||||
"network.dht.set_value_fanout" => Self::value_to_u32(val),
|
||||
"network.dht.min_peer_count" => Self::value_to_u32(val),
|
||||
"network.dht.min_peer_refresh_time" => Self::value_to_u64(val),
|
||||
"network.dht.validate_dial_info_receipt_time" => Self::value_to_u64(val),
|
||||
"network.upnp" => Self::value_to_bool(val),
|
||||
"network.natpmp" => Self::value_to_bool(val),
|
||||
"network.address_filter" => Self::value_to_bool(val),
|
||||
"network.tls.certificate_path" => Self::value_to_string(val),
|
||||
"network.tls.private_key_path" => Self::value_to_string(val),
|
||||
"network.application.path" => Self::value_to_string(val),
|
||||
"network.application.https.enabled" => Self::value_to_bool(val),
|
||||
"network.application.https.listen_address" => Self::value_to_string(val),
|
||||
"network.application.http.enabled" => Self::value_to_bool(val),
|
||||
"network.application.http.listen_address" => Self::value_to_string(val),
|
||||
"network.protocol.udp.enabled" => Self::value_to_bool(val),
|
||||
"network.protocol.udp.socket_pool_size" => Self::value_to_u32(val),
|
||||
"network.protocol.udp.listen_address" => Self::value_to_string(val),
|
||||
"network.protocol.udp.public_address" => Self::value_to_option_string(val),
|
||||
"network.protocol.tcp.connect" => Self::value_to_bool(val),
|
||||
"network.protocol.tcp.listen" => Self::value_to_bool(val),
|
||||
"network.protocol.tcp.max_connections" => Self::value_to_u32(val),
|
||||
"network.protocol.tcp.listen_address" => Self::value_to_string(val),
|
||||
"network.protocol.tcp.public_address" => Self::value_to_option_string(val),
|
||||
"network.protocol.ws.connect" => Self::value_to_bool(val),
|
||||
"network.protocol.ws.listen" => Self::value_to_bool(val),
|
||||
"network.protocol.ws.max_connections" => Self::value_to_u32(val),
|
||||
"network.protocol.ws.listen_address" => Self::value_to_string(val),
|
||||
"network.protocol.ws.path" => Self::value_to_string(val),
|
||||
"network.protocol.ws.public_address" => Self::value_to_option_string(val),
|
||||
"network.protocol.wss.connect" => Self::value_to_bool(val),
|
||||
"network.protocol.wss.listen" => Self::value_to_bool(val),
|
||||
"network.protocol.wss.max_connections" => Self::value_to_u32(val),
|
||||
"network.protocol.wss.listen_address" => Self::value_to_string(val),
|
||||
"network.protocol.wss.path" => Self::value_to_string(val),
|
||||
"network.protocol.wss.public_address" => Self::value_to_option_string(val),
|
||||
_ => return Err(()),
|
||||
}
|
||||
}
|
||||
fn translate_veilid_state(state: JsVeilidState) -> Result<VeilidState, JsValue> {
|
||||
Ok(match state.kind.as_str() {
|
||||
"attachment" => {
|
||||
let state_string = state
|
||||
.state
|
||||
.as_string()
|
||||
.ok_or(JsValue::from_str("state should be a string"))?;
|
||||
let astate = AttachmentState::try_from(state_string)
|
||||
.map_err(|e| JsValue::from_str(format!("invalid state: {:?}", e).as_str()))?;
|
||||
VeilidState::Attachment(astate)
|
||||
}
|
||||
_ => return Err(JsValue::from_str("unknown state kind")),
|
||||
})
|
||||
}
|
||||
// xxx rework this for new veilid_api mechanism which should be its own js object now
|
||||
pub fn startup(
|
||||
&self,
|
||||
js_state_change_callback: Function,
|
||||
js_config_callback: Function,
|
||||
) -> Promise {
|
||||
let core = self.core.clone();
|
||||
future_to_promise(async move {
|
||||
let vcs = VeilidCoreSetup {
|
||||
state_change_callback: Arc::new(
|
||||
move |change: VeilidStateChange| -> SystemPinBoxFuture<()> {
|
||||
let js_state_change_callback = js_state_change_callback.clone();
|
||||
Box::pin(async move {
|
||||
let js_change = match change {
|
||||
VeilidStateChange::Attachment {
|
||||
old_state,
|
||||
new_state,
|
||||
} => JsVeilidStateChange {
|
||||
kind: "attachment".to_owned(),
|
||||
from: JsValue::from_str(old_state.to_string().as_str()),
|
||||
to: JsValue::from_str(new_state.to_string().as_str()),
|
||||
},
|
||||
};
|
||||
|
||||
let ret = match Function::call1(
|
||||
&js_state_change_callback,
|
||||
&JsValue::UNDEFINED,
|
||||
&JsValue::from(js_change),
|
||||
) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("calling state change callback failed: {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let retp: Promise = match ret.dyn_into() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!(
|
||||
"state change callback did not return a promise: {:?}",
|
||||
e
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
match JsFuture::from(retp).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("state change callback returned an error: {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
})
|
||||
},
|
||||
),
|
||||
config_callback: Arc::new(
|
||||
move |key: String| -> Result<Box<dyn core::any::Any>, String> {
|
||||
let val = Function::call1(
|
||||
&js_config_callback,
|
||||
&JsValue::UNDEFINED,
|
||||
&JsValue::from_str(key.as_str()),
|
||||
)
|
||||
.map_err(|_| {
|
||||
format!("Failed to get config from callback for key '{}'", key)
|
||||
})?;
|
||||
|
||||
Self::translate_config_callback(key.as_str(), val)
|
||||
.map_err(|_| format!("invalid value type for config key '{}'", key))
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
match core.startup(vcs).await {
|
||||
Ok(_) => Ok(JsValue::UNDEFINED),
|
||||
Err(e) => Err(JsValue::from_str(
|
||||
format!("VeilidCore startup() failed: {}", e.to_string()).as_str(),
|
||||
)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn send_state_update(&self) {
|
||||
self.core.send_state_update();
|
||||
}
|
||||
|
||||
pub fn shutdown(&self) -> Promise {
|
||||
let core = self.core.clone();
|
||||
future_to_promise(async move {
|
||||
core.shutdown().await;
|
||||
Ok(JsValue::UNDEFINED)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn attach(&self) -> Promise {
|
||||
let core = self.core.clone();
|
||||
future_to_promise(async move {
|
||||
core.attach();
|
||||
Ok(JsValue::UNDEFINED)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn detach(&self) -> Promise {
|
||||
let core = self.core.clone();
|
||||
future_to_promise(async move {
|
||||
core.detach();
|
||||
Ok(JsValue::UNDEFINED)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn wait_for_state(&self, state: JsVeilidState) -> Promise {
|
||||
let core = self.core.clone();
|
||||
future_to_promise(async move {
|
||||
let state = Self::translate_veilid_state(state)?;
|
||||
core.wait_for_state(state).await;
|
||||
Ok(JsValue::UNDEFINED)
|
||||
})
|
||||
}
|
||||
}
|
25
veilid-wasm/src/lib.rs
Normal file
25
veilid-wasm/src/lib.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
pub use log::*;
|
||||
pub use wasm_bindgen::prelude::*;
|
||||
pub use wasm_bindgen::JsCast;
|
||||
|
||||
pub use alloc::boxed::Box;
|
||||
pub use alloc::string::String;
|
||||
pub use alloc::sync::Arc;
|
||||
pub use alloc::vec::Vec;
|
||||
pub use core::convert::TryFrom;
|
||||
pub use js_sys::*;
|
||||
pub use js_veilid_core::*;
|
||||
pub use utils::*;
|
||||
pub use veilid_core::dht::key::*;
|
||||
pub use veilid_core::xx::*;
|
||||
pub use veilid_core::*;
|
||||
pub use wasm_logger::*;
|
||||
|
||||
mod js_veilid_core;
|
||||
mod utils;
|
38
veilid-wasm/src/utils.rs
Normal file
38
veilid-wasm/src/utils.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
use cfg_if::*;
|
||||
use wasm_bindgen::prelude::*;
|
||||
//use wasm_bindgen_futures::*;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "wee_alloc")] {
|
||||
// When the `wee_alloc` feature is enabled, use `wee_alloc` as the global
|
||||
// allocator.
|
||||
extern crate wee_alloc;
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console, js_name = log)]
|
||||
pub fn console_log(s: &str);
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn alert(s: &str);
|
||||
}
|
||||
|
||||
pub fn set_panic_hook() {
|
||||
#[cfg(feature = "console_error_panic_hook")]
|
||||
console_error_panic_hook::set_once();
|
||||
}
|
||||
|
||||
pub fn f64_try_to_unsigned<T>(f: f64) -> Result<T,()>
|
||||
where T: core::convert::TryFrom<u64>
|
||||
{
|
||||
let rf = f.floor();
|
||||
if rf < 0.0 {
|
||||
return Err(());
|
||||
}
|
||||
T::try_from(rf as u64).map_err(drop)
|
||||
}
|
178
veilid-wasm/tests/web.rs
Normal file
178
veilid-wasm/tests/web.rs
Normal file
@@ -0,0 +1,178 @@
|
||||
//! Test suite for the Web and headless browsers.
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate wasm_bindgen_test;
|
||||
use core::sync::atomic::AtomicBool;
|
||||
use veilid_wasm::*;
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
static SETUP_ONCE: AtomicBool = AtomicBool::new(false);
|
||||
pub fn setup() -> () {
|
||||
if SETUP_ONCE
|
||||
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
|
||||
.is_ok()
|
||||
{
|
||||
console_log("setup()");
|
||||
console_error_panic_hook::set_once();
|
||||
wasm_logger::init(wasm_logger::Config::new(Level::Trace));
|
||||
init_callbacks();
|
||||
}
|
||||
}
|
||||
// xxx needs updating to new keys and veilid_api object
|
||||
fn init_callbacks() {
|
||||
assert_eq!(js_sys::eval(r#"
|
||||
window.sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) };
|
||||
window.stateChangeCallback = async (stateChange) => { console.log("State change: " + stateChange); };
|
||||
window.configCallback = (configKey) => {
|
||||
switch(configKey) {
|
||||
case "namespace": return "";
|
||||
case "capabilities.protocol_udp": return false;
|
||||
case "capabilities.protocol_connect_tcp": return false;
|
||||
case "capabilities.protocol_accept_tcp": return false;
|
||||
case "capabilities.protocol_connect_ws": return true;
|
||||
case "capabilities.protocol_accept_ws": return false;
|
||||
case "capabilities.protocol_connect_wss": return true;
|
||||
case "capabilities.protocol_accept_wss": return false;
|
||||
case "tablestore.directory": return "";
|
||||
case "network.max_connections": return 16;
|
||||
case "network.node_id": return "ZLd4uMYdP4qYLtxF6GqrzBb32Z6T3rE2FWMkWup1pdY";
|
||||
case "network.node_id_secret": return "s2Gvq6HJOxgQh-3xIgfWSL3I-DWZ2c1RjZLJl2Xmg2E";
|
||||
case "network.bootstrap": return [];
|
||||
case "network.rpc.concurrency": return 2;
|
||||
case "network.rpc.queue_size": return 128;
|
||||
case "network.rpc.max_timestamp_behind": return 10000000;
|
||||
case "network.rpc.max_timestamp_ahead": return 10000000;
|
||||
case "network.rpc.timeout": return 10000000;
|
||||
case "network.rpc.max_route_hop_count": return 7;
|
||||
case "network.dht.resolve_node_timeout": return null;
|
||||
case "network.dht.resolve_node_count": return 20;
|
||||
case "network.dht.resolve_node_fanout": return 3;
|
||||
case "network.dht.max_find_node_count": return 20;
|
||||
case "network.dht.get_value_timeout": return null;
|
||||
case "network.dht.get_value_count": return 20;
|
||||
case "network.dht.get_value_fanout": return 3;
|
||||
case "network.dht.set_value_timeout": return null;
|
||||
case "network.dht.set_value_count": return 20;
|
||||
case "network.dht.set_value_fanout": return 5;
|
||||
case "network.dht.min_peer_count": return 20;
|
||||
case "network.dht.min_peer_refresh_time": return 2000000;
|
||||
case "network.dht.validate_dial_info_receipt_time": return 5000000;
|
||||
case "network.upnp": return false;
|
||||
case "network.natpmp": return false;
|
||||
case "network.address_filter": return true;
|
||||
case "network.tls.certificate_path": return "";
|
||||
case "network.tls.private_key_path": return "";
|
||||
case "network.application.path": return "/app";
|
||||
case "network.application.https.enabled": return false;
|
||||
case "network.application.https.listen_address": return "";
|
||||
case "network.application.http.enabled": return false;
|
||||
case "network.application.http.listen_address": return "";
|
||||
case "network.protocol.udp.enabled": return false;
|
||||
case "network.protocol.udp.socket_pool_size": return 0;
|
||||
case "network.protocol.udp.listen_address": return "";
|
||||
case "network.protocol.udp.public_address": return "";
|
||||
case "network.protocol.tcp.connect": return false;
|
||||
case "network.protocol.tcp.listen": return false;
|
||||
case "network.protocol.tcp.max_connections": return 32;
|
||||
case "network.protocol.tcp.listen_address": return "";
|
||||
case "network.protocol.tcp.public_address": return "";
|
||||
case "network.protocol.ws.connect": return true;
|
||||
case "network.protocol.ws.listen": return false;
|
||||
case "network.protocol.ws.max_connections": return 16;
|
||||
case "network.protocol.ws.listen_address": return "";
|
||||
case "network.protocol.ws.path": return "/ws";
|
||||
case "network.protocol.ws.public_address": return "";
|
||||
case "network.protocol.wss.connect": return true;
|
||||
case "network.protocol.wss.listen": return false;
|
||||
case "network.protocol.wss.max_connections": return 16;
|
||||
case "network.protocol.wss.listen_address": return "";
|
||||
case "network.protocol.wss.path": return "/ws";
|
||||
case "network.protocol.wss.public_address": return "";
|
||||
default:
|
||||
console.log("config key '" + key +"' doesn't exist"); break;
|
||||
}
|
||||
};
|
||||
true
|
||||
"#).expect("failed to eval"), JsValue::TRUE);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_construct() {
|
||||
setup();
|
||||
|
||||
assert_eq!(
|
||||
js_sys::eval(
|
||||
r#"
|
||||
let vc = new VeilidCore();
|
||||
true
|
||||
"#
|
||||
)
|
||||
.expect("failed to eval"),
|
||||
JsValue::TRUE
|
||||
);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test(async)]
|
||||
async fn test_startup_shutdown() {
|
||||
setup();
|
||||
|
||||
assert_eq!(
|
||||
JsFuture::from(
|
||||
js_sys::eval(
|
||||
r#"
|
||||
(async function() {
|
||||
let vc = new VeilidCore();
|
||||
await vc.startup(window.stateChangeCallback, window.configCallback);
|
||||
await vc.shutdown();
|
||||
return true;
|
||||
})().then(v => {
|
||||
console.log("finished: " + v);
|
||||
return v;
|
||||
});
|
||||
"#
|
||||
)
|
||||
.expect("failed to eval")
|
||||
.dyn_into::<Promise>()
|
||||
.unwrap()
|
||||
)
|
||||
.await,
|
||||
Ok(JsValue::TRUE)
|
||||
);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test(async)]
|
||||
async fn test_attach_detach() {
|
||||
setup();
|
||||
|
||||
assert_eq!(
|
||||
JsFuture::from(
|
||||
js_sys::eval(
|
||||
r#"
|
||||
(async function() {
|
||||
let vc = new VeilidCore();
|
||||
await vc.startup(window.stateChangeCallback, window.configCallback);
|
||||
await vc.attach();
|
||||
await window.sleep(1000);
|
||||
await vc.detach();
|
||||
await vc.shutdown();
|
||||
return true;
|
||||
})().then(v => {
|
||||
console.log("finished: " + v);
|
||||
return v;
|
||||
});
|
||||
"#
|
||||
)
|
||||
.expect("failed to eval")
|
||||
.dyn_into::<Promise>()
|
||||
.unwrap()
|
||||
)
|
||||
.await,
|
||||
Ok(JsValue::TRUE)
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user