| 72 | // --------------------------------------------------------------------------- |
| 73 | |
| 74 | function refreshDiscoveredPipes( |
| 75 | pipeName: string, |
| 76 | aliveSubs: Array<{ |
| 77 | id: string |
| 78 | pipeName: string |
| 79 | subIndex: number |
| 80 | machineId: string |
| 81 | ip: string |
| 82 | hostname: string |
| 83 | }>, |
| 84 | store: StoreApi, |
| 85 | ): void { |
| 86 | const freshDiscovered = aliveSubs |
| 87 | .filter(sub => sub.pipeName !== pipeName) |
| 88 | .map(sub => ({ |
| 89 | id: sub.id, |
| 90 | pipeName: sub.pipeName, |
| 91 | role: `sub-${sub.subIndex}`, |
| 92 | machineId: sub.machineId, |
| 93 | ip: sub.ip, |
| 94 | hostname: sub.hostname, |
| 95 | alive: true, |
| 96 | })) |
| 97 | |
| 98 | // Include LAN beacon peers so they aren't wiped out by heartbeat |
| 99 | let lanDiscovered: typeof freshDiscovered = [] |
| 100 | if (feature('LAN_PIPES')) { |
| 101 | const beacon = lb.getLanBeacon() |
| 102 | if (beacon) { |
| 103 | const localNames = new Set(freshDiscovered.map(p => p.pipeName)) |
| 104 | localNames.add(pipeName) |
| 105 | for (const [pName, peer] of beacon.getPeers()) { |
| 106 | if (!localNames.has(pName)) { |
| 107 | lanDiscovered.push({ |
| 108 | id: `lan-${pName}`, |
| 109 | pipeName: pName, |
| 110 | role: peer.role, |
| 111 | machineId: peer.machineId, |
| 112 | ip: peer.ip, |
| 113 | hostname: peer.hostname, |
| 114 | alive: true, |
| 115 | }) |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | const allDiscovered = [...freshDiscovered, ...lanDiscovered] |
| 122 | |
| 123 | // Only update state if the list actually changed |
| 124 | const prev = pt.getPipeIpc(store.getState()) |
| 125 | const prevNames = (prev.discoveredPipes ?? []) |
| 126 | .map((p: any) => p.pipeName) |
| 127 | .join(',') |
| 128 | const newNames = allDiscovered.map(p => p.pipeName).join(',') |
| 129 | if (prevNames === newNames) return |
| 130 | |
| 131 | store.setState((prev: any) => { |