@steve02081504/fount-p2p 0.0.11 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -11
- package/core/bytes_codec.mjs +65 -10
- package/core/composite_key.mjs +5 -5
- package/core/tcp_port.mjs +1 -1
- package/crypto/checkpoint_sign.mjs +2 -2
- package/crypto/crypto.mjs +3 -3
- package/crypto/key.mjs +12 -12
- package/dag/canonicalize_row.mjs +3 -3
- package/dag/index.mjs +2 -3
- package/dag/storage.mjs +36 -36
- package/discovery/advert_peer_hints.mjs +1 -1
- package/discovery/adverts.mjs +109 -0
- package/discovery/bt/index.mjs +154 -113
- package/discovery/bt/probe_child.mjs +2 -1
- package/discovery/bt/runtime.mjs +5 -12
- package/discovery/index.mjs +267 -62
- package/discovery/internal/signal_crypto.mjs +109 -0
- package/discovery/lan.mjs +228 -0
- package/discovery/nostr.mjs +430 -141
- package/federation/chunk_fetch_pending.mjs +14 -18
- package/federation/dag_order_cache.mjs +1 -1
- package/federation/entity_key_chain.mjs +3 -4
- package/federation/manifest_fetch_pending.mjs +1 -3
- package/federation/topo_order_memo.mjs +11 -4
- package/files/assemble.mjs +14 -14
- package/files/assemble_stream.mjs +6 -6
- package/files/chunk_fetch.mjs +2 -2
- package/files/chunk_responder.mjs +29 -20
- package/files/evfs.mjs +31 -30
- package/files/manifest_fetch.mjs +16 -3
- package/files/public_manifest.mjs +11 -11
- package/files/transfer_key_registry.mjs +2 -2
- package/index.mjs +86 -11
- package/infra/cli.mjs +62 -0
- package/infra/debug_log.mjs +56 -0
- package/infra/default_node_dir.mjs +22 -0
- package/infra/priority.mjs +56 -0
- package/infra/service.mjs +140 -0
- package/infra/tunables.json +5 -0
- package/link/channel_mux.mjs +10 -10
- package/link/frame.mjs +76 -131
- package/link/handshake.mjs +19 -20
- package/link/pipe.mjs +53 -79
- package/link/providers/ble_gatt.mjs +19 -31
- package/link/providers/lan_tcp.mjs +17 -32
- package/link/providers/link_id_pipe.mjs +46 -0
- package/link/providers/webrtc.mjs +42 -51
- package/link/rtc.mjs +24 -12
- package/mailbox/consumer_registry.mjs +2 -2
- package/mailbox/deliver_or_store.mjs +6 -6
- package/mailbox/wire.mjs +28 -24
- package/node/entity_store.mjs +6 -6
- package/node/identity.mjs +4 -4
- package/node/instance.mjs +46 -27
- package/node/local_data_revision.mjs +26 -0
- package/node/log.mjs +56 -0
- package/node/network.mjs +46 -14
- package/node/reputation_store.mjs +4 -4
- package/node/reputation_sync.mjs +318 -0
- package/node/routing_profile.mjs +21 -0
- package/node/signaling_config.mjs +30 -11
- package/overlay/index.mjs +35 -14
- package/package.json +13 -2
- package/rooms/scoped_link.mjs +17 -182
- package/schemas/discovery.mjs +1 -2
- package/schemas/federation_pull.mjs +2 -2
- package/schemas/part_query.mjs +1 -1
- package/schemas/remote_event.mjs +1 -1
- package/transport/advert_ingest.mjs +17 -0
- package/transport/group_link_set.mjs +165 -134
- package/transport/ice_servers.mjs +2 -2
- package/transport/link_registry.mjs +283 -124
- package/transport/mesh_keepalive.mjs +217 -0
- package/transport/node_scope.mjs +289 -0
- package/transport/offer_answer.mjs +48 -47
- package/transport/peer_pool.mjs +169 -78
- package/transport/remote_user_room.mjs +18 -23
- package/transport/rtc_connection_budget.mjs +18 -4
- package/transport/{rtc_mdns_filter.mjs → rtc_ice_local_hostname.mjs} +13 -13
- package/transport/runtime_bootstrap.mjs +172 -104
- package/transport/tunables.json +11 -0
- package/transport/tunables.mjs +18 -0
- package/transport/user_room.mjs +93 -161
- package/trust_graph/build.mjs +0 -2
- package/trust_graph/cache.mjs +12 -3
- package/trust_graph/registry.mjs +6 -6
- package/trust_graph/send.mjs +1 -4
- package/utils/async_mutex.mjs +4 -4
- package/utils/emit_safe.mjs +11 -0
- package/utils/json_io.mjs +12 -12
- package/utils/map_pool.mjs +5 -5
- package/utils/shuffle.mjs +13 -0
- package/utils/ttl_map.mjs +29 -4
- package/wire/ingress.mjs +1 -1
- package/wire/part_ingress.mjs +38 -36
- package/wire/part_invoke.mjs +4 -4
- package/wire/part_query.mjs +28 -23
- package/wire/part_query.tunables.json +6 -1
- package/wire/part_query_cache.mjs +1 -1
- package/wire/volatile_signature.mjs +1 -1
- package/discovery/mdns.mjs +0 -191
- package/transport/signal_crypto.mjs +0 -82
package/infra/cli.mjs
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { on_shutdown } from 'on-shutdown'
|
|
4
|
+
|
|
5
|
+
import { ensureNodeDefaults, getNodeHash } from '../node/identity.mjs'
|
|
6
|
+
import { initNode, setNodeLogger } from '../node/instance.mjs'
|
|
7
|
+
import { setConnectivityDebug } from '../node/log.mjs'
|
|
8
|
+
import { getLinkRegistry } from '../transport/link_registry.mjs'
|
|
9
|
+
|
|
10
|
+
import { resolveNodeDir } from './default_node_dir.mjs'
|
|
11
|
+
import { setInfraPriority, startInfra, stopInfra } from './service.mjs'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {string[]} argv - 命令行参数(不含 node 路径)
|
|
15
|
+
* @returns {{ nodeDir?: string, quiet?: boolean, useLocalReputation?: boolean, help?: boolean }} 解析结果
|
|
16
|
+
*/
|
|
17
|
+
function parseArgs(argv) {
|
|
18
|
+
/** @type {ReturnType<typeof parseArgs>} */
|
|
19
|
+
const out = {}
|
|
20
|
+
for (let i = 0; i < argv.length; i++) {
|
|
21
|
+
const arg = argv[i]
|
|
22
|
+
if (arg === '--help' || arg === '-h') out.help = true
|
|
23
|
+
else if (arg === '--quiet') out.quiet = true
|
|
24
|
+
else if (arg === '--use-local-reputation') out.useLocalReputation = true
|
|
25
|
+
else if (arg === '--node-dir') out.nodeDir = argv[++i]
|
|
26
|
+
}
|
|
27
|
+
return out
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** 打印 CLI 用法。 */
|
|
31
|
+
function printHelp() {
|
|
32
|
+
console.log(`Usage: fount-p2p [--node-dir PATH] [--use-local-reputation] [--quiet]
|
|
33
|
+
|
|
34
|
+
Public-good infra relay node (overlay + mailbox).
|
|
35
|
+
Connectivity debug logs on by default (Nostr/LAN/mesh/dial); --quiet silences.
|
|
36
|
+
Non-CLI shells: setConnectivityDebug(true).
|
|
37
|
+
Default data dir: Windows %LOCALAPPDATA%/fount-p2p/node, else ~/.local/share/fount-p2p/node`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const args = parseArgs(process.argv.slice(2))
|
|
41
|
+
if (args.help) {
|
|
42
|
+
printHelp()
|
|
43
|
+
process.exit(0)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const nodeDir = resolveNodeDir(args.nodeDir)
|
|
47
|
+
initNode({ nodeDir })
|
|
48
|
+
if (args.quiet) {
|
|
49
|
+
setNodeLogger(null)
|
|
50
|
+
setConnectivityDebug(false)
|
|
51
|
+
}
|
|
52
|
+
else
|
|
53
|
+
setConnectivityDebug(true)
|
|
54
|
+
ensureNodeDefaults()
|
|
55
|
+
const nodeHash = getNodeHash()
|
|
56
|
+
await getLinkRegistry().ensureRuntime()
|
|
57
|
+
if (args.useLocalReputation) setInfraPriority({ useLocalReputation: true })
|
|
58
|
+
await startInfra({ logger: args.quiet ? null : console })
|
|
59
|
+
|
|
60
|
+
console.log(`p2p infra running (nodeDir=${nodeDir} nodeHash=${nodeHash})`)
|
|
61
|
+
|
|
62
|
+
on_shutdown(stopInfra)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { getLinkRegistry } from '../transport/link_registry.mjs'
|
|
2
|
+
|
|
3
|
+
/** @type {Array<() => void>} */
|
|
4
|
+
const cleanups = []
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 挂载 registry link/overlay/node scope 调试日志。
|
|
8
|
+
* @param {{ info?: Function, warn?: Function, error?: Function, log?: Function } | null} logger - 日志输出目标,null 表示静默
|
|
9
|
+
* @returns {() => void} 取消 debug 监听的 dispose
|
|
10
|
+
*/
|
|
11
|
+
export function attachInfraDebugLog(logger) {
|
|
12
|
+
detachInfraDebugLog()
|
|
13
|
+
if (!logger) return () => { }
|
|
14
|
+
const registry = getLinkRegistry()
|
|
15
|
+
/**
|
|
16
|
+
* @param {'info' | 'warn' | 'error' | 'log'} level - 日志级别
|
|
17
|
+
* @param {string} message - 日志消息
|
|
18
|
+
* @param {object} [extra] - 附加字段
|
|
19
|
+
*/
|
|
20
|
+
const log = (level, message, extra) => {
|
|
21
|
+
logger?.[level]?.(message, extra)
|
|
22
|
+
}
|
|
23
|
+
cleanups.push(registry.onLinkUp((nodeHash, link) => {
|
|
24
|
+
log('info', 'p2p:infra link up', {
|
|
25
|
+
nodeHash,
|
|
26
|
+
providerId: link?.providerId,
|
|
27
|
+
level: link?.level,
|
|
28
|
+
})
|
|
29
|
+
}))
|
|
30
|
+
cleanups.push(registry.onLinkDown((nodeHash, reason) => {
|
|
31
|
+
log('info', 'p2p:infra link down', { nodeHash, reason })
|
|
32
|
+
}))
|
|
33
|
+
cleanups.push(registry.subscribeScope('overlay', (from, envelope) => {
|
|
34
|
+
log('info', 'p2p:infra overlay', {
|
|
35
|
+
from,
|
|
36
|
+
action: envelope?.action,
|
|
37
|
+
path: envelope?.payload?.path,
|
|
38
|
+
})
|
|
39
|
+
}))
|
|
40
|
+
cleanups.push(registry.subscribeScope('node', (from, envelope) => {
|
|
41
|
+
log('info', 'p2p:infra node', {
|
|
42
|
+
from,
|
|
43
|
+
action: envelope?.action,
|
|
44
|
+
})
|
|
45
|
+
}))
|
|
46
|
+
return detachInfraDebugLog
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 卸掉 infra debug 监听。
|
|
51
|
+
* @returns {void}
|
|
52
|
+
*/
|
|
53
|
+
export function detachInfraDebugLog() {
|
|
54
|
+
for (const cleanup of cleanups.splice(0))
|
|
55
|
+
try { cleanup() } catch { /* ignore */ }
|
|
56
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import os from 'node:os'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @returns {string} 平台默认 node 数据目录
|
|
6
|
+
*/
|
|
7
|
+
export function defaultNodeDir() {
|
|
8
|
+
if (process.platform === 'win32') {
|
|
9
|
+
const base = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local')
|
|
10
|
+
return path.join(base, 'fount-p2p', 'node')
|
|
11
|
+
}
|
|
12
|
+
return path.join(os.homedir(), '.local', 'share', 'fount-p2p', 'node')
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {string | undefined} override - CLI 或调用方覆盖
|
|
17
|
+
* @returns {string} 解析后的绝对 node 目录
|
|
18
|
+
*/
|
|
19
|
+
export function resolveNodeDir(override) {
|
|
20
|
+
const trimmed = String(override || '').trim()
|
|
21
|
+
return trimmed ? path.resolve(trimmed) : defaultNodeDir()
|
|
22
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { normalizeHex64 } from '../core/hexIds.mjs'
|
|
2
|
+
import { getReputationTable } from '../node/reputation_sync.mjs'
|
|
3
|
+
import { pickNodeScoreFromReputation } from '../reputation/pick_score.mjs'
|
|
4
|
+
import { getLinkRegistry } from '../transport/link_registry.mjs'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/** @type {{ useLocalReputation: boolean }} */
|
|
8
|
+
let priorityConfig = { useLocalReputation: false }
|
|
9
|
+
|
|
10
|
+
const PRIORITY_BOOST = 1000
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 配置 infra 路由加权(是否用本地 reputation)。
|
|
14
|
+
* @param {{ useLocalReputation?: boolean }} config - 是否用本地 reputation 加权路由
|
|
15
|
+
* @returns {void}
|
|
16
|
+
*/
|
|
17
|
+
export function setInfraPriority(config = {}) {
|
|
18
|
+
priorityConfig = {
|
|
19
|
+
useLocalReputation: Boolean(config.useLocalReputation),
|
|
20
|
+
}
|
|
21
|
+
applyPriorityToRegistry()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @returns {{ useLocalReputation: boolean }} 当前 priority 配置副本
|
|
26
|
+
*/
|
|
27
|
+
export function getInfraPriority() {
|
|
28
|
+
return { ...priorityConfig }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @returns {void}
|
|
33
|
+
*/
|
|
34
|
+
export function applyPriorityToRegistry() {
|
|
35
|
+
const registry = getLinkRegistry()
|
|
36
|
+
if (!priorityConfig.useLocalReputation) {
|
|
37
|
+
registry.setPriorityWeightFunction(null)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
registry.setPriorityWeightFunction(nodeHash => {
|
|
41
|
+
const score = pickNodeScoreFromReputation(
|
|
42
|
+
getReputationTable(),
|
|
43
|
+
normalizeHex64(nodeHash) || nodeHash,
|
|
44
|
+
)
|
|
45
|
+
return Math.floor(score * PRIORITY_BOOST)
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* stopInfra:卸 weight,并重置 priority 配置,避免再次 startInfra 幽灵恢复加权。
|
|
51
|
+
* @returns {void}
|
|
52
|
+
*/
|
|
53
|
+
export function clearInfraPriorityFromRegistry() {
|
|
54
|
+
priorityConfig = { useLocalReputation: false }
|
|
55
|
+
getLinkRegistry().setPriorityWeightFunction(null)
|
|
56
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
|
|
2
|
+
import { isNodeInitialized } from '../node/instance.mjs'
|
|
3
|
+
import { setOverlayRateGate, clearOverlayRateGate } from '../overlay/index.mjs'
|
|
4
|
+
import { getLinkRegistry } from '../transport/link_registry.mjs'
|
|
5
|
+
import { attachNodeScopeMailbox } from '../transport/node_scope.mjs'
|
|
6
|
+
|
|
7
|
+
import { attachInfraDebugLog, detachInfraDebugLog } from './debug_log.mjs'
|
|
8
|
+
import {
|
|
9
|
+
applyPriorityToRegistry,
|
|
10
|
+
clearInfraPriorityFromRegistry,
|
|
11
|
+
getInfraPriority,
|
|
12
|
+
setInfraPriority,
|
|
13
|
+
} from './priority.mjs'
|
|
14
|
+
import infraTunables from './tunables.json' with { type: 'json' }
|
|
15
|
+
|
|
16
|
+
/** @type {Map<string, { tokens: number, updatedAt: number }>} */
|
|
17
|
+
const overlayRateBuckets = new Map()
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Token bucket:桶容量 = burst,补充速率 = perMin/min。
|
|
21
|
+
* @param {Map<string, { tokens: number, updatedAt: number }>} buckets - 每 sender 桶状态
|
|
22
|
+
* @param {string} sender - 发送方 nodeHash
|
|
23
|
+
* @param {number} now - 当前时间戳(ms)
|
|
24
|
+
* @param {{ perMin: number, burst: number }} limits - 限速参数
|
|
25
|
+
* @returns {boolean} 是否允许本次 overlay 动作
|
|
26
|
+
*/
|
|
27
|
+
export function consumeOverlayRateToken(buckets, sender, now, limits) {
|
|
28
|
+
const perMin = Math.max(1, limits.perMin)
|
|
29
|
+
const burst = Math.max(1, limits.burst)
|
|
30
|
+
const refillPerMs = perMin / 60_000
|
|
31
|
+
let bucket = buckets.get(sender)
|
|
32
|
+
if (!bucket) bucket = { tokens: burst, updatedAt: now }
|
|
33
|
+
const elapsed = Math.max(0, now - bucket.updatedAt)
|
|
34
|
+
bucket.tokens = Math.min(burst, bucket.tokens + elapsed * refillPerMs)
|
|
35
|
+
bucket.updatedAt = now
|
|
36
|
+
if (bucket.tokens < 1) {
|
|
37
|
+
buckets.set(sender, bucket)
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
bucket.tokens -= 1
|
|
41
|
+
buckets.set(sender, bucket)
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @returns {void}
|
|
47
|
+
*/
|
|
48
|
+
function installOverlayRateLimit() {
|
|
49
|
+
const limits = {
|
|
50
|
+
perMin: Math.max(1, Number(infraTunables.overlayRatePerMin) || 120),
|
|
51
|
+
burst: Math.max(1, Number(infraTunables.overlayRateBurst) || 30),
|
|
52
|
+
}
|
|
53
|
+
setOverlayRateGate((sender, action) => {
|
|
54
|
+
if (action !== 'route_req' && action !== 'relay') return true
|
|
55
|
+
return consumeOverlayRateToken(overlayRateBuckets, sender, Date.now(), limits)
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @returns {void}
|
|
61
|
+
*/
|
|
62
|
+
function removeOverlayRateLimit() {
|
|
63
|
+
clearOverlayRateGate()
|
|
64
|
+
overlayRateBuckets.clear()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** @type {boolean} */
|
|
68
|
+
let infraRunning = false
|
|
69
|
+
|
|
70
|
+
/** @type {(() => void) | null} */
|
|
71
|
+
let mailboxDispose = null
|
|
72
|
+
|
|
73
|
+
/** @type {(() => void) | null} */
|
|
74
|
+
let debugDispose = null
|
|
75
|
+
|
|
76
|
+
/** @type {number | null} */
|
|
77
|
+
let savedMaxActive = null
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @returns {boolean} infra relay 是否在运行
|
|
81
|
+
*/
|
|
82
|
+
export function isInfraRunning() {
|
|
83
|
+
return infraRunning
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 启动 public-good infra:overlay、mailbox、rate limit、priority、debug log。
|
|
88
|
+
* @param {{ maxActive?: number, logger?: { info?: Function, warn?: Function, error?: Function, log?: Function } | null }} [options] - maxActive 与 debug logger
|
|
89
|
+
* @returns {Promise<void>}
|
|
90
|
+
*/
|
|
91
|
+
export async function startInfra(options = {}) {
|
|
92
|
+
if (!isNodeInitialized()) throw new Error('p2p: startInfra requires initNode')
|
|
93
|
+
if (infraRunning) {
|
|
94
|
+
if (options.maxActive != null) await getLinkRegistry().setMaxActive(options.maxActive)
|
|
95
|
+
if (options.logger !== undefined) {
|
|
96
|
+
detachInfraDebugLog()
|
|
97
|
+
debugDispose = attachInfraDebugLog(options.logger ?? null)
|
|
98
|
+
}
|
|
99
|
+
applyPriorityToRegistry()
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
const registry = getLinkRegistry()
|
|
103
|
+
await registry.ensureRuntime()
|
|
104
|
+
registry.ensureOverlayRouter()
|
|
105
|
+
installOverlayRateLimit()
|
|
106
|
+
savedMaxActive = registry.getMaxActive()
|
|
107
|
+
if (options.maxActive != null)
|
|
108
|
+
await registry.setMaxActive(options.maxActive)
|
|
109
|
+
else
|
|
110
|
+
await registry.setMaxActive(infraTunables.defaultMaxActive ?? savedMaxActive)
|
|
111
|
+
if (!mailboxDispose) mailboxDispose = attachNodeScopeMailbox()
|
|
112
|
+
const logger = options.logger === undefined ? console : options.logger ?? null
|
|
113
|
+
debugDispose = attachInfraDebugLog(logger)
|
|
114
|
+
applyPriorityToRegistry()
|
|
115
|
+
infraRunning = true
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 卸掉 infra 自己挂的面(mailbox / rate / debug / priority / maxActive 恢复)。
|
|
120
|
+
* 不碰用户另行 attach 的 wires,不绑信誉同步。
|
|
121
|
+
* @returns {Promise<void>}
|
|
122
|
+
*/
|
|
123
|
+
export async function stopInfra() {
|
|
124
|
+
if (!infraRunning) return
|
|
125
|
+
debugDispose?.()
|
|
126
|
+
debugDispose = null
|
|
127
|
+
detachInfraDebugLog()
|
|
128
|
+
clearInfraPriorityFromRegistry()
|
|
129
|
+
removeOverlayRateLimit()
|
|
130
|
+
mailboxDispose?.()
|
|
131
|
+
mailboxDispose = null
|
|
132
|
+
const registry = getLinkRegistry()
|
|
133
|
+
if (savedMaxActive != null)
|
|
134
|
+
await registry.setMaxActive(savedMaxActive)
|
|
135
|
+
savedMaxActive = null
|
|
136
|
+
infraRunning = false
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** 再导出:infra 路由加权配置(见 `priority.mjs`)。 */
|
|
140
|
+
export { getInfraPriority, setInfraPriority }
|
package/link/channel_mux.mjs
CHANGED
|
@@ -57,7 +57,7 @@ const DEFAULT_ACTION_PRIORITIES = Object.freeze({
|
|
|
57
57
|
* @returns {number} 优先级(未知 action 默认 5)
|
|
58
58
|
*/
|
|
59
59
|
export function resolveActionPriority(action) {
|
|
60
|
-
return DEFAULT_ACTION_PRIORITIES[
|
|
60
|
+
return DEFAULT_ACTION_PRIORITIES[action] ?? 5
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
@@ -67,12 +67,11 @@ export function resolveActionPriority(action) {
|
|
|
67
67
|
* @returns {'control' | 'bulk'} 目标通道名
|
|
68
68
|
*/
|
|
69
69
|
export function pickChannel(action, byteLength) {
|
|
70
|
-
|
|
71
|
-
if (normalized === 'ping' || normalized === 'pong' || normalized.startsWith('route_'))
|
|
70
|
+
if (action === 'ping' || action === 'pong' || action.startsWith('route_'))
|
|
72
71
|
return CHANNEL_CONTROL
|
|
73
|
-
if (
|
|
72
|
+
if (byteLength > BULK_CHANNEL_MIN_BYTES)
|
|
74
73
|
return CHANNEL_BULK
|
|
75
|
-
return resolveActionPriority(
|
|
74
|
+
return resolveActionPriority(action) <= 3 ? CHANNEL_CONTROL : CHANNEL_BULK
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
/**
|
|
@@ -162,13 +161,14 @@ export function createChannelSendQueues(options) {
|
|
|
162
161
|
const flush = channelName => {
|
|
163
162
|
scheduled[channelName] = false
|
|
164
163
|
const channel = getChannel(channelName)
|
|
165
|
-
if (
|
|
164
|
+
if (channel?.readyState !== 'open') return
|
|
166
165
|
const queue = queues[channelName]
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
channel.send(
|
|
166
|
+
let i = 0
|
|
167
|
+
while (i < queue.length) {
|
|
168
|
+
if (readBufferedAmount(channel) > highWatermarkBytes) break
|
|
169
|
+
channel.send(queue[i++].bytes)
|
|
171
170
|
}
|
|
171
|
+
if (i > 0) queue.splice(0, i)
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
return {
|