dsh-mesh-ui 0.0.4 → 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.
Files changed (2) hide show
  1. package/lib/collect.js +19 -4
  2. package/package.json +1 -1
package/lib/collect.js CHANGED
@@ -14,7 +14,7 @@
14
14
  // 归宿:reusable(dsh-mesh/plugin/dsh-mesh-ui/lib/collect.js)
15
15
 
16
16
  import { execFile } from 'node:child_process'
17
- import { existsSync, readdirSync, readFileSync, statfsSync } from 'node:fs'
17
+ import { existsSync, readdirSync, readFileSync, statfsSync, writeFileSync } from 'node:fs'
18
18
  import { lookup as dnsLookup } from 'node:dns/promises'
19
19
  import { arch as osArch, cpus as osCpus, freemem as osFreemem, homedir, platform as osPlatform, release as osRelease, totalmem as osTotalmem } from 'node:os'
20
20
  import { join } from 'node:path'
@@ -439,12 +439,17 @@ export async function collect(repo) {
439
439
  list.push({ id: inst.id, port: 3080 + idx, up: Boolean(inst.up) })
440
440
  }
441
441
 
442
- // 远端节点:host_self 并发(单调用超时 6s)
442
+ // 远端节点:host_self 并发(超时放宽到 12s —— 跨公网节点 6s 偶尔不够,会导致硬件字段丢失)
443
443
  const meshPeers = mesh.peers || []
444
444
  const peerSelfs = await Promise.all(meshPeers.map(async (peer) => {
445
445
  if (!peer.up) return null
446
- return await cliJson(repo, ['peer', 'call', 'host_self', '--to', peer.name, '--args', '{}'], { timeout: 6000 })
446
+ return await cliJson(repo, ['peer', 'call', 'host_self', '--to', peer.name, '--args', '{}'], { timeout: 12000 })
447
447
  }))
448
+ // 硬件缓存:跨公网 host_self 偶发超时时,用上次成功结果兜底,避免面板时有时无
449
+ const HW_CACHE_FILE = join(meshHome(), 'peer-hardware.json')
450
+ let hwCache = {}
451
+ try { hwCache = JSON.parse(readFileSync(HW_CACHE_FILE, 'utf8')) || {} } catch { hwCache = {} }
452
+ const devKeyOf = (name) => String(name || '').toLowerCase().replace(/-(lan|wan|exec|exe|import|local|ctl)$/i, '')
448
453
  const peers = meshPeers.map((peer, index) => {
449
454
  const self = unwrapPeerCall(peerSelfs[index])
450
455
  const stats = agentStats(self?.agents)
@@ -460,7 +465,7 @@ export async function collect(repo) {
460
465
  sessions: stats.sessions,
461
466
  running: stats.running,
462
467
  hostname: self?.node?.hostname || '',
463
- hardware: self?.hardware || null,
468
+ hardware: self?.hardware || hwCache[devKeyOf(peer.name)] || null,
464
469
  release: self?.node?.release || '',
465
470
  os: osLabel(self?.node?.platform, self?.node?.release),
466
471
  uptimeSec: overviewByNode[peer.name]?.uptimeSec ?? null,
@@ -473,6 +478,16 @@ export async function collect(repo) {
473
478
  error: peer.error?.code || null
474
479
  }
475
480
  })
481
+ // 同一设备可能有多个入口(company / company-exec / -lan / -wan):硬件信息互通,
482
+ // 避免 UI 去重时选中了恰好没有 hardware 的那条记录。
483
+ const hwByDev = {}
484
+ for (const p of peers) { const k = devKeyOf(p.name); if (p.hardware) hwByDev[k] = p.hardware }
485
+ for (const p of peers) {
486
+ const k = devKeyOf(p.name)
487
+ if (!p.hardware && hwByDev[k]) p.hardware = hwByDev[k]
488
+ if (p.hardware) hwCache[k] = p.hardware
489
+ }
490
+ try { writeFileSync(HW_CACHE_FILE, JSON.stringify(hwCache, null, 1)) } catch { /* 缓存写失败不影响主流程 */ }
476
491
 
477
492
  // 2026-11-10:LAN 链路要显示 IP(不是主机名)→ 对域名型 tunnel.host 做一次 DNS 解析(800ms 超时,失败则回落主机名)
478
493
  function isIpLiteral(host) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mesh-ui",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "DSH settings-page panel for dsh-mesh: AI network topology, peer health, and delegation panel. Read-only; data is collected from the local mesh CLI.",
5
5
  "icon": "icon.svg",
6
6
  "type": "module",