collabSupport/integrations/cisco-mpp-phone/downloadStatusJson.js
jmcqueen f7953b8eb5 Add MPP desk phone diagnostics follow-up to /phonestatus via relay.
Wire CP-78xx probe discovery, relay phone-probe commands, and a chat follow-up message so store desk phones get registration, switch, and provisioning detail alongside DECT and WAN diagnostics.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-28 18:01:01 -04:00

90 lines
2.9 KiB
JavaScript

// integrations/cisco-mpp-phone/downloadStatusJson.js
//
// Parser for /Download%20Status.json (provisioning + firmware history).
import { coerceRows, fieldsFromRows, extractIndexed } from './jsonRows.js';
/**
* @param {string|Array} raw
* @returns {object}
*/
export function parseDownloadStatusJson(raw) {
const rows = coerceRows(raw);
const fields = fieldsFromRows(rows);
const firmwareUpgrades = extractIndexed(fields, /^Firmware Upgrade Status \d+$/i);
const provisioning = extractIndexed(fields, /^Provisioning Status \d+$/i);
const transitionAuth = extractIndexed(fields, /^Transition Authorization Status \d+$/i);
const micCertStatus = fields['MIC Cert Provisioning Status'] || null;
const micCertInfo = fields['MIC Cert Info'] || null;
return {
fields,
latestFirmwareUpgrade: parseHistoryEntry(firmwareUpgrades[0]),
latestProvisioning: parseHistoryEntry(provisioning[0]),
latestTransitionAuth: parseHistoryEntry(transitionAuth[0]),
firmwareUpgrades: firmwareUpgrades.map(parseHistoryEntry).filter(Boolean),
provisioningHistory: provisioning.map(parseHistoryEntry).filter(Boolean),
micCert: {
provisioningStatus: micCertStatus,
info: micCertInfo,
failed: !!(micCertStatus && /fail/i.test(micCertStatus)),
},
};
}
/**
* Parse "[timestamp][url]Result." or "[seq][timestamp][url]Result." entries.
* @param {string|null} raw
*/
export function parseHistoryEntry(raw) {
if (!raw || typeof raw !== 'string') return null;
const trimmed = raw.trim();
if (!trimmed) return null;
const triple = trimmed.match(/^\[([^\]]*)\]\[([^\]]*)\]\[([^\]]*)\](.+)$/);
if (triple && looksLikeUrl(triple[3])) {
return buildEntry(trimmed, triple[2], triple[3], triple[4]);
}
const double = trimmed.match(/^\[([^\]]*)\]\[([^\]]*)\](.+)$/);
if (double) {
if (looksLikeUrl(double[2])) {
return buildEntry(trimmed, double[1], double[2], double[3]);
}
return buildEntry(trimmed, null, double[1], double[2]);
}
return buildEntry(trimmed, null, null, trimmed);
}
function looksLikeUrl(s) {
return typeof s === 'string' && (/^https?:\/\//i.test(s) || /\.[a-z]{2,}/i.test(s));
}
function buildEntry(raw, timestamp, url, resultPart) {
const result = (resultPart || '').trim();
return {
raw,
timestamp: timestamp || null,
url: url || null,
result: result || null,
succeeded: /succeed/i.test(result),
failed: /fail/i.test(result),
};
}
export function downloadStatusWarnings(download) {
const warnings = [];
if (!download) return warnings;
if (download.micCert?.failed) {
warnings.push(`MIC cert: ${download.micCert.provisioningStatus}`);
}
if (download.latestProvisioning?.failed) {
warnings.push(`provisioning: ${download.latestProvisioning.result}`);
}
if (download.latestFirmwareUpgrade?.failed) {
warnings.push(`firmware upgrade: ${download.latestFirmwareUpgrade.result}`);
}
return warnings;
}