/* jshint esversion: 2024, module: true */ import { InterfaceState } from "./enums.js"; /** * Static utility functions * @module Utils */ class Utils { /** * Convert byte array to MAC address * @static * @param {Array} bytes - Byte array * @returns {string} MAC address */ static arrayToMac(bytes) { if (!Array.isArray(bytes)) return ""; return bytes.map((byte) => byte.toString(16).padStart(2, "0")).join(":"); } /** * Convert byte array to IP address * @static * @param {Array|Object} obj - IP data * @returns {string} IP address */ static ipFromArray(obj) { let bytes = null; if (Array.isArray(obj)) { bytes = obj; } else if (obj?.Address && Array.isArray(obj.Address)) { bytes = obj.Address; } else { return ""; } // IPv4 if (bytes.length === 4) { return bytes.join("."); } // IPv6 if (bytes.length === 16) { const parts = []; for (let i = 0; i < 16; i += 2) { parts.push(((bytes[i] << 8) | bytes[i + 1]).toString(16)); } return parts .join(":") .replace(/(^|:)0+/g, "$1") .replace(/:{3,}/, "::"); } return ""; } /** * Convert route object to string * @static * @param {Object} route - Route object * @returns {string} Route string */ static routeToString(route) { if (!route) return ""; const destination = route.Destination ? Utils.ipFromArray(route.Destination) : "default"; const gateway = route.Gateway ? Utils.ipFromArray(route.Gateway) : ""; return gateway ? `${destination} → ${gateway}` : destination; } /** * Get interface state from interface object * @static * @param {Object} iface - Interface object * @returns {Symbol} Interface state */ static getInterfaceState(iface) { const state = iface.OperationalState ?? iface.AdministrativeState ?? iface.State ?? ""; const stateLower = state.toLowerCase(); if ( stateLower.includes("up") || stateLower.includes("routable") || stateLower.includes("configured") ) { return InterfaceState.UP; } else if (stateLower.includes("down") || stateLower.includes("off")) { return InterfaceState.DOWN; } else { return InterfaceState.UNKNOWN; } } /** * Get CSS class for interface state * @static * @param {Symbol} state - Interface state * @returns {string} CSS class */ static getStateClass(state) { switch (state) { case InterfaceState.UP: return "state-up"; case InterfaceState.DOWN: return "state-down"; default: return "state-unknown"; } } /** * Get display text for interface state * @static * @param {Object} iface - Interface object * @returns {string} State text */ static getStateText(iface) { return ( iface.OperationalState ?? iface.AdministrativeState ?? iface.State ?? "unknown" ); } /** * Sanitize HTML string * @static * @param {string} str - String to sanitize * @returns {string} Sanitized string */ static sanitizeHTML(str) { const div = document.createElement("div"); div.textContent = str; return div.innerHTML; } /** * Create DOM element from HTML string * @static * @param {string} html - HTML string * @returns {HTMLElement} DOM element */ static createElementFromHTML(html) { const template = document.createElement("template"); template.innerHTML = html.trim(); return template.content.firstElementChild; } /** * Debounce function * @static * @param {Function} func - Function to debounce * @param {number} wait - Wait time in ms * @returns {Function} Debounced function */ static debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } /** * Safely convert any value to display string * @static * @param {*} value - Any value * @returns {string} Safe display string */ static safeToString(value) { if (value === null || value === undefined) return ""; if (typeof value === "string") return value; if (typeof value === "number" || typeof value === "boolean") return String(value); if (Array.isArray(value)) { return value.map((item) => Utils.safeToString(item)).join(", "); } if (typeof value === "object") { // Handle IP address objects if (value.Address && Array.isArray(value.Address)) { return Utils.ipFromArray(value); } // Try to stringify simple objects try { const simpleObj = {}; for (const [key, val] of Object.entries(value)) { if (val !== null && val !== undefined && typeof val !== "object") { simpleObj[key] = val; } } if (Object.keys(simpleObj).length > 0) { return JSON.stringify(simpleObj); } } catch (e) { // Fall through } return String(value); } return String(value); } } export { Utils };