Some checks failed
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
291 lines
7.5 KiB
JavaScript
291 lines
7.5 KiB
JavaScript
"use strict";
|
||
|
||
/**
|
||
* 设备扩展数据存储(巡检相关配置)
|
||
*
|
||
* 关联 NetMesh 的主机数据,扩展巡检相关字段:
|
||
* - 设备类型(catalog_id)
|
||
* - 设备层级(core/aggregation/access)
|
||
* - 巡检周期
|
||
* - 启用状态
|
||
* - 自定义告警阈值
|
||
* - 上次巡检信息
|
||
*
|
||
* 周期优先级(从高到低):
|
||
* 1. 设备独立设置 inspection_interval
|
||
* 2. 设备层级的默认周期 DEVICE_TIER_DEFAULT_INTERVAL
|
||
* 3. 系统默认周期 SYS_CONFIG_DEFAULTS.inspection_default_interval
|
||
*/
|
||
|
||
const {
|
||
STORAGE_KEY_DEVICE_EXTENSION,
|
||
STORAGE_KEY_SYS_CONFIG,
|
||
} = require("./storageKeys.cjs");
|
||
const {
|
||
DEVICE_TIERS,
|
||
DEVICE_TIER_LABELS,
|
||
DEVICE_TIER_DEFAULT_INTERVAL,
|
||
SYS_CONFIG_DEFAULTS,
|
||
} = require("./types.cjs");
|
||
const { getPresetCatalog } = require("./deviceCatalogStore.cjs");
|
||
|
||
// ---------- 内存缓存 ----------
|
||
let _extensions = null; // { [hostId]: { ... } }
|
||
let _sysConfig = null; // { inspection_default_interval: 5, ... }
|
||
let _catalog = null; // 设备类型列表
|
||
|
||
/**
|
||
* 从存储加载数据(首次调用时加载,之后用缓存)
|
||
* @param {function} readFn - 读取函数 (key) => rawString
|
||
*/
|
||
function _ensureLoaded(readFn) {
|
||
if (_extensions === null) {
|
||
const raw = readFn(STORAGE_KEY_DEVICE_EXTENSION);
|
||
_extensions = raw ? _safeParse(raw, {}) : {};
|
||
}
|
||
if (_sysConfig === null) {
|
||
const raw = readFn(STORAGE_KEY_SYS_CONFIG);
|
||
_sysConfig = raw ? _safeParse(raw, {}) : { ...SYS_CONFIG_DEFAULTS };
|
||
// 合并默认值
|
||
for (const k of Object.keys(SYS_CONFIG_DEFAULTS)) {
|
||
if (_sysConfig[k] === undefined) _sysConfig[k] = SYS_CONFIG_DEFAULTS[k];
|
||
}
|
||
}
|
||
if (_catalog === null) {
|
||
_catalog = getPresetCatalog();
|
||
}
|
||
}
|
||
|
||
function _safeParse(text, def) {
|
||
if (text === null || text === undefined) return def;
|
||
let parsed;
|
||
try { parsed = JSON.parse(text); }
|
||
catch (e) { return def; }
|
||
// 防御二次/三次 stringify:inspectionStorage.writeStorage 先 JSON.stringify 一次,
|
||
// _save 又 JSON.stringify 一次 → 文件里值是 "\"{...}\"" 这种嵌套字符串
|
||
// 连续 parse 直到拿到真正的对象/数组(最多 3 层避免死循环)
|
||
let depth = 0;
|
||
while (typeof parsed === "string" && parsed.length > 0 && depth < 3) {
|
||
let next;
|
||
try { next = JSON.parse(parsed); } catch { break; }
|
||
if (typeof next === "string" && next === parsed) break;
|
||
parsed = next;
|
||
depth++;
|
||
}
|
||
return (parsed !== null && typeof parsed === "object") ? parsed : def;
|
||
}
|
||
|
||
function _save(writeFn, key, data) {
|
||
writeFn(key, JSON.stringify(data));
|
||
}
|
||
|
||
// ---------- 系统配置 ----------
|
||
|
||
/**
|
||
* 获取系统配置
|
||
*/
|
||
function getSysConfig(readFn) {
|
||
_ensureLoaded(readFn);
|
||
return { ..._sysConfig };
|
||
}
|
||
|
||
/**
|
||
* 更新系统配置
|
||
*/
|
||
function updateSysConfig(readFn, writeFn, updates) {
|
||
_ensureLoaded(readFn);
|
||
_sysConfig = { ..._sysConfig, ...updates };
|
||
_save(writeFn, STORAGE_KEY_SYS_CONFIG, _sysConfig);
|
||
return { ..._sysConfig };
|
||
}
|
||
|
||
// ---------- 设备扩展 ----------
|
||
|
||
/**
|
||
* 获取所有设备扩展配置
|
||
*/
|
||
function getAllExtensions(readFn) {
|
||
_ensureLoaded(readFn);
|
||
return { ..._extensions };
|
||
}
|
||
|
||
/**
|
||
* 获取单个设备的扩展配置
|
||
*/
|
||
function getExtension(readFn, hostId) {
|
||
_ensureLoaded(readFn);
|
||
return _extensions[hostId] || null;
|
||
}
|
||
|
||
/**
|
||
* 创建/更新设备扩展配置
|
||
* @param {string} hostId - NetMesh 主机 ID
|
||
* @param {object} data - 扩展配置
|
||
* @param {string} data.catalog_id - 设备类型 ID
|
||
* @param {string} [data.tier] - 设备层级 core/aggregation/access
|
||
* @param {number} [data.inspection_interval] - 巡检周期(分钟),null 表示继承
|
||
* @param {boolean} [data.inspection_enabled] - 是否启用巡检
|
||
* @param {object} [data.custom_thresholds] - 自定义告警阈值
|
||
* @param {string[]} [data.inspection_tags] - 巡检标签
|
||
* @param {string} [data.hostname] - 主机名(IP 或域名),用于调度器关联 vault host SSH 配置
|
||
*/
|
||
function upsertExtension(readFn, writeFn, hostId, data) {
|
||
_ensureLoaded(readFn);
|
||
|
||
const existing = _extensions[hostId] || {
|
||
host_id: hostId,
|
||
hostname: null,
|
||
catalog_id: "",
|
||
tier: null,
|
||
inspection_interval: null,
|
||
inspection_enabled: false,
|
||
custom_thresholds: [],
|
||
inspection_tags: [],
|
||
last_scan_at: null,
|
||
last_scan_status: null,
|
||
last_scan_error: null,
|
||
};
|
||
|
||
_extensions[hostId] = {
|
||
...existing,
|
||
...data,
|
||
updated_at: Date.now(),
|
||
};
|
||
|
||
_save(writeFn, STORAGE_KEY_DEVICE_EXTENSION, _extensions);
|
||
return { ..._extensions[hostId] };
|
||
}
|
||
|
||
/**
|
||
* 删除设备扩展配置
|
||
*/
|
||
function deleteExtension(readFn, writeFn, hostId) {
|
||
_ensureLoaded(readFn);
|
||
if (_extensions[hostId]) {
|
||
delete _extensions[hostId];
|
||
_save(writeFn, STORAGE_KEY_DEVICE_EXTENSION, _extensions);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 计算设备的实际巡检周期(考虑三级继承)
|
||
* @param {string} hostId
|
||
* @returns {number} 周期(分钟)
|
||
*/
|
||
function getEffectiveInterval(readFn, hostId) {
|
||
_ensureLoaded(readFn);
|
||
const ext = _extensions[hostId];
|
||
if (!ext) return _sysConfig.inspection_default_interval;
|
||
|
||
// 1. 设备独立设置
|
||
if (typeof ext.inspection_interval === "number" && ext.inspection_interval > 0) {
|
||
return ext.inspection_interval;
|
||
}
|
||
|
||
// 2. 设备层级默认
|
||
if (ext.tier && DEVICE_TIER_DEFAULT_INTERVAL[ext.tier]) {
|
||
return DEVICE_TIER_DEFAULT_INTERVAL[ext.tier];
|
||
}
|
||
|
||
// 3. 系统默认
|
||
return _sysConfig.inspection_default_interval;
|
||
}
|
||
|
||
/**
|
||
* 获取所有启用了巡检的设备列表(带有效周期)
|
||
*/
|
||
function getEnabledDevices(readFn) {
|
||
_ensureLoaded(readFn);
|
||
const result = [];
|
||
|
||
for (const hostId of Object.keys(_extensions)) {
|
||
const ext = _extensions[hostId];
|
||
if (ext.inspection_enabled) {
|
||
result.push({
|
||
...ext,
|
||
effective_interval: getEffectiveInterval(readFn, hostId),
|
||
});
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* 更新上次巡检信息
|
||
*/
|
||
function updateLastScan(readFn, writeFn, hostId, status, error = null) {
|
||
_ensureLoaded(readFn);
|
||
if (!_extensions[hostId]) return false;
|
||
|
||
_extensions[hostId].last_scan_at = Date.now();
|
||
_extensions[hostId].last_scan_status = status;
|
||
_extensions[hostId].last_scan_error = error;
|
||
|
||
_save(writeFn, STORAGE_KEY_DEVICE_EXTENSION, _extensions);
|
||
return true;
|
||
}
|
||
|
||
// ---------- 设备类型 ----------
|
||
|
||
/**
|
||
* 获取设备类型列表
|
||
*/
|
||
function getCatalog() {
|
||
if (_catalog === null) {
|
||
_catalog = getPresetCatalog();
|
||
}
|
||
return [..._catalog];
|
||
}
|
||
|
||
/**
|
||
* 根据 ID 获取设备类型
|
||
*/
|
||
function getCatalogById(catalogId) {
|
||
const list = getCatalog();
|
||
return list.find((c) => c.id === catalogId) || null;
|
||
}
|
||
|
||
// ---------- 设备层级 ----------
|
||
|
||
/**
|
||
* 获取设备层级列表(带中文名称和默认周期)
|
||
*/
|
||
function getTiers() {
|
||
return [
|
||
{ key: DEVICE_TIERS.CORE, label: DEVICE_TIER_LABELS.core, default_interval: DEVICE_TIER_DEFAULT_INTERVAL.core },
|
||
{ key: DEVICE_TIERS.AGGREGATION, label: DEVICE_TIER_LABELS.aggregation, default_interval: DEVICE_TIER_DEFAULT_INTERVAL.aggregation },
|
||
{ key: DEVICE_TIERS.ACCESS, label: DEVICE_TIER_LABELS.access, default_interval: DEVICE_TIER_DEFAULT_INTERVAL.access },
|
||
];
|
||
}
|
||
|
||
// ---------- 重置(测试用) ----------
|
||
function _resetForTest() {
|
||
_extensions = null;
|
||
_sysConfig = null;
|
||
_catalog = null;
|
||
}
|
||
|
||
module.exports = {
|
||
// 系统配置
|
||
getSysConfig,
|
||
updateSysConfig,
|
||
// 设备扩展
|
||
getAllExtensions,
|
||
getExtension,
|
||
upsertExtension,
|
||
deleteExtension,
|
||
getEffectiveInterval,
|
||
getEnabledDevices,
|
||
updateLastScan,
|
||
// 设备类型
|
||
getCatalog,
|
||
getCatalogById,
|
||
// 设备层级
|
||
getTiers,
|
||
// 内部
|
||
_resetForTest,
|
||
};
|