Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bdda08c0b4 | |||
| 0e48ff5e9e | |||
| 68d6ece6c2 | |||
| 493f036687 | |||
| 1f4f312e8e | |||
| d829837275 | |||
| 36253e3f36 | |||
| 7743554bb8 | |||
| de05e32845 | |||
| 136f4a8473 | |||
| 57e2628928 | |||
| 879e324696 | |||
| 351552b863 | |||
| 847f3a0ecc | |||
| 58958a2449 | |||
| 3051d84e8d | |||
| 2d7003dfae | |||
| a91c997aed | |||
| 5787653210 | |||
| adbeeb3e5f | |||
| 4899ccf4ef | |||
| 9e0bcc025f | |||
| 16d6444169 | |||
| 730f03de30 | |||
| 2e366a094d | |||
| b134334ec7 | |||
| f95b9b7f4a | |||
| 11ed3b3e45 | |||
| a71e228a25 | |||
| e025564678 | |||
| cf6188d794 | |||
| dd7308d92f | |||
| 73ca14aae2 | |||
| 0fee189a89 | |||
| a0c6efafd2 | |||
| fcc5398aab | |||
| 9f1f765f73 | |||
| 7bbb10e52c | |||
| 1aad69a527 | |||
| 4ad02d5328 | |||
| 45b74008f1 | |||
| 2ddf9646ec | |||
| b258cd8733 | |||
| 7a1a7c003e | |||
| 2953837f25 | |||
| ee98820bb4 | |||
| 0f41dda013 |
@@ -38,7 +38,7 @@ jobs:
|
||||
- name: install npm
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
run: npm install
|
||||
working-directory: .github/workflows/support-files
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Build
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "16"
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Install Yarn
|
||||
run: npm install -g yarn
|
||||
- run: yarn
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
name: Linting for Network Explorer (eslint/prettier)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'explorer/**'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: explorer
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: custom-runner-linux
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Run ESLint
|
||||
# GitHub should automatically annotate the PR
|
||||
run: yarn && yarn lint
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
continue-on-error: true
|
||||
|
||||
@@ -152,7 +152,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
|
||||
@@ -167,7 +167,7 @@ jobs:
|
||||
uses: actions/setup-node@v3
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Matrix - Node Install
|
||||
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||
run: npm install
|
||||
|
||||
@@ -20,10 +20,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -51,11 +51,15 @@ jobs:
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies and build it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -73,7 +77,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64.dmg
|
||||
path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
|
||||
path: nym-connect/desktop/target/release/bundle/dmg/nym-connect_1*_x64.dmg
|
||||
retention-days: 30
|
||||
|
||||
- name: Clean up keychain
|
||||
|
||||
@@ -26,19 +26,25 @@ jobs:
|
||||
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
|
||||
continue-on-error: true
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
@@ -53,7 +59,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect.AppImage.tar.gz
|
||||
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1.0.0_amd64.AppImage
|
||||
path: nym-connect/desktop/target/release/bundle/appimage/nym-connect_1*_amd64.AppImage
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
|
||||
@@ -39,10 +39,10 @@ jobs:
|
||||
Remove-Item -path certificate -include tempCert.txt
|
||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -50,15 +50,21 @@ jobs:
|
||||
toolchain: stable
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
shell: bash
|
||||
run: yarn --network-timeout 100000
|
||||
|
||||
- name: Build and sign it
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
@@ -72,7 +78,7 @@ jobs:
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64_en-US.msi
|
||||
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1.0.0_x64_en-US.msi
|
||||
path: nym-connect/desktop/target/release/bundle/msi/nym-connect_1*_x64_en-US.msi
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
|
||||
@@ -20,10 +20,10 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -51,11 +51,15 @@ jobs:
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies and build it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
name: Publish Nym Wallet (Ubuntu)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
@@ -25,19 +26,24 @@ jobs:
|
||||
sudo apt-get install -y webkit2gtk-4.0
|
||||
continue-on-error: true
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
@@ -47,8 +53,17 @@ jobs:
|
||||
env:
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-wallet_1.0.0_amd64.AppImage.tar.gz
|
||||
path: nym-wallet/target/release/bundle/appimage/nym-wallet*.AppImage.tar.gz
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-wallet/target/release/bundle/appimage/*.AppImage
|
||||
|
||||
@@ -39,10 +39,10 @@ jobs:
|
||||
Remove-Item -path certificate -include tempCert.txt
|
||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
@@ -50,15 +50,21 @@ jobs:
|
||||
toolchain: stable
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
uses: timheuer/base64-to-file@v1.2
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install project dependencies
|
||||
shell: bash
|
||||
run: cd .. && yarn --network-timeout 100000
|
||||
|
||||
- name: Install app dependencies
|
||||
shell: bash
|
||||
run: yarn --network-timeout 100000
|
||||
|
||||
- name: Build and sign it
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
|
||||
@@ -16,19 +16,9 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
working-directory: clients/webassembly
|
||||
- name: Build WASM
|
||||
run: wasm-pack build
|
||||
working-directory: clients/webassembly
|
||||
- name: Build dependencies
|
||||
run: yarn && yarn build
|
||||
- name: Build storybook
|
||||
|
||||
@@ -34,10 +34,10 @@ jobs:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
|
||||
- name: Node v16
|
||||
- name: Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
|
||||
- name: Install yarn for building application
|
||||
run: yarn install
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
name: Publish SDK to NPM
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: [custom-runner-linux]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Build and publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
|
||||
working-directory: ./sdk/typescript/packages/sdk
|
||||
run: scripts/publish.sh
|
||||
@@ -1 +1 @@
|
||||
16
|
||||
18
|
||||
|
||||
@@ -11,6 +11,7 @@ on:
|
||||
- 'nym-connect/mobile/package.json'
|
||||
- 'nym-wallet/src/**'
|
||||
- 'nym-wallet/package.json'
|
||||
- 'explorer/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'ts-packages/**'
|
||||
@@ -21,6 +22,7 @@ on:
|
||||
- 'nym-connect/mobile/package.json'
|
||||
- 'nym-wallet/src/**'
|
||||
- 'nym-wallet/package.json'
|
||||
- 'explorer/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -33,19 +35,9 @@ jobs:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 18
|
||||
- name: Setup yarn
|
||||
run: npm install -g yarn
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install wasm-pack
|
||||
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||
working-directory: clients/webassembly
|
||||
- name: Build WASM
|
||||
run: wasm-pack build
|
||||
working-directory: clients/webassembly
|
||||
- name: Install
|
||||
run: yarn
|
||||
- name: Build packages
|
||||
|
||||
+5
-1
@@ -4,12 +4,16 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.23] (2023-06-27)
|
||||
## [v1.1.23] (2023-07-04)
|
||||
|
||||
- nym-cli: add client identity key signing support ([#3576])
|
||||
- Feature/node tester package ([#3634])
|
||||
- Add medium toggle to socks5 client ([#3615])
|
||||
- Don't fully turn off background task when cover traffic is disabled ([#3596])
|
||||
|
||||
[#3576]: https://github.com/nymtech/nym/issues/3576
|
||||
[#3634]: https://github.com/nymtech/nym/pull/3634
|
||||
[#3615]: https://github.com/nymtech/nym/pull/3615
|
||||
[#3596]: https://github.com/nymtech/nym/pull/3596
|
||||
|
||||
## [v1.1.22] (2023-06-20)
|
||||
|
||||
@@ -13,7 +13,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
* nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices.
|
||||
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||
|
||||
[](https://opensource.org/licenses/Apache-2.0)
|
||||
[](https://github.com/nymtech/nym/actions?query=branch%3Adevelop)
|
||||
@@ -21,7 +21,7 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
||||
|
||||
### Building
|
||||
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/build-nym.html).
|
||||
Platform build instructions are available on [our docs site](https://nymtech.net/docs/binaries/pre-built-binaries.html).
|
||||
Wallet build instructions are also available on [our docs site](https://nymtech.net/docs/wallet/desktop-wallet.html).
|
||||
|
||||
### Developing
|
||||
@@ -32,9 +32,9 @@ For Typescript components, please see [ts-packages](./ts-packages).
|
||||
|
||||
### Developer chat
|
||||
|
||||
> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team.
|
||||
> We used to use Keybase for developer chats, but we have since migrated to Matrix and Discord. We no longer check the old **nymtech.friends** Keybase team.
|
||||
|
||||
You can chat to us in two places:
|
||||
You can chat to us in two places:
|
||||
* The #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat)
|
||||
* The various developer channels on [Discord](https://discord.gg/nym)
|
||||
|
||||
@@ -84,4 +84,3 @@ where `s'` is stake `s` scaled over total token circulating supply.
|
||||
### Licensing and copyright information
|
||||
|
||||
This program is available as open source under the terms of the Apache 2.0 license. However, some elements are being licensed under CC0-1.0 and MIT. For accurate information, please check individual files.
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ impl From<Init> for OverrideConfig {
|
||||
use_anonymous_replies: init_config.use_reply_surbs,
|
||||
fastmode: init_config.fastmode,
|
||||
no_cover: init_config.no_cover,
|
||||
medium_toggle: false,
|
||||
nyxd_urls: init_config.nyxd_urls,
|
||||
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||
outfox: false,
|
||||
|
||||
@@ -19,7 +19,7 @@ use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
use nym_config::OptionalSet;
|
||||
use nym_sphinx::params::PacketType;
|
||||
use nym_sphinx::params::{PacketSize, PacketType};
|
||||
use std::error::Error;
|
||||
|
||||
pub mod init;
|
||||
@@ -72,6 +72,7 @@ pub(crate) struct OverrideConfig {
|
||||
use_anonymous_replies: Option<bool>,
|
||||
fastmode: bool,
|
||||
no_cover: bool,
|
||||
medium_toggle: bool,
|
||||
nyxd_urls: Option<Vec<url::Url>>,
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
outfox: bool,
|
||||
@@ -91,6 +92,10 @@ pub(crate) async fn execute(args: &Cli) -> Result<(), Box<dyn Error + Send + Syn
|
||||
}
|
||||
|
||||
pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
let disable_cover_traffic_with_keepalive = args.medium_toggle;
|
||||
let secondary_packet_size = args.medium_toggle.then_some(PacketSize::ExtendedPacket16);
|
||||
let no_per_hop_delays = args.medium_toggle;
|
||||
|
||||
let packet_type = if args.outfox {
|
||||
PacketType::Outfox
|
||||
} else {
|
||||
@@ -101,6 +106,17 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config {
|
||||
BaseClientConfig::with_high_default_traffic_volume,
|
||||
args.fastmode,
|
||||
)
|
||||
.with_base(
|
||||
// NOTE: This interacts with disabling cover traffic fully, so we want to this to be set before
|
||||
BaseClientConfig::with_disabled_cover_traffic_with_keepalive,
|
||||
disable_cover_traffic_with_keepalive,
|
||||
)
|
||||
.with_base(
|
||||
BaseClientConfig::with_secondary_packet_size,
|
||||
secondary_packet_size,
|
||||
)
|
||||
.with_base(BaseClientConfig::with_no_per_hop_delays, no_per_hop_delays)
|
||||
// NOTE: see comment above about the order of the other disble cover traffic config
|
||||
.with_base(BaseClientConfig::with_disabled_cover_traffic, args.no_cover)
|
||||
.with_base(BaseClientConfig::with_packet_type, packet_type)
|
||||
.with_optional(Config::with_anonymous_replies, args.use_anonymous_replies)
|
||||
|
||||
@@ -60,6 +60,11 @@ pub(crate) struct Run {
|
||||
#[clap(long, hide = true)]
|
||||
no_cover: bool,
|
||||
|
||||
/// Enable medium mixnet traffic, for experiments only.
|
||||
/// This includes things like disabling cover traffic, no per hop delays, etc.
|
||||
#[clap(long, hide = true)]
|
||||
medium_toggle: bool,
|
||||
|
||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||
/// with bandwidth credential requirement.
|
||||
#[clap(long, hide = true)]
|
||||
@@ -77,6 +82,7 @@ impl From<Run> for OverrideConfig {
|
||||
use_anonymous_replies: run_config.use_anonymous_replies,
|
||||
fastmode: run_config.fastmode,
|
||||
no_cover: run_config.no_cover,
|
||||
medium_toggle: run_config.medium_toggle,
|
||||
nyxd_urls: run_config.nyxd_urls,
|
||||
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||
outfox: run_config.outfox,
|
||||
|
||||
@@ -1 +1 @@
|
||||
16
|
||||
18
|
||||
@@ -79,7 +79,7 @@ copy-fonts = true
|
||||
no-section-label = false
|
||||
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"]
|
||||
additional-js = ["theme/pagetoc.js"]
|
||||
git-repository-url = "https://github.com/nymtech/dev-portal"
|
||||
git-repository-url = "https://github.com/nymtech/nym"
|
||||
git-repository-icon = "fa-github"
|
||||
# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}"
|
||||
site-url = "/developers/"
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
- [SOCKS Proxy (CLI)](quickstart/socks-proxy.md)
|
||||
- [NymConnect Beta (GUI)](quickstart/nymconnect-gui.md)
|
||||
|
||||
# User Manuals
|
||||
|
||||
- [NymConnect Monero](tutorials/monero.md)
|
||||
- [NymConnect Matrix](tutorials/matrix.md)
|
||||
|
||||
# Integrations
|
||||
|
||||
- [Integration Options](integrations/integration-options.md)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 314 KiB |
@@ -0,0 +1,44 @@
|
||||
# Matrix NymConnect Integration
|
||||
|
||||
|
||||
Chat applications became an essential part of human communication. Matrix chat has end to end encryption on protocol level and Element app users can sort their communication into spaces and rooms. Now the Matrix communities can rely on network privacy as NymConnect supports Matrix chat protocol.
|
||||
|
||||
Currently there is no option in Matrix's Element client to set a socks5 proxy. In order to use Element via NymConnect users have to start it from the command-line. The setup is simple, for convenience a a keyboard shortcut setting can be easily done.
|
||||
|
||||
|
||||
## Setup & Run
|
||||
|
||||
Make sure you have installed and started **[NymConnect](https://nymtech.net/developers/quickstart/nymconnect-gui.html)** on your desktop.
|
||||
|
||||
To then start Matrix's Element client via a Socks5 proxy connected to NymConnect, open terminal and run:
|
||||
|
||||
```sh
|
||||
element-desktop --proxy-server=socks5://127.0.0.1:1080
|
||||
```
|
||||
|
||||
## Optimise setup with a keybinding / alias
|
||||
|
||||
### Keybinding
|
||||
An eloquent solution to avoid entering a command every time is to setup your keybinding. Open your settings, navigate to `Keyboard Shortcuts` and choose to `Set Custom Shortcut`. `Name` and `Shortcut` fields are up to your preference, to the `Command` line add:
|
||||
|
||||
```sh
|
||||
element-desktop --proxy-server=socks5://127.0.0.1:1080
|
||||
```
|
||||
Make sure your `Shortcut` isn't already taken by something else in the menu.
|
||||
|
||||
An example can look like this.
|
||||
|
||||

|
||||
|
||||
Alternatively you can add a keybinding via the CLI, using whatever config files you edit for your given desktop environment / window manager.
|
||||
|
||||
### Create an alias
|
||||
If you prefer to simply shorten the length of the command (or all your keybindings are already taken) then you can simply create an alias for this long-winded command (this example aliases that command to the single word `element`, but you can replace it with whatever you like):
|
||||
|
||||
```sh
|
||||
alias element="element-desktop --proxy-server=socks5://127.0.0.1:1080"
|
||||
```
|
||||
|
||||
To make this alias persist, then add this to your `.bashrc` or `.zshrc` file (usually located in your `$HOME` directory) and `source` that file.
|
||||
|
||||
Now you can run Element throught the mixnet with a single-word command.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Monero NymConnect Integration
|
||||
|
||||
*New Nym mixnet integration launched for Monero desktop to secure the right to financial privacy and censorship-resistance*
|
||||
|
||||

|
||||
|
||||
Financial privacy is an important component of digital currencies and the use of Nym will provide users with the highest level of privacy at the infrastructure level. All users of digital currencies should be afforded equal rights to protection from financial surveillance.
|
||||
|
||||
A team made up of Monero community members have successfully set up a service provider to use Monero (using the Monero desktop wallet) over the Nym mixnet. This allows Monero users to easily use NymConnect to run Monero over the mixnet, thereby enhancing the privacy of Monero transactions.
|
||||
|
||||
## How can I use Monero over the Nym mixnet?
|
||||
|
||||
The mainnet service provider to Monero over the Nym mixnet is now ready for use via [NymConnect](https://nymtech.net/download-nymconnect/).
|
||||
|
||||
* Download and open the latest version of [NymConnect](https://nymtech.net/download-nymconnect/).
|
||||
* Click on the top left options and go to Settings
|
||||
* Go to “Select service provider” and turn it on
|
||||
* For Mainnet, search for this provider or insert it manually:
|
||||
|
||||
```sh
|
||||
i1TiuoNp4jp9weffCW7tPnkb4hRTPydRjX8iXFVaYDG.88Z1hruuvbzWpdCE2xYnTbPNrr49j4s7mmUQC5wvRRLZ@3EPuxwGn2WP2HdxybzoDa5QsohYSP76aQQRUJuPMvk23
|
||||
```
|
||||
|
||||
* Go to the main NymConnect interface and connect to the mixnet
|
||||
|
||||
Then go to your Monero wallet (gui or otherwise) and change the settings to run over socks5 proxy:
|
||||
|
||||
**Monero desktop:**
|
||||
|
||||
* Settings -> Interface -> Socks5 proxy -> Add values: IP address `localhost`, Port `1080`
|
||||
|
||||
<iframe width="700" height="400" src="https://www.youtube.com/embed/oSHnk1BG_f0" title="Demo: Connect Your Monero Wallet to the Nym Mixnet via NymConnect" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
|
||||
**CLI**
|
||||
|
||||
* **Monerod:** add `--proxy 127.0.0.1:1080 --bootstrap-daemon-proxy 127.0.0.1:1080` to args
|
||||
|
||||
* **Monero-wallet-{rpc, cli}:** add `--proxy 127.0.0.1:1080 --daemon-ssl-allow-any-cert` to args
|
||||
|
||||
Follow the instructions and the Monero mainnet will be connected through to the Nym mixnet.
|
||||
|
||||
For those who want to try it out in testnet, a stagenet service provider is also available: [https://nymtech.net/.wellknown/connect/service-providers.json](https://nymtech.net/.wellknown/connect/service-providers.json)
|
||||
|
||||
@@ -48,9 +48,9 @@ assets_version = "2.0.0" # do not edit: managed by `mdbook-admonish install`
|
||||
# https://gitlab.com/tglman/mdbook-variables/
|
||||
[preprocessor.variables.variables]
|
||||
minimum_rust_version = "1.66"
|
||||
|
||||
# old variables - this is still needed for links.. TODO change to develop?
|
||||
platform_release_version = "v1.1.21"
|
||||
# vars for links: TODO think on how to streamline updating
|
||||
platform_release_version = "v1.1.22"
|
||||
wallet_release_version = "v1.2.5"
|
||||
|
||||
[preprocessor.last-changed]
|
||||
command = "mdbook-last-changed"
|
||||
@@ -87,7 +87,7 @@ copy-fonts = true
|
||||
no-section-label = false
|
||||
additional-css = ["theme/pagetoc.css", "././mdbook-admonish.css", "last-changed.css"]
|
||||
additional-js = ["theme/pagetoc.js"]
|
||||
git-repository-url = "https://github.com/nymtech/docs"
|
||||
git-repository-url = "https://github.com/nymtech/nym"
|
||||
git-repository-icon = "fa-github"
|
||||
# edit-url-template = "https://github.com/rust-lang/mdBook/edit/master/guide/{path}"
|
||||
# site-url = "/docs/"
|
||||
|
||||
@@ -593,10 +593,19 @@ nyxd tx slashing unjail
|
||||
|
||||
### Upgrading your validator
|
||||
|
||||
Upgrading from `v0.26.0` -> `v0.31.1` doesn't require many modifications, simply grab a binary from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases) and once the chain has halted at the decided upon haltheight, stop your `nyxd` process, replace your binaries, and restart your process.
|
||||
Upgrading from `v0.26.0` -> `v0.31.1` process is fairly simple. Grab the v0.31.1 release tarball from the [`nyxd` releases page](https://github.com/nymtech/nyxd/releases), and untar it. Inside are two files:
|
||||
|
||||
- the new validator (`nyxd`) v0.31.1
|
||||
- the new wasmvm (it depends on your platform, but most common filename is `libwasmvm.x86_64.so`)
|
||||
|
||||
Before the upgrade height, copy `libwasmvm.x86_64.so` to the default LD_LIBRARY_PATH on your system (on Ubuntu 20.04 this is `/lib/x86_64-linux-gnu/`):
|
||||
|
||||
Then just swap in your new `nyxd` binary and restart once the halt height is reached.
|
||||
|
||||
You can also use something like [Cosmovisor](https://github.com/cosmos/cosmos-sdk/tree/main/tools/cosmovisor) - grab the relevant information from the current upgrade proposal [here](https://nym.explorers.guru/proposal/8).
|
||||
|
||||
Note: Cosmovisor will swap the `nyxd` binary, but you'll need to already have the `libwasmvm.x86_64.so` in place. Luckily, the name of the wasmvm in v0.26.1 was `libwasmvm.so`, and the new name is `libwasmvm.x86_64.so`, so you can have it already sitting there without disrupting service.
|
||||
|
||||
#### Common reasons for your validator being jailed
|
||||
|
||||
The most common reason for your validator being jailed is that your validator is out of memory because of bloated syslogs.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
16
|
||||
18
|
||||
|
||||
+2
-8
@@ -1,10 +1,4 @@
|
||||
{
|
||||
"packages": [
|
||||
"ts-packages/*",
|
||||
"nym-wallet",
|
||||
"nym-connect/**",
|
||||
"sdk/typescript/examples/docs",
|
||||
"sdk/typescript/packages/**"
|
||||
],
|
||||
"version": "0.0.0"
|
||||
"version": "0.0.0",
|
||||
"useWorkspaces": true
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
14
|
||||
18
|
||||
@@ -2,16 +2,18 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.14] (2023-06-27)
|
||||
## [v1.1.14] (2023-07-04)
|
||||
|
||||
- Nym connect fails to start when encountering an old config version ([#3588])
|
||||
- NC desktop - apps section adjustments + add monero integration ([#2977])
|
||||
- nym-connect: use different service provider directory when medium toggle enabled ([#3617])
|
||||
- Fix medium toggle in nym-connect ([#3590])
|
||||
- [bugfix] NC: load old gateway configuration if we're not registering ([#3586])
|
||||
- nym-connect: medium speed setting ([#3585])
|
||||
|
||||
[#3588]: https://github.com/nymtech/nym/issues/3588
|
||||
[#2977]: https://github.com/nymtech/nym/issues/2977
|
||||
[#3617]: https://github.com/nymtech/nym/pull/3617
|
||||
[#3590]: https://github.com/nymtech/nym/pull/3590
|
||||
[#3586]: https://github.com/nymtech/nym/pull/3586
|
||||
[#3585]: https://github.com/nymtech/nym/pull/3585
|
||||
|
||||
@@ -10,39 +10,58 @@ use nym_contracts_common::types::Percent;
|
||||
static SERVICE_PROVIDER_WELLKNOWN_URL: &str =
|
||||
"https://nymtech.net/.wellknown/connect/service-providers.json";
|
||||
|
||||
// List of network-requesters running with medium toggle enabled, for testing
|
||||
static SERVICE_PROVIDER_WELLKNOWN_URL_MEDIUM: &str =
|
||||
"https://nymtech.net/.wellknown/connect/service-providers-medium.json";
|
||||
|
||||
static HARBOUR_MASTER_URL: &str = "https://harbourmaster.nymtech.net/v1/services/?size=100";
|
||||
|
||||
static GATEWAYS_DETAILED_URL: &str =
|
||||
"https://validator.nymtech.net/api/v1/status/gateways/detailed";
|
||||
|
||||
fn get_services_url() -> &'static str {
|
||||
std::env::var("NYM_CONNECT_ENABLE_MEDIUM")
|
||||
.is_ok()
|
||||
.then(|| SERVICE_PROVIDER_WELLKNOWN_URL_MEDIUM)
|
||||
.unwrap_or(SERVICE_PROVIDER_WELLKNOWN_URL)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_services() -> Result<Vec<DirectoryServiceProvider>> {
|
||||
log::trace!("Fetching services");
|
||||
let services_res = reqwest::get(SERVICE_PROVIDER_WELLKNOWN_URL)
|
||||
.await?
|
||||
.json::<Vec<DirectoryService>>()
|
||||
.await?;
|
||||
log::trace!("Received: {:#?}", services_res);
|
||||
let all_services = fetch_services().await?;
|
||||
log::trace!("Received: {:#?}", all_services);
|
||||
|
||||
log::trace!("Fetching gateways");
|
||||
let gateway_res = reqwest::get(GATEWAYS_DETAILED_URL)
|
||||
.await?
|
||||
.json::<Vec<GatewayBondAnnotated>>()
|
||||
.await?;
|
||||
log::trace!("Received: {:#?}", gateway_res);
|
||||
// Early return if we're running with medium toggle enabled
|
||||
if std::env::var("NYM_CONNECT_ENABLE_MEDIUM").is_ok() {
|
||||
return Ok(all_services.into_iter().flat_map(|sp| sp.items).collect());
|
||||
}
|
||||
|
||||
// TODO: get paged
|
||||
log::trace!("Fetching active services");
|
||||
let active_services = reqwest::get(HARBOUR_MASTER_URL)
|
||||
.await?
|
||||
.json::<PagedResult<HarbourMasterService>>()
|
||||
.await?;
|
||||
let active_services = fetch_active_services().await?;
|
||||
log::trace!("Active: {:#?}", active_services);
|
||||
|
||||
let mut filtered: Vec<DirectoryService> = vec![];
|
||||
let filtered_services = filter_out_inactive(all_services, active_services);
|
||||
|
||||
for service in &services_res {
|
||||
let items = service
|
||||
log::trace!("Fetching gateways");
|
||||
let gateway_res = get_gateways_detailed().await?;
|
||||
log::trace!("Received: {:#?}", gateway_res);
|
||||
|
||||
// Use only services that are active AND have a performance of >= 90%
|
||||
let filtered_services_with_good_gateway =
|
||||
filter_out_poor_gateways(filtered_services, gateway_res);
|
||||
|
||||
Ok(filtered_services_with_good_gateway)
|
||||
}
|
||||
|
||||
fn filter_out_inactive(
|
||||
services_res: Vec<DirectoryService>,
|
||||
active_services: PagedResult<HarbourMasterService>,
|
||||
) -> Vec<DirectoryService> {
|
||||
let mut filtered: Vec<DirectoryService> = vec![];
|
||||
for service_type in &services_res {
|
||||
let items = service_type
|
||||
.items
|
||||
.clone()
|
||||
.into_iter()
|
||||
@@ -53,33 +72,48 @@ pub async fn get_services() -> Result<Vec<DirectoryServiceProvider>> {
|
||||
.any(|active| active.service_provider_client_id == sp.address)
|
||||
})
|
||||
.collect_vec();
|
||||
log::trace!("service = {} has {} items", service.id, items.len());
|
||||
log::trace!("service = {} has {} items", service_type.id, items.len());
|
||||
filtered.push(DirectoryService {
|
||||
id: service.id.clone(),
|
||||
description: service.description.clone(),
|
||||
id: service_type.id.clone(),
|
||||
description: service_type.description.clone(),
|
||||
items,
|
||||
})
|
||||
}
|
||||
filtered
|
||||
}
|
||||
|
||||
fn filter_out_poor_gateways(
|
||||
services: Vec<DirectoryService>,
|
||||
gateway_res: Vec<GatewayBondAnnotated>,
|
||||
) -> Vec<DirectoryServiceProvider> {
|
||||
let perf_threshold = Percent::from_percentage_value(90).unwrap();
|
||||
|
||||
// Use only services that are active AND have a performance of >= 90%
|
||||
let services_with_good_performance: Vec<DirectoryServiceProvider> = filtered
|
||||
.iter_mut()
|
||||
.fold(vec![], |mut acc, sp| {
|
||||
acc.append(&mut sp.items);
|
||||
acc
|
||||
})
|
||||
services
|
||||
.into_iter()
|
||||
.flat_map(|sp| sp.items)
|
||||
.filter(|sp| {
|
||||
gateway_res.iter().any(|gateway| {
|
||||
gateway.gateway_bond.gateway.identity_key == sp.gateway
|
||||
&& gateway.performance >= perf_threshold
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
.collect()
|
||||
}
|
||||
|
||||
Ok(services_with_good_performance)
|
||||
async fn fetch_services() -> Result<Vec<DirectoryService>> {
|
||||
let services_url = get_services_url();
|
||||
let services_res = reqwest::get(services_url)
|
||||
.await?
|
||||
.json::<Vec<DirectoryService>>()
|
||||
.await?;
|
||||
Ok(services_res)
|
||||
}
|
||||
|
||||
async fn fetch_active_services() -> Result<PagedResult<HarbourMasterService>> {
|
||||
let active_services = reqwest::get(HARBOUR_MASTER_URL)
|
||||
.await?
|
||||
.json::<PagedResult<HarbourMasterService>>()
|
||||
.await?;
|
||||
Ok(active_services)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@@ -3,34 +3,31 @@ import { Divider, Typography } from '@mui/material';
|
||||
import { Box } from '@mui/system';
|
||||
|
||||
const appsSchema = {
|
||||
messagingApps: ['Telegram', 'Keybase'],
|
||||
wallets: ['Blockstream', 'Electrum'],
|
||||
messagingApps: ['Matrix', 'Telegram', 'Keybase'],
|
||||
wallets: ['Monero', 'Blockstream', 'Electrum'],
|
||||
};
|
||||
|
||||
export const CompatibleApps = () => (
|
||||
<Box>
|
||||
<Typography fontSize="small" color="grey.600" sx={{ mb: 2 }}>
|
||||
<Typography fontWeight="bold" variant="body2" sx={{ mb: 2 }}>
|
||||
Supported apps
|
||||
</Typography>
|
||||
<Typography color="nym.highlight" sx={{ mb: 2 }}>
|
||||
Messaging apps
|
||||
</Typography>
|
||||
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
|
||||
<Box sx={{ mb: 4 }}>
|
||||
<Box sx={{ mb: 2 }}>
|
||||
{appsSchema.messagingApps.map((app) => (
|
||||
<Typography variant="body2" color="grey.400" sx={{ mb: 2 }} key={app}>
|
||||
{app}
|
||||
</Typography>
|
||||
))}
|
||||
</Box>
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
<Typography color="nym.highlight" sx={{ mb: 2 }}>
|
||||
Wallets
|
||||
</Typography>
|
||||
|
||||
<Divider sx={{ mb: 2 }} />
|
||||
|
||||
<Box sx={{ mb: 4 }}>
|
||||
{appsSchema.wallets.map((wallet) => (
|
||||
<Typography variant="body2" color="grey.400" sx={{ mb: 2 }} key={wallet}>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Apps, HelpOutline, Settings } from '@mui/icons-material';
|
||||
import { Apps, HelpOutline, Settings, BugReport } from '@mui/icons-material';
|
||||
import { Stack, Link, List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { AppVersion } from 'src/components/AppVersion';
|
||||
@@ -7,6 +7,7 @@ import { AppVersion } from 'src/components/AppVersion';
|
||||
const menuSchema = [
|
||||
{ title: 'Supported apps', icon: Apps, path: 'apps' },
|
||||
{ title: 'How to connect guide', icon: HelpOutline, path: 'guide' },
|
||||
{ title: 'Please help us improve the app', icon: BugReport, path: 'monitoring' },
|
||||
{ title: 'Settings', icon: Settings, path: 'settings' },
|
||||
];
|
||||
|
||||
|
||||
@@ -34,10 +34,6 @@ export const MonitoringSettings = () => {
|
||||
occur or if the app crashes, it will automatically send a report. Also it tracks various performance
|
||||
metrics. We use sentry.io service to handle this.
|
||||
</FormHelperText>
|
||||
<FormHelperText sx={{ m: 0, mb: 2 }}>
|
||||
Note: A report can include your external IP, this can be useful to catch issues related to IP location.
|
||||
All recorded data is used by Nym developers and for app development purposes only.
|
||||
</FormHelperText>
|
||||
</FormControl>
|
||||
<Stack direction="row" gap={1} alignItems="center">
|
||||
<WarningIcon color="warning" fontSize="small" />
|
||||
|
||||
@@ -7,7 +7,6 @@ import { toggleLogViewer } from 'src/utils';
|
||||
const menuSchema = [
|
||||
{ title: 'Select your gateway', path: 'gateway' },
|
||||
{ title: 'Select a service provider', path: 'service-provider' },
|
||||
{ title: 'Help improve the app', path: 'monitoring' },
|
||||
];
|
||||
|
||||
export const SettingsMenu = () => (
|
||||
|
||||
@@ -25,11 +25,11 @@ export const AppRoutes = () => {
|
||||
<Route index element={<Menu />} />
|
||||
<Route path="apps" element={<CompatibleApps />} />
|
||||
<Route path="guide" element={<HelpGuide />} />
|
||||
<Route path="monitoring" element={<MonitoringSettings />} />
|
||||
<Route path="settings">
|
||||
<Route index element={<SettingsMenu />} />
|
||||
<Route path="gateway" element={<GatewaySettings />} />
|
||||
<Route path="service-provider" element={<ServiceProviderSettings />} />
|
||||
<Route path="monitoring" element={<MonitoringSettings />} />
|
||||
</Route>
|
||||
</Route>
|
||||
</RoutesContainer>
|
||||
|
||||
@@ -43,6 +43,8 @@ async function initSentry() {
|
||||
getVersion().then((version) => {
|
||||
Sentry.setTag('app_version', version);
|
||||
});
|
||||
|
||||
Sentry.setUser({ id: 'nym', ip_address: undefined });
|
||||
}
|
||||
|
||||
export default initSentry;
|
||||
|
||||
@@ -1 +1 @@
|
||||
14
|
||||
18
|
||||
@@ -99,7 +99,6 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.10.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
|
||||
implementation 'androidx.activity:activity-compose:1.7.2'
|
||||
@@ -124,4 +123,5 @@ dependencies {
|
||||
debugImplementation 'androidx.compose.ui:ui-tooling'
|
||||
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
||||
implementation 'com.github.kittinunf.fuel:fuel:3.0.0-alpha1'
|
||||
implementation 'io.sentry:sentry-android:6.24.0'
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package net.nymtech.nyms5
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
@@ -9,11 +11,15 @@ import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import androidx.work.Configuration
|
||||
import androidx.work.DelegatingWorkerFactory
|
||||
import io.sentry.Scope
|
||||
import io.sentry.Sentry
|
||||
import io.sentry.android.core.SentryAndroid
|
||||
import io.sentry.protocol.User
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
|
||||
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
|
||||
val monitoringKey = booleanPreferencesKey("monitoring")
|
||||
|
||||
@@ -40,11 +46,34 @@ class App : Application(), Configuration.Provider {
|
||||
options.dsn =
|
||||
"https://6872f5818bc147ef9c0fce114fcaac8a@o967446.ingest.sentry.io/4505306218102784"
|
||||
options.enableAllAutoBreadcrumbs(true)
|
||||
options.isEnableUserInteractionTracing = true
|
||||
options.isEnableUserInteractionBreadcrumbs = true
|
||||
|
||||
// TODO should be adjusted in production env
|
||||
options.sampleRate = 1.0
|
||||
options.tracesSampleRate = 1.0
|
||||
options.profilesSampleRate = 1.0
|
||||
}
|
||||
|
||||
Sentry.configureScope { scope: Scope ->
|
||||
val packageManager = applicationContext.packageManager
|
||||
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
packageManager.getPackageInfo(
|
||||
packageName,
|
||||
PackageManager.PackageInfoFlags.of(0)
|
||||
)
|
||||
} else {
|
||||
packageManager.getPackageInfo(packageName, 0)
|
||||
}
|
||||
scope.setTag("app_version", packageInfo.versionName)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
scope.setTag("app_version_code", packageInfo.longVersionCode.toString())
|
||||
}
|
||||
}
|
||||
|
||||
val user = User()
|
||||
user.id = "nym"
|
||||
Sentry.setUser(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
@@ -249,7 +250,7 @@ fun S5ClientSwitch(
|
||||
Spacer(modifier = modifier.width(14.dp))
|
||||
Switch(checked = connected, enabled = !loading, onCheckedChange = {
|
||||
onSwitch(!connected)
|
||||
})
|
||||
}, modifier = Modifier.testTag("switch_connect"))
|
||||
}
|
||||
if (connected && !loading) {
|
||||
Column(modifier = modifier.padding(16.dp)) {
|
||||
@@ -332,12 +333,10 @@ fun Monitoring(
|
||||
tint = Color.Yellow
|
||||
)
|
||||
Spacer(modifier = modifier.width(16.dp))
|
||||
Text(stringResource(R.string.monitoring_desc_3), color = Color.Yellow)
|
||||
Text(stringResource(R.string.monitoring_desc_2), color = Color.Yellow)
|
||||
}
|
||||
Spacer(modifier = modifier.height(18.dp))
|
||||
Text(stringResource(R.string.monitoring_desc_1))
|
||||
Spacer(modifier = modifier.height(18.dp))
|
||||
Text(stringResource(R.string.monitoring_desc_2))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package net.nymtech.nyms5
|
||||
|
||||
import android.util.Log
|
||||
import io.sentry.Sentry
|
||||
|
||||
const val nymNativeLib = "nym_socks5_listener"
|
||||
|
||||
@@ -27,6 +28,7 @@ class NymProxy {
|
||||
startClient(serviceProvider, onStartCbObj, onStopCbObj)
|
||||
} catch (e: Throwable) {
|
||||
Log.e(tag, "$nymNativeLib:startClient internal error: $e")
|
||||
Sentry.captureException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +38,7 @@ class NymProxy {
|
||||
stopClient()
|
||||
} catch (e: Throwable) {
|
||||
Log.e(tag, "$nymNativeLib:stopClient internal error: $e")
|
||||
Sentry.captureException(e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +53,7 @@ class NymProxy {
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.e(tag, "$nymNativeLib:getClientState internal error: $e")
|
||||
Sentry.captureException(e)
|
||||
}
|
||||
return State.UNINITIALIZED
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import fuel.Fuel
|
||||
import fuel.get
|
||||
import io.sentry.Sentry
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
@@ -100,6 +101,7 @@ class ProxyWorker(
|
||||
tag,
|
||||
"failed to make the work run in the context of a foreground service"
|
||||
)
|
||||
Sentry.captureException(e)
|
||||
}
|
||||
|
||||
return try {
|
||||
@@ -127,6 +129,7 @@ class ProxyWorker(
|
||||
tag,
|
||||
"an error occurred while fetching the service providers list: $e"
|
||||
)
|
||||
Sentry.captureException(e)
|
||||
Log.w(tag, "using a default service provider $defaultSp")
|
||||
}
|
||||
|
||||
@@ -139,6 +142,7 @@ class ProxyWorker(
|
||||
Result.success()
|
||||
} catch (e: Throwable) {
|
||||
Log.e(tag, "error: ${e.message}")
|
||||
Sentry.captureException(e)
|
||||
Result.failure()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,5 @@
|
||||
<string name="default_sp">DpB3cHAchJiNBQi5FrZx2csXb1mrHkpYh9Wzf8Rjsuko.ANNWrvHqMYuertHGHUrZdBntQhpzfbWekB39qez9U2Vx@2BuMSfMW3zpeAjKXyKLhmY4QW1DXurrtSPEJ6CjX3SEh</string>
|
||||
<string name="connected_text">Connected to the mixnet</string>
|
||||
<string name="monitoring_desc_1">Help Nym developers to fix errors, crashes and improve the application by enabling this option. If errors occur or if the app crashes, it will automatically send a report. Also it tracks various performance metrics. We use sentry.io service to handle this.</string>
|
||||
<string name="monitoring_desc_2">Note: A report can include your external IP, this can be useful to catch issues related to IP location.
|
||||
All recorded data is used by Nym developers and for app development purposes only.</string>
|
||||
<string name="monitoring_desc_3">You must restart the application for the change to take effect.</string>
|
||||
<string name="monitoring_desc_2">You must restart the application for the change to take effect.</string>
|
||||
</resources>
|
||||
+1
-1
@@ -1 +1 @@
|
||||
16
|
||||
18
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.2.5] (2023-06-27)
|
||||
## [v1.2.5] (2023-07-04)
|
||||
|
||||
- Wallet - add "Test my node" in the Node Settings and show its results ([#2314])
|
||||
- Move client wasm to Wallet directory ([#3606])
|
||||
|
||||
[#2314]: https://github.com/nymtech/nym/issues/2314
|
||||
[#3606]: https://github.com/nymtech/nym/pull/3606
|
||||
|
||||
## [v1.2.4] (2023-06-06)
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"@nymproject/mui-theme": "^1.0.0",
|
||||
"@nymproject/react": "^1.0.0",
|
||||
"@nymproject/types": "^1.0.0",
|
||||
"@nymproject/sdk": "^1.1.8",
|
||||
"@storybook/react": "^6.5.15",
|
||||
"@tauri-apps/api": "^1.2.0",
|
||||
"@tauri-apps/tauri-forage": "^1.0.0-beta.2",
|
||||
@@ -41,7 +42,6 @@
|
||||
"lodash": "^4.17.21",
|
||||
"notistack": "^2.0.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"nym-client-wasm": "1.1.1",
|
||||
"qrcode.react": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { TestStatus } from '@nymproject/sdk';
|
||||
import { Divider, Typography } from '@mui/material';
|
||||
import { TestStatus } from 'src/pages/bonding/node-settings/node-test/types';
|
||||
import { ResultsCard, ResultsCardDetail } from './ResultsCard';
|
||||
|
||||
export const Packets = ({
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Card, CardContent, CardHeader, Dialog, Divider } from '@mui/material';
|
||||
import { NymLogo } from '@nymproject/react/logo/NymLogo';
|
||||
import { ResultsCardDetail } from './ResultsCard';
|
||||
import { sleep } from 'src/utils/sleep';
|
||||
import { ResultsCardDetail } from './ResultsCard';
|
||||
|
||||
export const PrintResults = ({
|
||||
packetsSent,
|
||||
@@ -30,7 +30,7 @@ export const PrintResults = ({
|
||||
asyncPrint();
|
||||
window.addEventListener('afterprint', OnPrintRequestComplete);
|
||||
|
||||
() => window.removeEventListener('afterprint', OnPrintRequestComplete);
|
||||
return () => window.removeEventListener('afterprint', OnPrintRequestComplete);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import { TestStatus } from '@nymproject/sdk';
|
||||
import { Grid } from '@mui/material';
|
||||
|
||||
import { TestStatus } from 'src/pages/bonding/node-settings/node-test/types';
|
||||
import { Packets } from './Packets';
|
||||
import { NodeScore } from './NodeScore';
|
||||
import { Overview } from './Overview';
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { WasmGateway, WasmMixNode, WasmNymTopology } from 'nym-client-wasm';
|
||||
|
||||
export const createDummyTopology = () => {
|
||||
const l1Mixnode = new WasmMixNode(
|
||||
1,
|
||||
'n1fzv4jc7fanl9s0qj02ge2ezk3kts545kjtek47',
|
||||
'178.79.143.65',
|
||||
1789,
|
||||
'4Yr4qmEHd9sgsuQ83191FR2hD88RfsbMmB4tzhhZWriz',
|
||||
'8ndjk5oZ6HxUZNScLJJ7hk39XtUqGexdKgW7hSX6kpWG',
|
||||
1,
|
||||
'1.10.0',
|
||||
);
|
||||
|
||||
const l2Mixnode = new WasmMixNode(
|
||||
2,
|
||||
'n1z93z44vf8ssvdhujjvxcj4rd5e3lz0l60wdk70',
|
||||
'109.74.197.180',
|
||||
1789,
|
||||
'7sVjiMrPYZrDWRujku9QLxgE8noT7NTgBAqizCsu7AoK',
|
||||
'GepXwRnKZDd8x2nBWAajGGBVvF3mrpVMQBkgfrGuqRCN',
|
||||
2,
|
||||
'1.10.0',
|
||||
);
|
||||
|
||||
const l3Mixnode = new WasmMixNode(
|
||||
3,
|
||||
'n1ptg680vnmef2cd8l0s9uyc4f0hgf3x8sed6w77',
|
||||
'176.58.101.80',
|
||||
1789,
|
||||
'FoM5Mx9Pxk1g3zEqkS3APgtBeTtTo3M8k7Yu4bV6kK1R',
|
||||
'DeYjrDC2AcQRVFshiKnbUo6bRvPyZ33QGYR2DLeFJ9qD',
|
||||
3,
|
||||
'1.10.0',
|
||||
);
|
||||
|
||||
const gateway = new WasmGateway(
|
||||
'n16evnn8glr0sham3matj8rg2s24m6x56ayk87ts',
|
||||
'85.159.212.96',
|
||||
1789,
|
||||
9000,
|
||||
'336yuXAeGEgedRfqTJZsG2YV7P13QH1bHv1SjCZYarc9',
|
||||
'BtYjoWihiuFihGKQypmpSspbhmWDPxzqeTVSd8ciCpWL',
|
||||
'1.10.1',
|
||||
);
|
||||
|
||||
const mixnodes = new Map();
|
||||
mixnodes.set(1, [l1Mixnode]);
|
||||
mixnodes.set(2, [l2Mixnode]);
|
||||
mixnodes.set(3, [l3Mixnode]);
|
||||
|
||||
const gateways = [gateway];
|
||||
|
||||
return new WasmNymTopology(mixnodes, gateways);
|
||||
};
|
||||
@@ -1,19 +1,20 @@
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
||||
import { Box, Button } from '@mui/material';
|
||||
import { Download } from '@mui/icons-material';
|
||||
import { NodeTestResultResponse, NodeTester, TestStatus, createNodeTesterClient } from '@nymproject/sdk';
|
||||
import { format } from 'date-fns';
|
||||
import { AppContext, useBondingContext } from 'src/context';
|
||||
import { LoadingModal } from 'src/components/Modals/LoadingModal';
|
||||
import { Results } from 'src/components/TestNode/Results';
|
||||
import { ErrorModal } from 'src/components/Modals/ErrorModal';
|
||||
import { PrintResults } from 'src/components/TestNode/PrintResults';
|
||||
import { Download } from '@mui/icons-material';
|
||||
import { format } from 'date-fns';
|
||||
import { NodeTestEvent, NodeTestResult, TestStatus } from './types';
|
||||
import { MAINNET_VALIDATOR_URL, QA_VALIDATOR_URL } from 'src/constants';
|
||||
|
||||
export const NodeTestPage = () => {
|
||||
const [nodeTestWorker, setNodeTestWorker] = useState<Worker>();
|
||||
const [nodeTestClient, setNodeTestClient] = useState<NodeTester>();
|
||||
const [error, setError] = useState<string>();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [results, setResults] = useState<NodeTestResult>();
|
||||
const [results, setResults] = useState<NodeTestResultResponse>();
|
||||
const [printResults, setPrintResults] = useState(false);
|
||||
const [testDate, setTestDate] = useState<string>();
|
||||
|
||||
@@ -23,15 +24,6 @@ export const NodeTestPage = () => {
|
||||
const { network } = useContext(AppContext);
|
||||
const { bondedNode } = useBondingContext();
|
||||
|
||||
const loadWorker = () => {
|
||||
try {
|
||||
const worker: Worker = new Worker(new URL('./worker.ts', import.meta.url));
|
||||
setNodeTestWorker(worker);
|
||||
} catch (e) {
|
||||
setError('Error loading worker');
|
||||
}
|
||||
};
|
||||
|
||||
const handleTestTimeout = () => {
|
||||
clearTimeout(timerRef.current);
|
||||
timerRef.current = setTimeout(() => {
|
||||
@@ -43,56 +35,52 @@ export const NodeTestPage = () => {
|
||||
}, 15000);
|
||||
};
|
||||
|
||||
const handleWorkerMessages = (ev: MessageEvent<NodeTestEvent>) => {
|
||||
const eventKind = ev.data.kind;
|
||||
|
||||
if (eventKind === 'Error') {
|
||||
setError(ev.data.args.message);
|
||||
testStateRef.current = 'Stopped';
|
||||
}
|
||||
if (eventKind === 'DisplayTesterResults') {
|
||||
setResults(ev.data.args.result);
|
||||
testStateRef.current = 'Complete';
|
||||
}
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const handleTestNode = async () => {
|
||||
setError(undefined);
|
||||
setResults(undefined);
|
||||
setIsLoading(true);
|
||||
setTestDate(format(new Date(), 'dd/MM/yyyy HH:mm'));
|
||||
|
||||
if (nodeTestWorker) {
|
||||
if (nodeTestClient && bondedNode) {
|
||||
setResults(undefined);
|
||||
setTestDate(format(new Date(), 'dd/MM/yyyy HH:mm'));
|
||||
setIsLoading(true);
|
||||
setError(undefined);
|
||||
testStateRef.current = 'Running';
|
||||
nodeTestWorker.postMessage({
|
||||
kind: 'TestPacket',
|
||||
args: {
|
||||
mixnodeIdentity: bondedNode?.identityKey,
|
||||
network,
|
||||
},
|
||||
} as NodeTestEvent);
|
||||
handleTestTimeout();
|
||||
try {
|
||||
const result = await nodeTestClient.tester.startTest(bondedNode.identityKey);
|
||||
setResults(result);
|
||||
testStateRef.current = 'Complete';
|
||||
} catch (e) {
|
||||
setError('Node test failed, please try again');
|
||||
testStateRef.current = 'Stopped';
|
||||
console.log(e);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadWorker();
|
||||
|
||||
return () => {
|
||||
if (nodeTestWorker) {
|
||||
nodeTestWorker.terminate();
|
||||
}
|
||||
};
|
||||
const loadNodeTestClient = useCallback(async () => {
|
||||
try {
|
||||
const nodeTesterId = new Date().toISOString(); // make a new tester id for each session
|
||||
const validator = network === 'MAINNET' ? MAINNET_VALIDATOR_URL : QA_VALIDATOR_URL;
|
||||
const client = await createNodeTesterClient();
|
||||
await client.tester.init(validator, nodeTesterId);
|
||||
setNodeTestClient(client);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
setError('Failed to load node tester client, please try again');
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (nodeTestWorker) {
|
||||
nodeTestWorker.addEventListener('message', (e) => handleWorkerMessages(e));
|
||||
}
|
||||
loadNodeTestClient();
|
||||
|
||||
return () => nodeTestWorker?.removeEventListener('message', handleWorkerMessages);
|
||||
}, [nodeTestWorker]);
|
||||
return () => {
|
||||
clearTimeout(timerRef.current);
|
||||
if (nodeTestClient) {
|
||||
nodeTestClient.tester.disconnectFromGateway();
|
||||
nodeTestClient.terminate();
|
||||
}
|
||||
};
|
||||
}, [loadNodeTestClient]);
|
||||
|
||||
return (
|
||||
<Box p={4}>
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Network } from 'src/types';
|
||||
|
||||
export type NodeTestResult = {
|
||||
score: number;
|
||||
sentPackets: number;
|
||||
receivedPackets: number;
|
||||
receivedAcks: number;
|
||||
duplicatePackets: number;
|
||||
duplicateAcks: number;
|
||||
};
|
||||
|
||||
type Error = {
|
||||
kind: 'Error';
|
||||
args: { message: string };
|
||||
};
|
||||
|
||||
type WorkerLoaded = {
|
||||
kind: 'WorkerLoaded';
|
||||
};
|
||||
|
||||
type DisplayTesterResults = {
|
||||
kind: 'DisplayTesterResults';
|
||||
args: {
|
||||
result: NodeTestResult;
|
||||
};
|
||||
};
|
||||
|
||||
type TestPacket = {
|
||||
kind: 'TestPacket';
|
||||
args: {
|
||||
mixnodeIdentity: string;
|
||||
network: Network;
|
||||
};
|
||||
};
|
||||
|
||||
export type TestStatus = 'Stopped' | 'Running' | 'Complete';
|
||||
|
||||
export type NodeTestEvent = Error | DisplayTesterResults | TestPacket | WorkerLoaded;
|
||||
@@ -1,102 +0,0 @@
|
||||
// Copyright 2020-2023 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/* eslint-disable no-restricted-globals */
|
||||
import { NymNodeTester, set_panic_hook, current_network_topology, NodeTestResult } from 'nym-client-wasm';
|
||||
import { Network } from 'src/types';
|
||||
import { NodeTestEvent } from './types';
|
||||
import { MAINNET_VALIDATOR_URL, QA_VALIDATOR_URL } from 'src/constants';
|
||||
|
||||
console.log('Initializing worker');
|
||||
|
||||
const postMessage = (data: NodeTestEvent) => self.postMessage(data);
|
||||
|
||||
postMessage({
|
||||
kind: 'WorkerLoaded',
|
||||
});
|
||||
|
||||
const printAndDisplayTestResult = (result: NodeTestResult) => {
|
||||
result.log_details();
|
||||
|
||||
postMessage({
|
||||
kind: 'DisplayTesterResults',
|
||||
args: {
|
||||
result: {
|
||||
score: result.score(),
|
||||
sentPackets: result.sent_packets,
|
||||
receivedPackets: result.received_packets,
|
||||
receivedAcks: result.received_acks,
|
||||
duplicatePackets: result.duplicate_packets,
|
||||
duplicateAcks: result.duplicate_acks,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const buildTester = async (network: Network) => {
|
||||
const validator = network === 'QA' ? QA_VALIDATOR_URL : MAINNET_VALIDATOR_URL;
|
||||
const topology = await current_network_topology(validator);
|
||||
const nodeTester = await new NymNodeTester(topology, network);
|
||||
|
||||
return nodeTester;
|
||||
};
|
||||
|
||||
async function testNode() {
|
||||
self.onmessage = async (event: MessageEvent<NodeTestEvent>) => {
|
||||
const eventKind = event.data.kind;
|
||||
|
||||
switch (eventKind) {
|
||||
case 'TestPacket': {
|
||||
const { mixnodeIdentity, network } = event.data.args;
|
||||
const nodeTester = await buildTester(network);
|
||||
|
||||
try {
|
||||
console.log(`Testing mixnode identity: ${mixnodeIdentity}, on network: ${network}.`);
|
||||
const result = await nodeTester.test_node(mixnodeIdentity);
|
||||
|
||||
printAndDisplayTestResult(result);
|
||||
|
||||
await nodeTester.disconnect_from_gateway();
|
||||
console.log('Disconnected from gateway');
|
||||
} catch (e) {
|
||||
const errorMessage = e instanceof Error ? e.message : 'Node test error';
|
||||
console.log(errorMessage);
|
||||
|
||||
nodeTester.disconnect_from_gateway();
|
||||
|
||||
postMessage({
|
||||
kind: 'Error',
|
||||
args: { message: errorMessage },
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// sets up better stack traces in case of in-rust panics
|
||||
set_panic_hook();
|
||||
|
||||
// run test on simplified and dedicated tester:
|
||||
await testNode();
|
||||
}
|
||||
|
||||
// Let's get started!
|
||||
main();
|
||||
+4
-3
@@ -10,8 +10,7 @@
|
||||
"nym-connect/**",
|
||||
"explorer",
|
||||
"types",
|
||||
"clients/validator",
|
||||
"clients/webassembly/**"
|
||||
"clients/validator"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "lerna run clean",
|
||||
@@ -28,7 +27,9 @@
|
||||
"lint:fix": "lerna run lint:fix --stream",
|
||||
"tsc": "lerna run tsc --stream",
|
||||
"types:lint:fix": "lerna run lint:fix --scope @nymproject/types --scope @nymproject/nym-wallet-app",
|
||||
"audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run"
|
||||
"audit:fix": "npm_config_yes=true npx yarn-audit-fix -- --dry-run",
|
||||
"preinstall": "yarn install:copy-placeholders",
|
||||
"install:copy-placeholders": "cp scripts/build/yarn/wasm-placeholder/package.json sdk/typescript/packages/nym-client-wasm"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lerna": "^6.6.2",
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@nymproject/nym-client-wasm",
|
||||
"version": "1.0.0",
|
||||
"sideEffects": false
|
||||
}
|
||||
@@ -27,7 +27,7 @@ module.exports = {
|
||||
'plugin:jest/recommended',
|
||||
'plugin:jest/style',
|
||||
],
|
||||
ignorePatterns: ['dist/**/*', 'dist', 'node_modules', '**/wasm/worker.js'],
|
||||
ignorePatterns: ['dist/**/*', 'dist', 'node_modules', '**/worker.js'],
|
||||
rules: {
|
||||
'jest/prefer-strict-equal': 'error',
|
||||
'jest/prefer-to-have-length': 'warn',
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/env", "@babel/react"]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# HTML Nyn Node Test
|
||||
|
||||
This is an example of using the Nym Mixnet node tester.
|
||||
|
||||
You can use this example as a seed for a new project.
|
||||
|
||||
## Running the example
|
||||
|
||||
Try out the node tester app by running:
|
||||
|
||||
```
|
||||
npm install
|
||||
npm start
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "@nymproject/sdk-example-node-tester-plain-html",
|
||||
"description": "An example project that uses WASM node tester and plain HTML",
|
||||
"version": "1.0.0",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/plugin-transform-async-to-generator": "^7.14.5",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.7.13",
|
||||
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
||||
"@typescript-eslint/parser": "^5.13.0",
|
||||
"babel-loader": "^8.3.0",
|
||||
"babel-plugin-root-import": "^5.1.0",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"css-loader": "^6.7.3",
|
||||
"css-minimizer-webpack-plugin": "^3.0.2",
|
||||
"dotenv-webpack": "^7.0.3",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^16.1.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-root-import": "^1.0.4",
|
||||
"eslint-plugin-import": "^2.25.4",
|
||||
"eslint-plugin-jest": "^26.1.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^7.2.1",
|
||||
"html-webpack-plugin": "^5.3.2",
|
||||
"jest": "^27.1.0",
|
||||
"mini-css-extract-plugin": "^2.2.2",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.8.7",
|
||||
"style-loader": "^3.3.1",
|
||||
"thread-loader": "^3.0.4",
|
||||
"ts-jest": "^27.0.5",
|
||||
"ts-loader": "^9.4.2",
|
||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||
"typescript": "^4.6.2",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.5.0",
|
||||
"webpack-merge": "^5.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "webpack serve --progress --port 3000",
|
||||
"build": "webpack build --progress --config webpack.prod.js",
|
||||
"build:dev": "webpack build --progress",
|
||||
"build:serve": "npx serve dist",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"tsc": "tsc",
|
||||
"tsc:watch": "tsc --watch",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint src --fix"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Nym WebAssembly Demo</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>
|
||||
<label>Mixnode Id: </label><input size="85" type="text" id="mixnodeId" value="">
|
||||
</p>
|
||||
<p>
|
||||
<button id="send-button">Test</button>
|
||||
<button id="disconnect-button">Disconnect from Gateway</button>
|
||||
<button id="reconnect-button">Reconnect to Gateway</button>
|
||||
<button id="terminate-button">Terminate worker</button>
|
||||
</p>
|
||||
|
||||
<p>Test a mixnode by entering the mixnode id above and click the Test button</p>
|
||||
|
||||
<hr>
|
||||
<p>
|
||||
<div id="output"></div>
|
||||
</p>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,116 @@
|
||||
import { createNodeTesterClient, NodeTester } from '@nymproject/sdk';
|
||||
|
||||
let nodeTester: NodeTester | null = null;
|
||||
|
||||
/**
|
||||
* Display messages that have been sent up the websocket. Colours them blue.
|
||||
*
|
||||
* @param {string} message
|
||||
*/
|
||||
function displayOutput(message: string, color?: string) {
|
||||
const timestamp = new Date().toISOString().substr(11, 12);
|
||||
|
||||
const sendDiv = document.createElement('div');
|
||||
const paragraph = document.createElement('p');
|
||||
paragraph.setAttribute('style', `color: ${color || 'blue'}`);
|
||||
const paragraphContent = document.createTextNode(`${timestamp} >>> ${message}`);
|
||||
paragraph.appendChild(paragraphContent);
|
||||
|
||||
sendDiv.appendChild(paragraph);
|
||||
document.getElementById('output')?.appendChild(sendDiv);
|
||||
}
|
||||
|
||||
/**
|
||||
* The main entry point
|
||||
*/
|
||||
async function main() {
|
||||
nodeTester = await createNodeTesterClient();
|
||||
|
||||
// add node tester to the Window globally, so that it can be used from the dev tools console
|
||||
(window as any).nodeTester = nodeTester;
|
||||
|
||||
if (!nodeTester) {
|
||||
console.error('Oh no! Could not the node test');
|
||||
return;
|
||||
}
|
||||
|
||||
const nymApiUrl = 'https://validator.nymtech.net/api';
|
||||
const nodeTesterId = new Date().toISOString(); // make a new tester id for each session
|
||||
await nodeTester.tester.init(nymApiUrl, nodeTesterId);
|
||||
|
||||
const mixnodes = await (await fetch(`${nymApiUrl}/v1/mixnodes/active`)).json();
|
||||
|
||||
const exampleMixnodeIdentityKey = mixnodes[0].bond_information.mix_node.identity_key;
|
||||
|
||||
const sendButton: HTMLButtonElement = document.querySelector('#send-button') as HTMLButtonElement;
|
||||
const reconnectButton: HTMLButtonElement = document.querySelector('#reconnect-button') as HTMLButtonElement;
|
||||
const disconnectButton: HTMLButtonElement = document.querySelector('#disconnect-button') as HTMLButtonElement;
|
||||
const terminateButton: HTMLButtonElement = document.querySelector('#terminate-button') as HTMLButtonElement;
|
||||
|
||||
const mixnodeIdInput = document.getElementById('mixnodeId') as HTMLFormElement;
|
||||
|
||||
mixnodeIdInput.value = exampleMixnodeIdentityKey;
|
||||
|
||||
reconnectButton.onclick = async function () {
|
||||
try {
|
||||
await nodeTester?.tester.reconnectToGateway();
|
||||
} catch (e: any) {
|
||||
console.error('Error', e);
|
||||
displayOutput(`ERROR: ${e.message}`, 'red');
|
||||
}
|
||||
};
|
||||
|
||||
disconnectButton.onclick = async function () {
|
||||
try {
|
||||
await nodeTester?.tester.disconnectFromGateway();
|
||||
} catch (e: any) {
|
||||
console.error('Error', e);
|
||||
displayOutput(`ERROR: ${e.message}`, 'red');
|
||||
}
|
||||
};
|
||||
|
||||
terminateButton.onclick = async function () {
|
||||
try {
|
||||
await nodeTester?.terminate();
|
||||
} catch (e: any) {
|
||||
console.error('Error', e);
|
||||
displayOutput(`ERROR: ${e.message}`, 'red');
|
||||
}
|
||||
};
|
||||
|
||||
if (sendButton) {
|
||||
sendButton.onclick = async function () {
|
||||
const mixnodeId = mixnodeIdInput.value;
|
||||
if (!nodeTester) {
|
||||
displayOutput('ERROR: The node tester is not defined');
|
||||
console.error('The node tester is not defined');
|
||||
return;
|
||||
}
|
||||
if (!mixnodeId) {
|
||||
displayOutput('ERROR: No mix id specified');
|
||||
console.error('No mix id specified');
|
||||
return;
|
||||
}
|
||||
|
||||
if (nodeTester && mixnodeId) {
|
||||
displayOutput('Starting test...');
|
||||
try {
|
||||
const response = await nodeTester.tester.startTest(mixnodeId);
|
||||
displayOutput('Done!');
|
||||
if (response) {
|
||||
displayOutput(JSON.stringify(response, null, 2), 'green');
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.error('Error', e);
|
||||
displayOutput(`ERROR: ${e.message}`, 'red');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// wait for the html to load
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
// let's do this!
|
||||
main();
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "build", "dist"]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist",
|
||||
"declaration": false
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "build", "dist", "**/*.stories.*", "**/*.test.*", "**/*.spec.*"]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
const path = require('path');
|
||||
const { mergeWithRules } = require('webpack-merge');
|
||||
const { webpackCommon } = require('../../.webpack/webpack.base');
|
||||
|
||||
module.exports = mergeWithRules({
|
||||
module: {
|
||||
rules: {
|
||||
test: 'match',
|
||||
use: 'replace',
|
||||
},
|
||||
},
|
||||
})(
|
||||
webpackCommon(__dirname, [
|
||||
{
|
||||
inject: true,
|
||||
filename: 'index.html',
|
||||
template: path.resolve(__dirname, 'src/index.html'),
|
||||
chunks: ['index'],
|
||||
},
|
||||
]),
|
||||
{
|
||||
entry: {
|
||||
index: path.resolve(__dirname, 'src/index.ts'),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
publicPath: '/',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,67 @@
|
||||
const { mergeWithRules } = require('webpack-merge');
|
||||
const webpack = require('webpack');
|
||||
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
|
||||
const ReactRefreshTypeScript = require('react-refresh-typescript');
|
||||
const commonConfig = require('./webpack.common');
|
||||
|
||||
module.exports = mergeWithRules({
|
||||
module: {
|
||||
rules: {
|
||||
test: 'match',
|
||||
use: 'replace',
|
||||
},
|
||||
},
|
||||
})(commonConfig, {
|
||||
mode: 'development',
|
||||
devtool: 'inline-source-map',
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
options: {
|
||||
getCustomTransformers: () => ({
|
||||
before: [ReactRefreshTypeScript()],
|
||||
}),
|
||||
// `ts-loader` does not work with HMR unless `transpileOnly` is used.
|
||||
// If you need type checking, `ForkTsCheckerWebpackPlugin` is an alternative.
|
||||
transpileOnly: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new ReactRefreshWebpackPlugin(),
|
||||
|
||||
// this can be included automatically by the dev server, however build mode fails if missing
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
],
|
||||
|
||||
target: 'web',
|
||||
|
||||
devServer: {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
|
||||
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
|
||||
},
|
||||
historyApiFallback: true,
|
||||
},
|
||||
|
||||
// recommended for faster rebuild
|
||||
optimization: {
|
||||
runtimeChunk: true,
|
||||
removeAvailableModules: false,
|
||||
removeEmptyChunks: false,
|
||||
splitChunks: false,
|
||||
},
|
||||
|
||||
cache: {
|
||||
type: 'filesystem',
|
||||
buildDependencies: {
|
||||
// restart on config change
|
||||
config: ['./webpack.config.js'],
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
const { mergeWithRules } = require('webpack-merge');
|
||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const commonConfig = require('./webpack.common');
|
||||
|
||||
module.exports = mergeWithRules({
|
||||
module: {
|
||||
rules: {
|
||||
test: 'match',
|
||||
use: 'replace',
|
||||
},
|
||||
},
|
||||
})(commonConfig, {
|
||||
mode: 'production',
|
||||
|
||||
// TODO: no source maps, add back
|
||||
devtool: false,
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [MiniCssExtractPlugin.loader, 'css-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
minimizer: ['...', new CssMinimizerPlugin()],
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: '[name].[contenthash].css',
|
||||
}),
|
||||
],
|
||||
output: {
|
||||
pathinfo: false,
|
||||
filename: '[name].[contenthash].js',
|
||||
},
|
||||
});
|
||||
@@ -1,20 +1,10 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"outDir": "./dist",
|
||||
"declaration": false
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"build",
|
||||
"dist",
|
||||
"**/*.stories.*",
|
||||
"**/*.test.*",
|
||||
"**/*.spec.*"
|
||||
]
|
||||
"include": ["src/**/*.ts", "src/**/*.tsx"],
|
||||
"exclude": ["node_modules", "build", "dist", "**/*.stories.*", "**/*.test.*", "**/*.spec.*"]
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
src/mixnet/wasm/worker.js
|
||||
src/mixnet/node-tester/worker.js
|
||||
@@ -34,6 +34,16 @@ The output bundle will be created in the `dist` directory.
|
||||
|
||||
If you're a Nym platform developer who's made changes to the Rust (or JS) files and wants to re-publish the package to NPM, here's how you do it:
|
||||
|
||||
Make sure you have logged into the NPM registry (`npm login`).
|
||||
|
||||
### Scripted
|
||||
|
||||
1. bump version numbers as necessary for SemVer
|
||||
2. make sure you're in the SDK directory (`cd sdk/typescript/packages/sdk`)
|
||||
3. run `scripts/publish.sh`
|
||||
|
||||
### Manually
|
||||
|
||||
1. bump version numbers as necessary for SemVer
|
||||
2. `yarn build` builds the release directory in the root of the repo in `dist/sdk`
|
||||
3. `cd ../../../../dist/sdk`
|
||||
@@ -45,3 +55,6 @@ Publish the CJS package:
|
||||
Publish the ESM package:
|
||||
- `cd ../esm`
|
||||
- `npm publish --access=public` will publish your changed package to NPM
|
||||
|
||||
4. bump the minor version and add `-rc0` to avoid local packages from using the workspace SDK, e.g. (`1.1.10` -> `1.1.11-rc0`)
|
||||
5. commit the updated `package.json` to git
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nymproject/sdk",
|
||||
"version": "1.1.7",
|
||||
"version": "1.1.9-rc0",
|
||||
"license": "Apache-2.0",
|
||||
"author": "Nym Technologies SA",
|
||||
"type": "module",
|
||||
@@ -26,10 +26,12 @@
|
||||
"build:only-this": "scripts/build-prod.sh",
|
||||
"prebuild:dev": "yarn build:dependencies",
|
||||
"build:dev": "yarn build:dev:only-this",
|
||||
"build:dev:only-this": "scripts/build.sh"
|
||||
"build:dev:only-this": "scripts/build.sh",
|
||||
"build:local": "run-s build:dependencies:nym-client-wasm build:dev:only-this"
|
||||
},
|
||||
"dependencies": {
|
||||
"@npmcli/node-gyp": "^3.0.0",
|
||||
"@nymproject/nym-client-wasm": "1",
|
||||
"comlink": "^4.3.1",
|
||||
"lerna": "^6.6.2",
|
||||
"node-gyp": "^9.3.1"
|
||||
|
||||
@@ -3,9 +3,7 @@ import resolve from '@rollup/plugin-node-resolve';
|
||||
import { wasm } from '@rollup/plugin-wasm';
|
||||
import webWorkerLoader from 'rollup-plugin-web-worker-loader';
|
||||
|
||||
const extensions = [
|
||||
'.js', '.jsx', '.ts', '.tsx',
|
||||
];
|
||||
const extensions = ['.js', '.jsx', '.ts', '.tsx'];
|
||||
|
||||
export default {
|
||||
input: 'src/index.ts',
|
||||
@@ -17,6 +15,9 @@ export default {
|
||||
webWorkerLoader({ targetPlatform: 'browser', inline: true }),
|
||||
resolve({ extensions }),
|
||||
wasm({ maxFileSize: 10000000, targetEnv: 'browser' }),
|
||||
typescript({ compilerOptions: { outDir: 'dist/cjs', target: 'es5' }, exclude: 'mixnet/wasm/worker.ts', }),
|
||||
typescript({
|
||||
compilerOptions: { outDir: 'dist/cjs', target: 'es5' },
|
||||
exclude: ['mixnet/wasm/worker.ts', 'mixnet/node-tester/worker.ts'],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -2,9 +2,7 @@ import typescript from '@rollup/plugin-typescript';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import webWorkerLoader from 'rollup-plugin-web-worker-loader';
|
||||
|
||||
const extensions = [
|
||||
'.js', '.jsx', '.ts', '.tsx',
|
||||
];
|
||||
const extensions = ['.js', '.jsx', '.ts', '.tsx'];
|
||||
|
||||
export default {
|
||||
input: 'src/index.ts',
|
||||
@@ -15,6 +13,9 @@ export default {
|
||||
plugins: [
|
||||
webWorkerLoader({ targetPlatform: 'browser', inline: true }),
|
||||
resolve({ extensions }),
|
||||
typescript({ exclude: 'mixnet/wasm/worker.ts', compilerOptions: { outDir: 'dist/esm' } }),
|
||||
typescript({
|
||||
exclude: ['mixnet/wasm/worker.ts', 'mixnet/node-tester/worker.ts'],
|
||||
compilerOptions: { outDir: 'dist/esm' },
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import { wasm } from '@rollup/plugin-wasm';
|
||||
import replace from '@rollup/plugin-replace';
|
||||
|
||||
const extensions = ['.js', '.jsx', '.ts', '.tsx'];
|
||||
|
||||
export default {
|
||||
input: 'src/mixnet/node-tester/worker.ts',
|
||||
output: {
|
||||
dir: 'dist',
|
||||
format: 'cjs',
|
||||
},
|
||||
plugins: [
|
||||
resolve({ extensions }),
|
||||
// this is some nasty monkey patching that removes the WASM URL (because it is handled by the `wasm` plugin)
|
||||
replace({
|
||||
values: { "input = new URL('nym_client_wasm_bg.wasm', import.meta.url);": 'input = undefined;' },
|
||||
delimiters: ['', ''],
|
||||
preventAssignment: true,
|
||||
}),
|
||||
// force the wasm plugin to embed the wasm bundle - this means no downstream bundlers have to worry about handling it
|
||||
wasm({ maxFileSize: 10000000, targetEnv: 'browser' }),
|
||||
typescript({ compilerOptions: { declaration: false, target: 'es5' } }),
|
||||
],
|
||||
};
|
||||
@@ -7,7 +7,7 @@ set -o pipefail
|
||||
rm -rf dist || true
|
||||
|
||||
#-------------------------------------------------------
|
||||
# WEB WORKER
|
||||
# WEB WORKER (WASM client)
|
||||
#-------------------------------------------------------
|
||||
# The web worker needs to be bundled because the WASM bundle needs to be loaded synchronously and all dependencies
|
||||
# must be included in the worker script (because it is not loaded as an ES Module)
|
||||
@@ -19,6 +19,19 @@ rollup -c rollup-worker.config.mjs
|
||||
rm -f src/mixnet/wasm/worker.js
|
||||
mv dist/worker.js src/mixnet/wasm/worker.js
|
||||
|
||||
#-------------------------------------------------------
|
||||
# WEB WORKER (Node tester)
|
||||
#-------------------------------------------------------
|
||||
# The web worker needs to be bundled because the WASM bundle needs to be loaded synchronously and all dependencies
|
||||
# must be included in the worker script (because it is not loaded as an ES Module)
|
||||
|
||||
# build the worker
|
||||
rollup -c rollup-node-tester-worker.config.mjs
|
||||
|
||||
# move it next to the Typescript `mixnet/node-tester/index.ts` so it can be inlined by rollup
|
||||
rm -f src/mixnet/node-tester/worker.js
|
||||
mv dist/worker.js src/mixnet/node-tester/worker.js
|
||||
|
||||
#-------------------------------------------------------
|
||||
# ESM
|
||||
#-------------------------------------------------------
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
|
||||
rm -rf dist || true
|
||||
rm -rf ../../../../dist || true
|
||||
|
||||
yarn
|
||||
yarn build
|
||||
cd ../../../../dist/sdk
|
||||
|
||||
cd cjs
|
||||
echo "Publishing CommonJS package to NPM.."
|
||||
npm publish --access=public
|
||||
cd ..
|
||||
|
||||
cd esm
|
||||
echo "Publishing ESM package to NPM.."
|
||||
npm publish --access=public
|
||||
cd ..
|
||||
@@ -1,2 +1,4 @@
|
||||
export * from './wasm';
|
||||
export * from './wasm/types';
|
||||
export * from './node-tester';
|
||||
export * from './node-tester/types';
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
const QA_VALIDATOR_URL = 'https://qa-nym-api.qa.nymte.ch/api';
|
||||
const QWERTY_VALIDATOR_URL = 'https://qwerty-validator-api.qa.nymte.ch/api';
|
||||
const MAINNET_VALIDATOR_URL = 'https://validator.nymtech.net/api/';
|
||||
|
||||
export { QA_VALIDATOR_URL, QWERTY_VALIDATOR_URL, MAINNET_VALIDATOR_URL };
|
||||
@@ -0,0 +1,50 @@
|
||||
import InlineWasmWebWorker from 'web-worker:./worker';
|
||||
import * as Comlink from 'comlink';
|
||||
import { INodeTesterWorkerAsync, NodeTester, NodeTesterEventKinds } from './types';
|
||||
|
||||
/**
|
||||
* Client for the Nym node tester.
|
||||
*/
|
||||
export const createNodeTesterClient = async (): Promise<NodeTester> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
const worker = await createWorker();
|
||||
|
||||
// let comlink handle interop with the web worker
|
||||
const tester = Comlink.wrap<INodeTesterWorkerAsync>(worker);
|
||||
|
||||
// expose the method to terminate the worker
|
||||
const terminate = async () => {
|
||||
worker.terminate();
|
||||
};
|
||||
|
||||
return { tester, terminate };
|
||||
};
|
||||
|
||||
/**
|
||||
* Async method to create a web worker that runs the Nym node tester client on another thread. It will only return once the worker
|
||||
* has passed back a `Loaded` event to the calling thread.
|
||||
*
|
||||
* @return The instance of the web worker.
|
||||
*/
|
||||
|
||||
const createWorker = async () =>
|
||||
new Promise<Worker>((resolve, reject) => {
|
||||
// rollup will inline the built worker script, so that when the SDK is used in
|
||||
// other projects, they will not need to mess around trying to bundle it
|
||||
// however, it will make this SDK bundle bigger because of Base64 inline data
|
||||
const worker = new InlineWasmWebWorker();
|
||||
|
||||
worker.addEventListener('error', reject);
|
||||
worker.addEventListener(
|
||||
'message',
|
||||
(msg) => {
|
||||
worker.removeEventListener('error', reject);
|
||||
if (msg.data?.kind === NodeTesterEventKinds.Loaded) {
|
||||
resolve(worker);
|
||||
} else {
|
||||
reject(msg);
|
||||
}
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
export interface INodeTesterWorkerAsync {
|
||||
init: (validatorUrl: string, nodeTesterId?: string) => Promise<void>;
|
||||
reconnectToGateway: () => Promise<void>;
|
||||
disconnectFromGateway: () => Promise<void>;
|
||||
startTest: (mixnodeIdentityKey: string) => Promise<NodeTestResultResponse | undefined>;
|
||||
}
|
||||
|
||||
export interface INodeTesterWorkerDisposableAsync {
|
||||
terminate: () => Promise<void>;
|
||||
}
|
||||
|
||||
export interface NodeTester extends INodeTesterWorkerDisposableAsync {
|
||||
tester: INodeTesterWorkerAsync;
|
||||
}
|
||||
|
||||
export enum NodeTesterEventKinds {
|
||||
Loaded = 'Loaded',
|
||||
Connected = 'Connected',
|
||||
}
|
||||
|
||||
export interface NodeTesterLoadedEvent {
|
||||
kind: NodeTesterEventKinds.Loaded;
|
||||
args: {
|
||||
loaded: true;
|
||||
};
|
||||
}
|
||||
|
||||
export type Network = 'QA' | 'SANDBOX' | 'MAINNET';
|
||||
|
||||
export type NodeTestResultResponse = {
|
||||
score: number;
|
||||
sentPackets: number;
|
||||
receivedPackets: number;
|
||||
receivedAcks: number;
|
||||
duplicatePackets: number;
|
||||
duplicateAcks: number;
|
||||
};
|
||||
|
||||
export type Error = {
|
||||
kind: 'Error';
|
||||
args: { message: string };
|
||||
};
|
||||
|
||||
export type WorkerLoaded = {
|
||||
kind: 'WorkerLoaded';
|
||||
};
|
||||
|
||||
export type DisplayTesterResults = {
|
||||
kind: 'DisplayTesterResults';
|
||||
args: {
|
||||
result: NodeTestResultResponse;
|
||||
};
|
||||
};
|
||||
|
||||
export type TestPacket = {
|
||||
kind: 'TestPacket';
|
||||
args: {
|
||||
mixnodeIdentity: string;
|
||||
network: Network;
|
||||
};
|
||||
};
|
||||
|
||||
export type TestStatus = 'Stopped' | 'Running' | 'Complete';
|
||||
|
||||
export type NodeTestEvent = Error | DisplayTesterResults | TestPacket | WorkerLoaded;
|
||||
@@ -0,0 +1,105 @@
|
||||
// Copyright 2020-2023 Nym Technologies SA
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as Comlink from 'comlink';
|
||||
|
||||
//
|
||||
// Rollup will replace wasmBytes with a function that loads the WASM bundle from a base64 string embedded in the output.
|
||||
//
|
||||
// Doing it this way, saves having to support a large variety of bundlers and their quirks.
|
||||
//
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import wasmBytes from '@nymproject/nym-client-wasm/nym_client_wasm_bg.wasm';
|
||||
|
||||
/* eslint-disable no-restricted-globals */
|
||||
import init, { NymNodeTester, current_network_topology, NodeTestResult } from '@nymproject/nym-client-wasm';
|
||||
import type { INodeTesterWorkerAsync, NodeTesterLoadedEvent } from './types';
|
||||
import { NodeTesterEventKinds } from './types';
|
||||
|
||||
/**
|
||||
* Helper method to send typed messages.
|
||||
* @param event The strongly typed message to send back to the calling thread.
|
||||
*/
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
const postMessageWithType = <E>(event: E) => self.postMessage(event);
|
||||
|
||||
console.log('[Nym WASM client] Starting Nym WASM web worker...');
|
||||
|
||||
const buildTester = async (validatorUrl: string, nodeTesterId?: string): Promise<NymNodeTester> => {
|
||||
const topology = await current_network_topology(validatorUrl);
|
||||
return new NymNodeTester(topology, nodeTesterId);
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const importResult = await init(wasmBytes());
|
||||
importResult.set_panic_hook();
|
||||
|
||||
let nodeTester: NymNodeTester | null = null;
|
||||
|
||||
const webWorker: INodeTesterWorkerAsync = {
|
||||
async init(validatorUrl: string, nodeTesterId?: string) {
|
||||
nodeTester = await buildTester(validatorUrl, nodeTesterId);
|
||||
},
|
||||
async reconnectToGateway() {
|
||||
if (!nodeTester) {
|
||||
throw Error('Please run init first');
|
||||
}
|
||||
await nodeTester.reconnect_to_gateway();
|
||||
},
|
||||
async disconnectFromGateway() {
|
||||
if (!nodeTester) {
|
||||
throw Error('Please run init first');
|
||||
}
|
||||
await nodeTester.disconnect_from_gateway();
|
||||
},
|
||||
async startTest(mixnodeIdentityKey: string) {
|
||||
if (!nodeTester) {
|
||||
throw Error('Please run init first');
|
||||
}
|
||||
console.log(`Testing mixnode with identity key = ${mixnodeIdentityKey}`);
|
||||
// TODO: fix typing in Rust code
|
||||
const result = (await nodeTester.test_node(mixnodeIdentityKey)) as NodeTestResult | undefined;
|
||||
|
||||
// return early if there was an error
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// log the result in the worker so that the packet stats are visible somewhere and extract the score
|
||||
result.log_details();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { duplicate_acks, duplicate_packets, received_acks, received_packets, sent_packets } = result;
|
||||
|
||||
// construct the response to avoid any weird proxy effects
|
||||
return {
|
||||
score: result.score(),
|
||||
sentPackets: sent_packets,
|
||||
receivedPackets: received_packets,
|
||||
receivedAcks: received_acks,
|
||||
duplicatePackets: duplicate_packets,
|
||||
duplicateAcks: duplicate_acks,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// start comlink listening for messages and handle them above
|
||||
Comlink.expose(webWorker);
|
||||
|
||||
// notify any listeners that the web worker has loaded and is ready for testing
|
||||
postMessageWithType<NodeTesterLoadedEvent>({ kind: NodeTesterEventKinds.Loaded, args: { loaded: true } });
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,336 @@
|
||||
/**
|
||||
*/
|
||||
export interface TopologyWasm {
|
||||
free(): void;
|
||||
/**
|
||||
* Specifies whether the client should not refresh the network topology after obtaining
|
||||
* the first valid instance.
|
||||
* Supersedes `topology_refresh_rate_ms`.
|
||||
*/
|
||||
disable_refreshing: boolean;
|
||||
/**
|
||||
* The uniform delay every which clients are querying the directory server
|
||||
* to try to obtain a compatible network topology to send sphinx packets through.
|
||||
*/
|
||||
topology_refresh_rate_ms: bigint;
|
||||
/**
|
||||
* During topology refresh, test packets are sent through every single possible network
|
||||
* path. This timeout determines waiting period until it is decided that the packet
|
||||
* did not reach its destination.
|
||||
*/
|
||||
topology_resolution_timeout_ms: bigint;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
export interface TrafficWasm {
|
||||
free(): void;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* sent packet is going to be delayed at any given mix node.
|
||||
* So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
* until the packet reaches its destination.
|
||||
*/
|
||||
average_packet_delay_ms: bigint;
|
||||
/**
|
||||
* Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
* poisson distribution.
|
||||
*/
|
||||
disable_main_poisson_packet_distribution: boolean;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* it is going to take another 'real traffic stream' message to be sent.
|
||||
* If no real packets are available and cover traffic is enabled,
|
||||
* a loop cover message is sent instead in order to preserve the rate.
|
||||
*/
|
||||
message_sending_average_delay_ms: bigint;
|
||||
/**
|
||||
* Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
|
||||
*/
|
||||
use_extended_packet_size: boolean;
|
||||
/**
|
||||
* Controls whether the sent packets should use outfox as opposed to the default sphinx.
|
||||
*/
|
||||
use_outfox: boolean;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
export interface WasmGateway {
|
||||
free(): void;
|
||||
/**
|
||||
*/
|
||||
clients_port: number;
|
||||
/**
|
||||
*/
|
||||
host: string;
|
||||
/**
|
||||
*/
|
||||
identity_key: string;
|
||||
/**
|
||||
*/
|
||||
mix_port: number;
|
||||
/**
|
||||
*/
|
||||
owner: string;
|
||||
/**
|
||||
*/
|
||||
sphinx_key: string;
|
||||
/**
|
||||
*/
|
||||
version: string;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
export interface ReplySurbsWasm {
|
||||
free(): void;
|
||||
/**
|
||||
* Defines the maximum number of reply surbs a remote party is allowed to request from this client at once.
|
||||
*/
|
||||
maximum_allowed_reply_surb_request_size: number;
|
||||
/**
|
||||
* Defines maximum amount of time given reply key is going to be valid for.
|
||||
* This is going to be superseded by key rotation once implemented.
|
||||
*/
|
||||
maximum_reply_key_age_ms: bigint;
|
||||
/**
|
||||
* Defines maximum amount of time given reply surb is going to be valid for.
|
||||
* This is going to be superseded by key rotation once implemented.
|
||||
*/
|
||||
maximum_reply_surb_age_ms: bigint;
|
||||
/**
|
||||
* Defines maximum amount of time the client is going to wait for reply surbs before
|
||||
* deciding it's never going to get them and would drop all pending messages
|
||||
*/
|
||||
maximum_reply_surb_drop_waiting_period_ms: bigint;
|
||||
/**
|
||||
* Defines the maximum number of reply surbs the client would request.
|
||||
*/
|
||||
maximum_reply_surb_request_size: number;
|
||||
/**
|
||||
* Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking
|
||||
* for more even though in theory they wouldn't need to.
|
||||
*/
|
||||
maximum_reply_surb_rerequest_waiting_period_ms: bigint;
|
||||
/**
|
||||
* Defines the maximum number of reply surbs the client wants to keep in its storage at any times.
|
||||
*/
|
||||
maximum_reply_surb_storage_threshold: number;
|
||||
/**
|
||||
* Defines the minimum number of reply surbs the client would request.
|
||||
*/
|
||||
minimum_reply_surb_request_size: number;
|
||||
/**
|
||||
* Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
* It can only allow to go below that value if its to request additional reply surbs.
|
||||
*/
|
||||
minimum_reply_surb_storage_threshold: number;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
export interface GatewayConnectionWasm {
|
||||
free(): void;
|
||||
/**
|
||||
* How long we're willing to wait for a response to a message sent to the gateway,
|
||||
* before giving up on it.
|
||||
*/
|
||||
gateway_response_timeout_ms: bigint;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
export interface AcknowledgementsWasm {
|
||||
free(): void;
|
||||
/**
|
||||
* Value added to the expected round trip time of an acknowledgement packet before
|
||||
* it is assumed it was lost and retransmission of the data packet happens.
|
||||
* In an ideal network with 0 latency, this value would have been 0.
|
||||
*/
|
||||
ack_wait_addition_ms: bigint;
|
||||
/**
|
||||
* Value multiplied with the expected round trip time of an acknowledgement packet before
|
||||
* it is assumed it was lost and retransmission of the data packet happens.
|
||||
* In an ideal network with 0 latency, this value would have been 1.
|
||||
*/
|
||||
ack_wait_multiplier: number;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* sent acknowledgement is going to be delayed at any given mix node.
|
||||
* So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
* until the packet reaches its destination.
|
||||
*/
|
||||
average_ack_delay_ms: bigint;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
export interface CoverTrafficWasm {
|
||||
free(): void;
|
||||
/**
|
||||
* Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic.
|
||||
* Only applicable if `secondary_packet_size` is enabled.
|
||||
*/
|
||||
cover_traffic_primary_size_ratio: number;
|
||||
/**
|
||||
* Controls whether the dedicated loop cover traffic stream should be enabled.
|
||||
* (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
|
||||
*/
|
||||
disable_loop_cover_traffic_stream: boolean;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* it is going to take for another loop cover traffic message to be sent.
|
||||
*/
|
||||
loop_cover_traffic_average_delay_ms: bigint;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
free(): void;
|
||||
}
|
||||
|
||||
export interface DebugWasm {
|
||||
free(): void;
|
||||
/**
|
||||
* Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
*/
|
||||
acknowledgements: AcknowledgementsWasm;
|
||||
/**
|
||||
* Defines all configuration options related to cover traffic stream(s).
|
||||
*/
|
||||
cover_traffic: CoverTrafficWasm;
|
||||
/**
|
||||
* Defines all configuration options related to the gateway connection.
|
||||
*/
|
||||
gateway_connection: GatewayConnectionWasm;
|
||||
/**
|
||||
* Defines all configuration options related to reply SURBs.
|
||||
*/
|
||||
reply_surbs: ReplySurbsWasm;
|
||||
/**
|
||||
* Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
*/
|
||||
topology: TopologyWasm;
|
||||
/**
|
||||
* Defines all configuration options related to traffic streams.
|
||||
*/
|
||||
traffic: TrafficWasm;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
export interface GatewayEndpointConfig {
|
||||
free(): void;
|
||||
/**
|
||||
* gateway_id specifies ID of the gateway to which the client should send messages.
|
||||
* If initially omitted, a random gateway will be chosen from the available topology.
|
||||
*/
|
||||
gateway_id: string;
|
||||
/**
|
||||
* Address of the gateway listener to which all client requests should be sent.
|
||||
*/
|
||||
gateway_listener: string;
|
||||
/**
|
||||
* Address of the gateway owner to which the client should send messages.
|
||||
*/
|
||||
gateway_owner: string;
|
||||
}
|
||||
/**
|
||||
*/
|
||||
export interface NymClient {
|
||||
free(): void;
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
self_address(): string;
|
||||
/**
|
||||
* The simplest message variant where no additional information is attached.
|
||||
* You're simply sending your `data` to specified `recipient` without any tagging.
|
||||
*
|
||||
* Ends up with `NymMessage::Plain` variant
|
||||
* @param {Uint8Array} message
|
||||
* @param {string} recipient
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
send_regular_message(message: Uint8Array, recipient: string): Promise<any>;
|
||||
/**
|
||||
* Creates a message used for a duplex anonymous communication where the recipient
|
||||
* will never learn of our true identity. This is achieved by carefully sending `reply_surbs`.
|
||||
*
|
||||
* Note that if reply_surbs is set to zero then
|
||||
* this variant requires the client having sent some reply_surbs in the past
|
||||
* (and thus the recipient also knowing our sender tag).
|
||||
*
|
||||
* Ends up with `NymMessage::Repliable` variant
|
||||
* @param {Uint8Array} message
|
||||
* @param {string} recipient
|
||||
* @param {number} reply_surbs
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
send_anonymous_message(message: Uint8Array, recipient: string, reply_surbs: number): Promise<any>;
|
||||
/**
|
||||
* Attempt to use our internally received and stored `ReplySurb` to send the message back
|
||||
* to specified recipient whilst not knowing its full identity (or even gateway).
|
||||
*
|
||||
* Ends up with `NymMessage::Reply` variant
|
||||
* @param {Uint8Array} message
|
||||
* @param {string} recipient_tag
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
send_reply(message: Uint8Array, recipient_tag: string): Promise<any>;
|
||||
}
|
||||
|
||||
export interface Topology {
|
||||
free(): void;
|
||||
/**
|
||||
* Specifies whether the client should not refresh the network topology after obtaining
|
||||
* the first valid instance.
|
||||
* Supersedes `topology_refresh_rate_ms`.
|
||||
*/
|
||||
disable_refreshing: boolean;
|
||||
/**
|
||||
* The uniform delay every which clients are querying the directory server
|
||||
* to try to obtain a compatible network topology to send sphinx packets through.
|
||||
*/
|
||||
topology_refresh_rate_ms: bigint;
|
||||
/**
|
||||
* During topology refresh, test packets are sent through every single possible network
|
||||
* path. This timeout determines waiting period until it is decided that the packet
|
||||
* did not reach its destination.
|
||||
*/
|
||||
topology_resolution_timeout_ms: bigint;
|
||||
}
|
||||
|
||||
export interface Traffic {
|
||||
free(): void;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* sent packet is going to be delayed at any given mix node.
|
||||
* So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
* until the packet reaches its destination.
|
||||
*/
|
||||
average_packet_delay_ms: bigint;
|
||||
/**
|
||||
* Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
* poisson distribution.
|
||||
*/
|
||||
disable_main_poisson_packet_distribution: boolean;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* it is going to take another 'real traffic stream' message to be sent.
|
||||
* If no real packets are available and cover traffic is enabled,
|
||||
* a loop cover message is sent instead in order to preserve the rate.
|
||||
*/
|
||||
message_sending_average_delay_ms: bigint;
|
||||
/**
|
||||
* Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
|
||||
*/
|
||||
use_extended_packet_size: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
export interface NymClientBuilder {
|
||||
free(): void;
|
||||
/**
|
||||
* @returns {Promise<Promise<any>>}
|
||||
*/
|
||||
start_client(): Promise<Promise<any>>;
|
||||
}
|
||||
@@ -1,174 +1,6 @@
|
||||
export interface Acknowledgements {
|
||||
free(): void;
|
||||
/**
|
||||
* Value added to the expected round trip time of an acknowledgement packet before
|
||||
* it is assumed it was lost and retransmission of the data packet happens.
|
||||
* In an ideal network with 0 latency, this value would have been 0.
|
||||
*/
|
||||
ack_wait_addition_ms: bigint;
|
||||
/**
|
||||
* Value multiplied with the expected round trip time of an acknowledgement packet before
|
||||
* it is assumed it was lost and retransmission of the data packet happens.
|
||||
* In an ideal network with 0 latency, this value would have been 1.
|
||||
*/
|
||||
ack_wait_multiplier: number;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* sent acknowledgement is going to be delayed at any given mix node.
|
||||
* So for an ack going through three mix nodes, on average, it will take three times this value
|
||||
* until the packet reaches its destination.
|
||||
*/
|
||||
average_ack_delay_ms: bigint;
|
||||
}
|
||||
import type { DebugWasm } from './types-from-wasm-pack';
|
||||
|
||||
export interface CoverTraffic {
|
||||
free(): void;
|
||||
/**
|
||||
* Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic.
|
||||
* Only applicable if `secondary_packet_size` is enabled.
|
||||
*/
|
||||
cover_traffic_primary_size_ratio: number;
|
||||
/**
|
||||
* Controls whether the dedicated loop cover traffic stream should be enabled.
|
||||
* (and sending packets, on average, every [Self::loop_cover_traffic_average_delay])
|
||||
*/
|
||||
disable_loop_cover_traffic_stream: boolean;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* it is going to take for another loop cover traffic message to be sent.
|
||||
*/
|
||||
loop_cover_traffic_average_delay_ms: bigint;
|
||||
}
|
||||
|
||||
export interface GatewayConnection {
|
||||
free(): void;
|
||||
/**
|
||||
* How long we're willing to wait for a response to a message sent to the gateway,
|
||||
* before giving up on it.
|
||||
*/
|
||||
gateway_response_timeout_ms: bigint;
|
||||
}
|
||||
|
||||
export interface ReplySurbs {
|
||||
free(): void;
|
||||
/**
|
||||
* Defines the maximum number of reply surbs a remote party is allowed to request from this client at once.
|
||||
*/
|
||||
maximum_allowed_reply_surb_request_size: number;
|
||||
/**
|
||||
* Defines maximum amount of time given reply key is going to be valid for.
|
||||
* This is going to be superseded by key rotation once implemented.
|
||||
*/
|
||||
maximum_reply_key_age_ms: bigint;
|
||||
/**
|
||||
* Defines maximum amount of time given reply surb is going to be valid for.
|
||||
* This is going to be superseded by key rotation once implemented.
|
||||
*/
|
||||
maximum_reply_surb_age_ms: bigint;
|
||||
/**
|
||||
* Defines maximum amount of time the client is going to wait for reply surbs before
|
||||
* deciding it's never going to get them and would drop all pending messages
|
||||
*/
|
||||
maximum_reply_surb_drop_waiting_period_ms: bigint;
|
||||
/**
|
||||
* Defines the maximum number of reply surbs the client would request.
|
||||
*/
|
||||
maximum_reply_surb_request_size: number;
|
||||
/**
|
||||
* Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking
|
||||
* for more even though in theory they wouldn't need to.
|
||||
*/
|
||||
maximum_reply_surb_rerequest_waiting_period_ms: bigint;
|
||||
/**
|
||||
* Defines the maximum number of reply surbs the client wants to keep in its storage at any times.
|
||||
*/
|
||||
maximum_reply_surb_storage_threshold: number;
|
||||
/**
|
||||
* Defines the minimum number of reply surbs the client would request.
|
||||
*/
|
||||
minimum_reply_surb_request_size: number;
|
||||
/**
|
||||
* Defines the minimum number of reply surbs the client wants to keep in its storage at all times.
|
||||
* It can only allow to go below that value if its to request additional reply surbs.
|
||||
*/
|
||||
minimum_reply_surb_storage_threshold: number;
|
||||
}
|
||||
|
||||
export interface Debug {
|
||||
free(): void;
|
||||
/**
|
||||
* Defines all configuration options related to acknowledgements, such as delays or wait timeouts.
|
||||
*/
|
||||
acknowledgements: Acknowledgements;
|
||||
/**
|
||||
* Defines all configuration options related to cover traffic stream(s).
|
||||
*/
|
||||
cover_traffic: CoverTraffic;
|
||||
/**
|
||||
* Defines all configuration options related to the gateway connection.
|
||||
*/
|
||||
gateway_connection: GatewayConnection;
|
||||
/**
|
||||
* Defines all configuration options related to reply SURBs.
|
||||
*/
|
||||
reply_surbs: ReplySurbs;
|
||||
/**
|
||||
* Defines all configuration options related topology, such as refresh rates or timeouts.
|
||||
*/
|
||||
topology: Topology;
|
||||
/**
|
||||
* Defines all configuration options related to traffic streams.
|
||||
*/
|
||||
traffic: Traffic;
|
||||
}
|
||||
|
||||
export interface Topology {
|
||||
free(): void;
|
||||
/**
|
||||
* Specifies whether the client should not refresh the network topology after obtaining
|
||||
* the first valid instance.
|
||||
* Supersedes `topology_refresh_rate_ms`.
|
||||
*/
|
||||
disable_refreshing: boolean;
|
||||
/**
|
||||
* The uniform delay every which clients are querying the directory server
|
||||
* to try to obtain a compatible network topology to send sphinx packets through.
|
||||
*/
|
||||
topology_refresh_rate_ms: bigint;
|
||||
/**
|
||||
* During topology refresh, test packets are sent through every single possible network
|
||||
* path. This timeout determines waiting period until it is decided that the packet
|
||||
* did not reach its destination.
|
||||
*/
|
||||
topology_resolution_timeout_ms: bigint;
|
||||
}
|
||||
|
||||
export interface Traffic {
|
||||
free(): void;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* sent packet is going to be delayed at any given mix node.
|
||||
* So for a packet going through three mix nodes, on average, it will take three times this value
|
||||
* until the packet reaches its destination.
|
||||
*/
|
||||
average_packet_delay_ms: bigint;
|
||||
/**
|
||||
* Controls whether the main packet stream constantly produces packets according to the predefined
|
||||
* poisson distribution.
|
||||
*/
|
||||
disable_main_poisson_packet_distribution: boolean;
|
||||
/**
|
||||
* The parameter of Poisson distribution determining how long, on average,
|
||||
* it is going to take another 'real traffic stream' message to be sent.
|
||||
* If no real packets are available and cover traffic is enabled,
|
||||
* a loop cover message is sent instead in order to preserve the rate.
|
||||
*/
|
||||
message_sending_average_delay_ms: bigint;
|
||||
/**
|
||||
* Controls whether the sent sphinx packet use the NON-DEFAULT bigger size.
|
||||
*/
|
||||
use_extended_packet_size: boolean;
|
||||
}
|
||||
export * from './types-from-wasm-pack';
|
||||
|
||||
/**
|
||||
* Some common mime types, however, you can always just specify the mime-type as a string
|
||||
@@ -221,7 +53,7 @@ export interface NymClientConfig {
|
||||
/**
|
||||
* Optional. Settings for the WASM client.
|
||||
*/
|
||||
debug?: Debug;
|
||||
debug?: DebugWasm;
|
||||
}
|
||||
|
||||
export interface IWebWorker {
|
||||
|
||||
@@ -168,43 +168,40 @@ init(wasmBytes())
|
||||
if (config.gatewayListener) gatewayEndpoint.gateway_listener = config.gatewayListener;
|
||||
|
||||
// create the client, passing handlers for events
|
||||
wrapper.init(
|
||||
new Config(config.clientId, config.nymApiUrl, gatewayEndpoint, config.debug || default_debug()),
|
||||
async (message) => {
|
||||
// fire an event with the raw message
|
||||
postMessageWithType<RawMessageReceivedEvent>({
|
||||
kind: EventKinds.RawMessageReceived,
|
||||
args: { payload: message },
|
||||
});
|
||||
wrapper.init(new Config(config.clientId, config.nymApiUrl, config.debug || default_debug()), async (message) => {
|
||||
// fire an event with the raw message
|
||||
postMessageWithType<RawMessageReceivedEvent>({
|
||||
kind: EventKinds.RawMessageReceived,
|
||||
args: { payload: message },
|
||||
});
|
||||
|
||||
try {
|
||||
// try to decode the payload to extract the mime-type, headers and payload body
|
||||
const decodedPayload = decode_payload(message);
|
||||
const { payload, headers } = decodedPayload;
|
||||
const mimeType = decodedPayload.mimeType as MimeTypes;
|
||||
try {
|
||||
// try to decode the payload to extract the mime-type, headers and payload body
|
||||
const decodedPayload = decode_payload(message);
|
||||
const { payload, headers } = decodedPayload;
|
||||
const mimeType = decodedPayload.mimeType as MimeTypes;
|
||||
|
||||
if (wrapper.getTextMimeTypes().includes(mimeType)) {
|
||||
const stringMessage = parse_utf8_string(payload);
|
||||
if (wrapper.getTextMimeTypes().includes(mimeType)) {
|
||||
const stringMessage = parse_utf8_string(payload);
|
||||
|
||||
// the payload is a string type (in the options at creation time, string mime-types are set, or fall back
|
||||
// to defaults, such as `text/plain`, `application/json`, etc)
|
||||
postMessageWithType<StringMessageReceivedEvent>({
|
||||
kind: EventKinds.StringMessageReceived,
|
||||
args: { mimeType, payload: stringMessage, payloadRaw: payload, headers },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// the payload is a binary type
|
||||
postMessageWithType<BinaryMessageReceivedEvent>({
|
||||
kind: EventKinds.BinaryMessageReceived,
|
||||
args: { mimeType, payload, headers },
|
||||
// the payload is a string type (in the options at creation time, string mime-types are set, or fall back
|
||||
// to defaults, such as `text/plain`, `application/json`, etc)
|
||||
postMessageWithType<StringMessageReceivedEvent>({
|
||||
kind: EventKinds.StringMessageReceived,
|
||||
args: { mimeType, payload: stringMessage, payloadRaw: payload, headers },
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to parse binary message', e);
|
||||
return;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// the payload is a binary type
|
||||
postMessageWithType<BinaryMessageReceivedEvent>({
|
||||
kind: EventKinds.BinaryMessageReceived,
|
||||
args: { mimeType, payload, headers },
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to parse binary message', e);
|
||||
}
|
||||
});
|
||||
|
||||
// start the client sending traffic
|
||||
await wrapper.start();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
import express from 'express';
|
||||
import dotenv from 'dotenv';
|
||||
import { createProxyMiddleware } from 'http-proxy-middleware';
|
||||
|
||||
@@ -20,6 +20,7 @@ export const Content: FCWithChildren = () => {
|
||||
const isMounted = useIsMounted();
|
||||
|
||||
if (isMounted()) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Content is mounted');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user