@steve02081504/fount-p2p 0.0.12 → 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 +41 -10
- package/core/composite_key.mjs +5 -5
- package/crypto/crypto.mjs +3 -3
- package/crypto/key.mjs +12 -12
- 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 +153 -112
- package/discovery/bt/probe_child.mjs +2 -1
- package/discovery/bt/runtime.mjs +2 -9
- package/discovery/index.mjs +267 -62
- package/discovery/internal/signal_crypto.mjs +109 -0
- package/discovery/lan.mjs +228 -0
- package/discovery/nostr.mjs +394 -59
- package/federation/chunk_fetch_pending.mjs +10 -13
- package/federation/manifest_fetch_pending.mjs +1 -3
- package/files/assemble.mjs +14 -14
- package/files/assemble_stream.mjs +6 -6
- package/files/chunk_responder.mjs +29 -20
- package/files/evfs.mjs +29 -28
- 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/frame.mjs +9 -16
- package/link/handshake.mjs +14 -15
- package/link/pipe.mjs +8 -8
- package/link/providers/ble_gatt.mjs +6 -6
- package/link/rtc.mjs +3 -3
- package/mailbox/consumer_registry.mjs +2 -2
- package/mailbox/deliver_or_store.mjs +5 -5
- package/mailbox/wire.mjs +28 -24
- package/node/entity_store.mjs +6 -6
- package/node/instance.mjs +46 -27
- package/node/local_data_revision.mjs +26 -0
- package/node/log.mjs +56 -0
- package/node/network.mjs +37 -5
- 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 +22 -1
- package/package.json +13 -2
- package/rooms/scoped_link.mjs +17 -166
- package/transport/advert_ingest.mjs +11 -14
- package/transport/group_link_set.mjs +149 -99
- package/transport/link_registry.mjs +211 -60
- package/transport/mesh_keepalive.mjs +217 -0
- package/transport/node_scope.mjs +289 -0
- package/transport/offer_answer.mjs +45 -48
- package/transport/peer_pool.mjs +116 -14
- package/transport/remote_user_room.mjs +6 -9
- package/transport/{rtc_mdns_filter.mjs → rtc_ice_local_hostname.mjs} +13 -13
- package/transport/runtime_bootstrap.mjs +170 -108
- package/transport/tunables.json +11 -0
- package/transport/tunables.mjs +18 -0
- package/transport/user_room.mjs +83 -158
- 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 +0 -3
- package/utils/async_mutex.mjs +4 -4
- package/utils/emit_safe.mjs +3 -3
- package/utils/json_io.mjs +12 -12
- package/utils/map_pool.mjs +5 -5
- package/wire/part_ingress.mjs +32 -28
- package/wire/part_query.mjs +26 -20
- package/discovery/mdns.mjs +0 -197
- package/transport/signal_crypto.mjs +0 -104
|
@@ -1,32 +1,51 @@
|
|
|
1
1
|
import process from 'node:process'
|
|
2
2
|
|
|
3
|
-
/** @typedef {'none' | 'rewrite-loopback' | 'drop'}
|
|
3
|
+
/** @typedef {'none' | 'rewrite-loopback' | 'drop'} IceLocalHostnamePolicy */
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @typedef {{
|
|
7
7
|
* relayOverride: string[] | null
|
|
8
|
-
*
|
|
8
|
+
* iceLocalHostnamePolicy: IceLocalHostnamePolicy
|
|
9
9
|
* trickleIceOff: boolean
|
|
10
10
|
* }} SignalingRuntimeConfig
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
const ICE_LOCAL_HOSTNAME_POLICIES = new Set(['none', 'rewrite-loopback', 'drop'])
|
|
14
|
+
|
|
13
15
|
/**
|
|
14
|
-
* 生产默认:win32 丢弃
|
|
15
|
-
* @returns {SignalingRuntimeConfig}
|
|
16
|
+
* 生产默认:win32 丢弃 `.local` host candidate;其它平台不过滤。
|
|
17
|
+
* @returns {SignalingRuntimeConfig} 默认信令运行时配置
|
|
16
18
|
*/
|
|
17
19
|
export function defaultSignalingRuntimeConfig() {
|
|
18
|
-
const
|
|
20
|
+
const iceLocalHostnamePolicy = process.platform === 'win32' ? 'drop' : 'none'
|
|
19
21
|
return {
|
|
20
22
|
relayOverride: null,
|
|
21
|
-
|
|
22
|
-
trickleIceOff:
|
|
23
|
+
iceLocalHostnamePolicy,
|
|
24
|
+
trickleIceOff: iceLocalHostnamePolicy !== 'none',
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
|
-
*
|
|
28
|
-
* @returns {SignalingRuntimeConfig}
|
|
29
|
+
* @param {Partial<SignalingRuntimeConfig>} [patch] 合并字段
|
|
30
|
+
* @returns {SignalingRuntimeConfig} 合并后的信令运行时配置
|
|
29
31
|
*/
|
|
30
|
-
export function resolveSignalingRuntimeConfig() {
|
|
31
|
-
|
|
32
|
+
export function resolveSignalingRuntimeConfig(patch = {}) {
|
|
33
|
+
const base = defaultSignalingRuntimeConfig()
|
|
34
|
+
if (!patch || typeof patch !== 'object') return base
|
|
35
|
+
const policyRaw = patch.iceLocalHostnamePolicy
|
|
36
|
+
const iceLocalHostnamePolicy = ICE_LOCAL_HOSTNAME_POLICIES.has(/** @type {string} */ policyRaw)
|
|
37
|
+
? /** @type {IceLocalHostnamePolicy} */ policyRaw
|
|
38
|
+
: base.iceLocalHostnamePolicy
|
|
39
|
+
let { relayOverride } = base
|
|
40
|
+
if (Object.prototype.hasOwnProperty.call(patch, 'relayOverride'))
|
|
41
|
+
relayOverride = patch.relayOverride == null
|
|
42
|
+
? null
|
|
43
|
+
: [...new Set((Array.isArray(patch.relayOverride) ? patch.relayOverride : [])
|
|
44
|
+
.map(url => String(url || '').trim())
|
|
45
|
+
.filter(url => url.startsWith('wss://')))]
|
|
46
|
+
return {
|
|
47
|
+
relayOverride,
|
|
48
|
+
iceLocalHostnamePolicy,
|
|
49
|
+
trickleIceOff: patch.trickleIceOff !== undefined ? !!patch.trickleIceOff : iceLocalHostnamePolicy !== 'none',
|
|
50
|
+
}
|
|
32
51
|
}
|
package/overlay/index.mjs
CHANGED
|
@@ -6,6 +6,26 @@ import { createLruMap } from '../utils/lru.mjs'
|
|
|
6
6
|
|
|
7
7
|
const ROUTE_DOMAIN = 'fount-route'
|
|
8
8
|
|
|
9
|
+
/** @type {((senderNodeHash: string, action: string) => boolean) | null} */
|
|
10
|
+
let overlayRateGate = null
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 安装 overlay 入站限速门(返回 false 则丢弃)。
|
|
14
|
+
* @param {((senderNodeHash: string, action: string) => boolean) | null} rateGate 返回 false 则丢弃
|
|
15
|
+
* @returns {void}
|
|
16
|
+
*/
|
|
17
|
+
export function setOverlayRateGate(rateGate) {
|
|
18
|
+
overlayRateGate = typeof rateGate === 'function' ? rateGate : null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 清除 overlay 限速门。
|
|
23
|
+
* @returns {void}
|
|
24
|
+
*/
|
|
25
|
+
export function clearOverlayRateGate() {
|
|
26
|
+
overlayRateGate = null
|
|
27
|
+
}
|
|
28
|
+
|
|
9
29
|
/**
|
|
10
30
|
* 构造 overlay 路由签名用的字节序列。
|
|
11
31
|
* @param {string} reqId 路由请求 id
|
|
@@ -27,7 +47,7 @@ export function createOverlayRouter(registry, ttl = 3) {
|
|
|
27
47
|
const selfPubKey = registry.localIdentity.nodePubKey
|
|
28
48
|
const { secretKey } = registry.localIdentity
|
|
29
49
|
const seenReqs = createLruMap(4096)
|
|
30
|
-
/** @type {Map<string, { resolve: (path: string[]) => void, reject: (
|
|
50
|
+
/** @type {Map<string, { resolve: (path: string[]) => void, reject: (error: Error) => void, timer: number }>} */
|
|
31
51
|
const pendingRoutes = new Map()
|
|
32
52
|
/** @type {Set<(body: unknown, meta: { path: string[], from: string }) => void>} */
|
|
33
53
|
const relayListeners = new Set()
|
|
@@ -52,6 +72,7 @@ export function createOverlayRouter(registry, ttl = 3) {
|
|
|
52
72
|
const payload = envelope?.payload
|
|
53
73
|
const action = envelope?.action || ''
|
|
54
74
|
if (!payload) return
|
|
75
|
+
if (overlayRateGate && !overlayRateGate(senderNodeHash, action)) return
|
|
55
76
|
if (action === 'route_req') {
|
|
56
77
|
const reqId = payload.reqId || ''
|
|
57
78
|
const target = payload.target || ''
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@steve02081504/fount-p2p",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "fount federation P2P layer — link, trust graph, mailbox, DAG, EVFS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"network",
|
|
@@ -30,8 +30,13 @@
|
|
|
30
30
|
"!sim/**",
|
|
31
31
|
"!scripts/**"
|
|
32
32
|
],
|
|
33
|
+
"bin": {
|
|
34
|
+
"fount-p2p": "./infra/cli.mjs"
|
|
35
|
+
},
|
|
33
36
|
"exports": {
|
|
34
37
|
".": "./index.mjs",
|
|
38
|
+
"./infra": "./infra/service.mjs",
|
|
39
|
+
"./link": "./link/providers/index.mjs",
|
|
35
40
|
"./core/*": "./core/*.mjs",
|
|
36
41
|
"./crypto": "./crypto/crypto.mjs",
|
|
37
42
|
"./crypto/*": "./crypto/*.mjs",
|
|
@@ -42,7 +47,12 @@
|
|
|
42
47
|
"./discovery/bt": "./discovery/bt/index.mjs",
|
|
43
48
|
"./discovery/bt/*": "./discovery/bt/*.mjs",
|
|
44
49
|
"./discovery/*": "./discovery/*.mjs",
|
|
45
|
-
"./transport
|
|
50
|
+
"./transport/link_registry": "./transport/link_registry.mjs",
|
|
51
|
+
"./transport/user_room": "./transport/user_room.mjs",
|
|
52
|
+
"./transport/group_link_set": "./transport/group_link_set.mjs",
|
|
53
|
+
"./transport/node_scope": "./transport/node_scope.mjs",
|
|
54
|
+
"./transport/room_scopes": "./transport/room_scopes.mjs",
|
|
55
|
+
"./transport/remote_user_room": "./transport/remote_user_room.mjs",
|
|
46
56
|
"./rooms/*": "./rooms/*.mjs",
|
|
47
57
|
"./overlay": "./overlay/index.mjs",
|
|
48
58
|
"./overlay/*": "./overlay/*.mjs",
|
|
@@ -62,6 +72,7 @@
|
|
|
62
72
|
"dependencies": {
|
|
63
73
|
"@noble/curves": "latest",
|
|
64
74
|
"node-datachannel": "latest",
|
|
75
|
+
"on-shutdown": "latest",
|
|
65
76
|
"ws": "latest"
|
|
66
77
|
},
|
|
67
78
|
"devDependencies": {
|
package/rooms/scoped_link.mjs
CHANGED
|
@@ -1,171 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ingestSignedAdvert } from '../transport/advert_ingest.mjs'
|
|
3
|
-
import { getLinkRegistry } from '../transport/link_registry.mjs'
|
|
4
|
-
import {
|
|
5
|
-
encryptSignalPacket,
|
|
6
|
-
groupRendezvousTopic,
|
|
7
|
-
} from '../transport/signal_crypto.mjs'
|
|
8
|
-
import { emitSafe } from '../utils/emit_safe.mjs'
|
|
1
|
+
import { createGroupLinkSet } from '../transport/group_link_set.mjs'
|
|
9
2
|
|
|
10
3
|
/**
|
|
11
|
-
*
|
|
12
|
-
* @param {object} options 房间选项
|
|
13
|
-
* @param {string} options.scope link registry scope
|
|
14
|
-
* @param {string} options.roomSecret
|
|
15
|
-
* @param {(nodeHash: string) => boolean} [options.allowNode]
|
|
16
|
-
* @returns {
|
|
4
|
+
* scoped 房间:group_link_set 的薄预设(任意 scope + allowNode + 发现即拨)。
|
|
5
|
+
* @param {object} options - 房间选项
|
|
6
|
+
* @param {string} options.scope - link registry scope
|
|
7
|
+
* @param {string} options.roomSecret - rendezvous 密钥
|
|
8
|
+
* @param {(nodeHash: string) => boolean} [options.allowNode] - 节点准入过滤
|
|
9
|
+
* @returns {ReturnType<typeof createGroupLinkSet>} scoped link 房间句柄
|
|
17
10
|
*/
|
|
18
11
|
export function createScopedLinkRoom(options) {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/** @type {Set<(peerId: string) => void>} */
|
|
30
|
-
const leaveListeners = new Set()
|
|
31
|
-
/** @type {Set<() => void>} */
|
|
32
|
-
const cleanups = new Set()
|
|
33
|
-
/** @type {Map<string, { handler: ((payload: unknown, peerId: string) => void) | null, backlog: Array<{ payload: unknown, peerId: string }> }>} */
|
|
34
|
-
const actionEntries = new Map()
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* @returns {string[]} 当前已连接且通过 allowNode 过滤的 peer nodeHash 列表
|
|
38
|
-
*/
|
|
39
|
-
function activePeerIds() {
|
|
40
|
-
return [...discoveredPeers].filter(nodeHash => allowNode(nodeHash) && registry.getLink(nodeHash))
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param {string} peerId 节点 hash
|
|
45
|
-
* @returns {void}
|
|
46
|
-
*/
|
|
47
|
-
function notePeerJoin(peerId) {
|
|
48
|
-
if (!peerId || announcedPeers.has(peerId)) return
|
|
49
|
-
announcedPeers.add(peerId)
|
|
50
|
-
emitSafe(joinListeners, peerId)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* @param {string} peerId 节点 hash
|
|
55
|
-
* @returns {void}
|
|
56
|
-
*/
|
|
57
|
-
function notePeerLeave(peerId) {
|
|
58
|
-
if (!peerId || !announcedPeers.has(peerId)) return
|
|
59
|
-
announcedPeers.delete(peerId)
|
|
60
|
-
emitSafe(leaveListeners, peerId)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* @param {string} name action 名称
|
|
65
|
-
* @returns {{ handler: ((payload: unknown, peerId: string) => void) | null, backlog: Array<{ payload: unknown, peerId: string }> }} action 槽(含待处理 backlog)
|
|
66
|
-
*/
|
|
67
|
-
function getActionEntry(name) {
|
|
68
|
-
if (!actionEntries.has(name))
|
|
69
|
-
actionEntries.set(name, { handler: null, backlog: [] })
|
|
70
|
-
return actionEntries.get(name)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
/**
|
|
75
|
-
* @returns {Promise<void>}
|
|
76
|
-
*/
|
|
77
|
-
async start() {
|
|
78
|
-
await registry.ensureRuntime()
|
|
79
|
-
cleanups.add(registry.subscribeScope(scope, (senderNodeHash, envelope) => {
|
|
80
|
-
if (!allowNode(senderNodeHash)) return
|
|
81
|
-
const entry = actionEntries.get(envelope.action)
|
|
82
|
-
if (!entry) return
|
|
83
|
-
if (entry.handler) entry.handler(envelope.payload, senderNodeHash)
|
|
84
|
-
else entry.backlog.push({ payload: envelope.payload, peerId: senderNodeHash })
|
|
85
|
-
}))
|
|
86
|
-
cleanups.add(registry.onLinkUp(nodeHash => {
|
|
87
|
-
if (!discoveredPeers.has(nodeHash) || !allowNode(nodeHash)) return
|
|
88
|
-
notePeerJoin(nodeHash)
|
|
89
|
-
}))
|
|
90
|
-
cleanups.add(registry.onLinkDown(nodeHash => {
|
|
91
|
-
if (!discoveredPeers.has(nodeHash)) return
|
|
92
|
-
notePeerLeave(nodeHash)
|
|
93
|
-
}))
|
|
94
|
-
cleanups.add(await subscribeTopic(topic, async (bytes, meta) => {
|
|
95
|
-
const ingested = await ingestSignedAdvert(topic, bytes, meta)
|
|
96
|
-
if (!ingested || !allowNode(ingested.verifiedNodeHash)) return
|
|
97
|
-
discoveredPeers.add(ingested.verifiedNodeHash)
|
|
98
|
-
await registry.ensureLinkToNode(ingested.verifiedNodeHash).catch(() => null)
|
|
99
|
-
if (registry.getLink(ingested.verifiedNodeHash)) notePeerJoin(ingested.verifiedNodeHash)
|
|
100
|
-
}))
|
|
101
|
-
cleanups.add(await advertiseTopic(topic, encryptSignalPacket(topic, {
|
|
102
|
-
type: 'advert',
|
|
103
|
-
body: await registry.buildLocalAdvert(topic),
|
|
104
|
-
})))
|
|
105
|
-
for (const peerId of activePeerIds())
|
|
106
|
-
notePeerJoin(peerId)
|
|
107
|
-
},
|
|
108
|
-
/**
|
|
109
|
-
* @returns {Promise<void>}
|
|
110
|
-
*/
|
|
111
|
-
async leave() {
|
|
112
|
-
for (const cleanup of cleanups)
|
|
113
|
-
try { cleanup() } catch { /* ignore */ }
|
|
114
|
-
cleanups.clear()
|
|
115
|
-
for (const peerId of [...announcedPeers])
|
|
116
|
-
notePeerLeave(peerId)
|
|
117
|
-
},
|
|
118
|
-
/**
|
|
119
|
-
* @param {string} name action 名称
|
|
120
|
-
* @returns {[(payload: unknown, peerId?: string | string[] | null) => Promise<void>, (handler: (payload: unknown, peerId: string) => void) => void]} [send, onReceive] 发送与订阅元组
|
|
121
|
-
*/
|
|
122
|
-
makeAction(name) {
|
|
123
|
-
return [
|
|
124
|
-
async (payload, peerId = null) => {
|
|
125
|
-
if (Array.isArray(peerId)) {
|
|
126
|
-
await Promise.all(peerId.map(targetPeerId =>
|
|
127
|
-
registry.sendToNodeLink(targetPeerId, { scope, action: name, payload })))
|
|
128
|
-
return
|
|
129
|
-
}
|
|
130
|
-
if (peerId)
|
|
131
|
-
await registry.sendToNodeLink(peerId, { scope, action: name, payload })
|
|
132
|
-
else
|
|
133
|
-
await Promise.all(activePeerIds().map(targetPeerId =>
|
|
134
|
-
registry.sendToNodeLink(targetPeerId, { scope, action: name, payload })))
|
|
135
|
-
},
|
|
136
|
-
handler => {
|
|
137
|
-
const entry = getActionEntry(name)
|
|
138
|
-
entry.handler = handler
|
|
139
|
-
for (const pending of entry.backlog.splice(0))
|
|
140
|
-
handler(pending.payload, pending.peerId)
|
|
141
|
-
},
|
|
142
|
-
]
|
|
143
|
-
},
|
|
144
|
-
/**
|
|
145
|
-
* @param {(peerId: string) => void} callback 新 peer 上线回调
|
|
146
|
-
* @returns {() => void} 取消订阅
|
|
147
|
-
*/
|
|
148
|
-
onPeerJoin(callback) {
|
|
149
|
-
joinListeners.add(callback)
|
|
150
|
-
for (const peerId of activePeerIds())
|
|
151
|
-
announcedPeers.add(peerId)
|
|
152
|
-
for (const peerId of announcedPeers)
|
|
153
|
-
try { callback(peerId) } catch { /* ignore */ }
|
|
154
|
-
return () => joinListeners.delete(callback)
|
|
155
|
-
},
|
|
156
|
-
/**
|
|
157
|
-
* @param {(peerId: string) => void} callback peer 离线回调
|
|
158
|
-
* @returns {() => void} 取消订阅
|
|
159
|
-
*/
|
|
160
|
-
onPeerLeave(callback) {
|
|
161
|
-
leaveListeners.add(callback)
|
|
162
|
-
return () => leaveListeners.delete(callback)
|
|
163
|
-
},
|
|
164
|
-
/**
|
|
165
|
-
* @returns {Record<string, true>} 当前活跃 peer 的 nodeHash 集合
|
|
166
|
-
*/
|
|
167
|
-
getPeers() {
|
|
168
|
-
return Object.fromEntries(activePeerIds().map(peerId => [peerId, true]))
|
|
169
|
-
},
|
|
170
|
-
}
|
|
12
|
+
const { scope, roomSecret, allowNode } = options
|
|
13
|
+
return createGroupLinkSet({
|
|
14
|
+
groupId: scope,
|
|
15
|
+
scope,
|
|
16
|
+
roomSecret,
|
|
17
|
+
members: [],
|
|
18
|
+
allowNode,
|
|
19
|
+
dialAll: true,
|
|
20
|
+
autoconnect: true,
|
|
21
|
+
})
|
|
171
22
|
}
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import { noteAdvertPeerHints } from '../discovery/advert_peer_hints.mjs'
|
|
2
|
-
import { verifySignedAdvert } from '../link/handshake.mjs'
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* 解密并验签 advert(`ingestEncryptedAdvert` 别名)。不写 peer hints;写入需 `applyAdvertPeerHints`。Untrusted ingress。
|
|
5
|
+
*/
|
|
6
|
+
export { ingestEncryptedAdvert as ingestSignedAdvert } from '../discovery/adverts.mjs'
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
|
-
*
|
|
8
|
-
* @param {string}
|
|
9
|
-
* @param {
|
|
10
|
-
* @param {object} [meta]
|
|
11
|
-
* @returns {
|
|
9
|
+
* 将已验签 advert 的 peer hints 写入本地(apply 侧;与 `ingestSignedAdvert` 分离)。
|
|
10
|
+
* @param {string} verifiedNodeHash 已验签 nodeHash
|
|
11
|
+
* @param {object} body advert body
|
|
12
|
+
* @param {object} [meta] 元数据
|
|
13
|
+
* @returns {void}
|
|
12
14
|
*/
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
if (packet?.type !== 'advert' || !packet.body) return null
|
|
16
|
-
const verifiedNodeHash = await verifySignedAdvert(topic, packet.body)
|
|
17
|
-
if (!verifiedNodeHash) return null
|
|
18
|
-
noteAdvertPeerHints(verifiedNodeHash, packet.body, meta)
|
|
19
|
-
return { verifiedNodeHash, body: packet.body }
|
|
15
|
+
export function applyAdvertPeerHints(verifiedNodeHash, body, meta) {
|
|
16
|
+
noteAdvertPeerHints(verifiedNodeHash, body, meta)
|
|
20
17
|
}
|