diff --git a/nym-connect/src/App.tsx b/nym-connect/src/App.tsx index 9d5afd1427..86efd95ba2 100644 --- a/nym-connect/src/App.tsx +++ b/nym-connect/src/App.tsx @@ -74,6 +74,7 @@ export const App: React.FC = () => { onConnectClick={handleConnectClick} ipAddress="127.0.0.1" port={1080} + gatewayPerformance={context.gatewayPerformance} connectedSince={context.connectedSince} serviceProvider={context.serviceProvider} stats={[ diff --git a/nym-connect/src/components/ConnectionStatus.tsx b/nym-connect/src/components/ConnectionStatus.tsx index c2f9add9ad..7514898496 100644 --- a/nym-connect/src/components/ConnectionStatus.tsx +++ b/nym-connect/src/components/ConnectionStatus.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Box, CircularProgress, Divider, Stack, Tooltip, Typography } from '@mui/material'; import { DateTime } from 'luxon'; -import { ConnectionStatusKind } from '../types'; +import { ConnectionStatusKind, GatewayPerformance } from '../types'; import { ServiceProvider } from '../types/directory'; import { ServiceProviderInfo } from './ServiceProviderInfo'; @@ -58,9 +58,10 @@ const ConnectionStatusContent: React.FC<{ export const ConnectionStatus: React.FC<{ status: ConnectionStatusKind; + gatewayPerformance?: GatewayPerformance; connectedSince?: DateTime; serviceProvider?: ServiceProvider; -}> = ({ status, serviceProvider }) => { +}> = ({ status, serviceProvider, gatewayPerformance }) => { const color = status === ConnectionStatusKind.connected || status === ConnectionStatusKind.disconnecting ? '#21D072' @@ -69,7 +70,13 @@ export const ConnectionStatus: React.FC<{ return ( <> - + {status === ConnectionStatusKind.connected && gatewayPerformance !== 'Good' ? ( + + Gateway has issues + + ) : ( + + )} {serviceProvider ? ( }> diff --git a/nym-connect/src/context/main.tsx b/nym-connect/src/context/main.tsx index 3258978ff8..e00d353e24 100644 --- a/nym-connect/src/context/main.tsx +++ b/nym-connect/src/context/main.tsx @@ -1,15 +1,15 @@ -import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react'; +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 { ConnectionStatusKind, GatewayPerformance } from '../types'; +import { ConnectionStatsItem } from '../components/ConnectionStats'; +import { ServiceProvider, Services } from '../types/directory'; import { Error } from 'src/types/error'; import { TauriEvent } from 'src/types/event'; import { getVersion } from '@tauri-apps/api/app'; -import { ConnectionStatusKind } from '../types'; -import { ConnectionStatsItem } from '../components/ConnectionStats'; -import { ServiceProvider, Services } from '../types/directory'; const TAURI_EVENT_STATUS_CHANGED = 'app:connection-status-changed'; @@ -25,7 +25,7 @@ export type TClientContext = { serviceProvider?: ServiceProvider; showHelp: boolean; error?: Error; - + gatewayPerformance: GatewayPerformance; setMode: (mode: ModeType) => void; clearError: () => void; handleShowHelp: () => void; @@ -50,6 +50,7 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode const [showHelp, setShowHelp] = useState(false); const [error, setError] = useState(); const [appVersion, setAppVersion] = useState(); + const [gatewayPerformance, setGatewayPerformance] = useState('Good'); const getAppVersion = async () => { const version = await getVersion(); @@ -93,6 +94,16 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode unlisten.push(result); }); + listen('socks5-status-event', (e: TauriEvent) => { + if (e.payload.message.includes('slow')) { + setGatewayPerformance('Poor'); + } else { + setGatewayPerformance('Good'); + } + }).then((result) => { + unlisten.push(result); + }); + return () => { unlisten.forEach((unsubscribe) => unsubscribe()); }; @@ -110,6 +121,7 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode const startDisconnecting = useCallback(async () => { try { await invoke('start_disconnecting'); + setGatewayPerformance('Good'); } catch (e) { console.log(e); } @@ -167,6 +179,20 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode getSpFromStorage(); }, []); + const timerId = useRef(); + + useEffect(() => { + if (timerId.current) { + clearTimeout(timerId.current); + } + + if (gatewayPerformance !== 'Good') { + timerId.current = setTimeout(() => { + setGatewayPerformance('Good'); + }, 15000); + } + }, [gatewayPerformance]); + const contextValue = useMemo( () => ({ mode, @@ -187,6 +213,7 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode setServiceProvider, showHelp, handleShowHelp, + gatewayPerformance, }), [ appVersion, @@ -200,6 +227,7 @@ export const ClientContextProvider = ({ children }: { children: React.ReactNode connectedSince, services, serviceProvider, + gatewayPerformance, ], ); diff --git a/nym-connect/src/context/mocks/main.tsx b/nym-connect/src/context/mocks/main.tsx index 9b09b6dc71..c6c1c033f4 100644 --- a/nym-connect/src/context/mocks/main.tsx +++ b/nym-connect/src/context/mocks/main.tsx @@ -9,6 +9,7 @@ const mockValues: TClientContext = { services: [], showHelp: false, serviceProvider: { id: '1', description: 'Keybase service provider', gateway: 'abc123', address: '123abc' }, + gatewayPerformance: 'Good', setMode: () => {}, clearError: () => {}, handleShowHelp: () => {}, diff --git a/nym-connect/src/layouts/ConnectedLayout.tsx b/nym-connect/src/layouts/ConnectedLayout.tsx index 9cf37b9f12..d2ea86228b 100644 --- a/nym-connect/src/layouts/ConnectedLayout.tsx +++ b/nym-connect/src/layouts/ConnectedLayout.tsx @@ -4,7 +4,7 @@ import { DateTime } from 'luxon'; import { IpAddressAndPortModal } from 'src/components/IpAddressAndPortModal'; import { ConnectionTimer } from 'src/components/ConntectionTimer'; import { ConnectionStatus } from '../components/ConnectionStatus'; -import { ConnectionStatusKind } from '../types'; +import { ConnectionStatusKind, GatewayPerformance } from '../types'; import { ConnectionStatsItem } from '../components/ConnectionStats'; import { ConnectionButton } from '../components/ConnectionButton'; import { IpAddressAndPort } from '../components/IpAddressAndPort'; @@ -13,6 +13,7 @@ import { TestAndEarnButtonArea } from '../components/Growth/TestAndEarnButtonAre export const ConnectedLayout: React.FC<{ status: ConnectionStatusKind; + gatewayPerformance: GatewayPerformance; stats: ConnectionStatsItem[]; ipAddress: string; port: number; @@ -25,6 +26,7 @@ export const ConnectedLayout: React.FC<{ serviceProvider?: ServiceProvider; }> = ({ status, + gatewayPerformance, showInfoModal, handleCloseInfoModal, ipAddress, @@ -37,8 +39,12 @@ export const ConnectedLayout: React.FC<{ }) => ( <> - - + + diff --git a/nym-connect/src/stories/AppFlow.stories.tsx b/nym-connect/src/stories/AppFlow.stories.tsx index 7055288f63..248334d0c8 100644 --- a/nym-connect/src/stories/AppFlow.stories.tsx +++ b/nym-connect/src/stories/AppFlow.stories.tsx @@ -86,32 +86,33 @@ export const Mock: ComponentStory = () => { } return ( - - - undefined} - status={context.connectionStatus} - busy={busy} - onConnectClick={handleConnectClick} - ipAddress="127.0.0.1" - port={1080} - connectedSince={context.connectedSince} - serviceProvider={services[0].items[0]} - stats={[ - { - label: 'in:', - totalBytes: 1024, - rateBytesPerSecond: 1024 * 1024 * 1024 + 10, - }, - { - label: 'out:', - totalBytes: 1024 * 1024 * 1024 * 1024 * 20, - rateBytesPerSecond: 1024 * 1024 + 10, - }, - ]} - /> - - + + { + return undefined; + }} + status={context.connectionStatus} + busy={busy} + onConnectClick={handleConnectClick} + ipAddress="127.0.0.1" + port={1080} + connectedSince={context.connectedSince} + serviceProvider={services[0].items[0]} + 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/stories/ConnectedLayout.stories.tsx b/nym-connect/src/stories/ConnectedLayout.stories.tsx index 53538457bf..4d79900340 100644 --- a/nym-connect/src/stories/ConnectedLayout.stories.tsx +++ b/nym-connect/src/stories/ConnectedLayout.stories.tsx @@ -14,6 +14,7 @@ export const Default: ComponentStory = () => ( { return undefined; }} diff --git a/nym-connect/src/stories/ConnectionStatus.stories.tsx b/nym-connect/src/stories/ConnectionStatus.stories.tsx index 10eb4d61ac..d98e262374 100644 --- a/nym-connect/src/stories/ConnectionStatus.stories.tsx +++ b/nym-connect/src/stories/ConnectionStatus.stories.tsx @@ -10,17 +10,17 @@ export default { } as ComponentMeta; export const Disconnected: ComponentStory = () => ( - + ); export const Connecting: ComponentStory = () => ( - + ); export const Connected: ComponentStory = () => ( - + ); export const Disconnecting: ComponentStory = () => ( - + ); diff --git a/nym-connect/src/types/connection.ts b/nym-connect/src/types/connection.ts index f5665b58ea..8fb5234477 100644 --- a/nym-connect/src/types/connection.ts +++ b/nym-connect/src/types/connection.ts @@ -4,3 +4,5 @@ export enum ConnectionStatusKind { connected = 'connected', connecting = 'connecting', } + +export type GatewayPerformance = 'Good' | 'Poor' | 'VeryPoor';