Surface handset registrations and RSSI, tighten reboot health to 7 days, and consolidate Base / Handsets & RF / Network & RTP sections. Co-authored-by: Cursor <cursoragent@cursor.com>
91 lines
2.5 KiB
JavaScript
91 lines
2.5 KiB
JavaScript
// integrations/cisco-dect/statusXmlInventory.js
|
|
//
|
|
// Walk a parsed status.xml tree and list every leaf path with a short
|
|
// preview. Used by collect-raw tooling to spot populated sections
|
|
// (RSSI_List, Device_Presence, SIP_Identity_Status, etc.) without
|
|
// hand-reading XML.
|
|
|
|
import { xmlToObject } from './statusXml.js';
|
|
|
|
const HANDSET_RELATED = /rssi|presence|sip_identity|device_line|statistics|rpn|mac/i;
|
|
|
|
/**
|
|
* @typedef {object} SectionInventoryEntry
|
|
* @property {string} path dot-separated path from root
|
|
* @property {boolean} isEmpty true when leaf is absent or whitespace-only
|
|
* @property {string|null} preview truncated leaf value (null for empty containers)
|
|
* @property {boolean} handsetRelated heuristic flag for operator summaries
|
|
*/
|
|
|
|
/**
|
|
* Build a flat inventory of leaf paths from raw status.xml text.
|
|
*
|
|
* @param {string} xml
|
|
* @returns {SectionInventoryEntry[]}
|
|
*/
|
|
export function inventoryStatusXml(xml) {
|
|
if (typeof xml !== 'string' || !xml.trim()) return [];
|
|
const tree = xmlToObject(xml);
|
|
const entries = [];
|
|
walk(tree, '', entries);
|
|
return entries;
|
|
}
|
|
|
|
/**
|
|
* Summarize non-empty handset-related paths for console output.
|
|
*
|
|
* @param {SectionInventoryEntry[]} inventory
|
|
* @returns {{ nonEmpty: number, handsetRelated: number, paths: string[] }}
|
|
*/
|
|
export function summarizeInventory(inventory) {
|
|
const list = Array.isArray(inventory) ? inventory : [];
|
|
const nonEmpty = list.filter((e) => !e.isEmpty);
|
|
const handsetPaths = nonEmpty
|
|
.filter((e) => e.handsetRelated)
|
|
.map((e) => e.path);
|
|
return {
|
|
nonEmpty: nonEmpty.length,
|
|
handsetRelated: handsetPaths.length,
|
|
paths: handsetPaths,
|
|
};
|
|
}
|
|
|
|
function walk(node, prefix, out) {
|
|
if (node == null) {
|
|
pushLeaf(prefix, '', out);
|
|
return;
|
|
}
|
|
if (typeof node === 'string') {
|
|
pushLeaf(prefix, node, out);
|
|
return;
|
|
}
|
|
if (typeof node !== 'object') {
|
|
pushLeaf(prefix, String(node), out);
|
|
return;
|
|
}
|
|
const keys = Object.keys(node);
|
|
if (keys.length === 0) {
|
|
pushLeaf(prefix, '', out);
|
|
return;
|
|
}
|
|
for (const key of keys) {
|
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
walk(node[key], path, out);
|
|
}
|
|
}
|
|
|
|
function pushLeaf(path, value, out) {
|
|
const str = value == null ? '' : String(value).trim();
|
|
const isEmpty = str === '';
|
|
out.push({
|
|
path,
|
|
isEmpty,
|
|
preview: isEmpty ? null : truncate(str, 120),
|
|
handsetRelated: HANDSET_RELATED.test(path),
|
|
});
|
|
}
|
|
|
|
function truncate(s, max) {
|
|
if (s.length <= max) return s;
|
|
return `${s.slice(0, max - 1)}…`;
|
|
}
|