metacubexd/src/signals/connections.ts

134 lines
3.4 KiB
TypeScript
Raw Normal View History

import { makePersisted } from '@solid-primitives/storage'
2023-09-08 13:39:51 +08:00
import { differenceWith, isNumber, unionWith } from 'lodash'
import { CONNECTIONS_TABLE_MAX_CLOSED_ROWS } from '~/constants'
2023-09-08 13:39:51 +08:00
import { Connection, ConnectionRawMessage } from '~/types'
2023-09-08 18:42:15 +08:00
export type WsMsg = {
connections?: ConnectionRawMessage[]
uploadTotal: number
downloadTotal: number
} | null
// DIRECT is from clash
// direct and dns-out is from the example of sing-box official site
export const [quickFilterRegex, setQuickFilterRegex] = makePersisted(
createSignal<string>('DIRECT|direct|dns-out'),
{
name: 'quickFilterRegex',
storage: localStorage,
},
)
2023-09-08 11:55:22 +08:00
// 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
export const [allConnections, setAllConnections] = createSignal<Connection[]>(
[],
)
export const [latestConnectionMsg, setLatestConnectionMsg] =
createSignal<WsMsg>(null)
export const useConnections = () => {
2023-09-08 13:39:51 +08:00
const [closedConnections, setClosedConnections] = createSignal<Connection[]>(
[],
)
const [activeConnections, setActiveConnections] = createSignal<Connection[]>(
[],
)
const [paused, setPaused] = createSignal(false)
createEffect(() => {
2023-09-08 13:39:51 +08:00
const rawConns = latestConnectionMsg()?.connections
2023-09-08 13:39:51 +08:00
if (!rawConns) {
return
}
untrack(() => {
2023-09-08 13:39:51 +08:00
const activeConns = restructRawMsgToConnection(
rawConns,
activeConnections(),
)
2023-09-17 14:55:03 +08:00
mergeAllConnections(activeConnections())
if (!paused()) {
2023-09-17 14:55:03 +08:00
const closedConns = diffClosedConnections(activeConns, allConnections())
2023-09-08 13:39:51 +08:00
setActiveConnections(activeConns)
setClosedConnections(
closedConns.slice(-CONNECTIONS_TABLE_MAX_CLOSED_ROWS),
)
}
2023-09-17 14:55:03 +08:00
setAllConnections((allConnections) =>
allConnections.slice(
-(activeConns.length + CONNECTIONS_TABLE_MAX_CLOSED_ROWS),
),
)
})
})
const speedGroupByName = createMemo(() => {
const returnMap: Record<string, number> = {}
activeConnections().forEach((c) => {
c.chains.forEach((chain) => {
if (!returnMap[chain]) {
returnMap[chain] = 0
}
returnMap[chain] += c.downloadSpeed
})
})
return returnMap
})
return {
2023-09-08 13:39:51 +08:00
closedConnections,
activeConnections,
speedGroupByName,
paused,
setPaused,
}
}
2023-09-08 13:39:51 +08:00
2023-09-08 17:09:32 +08:00
export const restructRawMsgToConnection = (
2023-09-08 13:39:51 +08:00
connections: ConnectionRawMessage[],
prevActiveConnections: Connection[],
2023-09-08 17:09:32 +08:00
): Connection[] => {
2023-09-08 13:39:51 +08:00
const prevMap = new Map<string, Connection>()
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,
}
})
}
2023-09-08 17:09:32 +08:00
export const mergeAllConnections = (activeConns: Connection[]) => {
2023-09-17 14:55:03 +08:00
setAllConnections((allConnections) =>
unionWith(allConnections, activeConns, (a, b) => a.id === b.id),
)
2023-09-08 13:39:51 +08:00
}
2023-09-08 17:09:32 +08:00
const diffClosedConnections = (
2023-09-08 13:39:51 +08:00
activeConns: Connection[],
allConns: Connection[],
2023-09-17 14:55:03 +08:00
) => differenceWith(allConns, activeConns, (a, b) => a.id === b.id)