feat(tsconnect-redux): add exit node suggestion and file targets to the ipn store

This commit is contained in:
2026-06-11 20:02:53 +00:00
parent f9becb6f24
commit a56199d5ae
3 changed files with 34 additions and 1 deletions
+11
View File
@@ -2,6 +2,8 @@ import type { IPN } from "@webnet/tsconnect"
import {
deleteWaitingFile,
setExitNode,
setExitNodeSuggestion,
setFileTargets,
setIncomingFiles,
setLoginUrl,
setNetmap,
@@ -38,6 +40,15 @@ export function runWithStore(ipn: IPN, store: IpnStore, params?: Parameters<IPN[
},
notifyNetMap: (netmap) => {
store.dispatch(setNetmap(netmap))
ipn
.suggestExitNode()
.then((suggested) => store.dispatch(setExitNodeSuggestion(suggested)))
.catch(() => void 0)
if (ipn.fileOps)
ipn
.listFileTargets()
.then((targets) => store.dispatch(setFileTargets(targets)))
.catch(() => void 0)
params?.notifyNetMap?.(netmap)
},
notifyOutgoingFiles: (files) => {
@@ -14,6 +14,7 @@ import {
selectPeers,
selectWaitingFiles,
} from "./store.js"
import { ExitNodeSuggestion } from "../../tsconnect/out/types.js"
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type IpnSelector<R, A extends any[] = []> = (state: IpnState, ...args: A) => R
@@ -24,6 +25,9 @@ export const getExitNode: IpnSelector<string | null> = (state) => selectIpnState
export const getIpnSelfNode: IpnSelector<IPNNetMapSelfNode | null> = (state) =>
selectIpnState(state).self
export const isIpnLockedOut: IpnSelector<boolean> = (state) => selectIpnState(state).lockedOut
export const getIpnSuggestedExitNode: IpnSelector<ExitNodeSuggestion | null> = (state) =>
selectIpnState(state).exitNodeSuggestion
export const getIpnFileTargets: IpnSelector<string[]> = (state) => selectIpnState(state).fileTargets
export const listOutgoingFiles: IpnSelector<string[]> = (state) => selectOutgoingFiles(state).ids
export const getOutgoingFiles: IpnSelector<Record<string, IPNOutgoingFile>> = (state) =>
+19 -1
View File
@@ -7,6 +7,7 @@ import {
type PayloadAction,
} from "@reduxjs/toolkit"
import type {
IPNFileTarget,
IPNIncomingFile,
IPNNetMap,
IPNNetMapPeerNode,
@@ -15,6 +16,7 @@ import type {
IPNState,
IPNWaitingFile,
} from "@webnet/tsconnect"
import { ExitNodeSuggestion } from "../../tsconnect/out/types"
export type IpnBaseState = {
state: IPNState
@@ -22,6 +24,8 @@ export type IpnBaseState = {
exitNode: string | null
self: IPNNetMapSelfNode | null
lockedOut: boolean
exitNodeSuggestion: ExitNodeSuggestion | null
fileTargets: string[]
}
const initialIpnState: IpnBaseState = {
@@ -30,6 +34,8 @@ const initialIpnState: IpnBaseState = {
exitNode: null,
self: null,
lockedOut: false,
exitNodeSuggestion: null,
fileTargets: [],
}
const outgoingFileAdapter = createEntityAdapter({
@@ -68,6 +74,18 @@ const stateSlice = createSlice({
if (payload === "Running") state.loginUrl = null
state.state = payload
},
setExitNodeSuggestion: (state, { payload }: PayloadAction<ExitNodeSuggestion>) => {
if (!state.exitNodeSuggestion || state.exitNodeSuggestion.id !== payload.id)
state.exitNodeSuggestion = payload
},
setFileTargets: (state, { payload }: PayloadAction<IPNFileTarget[]>) => {
const targets = payload.map((x) => x.stableNodeID).sort()
if (
state.fileTargets.length !== targets.length ||
state.fileTargets.some((x, i) => x !== targets[i])
)
state.fileTargets = targets
},
},
extraReducers(builder) {
builder.addCase(netmapAction, (state, { payload }) => {
@@ -194,7 +212,7 @@ export const buildIpnStore = () =>
export { netmapAction as setNetmap }
export const {
selectSlice: selectIpnState,
actions: { setExitNode, setLoginUrl, setState },
actions: { setExitNode, setLoginUrl, setState, setExitNodeSuggestion, setFileTargets },
} = stateSlice
export const {
selectSlice: selectOutgoingFiles,