diff --git a/.github/workflows/build-and-upload-binaries-ci.yml b/.github/workflows/build-and-upload-binaries-ci.yml
index c8e5bc924e..448b947179 100644
--- a/.github/workflows/build-and-upload-binaries-ci.yml
+++ b/.github/workflows/build-and-upload-binaries-ci.yml
@@ -34,7 +34,7 @@ on:
- 'tools/ts-rs-cli/**'
env:
- NETWORK: mainnet
+ NETWORK: mainnet
jobs:
publish-nym:
@@ -46,7 +46,7 @@ jobs:
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v3
-
+
- name: Prepare build output directory
shell: bash
env:
@@ -110,4 +110,3 @@ jobs:
REMOTE_USER: ${{ secrets.CI_WWW_REMOTE_USER }}
TARGET: ${{ secrets.CI_WWW_REMOTE_TARGET }}/builds/
EXCLUDE: "/dist/, /node_modules/"
-
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b108c9437e..b49c2a3e01 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,14 +6,28 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
### Added
-- remove coconut feature and unify builds ([#2890])
-- native-client: is now capable of listening for requests on sockets different than `127.0.0.1` ([#2939]). This can be specified via `--host` flag during `init` or `run`. Alternatively a custom `host` can be set in `config.toml` file under `socket` section.
- dkg resharing mode ([#2936])
-[#2890]: https://github.com/nymtech/nym/pull/2890
-[#2939]: https://github.com/nymtech/nym/pull/2939
[#2936]: https://github.com/nymtech/nym/pull/2936
+
+# [v1.1.9] (2023-02-07)
+
+### Added
+
+- Separate `nym-api` endpoints with values of "total-supply" and "circulating-supply" in `nym` ([#2964])
+- Add `host` option to client init ([#2912])
+- Remove Coconut feature flag ([#2793])
+- Don't drop in mixnet connection handler ([#2963])
+
+### Changed
+- native-client: is now capable of listening for requests on sockets different than `127.0.0.1` ([#2939]). This can be specified via `--host` flag during `init` or `run`. Alternatively a custom `host` can be set in `config.toml` file under `socket` section.
+- mixnode, gateway: fix unexpected shutdown on corrupted connection ([#2963])
+
+[#2939]: https://github.com/nymtech/nym/pull/2939
+[#2963]: https://github.com/nymtech/nym/pull/2963
+
+
# [v1.1.8] (2023-01-31)
### Added
diff --git a/explorer/CHANGELOG.md b/explorer/CHANGELOG.md
index 2bdbaeab0e..0098db042d 100644
--- a/explorer/CHANGELOG.md
+++ b/explorer/CHANGELOG.md
@@ -1,5 +1,15 @@
## UNRELEASED
+- nothing yet
+
+## [nym-explorer-v1.0.5](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.5) (2023-02-07)
+
+- NE - link `Owner` field on the node detail page to the account details on NG explorer ([#2923])
+- NE - Upgrade Sandbox and make below changes: ([#2332])
+
+[#2923]: https://github.com/nymtech/nym/issues/2923
+[#2332]: https://github.com/nymtech/nym/issues/2332
+
## [nym-explorer-v1.0.4](https://github.com/nymtech/nym/tree/nym-explorer-v1.0.4) (2023-01-31)
- Add routing score on gateway list ([#2913])
diff --git a/explorer/src/components/DetailTable.tsx b/explorer/src/components/DetailTable.tsx
index 17418de4f3..80e7ce969b 100644
--- a/explorer/src/components/DetailTable.tsx
+++ b/explorer/src/components/DetailTable.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
+import { Link, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { Tooltip } from '@nymproject/react/tooltip/Tooltip';
import { CopyToClipboard } from '@nymproject/react/clipboard/CopyToClipboard';
@@ -37,9 +37,19 @@ function formatCellValues(val: string | number, field: string) {
);
}
+
if (field === 'bond') {
return unymToNym(val, 6);
}
+
+ if (field === 'owner') {
+ return (
+
+ {val}
+
+ );
+ }
+
return val;
}
diff --git a/gateway/src/node/mixnet_handling/receiver/connection_handler.rs b/gateway/src/node/mixnet_handling/receiver/connection_handler.rs
index 3581d287d3..34d9808040 100644
--- a/gateway/src/node/mixnet_handling/receiver/connection_handler.rs
+++ b/gateway/src/node/mixnet_handling/receiver/connection_handler.rs
@@ -181,6 +181,7 @@ impl ConnectionHandler {
mut shutdown: TaskClient,
) {
debug!("Starting connection handler for {:?}", remote);
+ shutdown.mark_as_success();
let mut framed_conn = Framed::new(conn, SphinxCodec);
while !shutdown.is_shutdown() {
tokio::select! {
diff --git a/mixnode/src/node/listener/connection_handler/mod.rs b/mixnode/src/node/listener/connection_handler/mod.rs
index 2b6e9f562b..d09a78db2b 100644
--- a/mixnode/src/node/listener/connection_handler/mod.rs
+++ b/mixnode/src/node/listener/connection_handler/mod.rs
@@ -77,6 +77,7 @@ impl ConnectionHandler {
mut shutdown: TaskClient,
) {
debug!("Starting connection handler for {:?}", remote);
+ shutdown.mark_as_success();
let mut framed_conn = Framed::new(conn, SphinxCodec);
while !shutdown.is_shutdown() {
tokio::select! {
diff --git a/nym-api/src/circulating_supply_api/mod.rs b/nym-api/src/circulating_supply_api/mod.rs
index 9d0e984ab6..900d38380b 100644
--- a/nym-api/src/circulating_supply_api/mod.rs
+++ b/nym-api/src/circulating_supply_api/mod.rs
@@ -15,7 +15,11 @@ pub(crate) mod routes;
/// Merges the routes with http information and returns it to Rocket for serving
pub(crate) fn circulating_supply_routes(settings: &OpenApiSettings) -> (Vec, OpenApi) {
- openapi_get_routes_spec![settings: routes::get_circulating_supply]
+ openapi_get_routes_spec![
+ settings: routes::get_full_circulating_supply,
+ routes::get_total_supply,
+ routes::get_circulating_supply
+ ]
}
/// Spawn the circulating supply cache refresher.
diff --git a/nym-api/src/circulating_supply_api/routes.rs b/nym-api/src/circulating_supply_api/routes.rs
index 898248445a..da6aea1d22 100644
--- a/nym-api/src/circulating_supply_api/routes.rs
+++ b/nym-api/src/circulating_supply_api/routes.rs
@@ -1,15 +1,30 @@
-use rocket::http::Status;
-use rocket::serde::json::Json;
-use rocket::State;
+// Copyright 2022-2023 - Nym Technologies SA
+// SPDX-License-Identifier: Apache-2.0
use crate::circulating_supply_api::cache::CirculatingSupplyCache;
use crate::node_status_api::models::ErrorResponse;
use nym_api_requests::models::CirculatingSupplyResponse;
+use rocket::http::Status;
+use rocket::serde::json::Json;
+use rocket::State;
use rocket_okapi::openapi;
+use validator_client::nyxd::Coin;
+
+// TODO: this is not the best place to put it, it should be more centralised,
+// but for a quick fix, that's good enough for now...
+// (for proper solution we should be managing `NymNetworkDetails` via rocket and grabbing display exponent
+// value from the mix denom here.
+const UNYM_RATIO: f64 = 1000000.;
+
+fn unym_coin_to_float_unym(coin: Coin) -> f64 {
+ // our total supply can't exceed 1B so an overflow here is impossible
+ // (if it happened, then we SHOULD crash)
+ coin.amount as f64 / UNYM_RATIO
+}
#[openapi(tag = "circulating-supply")]
#[get("/circulating-supply")]
-pub(crate) async fn get_circulating_supply(
+pub(crate) async fn get_full_circulating_supply(
cache: &State,
) -> Result, ErrorResponse> {
match cache.get_circulating_supply().await {
@@ -20,3 +35,43 @@ pub(crate) async fn get_circulating_supply(
)),
}
}
+
+#[openapi(tag = "circulating-supply")]
+#[get("/circulating-supply/total-supply-value")]
+pub(crate) async fn get_total_supply(
+ cache: &State,
+) -> Result, ErrorResponse> {
+ let full_circulating_supply = match cache.get_circulating_supply().await {
+ Some(res) => res,
+ None => {
+ return Err(ErrorResponse::new(
+ "unavailable",
+ Status::InternalServerError,
+ ))
+ }
+ };
+
+ Ok(Json(unym_coin_to_float_unym(
+ full_circulating_supply.total_supply.into(),
+ )))
+}
+
+#[openapi(tag = "circulating-supply")]
+#[get("/circulating-supply/circulating-supply-value")]
+pub(crate) async fn get_circulating_supply(
+ cache: &State,
+) -> Result, ErrorResponse> {
+ let full_circulating_supply = match cache.get_circulating_supply().await {
+ Some(res) => res,
+ None => {
+ return Err(ErrorResponse::new(
+ "unavailable",
+ Status::InternalServerError,
+ ))
+ }
+ };
+
+ Ok(Json(unym_coin_to_float_unym(
+ full_circulating_supply.circulating_supply.into(),
+ )))
+}
diff --git a/nym-connect/CHANGELOG.md b/nym-connect/CHANGELOG.md
index c1bf4a7b85..5c0a81945a 100644
--- a/nym-connect/CHANGELOG.md
+++ b/nym-connect/CHANGELOG.md
@@ -2,6 +2,18 @@
## UNRELEASED
+## [nym-connect-v1.1.9](https://github.com/nymtech/nym/tree/nym-connect-v1.1.9) (2023-02-07)
+
+- NC - Button animations ([#2949])
+- NC - add effect when the button is clicked ([#2947])
+- NC - UI to select gateways based on some performance criteria by checking gateways' routing score from nym-api ([#2942])
+- NC - client health check when connecting ([#2859])
+
+[#2949]: https://github.com/nymtech/nym/issues/2949
+[#2947]: https://github.com/nymtech/nym/issues/2947
+[#2942]: https://github.com/nymtech/nym/issues/2942
+[#2859]: https://github.com/nymtech/nym/issues/2859
+
## [nym-connect-v1.1.8](https://github.com/nymtech/nym/tree/nym-connect-v1.1.8) (2023-01-31)
- Add supported apps in the menu + update guide ([#2868])
diff --git a/nym-connect/src-tauri/Cargo.toml b/nym-connect/src-tauri/Cargo.toml
index 54c39aac73..93e21710bb 100644
--- a/nym-connect/src-tauri/Cargo.toml
+++ b/nym-connect/src-tauri/Cargo.toml
@@ -45,6 +45,8 @@ url = "2.2"
yaml-rust = "0.4"
client-core = { path = "../../clients/client-core" }
+nym-api-requests = { path = "../../nym-api/nym-api-requests" }
+contracts-common = { path = "../../common/cosmwasm-smart-contracts/contracts-common"}
config-common = { path = "../../common/config", package = "config" }
crypto = { path = "../../common/crypto" }
logging = { path = "../../common/logging"}
diff --git a/nym-connect/src-tauri/src/main.rs b/nym-connect/src-tauri/src/main.rs
index 6540fa94f4..ec36c252d4 100644
--- a/nym-connect/src-tauri/src/main.rs
+++ b/nym-connect/src-tauri/src/main.rs
@@ -52,6 +52,7 @@ fn main() {
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_gateways_detailed,
crate::operations::export::export_keys,
crate::operations::window::hide_window,
crate::operations::growth::test_and_earn::growth_tne_get_client_id,
diff --git a/nym-connect/src-tauri/src/operations/directory/mod.rs b/nym-connect/src-tauri/src/operations/directory/mod.rs
index efc2ba175b..66070a3b00 100644
--- a/nym-connect/src-tauri/src/operations/directory/mod.rs
+++ b/nym-connect/src-tauri/src/operations/directory/mod.rs
@@ -1,21 +1,35 @@
use itertools::Itertools;
use crate::error::Result;
-use crate::models::{DirectoryService, HarbourMasterService, PagedResult};
+use crate::models::{
+ DirectoryService, DirectoryServiceProvider, HarbourMasterService, PagedResult,
+};
+use contracts_common::types::Percent;
+use nym_api_requests::models::GatewayBondAnnotated;
static SERVICE_PROVIDER_WELLKNOWN_URL: &str =
"https://nymtech.net/.wellknown/connect/service-providers.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";
+
#[tauri::command]
-pub async fn get_services() -> Result> {
+pub async fn get_services() -> Result> {
log::trace!("Fetching services");
- let res = reqwest::get(SERVICE_PROVIDER_WELLKNOWN_URL)
+ let services_res = reqwest::get(SERVICE_PROVIDER_WELLKNOWN_URL)
.await?
.json::>()
.await?;
- log::trace!("Received: {:#?}", res);
+ log::trace!("Received: {:#?}", services_res);
+
+ log::trace!("Fetching gateways");
+ let gateway_res = reqwest::get(GATEWAYS_DETAILED_URL)
+ .await?
+ .json::>()
+ .await?;
+ log::trace!("Received: {:#?}", gateway_res);
// TODO: get paged
log::trace!("Fetching active services");
@@ -27,7 +41,7 @@ pub async fn get_services() -> Result> {
let mut filtered: Vec = vec![];
- for service in &res {
+ for service in &services_res {
let items: _ = service
.items
.clone()
@@ -47,5 +61,32 @@ pub async fn get_services() -> Result> {
})
}
- Ok(filtered)
+ 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 = filtered
+ .iter_mut()
+ .fold(vec![], |mut acc, sp| {
+ acc.append(&mut sp.items);
+ acc
+ })
+ .into_iter()
+ .filter(|sp| {
+ gateway_res.iter().any(|gateway| {
+ gateway.gateway_bond.gateway.identity_key == sp.gateway
+ && gateway.performance >= perf_threshold
+ })
+ })
+ .collect();
+
+ Ok(services_with_good_performance)
+}
+
+#[tauri::command]
+pub async fn get_gateways_detailed() -> Result> {
+ let res = reqwest::get(GATEWAYS_DETAILED_URL)
+ .await?
+ .json::>()
+ .await?;
+ Ok(res)
}
diff --git a/nym-connect/src/App.tsx b/nym-connect/src/App.tsx
deleted file mode 100644
index 9d57dcf4d8..0000000000
--- a/nym-connect/src/App.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-import React, { useEffect } from 'react';
-import { DateTime } from 'luxon';
-import { forage } from '@tauri-apps/tauri-forage';
-import { useClientContext } from './context/main';
-import { useTauriEvents } from './utils';
-import { AppRoutes } from './routes';
-import { Connected } from './pages/connection/Connected';
-
-export const App: FCWithChildren = () => {
- const context = useClientContext();
- const [busy, setBusy] = React.useState();
-
- useTauriEvents('help://clear-storage', (_event) => {
- console.log('About to clear local storage...');
- // clear local storage
- try {
- forage.clear()();
- console.log('Local storage cleared');
- } catch (e) {
- console.error('Failed to clear local storage', e);
- }
- });
-
- const handleConnectClick = React.useCallback(async () => {
- const currentStatus = context.connectionStatus;
- if (currentStatus === 'connected' || currentStatus === 'disconnected') {
- setBusy(true);
-
- // eslint-disable-next-line default-case
- switch (currentStatus) {
- case 'disconnected':
- await context.startConnecting();
- context.setConnectedSince(DateTime.now());
- break;
- case 'connected':
- await context.startDisconnecting();
- context.setConnectedSince(undefined);
- break;
- }
- setBusy(false);
- }
- }, [context.connectionStatus]);
-
- if (context.connectionStatus === 'disconnected' || context.connectionStatus === 'connecting') {
- return ;
- }
-
- return (
- context.setShowInfoModal(false)}
- busy={busy}
- onConnectClick={handleConnectClick}
- ipAddress="127.0.0.1"
- port={1080}
- gatewayPerformance={context.gatewayPerformance}
- connectedSince={context.connectedSince}
- serviceProvider={context.selectedProvider}
- stats={[
- {
- label: 'in:',
- totalBytes: 1024,
- rateBytesPerSecond: 1024 * 1024 * 1024 + 10,
- },
- {
- label: 'out:',
- totalBytes: 1024 * 1024 * 1024 * 1024 * 20,
- rateBytesPerSecond: 1024 * 1024 + 10,
- },
- ]}
- />
- );
-};
diff --git a/nym-connect/src/components/ConnectionStatus.tsx b/nym-connect/src/components/ConnectionStatus.tsx
index e917644efe..1be1f4487b 100644
--- a/nym-connect/src/components/ConnectionStatus.tsx
+++ b/nym-connect/src/components/ConnectionStatus.tsx
@@ -83,7 +83,6 @@ export const ConnectionStatus: FCWithChildren<{
serviceProvider?: ServiceProvider;
}> = ({ status, serviceProvider, gatewayPerformance }) => {
const color = status === 'connected' || status === 'disconnecting' ? '#21D072' : 'white';
- console.log(gatewayPerformance);
return (
<>
diff --git a/nym-connect/src/components/PowerButton.tsx b/nym-connect/src/components/PowerButton.tsx
deleted file mode 100644
index 426028a767..0000000000
--- a/nym-connect/src/components/PowerButton.tsx
+++ /dev/null
@@ -1,132 +0,0 @@
-import React from 'react';
-import { ConnectionStatusKind } from 'src/types';
-
-const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isError: boolean): string => {
- if (isError && hover) {
- return '#21D072';
- }
- if (isError) {
- return '#40475C';
- }
-
- switch (status) {
- case 'disconnected':
- if (hover) {
- return '#FFF';
- }
- return '#BBB';
- case 'connecting':
- return '#FFF';
- case 'disconnecting':
- return '#FFF';
- default:
- // connected
- if (hover) {
- return '#E43E3E';
- }
- return '#21D072';
- }
-};
-
-export const PowerButton: FCWithChildren<{
- onClick?: (status: ConnectionStatusKind) => void;
- isError?: boolean;
- disabled?: boolean;
- status: ConnectionStatusKind;
- busy?: boolean;
-}> = ({ onClick, disabled, status, isError }) => {
- const [hover, setHover] = React.useState(false);
-
- const handleClick = () => {
- if (disabled === true) {
- return;
- }
- if (onClick) {
- onClick(status);
- }
- };
-
- const statusFillColor = getStatusFillColor(status, hover, Boolean(isError));
-
- return (
-
- );
-};
diff --git a/nym-connect/src/components/PowerButton/PowerButton.tsx b/nym-connect/src/components/PowerButton/PowerButton.tsx
new file mode 100644
index 0000000000..4e0c690967
--- /dev/null
+++ b/nym-connect/src/components/PowerButton/PowerButton.tsx
@@ -0,0 +1,123 @@
+import React, { useCallback } from 'react';
+import { ConnectionStatusKind } from 'src/types';
+import './power-button.css';
+
+const getStatusFillColor = (status: ConnectionStatusKind, hover: boolean, isError: boolean): string => {
+ if (isError && hover) {
+ return '#21D072';
+ }
+ if (isError) {
+ return '#40475C';
+ }
+
+ switch (status) {
+ case 'disconnected':
+ if (hover) {
+ return '#FFF';
+ }
+ return '#BBB';
+ case 'connecting':
+ return '#FFF';
+ case 'disconnecting':
+ return '#FFF';
+ default:
+ // connected
+ if (hover) {
+ return '#E43E3E';
+ }
+ return '#21D072';
+ }
+};
+
+export const PowerButton: FCWithChildren<{
+ onClick?: (status: ConnectionStatusKind) => void;
+ isError?: boolean;
+ disabled?: boolean;
+ status: ConnectionStatusKind;
+ busy?: boolean;
+}> = ({ onClick, disabled, status, isError }) => {
+ const [hover, setHover] = React.useState(false);
+
+ const handleClick = () => {
+ if (disabled === true) {
+ return;
+ }
+ if (onClick) {
+ onClick(status);
+ }
+ };
+
+ const statusFillColor = getStatusFillColor(status, hover, Boolean(isError));
+
+ const getClassName = useCallback(() => {
+ if (hover) {
+ switch (status) {
+ case 'disconnected':
+ return 'expand';
+ default:
+ return 'contract';
+ }
+ }
+ if (!hover) {
+ switch (status) {
+ case 'connected':
+ return 'expand';
+ default:
+ return 'contract';
+ }
+ }
+ }, [status, hover]);
+
+ const buttonPulse = () => {
+ if (status === 'connecting' || status === 'disconnecting') return 'pulse';
+ return undefined;
+ };
+
+ return (
+
+ );
+};
diff --git a/nym-connect/src/components/PowerButton/power-button.css b/nym-connect/src/components/PowerButton/power-button.css
new file mode 100644
index 0000000000..a493d8df25
--- /dev/null
+++ b/nym-connect/src/components/PowerButton/power-button.css
@@ -0,0 +1,72 @@
+#ring-expand {
+ animation-name: rings-expand;
+ animation-duration: 0.4s;
+ animation-timing-function: ease-in-out;
+ animation-play-state: paused;
+}
+
+#ring-one.expand {
+ opacity: 0.3;
+ transition: opacity 0.1s ease-in-out;
+}
+
+#ring-two.expand {
+ opacity: 0.2;
+ transition: opacity 0.2s ease-in-out;
+}
+
+#ring-three.expand {
+ opacity: 0.1;
+ transition: opacity 0.3s ease-in-out;
+}
+
+#ring-four.expand {
+ opacity: 0.05;
+ transition: opacity 0.4s ease-in-out;
+}
+
+#ring-one.contract {
+ opacity: 0;
+ transition: opacity 0.4s;
+ transition-delay: 0.1s;
+}
+
+#ring-two.contract {
+ opacity: 0;
+ transition: opacity 0.3s;
+ transition-delay: 0.1s;
+}
+
+#ring-three.contract {
+ opacity: 0;
+ transition: opacity 0.1s;
+ transition-delay: 0.1s;
+}
+
+#ring-four.contract {
+ opacity: 0;
+ transition: opacity 0.1s;
+ transition-delay: 0.1s;
+}
+
+circle,
+path {
+ transition: stroke 0.5s, fill 0.5s;
+}
+
+.pulse {
+ animation-name: pulse;
+ animation-duration: 0.5s;
+ animation-iteration-count: infinite;
+ animation-direction: alternate;
+}
+
+@keyframes pulse {
+ from {
+ opacity: 1;
+ }
+
+ to {
+ opacity: 0.3;
+ }
+}
diff --git a/nym-connect/src/context/main.tsx b/nym-connect/src/context/main.tsx
index 3ea8a3cad2..625cf7b5fd 100644
--- a/nym-connect/src/context/main.tsx
+++ b/nym-connect/src/context/main.tsx
@@ -1,15 +1,13 @@
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState, useRef } from 'react';
import { DateTime } from 'luxon';
import { invoke } from '@tauri-apps/api';
-import type { UnlistenFn } from '@tauri-apps/api/event';
-import { listen } from '@tauri-apps/api/event';
import { forage } from '@tauri-apps/tauri-forage';
import { Error } from 'src/types/error';
-import { TauriEvent } from 'src/types/event';
import { getVersion } from '@tauri-apps/api/app';
import { ConnectionStatusKind, GatewayPerformance } from '../types';
import { ConnectionStatsItem } from '../components/ConnectionStats';
import { ServiceProvider, Services } from '../types/directory';
+import { useEvents } from 'src/hooks/events';
const TAURI_EVENT_STATUS_CHANGED = 'app:connection-status-changed';
@@ -57,21 +55,21 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => {
const timerId = useRef();
- const flattenProviders = (services: Services) => {
- return services.reduce((a: ServiceProvider[], b) => {
- return [...a, ...b.items];
- }, []);
- };
-
const initialiseApp = async () => {
const services = await invoke('get_services');
- const allServiceProviders = flattenProviders(services as Services);
const AppVersion = await getAppVersion();
+ console.log(services);
setAppVersion(AppVersion);
- setServiceProviders(allServiceProviders);
+ setServiceProviders(services as ServiceProvider[]);
};
+ useEvents({
+ onError: (error) => setError(error),
+ onGatewayPerformanceChange: (performance) => setGatewayPerformance(performance),
+ onStatusChange: (status) => setConnectionStatus(status),
+ });
+
useEffect(() => {
initialiseApp();
}, []);
@@ -84,49 +82,6 @@ export const ClientContextProvider: FCWithChildren = ({ children }) => {
})();
}, []);
- useEffect(() => {
- const unlisten: UnlistenFn[] = [];
-
- // TODO: fix typings
- listen(TAURI_EVENT_STATUS_CHANGED, (event) => {
- const { status } = event.payload as any;
- console.log(TAURI_EVENT_STATUS_CHANGED, { status, event });
- setConnectionStatus(status);
- })
- .then((result) => {
- unlisten.push(result);
- })
- .catch((e) => console.log(e));
-
- listen('socks5-event', (e: TauriEvent) => {
- console.log(e);
-
- setError(e.payload);
- }).then((result) => {
- unlisten.push(result);
- });
-
- listen('socks5-status-event', (e: TauriEvent) => {
- if (e.payload.message.includes('slow')) {
- setGatewayPerformance('Poor');
-
- if (timerId.current) {
- clearTimeout(timerId.current);
- }
-
- timerId.current = setTimeout(() => {
- setGatewayPerformance('Good');
- }, 10000);
- }
- }).then((result) => {
- unlisten.push(result);
- });
-
- return () => {
- unlisten.forEach((unsubscribe) => unsubscribe());
- };
- }, []);
-
const startConnecting = useCallback(async () => {
try {
await invoke('start_connecting');
diff --git a/nym-connect/src/hooks/events.ts b/nym-connect/src/hooks/events.ts
new file mode 100644
index 0000000000..4b2c4fcc55
--- /dev/null
+++ b/nym-connect/src/hooks/events.ts
@@ -0,0 +1,68 @@
+import { useEffect, useRef } from 'react';
+import { listen, UnlistenFn } from '@tauri-apps/api/event';
+import { ConnectionStatusKind, GatewayPerformance } from 'src/types';
+import { Error } from 'src/types/error';
+import { TauriEvent } from 'src/types/event';
+
+const TAURI_EVENT_STATUS_CHANGED = 'app:connection-status-changed';
+
+export const useEvents = ({
+ onError,
+ onStatusChange,
+ onGatewayPerformanceChange,
+}: {
+ onError: (error: Error) => void;
+ onStatusChange: (status: ConnectionStatusKind) => void;
+ onGatewayPerformanceChange: (status: GatewayPerformance) => void;
+}) => {
+ const timerId = useRef();
+
+ useEffect(() => {
+ const unlisten: UnlistenFn[] = [];
+
+ // TODO: fix typings
+ listen(TAURI_EVENT_STATUS_CHANGED, (event) => {
+ const { status } = event.payload as any;
+ console.log(TAURI_EVENT_STATUS_CHANGED, { status, event });
+ onStatusChange(status);
+ })
+ .then((result) => {
+ unlisten.push(result);
+ })
+ .catch((e) => console.log(e));
+
+ listen('socks5-event', (e: TauriEvent) => {
+ console.log(e);
+ onError(e.payload);
+ }).then((result) => {
+ unlisten.push(result);
+ });
+
+ listen('socks5-status-event', (e: TauriEvent) => {
+ if (e.payload.message.includes('slow')) {
+ onGatewayPerformanceChange('Poor');
+
+ if (timerId?.current) {
+ clearTimeout(timerId.current);
+ }
+
+ timerId.current = setTimeout(() => {
+ onGatewayPerformanceChange('Good');
+ }, 10000);
+ }
+ }).then((result) => {
+ unlisten.push(result);
+ });
+
+ listen('socks5-connection-fail-event', (e: TauriEvent) => {
+ onError({ title: 'Connection failed', message: `${e.payload.message} - Please disconnect and reconnect.` });
+ onGatewayPerformanceChange('Poor');
+ }).then((result) => {
+ unlisten.push(result);
+ });
+
+ return () => {
+ unlisten.forEach((unsubscribe) => unsubscribe());
+ };
+ }, []);
+};
diff --git a/nym-connect/src/index.tsx b/nym-connect/src/index.tsx
index 7041b86787..2498330910 100644
--- a/nym-connect/src/index.tsx
+++ b/nym-connect/src/index.tsx
@@ -4,7 +4,6 @@ import { ErrorBoundary } from 'react-error-boundary';
import { ClientContextProvider } from './context/main';
import { ErrorFallback } from './components/Error';
import { NymMixnetTheme } from './theme';
-import { App } from './App';
import { AppWindowFrame } from './components/AppWindowFrame';
import { TestAndEarnContextProvider } from './components/Growth/context/TestAndEarnContext';
import { BrowserRouter as Router } from 'react-router-dom';
diff --git a/nym-connect/src/pages/connection/Connected.tsx b/nym-connect/src/pages/connection/Connected.tsx
index 63da0d6fb1..5071349ec3 100644
--- a/nym-connect/src/pages/connection/Connected.tsx
+++ b/nym-connect/src/pages/connection/Connected.tsx
@@ -10,9 +10,12 @@ import { IpAddressAndPort } from 'src/components/IpAddressAndPort';
import { ServiceProvider } from 'src/types/directory';
import { ExperimentalWarning } from 'src/components/ExperimentalWarning';
import { ConnectionLayout } from 'src/layouts/ConnectionLayout';
-import { PowerButton } from 'src/components/PowerButton';
+import { PowerButton } from 'src/components/PowerButton/PowerButton';
+import { Error } from 'src/types/error';
+import { InfoModal } from 'src/components/InfoModal';
export const Connected: FCWithChildren<{
+ error?: Error;
status: ConnectionStatusKind;
showInfoModal: boolean;
gatewayPerformance: GatewayPerformance;
@@ -23,9 +26,11 @@ export const Connected: FCWithChildren<{
busy?: boolean;
isError?: boolean;
serviceProvider?: ServiceProvider;
+ clearError: () => void;
onConnectClick: (status: ConnectionStatusKind) => void;
closeInfoModal: () => void;
}> = ({
+ error,
status,
showInfoModal,
gatewayPerformance,
@@ -35,11 +40,13 @@ export const Connected: FCWithChildren<{
busy,
isError,
serviceProvider,
+ clearError,
onConnectClick,
closeInfoModal,
}) => {
return (
<>
+ {error && }
}
BottomContent={
diff --git a/nym-connect/src/pages/connection/Disconnected.tsx b/nym-connect/src/pages/connection/Disconnected.tsx
index f92d70ad55..781f49eb85 100644
--- a/nym-connect/src/pages/connection/Disconnected.tsx
+++ b/nym-connect/src/pages/connection/Disconnected.tsx
@@ -2,14 +2,12 @@ import React from 'react';
import { Stack, Typography } from '@mui/material';
import { ConnectionStatus } from 'src/components/ConnectionStatus';
import { ConnectionTimer } from 'src/components/ConntectionTimer';
-import { useClientContext } from 'src/context/main';
import { InfoModal } from 'src/components/InfoModal';
import { Error } from 'src/types/error';
import { ExperimentalWarning } from 'src/components/ExperimentalWarning';
import { ServiceProvider, Services } from 'src/types/directory';
import { ConnectionStatusKind } from 'src/types';
-import { ConnectionButton } from 'src/components/ConnectionButton';
-import { PowerButton } from 'src/components/PowerButton';
+import { PowerButton } from 'src/components/PowerButton/PowerButton';
import { Box } from '@mui/system';
import { ConnectionLayout } from 'src/layouts/ConnectionLayout';
@@ -22,7 +20,7 @@ export const Disconnected: FCWithChildren<{
serviceProvider?: ServiceProvider;
clearError: () => void;
onConnectClick: (status: ConnectionStatusKind) => void;
-}> = ({ status, error, onConnectClick, clearError, serviceProvider }) => {
+}> = ({ status, error, onConnectClick, clearError }) => {
return (
<>
{error && }
@@ -33,7 +31,7 @@ export const Disconnected: FCWithChildren<{
}
- ConnectButton={}
+ ConnectButton={}
BottomContent={
{
if (context.connectionStatus === 'connected')
return (
= () => {
return (
{}}
gatewayPerformance="Good"
showInfoModal={false}
closeInfoModal={() => undefined}
diff --git a/nym-connect/src/stories/ConnectedLayout.stories.tsx b/nym-connect/src/stories/ConnectedLayout.stories.tsx
index b572d58490..f6d744f68c 100644
--- a/nym-connect/src/stories/ConnectedLayout.stories.tsx
+++ b/nym-connect/src/stories/ConnectedLayout.stories.tsx
@@ -15,6 +15,7 @@ export default {
export const Default: ComponentStory = () => (
{}}
gatewayPerformance="Good"
showInfoModal={false}
closeInfoModal={() => {
diff --git a/nym-connect/src/stories/PowerButton.stories.tsx b/nym-connect/src/stories/PowerButton.stories.tsx
index 97681cc974..6cb2896849 100644
--- a/nym-connect/src/stories/PowerButton.stories.tsx
+++ b/nym-connect/src/stories/PowerButton.stories.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import { ComponentMeta, ComponentStory } from '@storybook/react';
-import { PowerButton } from 'src/components/PowerButton';
+import { PowerButton } from 'src/components/PowerButton/PowerButton';
import { ConnectionStatusKind } from 'src/types';
export default {
@@ -13,7 +13,7 @@ export const Disconnected: ComponentStory = () => (
);
export const Connecting: ComponentStory = () => (
-
+
);
export const Connected: ComponentStory = () => (
@@ -21,9 +21,9 @@ export const Connected: ComponentStory = () => (
);
export const Disconnecting: ComponentStory = () => (
-
+
);
export const Disabled: ComponentStory = () => (
-
+
);