Files
ReinLoopTest/ControlPanel/poll-panel-inbox.js
T
2026-07-30 11:12:31 +08:00

113 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const fs = require("node:fs");
const path = require("node:path");
const readline = require("node:readline/promises");
const { callServer, downloadFromUrl } = require("./server-client");
const { publishConfig } = require("./b-admin");
const { plotCsv } = require("./plot-csv");
const { plotJson } = require("./plot-json");
const API_URL = process.env.REINLOOP_API_URL;
const B_ADMIN_TOKEN = process.env.B_ADMIN_TOKEN;
const DEVICE_ID = process.env.REINLOOP_DEVICE_ID;
const REVIEW_MODE = process.env.REVIEW_MODE || "manual";
const POLL_INTERVAL_MS = Number(process.env.POLL_INTERVAL_MS || 3000);
let polling = false;
async function reviewIdentification(message, imagePath) {
if (REVIEW_MODE !== "manual") {
console.log(`已生成 ${imagePath}REVIEW_MODE=${REVIEW_MODE},跳过人工评审`);
return;
}
const prompt = readline.createInterface({ input: process.stdin, output: process.stdout });
try {
console.log(`请查看辨识图像: ${imagePath}`);
let decision;
while (decision !== 0 && decision !== 1) {
const answer = (await prompt.question("参数是否通过?输入 1=通过,0=不通过: ")).trim();
if (answer === "0" || answer === "1") decision = Number(answer);
}
if (decision === 0) {
const configPath = (await prompt.question("请输入新的函数2参数 JSON 路径: ")).trim();
const config = JSON.parse(await fs.promises.readFile(path.resolve(configPath), "utf8"));
await publishConfig("identification", config.parameters || config, {
apiUrl: API_URL,
adminToken: B_ADMIN_TOKEN,
deviceId: DEVICE_ID
});
}
const result = await callServer({
type: "setIdentificationFeedback",
deviceId: DEVICE_ID,
runId: message.fileName,
result: decision
});
console.log(`辨识结果已提交: ${result.result === 1 ? "通过" : "不通过"}`);
} finally {
prompt.close();
}
}
async function processPendingMessage() {
const message = await callServer({ type: "getPendingPanelFile", deviceId: DEVICE_ID });
if (!message.pending) return false;
const sourcePath = await downloadFromUrl(message.url, message.fileName);
if (message.mediaType === "json") {
await plotJson(sourcePath);
} else {
const imagePath = await plotCsv(sourcePath);
await reviewIdentification(message, imagePath);
}
await callServer({
type: "ackPanelFile",
deviceId: DEVICE_ID,
fileID: message.fileID
});
return true;
}
async function poll() {
if (polling) return;
polling = true;
try {
while (await processPendingMessage()) {
// Drain messages already queued on the server before waiting again.
}
} catch (error) {
console.error(`[${new Date().toISOString()}] 消息处理失败: ${error.message}`);
} finally {
polling = false;
}
}
function validateConfig() {
if (!API_URL) throw new Error("缺少环境变量 REINLOOP_API_URL");
if (!DEVICE_ID) throw new Error("缺少环境变量 REINLOOP_DEVICE_ID");
if (REVIEW_MODE === "manual" && !B_ADMIN_TOKEN) {
throw new Error("人工评审模式缺少环境变量 B_ADMIN_TOKEN");
}
if (!Number.isFinite(POLL_INTERVAL_MS) || POLL_INTERVAL_MS < 1000) {
throw new Error("POLL_INTERVAL_MS 必须是大于或等于 1000 的数字");
}
}
function main() {
try {
validateConfig();
console.log(`开始获取设备 ${DEVICE_ID} 的待处理消息,轮询间隔 ${POLL_INTERVAL_MS}ms`);
void poll();
setInterval(poll, POLL_INTERVAL_MS);
} catch (error) {
console.error(error.message);
process.exitCode = 1;
}
}
if (require.main === module) main();
module.exports = { processPendingMessage };