@steve02081504/fount-p2p 0.0.16 → 0.0.18
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/discovery/bt/runtime.mjs +21 -40
- package/files/manifest_fetch.mjs +18 -9
- package/package.json +1 -1
- package/discovery/bt/probe_child.mjs +0 -21
package/discovery/bt/runtime.mjs
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process'
|
|
2
1
|
import { existsSync, readdirSync } from 'node:fs'
|
|
3
|
-
import { dirname, join } from 'node:path'
|
|
4
2
|
import process from 'node:process'
|
|
5
|
-
import { fileURLToPath } from 'node:url'
|
|
6
3
|
|
|
7
4
|
/**
|
|
8
5
|
* 解析 Bluetooth 角色(scan / dual)。
|
|
@@ -31,50 +28,34 @@ export function probeBluetoothHardware() {
|
|
|
31
28
|
|
|
32
29
|
/** @type {boolean | null} canUseBluetoothRuntime 缓存 */
|
|
33
30
|
let cachedRuntimeOk = null
|
|
34
|
-
/** @type {Promise<boolean> | null} 并发 canUse
|
|
31
|
+
/** @type {Promise<boolean> | null} 并发 canUse 合并为一次进程内探测 */
|
|
35
32
|
let probeInflight = null
|
|
36
33
|
|
|
37
|
-
const PROBE_CHILD = join(dirname(fileURLToPath(import.meta.url)), 'probe_child.mjs')
|
|
38
|
-
|
|
39
34
|
/**
|
|
40
|
-
*
|
|
35
|
+
* 进程内 BT 可用性探测:load → poweredOn → stop。
|
|
36
|
+
* 需要 @stoprocent/noble>=2.5.9(Windows stop() 与事件循环释放,见 stoprocent/noble#95)。
|
|
41
37
|
* @param {number} timeoutMs waitPoweredOn 超时
|
|
42
|
-
* @returns {Promise<boolean>}
|
|
38
|
+
* @returns {Promise<boolean>} poweredOn 且 stop 成功为 true
|
|
43
39
|
*/
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
settled = true
|
|
60
|
-
clearTimeout(timer)
|
|
61
|
-
resolve(ok)
|
|
62
|
-
}
|
|
63
|
-
const timer = setTimeout(() => {
|
|
64
|
-
child.kill('SIGKILL')
|
|
65
|
-
finish(false)
|
|
66
|
-
}, timeoutMs + 5_000)
|
|
67
|
-
timer.unref()
|
|
68
|
-
child.once('error', () => finish(false))
|
|
69
|
-
child.once('exit', (code, signal) => {
|
|
70
|
-
if (signal) finish(false)
|
|
71
|
-
else finish(code === 0)
|
|
72
|
-
})
|
|
73
|
-
})
|
|
40
|
+
async function probeBluetoothInProcess(timeoutMs) {
|
|
41
|
+
/** @type {any} */
|
|
42
|
+
let noble = null
|
|
43
|
+
try {
|
|
44
|
+
noble = await loadNoble()
|
|
45
|
+
if (!noble?.startScanningAsync) return false
|
|
46
|
+
await waitPoweredOn(noble, timeoutMs)
|
|
47
|
+
return true
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
if (noble) try { noble.stop() } catch { /* ignore */ }
|
|
54
|
+
}
|
|
74
55
|
}
|
|
75
56
|
|
|
76
57
|
/**
|
|
77
|
-
* 探测 BT 栈是否真正可用(硬件迹象 →
|
|
58
|
+
* 探测 BT 栈是否真正可用(硬件迹象 → 进程内 load → poweredOn → stop)。
|
|
78
59
|
* 任一步失败返回 false;不抛错。
|
|
79
60
|
* @param {number} [timeoutMs=3000] waitPoweredOn 超时
|
|
80
61
|
* @returns {Promise<boolean>} 可用为 true
|
|
@@ -86,7 +67,7 @@ export async function canUseBluetoothRuntime(timeoutMs = 3000) {
|
|
|
86
67
|
return false
|
|
87
68
|
}
|
|
88
69
|
if (!probeInflight)
|
|
89
|
-
probeInflight =
|
|
70
|
+
probeInflight = probeBluetoothInProcess(timeoutMs)
|
|
90
71
|
.then(ok => {
|
|
91
72
|
cachedRuntimeOk = ok
|
|
92
73
|
return ok
|
package/files/manifest_fetch.mjs
CHANGED
|
@@ -15,9 +15,12 @@ import { fanoutFedFetch } from './fetch_fanout.mjs'
|
|
|
15
15
|
import { normalizeFileManifest } from './manifest.mjs'
|
|
16
16
|
import { shouldPreferIncomingPublicManifest } from './public_manifest.mjs'
|
|
17
17
|
|
|
18
|
+
const DEFAULT_MANIFEST_FETCH_TIMEOUT_MS = 8000
|
|
19
|
+
|
|
18
20
|
/**
|
|
19
21
|
* 拉取公开 manifest;默认不写盘。`cache: true` 或 `cachePublicManifest` 才缓存。
|
|
20
|
-
*
|
|
22
|
+
* 本地已有 publicSig 时仍会 fanout 再校验,按 publishedAt 择新;超时则回退本地。
|
|
23
|
+
* @param {{ username: string, ownerEntityHash: string, logicalPath: string, cache?: boolean, timeoutMs?: number }} context - 拉取上下文
|
|
21
24
|
* @returns {Promise<import('./manifest.mjs').FileManifest | null>} 验签后的 manifest,失败为 null
|
|
22
25
|
*/
|
|
23
26
|
export async function fetchPublicManifest(context) {
|
|
@@ -27,16 +30,19 @@ export async function fetchPublicManifest(context) {
|
|
|
27
30
|
if (!ownerEntityHash || !logicalPath || !username) return null
|
|
28
31
|
|
|
29
32
|
const local = await loadFileManifest(ownerEntityHash, logicalPath)
|
|
30
|
-
|
|
31
|
-
return local
|
|
33
|
+
const hasLocalPublic = local?.transferKeyDescriptor?.type === 'public' && !!local?.meta?.publicSig
|
|
32
34
|
|
|
33
|
-
if (pendingManifestFetches.size >= MAX_PENDING_MANIFEST_FETCHES)
|
|
35
|
+
if (pendingManifestFetches.size >= MAX_PENDING_MANIFEST_FETCHES)
|
|
36
|
+
return hasLocalPublic ? local : null
|
|
34
37
|
|
|
38
|
+
const timeoutMs = Number(context.timeoutMs) > 0
|
|
39
|
+
? Number(context.timeoutMs)
|
|
40
|
+
: DEFAULT_MANIFEST_FETCH_TIMEOUT_MS
|
|
35
41
|
const requestId = randomUUID()
|
|
36
42
|
const { done } = registerManifestFetchWait(
|
|
37
43
|
requestId,
|
|
38
44
|
manifestFetchExpectedKey(ownerEntityHash, logicalPath),
|
|
39
|
-
|
|
45
|
+
timeoutMs,
|
|
40
46
|
)
|
|
41
47
|
const { nodeHash } = await resolveNodeHash(username)
|
|
42
48
|
const payload = {
|
|
@@ -47,11 +53,14 @@ export async function fetchPublicManifest(context) {
|
|
|
47
53
|
}
|
|
48
54
|
await fanoutFedFetch(username, 'fed_manifest_get', payload)
|
|
49
55
|
const result = await done
|
|
50
|
-
if (!result) return null
|
|
51
56
|
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
if (result && (!hasLocalPublic || shouldPreferIncomingPublicManifest(local, result))) {
|
|
58
|
+
if (context.cache === true)
|
|
59
|
+
await cachePublicManifest(ownerEntityHash, logicalPath, result)
|
|
60
|
+
return result
|
|
61
|
+
}
|
|
62
|
+
if (hasLocalPublic) return local
|
|
63
|
+
return null
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
/**
|
package/package.json
CHANGED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 子进程 BT 可用性探测:load → poweredOn → stop → exit。
|
|
3
|
-
* 由 `canUseBluetoothRuntime` spawn;勿在父进程直接跑 waitPoweredOn(会拖住事件循环)。
|
|
4
|
-
* argv[2]:waitPoweredOn 超时毫秒(默认 3000)。
|
|
5
|
-
*/
|
|
6
|
-
import process from 'node:process'
|
|
7
|
-
|
|
8
|
-
import { loadNoble, waitPoweredOn } from './runtime.mjs'
|
|
9
|
-
|
|
10
|
-
const timeoutMs = Number(process.argv[2] || 3000)
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
const noble = await loadNoble()
|
|
14
|
-
if (!noble?.startScanningAsync) process.exit(2)
|
|
15
|
-
await waitPoweredOn(noble, timeoutMs)
|
|
16
|
-
try { noble.stop() } catch { /* Windows 上 stop 偶发崩;子进程反正要退出 */ }
|
|
17
|
-
process.exit(0)
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
process.exit(1)
|
|
21
|
-
}
|