@steve02081504/fount-p2p 0.0.3 → 0.0.5
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 +1 -1
- package/core/bytes_codec.mjs +0 -27
- package/core/constants.mjs +0 -31
- package/core/hexIds.mjs +0 -13
- package/{entity → core}/logical_entity.mjs +2 -1
- package/crypto/key.mjs +14 -15
- package/dag/index.mjs +0 -73
- package/dag/storage.mjs +0 -22
- package/federation/entity_key_chain.mjs +0 -9
- package/federation/topo_order_memo.mjs +0 -15
- package/{entity/files → files}/acl.mjs +3 -3
- package/files/assemble.mjs +55 -39
- package/files/assemble_stream.mjs +96 -44
- package/files/chunk_provider_registry.mjs +0 -6
- package/files/chunk_store.mjs +1 -11
- package/{entity/files → files}/evfs.mjs +81 -55
- package/{entity/files → files}/evfs_ref.mjs +3 -5
- package/files/manifest.mjs +11 -2
- package/{entity/files → files}/manifest_acl_registry.mjs +4 -10
- package/files/manifest_fetch.mjs +2 -2
- package/files/public_manifest.mjs +1 -1
- package/files/transfer_key.mjs +12 -6
- package/files/transfer_key_registry.mjs +0 -7
- package/governance/branch.mjs +0 -11
- package/link/channel_mux.mjs +2 -0
- package/mailbox/importance.mjs +0 -33
- package/mailbox/settings.mjs +0 -9
- package/node/denylist.mjs +0 -24
- package/node/identity.mjs +33 -2
- package/node/network.mjs +0 -51
- package/node/personal_block.mjs +1 -36
- package/node/reputation_store.mjs +0 -9
- package/node/retention_policy.mjs +0 -15
- package/package.json +1 -3
- package/registries/event_type.mjs +0 -12
- package/registries/inbound.mjs +0 -22
- package/reputation/engine.mjs +0 -11
- package/schemas/part_query.mjs +156 -0
- package/transport/ice_servers.mjs +0 -8
- package/transport/peer_identity_maps.mjs +0 -58
- package/transport/remote_user_room.mjs +0 -12
- package/transport/rtc_connection_budget.mjs +2 -0
- package/transport/user_room.mjs +2 -11
- package/trust_graph/cache.mjs +0 -13
- package/trust_graph/engine.mjs +0 -24
- package/utils/async_mutex.mjs +0 -9
- package/wire/part_fanout.mjs +0 -19
- package/wire/part_query.mjs +487 -0
- package/wire/part_query.tunables.json +14 -0
- package/wire/part_query_cache.mjs +94 -0
- package/entity/files/replica_host_cache.mjs +0 -46
- package/entity/hosting_registry.mjs +0 -47
- package/entity/logical_entity_id_registry.mjs +0 -40
- package/entity/node_hash.mjs +0 -15
- package/entity/replica.mjs +0 -20
- package/entity/session_snapshot_registry.mjs +0 -38
- package/registries/p2p_viewer.mjs +0 -35
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { sha256Hex } from '../crypto/crypto.mjs'
|
|
2
|
+
import { normalizePartQueryCacheMaterial } from '../schemas/part_query.mjs'
|
|
3
|
+
import { createLruMap } from '../utils/lru.mjs'
|
|
4
|
+
|
|
5
|
+
import partQueryTunables from './part_query.tunables.json' with { type: 'json' }
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {{ rows: unknown[], storedAt: number }} PartQueryCacheEntry
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} partpath part 路径
|
|
13
|
+
* @param {string} kind 查询标签
|
|
14
|
+
* @param {unknown} query 不透明查询
|
|
15
|
+
* @returns {string | null} sha256 hex 缓存键
|
|
16
|
+
*/
|
|
17
|
+
export function partQueryCacheKey(partpath, kind, query) {
|
|
18
|
+
const material = normalizePartQueryCacheMaterial(partpath, kind, query)
|
|
19
|
+
if (!material) return null
|
|
20
|
+
return sha256Hex(material)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* LRU + TTL 中继缓存(未验证线索;发起端仍需验签复核)。
|
|
25
|
+
*/
|
|
26
|
+
export function createPartQueryCache(options = {}) {
|
|
27
|
+
const maxKeys = Math.max(1, Math.floor(Number(options.maxKeys) || partQueryTunables.cacheMaxKeys))
|
|
28
|
+
const ttlMs = Math.max(1, Math.floor(Number(options.ttlMs) || partQueryTunables.cacheTtlMs))
|
|
29
|
+
const maxHits = Math.max(1, Math.floor(Number(options.maxHits) || partQueryTunables.maxHits))
|
|
30
|
+
/** @type {ReturnType<typeof createLruMap<string, PartQueryCacheEntry>>} */
|
|
31
|
+
const map = createLruMap(maxKeys)
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {number} [now=Date.now()] 当前时间
|
|
35
|
+
* @returns {void}
|
|
36
|
+
*/
|
|
37
|
+
const sweep = (now = Date.now()) => {
|
|
38
|
+
for (const [key, entry] of map)
|
|
39
|
+
if (now - entry.storedAt >= ttlMs) map.delete(key)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} partpath part 路径
|
|
45
|
+
* @param {string} kind 查询标签
|
|
46
|
+
* @param {unknown} query 查询体
|
|
47
|
+
* @param {number} [now=Date.now()] 当前时间
|
|
48
|
+
* @returns {unknown[] | null} 未过期 rows
|
|
49
|
+
*/
|
|
50
|
+
get(partpath, kind, query, now = Date.now()) {
|
|
51
|
+
const key = partQueryCacheKey(partpath, kind, query)
|
|
52
|
+
if (!key) return null
|
|
53
|
+
const entry = map.get(key)
|
|
54
|
+
if (!entry) return null
|
|
55
|
+
if (now - entry.storedAt >= ttlMs) {
|
|
56
|
+
map.delete(key)
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
map.touch(key, entry)
|
|
60
|
+
return entry.rows.slice()
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {string} partpath part 路径
|
|
65
|
+
* @param {string} kind 查询标签
|
|
66
|
+
* @param {unknown} query 查询体
|
|
67
|
+
* @param {unknown[]} rows 聚合 rows
|
|
68
|
+
* @param {number} [now=Date.now()] 当前时间
|
|
69
|
+
* @returns {void}
|
|
70
|
+
*/
|
|
71
|
+
set(partpath, kind, query, rows, now = Date.now()) {
|
|
72
|
+
const key = partQueryCacheKey(partpath, kind, query)
|
|
73
|
+
if (!key || !Array.isArray(rows)) return
|
|
74
|
+
sweep(now)
|
|
75
|
+
map.touch(key, {
|
|
76
|
+
rows: rows.slice(0, maxHits),
|
|
77
|
+
storedAt: now,
|
|
78
|
+
})
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
/** @returns {void} */
|
|
82
|
+
clear() {
|
|
83
|
+
map.clear()
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
/** @returns {number} 当前条目数 */
|
|
87
|
+
get size() {
|
|
88
|
+
return map.size
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** 进程内默认中继缓存 */
|
|
94
|
+
export const partQueryCache = createPartQueryCache()
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { getEntityStore } from '../../node/instance.mjs'
|
|
2
|
-
|
|
3
|
-
/** @type {Map<string, { replica: string | null, at: number }>} */
|
|
4
|
-
const replicaHostCache = new Map()
|
|
5
|
-
|
|
6
|
-
const REPLICA_HOST_CACHE_MS = 60_000
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @param {string | string[]} [entityHash] owner(单个或批量)
|
|
10
|
-
* @returns {void}
|
|
11
|
-
*/
|
|
12
|
-
export function invalidateReplicaHostCache(entityHash) {
|
|
13
|
-
if (Array.isArray(entityHash)) {
|
|
14
|
-
for (const eh of entityHash)
|
|
15
|
-
replicaHostCache.delete(String(eh).trim().toLowerCase())
|
|
16
|
-
return
|
|
17
|
-
}
|
|
18
|
-
if (entityHash) {
|
|
19
|
-
replicaHostCache.delete(String(entityHash).trim().toLowerCase())
|
|
20
|
-
return
|
|
21
|
-
}
|
|
22
|
-
replicaHostCache.clear()
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @param {string} ownerEntityHash 所有者
|
|
27
|
-
* @returns {Promise<string | null>} 托管 manifest 的 replica
|
|
28
|
-
*/
|
|
29
|
-
export async function findReplicaHostingEntityFiles(ownerEntityHash) {
|
|
30
|
-
const eh = String(ownerEntityHash).trim().toLowerCase()
|
|
31
|
-
const cached = replicaHostCache.get(eh)
|
|
32
|
-
if (cached && Date.now() - cached.at < REPLICA_HOST_CACHE_MS)
|
|
33
|
-
return cached.replica
|
|
34
|
-
|
|
35
|
-
const store = getEntityStore()
|
|
36
|
-
if (typeof store.findHostingUser === 'function') {
|
|
37
|
-
const replica = await store.findHostingUser(eh)
|
|
38
|
-
replicaHostCache.set(eh, { replica, at: Date.now() })
|
|
39
|
-
return replica
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const files = await store.listEntityFiles(eh)
|
|
43
|
-
const replica = files.length ? '__node__' : null
|
|
44
|
-
replicaHostCache.set(eh, { replica, at: Date.now() })
|
|
45
|
-
return replica
|
|
46
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/** @type {((username: string, entityHash: string) => string | null) | null} */
|
|
2
|
-
let resolveAgentCharPartName = null
|
|
3
|
-
|
|
4
|
-
/** @type {((username: string) => { entityHash: string, charPartName: string }[]) | null} */
|
|
5
|
-
let listLocalAgents = null
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Chat Load 时注册:解析本地 agent 的 chars 目录名。
|
|
9
|
-
* @param {(username: string, entityHash: string) => string | null} resolver 解析函数
|
|
10
|
-
* @returns {void}
|
|
11
|
-
*/
|
|
12
|
-
export function registerAgentCharResolver(resolver) {
|
|
13
|
-
resolveAgentCharPartName = resolver
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Chat Load 时注册:枚举 replica 下本地 agent 实体。
|
|
18
|
-
* @param {(username: string) => { entityHash: string, charPartName: string }[]} provider 枚举函数
|
|
19
|
-
* @returns {void}
|
|
20
|
-
*/
|
|
21
|
-
export function registerListLocalAgentsProvider(provider) {
|
|
22
|
-
listLocalAgents = provider
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** @returns {void} */
|
|
26
|
-
export function unregisterAgentCharResolver() {
|
|
27
|
-
resolveAgentCharPartName = null
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** @returns {void} */
|
|
31
|
-
export function unregisterListLocalAgentsProvider() {
|
|
32
|
-
listLocalAgents = null
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @returns {((username: string, entityHash: string) => string | null) | null} 已注册解析器
|
|
37
|
-
*/
|
|
38
|
-
export function getAgentCharResolver() {
|
|
39
|
-
return resolveAgentCharPartName
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @returns {((username: string) => { entityHash: string, charPartName: string }[]) | null} 已注册枚举器
|
|
44
|
-
*/
|
|
45
|
-
export function getListLocalAgentsProvider() {
|
|
46
|
-
return listLocalAgents
|
|
47
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/** @type {Map<string, (username: string, entityHash: string) => Promise<string | null>>} */
|
|
2
|
-
const resolversByOwner = new Map()
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {string} ownerId 注册方
|
|
6
|
-
* @param {(username: string, entityHash: string) => Promise<string | null>} resolver logical entity id 反查
|
|
7
|
-
* @returns {void}
|
|
8
|
-
*/
|
|
9
|
-
export function registerLogicalEntityIdResolver(ownerId, resolver) {
|
|
10
|
-
resolversByOwner.set(String(ownerId), resolver)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {string} ownerId 注册方
|
|
15
|
-
* @returns {void}
|
|
16
|
-
*/
|
|
17
|
-
export function unregisterLogicalEntityIdResolver(ownerId) {
|
|
18
|
-
resolversByOwner.delete(String(ownerId))
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** @returns {void} */
|
|
22
|
-
export function clearLogicalEntityIdRegistry() {
|
|
23
|
-
resolversByOwner.clear()
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @param {string} username 副本用户名
|
|
28
|
-
* @param {string} entityHash 128 位十六进制 logical entity
|
|
29
|
-
* @returns {Promise<string | null>} 逻辑实体 id
|
|
30
|
-
*/
|
|
31
|
-
export async function resolveLogicalEntityId(username, entityHash) {
|
|
32
|
-
for (const resolver of resolversByOwner.values())
|
|
33
|
-
try {
|
|
34
|
-
const id = await resolver(username, entityHash)
|
|
35
|
-
if (id) return id
|
|
36
|
-
}
|
|
37
|
-
catch { /* next */ }
|
|
38
|
-
|
|
39
|
-
return null
|
|
40
|
-
}
|
package/entity/node_hash.mjs
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Buffer } from 'node:buffer'
|
|
2
|
-
|
|
3
|
-
import { keyPairFromSeed, pubKeyHash } from '../crypto/crypto.mjs'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 由持久化 nodeSeed 派生 nodeHash(64 hex)。
|
|
7
|
-
* @param {string} seedHex 32 字节 hex
|
|
8
|
-
* @returns {string} 节点哈希
|
|
9
|
-
*/
|
|
10
|
-
export function nodeHashFromSeed(seedHex) {
|
|
11
|
-
const seed = Buffer.from(String(seedHex).trim(), 'hex')
|
|
12
|
-
if (seed.length !== 32) throw new Error('invalid node seed')
|
|
13
|
-
const { publicKey } = keyPairFromSeed(seed)
|
|
14
|
-
return pubKeyHash(publicKey)
|
|
15
|
-
}
|
package/entity/replica.mjs
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { parseEntityHash } from '../core/entity_id.mjs'
|
|
2
|
-
import { entityHashFromKeys, getNodeHash } from '../node/identity.mjs'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {string} recoveryPubKeyHex 64 位十六进制 recovery 公钥
|
|
6
|
-
* @returns {string | null} 本节点 entityHash
|
|
7
|
-
*/
|
|
8
|
-
export function resolveLocalEntityHashFromRecoveryPubKeyHex(recoveryPubKeyHex) {
|
|
9
|
-
return entityHashFromKeys(getNodeHash(), recoveryPubKeyHex)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @param {string} entityHash 目标 entityHash
|
|
14
|
-
* @returns {boolean} 是否为本节点可写实体
|
|
15
|
-
*/
|
|
16
|
-
export function isWritableLocalEntity(entityHash) {
|
|
17
|
-
const parsed = parseEntityHash(entityHash)
|
|
18
|
-
if (!parsed) return false
|
|
19
|
-
return parsed.nodeHash === getNodeHash()
|
|
20
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/** @type {Map<string, (replicaUsername: string, groupId: string) => Promise<object | null>>} */
|
|
2
|
-
const providersByOwner = new Map()
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {string} ownerId 注册方
|
|
6
|
-
* @param {(replicaUsername: string, groupId: string) => Promise<object | null>} provider 物化会话
|
|
7
|
-
* @returns {void}
|
|
8
|
-
*/
|
|
9
|
-
export function registerMaterializedSessionProvider(ownerId, provider) {
|
|
10
|
-
providersByOwner.set(String(ownerId), provider)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {string} ownerId 注册方
|
|
15
|
-
* @returns {void}
|
|
16
|
-
*/
|
|
17
|
-
export function unregisterMaterializedSessionProvider(ownerId) {
|
|
18
|
-
providersByOwner.delete(String(ownerId))
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @param {string} replicaUsername 副本用户名
|
|
23
|
-
* @param {string} groupId 群 ID
|
|
24
|
-
* @param {string} [ownerId] 注册方 id;省略时遍历所有 provider
|
|
25
|
-
* @returns {Promise<object | null>} 物化会话
|
|
26
|
-
*/
|
|
27
|
-
export async function getMaterializedSession(replicaUsername, groupId, ownerId) {
|
|
28
|
-
if (ownerId != null) {
|
|
29
|
-
const provider = providersByOwner.get(String(ownerId))
|
|
30
|
-
if (!provider) return null
|
|
31
|
-
return provider(replicaUsername, groupId)
|
|
32
|
-
}
|
|
33
|
-
for (const provider of providersByOwner.values()) {
|
|
34
|
-
const session = await provider(replicaUsername, groupId)
|
|
35
|
-
if (session) return session
|
|
36
|
-
}
|
|
37
|
-
return null
|
|
38
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/** @type {Map<string, (replicaUsername: string, groupId: string) => Promise<string>>} */
|
|
2
|
-
const groupMemberEntityByOwner = new Map()
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {string} ownerId 注册方
|
|
6
|
-
* @param {(replicaUsername: string, groupId: string) => Promise<string>} resolver 群成员 entityHash
|
|
7
|
-
* @returns {void}
|
|
8
|
-
*/
|
|
9
|
-
export function registerGroupMemberEntityResolver(ownerId, resolver) {
|
|
10
|
-
groupMemberEntityByOwner.set(String(ownerId), resolver)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {string} ownerId 注册方
|
|
15
|
-
* @returns {void}
|
|
16
|
-
*/
|
|
17
|
-
export function unregisterGroupMemberEntityResolver(ownerId) {
|
|
18
|
-
groupMemberEntityByOwner.delete(String(ownerId))
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @param {string} replicaUsername 副本用户名
|
|
23
|
-
* @param {string} groupId 群 ID
|
|
24
|
-
* @returns {Promise<string | null>} entityHash;无注册方时 null
|
|
25
|
-
*/
|
|
26
|
-
export async function resolveGroupMemberEntityHash(replicaUsername, groupId) {
|
|
27
|
-
for (const resolver of groupMemberEntityByOwner.values())
|
|
28
|
-
try {
|
|
29
|
-
const eh = await resolver(replicaUsername, groupId)
|
|
30
|
-
if (eh) return eh
|
|
31
|
-
}
|
|
32
|
-
catch { /* next */ }
|
|
33
|
-
|
|
34
|
-
return null
|
|
35
|
-
}
|