gigafibre-fsm/services/targo-hub/lib/device-extractors.js
louispaulb 607ea54b5c refactor: reduce token count, DRY code, consolidate docs
Backend services:
- targo-hub: extract deepGetValue to helpers.js, DRY disconnect reasons
  lookup map, compact CAPABILITIES, consolidate vision.js prompts/schemas,
  extract dispatch scoring weights, trim section dividers across 9 files
- modem-bridge: extract getSession() helper (6 occurrences), resetIdleTimer(),
  consolidate DM query factory, fix duplicate username fill bug, trim headers
  (server.js -36%, tplink-session.js -47%, docker-compose.yml -57%)

Frontend:
- useWifiDiagnostic: extract THRESHOLDS const, split processDiagnostic into
  6 focused helpers (processOnlineStatus, processWanIPs, processRadios,
  processMeshNodes, processClients, checkRadioIssues)
- EquipmentDetail: merge duplicate ROLE_LABELS, remove verbose comments

Documentation (17 → 13 files, -1,400 lines):
- New consolidated README.md (architecture, services, dependencies, auth)
- Merge ECOSYSTEM-OVERVIEW into ARCHITECTURE.md
- Merge MIGRATION-PLAN + ARCHITECTURE-COMPARE + FIELD-GAP + CHANGELOG → MIGRATION.md
- Merge COMPETITIVE-ANALYSIS into PLATFORM-STRATEGY.md
- Update ROADMAP.md with current phase status
- Delete CONTEXT.md (absorbed into README)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 08:39:58 -04:00

130 lines
6.8 KiB
JavaScript

'use strict'
const { deepGetValue } = require('./helpers')
const findWanIp = d => {
const pub = extractAllInterfaces(d).find(i => i.role === 'internet')
return pub ? pub.ip : ''
}
const extractAllInterfaces = d => {
const ipIfaces = d.Device?.IP?.Interface
if (!ipIfaces) return []
const results = []
for (const ifKey of Object.keys(ipIfaces)) {
if (ifKey.startsWith('_')) continue
const iface = ipIfaces[ifKey]
if (!iface?.IPv4Address) continue
const name = iface.Name?._value || ''
for (const addrKey of Object.keys(iface.IPv4Address)) {
if (addrKey.startsWith('_')) continue
const addr = iface.IPv4Address[addrKey]
const ip = addr?.IPAddress?._value
if (!ip || ip === '0.0.0.0') continue
const status = addr.Status?._value
if (status && status !== 'Enabled') continue
const role = (ip.startsWith('192.168.') || (ip.startsWith('10.') && name === 'br0')) ? 'lan'
: (!ip.startsWith('10.') && !ip.startsWith('172.') && !ip.startsWith('192.168.') && !ip.startsWith('169.254.')) ? 'internet'
: (ip.startsWith('172.17.') || ip.startsWith('172.16.') || name.includes('_10')) ? 'management'
: 'service'
results.push({ iface: ifKey, name, ip, mask: addr.SubnetMask?._value || '', addrType: addr.AddressingType?._value || '', role })
}
}
return results
}
const countAllWifiClients = d => {
const aps = d.Device?.WiFi?.AccessPoint
if (!aps) return { direct: 0, mesh: 0, total: 0, perAp: [] }
let direct = 0, mesh = 0
const perAp = []
for (const k of Object.keys(aps)) {
if (k.startsWith('_') || !aps[k]) continue
const n = Number(aps[k].AssociatedDeviceNumberOfEntries?._value) || 0
const ssidRef = aps[k].SSIDReference?._value || ''
const ssidIdx = ssidRef.match(/SSID\.(\d+)/)
const idx = ssidIdx ? parseInt(ssidIdx[1]) : parseInt(k)
if (idx <= 8) direct += n; else mesh += n
if (n > 0) perAp.push({ ap: k, ssid: ssidRef, clients: n })
}
return { direct, mesh, total: direct + mesh, perAp }
}
const extractMeshTopology = d => {
const apDevices = d.Device?.WiFi?.MultiAP?.APDevice
if (!apDevices) return null
const nodes = []
let totalClients = 0
for (const dk of Object.keys(apDevices)) {
if (dk.startsWith('_')) continue
const dev = apDevices[dk]
if (!dev?._object) continue
const name = dev.X_TP_HostName?._value || ''
const mac = dev.MACAddress?._value || ''
let nodeClients = 0
for (const rk of Object.keys(dev.Radio || {})) {
if (rk.startsWith('_')) continue
for (const ak of Object.keys(dev.Radio[rk]?.AP || {})) {
if (ak.startsWith('_')) continue
nodeClients += Number(dev.Radio[rk].AP[ak]?.AssociatedDeviceNumberOfEntries?._value) || 0
}
}
totalClients += nodeClients
if (name || mac) nodes.push({ id: dk, name, active: dev.X_TP_Active?._value === true, mac, ip: dev.X_TP_IPAddress?._value || '', clients: nodeClients })
}
return nodes.length ? { nodes, totalClients } : null
}
const summarizeDevice = d => {
const g = path => deepGetValue(d, path)
const s = path => { const v = g(path); return v != null ? String(v) : '' }
const counts = countAllWifiClients(d)
const mesh = extractMeshTopology(d)
return {
_id: d._id,
serial: s('DeviceID.SerialNumber')
|| s('InternetGatewayDevice.DeviceInfo.SerialNumber')
|| s('Device.DeviceInfo.SerialNumber')
|| d.DeviceID?.SerialNumber?._value
|| (d._id ? decodeURIComponent(d._id.split('-').slice(2).join('-')) : '')
|| '',
manufacturer: s('DeviceID.Manufacturer') || d.DeviceID?.Manufacturer?._value || '',
model: s('DeviceID.ProductClass') || d.DeviceID?.ProductClass?._value || '',
oui: s('DeviceID.OUI') || d.DeviceID?.OUI?._value || '',
firmware: s('InternetGatewayDevice.DeviceInfo.SoftwareVersion') || s('Device.DeviceInfo.SoftwareVersion') || '',
uptime: g('InternetGatewayDevice.DeviceInfo.UpTime') || g('Device.DeviceInfo.UpTime') || null,
lastInform: d._lastInform || null, lastBoot: d._lastBootstrap || null, registered: d._registered || null,
interfaces: extractAllInterfaces(d),
ip: s('InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress') || findWanIp(d) || '',
rxPower: g('InternetGatewayDevice.WANDevice.1.X_GponInterafceConfig.RXPower')
|| g('InternetGatewayDevice.WANDevice.1.WANCommonInterfaceConfig.RXPower')
|| g('Device.Optical.Interface.1.Stats.SignalRxPower')
|| g('Device.Optical.Interface.1.OpticalSignalLevel') || null,
txPower: g('InternetGatewayDevice.WANDevice.1.X_GponInterafceConfig.TXPower')
|| g('InternetGatewayDevice.WANDevice.1.WANCommonInterfaceConfig.TXPower')
|| g('Device.Optical.Interface.1.Stats.SignalTxPower')
|| g('Device.Optical.Interface.1.TransmitOpticalLevel') || null,
pppoeUser: s('InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANPPPConnection.1.Username') || s('Device.PPP.Interface.1.Username') || '',
ssid: s('InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID') || s('Device.WiFi.SSID.1.SSID') || '',
macAddress: s('InternetGatewayDevice.WANDevice.1.WANEthernetInterfaceConfig.MACAddress') || s('Device.Ethernet.Interface.1.MACAddress') || '',
tags: d._tags || [],
opticalStatus: s('Device.Optical.Interface.1.Status') || null,
opticalErrors: { sent: g('Device.Optical.Interface.1.Stats.ErrorsSent') || 0, received: g('Device.Optical.Interface.1.Stats.ErrorsReceived') || 0 },
wifi: {
radio1: { status: s('Device.WiFi.Radio.1.Status') || null, channel: g('Device.WiFi.Radio.1.Channel') || null, bandwidth: s('Device.WiFi.Radio.1.CurrentOperatingChannelBandwidth') || null, noise: g('Device.WiFi.Radio.1.Stats.Noise') || null, clients: g('Device.WiFi.AccessPoint.1.AssociatedDeviceNumberOfEntries') || 0 },
radio2: { status: s('Device.WiFi.Radio.2.Status') || null, channel: g('Device.WiFi.Radio.2.Channel') || null, bandwidth: s('Device.WiFi.Radio.2.CurrentOperatingChannelBandwidth') || null, noise: g('Device.WiFi.Radio.2.Stats.Noise') || null, clients: g('Device.WiFi.AccessPoint.2.AssociatedDeviceNumberOfEntries') || 0 },
radio3: { status: s('Device.WiFi.Radio.3.Status') || null, channel: g('Device.WiFi.Radio.3.Channel') || null, clients: g('Device.WiFi.AccessPoint.3.AssociatedDeviceNumberOfEntries') || 0 },
totalClients: mesh ? mesh.totalClients : counts.total,
directClients: counts.direct,
meshClients: mesh ? (mesh.totalClients - counts.direct) : counts.mesh,
},
mesh: mesh ? mesh.nodes : null,
hostsCount: g('Device.Hosts.HostNumberOfEntries') || null,
ethernet: {
port1: { status: s('Device.Ethernet.Interface.1.Status') || null, speed: g('Device.Ethernet.Interface.1.MaxBitRate') || null },
port2: { status: s('Device.Ethernet.Interface.2.Status') || null, speed: g('Device.Ethernet.Interface.2.MaxBitRate') || null },
},
}
}
module.exports = { summarizeDevice }