add notice after config
This commit is contained in:
+199
-190
@@ -1,191 +1,200 @@
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const { parse } = require("csv-parse/sync");
|
||||
const { callServer } = require("./server-client");
|
||||
|
||||
const IDENTIFICATION_FIELDS = [
|
||||
"q_in_val", "dt", "n_order", "t_c", "levels",
|
||||
"dead_area", "xa_full", "V_val", "repeat"
|
||||
];
|
||||
|
||||
function getDeviceId(options = {}) {
|
||||
const deviceId = String(options.deviceId || process.env.REINLOOP_DEVICE_ID || "").trim();
|
||||
if (!deviceId) throw new Error("发布或读取辨识配置时必须提供设备 ID");
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
async function readParameters(filePath) {
|
||||
if (!filePath) throw new Error("发布参数时必须提供 JSON 文件路径");
|
||||
const content = await fs.promises.readFile(path.resolve(filePath), "utf8");
|
||||
const config = JSON.parse(content);
|
||||
return config.parameters || config;
|
||||
}
|
||||
|
||||
async function uploadVolumeConfig(parameters, options = {}) {
|
||||
const deviceId = getDeviceId(options);
|
||||
const request = await callServer({
|
||||
type: "getPendingVolumeConfigRequest",
|
||||
deviceId
|
||||
}, options);
|
||||
if (!request.pending) {
|
||||
throw new Error("ReinLoop 尚未发起容积参数请求,请先在客户端开始容积测试");
|
||||
}
|
||||
|
||||
const result = await callServer({
|
||||
type: "uploadDataFile",
|
||||
fileName: "volume_measurement.json",
|
||||
folder: `${deviceId}/volume_config_requests/${request.requestId}`
|
||||
}, options);
|
||||
const metadata = result.uploadMetadata;
|
||||
if (!metadata || !metadata.url) {
|
||||
throw new Error("server 未返回有效的配置上传地址");
|
||||
}
|
||||
|
||||
const orderedConfig = {
|
||||
q_in_val: parameters.q_in_val,
|
||||
dt: parameters.dt,
|
||||
p_max: parameters.p_max,
|
||||
fit_low: parameters.fit_low,
|
||||
fit_high: parameters.fit_high,
|
||||
T_delta: parameters.T_delta,
|
||||
xa_full: parameters.xa_full,
|
||||
num_runs: parameters.num_runs
|
||||
};
|
||||
const form = new FormData();
|
||||
form.append(
|
||||
"file",
|
||||
new Blob([`${JSON.stringify(orderedConfig, null, 2)}\n`], { type: "application/json" }),
|
||||
"volume_measurement.json"
|
||||
);
|
||||
|
||||
const uploadResponse = await fetch(metadata.url, { method: "POST", body: form });
|
||||
if (uploadResponse.status !== 200 && uploadResponse.status !== 204) {
|
||||
throw new Error(`配置文件直传失败: HTTP ${uploadResponse.status}`);
|
||||
}
|
||||
try {
|
||||
return await callServer({
|
||||
type: "submitVolumeConfigFile",
|
||||
deviceId,
|
||||
requestId: request.requestId,
|
||||
fileID: result.fileID,
|
||||
fileName: "volume_measurement.json"
|
||||
}, options);
|
||||
} catch (error) {
|
||||
await callServer({ type: "deleteFile", fileID: result.fileID }, options).catch(() => {});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function serializeIdentificationConfig(parameters) {
|
||||
const rows = IDENTIFICATION_FIELDS.map((field) => {
|
||||
const value = field === "levels" ? parameters[field].join(",") : parameters[field];
|
||||
return `${field},${field === "levels" ? `"${value}"` : value}`;
|
||||
});
|
||||
return `parameter,value\n${rows.join("\n")}\n`;
|
||||
}
|
||||
|
||||
async function uploadIdentificationConfig(parameters, options = {}) {
|
||||
const result = await callServer({
|
||||
type: "publishIdentificationConfig",
|
||||
deviceId: getDeviceId(options),
|
||||
parameters
|
||||
}, options);
|
||||
const metadata = result.uploadMetadata;
|
||||
if (!metadata || !metadata.url) {
|
||||
throw new Error("server 未返回有效的配置上传地址");
|
||||
}
|
||||
|
||||
const form = new FormData();
|
||||
form.append(
|
||||
"file",
|
||||
new Blob([serializeIdentificationConfig(parameters)], { type: "text/csv" }),
|
||||
"identification_config.csv"
|
||||
);
|
||||
const uploadResponse = await fetch(metadata.url, { method: "POST", body: form });
|
||||
if (uploadResponse.status !== 200 && uploadResponse.status !== 204) {
|
||||
throw new Error(`配置文件直传失败: HTTP ${uploadResponse.status}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function publishConfig(configType, parameters, options = {}) {
|
||||
if (configType === "volume") {
|
||||
return uploadVolumeConfig(parameters, options);
|
||||
}
|
||||
if (configType !== "identification") {
|
||||
throw new Error(`不支持的配置类型: ${configType}`);
|
||||
}
|
||||
return uploadIdentificationConfig(parameters, options);
|
||||
}
|
||||
|
||||
async function getConfig(configType, options = {}) {
|
||||
if (configType === "identification") {
|
||||
const result = await callServer({
|
||||
type: "getIdentificationConfig",
|
||||
deviceId: getDeviceId(options)
|
||||
}, options);
|
||||
const response = await fetch(result.url);
|
||||
if (!response.ok) throw new Error(`配置文件下载失败: HTTP ${response.status}`);
|
||||
const records = parse(await response.text(), { columns: true, skip_empty_lines: true });
|
||||
const values = Object.fromEntries(records.map((record) => [record.parameter, record.value]));
|
||||
return {
|
||||
q_in_val: Number(values.q_in_val),
|
||||
dt: Number(values.dt),
|
||||
n_order: Number(values.n_order),
|
||||
t_c: Number(values.t_c),
|
||||
levels: String(values.levels).split(",").map(Number),
|
||||
dead_area: Number(values.dead_area),
|
||||
xa_full: Number(values.xa_full),
|
||||
V_val: Number(values.V_val),
|
||||
repeat: Number(values.repeat)
|
||||
};
|
||||
}
|
||||
return callServer({ type: "getFunctionConfig", configType }, options);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const [command, filePath] = process.argv.slice(2);
|
||||
const commands = {
|
||||
"publish-volume": { action: "upload-volume", configType: "volume" },
|
||||
"publish-identification": { action: "publish", configType: "identification" },
|
||||
"get-volume": { action: "get", configType: "volume" },
|
||||
"get-identification": { action: "get", configType: "identification" }
|
||||
};
|
||||
const selected = commands[command];
|
||||
if (!selected) {
|
||||
throw new Error(
|
||||
"用法: node b-admin.js <publish-volume|publish-identification|get-volume|get-identification> [config.json]"
|
||||
);
|
||||
}
|
||||
|
||||
if (selected.action === "upload-volume") {
|
||||
const result = await publishConfig(selected.configType, await readParameters(filePath));
|
||||
console.log(`配置已上传: ${result.fileID}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = selected.action === "publish"
|
||||
? await publishConfig(selected.configType, await readParameters(filePath))
|
||||
: await getConfig(selected.configType);
|
||||
if (selected.action === "publish") {
|
||||
console.log(`配置已上传: ${result.fileID}`);
|
||||
return;
|
||||
}
|
||||
console.dir(result, { depth: null, colors: true });
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error.message);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getConfig,
|
||||
publishConfig,
|
||||
readParameters,
|
||||
serializeIdentificationConfig,
|
||||
uploadIdentificationConfig,
|
||||
uploadVolumeConfig
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const { parse } = require("csv-parse/sync");
|
||||
const { callServer } = require("./server-client");
|
||||
|
||||
const IDENTIFICATION_FIELDS = [
|
||||
"q_in_val", "dt", "n_order", "t_c", "levels",
|
||||
"dead_area", "xa_full", "V_val", "repeat"
|
||||
];
|
||||
|
||||
function getDeviceId(options = {}) {
|
||||
const deviceId = String(options.deviceId || process.env.REINLOOP_DEVICE_ID || "").trim();
|
||||
if (!deviceId) throw new Error("发布或读取辨识配置时必须提供设备 ID");
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
async function readParameters(filePath) {
|
||||
if (!filePath) throw new Error("发布参数时必须提供 JSON 文件路径");
|
||||
const content = await fs.promises.readFile(path.resolve(filePath), "utf8");
|
||||
const config = JSON.parse(content);
|
||||
return config.parameters || config;
|
||||
}
|
||||
|
||||
async function uploadVolumeConfig(parameters, options = {}) {
|
||||
const deviceId = getDeviceId(options);
|
||||
const request = await callServer({
|
||||
type: "getPendingVolumeConfigRequest",
|
||||
deviceId
|
||||
}, options);
|
||||
if (!request.pending) {
|
||||
throw new Error("ReinLoop 尚未发起容积参数请求,请先在客户端开始容积测试");
|
||||
}
|
||||
|
||||
const result = await callServer({
|
||||
type: "uploadDataFile",
|
||||
fileName: "volume_measurement.json",
|
||||
folder: `${deviceId}/volume_config_requests/${request.requestId}`
|
||||
}, options);
|
||||
const metadata = result.uploadMetadata;
|
||||
if (!metadata || !metadata.url) {
|
||||
throw new Error("server 未返回有效的配置上传地址");
|
||||
}
|
||||
|
||||
const orderedConfig = {
|
||||
q_in_val: parameters.q_in_val,
|
||||
dt: parameters.dt,
|
||||
p_max: parameters.p_max,
|
||||
fit_low: parameters.fit_low,
|
||||
fit_high: parameters.fit_high,
|
||||
T_delta: parameters.T_delta,
|
||||
xa_full: parameters.xa_full,
|
||||
num_runs: parameters.num_runs
|
||||
};
|
||||
const form = new FormData();
|
||||
form.append(
|
||||
"file",
|
||||
new Blob([`${JSON.stringify(orderedConfig, null, 2)}\n`], { type: "application/json" }),
|
||||
"volume_measurement.json"
|
||||
);
|
||||
|
||||
const uploadResponse = await fetch(metadata.url, { method: "POST", body: form });
|
||||
if (uploadResponse.status !== 200 && uploadResponse.status !== 204) {
|
||||
throw new Error(`配置文件直传失败: HTTP ${uploadResponse.status}`);
|
||||
}
|
||||
try {
|
||||
return await callServer({
|
||||
type: "submitVolumeConfigFile",
|
||||
deviceId,
|
||||
requestId: request.requestId,
|
||||
fileID: result.fileID,
|
||||
fileName: "volume_measurement.json"
|
||||
}, options);
|
||||
} catch (error) {
|
||||
await callServer({ type: "deleteFile", fileID: result.fileID }, options).catch(() => {});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function serializeIdentificationConfig(parameters) {
|
||||
const rows = IDENTIFICATION_FIELDS.map((field) => {
|
||||
const value = field === "levels" ? parameters[field].join(",") : parameters[field];
|
||||
return `${field},${field === "levels" ? `"${value}"` : value}`;
|
||||
});
|
||||
return `parameter,value\n${rows.join("\n")}\n`;
|
||||
}
|
||||
|
||||
async function uploadIdentificationConfig(parameters, options = {}) {
|
||||
const result = await callServer({
|
||||
type: "publishIdentificationConfig",
|
||||
deviceId: getDeviceId(options),
|
||||
parameters
|
||||
}, options);
|
||||
const metadata = result.uploadMetadata;
|
||||
if (!metadata || !metadata.url) {
|
||||
throw new Error("server 未返回有效的配置上传地址");
|
||||
}
|
||||
|
||||
const form = new FormData();
|
||||
form.append(
|
||||
"file",
|
||||
new Blob([serializeIdentificationConfig(parameters)], { type: "text/csv" }),
|
||||
"identification_config.csv"
|
||||
);
|
||||
const uploadResponse = await fetch(metadata.url, { method: "POST", body: form });
|
||||
if (uploadResponse.status !== 200 && uploadResponse.status !== 204) {
|
||||
throw new Error(`配置文件直传失败: HTTP ${uploadResponse.status}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function publishConfig(configType, parameters, options = {}) {
|
||||
if (configType === "volume") {
|
||||
return uploadVolumeConfig(parameters, options);
|
||||
}
|
||||
if (configType !== "identification") {
|
||||
throw new Error(`不支持的配置类型: ${configType}`);
|
||||
}
|
||||
return uploadIdentificationConfig(parameters, options);
|
||||
}
|
||||
|
||||
async function getConfig(configType, options = {}) {
|
||||
if (configType === "identification") {
|
||||
const result = await callServer({
|
||||
type: "getIdentificationConfig",
|
||||
deviceId: getDeviceId(options)
|
||||
}, options);
|
||||
const response = await fetch(result.url);
|
||||
if (!response.ok) throw new Error(`配置文件下载失败: HTTP ${response.status}`);
|
||||
const records = parse(await response.text(), { columns: true, skip_empty_lines: true });
|
||||
const values = Object.fromEntries(records.map((record) => [record.parameter, record.value]));
|
||||
return {
|
||||
q_in_val: Number(values.q_in_val),
|
||||
dt: Number(values.dt),
|
||||
n_order: Number(values.n_order),
|
||||
t_c: Number(values.t_c),
|
||||
levels: String(values.levels).split(",").map(Number),
|
||||
dead_area: Number(values.dead_area),
|
||||
xa_full: Number(values.xa_full),
|
||||
V_val: Number(values.V_val),
|
||||
repeat: Number(values.repeat)
|
||||
};
|
||||
}
|
||||
const result = await callServer({
|
||||
type: "getVolumeConfigFile",
|
||||
deviceId: getDeviceId(options)
|
||||
}, options);
|
||||
if (result.found === false || !result.url) {
|
||||
throw new Error("当前产线尚无已成功提交的容积配置");
|
||||
}
|
||||
const response = await fetch(result.url);
|
||||
if (!response.ok) throw new Error(`配置文件下载失败: HTTP ${response.status}`);
|
||||
return JSON.parse(await response.text());
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const [command, filePath] = process.argv.slice(2);
|
||||
const commands = {
|
||||
"publish-volume": { action: "upload-volume", configType: "volume" },
|
||||
"publish-identification": { action: "publish", configType: "identification" },
|
||||
"get-volume": { action: "get", configType: "volume" },
|
||||
"get-identification": { action: "get", configType: "identification" }
|
||||
};
|
||||
const selected = commands[command];
|
||||
if (!selected) {
|
||||
throw new Error(
|
||||
"用法: node b-admin.js <publish-volume|publish-identification|get-volume|get-identification> [config.json]"
|
||||
);
|
||||
}
|
||||
|
||||
if (selected.action === "upload-volume") {
|
||||
const result = await publishConfig(selected.configType, await readParameters(filePath));
|
||||
console.log(`配置已上传: ${result.fileID}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = selected.action === "publish"
|
||||
? await publishConfig(selected.configType, await readParameters(filePath))
|
||||
: await getConfig(selected.configType);
|
||||
if (selected.action === "publish") {
|
||||
console.log(`配置已上传: ${result.fileID}`);
|
||||
return;
|
||||
}
|
||||
console.dir(result, { depth: null, colors: true });
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main().catch((error) => {
|
||||
console.error(error.message);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getConfig,
|
||||
publishConfig,
|
||||
readParameters,
|
||||
serializeIdentificationConfig,
|
||||
uploadIdentificationConfig,
|
||||
uploadVolumeConfig
|
||||
};
|
||||
Reference in New Issue
Block a user