Skip to content

Commit ecb7d60

Browse files
committed
feat(utils): extract typeUsesRemotePort
1 parent e9950b9 commit ecb7d60

4 files changed

Lines changed: 88 additions & 80 deletions

File tree

packages/core/src/bridge/handlers/decorators.ts

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44
*/
55

66
import type { CommandHandler, CommandResult } from '../../runtime'
7-
import { ProxyType } from '@frp-bridge/types'
87
import { ModeError, ValidationError } from '../../errors'
8+
import { typeUsesRemotePort } from '../../utils'
9+
10+
// Error code type for type-safe error handling
11+
export type ErrorCode = 'VALIDATION_ERROR' | 'MODE_ERROR' | 'RUNTIME_ERROR' | 'UNKNOWN_ERROR' | 'RPC_NOT_AVAILABLE' | 'PORT_CONFLICT'
912

1013
/**
1114
* 验证结果
@@ -173,7 +176,7 @@ function handleError(error: unknown): CommandResult {
173176
return {
174177
status: 'failed',
175178
error: {
176-
code: error.code as any,
179+
code: error.code as ErrorCode,
177180
message: error.message
178181
}
179182
}
@@ -183,7 +186,7 @@ function handleError(error: unknown): CommandResult {
183186
return {
184187
status: 'failed',
185188
error: {
186-
code: error.code as any,
189+
code: error.code as ErrorCode,
187190
message: error.message
188191
}
189192
}
@@ -193,7 +196,7 @@ function handleError(error: unknown): CommandResult {
193196
return {
194197
status: 'failed',
195198
error: {
196-
code: 'RUNTIME_ERROR' as any,
199+
code: 'RUNTIME_ERROR',
197200
message: error.message
198201
}
199202
}
@@ -202,7 +205,7 @@ function handleError(error: unknown): CommandResult {
202205
return {
203206
status: 'failed',
204207
error: {
205-
code: 'UNKNOWN_ERROR' as any,
208+
code: 'UNKNOWN_ERROR',
206209
message: 'An unknown error occurred'
207210
}
208211
}
@@ -237,7 +240,7 @@ export const Validators = {
237240
* 验证数字字段
238241
*/
239242
number: <T>(field: keyof T, min?: number, max?: number): Validator<T> => (payload) => {
240-
const value = (payload as any)[field]
243+
const value = (payload as Record<string, unknown>)[String(field)] as number
241244
if (typeof value !== 'number') {
242245
return { valid: false, error: `${String(field)} must be a number` }
243246
}
@@ -264,20 +267,6 @@ export const Validators = {
264267
}
265268
}
266269

267-
/**
268-
* 检查代理类型是否使用 remotePort
269-
*/
270-
function typeUsesRemotePort(type: string): boolean {
271-
return [
272-
ProxyType.TCP,
273-
ProxyType.UDP,
274-
ProxyType.STCP,
275-
ProxyType.XTCP,
276-
ProxyType.SUDP,
277-
ProxyType.TCPMUX
278-
].includes(type as ProxyType)
279-
}
280-
281270
/**
282271
* 模式路由装饰器
283272
* Server 模式:通过 RPC 转发到节点
@@ -286,7 +275,7 @@ function typeUsesRemotePort(type: string): boolean {
286275
export function withModeRouting<T extends { nodeId?: string }>(
287276
localHandler: (payload: T, deps: CommandDependencies) => Promise<CommandResult>,
288277
rpcMethod: string,
289-
transformPayload?: (payload: T) => any
278+
transformPayload?: (payload: T) => Record<string, unknown>
290279
): (handler: CommandHandler<T>, deps: CommandDependencies) => CommandHandler<T> {
291280
return (_handler, deps) => {
292281
return async (command, _ctx) => {
@@ -343,13 +332,18 @@ export function withModeRouting<T extends { nodeId?: string }>(
343332
* 端口冲突检查装饰器
344333
* 检查远程端口是否已在所有节点上被使用
345334
*/
346-
export function withPortConflictCheck<T extends { proxy?: { remotePort?: number, type?: string }, nodeId?: string }>(
347-
handler: CommandHandler<T>,
348-
deps: CommandDependencies
349-
): CommandHandler<T> {
335+
export function withPortConflictCheck<
336+
T extends {
337+
proxy?: {
338+
remotePort?: number
339+
type?: string
340+
}
341+
nodeId?: string
342+
}
343+
>(handler: CommandHandler<T>, deps: CommandDependencies): CommandHandler<T> {
350344
return async (command, ctx) => {
351345
const payload = command.payload as T
352-
const proxy = payload.proxy as any
346+
const proxy = payload.proxy
353347

354348
if (proxy?.remotePort && proxy?.type && typeUsesRemotePort(proxy.type)) {
355349
const portCheck = deps.nodeManager?.isRemotePortInUse(proxy.remotePort, payload.nodeId)

packages/core/src/process/controllers/tunnel-manager.ts

Lines changed: 25 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import type { ProxyConfig } from '@frp-bridge/types'
77
import type { RuntimeLogger } from '../../runtime'
88
import type { ConfigurationStore, FrpConfig } from './configuration-store'
9-
import { ProxyType } from '@frp-bridge/types'
109
import { ConfigInvalidError, NotFoundError } from '../../errors'
1110
import { createLogger } from '../../logging'
11+
import { typeUsesRemotePort } from '../../utils'
1212

1313
/**
1414
* Extended config type that includes proxies array
@@ -82,15 +82,15 @@ export class TunnelManager {
8282

8383
// Handle [[proxies]] array syntax
8484
if (Array.isArray(config.proxies)) {
85-
const tunnel = config.proxies.find((p: any) => p && p.name === name) as ProxyConfig || null
85+
const tunnel = config.proxies.find(p => p && p.name === name) || null
8686
if (!tunnel) {
8787
this.log.debug('Tunnel not found in proxies array', { name })
8888
}
8989
return tunnel
9090
}
9191

9292
// Handle legacy format
93-
return (config as any)[name] as ProxyConfig || null
93+
return (config as Record<string, unknown>)[name] as ProxyConfig || null
9494
}
9595

9696
/**
@@ -104,7 +104,7 @@ export class TunnelManager {
104104

105105
// Handle [[proxies]] array syntax
106106
if (Array.isArray(config.proxies)) {
107-
const tunnelIndex = config.proxies.findIndex((p: any) => p && p.name === name)
107+
const tunnelIndex = config.proxies.findIndex(p => p && p.name === name)
108108
if (tunnelIndex === -1) {
109109
throw new NotFoundError(`Tunnel ${name} not found`)
110110
}
@@ -113,16 +113,17 @@ export class TunnelManager {
113113
const updatedTunnel = { ...existingTunnel, ...proxy }
114114

115115
// Check remotePort conflict if changed
116-
const newRemotePort = (proxy as any).remotePort
117-
if (newRemotePort && newRemotePort !== (existingTunnel as any).remotePort) {
118-
this.validateRemotePort(config.proxies, newRemotePort, (updatedTunnel as any).type, tunnelIndex)
116+
const newRemotePort = proxy.remotePort
117+
if (newRemotePort && newRemotePort !== existingTunnel.remotePort) {
118+
this.validateRemotePort(config.proxies, newRemotePort, updatedTunnel.type, tunnelIndex)
119119
}
120120

121121
config.proxies[tunnelIndex] = updatedTunnel
122122
}
123123
// Handle legacy format
124-
else if ((config as any)[name]) {
125-
;(config as any)[name] = { ...(config as any)[name], ...proxy }
124+
else if ((config as Record<string, unknown>)[name]) {
125+
const existing = (config as Record<string, unknown>)[name] as ProxyConfig
126+
;(config as Record<string, unknown>)[name] = { ...existing, ...proxy }
126127
}
127128
else {
128129
throw new NotFoundError(`Tunnel ${name} not found`)
@@ -147,7 +148,7 @@ export class TunnelManager {
147148

148149
// Handle [[proxies]] array syntax
149150
if (Array.isArray(config.proxies)) {
150-
const tunnelIndex = config.proxies.findIndex((p: any) => p && p.name === name)
151+
const tunnelIndex = config.proxies.findIndex(p => p && p.name === name)
151152
if (tunnelIndex !== -1) {
152153
config.proxies.splice(tunnelIndex, 1)
153154
modified = true
@@ -158,8 +159,8 @@ export class TunnelManager {
158159
}
159160
}
160161
// Handle legacy format
161-
else if ((config as any)[name]) {
162-
delete (config as any)[name]
162+
else if ((config as Record<string, unknown>)[name]) {
163+
delete (config as Record<string, unknown>)[name]
163164
modified = true
164165
this.log.success('Tunnel removed', { name })
165166
}
@@ -194,12 +195,12 @@ export class TunnelManager {
194195
}
195196

196197
// Handle legacy format
197-
const proxyKeys = new Set(tunnels.map((t: any) => t.name))
198+
const proxyKeys = new Set(tunnels.map(t => t.name))
198199
for (const [key, value] of Object.entries(config)) {
199200
if (key === 'proxies')
200201
continue
201202
if (typeof value === 'object' && value !== null && 'type' in value && !Array.isArray(value)) {
202-
const proxy = { ...value, name: (value as any).name || key } as ProxyConfig
203+
const proxy = { ...value, name: ((value as ProxyConfig).name) || key } as ProxyConfig
203204
if (!proxyKeys.has(proxy.name)) {
204205
tunnels.push(proxy)
205206
proxyKeys.add(proxy.name)
@@ -257,19 +258,19 @@ export class TunnelManager {
257258
/**
258259
* Validate tunnel uniqueness
259260
*/
260-
private validateUniqueness(config: any, proxy: ProxyConfig): void {
261-
const proxies = config.proxies || []
261+
private validateUniqueness(config: Record<string, unknown>, proxy: ProxyConfig): void {
262+
const proxies = (config.proxies as ProxyConfig[]) || []
262263

263264
// Check name uniqueness
264-
const existingName = proxies.find((p: any) => p && p.name === proxy.name)
265+
const existingName = proxies.find(p => p && p.name === proxy.name)
265266
if (existingName) {
266267
this.log.warn('Tunnel name already exists', { name: proxy.name })
267268
throw new ConfigInvalidError(`Tunnel ${proxy.name} already exists`)
268269
}
269270

270271
// Check remotePort conflict for types that use it
271-
const proxyRemotePort = (proxy as any).remotePort
272-
if (proxyRemotePort && this.typeUsesRemotePort(proxy.type)) {
272+
const proxyRemotePort = proxy.remotePort
273+
if (proxyRemotePort && typeUsesRemotePort(proxy.type)) {
273274
this.validateRemotePort(proxies, proxyRemotePort, proxy.type)
274275
}
275276

@@ -279,16 +280,16 @@ export class TunnelManager {
279280
/**
280281
* Validate remotePort conflict
281282
*/
282-
private validateRemotePort(proxies: any[], remotePort: number, type: string, excludeIndex = -1): void {
283-
if (!this.typeUsesRemotePort(type)) {
283+
private validateRemotePort(proxies: ProxyConfig[], remotePort: number, type: string, excludeIndex = -1): void {
284+
if (!typeUsesRemotePort(type)) {
284285
return
285286
}
286287

287-
const inUse = proxies.some((p: any, idx: number) => {
288+
const inUse = proxies.some((p, idx) => {
288289
if (idx === excludeIndex)
289290
return false
290-
const pRemotePort = (p as any).remotePort
291-
return p && pRemotePort === remotePort && this.typeUsesRemotePort(p.type)
291+
const pRemotePort = p.remotePort
292+
return p && pRemotePort === remotePort && typeUsesRemotePort(p.type)
292293
})
293294

294295
if (inUse) {
@@ -298,18 +299,4 @@ export class TunnelManager {
298299

299300
this.log.debug('Remote port validation passed', { remotePort, type })
300301
}
301-
302-
/**
303-
* Check if proxy type uses remotePort
304-
*/
305-
private typeUsesRemotePort(type: string): boolean {
306-
return [
307-
ProxyType.TCP,
308-
ProxyType.UDP,
309-
ProxyType.STCP,
310-
ProxyType.XTCP,
311-
ProxyType.SUDP,
312-
ProxyType.TCPMUX
313-
].includes(type as ProxyType)
314-
}
315302
}

0 commit comments

Comments
 (0)