Merge branch 'main' into add-contributor-docs

This commit is contained in:
TC Johnson 2023-08-01 13:46:58 -05:00
commit 035a650159
55 changed files with 1985 additions and 1983 deletions

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.1.4 current_version = 0.1.7
[bumpversion:file:veilid-server/Cargo.toml] [bumpversion:file:veilid-server/Cargo.toml]
search = name = "veilid-server" search = name = "veilid-server"

View File

@ -7,75 +7,153 @@ variables:
stages: stages:
- test - test
- build_packages - build_packages
- release
- distribute - distribute
#before_script: #before_script:
# - earthly bootstrap # - earthly bootstrap
create_test_machine:
stage: test
only:
- main
- merge_requests
tags:
- build-orchestration
script:
- /home/gitlab-runner/build-machine-ctl.sh create amd64-deb
when: manual
test_amd64: test_amd64:
stage: test stage: test
image: earthly/earthly:v0.6.30 image: earthly/earthly:v0.6.30
only: only:
- main - main
- merge_requests - merge_requests
needs:
- create_test_machine
tags: tags:
- build-server - earthly-tests
script: script:
- earthly bootstrap - earthly bootstrap
- earthly --ci +unit-tests-linux-amd64 - earthly --ci +unit-tests-linux-amd64
when: manual
delete_test_machine:
stage: test
only:
- main
- merge_requests
needs:
- test_amd64
tags:
- build-orchestration
script:
- /home/gitlab-runner/build-machine-ctl.sh delete amd64-deb
release_job:
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
script:
- echo "running release_job"
release: # See https://docs.gitlab.com/ee/ci/yaml/#release for available properties
tag_name: '$CI_COMMIT_TAG'
description: '$CI_COMMIT_TAG'
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
create_build_machines:
stage: build_packages
tags:
- build-orchestration
script:
- /home/gitlab-runner/build-machine-ctl.sh create amd64-deb
- /home/gitlab-runner/build-machine-ctl.sh create arm64-deb
- /home/gitlab-runner/build-machine-ctl.sh create amd64-rpm
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
package_amd64_deb: package_amd64_deb:
stage: build_packages stage: build_packages
only: needs:
- stable - create_build_machines
tags: tags:
- build-amd64-deb - build-amd64-deb
script: script:
- earthly bootstrap - earthly bootstrap
- earthly +package-linux-amd64-deb - earthly +package-linux-amd64-deb
- /home/gitlab-runner/scp-to-orchestrator.sh - /home/gitlab-runner/scp-to-orchestrator.sh
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
delete_amd64_deb_build_machine:
stage: build_packages
needs:
- package_amd64_deb
tags:
- build-orchestration
script:
- /home/gitlab-runner/build-machine-ctl.sh delete amd64-deb
package_arm64_deb: package_arm64_deb:
stage: build_packages stage: build_packages
only: needs:
- stable - create_build_machines
tags: tags:
- build-arm64-deb - build-arm64-deb
script: script:
- earthly bootstrap - earthly bootstrap
- earthly +package-linux-arm64-deb - earthly +package-linux-arm64-deb
- /home/gitlab-runner/scp-to-orchestrator.sh - /home/gitlab-runner/scp-to-orchestrator.sh
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
delete_arm64_deb_build_machine:
stage: build_packages
needs:
- package_arm64_deb
tags:
- build-orchestration
script:
- /home/gitlab-runner/build-machine-ctl.sh delete arm64-deb
package_amd64_rpm: package_amd64_rpm:
stage: build_packages stage: build_packages
only: needs:
- stable - create_build_machines
tags: tags:
- build-amd64-rpm - build-amd64-rpm
script: script:
- earthly bootstrap - earthly bootstrap
- earthly +package-linux-amd64-rpm - earthly +package-linux-amd64-rpm
- /home/gitlab-runner/scp-to-orchestrator.sh - /home/gitlab-runner/scp-to-orchestrator.sh
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
delete_amd64_rpm_build_machine:
stage: build_packages
needs:
- package_amd64_rpm
tags:
- build-orchestration
script:
- /home/gitlab-runner/build-machine-ctl.sh delete amd64-rpm
build_repositories: build_repositories:
stage: distribute stage: distribute
only:
- stable
tags: tags:
- build-orchestration - build-orchestration
script: script:
- /home/gitlab-runner/distribute-packages.sh - /home/gitlab-runner/distribute-packages.sh
rules:
- if: '$CI_COMMIT_TAG =~ /v\d.+/'
deploy_repos: deploy_repos:
stage: distribute stage: distribute
only:
- stable
needs: needs:
- build_repositories - build_repositories
tags: tags:
- repo-server - repo-server
script: script:
- /home/gitlab-runner/deploy-repo.sh - /home/gitlab-runner/deploy-repo.sh
rules:
#Note so merge works - if: '$CI_COMMIT_TAG =~ /v\d.+/'

18
CHANGELOG.md Normal file
View File

@ -0,0 +1,18 @@
**Changes in Veilid 0.1.7**
- Fix for connection table crash
- Fix for incorrect set_dht_value return value
- Python test updates
- Various VeilidChat-prompted veilid-flutter updates
**Changes in Veilid 0.1.6**
- Fix for 'find_node' too many nodes returned issue
**Changes in Veilid 0.1.5**
- Added Changelog
- Fix detachment issue with suspending network interfaces during operation
- Fix incorrect punishment on relayed undecryptable messages
- Minor API feature adds
- Relay bugfixes

232
Cargo.lock generated
View File

@ -252,7 +252,7 @@ dependencies = [
"async-lock", "async-lock",
"async-task", "async-task",
"concurrent-queue", "concurrent-queue",
"fastrand", "fastrand 1.9.0",
"futures-lite", "futures-lite",
"slab", "slab",
] ]
@ -286,7 +286,7 @@ dependencies = [
"log", "log",
"parking", "parking",
"polling", "polling",
"rustix", "rustix 0.37.23",
"slab", "slab",
"socket2 0.4.9", "socket2 0.4.9",
"waker-fn", "waker-fn",
@ -314,7 +314,7 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"event-listener", "event-listener",
"futures-lite", "futures-lite",
"rustix", "rustix 0.37.23",
"signal-hook", "signal-hook",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -381,7 +381,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -419,13 +419,13 @@ dependencies = [
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.71" version = "0.1.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -457,9 +457,9 @@ dependencies = [
[[package]] [[package]]
name = "async_executors" name = "async_executors"
version = "0.6.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b2463773401e1f684136f9cdb956cf611f22172472cf3f049e72123f59e359" checksum = "a982d2f86de6137cc05c9db9a915a19886c97911f9790d04f174cede74be01a5"
dependencies = [ dependencies = [
"async-std", "async-std",
"blanket", "blanket",
@ -694,13 +694,13 @@ dependencies = [
[[package]] [[package]]
name = "blanket" name = "blanket"
version = "0.2.0" version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b04ce3d2372d05d1ef4ea3fdf427da6ae3c17ca06d688a107b5344836276bc3" checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -753,7 +753,7 @@ dependencies = [
"async-lock", "async-lock",
"async-task", "async-task",
"atomic-waker", "atomic-waker",
"fastrand", "fastrand 1.9.0",
"futures-lite", "futures-lite",
"log", "log",
] ]
@ -1294,7 +1294,7 @@ dependencies = [
"flexi_logger", "flexi_logger",
"lazy_static", "lazy_static",
"log", "log",
"time 0.3.23", "time 0.3.24",
"unicode-width", "unicode-width",
] ]
@ -1336,7 +1336,7 @@ dependencies = [
"owning_ref", "owning_ref",
"serde_json", "serde_json",
"serde_yaml", "serde_yaml",
"time 0.3.23", "time 0.3.24",
"tokio", "tokio",
"toml 0.7.6", "toml 0.7.6",
"unicode-segmentation", "unicode-segmentation",
@ -1419,7 +1419,7 @@ dependencies = [
"ident_case", "ident_case",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -1441,7 +1441,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [ dependencies = [
"darling_core 0.20.3", "darling_core 0.20.3",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -1463,6 +1463,12 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "deranged"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8810e7e2cf385b1e9b50d68264908ec367ba642c96d02edfe61c39e88e2a3c01"
[[package]] [[package]]
name = "derivative" name = "derivative"
version = "2.2.0" version = "2.2.0"
@ -1556,9 +1562,9 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.1" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]] [[package]]
name = "enum-as-inner" name = "enum-as-inner"
@ -1589,7 +1595,7 @@ checksum = "8560b409800a72d2d7860f8e5f4e0b0bd22bea6a352ea2a9ce30ccdef7f16d2f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -1632,7 +1638,7 @@ dependencies = [
"darling 0.20.3", "darling 0.20.3",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -1676,9 +1682,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.1" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [ dependencies = [
"errno-dragonfly", "errno-dragonfly",
"libc", "libc",
@ -1764,6 +1770,12 @@ dependencies = [
"instant", "instant",
] ]
[[package]]
name = "fastrand"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
[[package]] [[package]]
name = "fdeflate" name = "fdeflate"
version = "0.3.0" version = "0.3.0"
@ -1814,7 +1826,7 @@ dependencies = [
"regex", "regex",
"rustversion", "rustversion",
"thiserror", "thiserror",
"time 0.3.23", "time 0.3.24",
] ]
[[package]] [[package]]
@ -1930,7 +1942,7 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
dependencies = [ dependencies = [
"fastrand", "fastrand 1.9.0",
"futures-core", "futures-core",
"futures-io", "futures-io",
"memchr", "memchr",
@ -1947,7 +1959,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -2752,9 +2764,9 @@ dependencies = [
[[package]] [[package]]
name = "libz-sys" name = "libz-sys"
version = "1.1.9" version = "1.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56ee889ecc9568871456d42f603d6a0ce59ff328d291063a45cbdf0036baf6db" checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -2774,6 +2786,12 @@ version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]]
name = "linux-raw-sys"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.10" version = "0.4.10"
@ -2840,9 +2858,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.7.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" checksum = "67827e6ea8ee8a7c4a72227ef4fc08957040acffdb5f122733b24fa12daff41b"
[[package]] [[package]]
name = "memchr" name = "memchr"
@ -3224,9 +3242,9 @@ dependencies = [
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.15" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [ dependencies = [
"autocfg", "autocfg",
] ]
@ -3596,7 +3614,7 @@ dependencies = [
"pest_meta", "pest_meta",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -3667,7 +3685,7 @@ checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -3846,9 +3864,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.31" version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -3979,7 +3997,7 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata 0.3.3", "regex-automata 0.3.4",
"regex-syntax 0.7.4", "regex-syntax 0.7.4",
] ]
@ -3994,9 +4012,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.3.3" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -4165,7 +4183,20 @@ dependencies = [
"errno", "errno",
"io-lifetimes", "io-lifetimes",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys 0.3.8",
"windows-sys 0.48.0",
]
[[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 0.4.3",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -4212,16 +4243,6 @@ dependencies = [
"base64 0.21.2", "base64 0.21.2",
] ]
[[package]]
name = "rustls-webpki"
version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e"
dependencies = [
"ring",
"untrusted",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.14" version = "1.0.14"
@ -4321,9 +4342,9 @@ dependencies = [
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.9.1" version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"core-foundation 0.9.3", "core-foundation 0.9.3",
@ -4334,9 +4355,9 @@ dependencies = [
[[package]] [[package]]
name = "security-framework-sys" name = "security-framework-sys"
version = "2.9.0" version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [ dependencies = [
"core-foundation-sys 0.8.4", "core-foundation-sys 0.8.4",
"libc", "libc",
@ -4380,9 +4401,9 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.173" version = "1.0.178"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91f70896d6720bc714a4a57d22fc91f1db634680e65c8efe13323f1fa38d53f" checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -4408,13 +4429,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.173" version = "1.0.178"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6250dde8342e0232232be9ca3db7aa40aceb5a3e5dd9bddbc00d99a007cde49" checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -4430,9 +4451,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.103" version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -4441,13 +4462,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_repr" name = "serde_repr"
version = "0.1.14" version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d89a8107374290037607734c0b73a85db7ed80cae314b3c5791f192a496e731" checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -4461,9 +4482,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_yaml" name = "serde_yaml"
version = "0.9.24" version = "0.9.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd5f51e3fdb5b9cdd1577e1cb7a733474191b1aca6a72c2e50913241632c1180" checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574"
dependencies = [ dependencies = [
"indexmap 2.0.0", "indexmap 2.0.0",
"itoa", "itoa",
@ -4637,9 +4658,9 @@ checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
version = "0.3.5" version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]] [[package]]
name = "simplelog" name = "simplelog"
@ -4649,7 +4670,7 @@ checksum = "acee08041c5de3d5048c8b3f6f13fafb3026b24ba43c6a695a0c76179b844369"
dependencies = [ dependencies = [
"log", "log",
"termcolor", "termcolor",
"time 0.3.23", "time 0.3.24",
] ]
[[package]] [[package]]
@ -4831,9 +4852,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.26" version = "2.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -4874,15 +4895,14 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.6.0" version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998"
dependencies = [ dependencies = [
"autocfg",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"fastrand", "fastrand 2.0.0",
"redox_syscall 0.3.5", "redox_syscall 0.3.5",
"rustix", "rustix 0.38.4",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -4912,22 +4932,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.43" version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.43" version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -4979,16 +4999,17 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.23" version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" checksum = "b79eabcd964882a646b3584543ccabeae7869e9ac32a46f6f22b7a5bd405308b"
dependencies = [ dependencies = [
"deranged",
"itoa", "itoa",
"libc", "libc",
"num_threads", "num_threads",
"serde", "serde",
"time-core", "time-core",
"time-macros 0.2.10", "time-macros 0.2.11",
] ]
[[package]] [[package]]
@ -5009,9 +5030,9 @@ dependencies = [
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.10" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
dependencies = [ dependencies = [
"time-core", "time-core",
] ]
@ -5083,7 +5104,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -5280,7 +5301,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e"
dependencies = [ dependencies = [
"crossbeam-channel", "crossbeam-channel",
"time 0.3.23", "time 0.3.24",
"tracing-subscriber", "tracing-subscriber",
] ]
@ -5292,7 +5313,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]
@ -5627,7 +5648,7 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]] [[package]]
name = "veilid-cli" name = "veilid-cli"
version = "0.1.4" version = "0.1.7"
dependencies = [ dependencies = [
"arboard", "arboard",
"async-std", "async-std",
@ -5663,7 +5684,7 @@ dependencies = [
[[package]] [[package]]
name = "veilid-core" name = "veilid-core"
version = "0.1.4" version = "0.1.7"
dependencies = [ dependencies = [
"argon2", "argon2",
"async-io", "async-io",
@ -5755,7 +5776,7 @@ dependencies = [
"weak-table", "weak-table",
"web-sys", "web-sys",
"webpki 0.22.0", "webpki 0.22.0",
"webpki-roots 0.24.0", "webpki-roots 0.25.1",
"wee_alloc", "wee_alloc",
"winapi", "winapi",
"windows 0.38.0", "windows 0.38.0",
@ -5766,7 +5787,7 @@ dependencies = [
[[package]] [[package]]
name = "veilid-flutter" name = "veilid-flutter"
version = "0.1.4" version = "0.1.7"
dependencies = [ dependencies = [
"allo-isolate", "allo-isolate",
"async-std", "async-std",
@ -5795,7 +5816,7 @@ dependencies = [
[[package]] [[package]]
name = "veilid-server" name = "veilid-server"
version = "0.1.4" version = "0.1.7"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"async-std", "async-std",
@ -5845,7 +5866,7 @@ dependencies = [
[[package]] [[package]]
name = "veilid-tools" name = "veilid-tools"
version = "0.1.4" version = "0.1.7"
dependencies = [ dependencies = [
"android-logd-logger", "android-logd-logger",
"async-lock", "async-lock",
@ -5896,7 +5917,7 @@ dependencies = [
[[package]] [[package]]
name = "veilid-wasm" name = "veilid-wasm"
version = "0.1.4" version = "0.1.7"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"console_error_panic_hook", "console_error_panic_hook",
@ -5996,7 +6017,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6030,7 +6051,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -6132,12 +6153,9 @@ dependencies = [
[[package]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "0.24.0" version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" checksum = "c9c6eda1c830a36f361e7721c87fd79ea84293b54f8c48c959f85ec636f0f196"
dependencies = [
"rustls-webpki",
]
[[package]] [[package]]
name = "wee_alloc" name = "wee_alloc"
@ -6438,9 +6456,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.0" version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" checksum = "8bd122eb777186e60c3fdf765a58ac76e41c582f1f535fbf3314434c6b58f3f7"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -6547,7 +6565,7 @@ dependencies = [
"byteorder", "byteorder",
"derivative", "derivative",
"enumflags2", "enumflags2",
"fastrand", "fastrand 1.9.0",
"futures", "futures",
"nb-connect", "nb-connect",
"nix 0.22.3", "nix 0.22.3",
@ -6589,7 +6607,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.26", "syn 2.0.27",
] ]
[[package]] [[package]]

View File

@ -115,10 +115,12 @@ build-linux-arm64:
# Unit tests # Unit tests
unit-tests-linux-amd64: unit-tests-linux-amd64:
FROM +code-linux FROM +code-linux
ENV RUST_BACKTRACE=1
RUN cargo test --target x86_64-unknown-linux-gnu --release -p veilid-server -p veilid-cli -p veilid-tools -p veilid-core RUN cargo test --target x86_64-unknown-linux-gnu --release -p veilid-server -p veilid-cli -p veilid-tools -p veilid-core
# unit-tests-linux-arm64: # unit-tests-linux-arm64:
# FROM +code-linux # FROM +code-linux
# ENV RUST_BACKTRACE=1
# RUN cargo test --target aarch64-unknown-linux-gnu --release -p veilid-server -p veilid-cli -p veilid-tools -p veilid-core # RUN cargo test --target aarch64-unknown-linux-gnu --release -p veilid-server -p veilid-cli -p veilid-tools -p veilid-core
# Package # Package

View File

@ -1,6 +1,6 @@
[package] [package]
name = "veilid-cli" name = "veilid-cli"
version = "0.1.4" version = "0.1.7"
authors = ["Veilid Team <contact@veilid.com>"] authors = ["Veilid Team <contact@veilid.com>"]
edition = "2021" edition = "2021"
license = "MPL-2.0" license = "MPL-2.0"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "veilid-core" name = "veilid-core"
version = "0.1.4" version = "0.1.7"
authors = ["Veilid Team <contact@veilid.com>"] authors = ["Veilid Team <contact@veilid.com>"]
edition = "2021" edition = "2021"
build = "build.rs" build = "build.rs"

View File

@ -330,7 +330,15 @@ impl Envelope {
self.sender_id self.sender_id
} }
pub fn get_sender_typed_id(&self) -> TypedKey {
TypedKey::new(self.crypto_kind, self.sender_id)
}
pub fn get_recipient_id(&self) -> PublicKey { pub fn get_recipient_id(&self) -> PublicKey {
self.recipient_id self.recipient_id
} }
pub fn get_recipient_typed_id(&self) -> TypedKey {
TypedKey::new(self.crypto_kind, self.recipient_id)
}
} }

View File

@ -207,6 +207,11 @@ impl Receipt {
pub fn get_sender_id(&self) -> PublicKey { pub fn get_sender_id(&self) -> PublicKey {
self.sender_id self.sender_id
} }
pub fn get_sender_typed_id(&self) -> TypedKey {
TypedKey::new(self.crypto_kind, self.sender_id)
}
pub fn get_extra_data(&self) -> &[u8] { pub fn get_extra_data(&self) -> &[u8] {
&self.extra_data &self.extra_data
} }

View File

@ -1,3 +1,4 @@
#![allow(non_camel_case_types)]
use super::*; use super::*;
use libc::{ use libc::{

View File

@ -344,9 +344,9 @@ impl NetworkInterfaces {
let mut last_interfaces = { let mut last_interfaces = {
let mut last_interfaces = BTreeMap::<String, NetworkInterface>::new(); let mut last_interfaces = BTreeMap::<String, NetworkInterface>::new();
let mut platform_support = PlatformSupport::new()?; let mut platform_support = PlatformSupport::new()?;
platform_support if let Err(e) = platform_support.get_interfaces(&mut last_interfaces).await {
.get_interfaces(&mut last_interfaces) debug!("no network interfaces are enabled: {}", e);
.await?; }
last_interfaces last_interfaces
}; };
@ -395,10 +395,16 @@ impl NetworkInterfaces {
continue; continue;
} }
if let Some(pipv4) = intf.primary_ipv4() { if let Some(pipv4) = intf.primary_ipv4() {
intf_addrs.push(pipv4); // Skip temporary addresses because they're going to change
if !pipv4.is_temporary() {
intf_addrs.push(pipv4);
}
} }
if let Some(pipv6) = intf.primary_ipv6() { if let Some(pipv6) = intf.primary_ipv6() {
intf_addrs.push(pipv6); // Skip temporary addresses because they're going to change
if !pipv6.is_temporary() {
intf_addrs.push(pipv6);
}
} }
} }

View File

@ -177,10 +177,10 @@ impl ConnectionTable {
// then drop the least recently used connection // then drop the least recently used connection
let mut out_conn = None; let mut out_conn = None;
if inner.conn_by_id[protocol_index].len() > inner.max_connections[protocol_index] { if inner.conn_by_id[protocol_index].len() > inner.max_connections[protocol_index] {
if let Some((lruk, lru_conn)) = inner.conn_by_id[protocol_index].remove_lru() { if let Some((lruk, lru_conn)) = inner.conn_by_id[protocol_index].peek_lru() {
let lruk = *lruk;
log_net!(debug "connection lru out: {:?}", lru_conn); log_net!(debug "connection lru out: {:?}", lru_conn);
out_conn = Some(lru_conn); out_conn = Some(Self::remove_connection_records(&mut *inner, lruk));
Self::remove_connection_records(&mut *inner, lruk);
} }
} }

View File

@ -954,6 +954,7 @@ impl NetworkManager {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
log_net!(debug "envelope failed to decode: {}", e); log_net!(debug "envelope failed to decode: {}", e);
// safe to punish here because relays also check here to ensure they arent forwarding things that don't decode
self.address_filter().punish_ip_addr(remote_addr); self.address_filter().punish_ip_addr(remote_addr);
return Ok(false); return Ok(false);
} }
@ -1005,12 +1006,12 @@ impl NetworkManager {
// Peek at header and see if we need to relay this // Peek at header and see if we need to relay this
// If the recipient id is not our node id, then it needs relaying // If the recipient id is not our node id, then it needs relaying
let sender_id = TypedKey::new(envelope.get_crypto_kind(), envelope.get_sender_id()); let sender_id = envelope.get_sender_typed_id();
if self.address_filter().is_node_id_punished(sender_id) { if self.address_filter().is_node_id_punished(sender_id) {
return Ok(false); return Ok(false);
} }
let recipient_id = TypedKey::new(envelope.get_crypto_kind(), envelope.get_recipient_id()); let recipient_id = envelope.get_recipient_typed_id();
if !routing_table.matches_own_node_id(&[recipient_id]) { if !routing_table.matches_own_node_id(&[recipient_id]) {
// See if the source node is allowed to resolve nodes // See if the source node is allowed to resolve nodes
// This is a costly operation, so only outbound-relay permitted // This is a costly operation, so only outbound-relay permitted
@ -1089,15 +1090,18 @@ impl NetworkManager {
) { ) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
log_net!(debug "failed to decrypt envelope body: {}",e); log_net!(debug "failed to decrypt envelope body: {}", e);
self.address_filter().punish_ip_addr(remote_addr); // Can't punish by ip address here because relaying can't decrypt envelope bodies to check
// But because the envelope was properly signed by the time it gets here, it is safe to
// punish by node id
self.address_filter().punish_node_id(sender_id);
return Ok(false); return Ok(false);
} }
}; };
// Cache the envelope information in the routing table // Cache the envelope information in the routing table
let source_noderef = match routing_table.register_node_with_existing_connection( let source_noderef = match routing_table.register_node_with_existing_connection(
TypedKey::new(envelope.get_crypto_kind(), envelope.get_sender_id()), envelope.get_sender_typed_id(),
connection_descriptor, connection_descriptor,
ts, ts,
) { ) {

View File

@ -315,7 +315,7 @@ impl NetworkConnection {
return RecvLoopAction::Finish; return RecvLoopAction::Finish;
} }
// Punish invalid messages // Punish invalid framing (tcp framing or websocket framing)
if v.is_invalid_message() { if v.is_invalid_message() {
address_filter.punish_ip_addr(peer_address.to_socket_addr().ip()); address_filter.punish_ip_addr(peer_address.to_socket_addr().ip());
return RecvLoopAction::Finish; return RecvLoopAction::Finish;

View File

@ -1054,8 +1054,8 @@ impl RoutingTableInner {
nodes.sort_by(|a, b| compare(self, a, b)); nodes.sort_by(|a, b| compare(self, a, b));
// return transformed vector for filtered+sorted nodes // return transformed vector for filtered+sorted nodes
let cnt = usize::min(node_count, nodes.len()); nodes.truncate(node_count);
let mut out = Vec::<O>::with_capacity(cnt); let mut out = Vec::<O>::with_capacity(nodes.len());
for node in nodes { for node in nodes {
let val = transform(self, node); let val = transform(self, node);
out.push(val); out.push(val);

View File

@ -81,7 +81,9 @@ pub struct RPCOperationFindNodeA {
impl RPCOperationFindNodeA { impl RPCOperationFindNodeA {
pub fn new(peers: Vec<PeerInfo>) -> Result<Self, RPCError> { pub fn new(peers: Vec<PeerInfo>) -> Result<Self, RPCError> {
if peers.len() > MAX_FIND_NODE_A_PEERS_LEN { if peers.len() > MAX_FIND_NODE_A_PEERS_LEN {
return Err(RPCError::protocol("find node peers length too long")); return Err(RPCError::protocol(
"encoded find node peers length too long",
));
} }
Ok(Self { peers }) Ok(Self { peers })
@ -106,7 +108,9 @@ impl RPCOperationFindNodeA {
let peers_reader = reader.get_peers().map_err(RPCError::protocol)?; let peers_reader = reader.get_peers().map_err(RPCError::protocol)?;
if peers_reader.len() as usize > MAX_FIND_NODE_A_PEERS_LEN { if peers_reader.len() as usize > MAX_FIND_NODE_A_PEERS_LEN {
return Err(RPCError::protocol("find node peers length too long")); return Err(RPCError::protocol(
"decoded find node peers length too long",
));
} }
let mut peers = Vec::<PeerInfo>::with_capacity( let mut peers = Vec::<PeerInfo>::with_capacity(

View File

@ -89,7 +89,9 @@ impl RPCOperationGetValueA {
descriptor: Option<SignedValueDescriptor>, descriptor: Option<SignedValueDescriptor>,
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
if peers.len() > MAX_GET_VALUE_A_PEERS_LEN { if peers.len() > MAX_GET_VALUE_A_PEERS_LEN {
return Err(RPCError::protocol("GetValueA peers length too long")); return Err(RPCError::protocol(
"encoded GetValueA peers length too long",
));
} }
Ok(Self { Ok(Self {
value, value,
@ -175,7 +177,9 @@ impl RPCOperationGetValueA {
let peers_reader = reader.get_peers().map_err(RPCError::protocol)?; let peers_reader = reader.get_peers().map_err(RPCError::protocol)?;
if peers_reader.len() as usize > MAX_GET_VALUE_A_PEERS_LEN { if peers_reader.len() as usize > MAX_GET_VALUE_A_PEERS_LEN {
return Err(RPCError::protocol("GetValueA peers length too long")); return Err(RPCError::protocol(
"decoded GetValueA peers length too long",
));
} }
let mut peers = Vec::<PeerInfo>::with_capacity( let mut peers = Vec::<PeerInfo>::with_capacity(
peers_reader peers_reader

View File

@ -123,7 +123,9 @@ impl RPCOperationSetValueA {
peers: Vec<PeerInfo>, peers: Vec<PeerInfo>,
) -> Result<Self, RPCError> { ) -> Result<Self, RPCError> {
if peers.len() as usize > MAX_SET_VALUE_A_PEERS_LEN { if peers.len() as usize > MAX_SET_VALUE_A_PEERS_LEN {
return Err(RPCError::protocol("SetValueA peers length too long")); return Err(RPCError::protocol(
"encoded SetValueA peers length too long",
));
} }
Ok(Self { set, value, peers }) Ok(Self { set, value, peers })
} }
@ -182,7 +184,9 @@ impl RPCOperationSetValueA {
}; };
let peers_reader = reader.get_peers().map_err(RPCError::protocol)?; let peers_reader = reader.get_peers().map_err(RPCError::protocol)?;
if peers_reader.len() as usize > MAX_SET_VALUE_A_PEERS_LEN { if peers_reader.len() as usize > MAX_SET_VALUE_A_PEERS_LEN {
return Err(RPCError::protocol("SetValueA peers length too long")); return Err(RPCError::protocol(
"decoded SetValueA peers length too long",
));
} }
let mut peers = Vec::<PeerInfo>::with_capacity( let mut peers = Vec::<PeerInfo>::with_capacity(
peers_reader peers_reader

View File

@ -319,10 +319,7 @@ impl RPCProcessor {
}; };
// Reply directly to the request's source // Reply directly to the request's source
let sender_node_id = TypedKey::new( let sender_node_id = detail.envelope.get_sender_typed_id();
detail.envelope.get_crypto_kind(),
detail.envelope.get_sender_id(),
);
// This may be a different node's reference than the 'sender' in the case of a relay // This may be a different node's reference than the 'sender' in the case of a relay
let peer_noderef = detail.peer_noderef.clone(); let peer_noderef = detail.peer_noderef.clone();

View File

@ -126,17 +126,9 @@ impl RPCMessageHeader {
} }
pub fn direct_sender_node_id(&self) -> TypedKey { pub fn direct_sender_node_id(&self) -> TypedKey {
match &self.detail { match &self.detail {
RPCMessageHeaderDetail::Direct(d) => { RPCMessageHeaderDetail::Direct(d) => d.envelope.get_sender_typed_id(),
TypedKey::new(d.envelope.get_crypto_kind(), d.envelope.get_sender_id()) RPCMessageHeaderDetail::SafetyRouted(s) => s.direct.envelope.get_sender_typed_id(),
} RPCMessageHeaderDetail::PrivateRouted(p) => p.direct.envelope.get_sender_typed_id(),
RPCMessageHeaderDetail::SafetyRouted(s) => TypedKey::new(
s.direct.envelope.get_crypto_kind(),
s.direct.envelope.get_sender_id(),
),
RPCMessageHeaderDetail::PrivateRouted(p) => TypedKey::new(
p.direct.envelope.get_crypto_kind(),
p.direct.envelope.get_sender_id(),
),
} }
} }
} }
@ -1464,10 +1456,7 @@ impl RPCProcessor {
let msg = match &encoded_msg.header.detail { let msg = match &encoded_msg.header.detail {
RPCMessageHeaderDetail::Direct(detail) => { RPCMessageHeaderDetail::Direct(detail) => {
// Get sender node id // Get sender node id
let sender_node_id = TypedKey::new( let sender_node_id = detail.envelope.get_sender_typed_id();
detail.envelope.get_crypto_kind(),
detail.envelope.get_sender_id(),
);
// Decode and validate the RPC operation // Decode and validate the RPC operation
let operation = match self.decode_rpc_operation(&encoded_msg) { let operation = match self.decode_rpc_operation(&encoded_msg) {
@ -1689,7 +1678,10 @@ impl RPCProcessor {
let send_channel = { let send_channel = {
let inner = self.inner.lock(); let inner = self.inner.lock();
inner.send_channel.as_ref().unwrap().clone() let Some(send_channel) = inner.send_channel.as_ref().cloned() else {
bail!("send channel is closed");
};
send_channel
}; };
let span_id = Span::current().id(); let span_id = Span::current().id();
send_channel send_channel
@ -1725,7 +1717,10 @@ impl RPCProcessor {
}; };
let send_channel = { let send_channel = {
let inner = self.inner.lock(); let inner = self.inner.lock();
inner.send_channel.as_ref().unwrap().clone() let Some(send_channel) = inner.send_channel.as_ref().cloned() else {
bail!("send channel is closed");
};
send_channel
}; };
let span_id = Span::current().id(); let span_id = Span::current().id();
send_channel send_channel
@ -1764,7 +1759,10 @@ impl RPCProcessor {
let send_channel = { let send_channel = {
let inner = self.inner.lock(); let inner = self.inner.lock();
inner.send_channel.as_ref().unwrap().clone() let Some(send_channel) = inner.send_channel.as_ref().cloned() else {
bail!("send channel is closed");
};
send_channel
}; };
let span_id = Span::current().id(); let span_id = Span::current().id();
send_channel send_channel

View File

@ -104,10 +104,7 @@ impl RPCProcessor {
// We filter on the -outgoing- protocol capability status not the node's dial info // We filter on the -outgoing- protocol capability status not the node's dial info
// Use the address type though, to ensure we reach an ipv6 capable node if this is // Use the address type though, to ensure we reach an ipv6 capable node if this is
// an ipv6 address // an ipv6 address
let sender_node_id = TypedKey::new( let sender_node_id = detail.envelope.get_sender_typed_id();
detail.envelope.get_crypto_kind(),
detail.envelope.get_sender_id(),
);
let routing_domain = detail.routing_domain; let routing_domain = detail.routing_domain;
let node_count = { let node_count = {
let c = self.config.get(); let c = self.config.get();

View File

@ -347,8 +347,9 @@ impl StorageManager {
if last_signed_value_data.value_data().data() == &data if last_signed_value_data.value_data().data() == &data
&& last_signed_value_data.value_data().writer() == &writer.key && last_signed_value_data.value_data().writer() == &writer.key
{ {
// Data and writer is the name, nothing is changing, just return the same ValueData // Data and writer is the same, nothing is changing,
return Ok(Some(last_signed_value_data.into_value_data())); // just return that we set it, but no network activity needs to happen
return Ok(None);
} }
let seq = last_signed_value_data.value_data().seq(); let seq = last_signed_value_data.value_data().seq();
ValueData::new_with_seq(seq + 1, data, writer.key) ValueData::new_with_seq(seq + 1, data, writer.key)
@ -380,7 +381,7 @@ impl StorageManager {
// Add to offline writes to flush // Add to offline writes to flush
inner.offline_subkey_writes.entry(key).and_modify(|x| { x.insert(subkey); } ).or_insert(ValueSubkeyRangeSet::single(subkey)); inner.offline_subkey_writes.entry(key).and_modify(|x| { x.insert(subkey); } ).or_insert(ValueSubkeyRangeSet::single(subkey));
return Ok(Some(signed_value_data.into_value_data())) return Ok(None)
}; };
// Drop the lock for network access // Drop the lock for network access
@ -393,7 +394,7 @@ impl StorageManager {
key, key,
subkey, subkey,
safety_selection, safety_selection,
signed_value_data, signed_value_data.clone(),
descriptor, descriptor,
) )
.await?; .await?;
@ -404,7 +405,13 @@ impl StorageManager {
.handle_set_local_value(key, subkey, final_signed_value_data.clone()) .handle_set_local_value(key, subkey, final_signed_value_data.clone())
.await?; .await?;
Ok(Some(final_signed_value_data.into_value_data())) // Return the new value if it differs from what was asked to set
if final_signed_value_data.value_data() != signed_value_data.value_data() {
return Ok(Some(final_signed_value_data.into_value_data()));
}
// If the original value was set, return None
Ok(None)
} }
pub async fn watch_values( pub async fn watch_values(

View File

@ -0,0 +1 @@
Ray says "Go SubSix!"

View File

@ -96,7 +96,7 @@ impl DHTSchemaSMPL {
impl TryFrom<&[u8]> for DHTSchemaSMPL { impl TryFrom<&[u8]> for DHTSchemaSMPL {
type Error = VeilidAPIError; type Error = VeilidAPIError;
fn try_from(b: &[u8]) -> Result<Self, Self::Error> { fn try_from(b: &[u8]) -> Result<Self, Self::Error> {
if b.len() != Self::FIXED_SIZE { if b.len() < Self::FIXED_SIZE {
apibail_generic!("invalid size"); apibail_generic!("invalid size");
} }
if &b[0..4] != &Self::FCC { if &b[0..4] != &Self::FCC {

View File

@ -1,5 +1,11 @@
include: package:flutter_lints/flutter.yaml include: package:lint_hard/all.yaml
analyzer: analyzer:
errors: errors:
invalid_annotation_target: ignore invalid_annotation_target: ignore
exclude:
- '**/*.g.dart'
- '**/*.freezed.dart'
linter:
rules:
avoid_positional_boolean_parameters: false

View File

@ -3,3 +3,7 @@ include: package:flutter_lints/flutter.yaml
analyzer: analyzer:
errors: errors:
invalid_annotation_target: ignore invalid_annotation_target: ignore
linter:
rules:
- unawaited_futures

View File

@ -357,6 +357,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "3.0.2"
system_info_plus:
dependency: transitive
description:
name: system_info_plus
sha256: b915c811c6605b802f3988859bc2bb79c95f735762a75b5451741f7a2b949d1b
url: "https://pub.dev"
source: hosted
version: "0.0.5"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -395,7 +403,7 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "0.1.1" version: "0.1.6"
win32: win32:
dependency: transitive dependency: transitive
description: description:

View File

@ -1,7 +1,11 @@
import 'dart:io';
import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:system_info2/system_info2.dart' as sysinfo; import 'package:system_info2/system_info2.dart' as sysinfo;
import 'package:system_info_plus/system_info_plus.dart';
import 'veilid.dart'; import 'veilid.dart';
const int megaByte = 1024 * 1024; const int megaByte = 1024 * 1024;
@ -13,10 +17,13 @@ int getLocalSubkeyCacheSize() {
return 1024; return 1024;
} }
int getLocalMaxSubkeyCacheMemoryMb() { Future<int> getLocalMaxSubkeyCacheMemoryMb() async {
if (kIsWeb) { if (kIsWeb) {
return 256; return 256;
} }
if (Platform.isIOS || Platform.isAndroid) {
return (await SystemInfoPlus.physicalMemory ?? 2048) ~/ 32;
}
return sysinfo.SysInfo.getTotalPhysicalMemory() ~/ 32 ~/ megaByte; return sysinfo.SysInfo.getTotalPhysicalMemory() ~/ 32 ~/ megaByte;
} }
@ -34,10 +41,13 @@ int getRemoteMaxRecords() {
return 128; return 128;
} }
int getRemoteMaxSubkeyCacheMemoryMb() { Future<int> getRemoteMaxSubkeyCacheMemoryMb() async {
if (kIsWeb) { if (kIsWeb) {
return 256; return 256;
} }
if (Platform.isIOS || Platform.isAndroid) {
return (await SystemInfoPlus.physicalMemory ?? 2048) ~/ 32;
}
return sysinfo.SysInfo.getTotalPhysicalMemory() ~/ 32 ~/ megaByte; return sysinfo.SysInfo.getTotalPhysicalMemory() ~/ 32 ~/ megaByte;
} }
@ -48,136 +58,129 @@ int getRemoteMaxStorageSpaceMb() {
return 256; return 256;
} }
Future<VeilidConfig> getDefaultVeilidConfig(String programName) async { Future<VeilidConfig> getDefaultVeilidConfig(String programName) async =>
return VeilidConfig( VeilidConfig(
programName: programName, programName: programName,
namespace: "", namespace: '',
capabilities: const VeilidConfigCapabilities(disable: []), capabilities: const VeilidConfigCapabilities(disable: []),
protectedStore: const VeilidConfigProtectedStore( protectedStore: const VeilidConfigProtectedStore(
allowInsecureFallback: false, allowInsecureFallback: false,
alwaysUseInsecureStorage: false, alwaysUseInsecureStorage: false,
directory: "", directory: '',
delete: false, delete: false,
deviceEncryptionKeyPassword: "", deviceEncryptionKeyPassword: '',
newDeviceEncryptionKeyPassword: null,
),
tableStore: VeilidConfigTableStore(
directory: kIsWeb
? ""
: p.join((await getApplicationSupportDirectory()).absolute.path,
"table_store"),
delete: false,
),
blockStore: VeilidConfigBlockStore(
directory: kIsWeb
? ""
: p.join((await getApplicationSupportDirectory()).absolute.path,
"block_store"),
delete: false,
),
network: VeilidConfigNetwork(
connectionInitialTimeoutMs: 2000,
connectionInactivityTimeoutMs: 60000,
maxConnectionsPerIp4: 32,
maxConnectionsPerIp6Prefix: 32,
maxConnectionsPerIp6PrefixSize: 56,
maxConnectionFrequencyPerMin: 128,
clientWhitelistTimeoutMs: 300000,
reverseConnectionReceiptTimeMs: 5000,
holePunchReceiptTimeMs: 5000,
routingTable: const VeilidConfigRoutingTable(
nodeId: [],
nodeIdSecret: [],
bootstrap: kIsWeb
? ["ws://bootstrap.veilid.net:5150/ws"]
: ["bootstrap.veilid.net"],
limitOverAttached: 64,
limitFullyAttached: 32,
limitAttachedStrong: 16,
limitAttachedGood: 8,
limitAttachedWeak: 4,
), ),
rpc: const VeilidConfigRPC( tableStore: VeilidConfigTableStore(
concurrency: 0, directory: kIsWeb
queueSize: 1024, ? ''
maxTimestampBehindMs: 10000, : p.join((await getApplicationSupportDirectory()).absolute.path,
maxTimestampAheadMs: 10000, 'table_store'),
timeoutMs: 5000, delete: false,
maxRouteHopCount: 4,
defaultRouteHopCount: 1,
), ),
dht: VeilidConfigDHT( blockStore: VeilidConfigBlockStore(
resolveNodeTimeoutMs: 10000, directory: kIsWeb
resolveNodeCount: 20, ? ''
resolveNodeFanout: 3, : p.join((await getApplicationSupportDirectory()).absolute.path,
maxFindNodeCount: 20, 'block_store'),
getValueTimeoutMs: 10000, delete: false,
getValueCount: 20, ),
getValueFanout: 3, network: VeilidConfigNetwork(
setValueTimeoutMs: 10000,
setValueCount: 20,
setValueFanout: 5,
minPeerCount: 20,
minPeerRefreshTimeMs: 60000,
validateDialInfoReceiptTimeMs: 2000,
localSubkeyCacheSize: getLocalSubkeyCacheSize(),
localMaxSubkeyCacheMemoryMb: getLocalMaxSubkeyCacheMemoryMb(),
remoteSubkeyCacheSize: getRemoteSubkeyCacheSize(),
remoteMaxRecords: getRemoteMaxRecords(),
remoteMaxSubkeyCacheMemoryMb: getRemoteMaxSubkeyCacheMemoryMb(),
remoteMaxStorageSpaceMb: getRemoteMaxStorageSpaceMb()),
upnp: true,
detectAddressChanges: true,
restrictedNatRetries: 0,
tls: const VeilidConfigTLS(
certificatePath: "",
privateKeyPath: "",
connectionInitialTimeoutMs: 2000, connectionInitialTimeoutMs: 2000,
), connectionInactivityTimeoutMs: 60000,
application: const VeilidConfigApplication( maxConnectionsPerIp4: 32,
https: VeilidConfigHTTPS( maxConnectionsPerIp6Prefix: 32,
enabled: false, maxConnectionsPerIp6PrefixSize: 56,
listenAddress: "", maxConnectionFrequencyPerMin: 128,
path: "", clientWhitelistTimeoutMs: 300000,
url: null, reverseConnectionReceiptTimeMs: 5000,
holePunchReceiptTimeMs: 5000,
routingTable: const VeilidConfigRoutingTable(
nodeId: [],
nodeIdSecret: [],
bootstrap: kIsWeb
? ['ws://bootstrap.veilid.net:5150/ws']
: ['bootstrap.veilid.net'],
limitOverAttached: 64,
limitFullyAttached: 32,
limitAttachedStrong: 16,
limitAttachedGood: 8,
limitAttachedWeak: 4,
),
rpc: const VeilidConfigRPC(
concurrency: 0,
queueSize: 1024,
maxTimestampBehindMs: 10000,
maxTimestampAheadMs: 10000,
timeoutMs: 5000,
maxRouteHopCount: 4,
defaultRouteHopCount: 1,
),
dht: VeilidConfigDHT(
resolveNodeTimeoutMs: 10000,
resolveNodeCount: 20,
resolveNodeFanout: 3,
maxFindNodeCount: 20,
getValueTimeoutMs: 10000,
getValueCount: 20,
getValueFanout: 3,
setValueTimeoutMs: 10000,
setValueCount: 20,
setValueFanout: 5,
minPeerCount: 20,
minPeerRefreshTimeMs: 60000,
validateDialInfoReceiptTimeMs: 2000,
localSubkeyCacheSize: getLocalSubkeyCacheSize(),
localMaxSubkeyCacheMemoryMb: await getLocalMaxSubkeyCacheMemoryMb(),
remoteSubkeyCacheSize: getRemoteSubkeyCacheSize(),
remoteMaxRecords: getRemoteMaxRecords(),
remoteMaxSubkeyCacheMemoryMb:
await getRemoteMaxSubkeyCacheMemoryMb(),
remoteMaxStorageSpaceMb: getRemoteMaxStorageSpaceMb()),
upnp: true,
detectAddressChanges: true,
restrictedNatRetries: 0,
tls: const VeilidConfigTLS(
certificatePath: '',
privateKeyPath: '',
connectionInitialTimeoutMs: 2000,
),
application: const VeilidConfigApplication(
https: VeilidConfigHTTPS(
enabled: false,
listenAddress: '',
path: '',
),
http: VeilidConfigHTTP(
enabled: false,
listenAddress: '',
path: '',
)),
protocol: const VeilidConfigProtocol(
udp: VeilidConfigUDP(
enabled: !kIsWeb,
socketPoolSize: 0,
listenAddress: '',
),
tcp: VeilidConfigTCP(
connect: !kIsWeb,
listen: !kIsWeb,
maxConnections: 32,
listenAddress: '',
),
ws: VeilidConfigWS(
connect: true,
listen: !kIsWeb,
maxConnections: 16,
listenAddress: '',
path: 'ws',
),
wss: VeilidConfigWSS(
connect: true,
listen: false,
maxConnections: 16,
listenAddress: '',
path: 'ws',
), ),
http: VeilidConfigHTTP(
enabled: false,
listenAddress: "",
path: "",
url: null,
)),
protocol: const VeilidConfigProtocol(
udp: VeilidConfigUDP(
enabled: !kIsWeb,
socketPoolSize: 0,
listenAddress: "",
publicAddress: null,
),
tcp: VeilidConfigTCP(
connect: !kIsWeb,
listen: !kIsWeb,
maxConnections: 32,
listenAddress: "",
publicAddress: null,
),
ws: VeilidConfigWS(
connect: true,
listen: !kIsWeb,
maxConnections: 16,
listenAddress: "",
path: "ws",
url: null,
),
wss: VeilidConfigWSS(
connect: true,
listen: false,
maxConnections: 16,
listenAddress: "",
path: "ws",
url: null,
), ),
), ),
), );
);
}

View File

@ -5,7 +5,6 @@ import 'package:change_case/change_case.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'veilid_encoding.dart';
import 'veilid.dart'; import 'veilid.dart';
part 'routing_context.freezed.dart'; part 'routing_context.freezed.dart';
@ -27,7 +26,7 @@ extension ValidateDFLT on DHTSchemaDFLT {
extension ValidateSMPL on DHTSchemaSMPL { extension ValidateSMPL on DHTSchemaSMPL {
bool validate() { bool validate() {
final totalsv = members.fold(0, (acc, v) => (acc + v.mCnt)) + oCnt; final totalsv = members.fold(0, (acc, v) => acc + v.mCnt) + oCnt;
if (totalsv > 65535) { if (totalsv > 65535) {
return false; return false;
} }
@ -51,8 +50,8 @@ sealed class DHTSchema with _$DHTSchema {
{required int oCnt, {required int oCnt,
required List<DHTSchemaMember> members}) = DHTSchemaSMPL; required List<DHTSchemaMember> members}) = DHTSchemaSMPL;
factory DHTSchema.fromJson(Map<String, dynamic> json) => factory DHTSchema.fromJson(dynamic json) =>
_$DHTSchemaFromJson(json); _$DHTSchemaFromJson(json as Map<String, dynamic>);
} }
const DHTSchema defaultDHTSchema = DHTSchema.dflt(oCnt: 1); const DHTSchema defaultDHTSchema = DHTSchema.dflt(oCnt: 1);
@ -65,8 +64,8 @@ class DHTSchemaMember with _$DHTSchemaMember {
required int mCnt, required int mCnt,
}) = _DHTSchemaMember; }) = _DHTSchemaMember;
factory DHTSchemaMember.fromJson(Map<String, dynamic> json) => factory DHTSchemaMember.fromJson(dynamic json) =>
_$DHTSchemaMemberFromJson(json); _$DHTSchemaMemberFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -77,11 +76,27 @@ class DHTRecordDescriptor with _$DHTRecordDescriptor {
const factory DHTRecordDescriptor({ const factory DHTRecordDescriptor({
required TypedKey key, required TypedKey key,
required PublicKey owner, required PublicKey owner,
PublicKey? ownerSecret,
required DHTSchema schema, required DHTSchema schema,
PublicKey? ownerSecret,
}) = _DHTRecordDescriptor; }) = _DHTRecordDescriptor;
factory DHTRecordDescriptor.fromJson(Map<String, dynamic> json) => factory DHTRecordDescriptor.fromJson(dynamic json) =>
_$DHTRecordDescriptorFromJson(json); _$DHTRecordDescriptorFromJson(json as Map<String, dynamic>);
}
extension DHTRecordDescriptorExt on DHTRecordDescriptor {
KeyPair? ownerKeyPair() {
if (ownerSecret == null) {
return null;
}
return KeyPair(key: owner, secret: ownerSecret!);
}
TypedKeyPair? ownerTypedKeyPair() {
if (ownerSecret == null) {
return null;
}
return TypedKeyPair(kind: key.kind, key: owner, secret: ownerSecret!);
}
} }
////////////////////////////////////// //////////////////////////////////////
@ -96,8 +111,8 @@ class ValueSubkeyRange with _$ValueSubkeyRange {
required int high, required int high,
}) = _ValueSubkeyRange; }) = _ValueSubkeyRange;
factory ValueSubkeyRange.fromJson(Map<String, dynamic> json) => factory ValueSubkeyRange.fromJson(dynamic json) =>
_$ValueSubkeyRangeFromJson(json); _$ValueSubkeyRangeFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -112,8 +127,8 @@ class ValueData with _$ValueData {
required PublicKey writer, required PublicKey writer,
}) = _ValueData; }) = _ValueData;
factory ValueData.fromJson(Map<String, dynamic> json) => factory ValueData.fromJson(dynamic json) =>
_$ValueDataFromJson(json); _$ValueDataFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -123,9 +138,9 @@ enum Stability {
lowLatency, lowLatency,
reliable; reliable;
factory Stability.fromJson(dynamic j) =>
Stability.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase(); String toJson() => name.toPascalCase();
factory Stability.fromJson(String j) =>
Stability.values.byName(j.toCamelCase());
} }
////////////////////////////////////// //////////////////////////////////////
@ -136,79 +151,74 @@ enum Sequencing {
preferOrdered, preferOrdered,
ensureOrdered; ensureOrdered;
factory Sequencing.fromJson(dynamic j) =>
Sequencing.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase(); String toJson() => name.toPascalCase();
factory Sequencing.fromJson(String j) =>
Sequencing.values.byName(j.toCamelCase());
} }
////////////////////////////////////// //////////////////////////////////////
/// SafetySelection /// SafetySelection
@immutable @immutable
abstract class SafetySelection extends Equatable { abstract class SafetySelection {
factory SafetySelection.fromJson(Map<String, dynamic> json) { factory SafetySelection.fromJson(dynamic jsond) {
if (json.containsKey("Unsafe")) { final json = jsond as Map<String, dynamic>;
if (json.containsKey('Unsafe')) {
return SafetySelectionUnsafe( return SafetySelectionUnsafe(
sequencing: Sequencing.fromJson(json["Unsafe"])); sequencing: Sequencing.fromJson(json['Unsafe']));
} else if (json.containsKey("Safe")) { } else if (json.containsKey('Safe')) {
return SafetySelectionSafe(safetySpec: SafetySpec.fromJson(json["Safe"])); return SafetySelectionSafe(safetySpec: SafetySpec.fromJson(json['Safe']));
} else { } else {
throw const VeilidAPIExceptionInternal("Invalid SafetySelection"); throw const VeilidAPIExceptionInternal('Invalid SafetySelection');
} }
} }
Map<String, dynamic> toJson(); Map<String, dynamic> toJson();
} }
@immutable @immutable
class SafetySelectionUnsafe implements SafetySelection { class SafetySelectionUnsafe extends Equatable implements SafetySelection {
//
const SafetySelectionUnsafe({
required this.sequencing,
});
final Sequencing sequencing; final Sequencing sequencing;
@override @override
List<Object> get props => [sequencing]; List<Object> get props => [sequencing];
@override @override
bool? get stringify => null; bool? get stringify => null;
//
const SafetySelectionUnsafe({
required this.sequencing,
});
@override @override
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() => {'Unsafe': sequencing.toJson()};
return {'Unsafe': sequencing.toJson()};
}
} }
@immutable @immutable
class SafetySelectionSafe implements SafetySelection { class SafetySelectionSafe extends Equatable implements SafetySelection {
//
const SafetySelectionSafe({
required this.safetySpec,
});
final SafetySpec safetySpec; final SafetySpec safetySpec;
@override @override
List<Object> get props => [safetySpec]; List<Object> get props => [safetySpec];
@override @override
bool? get stringify => null; bool? get stringify => null;
//
const SafetySelectionSafe({
required this.safetySpec,
});
@override @override
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() => {'Safe': safetySpec.toJson()};
return {'Safe': safetySpec.toJson()};
}
} }
/// Options for safety routes (sender privacy) /// Options for safety routes (sender privacy)
@freezed @freezed
class SafetySpec with _$SafetySpec { class SafetySpec with _$SafetySpec {
const factory SafetySpec({ const factory SafetySpec({
String? preferredRoute,
required int hopCount, required int hopCount,
required Stability stability, required Stability stability,
required Sequencing sequencing, required Sequencing sequencing,
String? preferredRoute,
}) = _SafetySpec; }) = _SafetySpec;
factory SafetySpec.fromJson(Map<String, dynamic> json) => factory SafetySpec.fromJson(dynamic json) =>
_$SafetySpecFromJson(json); _$SafetySpecFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -218,8 +228,8 @@ class RouteBlob with _$RouteBlob {
const factory RouteBlob( const factory RouteBlob(
{required String routeId, {required String routeId,
@Uint8ListJsonConverter() required Uint8List blob}) = _RouteBlob; @Uint8ListJsonConverter() required Uint8List blob}) = _RouteBlob;
factory RouteBlob.fromJson(Map<String, dynamic> json) => factory RouteBlob.fromJson(dynamic json) =>
_$RouteBlobFromJson(json); _$RouteBlobFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////

View File

@ -4,28 +4,26 @@ import 'dart:typed_data';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'veilid_stub.dart'
if (dart.library.io) 'veilid_ffi.dart'
if (dart.library.js) 'veilid_js.dart';
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
import 'routing_context.dart'; import 'routing_context.dart';
import 'veilid_config.dart'; import 'veilid_config.dart';
import 'veilid_crypto.dart'; import 'veilid_crypto.dart';
import 'veilid_table_db.dart';
import 'veilid_state.dart'; import 'veilid_state.dart';
import 'veilid_stub.dart'
if (dart.library.io) 'veilid_ffi.dart'
if (dart.library.js) 'veilid_js.dart';
import 'veilid_table_db.dart';
export 'default_config.dart'; export 'default_config.dart';
export 'routing_context.dart'; export 'routing_context.dart';
export 'veilid.dart';
export 'veilid_encoding.dart'; export 'veilid_api_exception.dart';
export 'veilid_config.dart'; export 'veilid_config.dart';
export 'veilid_crypto.dart'; export 'veilid_crypto.dart';
export 'veilid_table_db.dart'; export 'veilid_encoding.dart';
export 'veilid_api_exception.dart';
export 'veilid_state.dart'; export 'veilid_state.dart';
export 'veilid.dart'; export 'veilid_table_db.dart';
////////////////////////////////////// //////////////////////////////////////
/// JSON Encode Helper /// JSON Encode Helper
@ -41,57 +39,39 @@ Object? veilidApiToEncodable(Object? value) {
throw UnsupportedError('Cannot convert to JSON: $value'); throw UnsupportedError('Cannot convert to JSON: $value');
} }
T? Function(dynamic) optFromJson<T>(
T Function(Map<String, dynamic>) jsonConstructor) {
return (dynamic j) {
if (j == null) {
return null;
} else {
return jsonConstructor(j);
}
};
}
List<T> Function(dynamic) jsonListConstructor<T>( List<T> Function(dynamic) jsonListConstructor<T>(
T Function(Map<String, dynamic>) jsonConstructor) { T Function(dynamic) jsonConstructor) =>
return (dynamic j) { (dynamic j) => (j as List<dynamic>).map((e) => jsonConstructor(e)).toList();
return (j as List<Map<String, dynamic>>)
.map((e) => jsonConstructor(e))
.toList();
};
}
////////////////////////////////////// //////////////////////////////////////
/// VeilidVersion /// VeilidVersion
@immutable @immutable
class VeilidVersion extends Equatable { class VeilidVersion extends Equatable {
const VeilidVersion(this.major, this.minor, this.patch);
final int major; final int major;
final int minor; final int minor;
final int patch; final int patch;
@override @override
List<Object> get props => [major, minor, patch]; List<Object> get props => [major, minor, patch];
const VeilidVersion(this.major, this.minor, this.patch);
} }
////////////////////////////////////// //////////////////////////////////////
/// Timestamp /// Timestamp
@immutable @immutable
class Timestamp extends Equatable { class Timestamp extends Equatable {
const Timestamp({required this.value});
factory Timestamp.fromString(String s) => Timestamp(value: BigInt.parse(s));
factory Timestamp.fromJson(dynamic json) =>
Timestamp.fromString(json as String);
final BigInt value; final BigInt value;
@override @override
List<Object> get props => [value]; List<Object> get props => [value];
const Timestamp({required this.value});
@override @override
String toString() => value.toString(); String toString() => value.toString();
factory Timestamp.fromString(String s) => Timestamp(value: BigInt.parse(s));
String toJson() => toString(); String toJson() => toString();
factory Timestamp.fromJson(dynamic json) =>
Timestamp.fromString(json as String);
TimestampDuration diff(Timestamp other) => TimestampDuration diff(Timestamp other) =>
TimestampDuration(value: value - other.value); TimestampDuration(value: value - other.value);
@ -102,20 +82,19 @@ class Timestamp extends Equatable {
@immutable @immutable
class TimestampDuration extends Equatable { class TimestampDuration extends Equatable {
const TimestampDuration({required this.value});
factory TimestampDuration.fromString(String s) =>
TimestampDuration(value: BigInt.parse(s));
factory TimestampDuration.fromJson(dynamic json) =>
TimestampDuration.fromString(json as String);
final BigInt value; final BigInt value;
@override @override
List<Object> get props => [value]; List<Object> get props => [value];
const TimestampDuration({required this.value});
@override @override
String toString() => value.toString(); String toString() => value.toString();
factory TimestampDuration.fromString(String s) =>
TimestampDuration(value: BigInt.parse(s));
String toJson() => toString(); String toJson() => toString();
factory TimestampDuration.fromJson(dynamic json) =>
TimestampDuration.fromString(json as String);
int toMillis() => (value ~/ BigInt.from(1000)).toInt(); int toMillis() => (value ~/ BigInt.from(1000)).toInt();
BigInt toMicros() => value; BigInt toMicros() => value;
@ -156,7 +135,7 @@ abstract class Veilid {
Future<void> releasePrivateRoute(String key); Future<void> releasePrivateRoute(String key);
// App calls // App calls
Future<void> appCallReply(String id, Uint8List message); Future<void> appCallReply(String callId, Uint8List message);
// TableStore // TableStore
Future<VeilidTableDB> openTableDB(String name, int columnCount); Future<VeilidTableDB> openTableDB(String name, int columnCount);

View File

@ -5,70 +5,73 @@ import 'package:freezed_annotation/freezed_annotation.dart';
@immutable @immutable
abstract class VeilidAPIException implements Exception { abstract class VeilidAPIException implements Exception {
factory VeilidAPIException.fromJson(dynamic json) { factory VeilidAPIException.fromJson(dynamic j) {
switch (json["kind"]) { final json = j as Map<String, dynamic>;
case "NotInitialized": switch (json['kind']! as String) {
case 'NotInitialized':
{ {
return VeilidAPIExceptionNotInitialized(); return VeilidAPIExceptionNotInitialized();
} }
case "AlreadyInitialized": case 'AlreadyInitialized':
{ {
return VeilidAPIExceptionAlreadyInitialized(); return VeilidAPIExceptionAlreadyInitialized();
} }
case "Timeout": case 'Timeout':
{ {
return VeilidAPIExceptionTimeout(); return VeilidAPIExceptionTimeout();
} }
case "TryAgain": case 'TryAgain':
{ {
return VeilidAPIExceptionTryAgain(); return VeilidAPIExceptionTryAgain();
} }
case "Shutdown": case 'Shutdown':
{ {
return VeilidAPIExceptionShutdown(); return VeilidAPIExceptionShutdown();
} }
case "InvalidTarget": case 'InvalidTarget':
{ {
return VeilidAPIExceptionInvalidTarget(); return VeilidAPIExceptionInvalidTarget();
} }
case "NoConnection": case 'NoConnection':
{ {
return VeilidAPIExceptionNoConnection(json["message"]); return VeilidAPIExceptionNoConnection(json['message']! as String);
} }
case "KeyNotFound": case 'KeyNotFound':
{ {
return VeilidAPIExceptionKeyNotFound(json["key"]); return VeilidAPIExceptionKeyNotFound(json['key']! as String);
} }
case "Internal": case 'Internal':
{ {
return VeilidAPIExceptionInternal(json["message"]); return VeilidAPIExceptionInternal(json['message']! as String);
} }
case "Unimplemented": case 'Unimplemented':
{ {
return VeilidAPIExceptionUnimplemented(json["unimplemented"]); return VeilidAPIExceptionUnimplemented(
json['unimplemented']! as String);
} }
case "ParseError": case 'ParseError':
{ {
return VeilidAPIExceptionParseError(json["message"], json["value"]); return VeilidAPIExceptionParseError(
json['message']! as String, json['value']! as String);
} }
case "InvalidArgument": case 'InvalidArgument':
{ {
return VeilidAPIExceptionInvalidArgument( return VeilidAPIExceptionInvalidArgument(json['context']! as String,
json["context"], json["argument"], json["value"]); json['argument']! as String, json['value']! as String);
} }
case "MissingArgument": case 'MissingArgument':
{ {
return VeilidAPIExceptionMissingArgument( return VeilidAPIExceptionMissingArgument(
json["context"], json["argument"]); json['context']! as String, json['argument']! as String);
} }
case "Generic": case 'Generic':
{ {
return VeilidAPIExceptionGeneric(json["message"]); return VeilidAPIExceptionGeneric(json['message']! as String);
} }
default: default:
{ {
throw VeilidAPIExceptionInternal( throw VeilidAPIExceptionInternal(
"Invalid VeilidAPIException type: ${json['kind']}"); "Invalid VeilidAPIException type: ${json['kind']! as String}");
} }
} }
} }
@ -79,224 +82,163 @@ abstract class VeilidAPIException implements Exception {
@immutable @immutable
class VeilidAPIExceptionNotInitialized implements VeilidAPIException { class VeilidAPIExceptionNotInitialized implements VeilidAPIException {
@override @override
String toString() { String toString() => 'VeilidAPIException: NotInitialized';
return "VeilidAPIException: NotInitialized";
}
@override @override
String toDisplayError() { String toDisplayError() => 'Not initialized';
return "Not initialized";
}
} }
@immutable @immutable
class VeilidAPIExceptionAlreadyInitialized implements VeilidAPIException { class VeilidAPIExceptionAlreadyInitialized implements VeilidAPIException {
@override @override
String toString() { String toString() => 'VeilidAPIException: AlreadyInitialized';
return "VeilidAPIException: AlreadyInitialized";
}
@override @override
String toDisplayError() { String toDisplayError() => 'Already initialized';
return "Already initialized";
}
} }
@immutable @immutable
class VeilidAPIExceptionTimeout implements VeilidAPIException { class VeilidAPIExceptionTimeout implements VeilidAPIException {
@override @override
String toString() { String toString() => 'VeilidAPIException: Timeout';
return "VeilidAPIException: Timeout";
}
@override @override
String toDisplayError() { String toDisplayError() => 'Timeout';
return "Timeout";
}
} }
@immutable @immutable
class VeilidAPIExceptionTryAgain implements VeilidAPIException { class VeilidAPIExceptionTryAgain implements VeilidAPIException {
@override @override
String toString() { String toString() => 'VeilidAPIException: TryAgain';
return "VeilidAPIException: TryAgain";
}
@override @override
String toDisplayError() { String toDisplayError() => 'Try again';
return "Try again";
}
} }
@immutable @immutable
class VeilidAPIExceptionShutdown implements VeilidAPIException { class VeilidAPIExceptionShutdown implements VeilidAPIException {
@override @override
String toString() { String toString() => 'VeilidAPIException: Shutdown';
return "VeilidAPIException: Shutdown";
}
@override @override
String toDisplayError() { String toDisplayError() => 'Currently shut down';
return "Currently shut down";
}
} }
@immutable @immutable
class VeilidAPIExceptionInvalidTarget implements VeilidAPIException { class VeilidAPIExceptionInvalidTarget implements VeilidAPIException {
@override @override
String toString() { String toString() => 'VeilidAPIException: InvalidTarget';
return "VeilidAPIException: InvalidTarget";
}
@override @override
String toDisplayError() { String toDisplayError() => 'Invalid target';
return "Invalid target";
}
} }
@immutable @immutable
class VeilidAPIExceptionNoConnection implements VeilidAPIException { class VeilidAPIExceptionNoConnection implements VeilidAPIException {
final String message;
@override
String toString() {
return "VeilidAPIException: NoConnection (message: $message)";
}
@override
String toDisplayError() {
return "No connection: $message";
}
// //
const VeilidAPIExceptionNoConnection(this.message); const VeilidAPIExceptionNoConnection(this.message);
final String message;
@override
String toString() => 'VeilidAPIException: NoConnection (message: $message)';
@override
String toDisplayError() => 'No connection: $message';
} }
@immutable @immutable
class VeilidAPIExceptionKeyNotFound implements VeilidAPIException { class VeilidAPIExceptionKeyNotFound implements VeilidAPIException {
final String key;
@override
String toString() {
return "VeilidAPIException: KeyNotFound (key: $key)";
}
@override
String toDisplayError() {
return "Key not found: $key";
}
// //
const VeilidAPIExceptionKeyNotFound(this.key); const VeilidAPIExceptionKeyNotFound(this.key);
final String key;
@override
String toString() => 'VeilidAPIException: KeyNotFound (key: $key)';
@override
String toDisplayError() => 'Key not found: $key';
} }
@immutable @immutable
class VeilidAPIExceptionInternal implements VeilidAPIException { class VeilidAPIExceptionInternal implements VeilidAPIException {
//
const VeilidAPIExceptionInternal(this.message);
final String message; final String message;
@override @override
String toString() { String toString() => 'VeilidAPIException: Internal ($message)';
return "VeilidAPIException: Internal ($message)";
}
@override @override
String toDisplayError() { String toDisplayError() => 'Internal error: $message';
return "Internal error: $message";
}
//
const VeilidAPIExceptionInternal(this.message);
} }
@immutable @immutable
class VeilidAPIExceptionUnimplemented implements VeilidAPIException { class VeilidAPIExceptionUnimplemented implements VeilidAPIException {
//
const VeilidAPIExceptionUnimplemented(this.message);
final String message; final String message;
@override @override
String toString() { String toString() => 'VeilidAPIException: Unimplemented ($message)';
return "VeilidAPIException: Unimplemented ($message)";
}
@override @override
String toDisplayError() { String toDisplayError() => 'Unimplemented: $message';
return "Unimplemented: $message";
}
//
const VeilidAPIExceptionUnimplemented(this.message);
} }
@immutable @immutable
class VeilidAPIExceptionParseError implements VeilidAPIException { class VeilidAPIExceptionParseError implements VeilidAPIException {
//
const VeilidAPIExceptionParseError(this.message, this.value);
final String message; final String message;
final String value; final String value;
@override @override
String toString() { String toString() =>
return "VeilidAPIException: ParseError ($message)\n value: $value"; 'VeilidAPIException: ParseError ($message)\n value: $value';
}
@override @override
String toDisplayError() { String toDisplayError() => 'Parse error: $message';
return "Parse error: $message";
}
//
const VeilidAPIExceptionParseError(this.message, this.value);
} }
@immutable @immutable
class VeilidAPIExceptionInvalidArgument implements VeilidAPIException { class VeilidAPIExceptionInvalidArgument implements VeilidAPIException {
//
const VeilidAPIExceptionInvalidArgument(
this.context, this.argument, this.value);
final String context; final String context;
final String argument; final String argument;
final String value; final String value;
@override @override
String toString() { String toString() => 'VeilidAPIException: InvalidArgument'
return "VeilidAPIException: InvalidArgument ($context:$argument)\n value: $value"; ' ($context:$argument)\n value: $value';
}
@override @override
String toDisplayError() { String toDisplayError() => 'Invalid argument for $context: $argument';
return "Invalid argument for $context: $argument";
}
//
const VeilidAPIExceptionInvalidArgument(
this.context, this.argument, this.value);
} }
@immutable @immutable
class VeilidAPIExceptionMissingArgument implements VeilidAPIException { class VeilidAPIExceptionMissingArgument implements VeilidAPIException {
//
const VeilidAPIExceptionMissingArgument(this.context, this.argument);
final String context; final String context;
final String argument; final String argument;
@override @override
String toString() { String toString() =>
return "VeilidAPIException: MissingArgument ($context:$argument)"; 'VeilidAPIException: MissingArgument ($context:$argument)';
}
@override @override
String toDisplayError() { String toDisplayError() => 'Missing argument for $context: $argument';
return "Missing argument for $context: $argument";
}
//
const VeilidAPIExceptionMissingArgument(this.context, this.argument);
} }
@immutable @immutable
class VeilidAPIExceptionGeneric implements VeilidAPIException { class VeilidAPIExceptionGeneric implements VeilidAPIException {
//
const VeilidAPIExceptionGeneric(this.message);
final String message; final String message;
@override @override
String toString() { String toString() => 'VeilidAPIException: Generic (message: $message)';
return "VeilidAPIException: Generic (message: $message)";
}
@override @override
String toDisplayError() { String toDisplayError() => message;
return message;
}
//
const VeilidAPIExceptionGeneric(this.message);
} }

View File

@ -1,9 +1,8 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';
import 'package:change_case/change_case.dart'; import 'package:change_case/change_case.dart';
import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'veilid.dart'; import 'veilid.dart';
import 'veilid_encoding.dart';
import 'veilid_crypto.dart';
part 'veilid_config.freezed.dart'; part 'veilid_config.freezed.dart';
part 'veilid_config.g.dart'; part 'veilid_config.g.dart';
@ -17,8 +16,8 @@ class VeilidFFIConfigLoggingTerminal with _$VeilidFFIConfigLoggingTerminal {
required VeilidConfigLogLevel level, required VeilidConfigLogLevel level,
}) = _VeilidFFIConfigLoggingTerminal; }) = _VeilidFFIConfigLoggingTerminal;
factory VeilidFFIConfigLoggingTerminal.fromJson(Map<String, dynamic> json) => factory VeilidFFIConfigLoggingTerminal.fromJson(dynamic json) =>
_$VeilidFFIConfigLoggingTerminalFromJson(json); _$VeilidFFIConfigLoggingTerminalFromJson(json as Map<String, dynamic>);
} }
@freezed @freezed
@ -30,8 +29,8 @@ class VeilidFFIConfigLoggingOtlp with _$VeilidFFIConfigLoggingOtlp {
required String serviceName, required String serviceName,
}) = _VeilidFFIConfigLoggingOtlp; }) = _VeilidFFIConfigLoggingOtlp;
factory VeilidFFIConfigLoggingOtlp.fromJson(Map<String, dynamic> json) => factory VeilidFFIConfigLoggingOtlp.fromJson(dynamic json) =>
_$VeilidFFIConfigLoggingOtlpFromJson(json); _$VeilidFFIConfigLoggingOtlpFromJson(json as Map<String, dynamic>);
} }
@freezed @freezed
@ -41,8 +40,8 @@ class VeilidFFIConfigLoggingApi with _$VeilidFFIConfigLoggingApi {
required VeilidConfigLogLevel level, required VeilidConfigLogLevel level,
}) = _VeilidFFIConfigLoggingApi; }) = _VeilidFFIConfigLoggingApi;
factory VeilidFFIConfigLoggingApi.fromJson(Map<String, dynamic> json) => factory VeilidFFIConfigLoggingApi.fromJson(dynamic json) =>
_$VeilidFFIConfigLoggingApiFromJson(json); _$VeilidFFIConfigLoggingApiFromJson(json as Map<String, dynamic>);
} }
@freezed @freezed
@ -52,8 +51,8 @@ class VeilidFFIConfigLogging with _$VeilidFFIConfigLogging {
required VeilidFFIConfigLoggingOtlp otlp, required VeilidFFIConfigLoggingOtlp otlp,
required VeilidFFIConfigLoggingApi api}) = _VeilidFFIConfigLogging; required VeilidFFIConfigLoggingApi api}) = _VeilidFFIConfigLogging;
factory VeilidFFIConfigLogging.fromJson(Map<String, dynamic> json) => factory VeilidFFIConfigLogging.fromJson(dynamic json) =>
_$VeilidFFIConfigLoggingFromJson(json); _$VeilidFFIConfigLoggingFromJson(json as Map<String, dynamic>);
} }
@freezed @freezed
@ -62,8 +61,8 @@ class VeilidFFIConfig with _$VeilidFFIConfig {
required VeilidFFIConfigLogging logging, required VeilidFFIConfigLogging logging,
}) = _VeilidFFIConfig; }) = _VeilidFFIConfig;
factory VeilidFFIConfig.fromJson(Map<String, dynamic> json) => factory VeilidFFIConfig.fromJson(dynamic json) =>
_$VeilidFFIConfigFromJson(json); _$VeilidFFIConfigFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
@ -79,9 +78,9 @@ class VeilidWASMConfigLoggingPerformance
required bool logsInConsole, required bool logsInConsole,
}) = _VeilidWASMConfigLoggingPerformance; }) = _VeilidWASMConfigLoggingPerformance;
factory VeilidWASMConfigLoggingPerformance.fromJson( factory VeilidWASMConfigLoggingPerformance.fromJson(dynamic json) =>
Map<String, dynamic> json) => _$VeilidWASMConfigLoggingPerformanceFromJson(
_$VeilidWASMConfigLoggingPerformanceFromJson(json); json as Map<String, dynamic>);
} }
@freezed @freezed
@ -91,8 +90,8 @@ class VeilidWASMConfigLoggingApi with _$VeilidWASMConfigLoggingApi {
required VeilidConfigLogLevel level, required VeilidConfigLogLevel level,
}) = _VeilidWASMConfigLoggingApi; }) = _VeilidWASMConfigLoggingApi;
factory VeilidWASMConfigLoggingApi.fromJson(Map<String, dynamic> json) => factory VeilidWASMConfigLoggingApi.fromJson(dynamic json) =>
_$VeilidWASMConfigLoggingApiFromJson(json); _$VeilidWASMConfigLoggingApiFromJson(json as Map<String, dynamic>);
} }
@freezed @freezed
@ -101,8 +100,8 @@ class VeilidWASMConfigLogging with _$VeilidWASMConfigLogging {
{required VeilidWASMConfigLoggingPerformance performance, {required VeilidWASMConfigLoggingPerformance performance,
required VeilidWASMConfigLoggingApi api}) = _VeilidWASMConfigLogging; required VeilidWASMConfigLoggingApi api}) = _VeilidWASMConfigLogging;
factory VeilidWASMConfigLogging.fromJson(Map<String, dynamic> json) => factory VeilidWASMConfigLogging.fromJson(dynamic json) =>
_$VeilidWASMConfigLoggingFromJson(json); _$VeilidWASMConfigLoggingFromJson(json as Map<String, dynamic>);
} }
@freezed @freezed
@ -111,8 +110,8 @@ class VeilidWASMConfig with _$VeilidWASMConfig {
required VeilidWASMConfigLogging logging, required VeilidWASMConfigLogging logging,
}) = _VeilidWASMConfig; }) = _VeilidWASMConfig;
factory VeilidWASMConfig.fromJson(Map<String, dynamic> json) => factory VeilidWASMConfig.fromJson(dynamic json) =>
_$VeilidWASMConfigFromJson(json); _$VeilidWASMConfigFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -126,13 +125,9 @@ enum VeilidConfigLogLevel {
debug, debug,
trace; trace;
String toJson() { factory VeilidConfigLogLevel.fromJson(dynamic j) =>
return name.toPascalCase(); VeilidConfigLogLevel.values.byName((j as String).toCamelCase());
} String toJson() => name.toPascalCase();
factory VeilidConfigLogLevel.fromJson(dynamic j) {
return VeilidConfigLogLevel.values.byName((j as String).toCamelCase());
}
} }
////////////////////////////////////// //////////////////////////////////////
@ -147,8 +142,8 @@ class VeilidConfigHTTPS with _$VeilidConfigHTTPS {
String? url, String? url,
}) = _VeilidConfigHTTPS; }) = _VeilidConfigHTTPS;
factory VeilidConfigHTTPS.fromJson(Map<String, dynamic> json) => factory VeilidConfigHTTPS.fromJson(dynamic json) =>
_$VeilidConfigHTTPSFromJson(json); _$VeilidConfigHTTPSFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -162,8 +157,8 @@ class VeilidConfigHTTP with _$VeilidConfigHTTP {
String? url, String? url,
}) = _VeilidConfigHTTP; }) = _VeilidConfigHTTP;
factory VeilidConfigHTTP.fromJson(Map<String, dynamic> json) => factory VeilidConfigHTTP.fromJson(dynamic json) =>
_$VeilidConfigHTTPFromJson(json); _$VeilidConfigHTTPFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -175,8 +170,8 @@ class VeilidConfigApplication with _$VeilidConfigApplication {
required VeilidConfigHTTP http, required VeilidConfigHTTP http,
}) = _VeilidConfigApplication; }) = _VeilidConfigApplication;
factory VeilidConfigApplication.fromJson(Map<String, dynamic> json) => factory VeilidConfigApplication.fromJson(dynamic json) =>
_$VeilidConfigApplicationFromJson(json); _$VeilidConfigApplicationFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -188,8 +183,8 @@ class VeilidConfigUDP with _$VeilidConfigUDP {
required String listenAddress, required String listenAddress,
String? publicAddress}) = _VeilidConfigUDP; String? publicAddress}) = _VeilidConfigUDP;
factory VeilidConfigUDP.fromJson(Map<String, dynamic> json) => factory VeilidConfigUDP.fromJson(dynamic json) =>
_$VeilidConfigUDPFromJson(json); _$VeilidConfigUDPFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -202,8 +197,8 @@ class VeilidConfigTCP with _$VeilidConfigTCP {
required String listenAddress, required String listenAddress,
String? publicAddress}) = _VeilidConfigTCP; String? publicAddress}) = _VeilidConfigTCP;
factory VeilidConfigTCP.fromJson(Map<String, dynamic> json) => factory VeilidConfigTCP.fromJson(dynamic json) =>
_$VeilidConfigTCPFromJson(json); _$VeilidConfigTCPFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -217,8 +212,8 @@ class VeilidConfigWS with _$VeilidConfigWS {
required String path, required String path,
String? url}) = _VeilidConfigWS; String? url}) = _VeilidConfigWS;
factory VeilidConfigWS.fromJson(Map<String, dynamic> json) => factory VeilidConfigWS.fromJson(dynamic json) =>
_$VeilidConfigWSFromJson(json); _$VeilidConfigWSFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -232,8 +227,8 @@ class VeilidConfigWSS with _$VeilidConfigWSS {
required String path, required String path,
String? url}) = _VeilidConfigWSS; String? url}) = _VeilidConfigWSS;
factory VeilidConfigWSS.fromJson(Map<String, dynamic> json) => factory VeilidConfigWSS.fromJson(dynamic json) =>
_$VeilidConfigWSSFromJson(json); _$VeilidConfigWSSFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -247,8 +242,8 @@ class VeilidConfigProtocol with _$VeilidConfigProtocol {
required VeilidConfigWSS wss, required VeilidConfigWSS wss,
}) = _VeilidConfigProtocol; }) = _VeilidConfigProtocol;
factory VeilidConfigProtocol.fromJson(Map<String, dynamic> json) => factory VeilidConfigProtocol.fromJson(dynamic json) =>
_$VeilidConfigProtocolFromJson(json); _$VeilidConfigProtocolFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -261,8 +256,8 @@ class VeilidConfigTLS with _$VeilidConfigTLS {
required int connectionInitialTimeoutMs, required int connectionInitialTimeoutMs,
}) = _VeilidConfigTLS; }) = _VeilidConfigTLS;
factory VeilidConfigTLS.fromJson(Map<String, dynamic> json) => factory VeilidConfigTLS.fromJson(dynamic json) =>
_$VeilidConfigTLSFromJson(json); _$VeilidConfigTLSFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -289,8 +284,8 @@ class VeilidConfigDHT with _$VeilidConfigDHT {
required int remoteMaxSubkeyCacheMemoryMb, required int remoteMaxSubkeyCacheMemoryMb,
required int remoteMaxStorageSpaceMb}) = _VeilidConfigDHT; required int remoteMaxStorageSpaceMb}) = _VeilidConfigDHT;
factory VeilidConfigDHT.fromJson(Map<String, dynamic> json) => factory VeilidConfigDHT.fromJson(dynamic json) =>
_$VeilidConfigDHTFromJson(json); _$VeilidConfigDHTFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -300,14 +295,14 @@ class VeilidConfigRPC with _$VeilidConfigRPC {
const factory VeilidConfigRPC( const factory VeilidConfigRPC(
{required int concurrency, {required int concurrency,
required int queueSize, required int queueSize,
int? maxTimestampBehindMs,
int? maxTimestampAheadMs,
required int timeoutMs, required int timeoutMs,
required int maxRouteHopCount, required int maxRouteHopCount,
required int defaultRouteHopCount}) = _VeilidConfigRPC; required int defaultRouteHopCount,
int? maxTimestampBehindMs,
int? maxTimestampAheadMs}) = _VeilidConfigRPC;
factory VeilidConfigRPC.fromJson(Map<String, dynamic> json) => factory VeilidConfigRPC.fromJson(dynamic json) =>
_$VeilidConfigRPCFromJson(json); _$VeilidConfigRPCFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -325,8 +320,8 @@ class VeilidConfigRoutingTable with _$VeilidConfigRoutingTable {
required int limitAttachedWeak, required int limitAttachedWeak,
}) = _VeilidConfigRoutingTable; }) = _VeilidConfigRoutingTable;
factory VeilidConfigRoutingTable.fromJson(Map<String, dynamic> json) => factory VeilidConfigRoutingTable.fromJson(dynamic json) =>
_$VeilidConfigRoutingTableFromJson(json); _$VeilidConfigRoutingTableFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -343,7 +338,6 @@ class VeilidConfigNetwork with _$VeilidConfigNetwork {
required int clientWhitelistTimeoutMs, required int clientWhitelistTimeoutMs,
required int reverseConnectionReceiptTimeMs, required int reverseConnectionReceiptTimeMs,
required int holePunchReceiptTimeMs, required int holePunchReceiptTimeMs,
String? networkKeyPassword,
required VeilidConfigRoutingTable routingTable, required VeilidConfigRoutingTable routingTable,
required VeilidConfigRPC rpc, required VeilidConfigRPC rpc,
required VeilidConfigDHT dht, required VeilidConfigDHT dht,
@ -353,10 +347,11 @@ class VeilidConfigNetwork with _$VeilidConfigNetwork {
required VeilidConfigTLS tls, required VeilidConfigTLS tls,
required VeilidConfigApplication application, required VeilidConfigApplication application,
required VeilidConfigProtocol protocol, required VeilidConfigProtocol protocol,
String? networkKeyPassword,
}) = _VeilidConfigNetwork; }) = _VeilidConfigNetwork;
factory VeilidConfigNetwork.fromJson(Map<String, dynamic> json) => factory VeilidConfigNetwork.fromJson(dynamic json) =>
_$VeilidConfigNetworkFromJson(json); _$VeilidConfigNetworkFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -368,8 +363,8 @@ class VeilidConfigTableStore with _$VeilidConfigTableStore {
required bool delete, required bool delete,
}) = _VeilidConfigTableStore; }) = _VeilidConfigTableStore;
factory VeilidConfigTableStore.fromJson(Map<String, dynamic> json) => factory VeilidConfigTableStore.fromJson(dynamic json) =>
_$VeilidConfigTableStoreFromJson(json); _$VeilidConfigTableStoreFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -381,8 +376,8 @@ class VeilidConfigBlockStore with _$VeilidConfigBlockStore {
required bool delete, required bool delete,
}) = _VeilidConfigBlockStore; }) = _VeilidConfigBlockStore;
factory VeilidConfigBlockStore.fromJson(Map<String, dynamic> json) => factory VeilidConfigBlockStore.fromJson(dynamic json) =>
_$VeilidConfigBlockStoreFromJson(json); _$VeilidConfigBlockStoreFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -397,8 +392,8 @@ class VeilidConfigProtectedStore with _$VeilidConfigProtectedStore {
required String deviceEncryptionKeyPassword, required String deviceEncryptionKeyPassword,
String? newDeviceEncryptionKeyPassword}) = _VeilidConfigProtectedStore; String? newDeviceEncryptionKeyPassword}) = _VeilidConfigProtectedStore;
factory VeilidConfigProtectedStore.fromJson(Map<String, dynamic> json) => factory VeilidConfigProtectedStore.fromJson(dynamic json) =>
_$VeilidConfigProtectedStoreFromJson(json); _$VeilidConfigProtectedStoreFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -409,8 +404,8 @@ class VeilidConfigCapabilities with _$VeilidConfigCapabilities {
required List<String> disable, required List<String> disable,
}) = _VeilidConfigCapabilities; }) = _VeilidConfigCapabilities;
factory VeilidConfigCapabilities.fromJson(Map<String, dynamic> json) => factory VeilidConfigCapabilities.fromJson(dynamic json) =>
_$VeilidConfigCapabilitiesFromJson(json); _$VeilidConfigCapabilitiesFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -427,6 +422,6 @@ class VeilidConfig with _$VeilidConfig {
required VeilidConfigNetwork network, required VeilidConfigNetwork network,
}) = _VeilidConfig; }) = _VeilidConfig;
factory VeilidConfig.fromJson(Map<String, dynamic> json) => factory VeilidConfig.fromJson(dynamic json) =>
_$VeilidConfigFromJson(json); _$VeilidConfigFromJson(json as Map<String, dynamic>);
} }

View File

@ -5,7 +5,6 @@ import 'package:charcode/charcode.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'veilid_encoding.dart';
import 'veilid.dart'; import 'veilid.dart';
////////////////////////////////////// //////////////////////////////////////
@ -17,27 +16,23 @@ const CryptoKind cryptoKindVLD0 =
const CryptoKind cryptoKindNONE = const CryptoKind cryptoKindNONE =
$N << 0 | $O << 8 | $N << 16 | $E << 24; // "NONE" $N << 0 | $O << 8 | $N << 16 | $E << 24; // "NONE"
String cryptoKindToString(CryptoKind kind) { String cryptoKindToString(CryptoKind kind) =>
return "${String.fromCharCode(kind & 0xFF)}${String.fromCharCode((kind >> 8) & 0xFF)}${String.fromCharCode((kind >> 16) & 0xFF)}${String.fromCharCode((kind >> 24) & 0xFF)}"; cryptoKindToBytes(kind).map(String.fromCharCode).join();
}
const CryptoKind bestCryptoKind = cryptoKindVLD0;
Uint8List cryptoKindToBytes(CryptoKind kind) { Uint8List cryptoKindToBytes(CryptoKind kind) {
var b = Uint8List(4); final b = Uint8List(4);
b[0] = kind & 0xFF; ByteData.sublistView(b).setUint32(0, kind);
b[1] = (kind >> 8) & 0xFF;
b[2] = (kind >> 16) & 0xFF;
b[3] = (kind >> 24) & 0xFF;
return b; return b;
} }
CryptoKind cryptoKindFromString(String s) { CryptoKind cryptoKindFromString(String s) {
if (s.codeUnits.length != 4) { if (s.codeUnits.length != 4) {
throw const FormatException("malformed string"); throw const FormatException('malformed string');
} }
CryptoKind kind = s.codeUnits[0] | final kind =
s.codeUnits[1] << 8 | ByteData.sublistView(Uint8List.fromList(s.codeUnits)).getUint32(0);
s.codeUnits[2] << 16 |
s.codeUnits[3] << 24;
return kind; return kind;
} }
@ -46,100 +41,95 @@ CryptoKind cryptoKindFromString(String s) {
@immutable @immutable
class Typed<V extends EncodedString> extends Equatable { class Typed<V extends EncodedString> extends Equatable {
const Typed({required this.kind, required this.value});
factory Typed.fromString(String s) {
final parts = s.split(':');
if (parts.length < 2 || parts[0].codeUnits.length != 4) {
throw const FormatException('malformed string');
}
final kind = cryptoKindFromString(parts[0]);
final value = EncodedString.fromString<V>(parts.sublist(1).join(':'));
return Typed(kind: kind, value: value);
}
factory Typed.fromJson(dynamic json) => Typed.fromString(json as String);
final CryptoKind kind; final CryptoKind kind;
final V value; final V value;
@override @override
List<Object> get props => [kind, value]; List<Object> get props => [kind, value];
const Typed({required this.kind, required this.value});
@override @override
String toString() { String toString() => '${cryptoKindToString(kind)}:$value';
return "${cryptoKindToString(kind)}:$value";
}
factory Typed.fromString(String s) {
final parts = s.split(":");
if (parts.length < 2 || parts[0].codeUnits.length != 4) {
throw const FormatException("malformed string");
}
final kind = cryptoKindFromString(parts[0]);
final value = EncodedString.fromString<V>(parts.sublist(1).join(":"));
return Typed(kind: kind, value: value);
}
Uint8List decode() { Uint8List decode() {
var b = cryptoKindToBytes(kind); final b = BytesBuilder()
b.addAll(value.decode()); ..add(cryptoKindToBytes(kind))
return b; ..add(value.decode());
return b.toBytes();
} }
String toJson() => toString(); String toJson() => toString();
factory Typed.fromJson(dynamic json) => Typed.fromString(json as String);
} }
@immutable @immutable
class KeyPair extends Equatable { class KeyPair extends Equatable {
final PublicKey key;
final PublicKey secret;
@override
List<Object> get props => [key, secret];
const KeyPair({required this.key, required this.secret}); const KeyPair({required this.key, required this.secret});
@override
String toString() {
return "${key.toString()}:${secret.toString()}";
}
factory KeyPair.fromString(String s) { factory KeyPair.fromString(String s) {
final parts = s.split(":"); final parts = s.split(':');
if (parts.length != 2 || if (parts.length != 2 ||
parts[0].codeUnits.length != 43 || parts[0].codeUnits.length != 43 ||
parts[1].codeUnits.length != 43) { parts[1].codeUnits.length != 43) {
throw const FormatException("malformed string"); throw const FormatException('malformed string');
} }
final key = PublicKey.fromString(parts[0]); final key = PublicKey.fromString(parts[0]);
final secret = PublicKey.fromString(parts[1]); final secret = PublicKey.fromString(parts[1]);
return KeyPair(key: key, secret: secret); return KeyPair(key: key, secret: secret);
} }
factory KeyPair.fromJson(dynamic json) => KeyPair.fromString(json as String);
final PublicKey key;
final PublicKey secret;
@override
List<Object> get props => [key, secret];
@override
String toString() => '$key:$secret';
String toJson() => toString(); String toJson() => toString();
factory KeyPair.fromJson(dynamic json) => KeyPair.fromString(json as String);
} }
@immutable @immutable
class TypedKeyPair extends Equatable { class TypedKeyPair extends Equatable {
final CryptoKind kind;
final PublicKey key;
final PublicKey secret;
@override
List<Object> get props => [kind, key, secret];
const TypedKeyPair( const TypedKeyPair(
{required this.kind, required this.key, required this.secret}); {required this.kind, required this.key, required this.secret});
@override
String toString() =>
"${cryptoKindToString(kind)}:${key.toString()}:${secret.toString()}";
factory TypedKeyPair.fromString(String s) { factory TypedKeyPair.fromString(String s) {
final parts = s.split(":"); final parts = s.split(':');
if (parts.length != 3 || if (parts.length != 3 ||
parts[0].codeUnits.length != 4 || parts[0].codeUnits.length != 4 ||
parts[1].codeUnits.length != 43 || parts[1].codeUnits.length != 43 ||
parts[2].codeUnits.length != 43) { parts[2].codeUnits.length != 43) {
throw VeilidAPIExceptionInvalidArgument("malformed string", "s", s); throw VeilidAPIExceptionInvalidArgument('malformed string', 's', s);
} }
final kind = cryptoKindFromString(parts[0]); final kind = cryptoKindFromString(parts[0]);
final key = PublicKey.fromString(parts[1]); final key = PublicKey.fromString(parts[1]);
final secret = PublicKey.fromString(parts[2]); final secret = PublicKey.fromString(parts[2]);
return TypedKeyPair(kind: kind, key: key, secret: secret); return TypedKeyPair(kind: kind, key: key, secret: secret);
} }
String toJson() => toString();
factory TypedKeyPair.fromJson(dynamic json) => factory TypedKeyPair.fromJson(dynamic json) =>
TypedKeyPair.fromString(json as String); TypedKeyPair.fromString(json as String);
factory TypedKeyPair.fromKeyPair(CryptoKind kind, KeyPair keyPair) =>
TypedKeyPair(kind: kind, key: keyPair.key, secret: keyPair.secret);
final CryptoKind kind;
final PublicKey key;
final PublicKey secret;
@override
List<Object> get props => [kind, key, secret];
@override
String toString() => '${cryptoKindToString(kind)}:$key:$secret';
String toJson() => toString();
} }
typedef CryptoKey = FixedEncodedString43; typedef CryptoKey = FixedEncodedString43;
@ -176,17 +166,15 @@ abstract class VeilidCryptoSystem {
Future<HashDigest> generateHash(Uint8List data); Future<HashDigest> generateHash(Uint8List data);
//Future<HashDigest> generateHashReader(Stream<List<int>> reader); //Future<HashDigest> generateHashReader(Stream<List<int>> reader);
Future<bool> validateKeyPair(PublicKey key, SecretKey secret); Future<bool> validateKeyPair(PublicKey key, SecretKey secret);
Future<bool> validateKeyPairWithKeyPair(KeyPair keyPair) { Future<bool> validateKeyPairWithKeyPair(KeyPair keyPair) =>
return validateKeyPair(keyPair.key, keyPair.secret); validateKeyPair(keyPair.key, keyPair.secret);
}
Future<bool> validateHash(Uint8List data, HashDigest hash); Future<bool> validateHash(Uint8List data, HashDigest hash);
//Future<bool> validateHashReader(Stream<List<int>> reader, HashDigest hash); //Future<bool> validateHashReader(Stream<List<int>> reader, HashDigest hash);
Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2); Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2);
Future<Signature> sign(PublicKey key, SecretKey secret, Uint8List data); Future<Signature> sign(PublicKey key, SecretKey secret, Uint8List data);
Future<Signature> signWithKeyPair(KeyPair keyPair, Uint8List data) { Future<Signature> signWithKeyPair(KeyPair keyPair, Uint8List data) =>
return sign(keyPair.key, keyPair.secret, data); sign(keyPair.key, keyPair.secret, data);
}
Future<void> verify(PublicKey key, Uint8List data, Signature signature); Future<void> verify(PublicKey key, Uint8List data, Signature signature);
Future<int> aeadOverhead(); Future<int> aeadOverhead();

View File

@ -27,22 +27,20 @@ class Uint8ListJsonConverter implements JsonConverter<Uint8List, String> {
const Uint8ListJsonConverter(); const Uint8ListJsonConverter();
@override @override
Uint8List fromJson(String json) => base64UrlNoPadDecode(json); Uint8List fromJson(dynamic json) => base64UrlNoPadDecode(json as String);
@override @override
String toJson(Uint8List data) => base64UrlNoPadEncode(data); String toJson(Uint8List data) => base64UrlNoPadEncode(data);
} }
@immutable @immutable
abstract class EncodedString extends Equatable { abstract class EncodedString extends Equatable {
const EncodedString(String s) : contents = s;
final String contents; final String contents;
@override @override
List<Object> get props => [contents]; List<Object> get props => [contents];
const EncodedString(String s) : contents = s; Uint8List decode() => base64UrlNoPadDecode(contents);
Uint8List decode() {
return base64UrlNoPadDecode(contents);
}
@override @override
String toString() => contents; String toString() => contents;
@ -76,96 +74,82 @@ abstract class EncodedString extends Equatable {
@immutable @immutable
class FixedEncodedString32 extends EncodedString { class FixedEncodedString32 extends EncodedString {
const FixedEncodedString32._(String s) : super(s);
static int encodedLength() {
return 32;
}
static int decodedLength() {
return 24;
}
factory FixedEncodedString32.fromBytes(Uint8List bytes) { factory FixedEncodedString32.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) { if (bytes.length != decodedLength()) {
throw Exception("length ${bytes.length} should be ${decodedLength()}"); throw Exception('length ${bytes.length} should be ${decodedLength()}');
} }
return FixedEncodedString32._(base64UrlNoPadEncode(bytes)); return FixedEncodedString32._(base64UrlNoPadEncode(bytes));
} }
factory FixedEncodedString32.fromString(String s) { factory FixedEncodedString32.fromString(String s) {
var d = base64UrlNoPadDecode(s); final d = base64UrlNoPadDecode(s);
if (d.length != decodedLength()) { if (d.length != decodedLength()) {
throw Exception("length ${s.length} should be ${encodedLength()}"); throw Exception('length ${s.length} should be ${encodedLength()}');
} }
return FixedEncodedString32._(s); return FixedEncodedString32._(s);
} }
String toJson() => toString();
factory FixedEncodedString32.fromJson(dynamic json) => factory FixedEncodedString32.fromJson(dynamic json) =>
FixedEncodedString32.fromString(json as String); FixedEncodedString32.fromString(json as String);
const FixedEncodedString32._(super.s);
static int encodedLength() => 32;
static int decodedLength() => 24;
String toJson() => toString();
} }
@immutable @immutable
class FixedEncodedString43 extends EncodedString { class FixedEncodedString43 extends EncodedString {
const FixedEncodedString43._(String s) : super(s);
static int encodedLength() {
return 43;
}
static int decodedLength() {
return 32;
}
factory FixedEncodedString43.fromBytes(Uint8List bytes) { factory FixedEncodedString43.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) { if (bytes.length != decodedLength()) {
throw Exception("length ${bytes.length} should be ${decodedLength()}"); throw Exception('length ${bytes.length} should be ${decodedLength()}');
} }
return FixedEncodedString43._(base64UrlNoPadEncode(bytes)); return FixedEncodedString43._(base64UrlNoPadEncode(bytes));
} }
factory FixedEncodedString43.fromString(String s) { factory FixedEncodedString43.fromString(String s) {
var d = base64UrlNoPadDecode(s); final d = base64UrlNoPadDecode(s);
if (d.length != decodedLength()) { if (d.length != decodedLength()) {
throw Exception("length ${s.length} should be ${encodedLength()}"); throw Exception('length ${s.length} should be ${encodedLength()}');
} }
return FixedEncodedString43._(s); return FixedEncodedString43._(s);
} }
String toJson() => toString();
factory FixedEncodedString43.fromJson(dynamic json) => factory FixedEncodedString43.fromJson(dynamic json) =>
FixedEncodedString43.fromString(json as String); FixedEncodedString43.fromString(json as String);
const FixedEncodedString43._(super.s);
static int encodedLength() => 43;
static int decodedLength() => 32;
String toJson() => toString();
} }
@immutable @immutable
class FixedEncodedString86 extends EncodedString { class FixedEncodedString86 extends EncodedString {
const FixedEncodedString86._(String s) : super(s);
static int encodedLength() {
return 86;
}
static int decodedLength() {
return 64;
}
String toJson() {
return toString();
}
factory FixedEncodedString86.fromBytes(Uint8List bytes) { factory FixedEncodedString86.fromBytes(Uint8List bytes) {
if (bytes.length != decodedLength()) { if (bytes.length != decodedLength()) {
throw Exception("length ${bytes.length} should be ${decodedLength()}"); throw Exception('length ${bytes.length} should be ${decodedLength()}');
} }
return FixedEncodedString86._(base64UrlNoPadEncode(bytes)); return FixedEncodedString86._(base64UrlNoPadEncode(bytes));
} }
factory FixedEncodedString86.fromString(String s) { factory FixedEncodedString86.fromString(String s) {
var d = base64UrlNoPadDecode(s); final d = base64UrlNoPadDecode(s);
if (d.length != decodedLength()) { if (d.length != decodedLength()) {
throw Exception("length ${s.length} should be ${encodedLength()}"); throw Exception('length ${s.length} should be ${encodedLength()}');
} }
return FixedEncodedString86._(s); return FixedEncodedString86._(s);
} }
factory FixedEncodedString86.fromJson(dynamic json) => factory FixedEncodedString86.fromJson(dynamic json) =>
FixedEncodedString86.fromString(json as String); FixedEncodedString86.fromString(json as String);
const FixedEncodedString86._(super.s);
static int encodedLength() => 86;
static int decodedLength() => 64;
String toJson() => toString();
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +1,53 @@
import 'veilid.dart'; import 'dart:async';
import 'dart:convert';
import 'dart:html' as html; import 'dart:html' as html;
import 'dart:js' as js; import 'dart:js' as js;
import 'dart:js_util' as js_util; import 'dart:js_util' as js_util;
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'veilid_encoding.dart'; import 'veilid.dart';
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
Veilid getVeilid() => VeilidJS(); Veilid getVeilid() => VeilidJS();
Object wasm = js_util.getProperty(html.window, "veilid_wasm"); Object wasm = js_util.getProperty(html.window, 'veilid_wasm');
Future<T> _wrapApiPromise<T>(Object p) { Future<T> _wrapApiPromise<T>(Object p) => js_util
return js_util.promiseToFuture(p).then((value) => value as T).catchError( .promiseToFuture<T>(p)
(error) => Future<T>.error( .then((value) => value)
VeilidAPIException.fromJson(jsonDecode(error as String)))); // ignore: inference_failure_on_untyped_parameter
} .catchError((e) {
// Wrap all other errors in VeilidAPIExceptionInternal
throw VeilidAPIExceptionInternal(e.toString());
}, test: (e) => e is! VeilidAPIException);
class _Ctx { class _Ctx {
int? id; _Ctx(int id, this.js) : _id = id;
int? _id;
final VeilidJS js; final VeilidJS js;
_Ctx(int this.id, this.js); int requireId() {
void ensureValid() { if (_id == null) {
if (id == null) {
throw VeilidAPIExceptionNotInitialized(); throw VeilidAPIExceptionNotInitialized();
} }
return _id!;
} }
void close() { void close() {
if (id != null) { if (_id != null) {
js_util.callMethod(wasm, "release_routing_context", [id!]); js_util.callMethod<void>(wasm, 'release_routing_context', [_id]);
id = null; _id = null;
} }
} }
} }
// JS implementation of VeilidRoutingContext // JS implementation of VeilidRoutingContext
class VeilidRoutingContextJS extends VeilidRoutingContext { class VeilidRoutingContextJS extends VeilidRoutingContext {
final _Ctx _ctx;
static final Finalizer<_Ctx> _finalizer = Finalizer((ctx) => ctx.close());
VeilidRoutingContextJS._(this._ctx) { VeilidRoutingContextJS._(this._ctx) {
_finalizer.attach(this, _ctx, detach: this); _finalizer.attach(this, _ctx, detach: this);
} }
final _Ctx _ctx;
static final Finalizer<_Ctx> _finalizer = Finalizer((ctx) => ctx.close());
@override @override
void close() { void close() {
@ -55,113 +56,113 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
@override @override
VeilidRoutingContextJS withPrivacy() { VeilidRoutingContextJS withPrivacy() {
_ctx.ensureValid(); final id = _ctx.requireId();
int newId = final int newId =
js_util.callMethod(wasm, "routing_context_with_privacy", [_ctx.id!]); js_util.callMethod(wasm, 'routing_context_with_privacy', [id]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js)); return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
} }
@override @override
VeilidRoutingContextJS withCustomPrivacy(SafetySelection safetySelection) { VeilidRoutingContextJS withCustomPrivacy(SafetySelection safetySelection) {
_ctx.ensureValid(); final id = _ctx.requireId();
final newId = js_util.callMethod( final newId = js_util.callMethod<int>(
wasm, wasm,
"routing_context_with_custom_privacy", 'routing_context_with_custom_privacy',
[_ctx.id!, jsonEncode(safetySelection)]); [id, jsonEncode(safetySelection)]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js)); return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
} }
@override @override
VeilidRoutingContextJS withSequencing(Sequencing sequencing) { VeilidRoutingContextJS withSequencing(Sequencing sequencing) {
_ctx.ensureValid(); final id = _ctx.requireId();
final newId = js_util.callMethod(wasm, "routing_context_with_sequencing", final newId = js_util.callMethod<int>(
[_ctx.id!, jsonEncode(sequencing)]); wasm, 'routing_context_with_sequencing', [id, jsonEncode(sequencing)]);
return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js)); return VeilidRoutingContextJS._(_Ctx(newId, _ctx.js));
} }
@override @override
Future<Uint8List> appCall(String target, Uint8List request) async { Future<Uint8List> appCall(String target, Uint8List request) async {
_ctx.ensureValid(); final id = _ctx.requireId();
var encodedRequest = base64UrlNoPadEncode(request); final encodedRequest = base64UrlNoPadEncode(request);
return base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod( return base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod(
wasm, "routing_context_app_call", [_ctx.id!, target, encodedRequest]))); wasm, 'routing_context_app_call', [id, target, encodedRequest])));
} }
@override @override
Future<void> appMessage(String target, Uint8List message) { Future<void> appMessage(String target, Uint8List message) {
_ctx.ensureValid(); final id = _ctx.requireId();
var encodedMessage = base64UrlNoPadEncode(message); final encodedMessage = base64UrlNoPadEncode(message);
return _wrapApiPromise(js_util.callMethod(wasm, return _wrapApiPromise(js_util.callMethod(
"routing_context_app_message", [_ctx.id!, target, encodedMessage])); wasm, 'routing_context_app_message', [id, target, encodedMessage]));
} }
@override @override
Future<DHTRecordDescriptor> createDHTRecord(DHTSchema schema, Future<DHTRecordDescriptor> createDHTRecord(DHTSchema schema,
{CryptoKind kind = 0}) async { {CryptoKind kind = 0}) async {
_ctx.ensureValid(); final id = _ctx.requireId();
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "routing_context_create_dht_record", .callMethod(wasm, 'routing_context_create_dht_record',
[_ctx.id!, jsonEncode(schema), kind])))); [id, jsonEncode(schema), kind]))));
} }
@override @override
Future<DHTRecordDescriptor> openDHTRecord( Future<DHTRecordDescriptor> openDHTRecord(
TypedKey key, KeyPair? writer) async { TypedKey key, KeyPair? writer) async {
_ctx.ensureValid(); final id = _ctx.requireId();
return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util return DHTRecordDescriptor.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "routing_context_open_dht_record", [ .callMethod(wasm, 'routing_context_open_dht_record', [
_ctx.id!, id,
jsonEncode(key), jsonEncode(key),
writer != null ? jsonEncode(writer) : null if (writer != null) jsonEncode(writer) else null
])))); ]))));
} }
@override @override
Future<void> closeDHTRecord(TypedKey key) { Future<void> closeDHTRecord(TypedKey key) {
_ctx.ensureValid(); final id = _ctx.requireId();
return _wrapApiPromise(js_util.callMethod( return _wrapApiPromise(js_util.callMethod(
wasm, "routing_context_close_dht_record", [_ctx.id!, jsonEncode(key)])); wasm, 'routing_context_close_dht_record', [id, jsonEncode(key)]));
} }
@override @override
Future<void> deleteDHTRecord(TypedKey key) { Future<void> deleteDHTRecord(TypedKey key) {
_ctx.ensureValid(); final id = _ctx.requireId();
return _wrapApiPromise(js_util.callMethod(wasm, return _wrapApiPromise(js_util.callMethod(
"routing_context_delete_dht_record", [_ctx.id!, jsonEncode(key)])); wasm, 'routing_context_delete_dht_record', [id, jsonEncode(key)]));
} }
@override @override
Future<ValueData?> getDHTValue( Future<ValueData?> getDHTValue(
TypedKey key, int subkey, bool forceRefresh) async { TypedKey key, int subkey, bool forceRefresh) async {
_ctx.ensureValid(); final id = _ctx.requireId();
final opt = await _wrapApiPromise(js_util.callMethod( final opt = await _wrapApiPromise<String?>(js_util.callMethod(
wasm, wasm,
"routing_context_get_dht_value", 'routing_context_get_dht_value',
[_ctx.id!, jsonEncode(key), subkey, forceRefresh])); [id, jsonEncode(key), subkey, forceRefresh]));
return opt == null ? null : ValueData.fromJson(jsonDecode(opt)); return opt == null ? null : ValueData.fromJson(jsonDecode(opt));
} }
@override @override
Future<ValueData?> setDHTValue( Future<ValueData?> setDHTValue(
TypedKey key, int subkey, Uint8List data) async { TypedKey key, int subkey, Uint8List data) async {
_ctx.ensureValid(); final id = _ctx.requireId();
final opt = await _wrapApiPromise(js_util.callMethod( final opt = await _wrapApiPromise<String?>(js_util.callMethod(
wasm, wasm,
"routing_context_set_dht_value", 'routing_context_set_dht_value',
[_ctx.id!, jsonEncode(key), subkey, base64UrlNoPadEncode(data)])); [id, jsonEncode(key), subkey, base64UrlNoPadEncode(data)]));
return opt == null ? null : ValueData.fromJson(jsonDecode(opt)); return opt == null ? null : ValueData.fromJson(jsonDecode(opt));
} }
@override @override
Future<Timestamp> watchDHTValues(TypedKey key, List<ValueSubkeyRange> subkeys, Future<Timestamp> watchDHTValues(TypedKey key, List<ValueSubkeyRange> subkeys,
Timestamp expiration, int count) async { Timestamp expiration, int count) async {
_ctx.ensureValid(); final id = _ctx.requireId();
final ts = await _wrapApiPromise(js_util.callMethod( final ts = await _wrapApiPromise<String>(js_util.callMethod(
wasm, "routing_context_watch_dht_values", [ wasm, 'routing_context_watch_dht_values', [
_ctx.id!, id,
jsonEncode(key), jsonEncode(key),
jsonEncode(subkeys), jsonEncode(subkeys),
expiration.toString(), expiration.toString(),
@ -172,195 +173,176 @@ class VeilidRoutingContextJS extends VeilidRoutingContext {
@override @override
Future<bool> cancelDHTWatch(TypedKey key, List<ValueSubkeyRange> subkeys) { Future<bool> cancelDHTWatch(TypedKey key, List<ValueSubkeyRange> subkeys) {
_ctx.ensureValid(); final id = _ctx.requireId();
return _wrapApiPromise(js_util.callMethod( return _wrapApiPromise(js_util.callMethod(
wasm, wasm,
"routing_context_cancel_dht_watch", 'routing_context_cancel_dht_watch',
[_ctx.id!, jsonEncode(key), jsonEncode(subkeys)])); [id, jsonEncode(key), jsonEncode(subkeys)]));
} }
} }
// JS implementation of VeilidCryptoSystem // JS implementation of VeilidCryptoSystem
class VeilidCryptoSystemJS extends VeilidCryptoSystem { class VeilidCryptoSystemJS extends VeilidCryptoSystem {
VeilidCryptoSystemJS._(this._js, this._kind);
final CryptoKind _kind; final CryptoKind _kind;
// Keep the reference
// ignore: unused_field
final VeilidJS _js; final VeilidJS _js;
VeilidCryptoSystemJS._(this._js, this._kind) { @override
// Keep the reference CryptoKind kind() => _kind;
_js;
}
@override @override
CryptoKind kind() { Future<SharedSecret> cachedDH(PublicKey key, SecretKey secret) async =>
return _kind; SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
} wasm,
'crypto_cached_dh',
[_kind, jsonEncode(key), jsonEncode(secret)]))));
@override @override
Future<SharedSecret> cachedDH(PublicKey key, SecretKey secret) async { Future<SharedSecret> computeDH(PublicKey key, SecretKey secret) async =>
return SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
.callMethod(wasm, "crypto_cached_dh", wasm,
[_kind, jsonEncode(key), jsonEncode(secret)])))); 'crypto_compute_dh',
} [_kind, jsonEncode(key), jsonEncode(secret)]))));
@override @override
Future<SharedSecret> computeDH(PublicKey key, SecretKey secret) async { Future<Uint8List> randomBytes(int len) async =>
return SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util base64UrlNoPadDecode(await _wrapApiPromise(
.callMethod(wasm, "crypto_compute_dh", js_util.callMethod(wasm, 'crypto_random_bytes', [_kind, len])));
[_kind, jsonEncode(key), jsonEncode(secret)]))));
}
@override @override
Future<Uint8List> randomBytes(int len) async { Future<int> defaultSaltLength() => _wrapApiPromise(
return base64UrlNoPadDecode(await _wrapApiPromise( js_util.callMethod(wasm, 'crypto_default_salt_length', [_kind]));
js_util.callMethod(wasm, "crypto_random_bytes", [_kind, len])));
}
@override @override
Future<int> defaultSaltLength() { Future<String> hashPassword(Uint8List password, Uint8List salt) =>
return _wrapApiPromise( _wrapApiPromise(js_util.callMethod(wasm, 'crypto_hash_password',
js_util.callMethod(wasm, "crypto_default_salt_length", [_kind])); [_kind, base64UrlNoPadEncode(password), base64UrlNoPadEncode(salt)]));
}
@override @override
Future<String> hashPassword(Uint8List password, Uint8List salt) { Future<bool> verifyPassword(Uint8List password, String passwordHash) =>
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_hash_password", _wrapApiPromise(js_util.callMethod(wasm, 'crypto_verify_password',
[_kind, base64UrlNoPadEncode(password), base64UrlNoPadEncode(salt)])); [_kind, base64UrlNoPadEncode(password), passwordHash]));
}
@override
Future<bool> verifyPassword(Uint8List password, String passwordHash) {
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_verify_password",
[_kind, base64UrlNoPadEncode(password), passwordHash]));
}
@override @override
Future<SharedSecret> deriveSharedSecret( Future<SharedSecret> deriveSharedSecret(
Uint8List password, Uint8List salt) async { Uint8List password, Uint8List salt) async =>
return SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
.callMethod(wasm, "crypto_derive_shared_secret", [ wasm, 'crypto_derive_shared_secret', [
_kind, _kind,
base64UrlNoPadEncode(password), base64UrlNoPadEncode(password),
base64UrlNoPadEncode(salt) base64UrlNoPadEncode(salt)
])))); ]))));
}
@override @override
Future<Nonce> randomNonce() async { Future<Nonce> randomNonce() async =>
return Nonce.fromJson(jsonDecode(await _wrapApiPromise( Nonce.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "crypto_random_nonce", [_kind])))); js_util.callMethod(wasm, 'crypto_random_nonce', [_kind]))));
}
@override @override
Future<SharedSecret> randomSharedSecret() async { Future<SharedSecret> randomSharedSecret() async =>
return SharedSecret.fromJson(jsonDecode(await _wrapApiPromise( SharedSecret.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "crypto_random_shared_secret", [_kind])))); js_util.callMethod(wasm, 'crypto_random_shared_secret', [_kind]))));
}
@override @override
Future<KeyPair> generateKeyPair() async { Future<KeyPair> generateKeyPair() async =>
return KeyPair.fromJson(jsonDecode(await _wrapApiPromise( KeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "crypto_generate_key_pair", [_kind])))); js_util.callMethod(wasm, 'crypto_generate_key_pair', [_kind]))));
}
@override @override
Future<HashDigest> generateHash(Uint8List data) async { Future<HashDigest> generateHash(Uint8List data) async =>
return HashDigest.fromJson(jsonDecode(await _wrapApiPromise(js_util HashDigest.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
.callMethod(wasm, "crypto_generate_hash", wasm, 'crypto_generate_hash', [_kind, base64UrlNoPadEncode(data)]))));
[_kind, base64UrlNoPadEncode(data)]))));
}
@override @override
Future<bool> validateKeyPair(PublicKey key, SecretKey secret) { Future<bool> validateKeyPair(PublicKey key, SecretKey secret) =>
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_validate_key_pair", _wrapApiPromise(js_util.callMethod(wasm, 'crypto_validate_key_pair',
[_kind, jsonEncode(key), jsonEncode(secret)])); [_kind, jsonEncode(key), jsonEncode(secret)]));
}
@override @override
Future<bool> validateHash(Uint8List data, HashDigest hash) { Future<bool> validateHash(Uint8List data, HashDigest hash) =>
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_validate_hash", _wrapApiPromise(js_util.callMethod(wasm, 'crypto_validate_hash',
[_kind, base64UrlNoPadEncode(data), jsonEncode(hash)])); [_kind, base64UrlNoPadEncode(data), jsonEncode(hash)]));
}
@override @override
Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2) async { Future<CryptoKeyDistance> distance(CryptoKey key1, CryptoKey key2) async =>
return CryptoKeyDistance.fromJson(jsonDecode(await _wrapApiPromise(js_util CryptoKeyDistance.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod(wasm, "crypto_distance", .callMethod(wasm, 'crypto_distance',
[_kind, jsonEncode(key1), jsonEncode(key2)])))); [_kind, jsonEncode(key1), jsonEncode(key2)]))));
}
@override @override
Future<Signature> sign( Future<Signature> sign(
PublicKey key, SecretKey secret, Uint8List data) async { PublicKey key, SecretKey secret, Uint8List data) async =>
return Signature.fromJson(jsonDecode(await _wrapApiPromise(js_util Signature.fromJson(jsonDecode(await _wrapApiPromise(js_util.callMethod(
.callMethod(wasm, "crypto_sign", [ wasm, 'crypto_sign', [
_kind, _kind,
jsonEncode(key), jsonEncode(key),
jsonEncode(secret), jsonEncode(secret),
base64UrlNoPadEncode(data) base64UrlNoPadEncode(data)
])))); ]))));
}
@override @override
Future<void> verify(PublicKey key, Uint8List data, Signature signature) { Future<void> verify(PublicKey key, Uint8List data, Signature signature) =>
return _wrapApiPromise(js_util.callMethod(wasm, "crypto_verify", [ _wrapApiPromise(js_util.callMethod(wasm, 'crypto_verify', [
_kind, _kind,
jsonEncode(key), jsonEncode(key),
base64UrlNoPadEncode(data), base64UrlNoPadEncode(data),
jsonEncode(signature), jsonEncode(signature),
])); ]));
}
@override @override
Future<int> aeadOverhead() { Future<int> aeadOverhead() => _wrapApiPromise(
return _wrapApiPromise( js_util.callMethod(wasm, 'crypto_aead_overhead', [_kind]));
js_util.callMethod(wasm, "crypto_aead_overhead", [_kind]));
}
@override @override
Future<Uint8List> decryptAead(Uint8List body, Nonce nonce, Future<Uint8List> decryptAead(Uint8List body, Nonce nonce,
SharedSecret sharedSecret, Uint8List? associatedData) async { SharedSecret sharedSecret, Uint8List? associatedData) async =>
return base64UrlNoPadDecode( base64UrlNoPadDecode(await _wrapApiPromise(
await _wrapApiPromise(js_util.callMethod(wasm, "crypto_decrypt_aead", [ js_util.callMethod(wasm, 'crypto_decrypt_aead', [
_kind, _kind,
base64UrlNoPadEncode(body), base64UrlNoPadEncode(body),
jsonEncode(nonce), jsonEncode(nonce),
jsonEncode(sharedSecret), jsonEncode(sharedSecret),
associatedData != null ? base64UrlNoPadEncode(associatedData) : null if (associatedData != null)
]))); base64UrlNoPadEncode(associatedData)
} else
null
])));
@override @override
Future<Uint8List> encryptAead(Uint8List body, Nonce nonce, Future<Uint8List> encryptAead(Uint8List body, Nonce nonce,
SharedSecret sharedSecret, Uint8List? associatedData) async { SharedSecret sharedSecret, Uint8List? associatedData) async =>
return base64UrlNoPadDecode( base64UrlNoPadDecode(await _wrapApiPromise(
await _wrapApiPromise(js_util.callMethod(wasm, "crypto_encrypt_aead", [ js_util.callMethod(wasm, 'crypto_encrypt_aead', [
_kind, _kind,
base64UrlNoPadEncode(body), base64UrlNoPadEncode(body),
jsonEncode(nonce), jsonEncode(nonce),
jsonEncode(sharedSecret), jsonEncode(sharedSecret),
associatedData != null ? base64UrlNoPadEncode(associatedData) : null if (associatedData != null)
]))); base64UrlNoPadEncode(associatedData)
} else
null
])));
@override @override
Future<Uint8List> cryptNoAuth( Future<Uint8List> cryptNoAuth(
Uint8List body, Nonce nonce, SharedSecret sharedSecret) async { Uint8List body, Nonce nonce, SharedSecret sharedSecret) async =>
return base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod( base64UrlNoPadDecode(await _wrapApiPromise(js_util.callMethod(
wasm, "crypto_crypt_no_auth", [ wasm, 'crypto_crypt_no_auth', [
_kind, _kind,
base64UrlNoPadEncode(body), base64UrlNoPadEncode(body),
jsonEncode(nonce), jsonEncode(nonce),
jsonEncode(sharedSecret) jsonEncode(sharedSecret)
]))); ])));
}
} }
class _TDBT { class _TDBT {
_TDBT(this.id, this.tdbjs, this.js);
int? id; int? id;
final VeilidTableDBJS tdbjs; final VeilidTableDBJS tdbjs;
final VeilidJS js; final VeilidJS js;
_TDBT(this.id, this.tdbjs, this.js);
void ensureValid() { void ensureValid() {
if (id == null) { if (id == null) {
throw VeilidAPIExceptionNotInitialized(); throw VeilidAPIExceptionNotInitialized();
@ -369,7 +351,7 @@ class _TDBT {
void close() { void close() {
if (id != null) { if (id != null) {
js_util.callMethod(wasm, "release_table_db_transaction", [id!]); js_util.callMethod<void>(wasm, 'release_table_db_transaction', [id]);
id = null; id = null;
} }
} }
@ -377,81 +359,83 @@ class _TDBT {
// JS implementation of VeilidTableDBTransaction // JS implementation of VeilidTableDBTransaction
class VeilidTableDBTransactionJS extends VeilidTableDBTransaction { class VeilidTableDBTransactionJS extends VeilidTableDBTransaction {
final _TDBT _tdbt;
static final Finalizer<_TDBT> _finalizer = Finalizer((tdbt) => tdbt.close());
VeilidTableDBTransactionJS._(this._tdbt) { VeilidTableDBTransactionJS._(this._tdbt) {
_finalizer.attach(this, _tdbt, detach: this); _finalizer.attach(this, _tdbt, detach: this);
} }
final _TDBT _tdbt;
static final Finalizer<_TDBT> _finalizer = Finalizer((tdbt) => tdbt.close());
@override @override
bool isDone() { bool isDone() => _tdbt.id == null;
return _tdbt.id == null;
}
@override @override
Future<void> commit() async { Future<void> commit() async {
_tdbt.ensureValid(); _tdbt.ensureValid();
await _wrapApiPromise( final id = _tdbt.id!;
js_util.callMethod(wasm, "table_db_transaction_commit", [_tdbt.id!])); await _wrapApiPromise<void>(
js_util.callMethod(wasm, 'table_db_transaction_commit', [id]));
_tdbt.close(); _tdbt.close();
} }
@override @override
Future<void> rollback() async { Future<void> rollback() async {
_tdbt.ensureValid(); _tdbt.ensureValid();
await _wrapApiPromise( final id = _tdbt.id!;
js_util.callMethod(wasm, "table_db_transaction_rollback", [_tdbt.id!])); await _wrapApiPromise<void>(
js_util.callMethod(wasm, 'table_db_transaction_rollback', [id]));
_tdbt.close(); _tdbt.close();
} }
@override @override
Future<void> store(int col, Uint8List key, Uint8List value) async { Future<void> store(int col, Uint8List key, Uint8List value) async {
_tdbt.ensureValid(); _tdbt.ensureValid();
final id = _tdbt.id!;
final encodedKey = base64UrlNoPadEncode(key); final encodedKey = base64UrlNoPadEncode(key);
final encodedValue = base64UrlNoPadEncode(value); final encodedValue = base64UrlNoPadEncode(value);
await _wrapApiPromise(js_util.callMethod(wasm, "table_db_transaction_store", await _wrapApiPromise<void>(js_util.callMethod(wasm,
[_tdbt.id!, col, encodedKey, encodedValue])); 'table_db_transaction_store', [id, col, encodedKey, encodedValue]));
} }
@override @override
Future<void> delete(int col, Uint8List key) async { Future<void> delete(int col, Uint8List key) async {
_tdbt.ensureValid(); _tdbt.ensureValid();
final id = _tdbt.id!;
final encodedKey = base64UrlNoPadEncode(key); final encodedKey = base64UrlNoPadEncode(key);
await _wrapApiPromise(js_util.callMethod( await _wrapApiPromise<void>(js_util.callMethod(
wasm, "table_db_transaction_delete", [_tdbt.id!, col, encodedKey])); wasm, 'table_db_transaction_delete', [id, col, encodedKey]));
} }
} }
class _TDB { class _TDB {
int? id; _TDB(int id, this.js) : _id = id;
final VeilidJS js;
_TDB(int this.id, this.js); int? _id;
void ensureValid() {
if (id == null) { final VeilidJS js;
int requireId() {
if (_id == null) {
throw VeilidAPIExceptionNotInitialized(); throw VeilidAPIExceptionNotInitialized();
} }
return _id!;
} }
void close() { void close() {
if (id != null) { if (_id != null) {
js_util.callMethod(wasm, "release_table_db", [id!]); js_util.callMethod<void>(wasm, 'release_table_db', [_id]);
id = null; _id = null;
} }
} }
} }
// JS implementation of VeilidTableDB // JS implementation of VeilidTableDB
class VeilidTableDBJS extends VeilidTableDB { class VeilidTableDBJS extends VeilidTableDB {
final _TDB _tdb;
static final Finalizer<_TDB> _finalizer = Finalizer((tdb) => tdb.close());
VeilidTableDBJS._(this._tdb) { VeilidTableDBJS._(this._tdb) {
_finalizer.attach(this, _tdb, detach: this); _finalizer.attach(this, _tdb, detach: this);
} }
final _TDB _tdb;
static final Finalizer<_TDB> _finalizer = Finalizer((tdb) => tdb.close());
@override @override
void close() { void close() {
@ -460,42 +444,42 @@ class VeilidTableDBJS extends VeilidTableDB {
@override @override
int getColumnCount() { int getColumnCount() {
_tdb.ensureValid(); final id = _tdb.requireId();
return js_util.callMethod(wasm, "table_db_get_column_count", [_tdb.id!]); return js_util.callMethod(wasm, 'table_db_get_column_count', [id]);
} }
@override @override
Future<List<Uint8List>> getKeys(int col) async { Future<List<Uint8List>> getKeys(int col) async {
_tdb.ensureValid(); final id = _tdb.requireId();
return jsonListConstructor(base64UrlNoPadDecodeDynamic)(jsonDecode( return jsonListConstructor(base64UrlNoPadDecodeDynamic)(jsonDecode(
await js_util.callMethod(wasm, "table_db_get_keys", [_tdb.id!, col]))); await js_util.callMethod(wasm, 'table_db_get_keys', [id, col])));
} }
@override @override
VeilidTableDBTransaction transact() { VeilidTableDBTransaction transact() {
_tdb.ensureValid(); final id = _tdb.requireId();
final id = js_util.callMethod(wasm, "table_db_transact", [_tdb.id!]); final xid = js_util.callMethod<int>(wasm, 'table_db_transact', [id]);
return VeilidTableDBTransactionJS._(_TDBT(id, this, _tdb.js)); return VeilidTableDBTransactionJS._(_TDBT(xid, this, _tdb.js));
} }
@override @override
Future<void> store(int col, Uint8List key, Uint8List value) { Future<void> store(int col, Uint8List key, Uint8List value) {
_tdb.ensureValid(); final id = _tdb.requireId();
final encodedKey = base64UrlNoPadEncode(key); final encodedKey = base64UrlNoPadEncode(key);
final encodedValue = base64UrlNoPadEncode(value); final encodedValue = base64UrlNoPadEncode(value);
return _wrapApiPromise(js_util.callMethod( return _wrapApiPromise(js_util.callMethod(
wasm, "table_db_store", [_tdb.id!, col, encodedKey, encodedValue])); wasm, 'table_db_store', [id, col, encodedKey, encodedValue]));
} }
@override @override
Future<Uint8List?> load(int col, Uint8List key) async { Future<Uint8List?> load(int col, Uint8List key) async {
_tdb.ensureValid(); final id = _tdb.requireId();
final encodedKey = base64UrlNoPadEncode(key); final encodedKey = base64UrlNoPadEncode(key);
String? out = await _wrapApiPromise( final out = await _wrapApiPromise<String?>(
js_util.callMethod(wasm, "table_db_load", [_tdb.id!, col, encodedKey])); js_util.callMethod(wasm, 'table_db_load', [id, col, encodedKey]));
if (out == null) { if (out == null) {
return null; return null;
} }
@ -503,12 +487,16 @@ class VeilidTableDBJS extends VeilidTableDB {
} }
@override @override
Future<Uint8List?> delete(int col, Uint8List key) { Future<Uint8List?> delete(int col, Uint8List key) async {
_tdb.ensureValid(); final id = _tdb.requireId();
final encodedKey = base64UrlNoPadEncode(key); final encodedKey = base64UrlNoPadEncode(key);
return _wrapApiPromise(js_util final out = await _wrapApiPromise<String?>(
.callMethod(wasm, "table_db_delete", [_tdb.id!, col, encodedKey])); js_util.callMethod(wasm, 'table_db_delete', [id, col, encodedKey]));
if (out == null) {
return null;
}
return base64UrlNoPadDecode(out);
} }
} }
@ -517,178 +505,164 @@ class VeilidTableDBJS extends VeilidTableDB {
class VeilidJS extends Veilid { class VeilidJS extends Veilid {
@override @override
void initializeVeilidCore(Map<String, dynamic> platformConfigJson) { void initializeVeilidCore(Map<String, dynamic> platformConfigJson) {
var platformConfigJsonString = jsonEncode(platformConfigJson); final platformConfigJsonString = jsonEncode(platformConfigJson);
js_util js_util.callMethod<void>(
.callMethod(wasm, "initialize_veilid_core", [platformConfigJsonString]); wasm, 'initialize_veilid_core', [platformConfigJsonString]);
} }
@override @override
void changeLogLevel(String layer, VeilidConfigLogLevel logLevel) { void changeLogLevel(String layer, VeilidConfigLogLevel logLevel) {
var logLevelJsonString = jsonEncode(logLevel); final logLevelJsonString = jsonEncode(logLevel);
js_util.callMethod(wasm, "change_log_level", [layer, logLevelJsonString]); js_util.callMethod<void>(
wasm, 'change_log_level', [layer, logLevelJsonString]);
} }
@override @override
Future<Stream<VeilidUpdate>> startupVeilidCore(VeilidConfig config) async { Future<Stream<VeilidUpdate>> startupVeilidCore(VeilidConfig config) async {
var streamController = StreamController<VeilidUpdate>(); final streamController = StreamController<VeilidUpdate>();
updateCallback(String update) { void updateCallback(String update) {
var updateJson = jsonDecode(update); final updateJson = jsonDecode(update) as Map<String, dynamic>;
if (updateJson["kind"] == "Shutdown") { if (updateJson['kind'] == 'Shutdown') {
streamController.close(); unawaited(streamController.close());
} else { } else {
var update = VeilidUpdate.fromJson(updateJson); final update = VeilidUpdate.fromJson(updateJson);
streamController.add(update); streamController.add(update);
} }
} }
await _wrapApiPromise(js_util.callMethod(wasm, "startup_veilid_core", await _wrapApiPromise<void>(js_util.callMethod(wasm, 'startup_veilid_core',
[js.allowInterop(updateCallback), jsonEncode(config)])); [js.allowInterop(updateCallback), jsonEncode(config)]));
return streamController.stream; return streamController.stream;
} }
@override @override
Future<VeilidState> getVeilidState() async { Future<VeilidState> getVeilidState() async =>
return VeilidState.fromJson(jsonDecode(await _wrapApiPromise( VeilidState.fromJson(jsonDecode(await _wrapApiPromise<String>(
js_util.callMethod(wasm, "get_veilid_state", [])))); js_util.callMethod(wasm, 'get_veilid_state', []))));
}
@override @override
Future<void> attach() { Future<void> attach() =>
return _wrapApiPromise(js_util.callMethod(wasm, "attach", [])); _wrapApiPromise(js_util.callMethod(wasm, 'attach', []));
}
@override @override
Future<void> detach() { Future<void> detach() =>
return _wrapApiPromise(js_util.callMethod(wasm, "detach", [])); _wrapApiPromise(js_util.callMethod(wasm, 'detach', []));
}
@override @override
Future<void> shutdownVeilidCore() { Future<void> shutdownVeilidCore() =>
return _wrapApiPromise( _wrapApiPromise(js_util.callMethod(wasm, 'shutdown_veilid_core', []));
js_util.callMethod(wasm, "shutdown_veilid_core", []));
}
@override @override
List<CryptoKind> validCryptoKinds() { List<CryptoKind> validCryptoKinds() {
return jsonDecode(js_util.callMethod(wasm, "valid_crypto_kinds", [])); final vck = jsonDecode(js_util.callMethod(wasm, 'valid_crypto_kinds', []))
as List<dynamic>;
return vck.map((v) => v as CryptoKind).toList();
} }
@override @override
Future<VeilidCryptoSystem> getCryptoSystem(CryptoKind kind) async { Future<VeilidCryptoSystem> getCryptoSystem(CryptoKind kind) async {
if (!validCryptoKinds().contains(kind)) { if (!validCryptoKinds().contains(kind)) {
throw VeilidAPIExceptionGeneric("unsupported cryptosystem"); throw const VeilidAPIExceptionGeneric('unsupported cryptosystem');
} }
return VeilidCryptoSystemJS._(this, kind); return VeilidCryptoSystemJS._(this, kind);
} }
@override @override
Future<VeilidCryptoSystem> bestCryptoSystem() async { Future<VeilidCryptoSystem> bestCryptoSystem() async => VeilidCryptoSystemJS._(
return VeilidCryptoSystemJS._( this, js_util.callMethod(wasm, 'best_crypto_kind', []));
this, js_util.callMethod(wasm, "best_crypto_kind", []));
}
@override @override
Future<List<TypedKey>> verifySignatures(List<TypedKey> nodeIds, Future<List<TypedKey>> verifySignatures(List<TypedKey> nodeIds,
Uint8List data, List<TypedSignature> signatures) async { Uint8List data, List<TypedSignature> signatures) async =>
return jsonListConstructor(TypedKey.fromJson)(jsonDecode( jsonListConstructor(TypedKey.fromJson)(jsonDecode(await _wrapApiPromise(
await _wrapApiPromise(js_util.callMethod(wasm, "verify_signatures", [ js_util.callMethod(wasm, 'verify_signatures', [
jsonEncode(nodeIds), jsonEncode(nodeIds),
base64UrlNoPadEncode(data), base64UrlNoPadEncode(data),
jsonEncode(signatures) jsonEncode(signatures)
])))); ]))));
}
@override @override
Future<List<TypedSignature>> generateSignatures( Future<List<TypedSignature>> generateSignatures(
Uint8List data, List<TypedKeyPair> keyPairs) async { Uint8List data, List<TypedKeyPair> keyPairs) async =>
return jsonListConstructor(TypedSignature.fromJson)(jsonDecode( jsonListConstructor(TypedSignature.fromJson)(jsonDecode(
await _wrapApiPromise(js_util.callMethod(wasm, "generate_signatures", await _wrapApiPromise(js_util.callMethod(wasm, 'generate_signatures',
[base64UrlNoPadEncode(data), jsonEncode(keyPairs)])))); [base64UrlNoPadEncode(data), jsonEncode(keyPairs)]))));
}
@override @override
Future<TypedKeyPair> generateKeyPair(CryptoKind kind) async { Future<TypedKeyPair> generateKeyPair(CryptoKind kind) async =>
return TypedKeyPair.fromJson(jsonDecode(await _wrapApiPromise( TypedKeyPair.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "generate_key_pair", [kind])))); js_util.callMethod(wasm, 'generate_key_pair', [kind]))));
}
@override @override
Future<VeilidRoutingContext> routingContext() async { Future<VeilidRoutingContext> routingContext() async {
int id = final rcid = await _wrapApiPromise<int>(
await _wrapApiPromise(js_util.callMethod(wasm, "routing_context", [])); js_util.callMethod(wasm, 'routing_context', []));
return VeilidRoutingContextJS._(_Ctx(id, this)); return VeilidRoutingContextJS._(_Ctx(rcid, this));
} }
@override @override
Future<RouteBlob> newPrivateRoute() async { Future<RouteBlob> newPrivateRoute() async =>
return RouteBlob.fromJson(jsonDecode(await _wrapApiPromise( RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(
js_util.callMethod(wasm, "new_private_route", [])))); js_util.callMethod(wasm, 'new_private_route', []))));
}
@override @override
Future<RouteBlob> newCustomPrivateRoute( Future<RouteBlob> newCustomPrivateRoute(
Stability stability, Sequencing sequencing) async { Stability stability, Sequencing sequencing) async {
var stabilityString = jsonEncode(stability); final stabilityString = jsonEncode(stability);
var sequencingString = jsonEncode(sequencing); final sequencingString = jsonEncode(sequencing);
return RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(js_util return RouteBlob.fromJson(jsonDecode(await _wrapApiPromise(js_util
.callMethod( .callMethod(
wasm, "new_private_route", [stabilityString, sequencingString])))); wasm, 'new_private_route', [stabilityString, sequencingString]))));
} }
@override @override
Future<String> importRemotePrivateRoute(Uint8List blob) { Future<String> importRemotePrivateRoute(Uint8List blob) {
var encodedBlob = base64UrlNoPadEncode(blob); final encodedBlob = base64UrlNoPadEncode(blob);
return _wrapApiPromise( return _wrapApiPromise(
js_util.callMethod(wasm, "import_remote_private_route", [encodedBlob])); js_util.callMethod(wasm, 'import_remote_private_route', [encodedBlob]));
} }
@override @override
Future<void> releasePrivateRoute(String key) { Future<void> releasePrivateRoute(String key) =>
return _wrapApiPromise( _wrapApiPromise(js_util.callMethod(wasm, 'release_private_route', [key]));
js_util.callMethod(wasm, "release_private_route", [key]));
}
@override @override
Future<void> appCallReply(String callId, Uint8List message) { Future<void> appCallReply(String callId, Uint8List message) {
var encodedMessage = base64UrlNoPadEncode(message); final encodedMessage = base64UrlNoPadEncode(message);
return _wrapApiPromise( return _wrapApiPromise(
js_util.callMethod(wasm, "app_call_reply", [callId, encodedMessage])); js_util.callMethod(wasm, 'app_call_reply', [callId, encodedMessage]));
} }
@override @override
Future<VeilidTableDB> openTableDB(String name, int columnCount) async { Future<VeilidTableDB> openTableDB(String name, int columnCount) async {
int id = await _wrapApiPromise( final dbid = await _wrapApiPromise<int>(
js_util.callMethod(wasm, "open_table_db", [name, columnCount])); js_util.callMethod(wasm, 'open_table_db', [name, columnCount]));
return VeilidTableDBJS._(_TDB(id, this)); return VeilidTableDBJS._(_TDB(dbid, this));
} }
@override @override
Future<bool> deleteTableDB(String name) { Future<bool> deleteTableDB(String name) =>
return _wrapApiPromise(js_util.callMethod(wasm, "delete_table_db", [name])); _wrapApiPromise(js_util.callMethod(wasm, 'delete_table_db', [name]));
}
@override @override
Timestamp now() { Timestamp now() => Timestamp.fromString(js_util.callMethod(wasm, 'now', []));
return Timestamp.fromString(js_util.callMethod(wasm, "now", []));
}
@override @override
Future<String> debug(String command) async { Future<String> debug(String command) async =>
return await _wrapApiPromise(js_util.callMethod(wasm, "debug", [command])); _wrapApiPromise(js_util.callMethod(wasm, 'debug', [command]));
}
@override @override
String veilidVersionString() { String veilidVersionString() =>
return js_util.callMethod(wasm, "veilid_version_string", []); js_util.callMethod(wasm, 'veilid_version_string', []);
}
@override @override
VeilidVersion veilidVersion() { VeilidVersion veilidVersion() {
Map<String, dynamic> jsonVersion = final jsonVersion =
jsonDecode(js_util.callMethod(wasm, "veilid_version", [])); jsonDecode(js_util.callMethod(wasm, 'veilid_version', []))
return VeilidVersion( as Map<String, dynamic>;
jsonVersion["major"], jsonVersion["minor"], jsonVersion["patch"]); return VeilidVersion(jsonVersion['major'] as int,
jsonVersion['minor'] as int, jsonVersion['patch'] as int);
} }
} }

View File

@ -11,7 +11,7 @@ class VeilidPluginStubWeb {
Future<dynamic> handleMethodCall(MethodCall call) async { Future<dynamic> handleMethodCall(MethodCall call) async {
throw PlatformException( throw PlatformException(
code: 'Unimplemented', code: 'Unimplemented',
details: 'Veilid for Web doesn\'t implement \'${call.method}\'', details: "Veilid for Web doesn't implement '${call.method}'",
); );
} }
} }

View File

@ -21,9 +21,10 @@ enum AttachmentState {
overAttached, overAttached,
detaching; detaching;
factory AttachmentState.fromJson(dynamic j) =>
AttachmentState.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase(); String toJson() => name.toPascalCase();
factory AttachmentState.fromJson(String j) =>
AttachmentState.values.byName(j.toCamelCase());
} }
////////////////////////////////////// //////////////////////////////////////
@ -36,9 +37,10 @@ enum VeilidLogLevel {
debug, debug,
trace; trace;
factory VeilidLogLevel.fromJson(dynamic j) =>
VeilidLogLevel.values.byName((j as String).toCamelCase());
String toJson() => name.toPascalCase(); String toJson() => name.toPascalCase();
factory VeilidLogLevel.fromJson(String j) =>
VeilidLogLevel.values.byName(j.toCamelCase());
} }
//////////// ////////////
@ -51,8 +53,8 @@ class LatencyStats with _$LatencyStats {
required TimestampDuration slowest, required TimestampDuration slowest,
}) = _LatencyStats; }) = _LatencyStats;
factory LatencyStats.fromJson(Map<String, dynamic> json) => factory LatencyStats.fromJson(dynamic json) =>
_$LatencyStatsFromJson(json); _$LatencyStatsFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -66,8 +68,8 @@ class TransferStats with _$TransferStats {
required BigInt minimum, required BigInt minimum,
}) = _TransferStats; }) = _TransferStats;
factory TransferStats.fromJson(Map<String, dynamic> json) => factory TransferStats.fromJson(dynamic json) =>
_$TransferStatsFromJson(json); _$TransferStatsFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -79,8 +81,8 @@ class TransferStatsDownUp with _$TransferStatsDownUp {
required TransferStats up, required TransferStats up,
}) = _TransferStatsDownUp; }) = _TransferStatsDownUp;
factory TransferStatsDownUp.fromJson(Map<String, dynamic> json) => factory TransferStatsDownUp.fromJson(dynamic json) =>
_$TransferStatsDownUpFromJson(json); _$TransferStatsDownUpFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -98,8 +100,8 @@ class RPCStats with _$RPCStats {
required int failedToSend, required int failedToSend,
}) = _RPCStats; }) = _RPCStats;
factory RPCStats.fromJson(Map<String, dynamic> json) => factory RPCStats.fromJson(dynamic json) =>
_$RPCStatsFromJson(json); _$RPCStatsFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -109,12 +111,12 @@ class PeerStats with _$PeerStats {
const factory PeerStats({ const factory PeerStats({
required Timestamp timeAdded, required Timestamp timeAdded,
required RPCStats rpcStats, required RPCStats rpcStats,
LatencyStats? latency,
required TransferStatsDownUp transfer, required TransferStatsDownUp transfer,
LatencyStats? latency,
}) = _PeerStats; }) = _PeerStats;
factory PeerStats.fromJson(Map<String, dynamic> json) => factory PeerStats.fromJson(dynamic json) =>
_$PeerStatsFromJson(json); _$PeerStatsFromJson(json as Map<String, dynamic>);
} }
//////////// ////////////
@ -127,8 +129,8 @@ class PeerTableData with _$PeerTableData {
required PeerStats peerStats, required PeerStats peerStats,
}) = _PeerTableData; }) = _PeerTableData;
factory PeerTableData.fromJson(Map<String, dynamic> json) => factory PeerTableData.fromJson(dynamic json) =>
_$PeerTableDataFromJson(json); _$PeerTableDataFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -142,13 +144,13 @@ sealed class VeilidUpdate with _$VeilidUpdate {
String? backtrace, String? backtrace,
}) = VeilidLog; }) = VeilidLog;
const factory VeilidUpdate.appMessage({ const factory VeilidUpdate.appMessage({
TypedKey? sender,
@Uint8ListJsonConverter() required Uint8List message, @Uint8ListJsonConverter() required Uint8List message,
TypedKey? sender,
}) = VeilidAppMessage; }) = VeilidAppMessage;
const factory VeilidUpdate.appCall({ const factory VeilidUpdate.appCall({
TypedKey? sender,
@Uint8ListJsonConverter() required Uint8List message, @Uint8ListJsonConverter() required Uint8List message,
required String callId, required String callId,
TypedKey? sender,
}) = VeilidAppCall; }) = VeilidAppCall;
const factory VeilidUpdate.attachment( const factory VeilidUpdate.attachment(
{required AttachmentState state, {required AttachmentState state,
@ -173,8 +175,8 @@ sealed class VeilidUpdate with _$VeilidUpdate {
required ValueData valueData, required ValueData valueData,
}) = VeilidUpdateValueChange; }) = VeilidUpdateValueChange;
factory VeilidUpdate.fromJson(Map<String, dynamic> json) => factory VeilidUpdate.fromJson(dynamic json) =>
_$VeilidUpdateFromJson(json); _$VeilidUpdateFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -187,8 +189,8 @@ class VeilidStateAttachment with _$VeilidStateAttachment {
required bool publicInternetReady, required bool publicInternetReady,
required bool localNetworkReady}) = _VeilidStateAttachment; required bool localNetworkReady}) = _VeilidStateAttachment;
factory VeilidStateAttachment.fromJson(Map<String, dynamic> json) => factory VeilidStateAttachment.fromJson(dynamic json) =>
_$VeilidStateAttachmentFromJson(json); _$VeilidStateAttachmentFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -202,8 +204,8 @@ class VeilidStateNetwork with _$VeilidStateNetwork {
required BigInt bpsUp, required BigInt bpsUp,
required List<PeerTableData> peers}) = _VeilidStateNetwork; required List<PeerTableData> peers}) = _VeilidStateNetwork;
factory VeilidStateNetwork.fromJson(Map<String, dynamic> json) => factory VeilidStateNetwork.fromJson(dynamic json) =>
_$VeilidStateNetworkFromJson(json); _$VeilidStateNetworkFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -215,8 +217,8 @@ class VeilidStateConfig with _$VeilidStateConfig {
required VeilidConfig config, required VeilidConfig config,
}) = _VeilidStateConfig; }) = _VeilidStateConfig;
factory VeilidStateConfig.fromJson(Map<String, dynamic> json) => factory VeilidStateConfig.fromJson(dynamic json) =>
_$VeilidStateConfigFromJson(json); _$VeilidStateConfigFromJson(json as Map<String, dynamic>);
} }
////////////////////////////////////// //////////////////////////////////////
@ -230,6 +232,6 @@ class VeilidState with _$VeilidState {
required VeilidStateConfig config, required VeilidStateConfig config,
}) = _VeilidState; }) = _VeilidState;
factory VeilidState.fromJson(Map<String, dynamic> json) => factory VeilidState.fromJson(dynamic json) =>
_$VeilidStateFromJson(json); _$VeilidStateFromJson(json as Map<String, dynamic>);
} }

View File

@ -1,6 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data';
import 'dart:convert'; import 'dart:convert';
import 'dart:typed_data';
///////////////////////////////////// /////////////////////////////////////
/// VeilidTableDB /// VeilidTableDB
@ -12,16 +12,14 @@ abstract class VeilidTableDBTransaction {
Future<void> delete(int col, Uint8List key); Future<void> delete(int col, Uint8List key);
Future<void> storeJson(int col, Uint8List key, Object? object, Future<void> storeJson(int col, Uint8List key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) async { {Object? Function(Object? nonEncodable)? toEncodable}) async =>
return store(col, key, store(col, key,
utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable))); utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable)));
}
Future<void> storeStringJson(int col, String key, Object? object, Future<void> storeStringJson(int col, String key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) { {Object? Function(Object? nonEncodable)? toEncodable}) =>
return storeJson(col, utf8.encoder.convert(key), object, storeJson(col, utf8.encoder.convert(key), object,
toEncodable: toEncodable); toEncodable: toEncodable);
}
} }
abstract class VeilidTableDB { abstract class VeilidTableDB {
@ -34,20 +32,18 @@ abstract class VeilidTableDB {
Future<Uint8List?> delete(int col, Uint8List key); Future<Uint8List?> delete(int col, Uint8List key);
Future<void> storeJson(int col, Uint8List key, Object? object, Future<void> storeJson(int col, Uint8List key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) { {Object? Function(Object? nonEncodable)? toEncodable}) =>
return store(col, key, store(col, key,
utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable))); utf8.encoder.convert(jsonEncode(object, toEncodable: toEncodable)));
}
Future<void> storeStringJson(int col, String key, Object? object, Future<void> storeStringJson(int col, String key, Object? object,
{Object? Function(Object? nonEncodable)? toEncodable}) { {Object? Function(Object? nonEncodable)? toEncodable}) =>
return storeJson(col, utf8.encoder.convert(key), object, storeJson(col, utf8.encoder.convert(key), object,
toEncodable: toEncodable); toEncodable: toEncodable);
}
Future<Object?> loadJson(int col, Uint8List key, Future<Object?> loadJson(int col, Uint8List key,
{Object? Function(Object? key, Object? value)? reviver}) async { {Object? Function(Object? key, Object? value)? reviver}) async {
var s = await load(col, key); final s = await load(col, key);
if (s == null) { if (s == null) {
return null; return null;
} }
@ -55,13 +51,12 @@ abstract class VeilidTableDB {
} }
Future<Object?> loadStringJson(int col, String key, Future<Object?> loadStringJson(int col, String key,
{Object? Function(Object? key, Object? value)? reviver}) { {Object? Function(Object? key, Object? value)? reviver}) =>
return loadJson(col, utf8.encoder.convert(key), reviver: reviver); loadJson(col, utf8.encoder.convert(key), reviver: reviver);
}
Future<Object?> deleteJson(int col, Uint8List key, Future<Object?> deleteJson(int col, Uint8List key,
{Object? Function(Object? key, Object? value)? reviver}) async { {Object? Function(Object? key, Object? value)? reviver}) async {
var s = await delete(col, key); final s = await delete(col, key);
if (s == null) { if (s == null) {
return null; return null;
} }
@ -69,7 +64,6 @@ abstract class VeilidTableDB {
} }
Future<Object?> deleteStringJson(int col, String key, Future<Object?> deleteStringJson(int col, String key,
{Object? Function(Object? key, Object? value)? reviver}) { {Object? Function(Object? key, Object? value)? reviver}) =>
return deleteJson(col, utf8.encoder.convert(key), reviver: reviver); deleteJson(col, utf8.encoder.convert(key), reviver: reviver);
}
} }

View File

@ -1,5 +1,5 @@
name: veilid name: veilid
version: 0.1.4 version: 0.1.7
description: Veilid Framework description: Veilid Framework
homepage: https://veilid.com homepage: https://veilid.com
publish_to: "none" # Remove this line if you wish to publish to pub.dev publish_to: "none" # Remove this line if you wish to publish to pub.dev
@ -8,27 +8,28 @@ environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
dependencies: dependencies:
change_case: ^1.0.1
charcode: ^1.3.1
equatable: ^2.0.5
ffi: ^2.0.0
flutter: flutter:
sdk: flutter sdk: flutter
flutter_web_plugins: flutter_web_plugins:
sdk: flutter sdk: flutter
ffi: ^2.0.0
change_case: ^1.0.1
path_provider: ^2.0.9
path: ^1.8.0
system_info2: ^3.0.2
charcode: ^1.3.1
freezed_annotation: ^2.2.0 freezed_annotation: ^2.2.0
json_annotation: ^4.8.1 json_annotation: ^4.8.1
equatable: ^2.0.5 path: ^1.8.0
path_provider: ^2.0.9
system_info2: ^3.0.2
system_info_plus: ^0.0.5
dev_dependencies: dev_dependencies:
build_runner: ^2.4.6
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.1
build_runner: ^2.4.6
freezed: ^2.3.5 freezed: ^2.3.5
json_serializable: ^6.7.1 json_serializable: ^6.7.1
lint_hard: ^4.0.0
# The following section is specific to Flutter. # The following section is specific to Flutter.
flutter: flutter:

View File

@ -1,6 +1,6 @@
[package] [package]
name = "veilid-flutter" name = "veilid-flutter"
version = "0.1.4" version = "0.1.7"
authors = ["Veilid Team <contact@veilid.com>"] authors = ["Veilid Team <contact@veilid.com>"]
license = "MPL-2.0" license = "MPL-2.0"
edition = "2021" edition = "2021"

View File

@ -367,9 +367,8 @@ pub extern "C" fn shutdown_veilid_core(port: i64) {
}); });
} }
fn add_routing_context(routing_context: veilid_core::RoutingContext) -> u32 { fn add_routing_context(rc: &mut BTreeMap<u32, veilid_core::RoutingContext>, routing_context: veilid_core::RoutingContext) -> u32 {
let mut next_id: u32 = 1; let mut next_id: u32 = 1;
let mut rc = ROUTING_CONTEXTS.lock();
while rc.contains_key(&next_id) { while rc.contains_key(&next_id) {
next_id += 1; next_id += 1;
} }
@ -382,7 +381,8 @@ pub extern "C" fn routing_context(port: i64) {
DartIsolateWrapper::new(port).spawn_result(async move { DartIsolateWrapper::new(port).spawn_result(async move {
let veilid_api = get_veilid_api().await?; let veilid_api = get_veilid_api().await?;
let routing_context = veilid_api.routing_context(); let routing_context = veilid_api.routing_context();
let new_id = add_routing_context(routing_context); let mut rc = ROUTING_CONTEXTS.lock();
let new_id = add_routing_context(&mut *rc, routing_context);
APIResult::Ok(new_id) APIResult::Ok(new_id)
}); });
} }
@ -398,14 +398,14 @@ pub extern "C" fn release_routing_context(id: u32) -> i32 {
#[no_mangle] #[no_mangle]
pub extern "C" fn routing_context_with_privacy(id: u32) -> u32 { pub extern "C" fn routing_context_with_privacy(id: u32) -> u32 {
let rc = ROUTING_CONTEXTS.lock(); let mut rc = ROUTING_CONTEXTS.lock();
let Some(routing_context) = rc.get(&id) else { let Some(routing_context) = rc.get(&id) else {
return 0; return 0;
}; };
let Ok(routing_context) = routing_context.clone().with_privacy() else { let Ok(routing_context) = routing_context.clone().with_privacy() else {
return 0; return 0;
}; };
let new_id = add_routing_context(routing_context); let new_id = add_routing_context(&mut rc, routing_context);
new_id new_id
} }
@ -414,14 +414,14 @@ pub extern "C" fn routing_context_with_custom_privacy(id: u32, safety_selection:
let safety_selection: veilid_core::SafetySelection = let safety_selection: veilid_core::SafetySelection =
veilid_core::deserialize_opt_json(safety_selection.into_opt_string()).unwrap(); veilid_core::deserialize_opt_json(safety_selection.into_opt_string()).unwrap();
let rc = ROUTING_CONTEXTS.lock(); let mut rc = ROUTING_CONTEXTS.lock();
let Some(routing_context) = rc.get(&id) else { let Some(routing_context) = rc.get(&id) else {
return 0; return 0;
}; };
let Ok(routing_context) = routing_context.clone().with_custom_privacy(safety_selection) else { let Ok(routing_context) = routing_context.clone().with_custom_privacy(safety_selection) else {
return 0; return 0;
}; };
let new_id = add_routing_context(routing_context); let new_id = add_routing_context(&mut rc, routing_context);
new_id new_id
} }
@ -430,12 +430,12 @@ pub extern "C" fn routing_context_with_sequencing(id: u32, sequencing: FfiStr) -
let sequencing: veilid_core::Sequencing = let sequencing: veilid_core::Sequencing =
veilid_core::deserialize_opt_json(sequencing.into_opt_string()).unwrap(); veilid_core::deserialize_opt_json(sequencing.into_opt_string()).unwrap();
let rc = ROUTING_CONTEXTS.lock(); let mut rc = ROUTING_CONTEXTS.lock();
let Some(routing_context) = rc.get(&id) else { let Some(routing_context) = rc.get(&id) else {
return 0; return 0;
}; };
let routing_context = routing_context.clone().with_sequencing(sequencing); let routing_context = routing_context.clone().with_sequencing(sequencing);
let new_id = add_routing_context(routing_context); let new_id = add_routing_context(&mut rc, routing_context);
new_id new_id
} }
@ -569,7 +569,7 @@ pub extern "C" fn routing_context_delete_dht_record(port: i64, id: u32, key: Ffi
#[no_mangle] #[no_mangle]
pub extern "C" fn routing_context_get_dht_value(port: i64, id: u32, key: FfiStr, subkey: u32, force_refresh: bool) { pub extern "C" fn routing_context_get_dht_value(port: i64, id: u32, key: FfiStr, subkey: u32, force_refresh: bool) {
let key: veilid_core::TypedKey = veilid_core::deserialize_opt_json(key.into_opt_string()).unwrap(); let key: veilid_core::TypedKey = veilid_core::deserialize_opt_json(key.into_opt_string()).unwrap();
DartIsolateWrapper::new(port).spawn_result_opt_json(async move { DartIsolateWrapper::new(port).spawn_result_json(async move {
let routing_context = { let routing_context = {
let rc = ROUTING_CONTEXTS.lock(); let rc = ROUTING_CONTEXTS.lock();
let Some(routing_context) = rc.get(&id) else { let Some(routing_context) = rc.get(&id) else {
@ -594,7 +594,7 @@ pub extern "C" fn routing_context_set_dht_value(port: i64, id: u32, key: FfiStr,
) )
.unwrap(); .unwrap();
DartIsolateWrapper::new(port).spawn_result_opt_json(async move { DartIsolateWrapper::new(port).spawn_result_json(async move {
let routing_context = { let routing_context = {
let rc = ROUTING_CONTEXTS.lock(); let rc = ROUTING_CONTEXTS.lock();
let Some(routing_context) = rc.get(&id) else { let Some(routing_context) = rc.get(&id) else {
@ -1404,7 +1404,7 @@ pub extern "C" fn crypto_decrypt_aead(port: i64, kind: u32, body: FfiStr, nonce:
let associated_data: Option<Vec<u8>> = associated_data.into_opt_string().map(|s| data_encoding::BASE64URL_NOPAD.decode(s.as_bytes()).unwrap()); let associated_data: Option<Vec<u8>> = associated_data.into_opt_string().map(|s| data_encoding::BASE64URL_NOPAD.decode(s.as_bytes()).unwrap());
DartIsolateWrapper::new(port).spawn_result_json(async move { DartIsolateWrapper::new(port).spawn_result(async move {
let veilid_api = get_veilid_api().await?; let veilid_api = get_veilid_api().await?;
let crypto = veilid_api.crypto()?; let crypto = veilid_api.crypto()?;
let csv = crypto.get(kind).ok_or_else(|| veilid_core::VeilidAPIError::invalid_argument("crypto_decrypt_aead", "kind", kind.to_string()))?; let csv = crypto.get(kind).ok_or_else(|| veilid_core::VeilidAPIError::invalid_argument("crypto_decrypt_aead", "kind", kind.to_string()))?;
@ -1412,6 +1412,7 @@ pub extern "C" fn crypto_decrypt_aead(port: i64, kind: u32, body: FfiStr, nonce:
Some(ad) => Some(ad.as_slice()), Some(ad) => Some(ad.as_slice()),
None => None None => None
})?; })?;
let out = data_encoding::BASE64URL_NOPAD.encode(&out);
APIResult::Ok(out) APIResult::Ok(out)
}); });
} }
@ -1436,7 +1437,7 @@ pub extern "C" fn crypto_encrypt_aead(port: i64, kind: u32, body: FfiStr, nonce:
let associated_data: Option<Vec<u8>> = associated_data.into_opt_string().map(|s| data_encoding::BASE64URL_NOPAD.decode(s.as_bytes()).unwrap()); let associated_data: Option<Vec<u8>> = associated_data.into_opt_string().map(|s| data_encoding::BASE64URL_NOPAD.decode(s.as_bytes()).unwrap());
DartIsolateWrapper::new(port).spawn_result_json(async move { DartIsolateWrapper::new(port).spawn_result(async move {
let veilid_api = get_veilid_api().await?; let veilid_api = get_veilid_api().await?;
let crypto = veilid_api.crypto()?; let crypto = veilid_api.crypto()?;
let csv = crypto.get(kind).ok_or_else(|| veilid_core::VeilidAPIError::invalid_argument("crypto_encrypt_aead", "kind", kind.to_string()))?; let csv = crypto.get(kind).ok_or_else(|| veilid_core::VeilidAPIError::invalid_argument("crypto_encrypt_aead", "kind", kind.to_string()))?;
@ -1444,6 +1445,7 @@ pub extern "C" fn crypto_encrypt_aead(port: i64, kind: u32, body: FfiStr, nonce:
Some(ad) => Some(ad.as_slice()), Some(ad) => Some(ad.as_slice()),
None => None None => None
})?; })?;
let out = data_encoding::BASE64URL_NOPAD.encode(&out);
APIResult::Ok(out) APIResult::Ok(out)
}); });
} }
@ -1468,11 +1470,12 @@ pub extern "C" fn crypto_crypt_no_auth(port: i64, kind: u32, body: FfiStr, nonce
let shared_secret: veilid_core::SharedSecret = let shared_secret: veilid_core::SharedSecret =
veilid_core::deserialize_opt_json(shared_secret.into_opt_string()).unwrap(); veilid_core::deserialize_opt_json(shared_secret.into_opt_string()).unwrap();
DartIsolateWrapper::new(port).spawn_result_json(async move { DartIsolateWrapper::new(port).spawn_result(async move {
let veilid_api = get_veilid_api().await?; let veilid_api = get_veilid_api().await?;
let crypto = veilid_api.crypto()?; let crypto = veilid_api.crypto()?;
let csv = crypto.get(kind).ok_or_else(|| veilid_core::VeilidAPIError::invalid_argument("crypto_crypt_no_auth", "kind", kind.to_string()))?; let csv = crypto.get(kind).ok_or_else(|| veilid_core::VeilidAPIError::invalid_argument("crypto_crypt_no_auth", "kind", kind.to_string()))?;
csv.crypt_in_place_no_auth(&mut body, &nonce, &shared_secret); csv.crypt_in_place_no_auth(&mut body, &nonce, &shared_secret);
let body = data_encoding::BASE64URL_NOPAD.encode(&body);
APIResult::Ok(body) APIResult::Ok(body)
}); });
} }

View File

@ -52,17 +52,6 @@ impl DartIsolateWrapper {
}); });
} }
pub fn spawn_result_opt_json<F, T, E>(self, future: F)
where
F: Future<Output = Result<Option<T>, E>> + Send + 'static,
T: Serialize + Debug,
E: Serialize + Debug,
{
spawn(async move {
self.result_opt_json(future.await);
});
}
pub fn result<T: IntoDart + Debug, E: Serialize + Debug>(self, result: Result<T, E>) -> bool { pub fn result<T: IntoDart + Debug, E: Serialize + Debug>(self, result: Result<T, E>) -> bool {
match result { match result {
Ok(v) => self.ok(v), Ok(v) => self.ok(v),
@ -78,16 +67,6 @@ impl DartIsolateWrapper {
Err(e) => self.err_json(e), Err(e) => self.err_json(e),
} }
} }
pub fn result_opt_json<T: Serialize + Debug, E: Serialize + Debug>(
self,
result: Result<Option<T>, E>,
) -> bool {
match result {
Ok(Some(v)) => self.ok_json(v),
Ok(None) => self.ok(()),
Err(e) => self.err_json(e),
}
}
pub fn ok<T: IntoDart>(self, value: T) -> bool { pub fn ok<T: IntoDart>(self, value: T) -> bool {
self.isolate self.isolate
.post(vec![MESSAGE_OK.into_dart(), value.into_dart()]) .post(vec![MESSAGE_OK.into_dart(), value.into_dart()])

View File

@ -2,7 +2,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:veilid/veilid.dart'; import 'package:veilid/veilid.dart';
void main() { void main() {
Veilid api = Veilid.instance; final api = Veilid.instance;
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "veilid" name = "veilid"
version = "0.1.4" version = "0.1.7"
description = "" description = ""
authors = ["Veilid Team <contact@veilid.com>"] authors = ["Veilid Team <contact@veilid.com>"]
readme = "README.md" readme = "README.md"

View File

@ -0,0 +1,70 @@
import errno
import os
import re
from collections.abc import Callable
from functools import cache
from veilid.json_api import _JsonVeilidAPI
import veilid
ERRNO_PATTERN = re.compile(r"errno (\d+)", re.IGNORECASE)
class VeilidTestConnectionError(Exception):
"""The test client could not connect to the veilid-server."""
pass
@cache
def server_info() -> tuple[str, int]:
"""Return the hostname and port of the test server."""
VEILID_SERVER = os.getenv("VEILID_SERVER")
if VEILID_SERVER is None:
return "localhost", 5959
hostname, *rest = VEILID_SERVER.split(":")
if rest:
return hostname, int(rest[0])
return hostname, 5959
async def api_connector(callback: Callable) -> _JsonVeilidAPI:
"""Return an API connection if possible.
If the connection fails due to an inability to connect to the
server's socket, raise an easy-to-catch VeilidTestConnectionError.
"""
hostname, port = server_info()
try:
return await veilid.json_api_connect(hostname, port, callback)
except OSError as exc:
# This is a little goofy. The underlying Python library handles
# connection errors in 2 ways, depending on how many connections
# it attempted to make:
#
# - If it only tried to connect to one IP address socket, the
# library propagates the one single OSError it got.
#
# - If it tried to connect to multiple sockets, perhaps because
# the hostname resolved to several addresses (e.g. "localhost"
# => 127.0.0.1 and ::1), then the library raises one exception
# with all the failure exception strings joined together.
# If errno is set, it's the first kind of exception. Check that
# it's the code we expected.
if exc.errno is not None:
if exc.errno == errno.ECONNREFUSED:
raise VeilidTestConnectionError
raise
# If not, use a regular expression to find all the errno values
# in the combined error string. Check that all of them have the
# code we're looking for.
errnos = ERRNO_PATTERN.findall(str(exc))
if all(int(err) == errno.ECONNREFUSED for err in errnos):
raise VeilidTestConnectionError
raise

View File

@ -1,35 +1,30 @@
import os """Common test fixtures."""
from functools import cache
from typing import AsyncGenerator from typing import AsyncGenerator
import pytest
import pytest_asyncio import pytest_asyncio
import veilid
from veilid.json_api import _JsonVeilidAPI from veilid.json_api import _JsonVeilidAPI
import veilid
from .api import VeilidTestConnectionError, api_connector
pytest_plugins = ("pytest_asyncio",) pytest_plugins = ("pytest_asyncio",)
@cache
def server_info() -> tuple[str, int]:
"""Return the hostname and port of the test server."""
VEILID_SERVER = os.getenv("VEILID_SERVER")
if VEILID_SERVER is None:
return "localhost", 5959
hostname, *rest = VEILID_SERVER.split(":")
if rest:
return hostname, int(rest[0])
return hostname, 5959
async def simple_update_callback(update: veilid.VeilidUpdate): async def simple_update_callback(update: veilid.VeilidUpdate):
print(f"VeilidUpdate: {update}") print(f"VeilidUpdate: {update}")
@pytest_asyncio.fixture @pytest_asyncio.fixture
async def api_connection() -> AsyncGenerator[_JsonVeilidAPI, None]: async def api_connection() -> AsyncGenerator[_JsonVeilidAPI, None]:
hostname, port = server_info() try:
api = await veilid.json_api_connect(hostname, port, simple_update_callback) api = await api_connector(simple_update_callback)
except VeilidTestConnectionError:
pytest.skip("Unable to connect to veilid-server.")
return
async with api: async with api:
# purge routes to ensure we start fresh # purge routes to ensure we start fresh
await api.debug("purge routes") await api.debug("purge routes")

View File

@ -7,7 +7,9 @@ import json
from . import * from . import *
################################################################## ##################################################################
BOGUS_KEY = veilid.TypedKey.from_value(veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.PublicKey.from_bytes(b' ')) BOGUS_KEY = veilid.TypedKey.from_value(
veilid.CryptoKind.CRYPTO_KIND_VLD0, veilid.PublicKey.from_bytes(b' '))
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_get_dht_value_unopened(api_connection: veilid.VeilidAPI): async def test_get_dht_value_unopened(api_connection: veilid.VeilidAPI):
@ -24,6 +26,7 @@ async def test_open_dht_record_nonexistent_no_writer(api_connection: veilid.Veil
with pytest.raises(veilid.VeilidAPIError): with pytest.raises(veilid.VeilidAPIError):
out = await rc.open_dht_record(BOGUS_KEY, None) out = await rc.open_dht_record(BOGUS_KEY, None)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_close_dht_record_nonexistent(api_connection: veilid.VeilidAPI): async def test_close_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context() rc = await api_connection.new_routing_context()
@ -31,13 +34,15 @@ async def test_close_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
with pytest.raises(veilid.VeilidAPIError): with pytest.raises(veilid.VeilidAPIError):
await rc.close_dht_record(BOGUS_KEY) await rc.close_dht_record(BOGUS_KEY)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_delete_dht_record_nonexistent(api_connection: veilid.VeilidAPI): async def test_delete_dht_record_nonexistent(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context() rc = await api_connection.new_routing_context()
async with rc: async with rc:
with pytest.raises(veilid.VeilidAPIError): with pytest.raises(veilid.VeilidAPIError):
await rc.delete_dht_record(BOGUS_KEY) await rc.delete_dht_record(BOGUS_KEY)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_create_delete_dht_record_simple(api_connection: veilid.VeilidAPI): async def test_create_delete_dht_record_simple(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context() rc = await api_connection.new_routing_context()
@ -46,6 +51,7 @@ async def test_create_delete_dht_record_simple(api_connection: veilid.VeilidAPI)
await rc.close_dht_record(rec.key) await rc.close_dht_record(rec.key)
await rc.delete_dht_record(rec.key) await rc.delete_dht_record(rec.key)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_get_dht_value_nonexistent(api_connection: veilid.VeilidAPI): async def test_get_dht_value_nonexistent(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context() rc = await api_connection.new_routing_context()
@ -55,34 +61,34 @@ async def test_get_dht_value_nonexistent(api_connection: veilid.VeilidAPI):
await rc.close_dht_record(rec.key) await rc.close_dht_record(rec.key)
await rc.delete_dht_record(rec.key) await rc.delete_dht_record(rec.key)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_set_get_dht_value(api_connection: veilid.VeilidAPI): async def test_set_get_dht_value(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context() rc = await api_connection.new_routing_context()
async with rc: async with rc:
rec = await rc.create_dht_record(veilid.DHTSchema.dflt(2)) rec = await rc.create_dht_record(veilid.DHTSchema.dflt(2))
vd = await rc.set_dht_value(rec.key, 0, b"BLAH BLAH BLAH") vd = await rc.set_dht_value(rec.key, 0, b"BLAH BLAH BLAH")
assert vd != None assert vd == None
vd2 = await rc.get_dht_value(rec.key, 0, False) vd2 = await rc.get_dht_value(rec.key, 0, False)
assert vd2 != None assert vd2 != None
vd3 = await rc.get_dht_value(rec.key, 0, True) vd3 = await rc.get_dht_value(rec.key, 0, True)
assert vd3 != None assert vd3 != None
vd4 = await rc.get_dht_value(rec.key, 1, False) vd4 = await rc.get_dht_value(rec.key, 1, False)
assert vd4 == None assert vd4 == None
print("vd: {}", vd.__dict__)
print("vd2: {}", vd2.__dict__) print("vd2: {}", vd2.__dict__)
print("vd3: {}", vd3.__dict__) print("vd3: {}", vd3.__dict__)
assert vd == vd2
assert vd2 == vd3 assert vd2 == vd3
await rc.close_dht_record(rec.key) await rc.close_dht_record(rec.key)
await rc.delete_dht_record(rec.key) await rc.delete_dht_record(rec.key)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI): async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
rc = await api_connection.new_routing_context() rc = await api_connection.new_routing_context()
@ -104,10 +110,7 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Test subkey writes # Test subkey writes
vdtemp = await rc.set_dht_value(key, 1, va) vdtemp = await rc.set_dht_value(key, 1, va)
assert vdtemp != None assert vdtemp == None
assert vdtemp.data == va
assert vdtemp.seq == 0
assert vdtemp.writer == owner
vdtemp = await rc.get_dht_value(key, 1, False) vdtemp = await rc.get_dht_value(key, 1, False)
assert vdtemp.data == va assert vdtemp.data == va
@ -118,8 +121,7 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
assert vdtemp == None assert vdtemp == None
vdtemp = await rc.set_dht_value(key, 0, vb) vdtemp = await rc.set_dht_value(key, 0, vb)
assert vdtemp.data == vb assert vdtemp == None
assert vdtemp.seq == 0
vdtemp = await rc.get_dht_value(key, 0, True) vdtemp = await rc.get_dht_value(key, 0, True)
assert vdtemp.data == vb assert vdtemp.data == vb
@ -129,17 +131,11 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Equal value should not trigger sequence number update # Equal value should not trigger sequence number update
vdtemp = await rc.set_dht_value(key, 1, va) vdtemp = await rc.set_dht_value(key, 1, va)
assert vdtemp != None assert vdtemp == None
assert vdtemp.data == va
assert vdtemp.seq == 0
assert vdtemp.writer == owner
# Different value should trigger sequence number update # Different value should trigger sequence number update
vdtemp = await rc.set_dht_value(key, 1, vb) vdtemp = await rc.set_dht_value(key, 1, vb)
assert vdtemp != None assert vdtemp == None
assert vdtemp.data == vb
assert vdtemp.seq == 1
assert vdtemp.writer == owner
# Now that we initialized some subkeys # Now that we initialized some subkeys
# and verified they stored correctly # and verified they stored correctly
@ -166,11 +162,8 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Verify subkey 1 can be set a second time and it updates because seq is newer # Verify subkey 1 can be set a second time and it updates because seq is newer
vdtemp = await rc.set_dht_value(key, 1, vc) vdtemp = await rc.set_dht_value(key, 1, vc)
assert vdtemp != None assert vdtemp == None
assert vdtemp.data == vc
assert vdtemp.seq == 2
assert vdtemp.writer == owner
# Verify the network got the subkey update with a refresh check # Verify the network got the subkey update with a refresh check
vdtemp = await rc.get_dht_value(key, 1, True) vdtemp = await rc.get_dht_value(key, 1, True)
assert vdtemp != None assert vdtemp != None
@ -183,7 +176,7 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
await rc.close_dht_record(key) await rc.close_dht_record(key)
await rc.delete_dht_record(key) await rc.delete_dht_record(key)
rec = await rc.open_dht_record(key, other_keypair) rec = await rc.open_dht_record(key, other_keypair)
assert rec != None assert rec != None
assert rec.key == key assert rec.key == key
@ -195,12 +188,11 @@ async def test_open_writer_dht_value(api_connection: veilid.VeilidAPI):
# Verify subkey 1 can NOT be set because we have the wrong writer # Verify subkey 1 can NOT be set because we have the wrong writer
with pytest.raises(veilid.VeilidAPIError): with pytest.raises(veilid.VeilidAPIError):
vdtemp = await rc.set_dht_value(key, 1, va) vdtemp = await rc.set_dht_value(key, 1, va)
# Verify subkey 0 can NOT be set because we have the wrong writer # Verify subkey 0 can NOT be set because we have the wrong writer
with pytest.raises(veilid.VeilidAPIError): with pytest.raises(veilid.VeilidAPIError):
vdtemp = await rc.set_dht_value(key, 0, va) vdtemp = await rc.set_dht_value(key, 0, va)
# Clean up # Clean up
await rc.close_dht_record(key) await rc.close_dht_record(key)
await rc.delete_dht_record(key) await rc.delete_dht_record(key)

View File

@ -1,15 +1,15 @@
# Routing context veilid tests # Routing context veilid tests
import asyncio import asyncio
import os
import random import random
import sys import sys
import os
import pytest import pytest
import veilid
from veilid.types import OperationId
from .conftest import server_info import veilid
from .api import VeilidTestConnectionError, api_connector
################################################################## ##################################################################
@ -26,18 +26,24 @@ async def test_routing_contexts(api_connection: veilid.VeilidAPI):
async with rcp: async with rcp:
pass pass
rc = await (await api_connection.new_routing_context()).with_sequencing(veilid.Sequencing.ENSURE_ORDERED) rc = await (await api_connection.new_routing_context()).with_sequencing(
veilid.Sequencing.ENSURE_ORDERED
)
async with rc: async with rc:
pass pass
rc = await (await api_connection.new_routing_context()).with_custom_privacy( rc = await (await api_connection.new_routing_context()).with_custom_privacy(
veilid.SafetySelection.safe( veilid.SafetySelection.safe(
veilid.SafetySpec(None, 2, veilid.Stability.RELIABLE, veilid.SafetySpec(
veilid.Sequencing.ENSURE_ORDERED) None, 2, veilid.Stability.RELIABLE, veilid.Sequencing.ENSURE_ORDERED
)) )
)
)
await rc.release() await rc.release()
rc = await (await api_connection.new_routing_context()).with_custom_privacy(veilid.SafetySelection.unsafe(veilid.Sequencing.ENSURE_ORDERED)) rc = await (await api_connection.new_routing_context()).with_custom_privacy(
veilid.SafetySelection.unsafe(veilid.Sequencing.ENSURE_ORDERED)
)
await rc.release() await rc.release()
@ -50,10 +56,12 @@ async def test_routing_context_app_message_loopback():
if update.kind == veilid.VeilidUpdateKind.APP_MESSAGE: if update.kind == veilid.VeilidUpdateKind.APP_MESSAGE:
await app_message_queue.put(update) await app_message_queue.put(update)
hostname, port = server_info() try:
api = await veilid.json_api_connect( api = await api_connector(app_message_queue_update_callback)
hostname, port, app_message_queue_update_callback except VeilidTestConnectionError:
) pytest.skip("Unable to connect to veilid-server.")
return
async with api: async with api:
# purge routes to ensure we start fresh # purge routes to ensure we start fresh
await api.debug("purge routes") await api.debug("purge routes")
@ -61,7 +69,6 @@ async def test_routing_context_app_message_loopback():
# make a routing context that uses a safety route # make a routing context that uses a safety route
rc = await (await api.new_routing_context()).with_privacy() rc = await (await api.new_routing_context()).with_privacy()
async with rc: async with rc:
# make a new local private route # make a new local private route
prl, blob = await api.new_private_route() prl, blob = await api.new_private_route()
@ -89,8 +96,12 @@ async def test_routing_context_app_call_loopback():
if update.kind == veilid.VeilidUpdateKind.APP_CALL: if update.kind == veilid.VeilidUpdateKind.APP_CALL:
await app_call_queue.put(update) await app_call_queue.put(update)
hostname, port = server_info() try:
api = await veilid.json_api_connect(hostname, port, app_call_queue_update_callback) api = await api_connector(app_call_queue_update_callback)
except VeilidTestConnectionError:
pytest.skip("Unable to connect to veilid-server.")
return
async with api: async with api:
# purge routes to ensure we start fresh # purge routes to ensure we start fresh
await api.debug("purge routes") await api.debug("purge routes")
@ -98,7 +109,6 @@ async def test_routing_context_app_call_loopback():
# make a routing context that uses a safety route # make a routing context that uses a safety route
rc = await (await api.new_routing_context()).with_privacy() rc = await (await api.new_routing_context()).with_privacy()
async with rc: async with rc:
# make a new local private route # make a new local private route
prl, blob = await api.new_private_route() prl, blob = await api.new_private_route()
@ -131,33 +141,33 @@ async def test_routing_context_app_call_loopback():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_routing_context_app_message_loopback_big_packets(): async def test_routing_context_app_message_loopback_big_packets():
app_message_queue: asyncio.Queue = asyncio.Queue() app_message_queue: asyncio.Queue = asyncio.Queue()
global got_message count_hack = [0]
got_message = 0
async def app_message_queue_update_callback(update: veilid.VeilidUpdate): async def app_message_queue_update_callback(update: veilid.VeilidUpdate):
if update.kind == veilid.VeilidUpdateKind.APP_MESSAGE: if update.kind == veilid.VeilidUpdateKind.APP_MESSAGE:
global got_message count_hack[0] += 1
got_message += 1 print(f"{count_hack[0]} ", end="")
sys.stdout.write("{} ".format(got_message))
await app_message_queue.put(update) await app_message_queue.put(update)
sent_messages: set[bytes] = set() sent_messages: set[bytes] = set()
hostname, port = server_info() try:
api = await veilid.json_api_connect( api = await api_connector(app_message_queue_update_callback)
hostname, port, app_message_queue_update_callback except VeilidTestConnectionError:
) pytest.skip("Unable to connect to veilid-server.")
return
async with api: async with api:
# purge routes to ensure we start fresh # purge routes to ensure we start fresh
await api.debug("purge routes") await api.debug("purge routes")
# make a routing context that uses a safety route # make a routing context that uses a safety route
rc = await (await (await api.new_routing_context()).with_privacy()).with_sequencing(veilid.Sequencing.ENSURE_ORDERED) rc = await (
await (await api.new_routing_context()).with_privacy()
).with_sequencing(veilid.Sequencing.ENSURE_ORDERED)
async with rc: async with rc:
# make a new local private route # make a new local private route
prl, blob = await api.new_private_route() prl, blob = await api.new_private_route()
@ -166,7 +176,6 @@ async def test_routing_context_app_message_loopback_big_packets():
# do this test 1000 times # do this test 1000 times
for _ in range(1000): for _ in range(1000):
# send a random sized random app message to our own private route # send a random sized random app message to our own private route
message = random.randbytes(random.randint(0, 32768)) message = random.randbytes(random.randint(0, 32768))
await rc.app_message(prr, message) await rc.app_message(prr, message)
@ -187,8 +196,7 @@ async def test_routing_context_app_message_loopback_big_packets():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_routing_context_app_call_loopback_big_packets(): async def test_routing_context_app_call_loopback_big_packets():
global got_message count_hack = [0]
got_message = 0
app_call_queue: asyncio.Queue = asyncio.Queue() app_call_queue: asyncio.Queue = asyncio.Queue()
@ -200,18 +208,17 @@ async def test_routing_context_app_call_loopback_big_packets():
while True: while True:
update = await app_call_queue.get() update = await app_call_queue.get()
global got_message count_hack[0] += 1
got_message += 1 print(f"{count_hack[0]} ", end="", flush=True)
sys.stdout.write("{} ".format(got_message))
sys.stdout.flush()
await api.app_call_reply(update.detail.call_id, update.detail.message) await api.app_call_reply(update.detail.call_id, update.detail.message)
hostname, port = server_info() try:
api = await veilid.json_api_connect( api = await api_connector(app_call_queue_update_callback)
hostname, port, app_call_queue_update_callback except VeilidTestConnectionError:
) pytest.skip("Unable to connect to veilid-server.")
return
async with api: async with api:
# purge routes to ensure we start fresh # purge routes to ensure we start fresh
await api.debug("purge routes") await api.debug("purge routes")
@ -221,9 +228,10 @@ async def test_routing_context_app_call_loopback_big_packets():
) )
# make a routing context that uses a safety route # make a routing context that uses a safety route
rc = await (await (await api.new_routing_context()).with_privacy()).with_sequencing(veilid.Sequencing.ENSURE_ORDERED) rc = await (
await (await api.new_routing_context()).with_privacy()
).with_sequencing(veilid.Sequencing.ENSURE_ORDERED)
async with rc: async with rc:
# make a new local private route # make a new local private route
prl, blob = await api.new_private_route() prl, blob = await api.new_private_route()
@ -232,7 +240,6 @@ async def test_routing_context_app_call_loopback_big_packets():
# do this test 10 times # do this test 10 times
for _ in range(10): for _ in range(10):
# send a random sized random app message to our own private route # send a random sized random app message to our own private route
message = random.randbytes(random.randint(0, 32768)) message = random.randbytes(random.randint(0, 32768))
out_message = await rc.app_call(prr, message) out_message = await rc.app_call(prr, message)
@ -242,20 +249,23 @@ async def test_routing_context_app_call_loopback_big_packets():
app_call_task.cancel() app_call_task.cancel()
@pytest.mark.skipif(os.getenv("NOSKIP") != "1", reason="unneeded test, only for performance check") @pytest.mark.skipif(
os.getenv("NOSKIP") != "1", reason="unneeded test, only for performance check"
)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_routing_context_app_message_loopback_bandwidth(): async def test_routing_context_app_message_loopback_bandwidth():
app_message_queue: asyncio.Queue = asyncio.Queue() app_message_queue: asyncio.Queue = asyncio.Queue()
async def app_message_queue_update_callback(update: veilid.VeilidUpdate): async def app_message_queue_update_callback(update: veilid.VeilidUpdate):
if update.kind == veilid.VeilidUpdateKind.APP_MESSAGE: if update.kind == veilid.VeilidUpdateKind.APP_MESSAGE:
await app_message_queue.put(True) await app_message_queue.put(True)
hostname, port = server_info() try:
api = await veilid.json_api_connect( api = await api_connector(app_message_queue_update_callback)
hostname, port, app_message_queue_update_callback except VeilidTestConnectionError:
) pytest.skip("Unable to connect to veilid-server.")
return
async with api: async with api:
# purge routes to ensure we start fresh # purge routes to ensure we start fresh
await api.debug("purge routes") await api.debug("purge routes")
@ -265,7 +275,6 @@ async def test_routing_context_app_message_loopback_bandwidth():
# rc = await (await api.new_routing_context()).with_privacy() # rc = await (await api.new_routing_context()).with_privacy()
rc = await api.new_routing_context() rc = await api.new_routing_context()
async with rc: async with rc:
# make a new local private route # make a new local private route
prl, blob = await api.new_private_route() prl, blob = await api.new_private_route()
@ -275,12 +284,9 @@ async def test_routing_context_app_message_loopback_bandwidth():
# do this test 1000 times # do this test 1000 times
message = random.randbytes(16384) message = random.randbytes(16384)
for _ in range(10000): for _ in range(10000):
# send a random sized random app message to our own private route # send a random sized random app message to our own private route
await rc.app_message(prr, message) await rc.app_message(prr, message)
# we should get the same number of messages back (not storing all that data) # we should get the same number of messages back (not storing all that data)
for _ in range(10000): for _ in range(10000):
await asyncio.wait_for( await asyncio.wait_for(app_message_queue.get(), timeout=10)
app_message_queue.get(), timeout=10
)

View File

@ -1,6 +1,6 @@
[package] [package]
name = "veilid-server" name = "veilid-server"
version = "0.1.4" version = "0.1.7"
authors = ["Veilid Team <contact@veilid.com>"] authors = ["Veilid Team <contact@veilid.com>"]
license = "MPL-2.0" license = "MPL-2.0"
edition = "2021" edition = "2021"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "veilid-tools" name = "veilid-tools"
version = "0.1.4" version = "0.1.7"
authors = ["Veilid Team <contact@veilid.com>"] authors = ["Veilid Team <contact@veilid.com>"]
license = "MPL-2.0" license = "MPL-2.0"
edition = "2021" edition = "2021"

View File

@ -12,7 +12,7 @@ const MAX_LEN: usize = LengthType::MAX as usize;
// XXX: keep statistics on all drops and why we dropped them // XXX: keep statistics on all drops and why we dropped them
// XXX: move to config eventually? // XXX: move to config eventually?
const FRAGMENT_LEN: usize = 1280 - HEADER_LEN; pub const FRAGMENT_LEN: usize = 1280 - HEADER_LEN;
const MAX_CONCURRENT_HOSTS: usize = 256; const MAX_CONCURRENT_HOSTS: usize = 256;
const MAX_ASSEMBLIES_PER_HOST: usize = 256; const MAX_ASSEMBLIES_PER_HOST: usize = 256;
const MAX_BUFFER_PER_HOST: usize = 256 * 1024; const MAX_BUFFER_PER_HOST: usize = 256 * 1024;

View File

@ -86,7 +86,7 @@ pub async fn test_one_frag_out_in() {
// Sending // Sending
println!("sending"); println!("sending");
for _ in 0..10000 { for _ in 0..10000 {
let random_len = (get_random_u32() % 1000) as usize + 1280; let random_len = (get_random_u32() % 1000) as usize + FRAGMENT_LEN;
let mut message = vec![1u8; random_len]; let mut message = vec![1u8; random_len];
random_bytes(&mut message); random_bytes(&mut message);
let remote_addr = random_sockaddr(); let remote_addr = random_sockaddr();
@ -289,7 +289,7 @@ pub async fn test_many_frags_with_drops() {
println!("sending"); println!("sending");
for _ in 0..1000 { for _ in 0..1000 {
let random_len = (get_random_u32() % 65536) as usize; let random_len = (get_random_u32() % 65536) as usize;
if random_len > 1280 { if random_len > FRAGMENT_LEN {
total_fragged += 1; total_fragged += 1;
} }
total_sent_size += random_len; total_sent_size += random_len;

View File

@ -1,6 +1,6 @@
[package] [package]
name = "veilid-wasm" name = "veilid-wasm"
version = "0.1.4" version = "0.1.7"
authors = ["Veilid Team <contact@veilid.com>"] authors = ["Veilid Team <contact@veilid.com>"]
license = "MPL-2.0" license = "MPL-2.0"
edition = "2021" edition = "2021"

View File

@ -60,12 +60,6 @@ fn take_veilid_api() -> Result<veilid_core::VeilidAPI, veilid_core::VeilidAPIErr
pub fn to_json<T: Serialize + Debug>(val: T) -> JsValue { pub fn to_json<T: Serialize + Debug>(val: T) -> JsValue {
JsValue::from_str(&serialize_json(val)) JsValue::from_str(&serialize_json(val))
} }
pub fn to_opt_json<T: Serialize + Debug>(val: Option<T>) -> JsValue {
match val {
Some(v) => JsValue::from_str(&serialize_json(v)),
None => JsValue::UNDEFINED,
}
}
pub fn to_jsvalue<T>(val: T) -> JsValue pub fn to_jsvalue<T>(val: T) -> JsValue
where where
@ -120,14 +114,6 @@ where
future_to_promise(future.map(|res| res.map(|v| to_json(v)).map_err(|e| to_json(e)))) future_to_promise(future.map(|res| res.map(|v| to_json(v)).map_err(|e| to_json(e))))
} }
pub fn wrap_api_future_opt_json<F, T>(future: F) -> Promise
where
F: Future<Output = APIResult<Option<T>>> + 'static,
T: Serialize + Debug + 'static,
{
future_to_promise(future.map(|res| res.map(|v| to_opt_json(v)).map_err(|e| to_json(e))))
}
pub fn wrap_api_future_plain<F, T>(future: F) -> Promise pub fn wrap_api_future_plain<F, T>(future: F) -> Promise
where where
F: Future<Output = APIResult<T>> + 'static, F: Future<Output = APIResult<T>> + 'static,
@ -507,7 +493,7 @@ pub fn routing_context_get_dht_value(
force_refresh: bool, force_refresh: bool,
) -> Promise { ) -> Promise {
let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap(); let key: veilid_core::TypedKey = veilid_core::deserialize_json(&key).unwrap();
wrap_api_future_opt_json(async move { wrap_api_future_json(async move {
let routing_context = { let routing_context = {
let rc = (*ROUTING_CONTEXTS).borrow(); let rc = (*ROUTING_CONTEXTS).borrow();
let Some(routing_context) = rc.get(&id) else { let Some(routing_context) = rc.get(&id) else {
@ -529,7 +515,7 @@ pub fn routing_context_set_dht_value(id: u32, key: String, subkey: u32, data: St
.decode(&data.as_bytes()) .decode(&data.as_bytes())
.unwrap(); .unwrap();
wrap_api_future_opt_json(async move { wrap_api_future_json(async move {
let routing_context = { let routing_context = {
let rc = (*ROUTING_CONTEXTS).borrow(); let rc = (*ROUTING_CONTEXTS).borrow();
let Some(routing_context) = rc.get(&id) else { let Some(routing_context) = rc.get(&id) else {
@ -1361,7 +1347,7 @@ pub fn crypto_decrypt_aead(
.unwrap() .unwrap()
}); });
wrap_api_future_json(async move { wrap_api_future(async move {
let veilid_api = get_veilid_api()?; let veilid_api = get_veilid_api()?;
let crypto = veilid_api.crypto()?; let crypto = veilid_api.crypto()?;
let csv = crypto.get(kind).ok_or_else(|| { let csv = crypto.get(kind).ok_or_else(|| {
@ -1380,6 +1366,7 @@ pub fn crypto_decrypt_aead(
None => None, None => None,
}, },
)?; )?;
let out = data_encoding::BASE64URL_NOPAD.encode(&out);
APIResult::Ok(out) APIResult::Ok(out)
}) })
} }
@ -1409,7 +1396,7 @@ pub fn crypto_encrypt_aead(
.unwrap() .unwrap()
}); });
wrap_api_future_json(async move { wrap_api_future(async move {
let veilid_api = get_veilid_api()?; let veilid_api = get_veilid_api()?;
let crypto = veilid_api.crypto()?; let crypto = veilid_api.crypto()?;
let csv = crypto.get(kind).ok_or_else(|| { let csv = crypto.get(kind).ok_or_else(|| {
@ -1428,6 +1415,7 @@ pub fn crypto_encrypt_aead(
None => None, None => None,
}, },
)?; )?;
let out = data_encoding::BASE64URL_NOPAD.encode(&out);
APIResult::Ok(out) APIResult::Ok(out)
}) })
} }
@ -1450,7 +1438,7 @@ pub fn crypto_crypt_no_auth(
let shared_secret: veilid_core::SharedSecret = let shared_secret: veilid_core::SharedSecret =
veilid_core::deserialize_json(&shared_secret).unwrap(); veilid_core::deserialize_json(&shared_secret).unwrap();
wrap_api_future_json(async move { wrap_api_future(async move {
let veilid_api = get_veilid_api()?; let veilid_api = get_veilid_api()?;
let crypto = veilid_api.crypto()?; let crypto = veilid_api.crypto()?;
let csv = crypto.get(kind).ok_or_else(|| { let csv = crypto.get(kind).ok_or_else(|| {
@ -1461,6 +1449,7 @@ pub fn crypto_crypt_no_auth(
) )
})?; })?;
csv.crypt_in_place_no_auth(&mut body, &nonce, &shared_secret); csv.crypt_in_place_no_auth(&mut body, &nonce, &shared_secret);
let out = data_encoding::BASE64URL_NOPAD.encode(&out);
APIResult::Ok(body) APIResult::Ok(body)
}) })
} }