update server
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
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 };
|
||||
Reference in New Issue
Block a user