UNPKG

lup-system

Version:

NodeJS library to retrieve system information and utilization.

313 lines (312 loc) 11.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.execCommand = execCommand; exports.parseByteValue = parseByteValue; exports.parseDate = parseDate; exports.processKeyValueString = processKeyValueString; exports.sleep = sleep; const child_process_1 = require("child_process"); /** * Runs a shell command and returns the output. * * @param command Command to execute in the shell. * @returns Stdout and stderr output of the command. */ async function execCommand(command) { return new Promise((resolve, reject) => { let output = ''; const child = (0, child_process_1.exec)(command, { windowsHide: true }); child.stdout?.on('data', (data) => { output += data.toString(); }); child.stderr?.on('data', (data) => { output += data.toString(); }); child.on('close', (code) => { if (code === 0) { resolve(output); } else { reject(new Error(`Command failed with exit code ${code}: ${output}`)); } }); }); } /** * Parses a byte value from a string. * * @param value String representation of a byte value (e.g., "100MB", "2GB"). * @returns The parsed byte value as a number. */ function parseByteValue(value) { if (!value) return 0; value = value.trim(); let i = 0; // extract numeric part let numStr = ''; let hasDot = false; for (; i < value.length; i++) { const c = value[i]; if (c === '0' || c === '1' || c === '2' || c === '3' || c === '4' || c === '5' || c === '6' || c === '7' || c === '8' || c === '9') { numStr += c; } else if ((c === '.' || c === ',') && !hasDot) { hasDot = true; numStr += c; } else { break; // stop at first non-numeric character } } const num = hasDot ? parseFloat(numStr) : parseInt(numStr, 10); if (isNaN(num)) return num; // extract unit value = value.substring(i).trim().toLowerCase().split(' ')[0]; value = value.replace(/[^a-z]/g, ''); // remove non-alphabetic characters if (value === 'b' || value === 'bytes' || value === 'byte') return num; if (value === 'kb' || value === 'kilobyte' || value === 'kilobytes') return num * 1000; if (value === 'mb' || value === 'megabyte' || value === 'megabytes') return num * 1000 * 1000; if (value === 'gb' || value === 'gigabyte' || value === 'gigabytes') return num * 1000 * 1000 * 1000; if (value === 'tb' || value === 'terabyte' || value === 'terabytes') return num * 1000 * 1000 * 1000 * 1000; if (value === 'kib' || value === 'kibibyte' || value === 'kibibytes') return num * 1024; if (value === 'mib' || value === 'mebibyte' || value === 'mebibytes') return num * 1024 * 1024; if (value === 'gib' || value === 'gibibyte' || value === 'gibibytes') return num * 1024 * 1024 * 1024; if (value === 'tib' || value === 'tebibyte' || value === 'tebibytes') return num * 1024 * 1024 * 1024 * 1024; // unknown unit, return as bytes return num; } /** * Tries to parse a string as a date. * * @param dateString String to parse as a date. * @returns Date object if parsing is successful, otherwise null. */ function parseDate(dateString) { if (!dateString) return null; dateString = dateString.trim(); if (dateString.startsWith('/') || dateString.startsWith('\\')) { return null; } // try direct parsing try { const date = new Date(dateString); if (date && !isNaN(date.getTime())) { return date; } // tslint:disable-next-line:no-empty } catch { } // special case: 2025-04-13 22:02:39 +0200 CEST try { const parts = dateString.split(' '); if (parts.length === 4) { const date = new Date(parts.slice(0, 3).join(' ')); if (date && !isNaN(date.getTime())) { return date; } } // tslint:disable-next-line:no-empty } catch { } return null; // Return null if parsing fails } /** * Processes a string of key-value pairs separated by a specified separator. * Values can be values, strings, numbers, dates, or JSON objects/arrays. * * @param keyValueString String to process containing key-value pairs. * @param pairSeparator The separator between key-value pairs (default is ','). * @param keyValueSeparator The separator between keys and values (default is '='). * @returns An object with keys and their corresponding values. */ function processKeyValueString(keyValueString, pairSeparator = ',', keyValueSeparator = '=') { const result = {}; function skipWhitespace(offset) { // skip leading whitespace while (offset < keyValueString.length && /\s/.test(keyValueString[offset])) offset++; return offset; } function determineEndOfJson(offset) { offset = skipWhitespace(offset); // string if (keyValueString[offset] === '"' || keyValueString[offset] === "'") { const quote = keyValueString[offset]; for (let i = offset + 1; i < keyValueString.length; i++) { const c = keyValueString[i]; if (c === quote) { // end of quoted value return i + 1; } if (c === '\\') { i++; // skip next escaped character } } return keyValueString.length; // unclosed quote, return rest of string } // object if (keyValueString[offset] === '{') { offset++; while (true) { offset = determineEndOfJson(offset); // parses key as string offset = keyValueString.indexOf(':', offset); if (offset < 0 || offset >= keyValueString.length) { throw new Error('Invalid JSON object: missing value after key'); } offset = determineEndOfJson(offset + 1); // parse any json value offset = skipWhitespace(offset); if (keyValueString[offset] === '}') { return offset + 1; // end of JSON object } else if (keyValueString[offset] === ',') { offset++; // skip comma } else { throw new Error('Invalid JSON object: expected "}" or ","'); } } } // array if (keyValueString[offset] === '[') { offset++; while (true) { offset = determineEndOfJson(offset); // parses value as string offset = skipWhitespace(offset); if (keyValueString[offset] === ']') { return offset + 1; // end of JSON array } else if (keyValueString[offset] === ',') { offset++; // skip comma } else { throw new Error('Invalid JSON array: expected "]" or ","'); } } } // number or boolean for (let i = offset; i < keyValueSeparator.length; i++) { const c = keyValueString[i]; if (c === ',' || c === '}' || c === ']') { // end of number or boolean value return i; } } return keyValueString.indexOf(pairSeparator, offset); } function parseValue(offset) { offset = skipWhitespace(offset); let end; // parse JSON if (keyValueString[offset] === '{' || keyValueString[offset] === '[' || keyValueString[offset] === '"' || keyValueString[offset] === "'") { const start = offset; end = determineEndOfJson(offset); const jsonString = keyValueString.substring(start, end); try { return [JSON.parse(jsonString), end]; } catch { return [jsonString, end]; // return as string if JSON parsing fails } } // try to parse boolean, null, or number end = keyValueString.indexOf(pairSeparator, offset); if (end === offset) return ['', end]; // empty value end = end < 0 ? keyValueString.length : end; const valueString = keyValueString.substring(offset, end).trim(); const valueStringLower = valueString.toLowerCase(); if (valueStringLower === 'true' || valueStringLower === 'enabled' || valueStringLower === 'on') return [true, end]; if (valueStringLower === 'false' || valueStringLower === 'disabled' || valueStringLower === 'off') return [false, end]; if (valueStringLower === 'null' || valueStringLower === 'none' || valueStringLower === 'undefined') return [null, end]; try { const integer = parseInt(valueString, 10); if (!isNaN(integer)) return [integer, end]; // tslint:disable-next-line:no-empty } catch { } try { const float = parseFloat(valueString); if (!isNaN(float)) return [float, end]; // tslint:disable-next-line:no-empty } catch { } // try to parse Date let date = parseDate(valueString); if (date) return [date, end]; if (pairSeparator === ',') { // maybe date contains pairSeparator const end2 = keyValueString.indexOf(pairSeparator, end + 1); if (end2 > end) { date = parseDate(keyValueString.substring(offset, end2)); if (date) return [date, end2]; } } // if no other type matches, return as string return [valueString, end]; // return as string if no other type matches } for (let i = 0; i < keyValueString.length;) { const keyStart = i; const keyEnd = keyValueString.indexOf(keyValueSeparator, keyStart); let key; if (keyEnd < 0 || keyEnd >= keyValueString.length) { key = keyValueString.substring(keyStart).trim(); if (key.length > 0) { result[key] = ''; } break; } key = keyValueString.substring(keyStart, keyEnd).trim(); i = keyEnd + keyValueSeparator.length; // end of value must be determined semantically because value itself can contain the pair separator const valueStart = i; const [value, valueEnd] = parseValue(valueStart); result[key] = value; i = skipWhitespace(valueEnd); if (i < keyValueString.length && keyValueString[i] === pairSeparator) { i++; // skip pair separator } } return result; } /** * Pauses execution for a specified duration. * * @param ms Duration to sleep in milliseconds. * @returns A promise that resolves after the specified duration. */ async function sleep(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); }