Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca2aad778b | |||
| 584c902f93 | |||
| 2b15d53f45 | |||
| ce98ce72d8 | |||
| 8af83ceac6 | |||
| ee6b6ecc7e | |||
| a50b4ad211 | |||
| ca613ad3aa | |||
| f518c8377b | |||
| e1a30ea01a | |||
| 9f5a0a7ca6 | |||
| c7de97d6dd | |||
| 85a7ec9f02 | |||
| 8d105cf4dd | |||
| 6131d000e6 | |||
| 972a220209 | |||
| b7cf7e06d2 | |||
| 2df42e222c | |||
| 83a0a6455f | |||
| f53e5c42c3 | |||
| b537a7c2c7 | |||
| 9fb8b1d7c0 | |||
| a1482a2887 | |||
| b57df35f8c | |||
| 7f0a02f6ec | |||
| cfc86ba9f5 | |||
| 9c68de64a0 | |||
| 2fdd09deee | |||
| 5f9a514bc7 | |||
| 0812a0f599 | |||
| 7741a3fea1 | |||
| 017d536d35 | |||
| eb444f73ce | |||
| d108919cf6 | |||
| 5d454f2efc | |||
| ffac0a1f92 | |||
| 8004d54d5e | |||
| b6febc51a3 | |||
| 5a0255fd01 | |||
| 5b86646bd8 | |||
| 067a501d98 | |||
| fa9908413b | |||
| d6369ea784 | |||
| e49c8588c6 | |||
| 3ea4e0bf7c | |||
| 4681c0b275 |
@@ -25,7 +25,7 @@ jobs:
|
||||
|
||||
outputs:
|
||||
release_id: ${{ steps.create-release.outputs.id }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].created_at }}
|
||||
release_date: ${{ fromJSON(steps.create-release.outputs.assets)[0].published_at }}
|
||||
client_hash: ${{ steps.binary-hashes.outputs.client_hash }}
|
||||
mixnode_hash: ${{ steps.binary-hashes.outputs.mixnode_hash }}
|
||||
gateway_hash: ${{ steps.binary-hashes.outputs.gateway_hash }}
|
||||
@@ -40,7 +40,6 @@ jobs:
|
||||
netreq_version: ${{ steps.binary-versions.outputs.netreq_version }}
|
||||
cli_version: ${{ steps.binary-versions.outputs.cli_version }}
|
||||
netstat_version: ${{ steps.binary-versions.outputs.netstat_version }}
|
||||
platform: ${{ steps.get-platform-version.outputs.platform }}"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -97,11 +96,6 @@ jobs:
|
||||
target/release/nym-network-statistics
|
||||
target/release/nym-cli
|
||||
|
||||
- id: echo-outputs
|
||||
name: echo output for assets
|
||||
run: |
|
||||
echo "data from release: $ ${{ steps.create-release.outputs }}"
|
||||
|
||||
- id: release-info
|
||||
name: Prepare release info
|
||||
run: |
|
||||
@@ -130,12 +124,6 @@ jobs:
|
||||
v=$(rg '^version = "(.*)"' -or '$1' tools/nym-cli/Cargo.toml) && echo "cli_version=$v" >> "$GITHUB_OUTPUT"
|
||||
v=$(rg '^version = "(.*)"' -or '$1' service-providers/network-statistics/Cargo.toml) && echo "netstat_version=$v" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- id: get-platform-version
|
||||
name: get platform version
|
||||
run: |
|
||||
echo "::set-output name=platform::$(uname -r)"
|
||||
|
||||
|
||||
push-release-data-client:
|
||||
if: ${{ (startsWith(github.ref, 'refs/tags/nym-binaries-') && github.event_name == 'release') || github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/workflows/push-release-data.yml
|
||||
@@ -151,7 +139,6 @@ jobs:
|
||||
file_hash: ${{ needs.publish-nym.outputs.client_hash }}
|
||||
name: Client
|
||||
category: binaries
|
||||
platform: "${{ needs.publish-nym.outputs.platform }}"
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-mixnode:
|
||||
@@ -169,7 +156,6 @@ jobs:
|
||||
file_hash: ${{ needs.publish-nym.outputs.mixnode_hash }}
|
||||
name: Mixnode
|
||||
category: binaries
|
||||
platform: "${{ needs.publish-nym.outputs.platform }}"
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-gateway:
|
||||
@@ -187,7 +173,6 @@ jobs:
|
||||
file_hash: ${{ needs.publish-nym.outputs.gateway_hash }}
|
||||
name: Gateway
|
||||
category: binaries
|
||||
platform: "${{ needs.publish-nym.outputs.platform }}"
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-socks5:
|
||||
@@ -205,7 +190,6 @@ jobs:
|
||||
file_hash: ${{ needs.publish-nym.outputs.socks5_hash }}
|
||||
name: Socks5 Client
|
||||
category: binaries
|
||||
platform: "${{ needs.publish-nym.outputs.platform }}"
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-network-requester:
|
||||
@@ -223,7 +207,6 @@ jobs:
|
||||
file_hash: ${{ needs.publish-nym.outputs.netreq_hash }}
|
||||
name: Network Requester
|
||||
category: binaries
|
||||
platform: "${{ needs.publish-nym.outputs.platform }}"
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-cli:
|
||||
@@ -241,7 +224,6 @@ jobs:
|
||||
file_hash: ${{ needs.publish-nym.outputs.cli_hash }}
|
||||
name: Cli
|
||||
category: binaries
|
||||
platform: "${{ needs.publish-nym.outputs.platform }}"
|
||||
secrets: inherit
|
||||
|
||||
push-release-data-network-stat:
|
||||
@@ -259,5 +241,4 @@ jobs:
|
||||
file_hash: ${{ needs.publish-nym.outputs.netstat_hash }}
|
||||
name: Network Statistics
|
||||
category: binaries
|
||||
platform: "${{ needs.publish-nym.outputs.platform }}"
|
||||
secrets: inherit
|
||||
|
||||
+22
-2
@@ -4,7 +4,27 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.1.28] (2023-08-22)
|
||||
## [v1.1.29-snickers] (2023-08-29)
|
||||
|
||||
- Add EXPLORER_API configurable url ([#3810])
|
||||
- Bugfix/use correct tendermint dialect ([#3802])
|
||||
- Explorer - look up gateways based on geo-location ([#3776])
|
||||
- Speedy mode - select the mixnodes based on the location of the NR ([#3775])
|
||||
- NR - reduce response time by removing poisson delay ([#3774])
|
||||
- [demo] libp2p example with nym-sdk ([#3763])
|
||||
- introduced /network/details endpoint to nym-api to return used network information ([#3758])
|
||||
- Feature/issue credentials ([#3691])
|
||||
|
||||
[#3810]: https://github.com/nymtech/nym/pull/3810
|
||||
[#3802]: https://github.com/nymtech/nym/pull/3802
|
||||
[#3776]: https://github.com/nymtech/nym/issues/3776
|
||||
[#3775]: https://github.com/nymtech/nym/issues/3775
|
||||
[#3774]: https://github.com/nymtech/nym/issues/3774
|
||||
[#3763]: https://github.com/nymtech/nym/pull/3763
|
||||
[#3758]: https://github.com/nymtech/nym/pull/3758
|
||||
[#3691]: https://github.com/nymtech/nym/pull/3691
|
||||
|
||||
## [v1.1.28] (2023-08-22)
|
||||
|
||||
- [final step3]: add [rust] support to nyxd client in wasm ([#3743])
|
||||
- Feature/ephemera upgrade ([#3791])
|
||||
@@ -19,7 +39,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
[#3767]: https://github.com/nymtech/nym/pull/3767
|
||||
|
||||
|
||||
## [1.1.27] (2023-08-16)
|
||||
## [v1.1.27] (2023-08-16)
|
||||
|
||||
- fix serialisation of contract types ([#3752])
|
||||
- Investigate spending credentials from the main API (coconut enabled to a gateway) from feature/ephemera branch ([#3741])
|
||||
|
||||
Generated
+23
-10
@@ -2768,7 +2768,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "explorer-api"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap 4.3.21",
|
||||
@@ -5638,7 +5638,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-api"
|
||||
version = "1.1.27"
|
||||
version = "1.1.28"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"anyhow",
|
||||
@@ -5785,7 +5785,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-cli"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.13.1",
|
||||
@@ -5858,7 +5858,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-client"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
dependencies = [
|
||||
"clap 4.3.21",
|
||||
"dirs 4.0.0",
|
||||
@@ -5909,7 +5909,7 @@ dependencies = [
|
||||
"nym-config",
|
||||
"nym-credential-storage",
|
||||
"nym-crypto",
|
||||
"nym-explorer-api-requests",
|
||||
"nym-explorer-client",
|
||||
"nym-gateway-client",
|
||||
"nym-gateway-requests",
|
||||
"nym-network-defaults",
|
||||
@@ -6151,9 +6151,22 @@ dependencies = [
|
||||
"ts-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-explorer-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nym-explorer-api-requests",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -6308,7 +6321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-mixnode"
|
||||
version = "1.1.27"
|
||||
version = "1.1.28"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bs58 0.4.0",
|
||||
@@ -6426,7 +6439,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-file-watcher",
|
||||
@@ -6473,7 +6486,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-network-statistics"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"log",
|
||||
@@ -6638,7 +6651,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
dependencies = [
|
||||
"clap 4.3.21",
|
||||
"lazy_static",
|
||||
|
||||
@@ -76,6 +76,7 @@ members = [
|
||||
"common/wasm-utils",
|
||||
"explorer-api",
|
||||
"explorer-api/explorer-api-requests",
|
||||
"explorer-api/explorer-client",
|
||||
"gateway",
|
||||
"gateway/gateway-requests",
|
||||
"integrations/bity",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-client"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||
description = "Implementation of the Nym Client"
|
||||
edition = "2021"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-socks5-client"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||
edition = "2021"
|
||||
|
||||
Generated
+13
-1
@@ -2514,7 +2514,7 @@ dependencies = [
|
||||
"nym-config",
|
||||
"nym-credential-storage",
|
||||
"nym-crypto",
|
||||
"nym-explorer-api-requests",
|
||||
"nym-explorer-client",
|
||||
"nym-gateway-client",
|
||||
"nym-gateway-requests",
|
||||
"nym-network-defaults",
|
||||
@@ -2752,6 +2752,18 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-explorer-client"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nym-explorer-api-requests",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-gateway-client"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -33,7 +33,7 @@ zeroize = { workspace = true }
|
||||
nym-bandwidth-controller = { path = "../bandwidth-controller" }
|
||||
nym-config = { path = "../config" }
|
||||
nym-crypto = { path = "../crypto" }
|
||||
nym-explorer-api-requests = { path = "../../explorer-api/explorer-api-requests" }
|
||||
nym-explorer-client = { path = "../../explorer-api/explorer-client" }
|
||||
nym-gateway-client = { path = "../client-libs/gateway-client" }
|
||||
#gateway-client = { path = "../../common/client-libs/gateway-client", default-features = false, features = ["wasm", "coconut"] }
|
||||
nym-gateway-requests = { path = "../../gateway/gateway-requests" }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::{collections::HashMap, fmt};
|
||||
|
||||
use log::{debug, error, info};
|
||||
use nym_explorer_api_requests::{PrettyDetailedGatewayBond, PrettyDetailedMixNodeBond};
|
||||
use nym_explorer_client::{ExplorerClient, PrettyDetailedGatewayBond, PrettyDetailedMixNodeBond};
|
||||
use nym_network_defaults::var_names::EXPLORER_API;
|
||||
use nym_topology::{
|
||||
nym_topology_from_detailed,
|
||||
@@ -18,55 +18,24 @@ use crate::config::GroupBy;
|
||||
|
||||
const MIN_NODES_PER_LAYER: usize = 1;
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn reqwest_client() -> Option<reqwest::Client> {
|
||||
reqwest::Client::builder().build().ok()
|
||||
}
|
||||
fn create_explorer_client() -> Option<ExplorerClient> {
|
||||
let Ok(explorer_api_url) = std::env::var(EXPLORER_API) else {
|
||||
error!("Missing EXPLORER_API");
|
||||
return None;
|
||||
};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn reqwest_client() -> Option<reqwest::Client> {
|
||||
reqwest::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.build()
|
||||
.ok()
|
||||
}
|
||||
let Ok(explorer_api_url) = explorer_api_url.parse() else {
|
||||
error!("Failed to parse EXPLORER_API");
|
||||
return None;
|
||||
};
|
||||
|
||||
// TODO: create a explorer-api-client
|
||||
async fn fetch_mixnodes_from_explorer_api() -> Option<Vec<PrettyDetailedMixNodeBond>> {
|
||||
let explorer_api_url = std::env::var(EXPLORER_API).ok()?;
|
||||
let explorer_api_url = Url::parse(&explorer_api_url)
|
||||
.ok()?
|
||||
.join("v1/mix-nodes")
|
||||
.ok()?;
|
||||
log::debug!("Using explorer-api url: {}", explorer_api_url);
|
||||
let Ok(client) = nym_explorer_client::ExplorerClient::new(explorer_api_url) else {
|
||||
error!("Failed to create explorer-api client");
|
||||
return None;
|
||||
};
|
||||
|
||||
debug!("Fetching: {}", explorer_api_url);
|
||||
reqwest_client()?
|
||||
.get(explorer_api_url)
|
||||
.send()
|
||||
.await
|
||||
.ok()?
|
||||
.json::<Vec<PrettyDetailedMixNodeBond>>()
|
||||
.await
|
||||
.ok()
|
||||
}
|
||||
|
||||
// TODO: create a explorer-api-client
|
||||
async fn fetch_gateways_from_explorer_api() -> Option<Vec<PrettyDetailedGatewayBond>> {
|
||||
let explorer_api_url = std::env::var(EXPLORER_API).ok()?;
|
||||
let explorer_api_url = Url::parse(&explorer_api_url)
|
||||
.ok()?
|
||||
.join("v1/gateways")
|
||||
.ok()?;
|
||||
|
||||
debug!("Fetching: {}", explorer_api_url);
|
||||
reqwest_client()?
|
||||
.get(explorer_api_url)
|
||||
.send()
|
||||
.await
|
||||
.ok()?
|
||||
.json::<Vec<PrettyDetailedGatewayBond>>()
|
||||
.await
|
||||
.ok()
|
||||
Some(client)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
@@ -83,6 +52,8 @@ pub enum CountryGroup {
|
||||
impl CountryGroup {
|
||||
// We map contry codes into group, which initially are continent codes to a first approximation,
|
||||
// but we do it manually to reserve the right to tweak this distribution for our purposes.
|
||||
// NOTE: I did this quickly and it's not a complete list of all countries, but only those that
|
||||
// were present in the network at the time. Please add more as needed.
|
||||
fn new(country_code: &str) -> Self {
|
||||
let country_code = country_code.to_uppercase();
|
||||
use CountryGroup::*;
|
||||
@@ -303,7 +274,7 @@ impl GeoAwareTopologyProvider {
|
||||
filter_on: GroupBy,
|
||||
) -> GeoAwareTopologyProvider {
|
||||
log::info!(
|
||||
"Creating geo-aware topology provider with filter on {:?}",
|
||||
"Creating geo-aware topology provider with filter on {}",
|
||||
filter_on
|
||||
);
|
||||
nym_api_urls.shuffle(&mut thread_rng());
|
||||
@@ -337,13 +308,14 @@ impl GeoAwareTopologyProvider {
|
||||
// Also fetch mixnodes cached by explorer-api, with the purpose of getting their
|
||||
// geolocation.
|
||||
debug!("Fetching mixnodes from explorer-api...");
|
||||
let Some(mixnodes_from_explorer_api) = fetch_mixnodes_from_explorer_api().await else {
|
||||
let explorer_client = create_explorer_client()?;
|
||||
let Ok(mixnodes_from_explorer_api) = explorer_client.get_mixnodes().await else {
|
||||
error!("failed to get mixnodes from explorer-api");
|
||||
return None;
|
||||
};
|
||||
|
||||
debug!("Fetching gateways from explorer-api...");
|
||||
let Some(gateways_from_explorer_api) = fetch_gateways_from_explorer_api().await else {
|
||||
let Ok(gateways_from_explorer_api) = explorer_client.get_gateways().await else {
|
||||
error!("failed to get mixnodes from explorer-api");
|
||||
return None;
|
||||
};
|
||||
|
||||
@@ -498,6 +498,15 @@ pub enum GroupBy {
|
||||
NymAddress(Recipient),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for GroupBy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GroupBy::CountryGroup(group) => write!(f, "group: {}", group),
|
||||
GroupBy::NymAddress(address) => write!(f, "address: {}", address),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Topology {
|
||||
fn default() -> Self {
|
||||
Topology {
|
||||
|
||||
@@ -149,7 +149,7 @@ async fn measure_latency(gateway: &gateway::Node) -> Result<GatewayWithLatency,
|
||||
Ok(GatewayWithLatency::new(gateway, avg))
|
||||
}
|
||||
|
||||
pub(super) async fn choose_gateway_by_latency<R: Rng>(
|
||||
pub async fn choose_gateway_by_latency<R: Rng>(
|
||||
rng: &mut R,
|
||||
gateways: &[gateway::Node],
|
||||
) -> Result<gateway::Node, ClientCoreError> {
|
||||
|
||||
@@ -110,10 +110,10 @@ pub struct Socks5 {
|
||||
/// The version of the 'service provider' this client is going to use in its communication with the
|
||||
/// specified socks5 provider.
|
||||
// if in doubt, use the legacy version as initially nobody will be using the updated binaries
|
||||
#[serde(default = "ProviderInterfaceVersion::new_legacy")]
|
||||
#[serde(default)]
|
||||
pub provider_interface_version: ProviderInterfaceVersion,
|
||||
|
||||
#[serde(default = "Socks5ProtocolVersion::new_legacy")]
|
||||
#[serde(default)]
|
||||
pub socks5_protocol_version: Socks5ProtocolVersion,
|
||||
|
||||
/// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider.
|
||||
@@ -147,7 +147,7 @@ impl Socks5 {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Socks5Debug {
|
||||
/// Number of reply SURBs attached to each `Request::Connect` message.
|
||||
pub connection_start_surbs: u32,
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
# Documentation
|
||||
|
||||
## Doc projects
|
||||
Each directory contains a readme with more information about running and contributing to the projects. Each is built with [`mdbook`](https://rust-lang.github.io/mdBook/index.html) - use `mdbook serve` to build and serve them (defaults to `localhost:3000`).
|
||||
* `docs` contains technical documentation hosted at [https://nymtech.net/docs](https://nymtech.net/docs)
|
||||
* `dev-portal` contains developer documentation hosted at [https://nymtech.net/developers](https://nymtech.net/developers)
|
||||
* `operators` contains node setup and maintenance guides hosted at [https://nymtech.net/operators](https://nymtech.net/operators)
|
||||
|
||||
Each directory contains a readme with more information about running and contributing to the projects. Each is built with [`mdbook`](https://rust-lang.github.io/mdBook/index.html) - use `mdbook serve` to build and serve them (defaults to `localhost:3000`).
|
||||
## Scripts
|
||||
* `bump_versions.sh` allows you to update the `platform_release_version` and `wallet_release_version` variables in the `book.toml` of each mdbook project at once. You can also optionally update the `minimum_rust_version` as well. Helpful for lazy-updating when cutting a new version of the docs.
|
||||
* `build_all_to_dist.sh` is used by the `ci-dev.yml` and `cd-dev.yml` scripts for building all mdbook projects and moving the rendered html to `../dist/` to be rsynced with various servers.
|
||||
|
||||
|
||||
|
||||
@@ -1,37 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
# commands assume you run script from `nym/documentation/`
|
||||
# this is a script called by the github CI and CD workflows to build all 3 docs projects
|
||||
# and move them to /dist/ in the root of the monorepo. They are rsynced to various servers
|
||||
# from there by subsequent workflow tasks.
|
||||
|
||||
# array of project dirs
|
||||
declare -a projects=("docs" "dev-portal" "operators")
|
||||
|
||||
## now loop through the above array
|
||||
for i in "${projects[@]}"
|
||||
do
|
||||
# cd to project dir
|
||||
cd "./$i" &&
|
||||
# little sanity checks
|
||||
echo $(pwd) && echo $(mdbook --version) &&
|
||||
# clean old book
|
||||
echo "cleaning old book"
|
||||
rm -rf ./book/
|
||||
# build book
|
||||
mdbook build
|
||||
# check for destination, if ! then mkdir & check again else echo thumbs up
|
||||
if [ ! -d ../../dist/docs/$i ]; then
|
||||
echo "dest doesn't exist: creating dir"
|
||||
mkdir -p ../../dist/docs/$i
|
||||
fi
|
||||
if [ -d ../../dist/docs/$i ]; then
|
||||
echo "cp destination exists, all good"
|
||||
fi
|
||||
# clean old dist/$i
|
||||
rm -rf ../../dist/docs/$i
|
||||
# move newly rendered book/ to dist
|
||||
rsync -r ./book/html/ ../../dist/docs/$i
|
||||
# sanity check
|
||||
ls -laF ../../dist/docs/
|
||||
# cd back to ../documentation/
|
||||
cd ../
|
||||
done
|
||||
mv ../dist/docs/dev-portal ../dist/docs/developers
|
||||
# check you're calling from the right place
|
||||
if [ $(pwd | awk -F/ '{print $NF}') != "documentation" ]
|
||||
then
|
||||
echo "failure: please run script from documentation/"
|
||||
else
|
||||
for i in "${projects[@]}"
|
||||
do
|
||||
# cd to project dir
|
||||
cd "./$i" &&
|
||||
# little sanity checks
|
||||
echo $(pwd) && echo $(mdbook --version) &&
|
||||
# clean old book
|
||||
echo "cleaning old book"
|
||||
rm -rf ./book/
|
||||
# build book
|
||||
mdbook build
|
||||
# check for destination, if ! then mkdir & check again else echo thumbs up
|
||||
if [ ! -d ../../dist/docs/$i ]; then
|
||||
echo "dest doesn't exist: creating dir"
|
||||
mkdir -p ../../dist/docs/$i
|
||||
fi
|
||||
if [ -d ../../dist/docs/$i ]; then
|
||||
echo "cp destination exists, all good"
|
||||
fi
|
||||
# clean old dist/$i
|
||||
rm -rf ../../dist/docs/$i
|
||||
# move newly rendered book/ to dist
|
||||
rsync -r ./book/html/ ../../dist/docs/$i
|
||||
# sanity check
|
||||
ls -laF ../../dist/docs/
|
||||
# cd back to ../documentation/
|
||||
cd ../
|
||||
done
|
||||
# rename for server paths
|
||||
rm -rf ../dist/docs/developers
|
||||
mv ../dist/docs/dev-portal ../dist/docs/developers
|
||||
fi
|
||||
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
# this takes two args: platform release version and wallet release version.
|
||||
# it then uses sed to bump them in the three book.toml files.
|
||||
#
|
||||
# e.g if the upcoming platform release was v1.1.29 and the release version 1.2.9 you'd run this as:
|
||||
# `./bump_versions.sh "1.1.29" "1.2.9"`
|
||||
#
|
||||
# you can also set the minumum rust version by passing an optional 3rd argument:
|
||||
# `./bump_versions.sh "1.1.29" "1.2.9" "1.67"`
|
||||
|
||||
# array of project dirs
|
||||
declare -a projects=("docs" "dev-portal" "operators")
|
||||
|
||||
# check number of args passed
|
||||
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ];
|
||||
then
|
||||
echo "failure: please pass at least 2 and at most 3 args: "
|
||||
echo "./bump_version.sh <new platform_release_version> <new wallet_release_version> [OPTIONAL]<new minimum_rust_version>"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# check you're calling from the right place
|
||||
if [ $(pwd | awk -F/ '{print $NF}') != "documentation" ]
|
||||
then
|
||||
echo "failure: please run script from documentation/"
|
||||
exit 0
|
||||
else
|
||||
## now loop through the above array sed-ing the variable values in the book.toml files
|
||||
for i in "${projects[@]}"
|
||||
do
|
||||
# sed the vars in the book.toml file for each project
|
||||
echo "setting platform and wallet versions in $i/"
|
||||
sed -i 's/platform_release_version =.*/platform_release_version = "'$1'"/' "$i"/book.toml
|
||||
sed -i 's/wallet_release_version =.*/wallet_release_version = "'$2'"/' "$i"/book.toml
|
||||
if [ "$3" ]
|
||||
then
|
||||
echo "setting minimum rust version in $i/"
|
||||
sed -i 's/minimum_rust_version = .*/minimum_rust_version = "'$3'"/' "$i"/book.toml
|
||||
fi
|
||||
done
|
||||
fi
|
||||
@@ -48,8 +48,8 @@ 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"
|
||||
platform_release_version = "v1.1.28"
|
||||
wallet_release_version = "v1.2.7"
|
||||
platform_release_version = "1.1.29"
|
||||
wallet_release_version = "1.2.8"
|
||||
|
||||
[preprocessor.last-changed]
|
||||
command = "mdbook-last-changed"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
- [NymConnect Monero](tutorials/monero.md)
|
||||
- [NymConnect Matrix](tutorials/matrix.md)
|
||||
- [NymConnect Telegram](tutorials/telegram.md)
|
||||
|
||||
# Integrations
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Telegram NymConnect Integration
|
||||
|
||||
*This is a shortened version of a [Nym Community post](https://blog.nymtech.net/how-to-use-telegram-in-iraq-with-nymconnect-106a3b8dd050) written by Saliveja.*
|
||||
|
||||
The purpose of the following manual is not to promote Telegram but so people can use it with the Nym mixnet if they wish to, should a situation ask for that. This privacy-enhances Telegram at the network level and allows users to access the application from locations like where the application was banned.
|
||||
|
||||
See also: [Element (Matrix) over the Nym mixnet](./matrix.md): private, decentralised and secure messaging.
|
||||
|
||||
## Setup & Run
|
||||
|
||||
Here’s how to configure Telegram with NymConnect:
|
||||
|
||||
1. Download and install NymConnect ().**
|
||||
For more releases, check out [Github](https://github.com/nymtech/nym/tags). NymConnect is available for Linux, Windows, and MacOS.
|
||||
On Linux make sure NymConnect is executable. Opening a terminal in the same directory and run:
|
||||
```sh
|
||||
chmod +x ./<YOUR-NYM-CONNECT-VERSION>.AppImage
|
||||
```
|
||||
2. **Start NymConnect**
|
||||
Telegram is added to NymConnect by default.
|
||||
3. **Click connect - the host and port will now be displayed.**
|
||||
4. **Click on host or port to copy** the value to the clipboard.
|
||||
5. **Open the Telegram proxy settings.**
|
||||
Linux: Telegram -> Settings -> Advanced -> Connection type -> Use custom proxy
|
||||
MacOS: Telegram -> Settings -> Advanced -> Data & Storage -> Connection Type -> Use custom Proxy
|
||||
Windows: Telegram -> Settings -> Data and Storage -> Use proxy
|
||||
6. **Add a proxy** with the Add proxy button.
|
||||
7. **Select SOCKS5** and make sure the port details are the same as those generated by NymConnect. Alternatively, follow this link: https://t.me/socks?server=127.0.0.1&port=1080
|
||||
8. **Save the proxy settings** in Telegram.
|
||||
9. **Telegram is now running through the Nym Mixnet and is privacy-enhanced!**
|
||||
This allows you to connect from regions which blocked Telegram.
|
||||
10. Note if you remain idle on Telegram for a while you might lose connectivity and your messages might not get through via SOCKS5 proxy. If that happens reconnect your NymConnect and reset the proxy again.
|
||||
|
||||
|
||||
Follow this [video](https://youtu.be/quj8H2qeOwY?t=97) to see the steps on Telegram setup.
|
||||
<!---It's set to particular time as the NC setup part is outdated --->
|
||||
|
||||
**Now your Telegram runs over NymConnect.**
|
||||
|
||||
NymConnect is currently available for several applications and service providers. Support for more apps is on the way. For any bug reports or feedback please reach out to us on Telegram or our [Discord](http://discord.gg/nym) server.
|
||||
|
||||
@@ -48,8 +48,8 @@ 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"
|
||||
platform_release_version = "v1.1.28"
|
||||
wallet_release_version = "v1.2.7"
|
||||
platform_release_version = "1.1.29"
|
||||
wallet_release_version = "1.2.8"
|
||||
|
||||
[preprocessor.last-changed]
|
||||
command = "mdbook-last-changed"
|
||||
|
||||
@@ -48,8 +48,8 @@ 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"
|
||||
platform_release_version = "v1.1.28"
|
||||
wallet_release_version = "v1.2.7"
|
||||
platform_release_version = "1.1.29"
|
||||
wallet_release_version = "1.2.8"
|
||||
|
||||
[preprocessor.last-changed]
|
||||
command = "mdbook-last-changed"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "explorer-api"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "nym-explorer-client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
log.workspace = true
|
||||
nym-explorer-api-requests = { path = "../explorer-api-requests" }
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
serde.workspace = true
|
||||
thiserror.workspace = true
|
||||
url.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
@@ -0,0 +1,96 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use reqwest::StatusCode;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
// Re-export request types
|
||||
pub use nym_explorer_api_requests::{PrettyDetailedGatewayBond, PrettyDetailedMixNodeBond};
|
||||
|
||||
// Paths
|
||||
const API_VERSION: &str = "v1";
|
||||
const MIXNODES: &str = "mix-nodes";
|
||||
const GATEWAYS: &str = "gateways";
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
const REQUEST_TIMEOUT: Duration = Duration::from_secs(5);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ExplorerApiError {
|
||||
#[error("REST request error: {0}")]
|
||||
ReqwestError(#[from] reqwest::Error),
|
||||
|
||||
#[error("URL parse error: {0}")]
|
||||
UrlParseError(#[from] url::ParseError),
|
||||
|
||||
#[error("not found")]
|
||||
NotFound,
|
||||
|
||||
#[error("request failure: {0}")]
|
||||
RequestFailure(String),
|
||||
}
|
||||
|
||||
pub struct ExplorerClient {
|
||||
url: Url,
|
||||
client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl ExplorerClient {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn new(url: url::Url) -> Result<Self, ExplorerApiError> {
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(REQUEST_TIMEOUT)
|
||||
.build()?;
|
||||
Ok(Self { client, url })
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn new(url: url::Url) -> Result<Self, ExplorerApiError> {
|
||||
let client = reqwest::Client::builder().build()?;
|
||||
Ok(Self { client, url })
|
||||
}
|
||||
|
||||
async fn send_get_request(
|
||||
&self,
|
||||
paths: &[&str],
|
||||
) -> Result<reqwest::Response, ExplorerApiError> {
|
||||
let url = combine_url(self.url.clone(), paths)?;
|
||||
log::trace!("Sending GET request {url:?}");
|
||||
Ok(self.client.get(url).send().await?)
|
||||
}
|
||||
|
||||
async fn query_explorer_api<T>(&self, paths: &[&str]) -> Result<T, ExplorerApiError>
|
||||
where
|
||||
T: std::fmt::Debug,
|
||||
T: for<'a> serde::Deserialize<'a>,
|
||||
{
|
||||
let response = self.send_get_request(paths).await?;
|
||||
if response.status().is_success() {
|
||||
let res = response.json::<T>().await?;
|
||||
log::trace!("Got response: {res:?}");
|
||||
Ok(res)
|
||||
} else if response.status() == StatusCode::NOT_FOUND {
|
||||
Err(ExplorerApiError::NotFound)
|
||||
} else {
|
||||
Err(ExplorerApiError::RequestFailure(response.text().await?))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_mixnodes(&self) -> Result<Vec<PrettyDetailedMixNodeBond>, ExplorerApiError> {
|
||||
self.query_explorer_api(&[API_VERSION, MIXNODES]).await
|
||||
}
|
||||
|
||||
pub async fn get_gateways(&self) -> Result<Vec<PrettyDetailedGatewayBond>, ExplorerApiError> {
|
||||
self.query_explorer_api(&[API_VERSION, GATEWAYS]).await
|
||||
}
|
||||
}
|
||||
|
||||
fn combine_url(mut base_url: Url, paths: &[&str]) -> Result<Url, ExplorerApiError> {
|
||||
{
|
||||
let mut segments = base_url.path_segments_mut().expect("failed to parse url");
|
||||
for path in paths {
|
||||
segments.push(path);
|
||||
}
|
||||
}
|
||||
Ok(base_url)
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-gateway"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
@@ -292,8 +292,7 @@ impl Default for Debug {
|
||||
maximum_connection_buffer_size: DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE,
|
||||
stored_messages_filename_length: DEFAULT_STORED_MESSAGE_FILENAME_LENGTH,
|
||||
message_retrieval_limit: DEFAULT_MESSAGE_RETRIEVAL_LIMIT,
|
||||
// TODO: remember to change it in one of future releases!!
|
||||
use_legacy_framed_packet_version: true,
|
||||
use_legacy_framed_packet_version: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-mixnode"
|
||||
version = "1.1.27"
|
||||
version = "1.1.28"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
@@ -282,8 +282,7 @@ impl Default for Debug {
|
||||
packet_forwarding_maximum_backoff: DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF,
|
||||
initial_connection_timeout: DEFAULT_INITIAL_CONNECTION_TIMEOUT,
|
||||
maximum_connection_buffer_size: DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE,
|
||||
// TODO: remember to change it in one of future releases!!
|
||||
use_legacy_framed_packet_version: true,
|
||||
use_legacy_framed_packet_version: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@ impl MixNodePaths {
|
||||
pub fn new_default<P: AsRef<Path>>(id: P) -> Self {
|
||||
MixNodePaths {
|
||||
keys: KeysPaths::new_default(id.as_ref()),
|
||||
// TODO: next time there is a breaking change in the mixnode config, change this to
|
||||
// `default_base_directory`.
|
||||
// I'd rather not change this willy-nilly since it means a `mixnode init` will break
|
||||
// the existing configurated description.
|
||||
node_description: default_config_directory(id).join(DEFAULT_DESCRIPTION_FILENAME),
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-api"
|
||||
version = "1.1.27"
|
||||
version = "1.1.28"
|
||||
authors = [
|
||||
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
|
||||
"Jędrzej Stuczyński <andrew@nymtech.net>",
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.1.19-snickers] (2023-08-29)
|
||||
|
||||
- NymConnect sometimes fails to connect because the gateway it fetches from the validator-api to use is running an old version (of the gateway binary) ([#3788])
|
||||
|
||||
[#3788]: https://github.com/nymtech/nym/issues/3788
|
||||
|
||||
## [1.1.18] (2023-08-22)
|
||||
|
||||
- refactor(nc-desktop): use userdata storage to save user gateway&sp ([#3723])
|
||||
|
||||
Generated
+2
@@ -4014,8 +4014,10 @@ dependencies = [
|
||||
"nym-socks5-client-core",
|
||||
"nym-sphinx",
|
||||
"nym-task",
|
||||
"nym-topology",
|
||||
"nym-validator-client",
|
||||
"pretty_env_logger",
|
||||
"rand 0.7.3",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"rust-embed",
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
[workspace]
|
||||
members = ["src-tauri"]
|
||||
resolver = "2"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nym/nym-connect",
|
||||
"version": "1.1.18",
|
||||
"version": "1.1.19",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-connect"
|
||||
version = "1.1.18"
|
||||
version = "1.1.19"
|
||||
description = "nym-connect"
|
||||
authors = ["Nym Technologies SA"]
|
||||
license = ""
|
||||
@@ -30,6 +30,7 @@ itertools = "0.10.5"
|
||||
log = { version = "0.4", features = ["serde"] }
|
||||
pretty_env_logger = "0.4.0"
|
||||
rand = "0.8"
|
||||
rand-07 = { package = "rand", version = "0.7.3" }
|
||||
reqwest = { version = "0.11.18", features = ["json", "socks"] }
|
||||
rust-embed = { version = "6.4.2", features = ["include-exclude"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
@@ -58,6 +59,7 @@ nym-bin-common = { path = "../../../common/bin-common"}
|
||||
nym-socks5-client-core = { path = "../../../common/socks5-client-core" }
|
||||
nym-sphinx = { path = "../../../common/nymsphinx" }
|
||||
nym-task = { path = "../../../common/task" }
|
||||
nym-topology = { path = "../../../common/topology" }
|
||||
nym-validator-client = { path = "../../../common/client-libs/validator-client" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -86,8 +86,10 @@ fn main() {
|
||||
crate::operations::connection::status::get_connection_status,
|
||||
crate::operations::connection::status::get_gateway_connection_status,
|
||||
crate::operations::connection::status::start_connection_health_check_task,
|
||||
crate::operations::directory::get_services,
|
||||
crate::operations::directory::get_gateway_with_low_latency,
|
||||
crate::operations::directory::get_gateways,
|
||||
crate::operations::directory::get_services,
|
||||
crate::operations::directory::select_gateway_with_low_latency_from_list,
|
||||
crate::operations::export::export_keys,
|
||||
crate::operations::window::hide_window,
|
||||
crate::operations::growth::test_and_earn::growth_tne_get_client_id,
|
||||
|
||||
@@ -11,6 +11,7 @@ use nym_api_requests::models::GatewayBondAnnotated;
|
||||
use nym_bin_common::version_checker::is_minor_version_compatible;
|
||||
use nym_config::defaults::var_names::{NETWORK_NAME, NYM_API};
|
||||
use nym_contracts_common::types::Percent;
|
||||
use nym_topology::gateway;
|
||||
use nym_validator_client::nym_api::Client as ApiClient;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
@@ -134,25 +135,47 @@ async fn fetch_gateways() -> Result<Vec<GatewayBondAnnotated>> {
|
||||
Ok(gateways)
|
||||
}
|
||||
|
||||
fn filter_out_low_performance_gateways(
|
||||
gateways: Vec<GatewayBondAnnotated>,
|
||||
) -> Vec<GatewayBondAnnotated> {
|
||||
gateways
|
||||
.into_iter()
|
||||
.filter(|g| {
|
||||
g.node_performance.most_recent
|
||||
> Percent::from_percentage_value(GATEWAY_PERFORMANCE_SCORE_THRESHOLD).unwrap()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn select_gateway_by_latency(gateways: Vec<GatewayBondAnnotated>) -> Result<gateway::Node> {
|
||||
let gateways_as_nodes: Vec<gateway::Node> = gateways
|
||||
.into_iter()
|
||||
.filter_map(|g| g.gateway_bond.try_into().ok())
|
||||
.collect();
|
||||
|
||||
let mut rng = rand_07::rngs::OsRng;
|
||||
let selected_gateway =
|
||||
nym_client_core::init::helpers::choose_gateway_by_latency(&mut rng, &gateways_as_nodes)
|
||||
.await?;
|
||||
Ok(selected_gateway)
|
||||
}
|
||||
|
||||
// Get all gateways satisfying the performance threshold.
|
||||
#[tauri::command]
|
||||
pub async fn get_gateways() -> Result<Vec<Gateway>> {
|
||||
log::trace!("Fetching gateways");
|
||||
let all_gateways = fetch_gateways().await?;
|
||||
log::trace!("Received: {:#?}", all_gateways);
|
||||
|
||||
let filtered_gateways = all_gateways
|
||||
.iter()
|
||||
.filter(|g| {
|
||||
g.node_performance.most_recent
|
||||
> Percent::from_percentage_value(GATEWAY_PERFORMANCE_SCORE_THRESHOLD).unwrap()
|
||||
})
|
||||
let gateways_filtered = filter_out_low_performance_gateways(all_gateways.clone())
|
||||
.into_iter()
|
||||
.map(|g| Gateway {
|
||||
identity: g.identity().clone(),
|
||||
})
|
||||
.collect_vec();
|
||||
log::trace!("Filtered: {:#?}", filtered_gateways);
|
||||
log::trace!("Filtered: {:#?}", gateways_filtered);
|
||||
|
||||
if filtered_gateways.is_empty() {
|
||||
if gateways_filtered.is_empty() {
|
||||
log::warn!("No gateways with high enough performance score found! Using all gateways instead as fallback");
|
||||
return Ok(all_gateways
|
||||
.iter()
|
||||
@@ -162,5 +185,38 @@ pub async fn get_gateways() -> Result<Vec<Gateway>> {
|
||||
.collect_vec());
|
||||
}
|
||||
|
||||
Ok(filtered_gateways)
|
||||
Ok(gateways_filtered)
|
||||
}
|
||||
|
||||
// Lookup and select a single gateway with low latency.
|
||||
#[tauri::command]
|
||||
pub async fn get_gateway_with_low_latency() -> Result<Gateway> {
|
||||
log::trace!("Fetching gateways");
|
||||
let all_gateways = fetch_gateways().await?;
|
||||
log::trace!("Received: {:#?}", all_gateways);
|
||||
|
||||
let gateways_filtered = filter_out_low_performance_gateways(all_gateways);
|
||||
let selected_gateway = select_gateway_by_latency(gateways_filtered).await?;
|
||||
log::debug!("Selected gateway: {}", selected_gateway);
|
||||
Ok(Gateway {
|
||||
identity: selected_gateway.identity().to_base58_string(),
|
||||
})
|
||||
}
|
||||
|
||||
// From a given list of gateways, select the one with low latency.
|
||||
#[tauri::command]
|
||||
pub async fn select_gateway_with_low_latency_from_list(gateways: Vec<Gateway>) -> Result<Gateway> {
|
||||
log::debug!("Selecting a gateway with low latency");
|
||||
let gateways = gateways.into_iter().map(|g| g.identity).collect_vec();
|
||||
let all_gateways = fetch_gateways().await?;
|
||||
let gateways_union_set: Vec<GatewayBondAnnotated> = all_gateways
|
||||
.into_iter()
|
||||
.filter(|g| gateways.contains(g.identity()))
|
||||
.collect();
|
||||
let gateways_filtered = filter_out_low_performance_gateways(gateways_union_set);
|
||||
let selected_gateway = select_gateway_by_latency(gateways_filtered).await?;
|
||||
log::debug!("Selected gateway: {}", selected_gateway);
|
||||
Ok(Gateway {
|
||||
identity: selected_gateway.identity().to_base58_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ fn override_config_from_env(config: &mut Config, privacy_level: &PrivacyLevel) {
|
||||
.provider_mix_address
|
||||
.parse()
|
||||
.expect("failed to parse provider mix address");
|
||||
log::warn!("Using geo-aware mixnode selection baseon the location of: {address}");
|
||||
log::warn!("Using geo-aware mixnode selection based on the location of: {address}");
|
||||
config
|
||||
.core
|
||||
.base
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "nym-connect",
|
||||
"version": "1.1.18"
|
||||
"version": "1.1.19"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
|
||||
@@ -214,7 +214,12 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => {
|
||||
|
||||
const setGateway = async () => {
|
||||
if (gateways) {
|
||||
const randomGateway = getRandomFromList(gateways);
|
||||
let randomGateway;
|
||||
if (userData?.privacy_level === 'Medium') {
|
||||
randomGateway = await invoke<Gateway>('select_gateway_with_low_latency_from_list', { gateways });
|
||||
} else {
|
||||
randomGateway = getRandomFromList(gateways);
|
||||
}
|
||||
const withUserDefinitions = await buildGateway(randomGateway);
|
||||
await invoke('set_gateway', {
|
||||
gateway: shouldUseUserGateway ? userDefinedGateway.address : withUserDefinitions.identity,
|
||||
|
||||
@@ -2,9 +2,10 @@ import React, { ChangeEvent, useState } from 'react';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { Box, FormControl, FormControlLabel, FormHelperText, Stack, Switch, Typography } from '@mui/material';
|
||||
import { useClientContext } from '../../context/main';
|
||||
import { ConnectionStatusKind } from '../../types';
|
||||
|
||||
export const PrivacyLevelSettings = () => {
|
||||
const { userData, setPrivacyLevel } = useClientContext();
|
||||
const { userData, setPrivacyLevel, connectionStatus } = useClientContext();
|
||||
const [speedBoost, setSpeedBoost] = useState(userData?.privacy_level !== 'High');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@@ -29,7 +30,7 @@ export const PrivacyLevelSettings = () => {
|
||||
<Switch
|
||||
checked={speedBoost}
|
||||
onChange={handleChange}
|
||||
disabled={loading}
|
||||
disabled={loading || connectionStatus === ConnectionStatusKind.connected}
|
||||
size="small"
|
||||
sx={{ ml: 1, mr: 1 }}
|
||||
/>
|
||||
|
||||
@@ -7,12 +7,12 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "net.nymtech.nyms5"
|
||||
compileSdk = 33
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "net.nymtech.nyms5"
|
||||
minSdk = 24
|
||||
targetSdk = 33
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
|
||||
@@ -16,11 +16,16 @@ import kotlinx.coroutines.launch
|
||||
import net.nymtech.nyms5.ui.theme.NymTheme
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.map
|
||||
import net.nymtech.nyms5.ui.composables.HomeScreen
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
class MainActivity : ComponentActivity() {
|
||||
private val tag = "MainActivity"
|
||||
private val nymProxy = App.nymProxy
|
||||
|
||||
private val viewModel: MainViewModel by viewModels {
|
||||
MainViewModelFactory(
|
||||
@@ -45,27 +50,53 @@ class MainActivity : ComponentActivity() {
|
||||
Log.d(tag, "____onCreate")
|
||||
Log.i(tag, "device SDK [${Build.VERSION.SDK_INT}]")
|
||||
|
||||
val workManager = WorkManager.getInstance(applicationContext)
|
||||
|
||||
checkPermission()
|
||||
|
||||
// observe proxy work progress
|
||||
WorkManager.getInstance(applicationContext)
|
||||
.getWorkInfoByIdLiveData(ProxyWorker.workId)
|
||||
workManager.getWorkInfoByIdLiveData(ProxyWorker.workId)
|
||||
// this observer is tied to the activity lifecycle
|
||||
.observe(this) { workInfo ->
|
||||
if (workInfo != null && workInfo.state == WorkInfo.State.RUNNING) {
|
||||
val progress =
|
||||
workInfo.progress.getString(ProxyWorker.State)
|
||||
when (progress) {
|
||||
ProxyWorker.Work.Status.CONNECTED.name -> {
|
||||
Log.i(tag, "Nym proxy $progress")
|
||||
viewModel.setConnected()
|
||||
}
|
||||
|
||||
else -> Log.i(tag, "Nym proxy $progress")
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val proxyState = App.nymProxy.getState()
|
||||
val workState = workInfo.state
|
||||
val workProgress = workInfo.progress.getString(ProxyWorker.State)
|
||||
Log.i(
|
||||
tag,
|
||||
"proxy state: $proxyState, work state: $workState, work progress: $workProgress"
|
||||
)
|
||||
if (proxyState == NymProxy.Companion.State.CONNECTED &&
|
||||
workState == WorkInfo.State.RUNNING
|
||||
) {
|
||||
viewModel.setUiConnected()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The work can be cancelled by the user from the dedicated notification
|
||||
// by tapping the "Stop" action. When that happens the underlying proxy
|
||||
// process keeps running in the background
|
||||
// We have to manually call `stopClient` to kill it
|
||||
workManager.getWorkInfoByIdLiveData(ProxyWorker.workId)
|
||||
// watch "forever", ie. even when this viewModel has been cleared
|
||||
.observeForever { workInfo ->
|
||||
if (workInfo?.state == WorkInfo.State.CANCELLED || workInfo?.state == WorkInfo.State.FAILED) {
|
||||
// ⚠ here one could be tempted to call `viewModel.cancelProxyWork`
|
||||
// but it uses viewModelScope which is cancelled when
|
||||
// the app goes to background so use `GlobalScope` instead
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
// if the proxy process is still running kill it
|
||||
if (nymProxy.getState() == NymProxy.Companion.State.CONNECTED) {
|
||||
Log.i(tag, "⚠ work has been cancelled")
|
||||
nymProxy.stop()
|
||||
}
|
||||
}
|
||||
// update the UI
|
||||
viewModel.setUiDisconnected()
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
Log.d(tag, "____UI recompose")
|
||||
@@ -100,11 +131,6 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
viewModel.checkStateSync()
|
||||
}
|
||||
|
||||
private fun checkPermission() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
// POST_NOTIFICATIONS is needed for the notification displayed
|
||||
|
||||
@@ -10,11 +10,8 @@ import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.OutOfQuotaPolicy
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkManager
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
@@ -22,7 +19,6 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
class MainViewModel(
|
||||
private val workManager: WorkManager,
|
||||
private val nymProxy: NymProxy
|
||||
@@ -40,33 +36,7 @@ class MainViewModel(
|
||||
.setId(ProxyWorker.workId)
|
||||
.build()
|
||||
|
||||
init {
|
||||
Log.d(tag, "____init")
|
||||
|
||||
// When the work is cancelled "externally" ie. when the user tap the
|
||||
// "Stop" action on the notification, the underlying proxy process
|
||||
// keeps running in background
|
||||
// We have to manually call `stopClient` to kill it
|
||||
workManager.getWorkInfoByIdLiveData(ProxyWorker.workId)
|
||||
// watch "forever", ie. even when this viewModel has been cleared
|
||||
.observeForever { workInfo ->
|
||||
if (workInfo?.state == WorkInfo.State.CANCELLED || workInfo?.state == WorkInfo.State.FAILED) {
|
||||
// ⚠ here one could be tempted to call cancelProxyWork
|
||||
// but it uses viewModelScope which is cancelled when
|
||||
// this viewModel instance is cleared
|
||||
// use GlobalScope instead
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
// if the proxy process is still running ie. connected kill it
|
||||
if (nymProxy.getState() == NymProxy.Companion.State.CONNECTED) {
|
||||
Log.d(tag, "stopping proxy")
|
||||
nymProxy.stop()
|
||||
Log.i(tag, "proxy work cancelled")
|
||||
}
|
||||
}
|
||||
setDisconnected()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ProxyState(
|
||||
val connected: Boolean = false,
|
||||
@@ -77,7 +47,8 @@ class MainViewModel(
|
||||
private val _uiState = MutableStateFlow(ProxyState())
|
||||
val uiState: StateFlow<ProxyState> = _uiState.asStateFlow()
|
||||
|
||||
fun setConnected() {
|
||||
fun setUiConnected() {
|
||||
Log.d(tag, "____setUiConnected")
|
||||
_uiState.update { currentState ->
|
||||
currentState.copy(
|
||||
connected = true,
|
||||
@@ -86,7 +57,8 @@ class MainViewModel(
|
||||
}
|
||||
}
|
||||
|
||||
private fun setDisconnected() {
|
||||
fun setUiDisconnected() {
|
||||
Log.d(tag, "____setUiDisconnected")
|
||||
_uiState.update { currentState ->
|
||||
currentState.copy(
|
||||
connected = false,
|
||||
@@ -127,30 +99,7 @@ class MainViewModel(
|
||||
// wait a bit to be sure the proxy client has enough time to
|
||||
// close connection
|
||||
delay(2000)
|
||||
setDisconnected()
|
||||
}
|
||||
}
|
||||
|
||||
fun checkStateSync() {
|
||||
Log.d(tag, "check state sync")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val proxyState = nymProxy.getState()
|
||||
val workInfo = workManager.getWorkInfoById(ProxyWorker.workId).get()
|
||||
Log.d(tag, "proxy state $proxyState, work state ${workInfo?.state}")
|
||||
if (proxyState == NymProxy.Companion.State.CONNECTED &&
|
||||
workInfo?.state != WorkInfo.State.RUNNING
|
||||
) {
|
||||
Log.w(tag, "⚠ state desync")
|
||||
Log.i(tag, "stopping proxy")
|
||||
cancelProxyWork()
|
||||
}
|
||||
if (proxyState == NymProxy.Companion.State.DISCONNECTED &&
|
||||
workInfo?.state == WorkInfo.State.RUNNING
|
||||
) {
|
||||
Log.w(tag, "⚠ state desync")
|
||||
Log.i(tag, "stopping worker")
|
||||
workManager.cancelAllWorkByTag(ProxyWorker.workTag)
|
||||
}
|
||||
setUiDisconnected()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ class NymProxy {
|
||||
Log.i(tag, "loaded native library $nymNativeLib")
|
||||
}
|
||||
|
||||
// this is a blocking call as `startClient` is blocking and will releases when
|
||||
// the socks5 connection has been terminated
|
||||
fun start(serviceProvider: String, onStartCbObj: Any, onStopCbObj: Any) {
|
||||
Log.d(tag, "calling $nymNativeLib:startClient")
|
||||
try {
|
||||
@@ -42,6 +44,17 @@ class NymProxy {
|
||||
}
|
||||
}
|
||||
|
||||
fun ping(): Boolean {
|
||||
Log.d(tag, "calling $nymNativeLib:pingClient")
|
||||
try {
|
||||
return pingClient()
|
||||
} catch (e: Throwable) {
|
||||
Log.e(tag, "$nymNativeLib:pingClient internal error: $e")
|
||||
Sentry.captureException(e)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun getState(): State {
|
||||
Log.d(tag, "calling $nymNativeLib:getClientState")
|
||||
try {
|
||||
@@ -66,4 +79,5 @@ class NymProxy {
|
||||
|
||||
private external fun stopClient()
|
||||
private external fun getClientState(): Int
|
||||
private external fun pingClient(): Boolean
|
||||
}
|
||||
@@ -17,6 +17,10 @@ import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import io.sentry.Sentry
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
@@ -32,7 +36,9 @@ class ProxyWorker(
|
||||
companion object Work {
|
||||
const val name = "nymS5ProxyWorker"
|
||||
const val workTag = "nymProxy"
|
||||
val workId: UUID = UUID.randomUUID()
|
||||
// it is very important to use a static UUID in order to allow WorkManager
|
||||
// handling the proxy work as a unique work
|
||||
val workId: UUID = UUID.fromString("cc785aa4-5775-4bf0-b870-39645e35e660")
|
||||
|
||||
const val State = "State"
|
||||
|
||||
@@ -45,6 +51,8 @@ class ProxyWorker(
|
||||
|
||||
private val tag = "proxyWorker"
|
||||
|
||||
private val pingRate = 1000L
|
||||
|
||||
private val spUrl = context.getString(R.string.sp_url)
|
||||
|
||||
private val defaultSp = context.getString(R.string.default_sp)
|
||||
@@ -135,7 +143,26 @@ class ProxyWorker(
|
||||
Log.w(tag, "using a default service provider $defaultSp")
|
||||
}
|
||||
|
||||
nymProxy.start(serviceProvider ?: defaultSp, onStartCb, onStopCb)
|
||||
withContext(Dispatchers.IO) {
|
||||
val pingJob = launch {
|
||||
// this job will get automatically killed by the WorkManager once
|
||||
// the job has been terminated, so it's safe to use `while (true)`
|
||||
while (true) {
|
||||
nymProxy.ping()
|
||||
delay(pingRate)
|
||||
}
|
||||
}
|
||||
|
||||
val proxyJob = launch {
|
||||
nymProxy.start(serviceProvider ?: defaultSp, onStartCb, onStopCb)
|
||||
}
|
||||
|
||||
// wait for the underlying call to `startClient` to be released which means
|
||||
// the connection has been terminated (`startClient` is a blocking call)
|
||||
proxyJob.join()
|
||||
// stop pinging
|
||||
pingJob.cancel()
|
||||
}
|
||||
|
||||
// the state should be already set to DISCONNECTED at this point
|
||||
// but for the sake of it, reset it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id("com.android.application") version "8.1.0" apply false
|
||||
id("com.android.library") version "8.1.0" apply false
|
||||
id("com.android.application") version "8.1.1" apply false
|
||||
id("com.android.library") version "8.1.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "1.8.20" apply false
|
||||
}
|
||||
@@ -89,3 +89,9 @@ pub unsafe extern "C" fn Java_net_nymtech_nyms5_NymProxy_getClientState(
|
||||
ClientState::Disconnected => 2,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Java_net_nymtech_nyms5_NymProxy_pingClient(_env: JNIEnv, _class: JClass) {
|
||||
log::debug!("pong");
|
||||
crate::ping_client();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::persistence::MobileClientStorage;
|
||||
use ::safer_ffi::prelude::*;
|
||||
use anyhow::{anyhow, Result};
|
||||
use lazy_static::lazy_static;
|
||||
use log::{info, warn};
|
||||
use log::{debug, info, warn};
|
||||
use nym_bin_common::logging::setup_logging;
|
||||
use nym_client_core::init::GatewaySetup;
|
||||
use nym_config_common::defaults::setup_env;
|
||||
@@ -16,8 +16,10 @@ use std::marker::Send;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::runtime::Runtime;
|
||||
use tokio::sync::{Mutex, Notify};
|
||||
use tokio::time::{sleep, Instant};
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub mod android;
|
||||
@@ -25,11 +27,14 @@ mod config;
|
||||
mod persistence;
|
||||
|
||||
static SOCKS5_CONFIG_ID: &str = "mobile-socks5-test";
|
||||
const ANDROID_HEALTHCHECK_INTERVAL: Duration = Duration::from_secs(5);
|
||||
const HEALTHCHECK_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
|
||||
// hehe, this is so disgusting : )
|
||||
lazy_static! {
|
||||
static ref CLIENT_SHUTDOWN_HANDLE: Mutex<Option<Arc<Notify>>> = Mutex::new(None);
|
||||
static ref RUNTIME: Runtime = Runtime::new().unwrap();
|
||||
static ref LAST_HEALTHCHECK_PING: Mutex<Option<Instant>> = Mutex::new(None);
|
||||
}
|
||||
static ENV_SET: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
@@ -136,6 +141,50 @@ pub fn stop_client() {
|
||||
RUNTIME.block_on(async move { stop_and_reset_shutdown_handle().await });
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
pub fn ping_client() {
|
||||
RUNTIME.spawn(async {
|
||||
let mut guard = LAST_HEALTHCHECK_PING.lock().await;
|
||||
*guard = Some(Instant::now());
|
||||
});
|
||||
}
|
||||
|
||||
// Continusouly poll that we are being pinged from the outside. If the pings stop that means
|
||||
// that the higher layer somehow terminated without telling us.
|
||||
pub async fn health_check() {
|
||||
// init the ping to now
|
||||
let mut guard = LAST_HEALTHCHECK_PING.lock().await;
|
||||
*guard = Some(Instant::now());
|
||||
// release the mutex
|
||||
drop(guard);
|
||||
|
||||
loop {
|
||||
sleep(ANDROID_HEALTHCHECK_INTERVAL).await;
|
||||
|
||||
if !is_shutdown_handle_set().await {
|
||||
debug!("client has been shutdown, cancelling healthcheck");
|
||||
break;
|
||||
}
|
||||
let mut guard = LAST_HEALTHCHECK_PING.lock().await;
|
||||
let Some(last_ping) = *guard else {
|
||||
warn!("client has not been pinged yet - shutting down");
|
||||
*guard = None;
|
||||
stop_and_reset_shutdown_handle().await;
|
||||
break;
|
||||
};
|
||||
if last_ping.elapsed() > HEALTHCHECK_TIMEOUT {
|
||||
warn!(
|
||||
"client has not been pinged for more than {} seconds - shutting down",
|
||||
HEALTHCHECK_TIMEOUT.as_secs()
|
||||
);
|
||||
*guard = None;
|
||||
stop_and_reset_shutdown_handle().await;
|
||||
break;
|
||||
}
|
||||
debug!("✓ android app healthy");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blocking_run_client<'cb, F, S>(
|
||||
storage_directory: Option<char_p::Ref<'_>>,
|
||||
service_provider: Option<char_p::Ref<'_>>,
|
||||
@@ -150,6 +199,10 @@ pub fn blocking_run_client<'cb, F, S>(
|
||||
return;
|
||||
}
|
||||
|
||||
// Spawn a task that monitors that we are continuously receiving pings from the outside,
|
||||
// to make sure we don't end up with a runaway process
|
||||
RUNTIME.spawn(async { health_check().await });
|
||||
|
||||
let storage_dir = storage_directory.map(|s| s.to_string());
|
||||
let service_provider = service_provider.map(|s| s.to_string());
|
||||
RUNTIME
|
||||
@@ -163,7 +216,10 @@ pub fn blocking_run_client<'cb, F, S>(
|
||||
)
|
||||
.await
|
||||
})
|
||||
.unwrap();
|
||||
.map_err(|err| {
|
||||
warn!("failed to run client: {}", err);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
#[ffi_export]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
[package]
|
||||
name = "nym-network-requester"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version = "1.65"
|
||||
|
||||
@@ -7,7 +7,7 @@ use nym_bin_common::output_format::OutputFormat;
|
||||
|
||||
#[derive(Args)]
|
||||
pub(crate) struct BuildInfo {
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
#[arg(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
|
||||
@@ -24,38 +24,38 @@ use tap::TapFallible;
|
||||
#[derive(Args, Clone)]
|
||||
pub(crate) struct Init {
|
||||
/// Id of the nym-mixnet-client we want to create config for.
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
id: String,
|
||||
|
||||
/// Id of the gateway we are going to connect to.
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
gateway: Option<identity::PublicKey>,
|
||||
|
||||
/// Specifies whether the new gateway should be determined based by latency as opposed to being chosen
|
||||
/// uniformly.
|
||||
#[clap(long, conflicts_with = "gateway")]
|
||||
#[arg(long, conflicts_with = "gateway")]
|
||||
latency_based_selection: bool,
|
||||
|
||||
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
|
||||
/// potentially causing loss of access.
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
force_register_gateway: bool,
|
||||
|
||||
/// Comma separated list of rest endpoints of the nyxd validators
|
||||
#[clap(long, alias = "nymd_validators", value_delimiter = ',')]
|
||||
#[arg(long, alias = "nymd_validators", value_delimiter = ',')]
|
||||
nyxd_urls: Option<Vec<url::Url>>,
|
||||
|
||||
/// Comma separated list of rest endpoints of the API validators
|
||||
#[clap(long, alias = "api_validators", value_delimiter = ',')]
|
||||
#[arg(long, alias = "api_validators", value_delimiter = ',')]
|
||||
// the alias here is included for backwards compatibility (1.1.4 and before)
|
||||
nym_apis: Option<Vec<url::Url>>,
|
||||
|
||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||
/// with bandwidth credential requirement.
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
#[arg(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
error::NetworkRequesterError,
|
||||
};
|
||||
use clap::{CommandFactory, Parser, Subcommand};
|
||||
use log::{error, info};
|
||||
use log::{error, info, trace};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_bin_common::version_checker;
|
||||
@@ -36,17 +36,17 @@ fn pretty_build_info_static() -> &'static str {
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author = "Nymtech", version, about, long_version = pretty_build_info_static())]
|
||||
#[command(author = "Nymtech", version, about, long_version = pretty_build_info_static())]
|
||||
pub(crate) struct Cli {
|
||||
/// Path pointing to an env file that configures the client.
|
||||
#[clap(short, long)]
|
||||
#[arg(short, long)]
|
||||
pub(crate) config_env_file: Option<std::path::PathBuf>,
|
||||
|
||||
/// Flag used for disabling the printed banner in tty.
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
pub(crate) no_banner: bool,
|
||||
|
||||
#[clap(subcommand)]
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
@@ -165,6 +165,7 @@ fn persist_gateway_details(
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, NetworkRequesterError> {
|
||||
trace!("Trying to load as v1.1.13 config");
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
|
||||
// explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19)
|
||||
@@ -186,6 +187,7 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result<bool, NetworkRequesterError> {
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, NetworkRequesterError> {
|
||||
trace!("Trying to load as v1.1.20 config");
|
||||
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
|
||||
|
||||
// explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21)
|
||||
@@ -207,6 +209,8 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result<bool, NetworkRequesterError> {
|
||||
}
|
||||
|
||||
fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, NetworkRequesterError> {
|
||||
trace!("Trying to load as v1.1.20_2 config");
|
||||
|
||||
// explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21)
|
||||
let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else {
|
||||
// if we failed to load it, there might have been nothing to upgrade
|
||||
@@ -224,6 +228,7 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result<bool, NetworkRequesterError>
|
||||
}
|
||||
|
||||
fn try_upgrade_config(id: &str) -> Result<(), NetworkRequesterError> {
|
||||
trace!("Attempting to upgrade config");
|
||||
if try_upgrade_v1_1_13_config(id)? {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -16,39 +16,39 @@ const ENABLE_STATISTICS: &str = "enable-statistics";
|
||||
#[derive(Args, Clone)]
|
||||
pub(crate) struct Run {
|
||||
/// Id of the nym-mixnet-client we want to run.
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
id: String,
|
||||
|
||||
/// Specifies whether this network requester should run in 'open-proxy' mode
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
open_proxy: bool,
|
||||
|
||||
/// Enable service anonymized statistics that get sent to a statistics aggregator server
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
enable_statistics: bool,
|
||||
|
||||
/// Mixnet client address where a statistics aggregator is running. The default value is a Nym
|
||||
/// aggregator client
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
statistics_recipient: Option<String>,
|
||||
|
||||
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||
/// with bandwidth credential requirement.
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
enabled_credentials_mode: Option<bool>,
|
||||
|
||||
/// Mostly debug-related option to increase default traffic rate so that you would not need to
|
||||
/// modify config post init
|
||||
#[clap(long, hide = true)]
|
||||
#[arg(long, hide = true)]
|
||||
fastmode: bool,
|
||||
|
||||
/// Disable loop cover traffic and the Poisson rate limiter (for debugging only)
|
||||
#[clap(long, hide = true)]
|
||||
#[arg(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)]
|
||||
#[arg(long, hide = true)]
|
||||
medium_toggle: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,14 @@ use nym_types::helpers::ConsoleSigningOutput;
|
||||
#[derive(Args, Clone)]
|
||||
pub(crate) struct Sign {
|
||||
/// The id of the mixnode you want to sign with
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
id: String,
|
||||
|
||||
/// Signs a transaction-specific payload, that is going to be sent to the smart contract, with your identity key
|
||||
#[clap(long)]
|
||||
#[arg(long)]
|
||||
contract_msg: String,
|
||||
|
||||
#[clap(short, long, default_value_t = OutputFormat::default())]
|
||||
#[arg(short, long, default_value_t = OutputFormat::default())]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use crate::config::persistence::NetworkRequesterPaths;
|
||||
use crate::config::{default_config_filepath, Config, Debug, NetworkRequester};
|
||||
use log::trace;
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2;
|
||||
use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseClientConfigV1_1_20_2;
|
||||
@@ -13,6 +14,8 @@ use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use super::persistence::DEFAULT_DESCRIPTION_FILENAME;
|
||||
|
||||
pub const DEFAULT_STANDARD_LIST_UPDATE_INTERVAL: Duration = Duration::from_secs(30 * 60);
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
|
||||
@@ -56,13 +59,23 @@ impl ConfigV1_1_20_2 {
|
||||
// in this upgrade, gateway endpoint configuration was moved out of the config file,
|
||||
// so its returned to be stored elsewhere.
|
||||
pub fn upgrade(self) -> (Config, GatewayEndpointConfig) {
|
||||
trace!("Upgrading from v1.1.20_2");
|
||||
let gateway_details = self.base.client.gateway_endpoint.clone().into();
|
||||
let nr_description = self
|
||||
.storage_paths
|
||||
.common_paths
|
||||
.keys
|
||||
.ack_key_file
|
||||
.parent()
|
||||
.expect("config paths upgrade failure")
|
||||
.join(DEFAULT_DESCRIPTION_FILENAME);
|
||||
let config = Config {
|
||||
base: self.base.into(),
|
||||
storage_paths: NetworkRequesterPaths {
|
||||
common_paths: self.storage_paths.common_paths.upgrade_default(),
|
||||
allowed_list_location: self.storage_paths.allowed_list_location,
|
||||
unknown_list_location: self.storage_paths.unknown_list_location,
|
||||
nr_description,
|
||||
},
|
||||
network_requester_debug: self.network_requester_debug.into(),
|
||||
logging: self.logging,
|
||||
|
||||
@@ -7,6 +7,7 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
pub const DEFAULT_ALLOWED_LIST_FILENAME: &str = "allowed.list";
|
||||
pub const DEFAULT_UNKNOWN_LIST_FILENAME: &str = "unknown.list";
|
||||
pub const DEFAULT_DESCRIPTION_FILENAME: &str = "description.toml";
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
|
||||
pub struct NetworkRequesterPaths {
|
||||
@@ -18,6 +19,11 @@ pub struct NetworkRequesterPaths {
|
||||
|
||||
/// Location of the file containing our unknown.list
|
||||
pub unknown_list_location: PathBuf,
|
||||
|
||||
/// Location of the file containing our description
|
||||
// For upgrade use default if missing. On next config upgrade iteration, remove the serde(default)
|
||||
#[serde(default)]
|
||||
pub nr_description: PathBuf,
|
||||
}
|
||||
|
||||
impl NetworkRequesterPaths {
|
||||
@@ -28,6 +34,7 @@ impl NetworkRequesterPaths {
|
||||
common_paths: CommonClientPaths::new_default(base_dir),
|
||||
allowed_list_location: base_dir.join(DEFAULT_ALLOWED_LIST_FILENAME),
|
||||
unknown_list_location: base_dir.join(DEFAULT_UNKNOWN_LIST_FILENAME),
|
||||
nr_description: base_dir.join(DEFAULT_DESCRIPTION_FILENAME),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,9 @@ allowed_list_location = '{{ storage_paths.allowed_list_location }}'
|
||||
# Location of the file containing our unknown.list
|
||||
unknown_list_location = '{{ storage_paths.unknown_list_location }}'
|
||||
|
||||
# Path to file containing description of this network-requester.
|
||||
nr_description = '{{ storage_paths.nr_description }}'
|
||||
|
||||
|
||||
[network_requester]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-network-statistics"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nym-cli"
|
||||
version = "1.1.26"
|
||||
version = "1.1.27"
|
||||
authors.workspace = true
|
||||
edition = "2021"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user