add notice after config
This commit is contained in:
@@ -10,6 +10,9 @@ const { plotJson } = require("./plot-json");
|
||||
const VOLUME_FIELDS = [
|
||||
"q_in_val", "dt", "p_max", "fit_low", "fit_high", "T_delta", "xa_full", "num_runs"
|
||||
];
|
||||
const IDENTIFICATION_FIELDS = [
|
||||
"q_in_val", "dt", "n_order", "t_c", "levels", "dead_area", "xa_full", "V_val", "repeat"
|
||||
];
|
||||
const DEFAULT_API_URL = "https://ReinLoop.dominatedconvergence.com";
|
||||
const API_URL = process.env.REINLOOP_API_URL || DEFAULT_API_URL;
|
||||
const INBOX_POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS || 1000);
|
||||
@@ -35,13 +38,42 @@ function startPanelInboxPoller(window) {
|
||||
}
|
||||
|
||||
let polling = false;
|
||||
let notificationDeviceId = null;
|
||||
const deliveredNotificationIds = new Set();
|
||||
let notificationFailureReported = false;
|
||||
|
||||
async function pollNotifications(requestContext) {
|
||||
if (notificationDeviceId !== requestContext.deviceId) {
|
||||
notificationDeviceId = requestContext.deviceId;
|
||||
deliveredNotificationIds.clear();
|
||||
}
|
||||
const pending = await callServer(
|
||||
{ type: "getPendingPanelNotification", deviceId: requestContext.deviceId },
|
||||
requestContext
|
||||
);
|
||||
notificationFailureReported = false;
|
||||
const notification = pending.notification;
|
||||
if (!pending.pending || !notification?.notificationId) return;
|
||||
if (deliveredNotificationIds.has(notification.notificationId)) return;
|
||||
deliveredNotificationIds.add(notification.notificationId);
|
||||
window.webContents.send("panel:notification", notification);
|
||||
}
|
||||
|
||||
const poll = async () => {
|
||||
if (polling || window.isDestroyed()) return;
|
||||
if (!connectionState.deviceId || !connectionState.adminToken) return;
|
||||
if (pendingReview) return;
|
||||
const requestContext = { ...connectionState };
|
||||
polling = true;
|
||||
try {
|
||||
try {
|
||||
await pollNotifications(requestContext);
|
||||
} catch (error) {
|
||||
if (!notificationFailureReported) {
|
||||
console.warn(`[${new Date().toISOString()}] Panel 通知轮询不可用: ${error.message}`);
|
||||
notificationFailureReported = true;
|
||||
}
|
||||
}
|
||||
if (pendingReview) return;
|
||||
const pending = await callServer(
|
||||
{ type: "getPendingPanelFile", deviceId: requestContext.deviceId },
|
||||
requestContext
|
||||
@@ -128,7 +160,35 @@ function validateParameters(configType, parameters) {
|
||||
if (!Number.isInteger(parameters.num_runs)) {
|
||||
throw new Error("num_runs 必须是整数");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (configType === "identification") {
|
||||
const fields = Object.keys(parameters);
|
||||
const missing = IDENTIFICATION_FIELDS.filter((field) => !(field in parameters));
|
||||
const extra = fields.filter((field) => !IDENTIFICATION_FIELDS.includes(field));
|
||||
if (missing.length || extra.length) {
|
||||
throw new Error(`系统辨识配置字段不匹配。缺少: ${missing.join(", ") || "无"};多余: ${extra.join(", ") || "无"}`);
|
||||
}
|
||||
for (const field of IDENTIFICATION_FIELDS) {
|
||||
if (field === "levels") continue;
|
||||
if (typeof parameters[field] !== "number" || !Number.isFinite(parameters[field])) {
|
||||
throw new Error(`${field} 必须是有效数字`);
|
||||
}
|
||||
}
|
||||
if (!Array.isArray(parameters.levels) || parameters.levels.some((value) => typeof value !== "number" || !Number.isFinite(value))) {
|
||||
throw new Error("levels 必须是有效数字数组");
|
||||
}
|
||||
if (parameters.levels.length < 2 || (parameters.levels.length & (parameters.levels.length - 1)) !== 0) {
|
||||
throw new Error("levels 元素个数必须是不小于 2 的 2 的整数次幂");
|
||||
}
|
||||
if (!Number.isInteger(parameters.n_order) || !Number.isInteger(parameters.repeat)) {
|
||||
throw new Error("n_order 和 repeat 必须是整数");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Error(`不支持的配置类型: ${configType}`);
|
||||
}
|
||||
|
||||
function toDataUrl(filePath) {
|
||||
@@ -155,6 +215,21 @@ function registerHandlers() {
|
||||
return { success: true };
|
||||
});
|
||||
|
||||
ipcMain.handle("panel:ack-notification", (_event, request) =>
|
||||
callServer({
|
||||
type: "ackPanelNotification",
|
||||
deviceId: request.deviceId,
|
||||
notificationId: request.notificationId
|
||||
}, request.credentials));
|
||||
ipcMain.handle("panel:open-notification-file", async (_event, request) => {
|
||||
if (!request.fileID) throw new Error("该提醒未关联结果文件");
|
||||
const download = await callServer({ type: "downloadModel", fileID: request.fileID }, request.credentials);
|
||||
const sourcePath = await downloadFromUrl(download.url, download.fileName || "volume_result.json", request.credentials);
|
||||
const error = await shell.openPath(sourcePath);
|
||||
if (error) throw new Error(`无法打开结果文件: ${error}`);
|
||||
return { filePath: sourcePath };
|
||||
});
|
||||
|
||||
ipcMain.handle("connection:test", async (_event, request) => {
|
||||
const result = await callServer({ type: "listOrganizations" }, request);
|
||||
connectionState.apiUrl = String(request.apiUrl || API_URL).trim();
|
||||
|
||||
Reference in New Issue
Block a user