diff --git a/src/pages/Connections.tsx b/src/pages/Connections.tsx index a884024..5c5c4b2 100644 --- a/src/pages/Connections.tsx +++ b/src/pages/Connections.tsx @@ -42,11 +42,6 @@ import { } from '~/signals' import type { Connection } from '~/types' -type ConnectionWithSpeed = Connection & { - downloadSpeed: number - uploadSpeed: number -} - type ColumnVisibility = Partial> type ColumnOrder = CONNECTIONS_TABLE_ACCESSOR_KEY[] @@ -61,12 +56,8 @@ export default () => { const [search, setSearch] = createSignal('') const [activeTab, setActiveTab] = createSignal(ActiveTab.activeConnections) - const { - activeConnectionsWithSpeed, - closedConnectionsWithSpeed, - paused, - setPaused, - } = useConnections() + const { activeConnections, closedConnections, paused, setPaused } = + useConnections() const onCloseConnection = (id: string) => request.delete(`connections/${id}`) const [columnVisibility, setColumnVisibility] = makePersisted( @@ -84,7 +75,7 @@ export default () => { }, ) - const columns = createMemo[]>(() => [ + const columns = createMemo[]>(() => [ { header: () => t('close'), enableGrouping: false, @@ -229,8 +220,8 @@ export default () => { }, get data() { return activeTab() === ActiveTab.activeConnections - ? activeConnectionsWithSpeed() - : closedConnectionsWithSpeed() + ? activeConnections() + : closedConnections() }, sortDescFirst: true, enableHiding: true, @@ -249,12 +240,12 @@ export default () => { { type: ActiveTab.activeConnections, name: t('activeConnections'), - count: activeConnectionsWithSpeed().length, + count: activeConnections().length, }, { type: ActiveTab.closedConnections, name: t('closedConnections'), - count: closedConnectionsWithSpeed().length, + count: closedConnections().length, }, ]) diff --git a/src/pages/Overview.tsx b/src/pages/Overview.tsx index 148c556..cc72f4a 100644 --- a/src/pages/Overview.tsx +++ b/src/pages/Overview.tsx @@ -13,7 +13,7 @@ import { createSignal, } from 'solid-js' import { CHART_MAX_XAXIS, DEFAULT_CHART_OPTIONS } from '~/constants' -import { connections, useWsRequest } from '~/signals' +import { latestConnectionMsg, useWsRequest } from '~/signals' const TrafficWidget: ParentComponent<{ label: JSX.Element }> = (props) => (
@@ -95,15 +95,15 @@ export default () => { - {byteSize(connections()?.uploadTotal || 0).toString()} + {byteSize(latestConnectionMsg()?.uploadTotal || 0).toString()} - {byteSize(connections()?.downloadTotal || 0).toString()} + {byteSize(latestConnectionMsg()?.downloadTotal || 0).toString()} - {connections()?.connections.length || 0} + {latestConnectionMsg()?.connections.length || 0} diff --git a/src/signals/connections.ts b/src/signals/connections.ts index aafd626..e8e4699 100644 --- a/src/signals/connections.ts +++ b/src/signals/connections.ts @@ -1,10 +1,10 @@ -import { differenceWith, unionWith } from 'lodash' +import { differenceWith, isNumber, unionWith } from 'lodash' import { Accessor, createEffect, createSignal, untrack } from 'solid-js' -import { Connection, ConnectionWithSpeed } from '~/types' +import { Connection, ConnectionRawMessage } from '~/types' import { selectedEndpoint, useWsRequest } from './request' type WsMsg = { - connections: Connection[] + connections: ConnectionRawMessage[] uploadTotal: number downloadTotal: number } | null @@ -12,11 +12,9 @@ type WsMsg = { // we make connections global, so we can keep track of connections when user in proxy page // when user selects proxy and close some connections they can back and check connections // they closed -const [allConnectionsWithSpeed, setAllConnectionsWithSpeed] = createSignal< - ConnectionWithSpeed[] ->([]) +const [allConnections, setAllConnections] = createSignal([]) -export let connections: Accessor = () => ({ +export let latestConnectionMsg: Accessor = () => ({ uploadTotal: 0, downloadTotal: 0, connections: [], @@ -24,82 +22,86 @@ export let connections: Accessor = () => ({ createEffect(() => { if (selectedEndpoint()) { - connections = useWsRequest('connections') + setAllConnections([]) + latestConnectionMsg = useWsRequest('connections') } }) export const useConnections = () => { - const [closedConnectionsWithSpeed, setClosedConnectionsWithSpeed] = - createSignal([]) - const [activeConnectionsWithSpeed, setActiveConnectionsWithSpeed] = - createSignal([]) + const [closedConnections, setClosedConnections] = createSignal( + [], + ) + const [activeConnections, setActiveConnections] = createSignal( + [], + ) const [paused, setPaused] = createSignal(false) - const updateConnectionsWithSpeed = (connections: Connection[]) => { - const prevActiveConnections = activeConnectionsWithSpeed() - const prevMap = new Map() - prevActiveConnections.forEach((prev) => prevMap.set(prev.id, prev)) - - const activeConnections: ConnectionWithSpeed[] = connections.map( - (connection) => { - const prevConn = prevMap.get(connection.id) - - if (!prevConn) { - return { ...connection, downloadSpeed: 0, uploadSpeed: 0 } - } - - return { - ...connection, - downloadSpeed: - connection.download - (prevConn.download ?? connection.download), - uploadSpeed: - connection.upload - (prevConn.upload ?? connection.upload), - } - }, - ) - - const allConnections = unionWith( - allConnectionsWithSpeed(), - activeConnections, - (a, b) => a.id === b.id, - ) - const closedConnections = differenceWith( - allConnections, - activeConnections, - (a, b) => a.id === b.id, - ) - - return { - activeConns: activeConnections.slice(-200), - closedConns: closedConnections.slice(-200), - allConns: allConnections.slice(-400), - } - } - createEffect(() => { - const connection = connections()?.connections + const rawConns = latestConnectionMsg()?.connections - if (!connection) { + if (!rawConns) { return } untrack(() => { - const { activeConns, closedConns, allConns } = - updateConnectionsWithSpeed(connection) + const activeConns = restructRawMsgToConnection( + rawConns, + activeConnections(), + ) + const allConns = mergeAllConnections(activeConns) if (!paused()) { - setActiveConnectionsWithSpeed(activeConns) - setClosedConnectionsWithSpeed(closedConns) + const closedConns = diffClosedConnections(activeConns, allConns) + + setActiveConnections(activeConns) + setClosedConnections(closedConns) } - setAllConnectionsWithSpeed(allConns) + setAllConnections(allConns) }) }) return { - closedConnectionsWithSpeed, - activeConnectionsWithSpeed, + closedConnections, + activeConnections, paused, setPaused, } } + +function restructRawMsgToConnection( + connections: ConnectionRawMessage[], + prevActiveConnections: Connection[], +): Connection[] { + const prevMap = new Map() + prevActiveConnections.forEach((prev) => prevMap.set(prev.id, prev)) + + return connections.map((connection) => { + const prevConn = prevMap.get(connection.id) + + if ( + !prevConn || + !isNumber(prevConn.download) || + !isNumber(prevConn.upload) + ) { + return { ...connection, downloadSpeed: 0, uploadSpeed: 0 } + } + + return { + ...connection, + downloadSpeed: connection.download - prevConn.download, + uploadSpeed: connection.upload - prevConn.upload, + } + }) +} + +function mergeAllConnections(activeConns: Connection[]) { + return unionWith(allConnections(), activeConns, (a, b) => a.id === b.id) +} + +function diffClosedConnections( + activeConns: Connection[], + allConns: Connection[], +) { + return differenceWith(allConns, activeConns, (a, b) => a.id === b.id) +} diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 24fac7f..8e6797b 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -69,7 +69,7 @@ export type RuleProvider = { vehicleType: string } -export type Connection = { +export type ConnectionRawMessage = { id: string download: number upload: number @@ -100,7 +100,7 @@ export type Connection = { } } -export type ConnectionWithSpeed = Connection & { +export type Connection = ConnectionRawMessage & { downloadSpeed: number uploadSpeed: number }