feat(demo): mock WRT/TollGate gateway as thoroughly used + nostr discovery data

- openwrt.get-status/scan/scan-wifi/provision-tollgate/configure-wan
  mocked: 19-day-uptime GL-MT3000 TollGate gateway, two open TollGate
  SSIDs + private SSID, live upstream WAN, 21 sat/min pricing (edits
  via the reconfigure form persist in mock state)
- handshake.discover returns 4 discoverable nodes; nostr.set-discovery/
  discovery-status stateful; handshake.connect + pending-request
  approve/reject round-trip against mock state (incl. one inbound
  request for the demo)
- node-nostr-discover (Web5) list grown to 5 nodes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago 2026-07-14 06:40:26 -04:00
parent a8b00e97b6
commit 0f1d219357

View File

@ -223,6 +223,25 @@ function seedMockState() {
return {
analyticsEnabled: false,
nodeVisibility: 'discoverable',
nostrDiscovery: true,
pendingPeerRequests: [
{
id: 'preq-demo-1',
from_nostr_pubkey: '7e2a9c4b1d8f3a6c5e0b9d2f7a4c1e8b3d6f9a2c5e8b1d4f7a0c3e6b9d2f5a8c',
from_nostr_npub: 'npub1demo0inbound0request0xyzq',
from_did: 'did:key:z6MkwPn5xQc8vT2sLb6eRu9dYf3gHa7mJzK1oDiW4nXvE8tq',
from_name: 'basement-node',
message: 'Hey — saw your node on the relay, mind if we peer?',
received_at: new Date(Date.now() - 45 * 60000).toISOString(),
state: 'pending',
outbound: false,
},
],
tollgateEnabled: true,
tollgatePrice: 21,
tollgateStepMs: 60000,
tollgateMinSteps: 5,
tollgateMint: 'https://mint.archy.demo',
cashuMints: [
'https://mint.minibits.cash/Bitcoin',
'https://stablenut.umint.cash',
@ -2447,6 +2466,9 @@ app.post('/rpc/v1', (req, res) => {
nodes: [
{ did: 'did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2ReMkBe4bR6XBIDNq9', onion: 'disc1abc2def3ghi4jkl5mno6pqr7stu8vwx9yz.onion', pubkey: 'disc1pub', node_address: '192.168.1.50' },
{ did: 'did:key:z6MkpTHR8VNsBxYAAWHut2Geadd9jSwuBV8xRoAnwWsdvktH', onion: 'disc2xyz9wvu8tsr7qpo6nml5kji4hgf3edc2ba.onion', pubkey: 'disc2pub', node_address: '192.168.1.51' },
{ did: 'did:key:z6MkfV2sQpXm4d8YtR1nWc7uHb3eKj9gLa5xPzD6oTiN8rEw', onion: 'disc3mn04pq15rs26tu37vw48xy59za60bc71de.onion', pubkey: 'disc3pub', node_address: '192.168.1.72' },
{ did: 'did:key:z6MkrJ8pWx2yNc5vT9qLb4eHu7dKf1gMa3sPzE6oXiQ8nRvw', onion: 'disc4fg82hi93jk04lm15no26pq37rs48tu59vw.onion', pubkey: 'disc4pub', node_address: '100.72.19.44' },
{ did: 'did:key:z6MkhT4wQn8xPc2vL6sRb9eYu3dJf7gKa1mNzD5oWiE8tXvq', onion: 'disc5xy60za71bc82de93fg04hi15jk26lm37no.onion', pubkey: 'disc5pub', node_address: '100.101.7.23' },
],
},
})
@ -3665,6 +3687,134 @@ app.post('/rpc/v1', (req, res) => {
return res.json({ result: { node_id: nodeId, history } })
}
// ── OpenWRT / TollGate gateway (demo: a thoroughly-used gateway) ──
case 'openwrt.get-status': {
return res.json({
result: {
host: '192.168.8.1',
hostname: 'archy-tollgate',
uptime_secs: 19 * 86400 + 7 * 3600 + 42 * 60,
release: {
openwrt_release: 'OpenWrt 24.10.1',
openwrt_version: 'r28597-0425664679',
openwrt_board_name: 'glinet,gl-mt3000',
openwrt_arch: 'aarch64_cortex-a53',
openwrt_target: 'mediatek/filogic',
},
tollgate: {
installed: true,
enabled: mockState.tollgateEnabled,
metric: 'milliseconds',
step_size_ms: mockState.tollgateStepMs,
price_per_step: mockState.tollgatePrice,
min_steps: mockState.tollgateMinSteps,
currency: 'sat',
mint_url: mockState.tollgateMint,
},
wifi_interfaces: [
{ section: 'default_radio0', ssid: 'TollGate-⚡-2.4G', device: 'radio0', encryption: 'none', network: 'lan', disabled: false },
{ section: 'default_radio1', ssid: 'TollGate-⚡-5G', device: 'radio1', encryption: 'none', network: 'lan', disabled: false },
{ section: 'wifinet2', ssid: 'Archy-Private', device: 'radio1', encryption: 'sae', network: 'lan', disabled: false },
],
wan: {
configured: true,
ssid: 'CasaDelSol-5G',
assoc_ssid: 'CasaDelSol-5G',
encryption: 'psk2',
ip: '192.168.1.187',
internet: true,
radio0_disabled: false,
sta_iface: 'wifinet1',
sta_state: 'COMPLETED',
wifi_log: 'wlan1: associated -> COMPLETED (RSSI -52 dBm)',
lan_ip: '172.16.0.1',
lan_netmask: '255.255.255.0',
dhcp_start: '100',
dhcp_limit: '150',
masq: true,
},
},
})
}
case 'openwrt.scan': {
return res.json({ result: { routers: ['192.168.8.1'] } })
}
case 'openwrt.scan-wifi': {
return res.json({
result: {
networks: [
{ ssid: 'CasaDelSol-5G', bssid: 'a4:3e:51:0b:77:21', signal: -52, channel: 44, encryption: 'psk2' },
{ ssid: 'CasaDelSol', bssid: 'a4:3e:51:0b:77:20', signal: -49, channel: 6, encryption: 'psk2' },
{ ssid: 'Vodafone-B221', bssid: '5c:35:3b:9a:12:f0', signal: -71, channel: 1, encryption: 'psk2' },
{ ssid: 'cafe-guest', bssid: '10:27:f5:c4:88:3a', signal: -78, channel: 11, encryption: 'none' },
],
},
})
}
case 'openwrt.provision-tollgate': {
if (params?.price_per_step != null) mockState.tollgatePrice = params.price_per_step
if (params?.step_size_ms != null) mockState.tollgateStepMs = params.step_size_ms
if (params?.min_steps != null) mockState.tollgateMinSteps = params.min_steps
if (params?.mint_url) mockState.tollgateMint = params.mint_url
if (params?.enabled != null) mockState.tollgateEnabled = !!params.enabled
return res.json({ result: { ok: true } })
}
case 'openwrt.configure-wan': {
return res.json({ result: { ok: true } })
}
// ── Nostr peer discovery (demo) ──────────────────────────────────
case 'nostr.discovery-status': {
return res.json({ result: { enabled: mockState.nostrDiscovery } })
}
case 'nostr.set-discovery': {
mockState.nostrDiscovery = !!params?.enabled
return res.json({ result: { enabled: mockState.nostrDiscovery } })
}
case 'handshake.discover': {
return res.json({
result: {
nodes: [
{ nostr_pubkey: '8f1c9a2b7d4e6f0a3c5b8d1e4f7a0c3b6e9d2f5a8b1c4e7d0a3f6c9b2e5d8a1f', nostr_npub: 'npub13uwf52m04893s79hxc7fmz57jd60jz4kd3nk28h5t2rr3l2xkq0qte0mfz', did: 'did:key:z6MkfV2sQpXm4d8YtR1nWc7uHb3eKj9gLa5xPzD6oTiN8rEw', version: '1.7.99' },
{ nostr_pubkey: '2a4c6e8f0b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a', nostr_npub: 'npub1z5jvknq0k8f7am7wp0946fmdxu2yjkzr8mfw2n0lqv4tksz3xy8s5c9m2d', did: 'did:key:z6MkrJ8pWx2yNc5vT9qLb4eHu7dKf1gMa3sPzE6oXiQ8nRvw', version: '1.7.99' },
{ nostr_pubkey: '5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d', nostr_npub: 'npub1t9k2vfmq7x8n3a5wj0c4bz6y1d8s2e7r5m9p0l3q6u4i8o2h7g1f5x9c3vk', did: 'did:key:z6MkhT4wQn8xPc2vL6sRb9eYu3dJf7gKa1mNzD5oWiE8tXvq', version: '1.7.98' },
{ nostr_pubkey: '9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e', nostr_npub: 'npub1w3e8rkmq2x7n9a4vj5c0bz1y6d3s8e2r7m4p9l0q5u8i3o6h2g7f1x4c9vs', did: 'did:key:z6MkgS9wPm3xNc7vK2sQb5eTu8dHf4gJa6mLzD1oXiR8nEvw', version: '1.7.99' },
],
},
})
}
case 'handshake.connect': {
const reqId = `preq-${Date.now()}`
mockState.pendingPeerRequests.push({
id: reqId,
from_nostr_pubkey: params?.recipient_nostr_pubkey || 'unknown',
from_nostr_npub: 'npub1outbounddemo',
from_did: 'did:key:zOutboundDemo',
from_name: params?.name || null,
message: params?.message || null,
received_at: new Date().toISOString(),
state: 'pending',
outbound: true,
})
return res.json({ result: { ok: true, sent_to: params?.recipient_nostr_pubkey || '', id: reqId } })
}
case 'handshake.poll': {
return res.json({ result: { polled: 4, new_requests: [], applied_invites: [], rejected_outbound: [], skipped: [] } })
}
case 'federation.list-pending-requests': {
return res.json({ result: { requests: mockState.pendingPeerRequests } })
}
case 'federation.approve-request': {
const r = mockState.pendingPeerRequests.find((x) => x.id === params?.id)
if (r) r.state = 'approved'
return res.json({ result: { approved: true, id: params?.id || '' } })
}
case 'federation.reject-request': {
const r = mockState.pendingPeerRequests.find((x) => x.id === params?.id)
if (r) r.state = 'rejected'
return res.json({ result: { rejected: true, id: params?.id || '' } })
}
default: {
console.log(`[RPC] Unknown method: ${method}`)
return res.json({