212 lines
6.3 KiB
TypeScript
212 lines
6.3 KiB
TypeScript
// main.ts
|
||
|
||
/// <reference lib="deno.unstable" />
|
||
|
||
// 导入 UUID 库(请根据实际情况调整URL)
|
||
import { v4 as uuidv4 } from "npm:uuid";
|
||
import { setupAgvWorker, initAgvWorker } from "./agv_manager.ts";
|
||
import { reconnectAllWorker, setupMasterWorker, updateDeviceListFromConfig } from "./master_manager.ts";
|
||
import { globalEventManager } from "./event_manager.ts";
|
||
|
||
// Load config and mappings from JSON files at runtime
|
||
const configText = await Deno.readTextFile("./config.json");
|
||
const config = JSON.parse(configText);
|
||
const mappingFile = config.mappingFile || "mapping.json";
|
||
const mappingsText = await Deno.readTextFile(`./${mappingFile}`);
|
||
const mappings = JSON.parse(mappingsText);
|
||
|
||
// Generate a unique instance ID from manufacturer and UUID
|
||
const instanceId = uuidv4();
|
||
|
||
// 添加全局事件监听器
|
||
globalEventManager.addEventListener("reconnect-all", (event: Event) => {
|
||
const customEvent = event as CustomEvent;
|
||
console.log("🎯 主线程收到全局重连事件:", customEvent.detail);
|
||
handleReconnectAll();
|
||
});
|
||
|
||
globalEventManager.addEventListener("grpc-connection-lost", (event: Event) => {
|
||
const customEvent = event as CustomEvent;
|
||
console.log("🎯 主线程收到 gRPC 连接丢失事件:", customEvent.detail);
|
||
// 可以添加特殊的 gRPC 重连逻辑
|
||
});
|
||
|
||
globalEventManager.addEventListener("device-status-update", (event: Event) => {
|
||
const customEvent = event as CustomEvent;
|
||
console.log("🎯 主线程收到设备状态更新事件:", customEvent.detail.data);
|
||
});
|
||
|
||
// 重连处理函数
|
||
function handleReconnectAll() {
|
||
console.log("agv_main: 执行全局重连");
|
||
reconnectAllWorker(kv, webWorker, masterWorker, agvWorker, config, mappings, instanceId);
|
||
}
|
||
|
||
// 初始化 downWorker 并支持自身重启
|
||
let downWorker: Worker;
|
||
function startDownWorker() {
|
||
console.log("agv_main: 启动 downWorker");
|
||
downWorker = new Worker(
|
||
new URL("./vda5050_transformer_worker.ts", import.meta.url).href,
|
||
{ type: "module" }
|
||
);
|
||
|
||
// 注册到全局事件管理器
|
||
globalEventManager.registerWorker("downWorker", downWorker);
|
||
|
||
// 初始化 downWorker
|
||
downWorker.postMessage({
|
||
type: "init",
|
||
mqtt: config.mqtt,
|
||
mappings,
|
||
instanceId
|
||
});
|
||
|
||
// 监听重启请求
|
||
downWorker.onmessage = (event: MessageEvent) => {
|
||
const message = event.data;
|
||
// 只处理非全局事件相关的消息
|
||
if (message.type === "reconnect-all" && message.type !== "dispatchGlobalEvent") {
|
||
console.log("agv_main: 收到 downWorker reconnect-all,重启所有 Workers");
|
||
handleReconnectAll();
|
||
} else if (message.type === "reconnect-down") {
|
||
console.log("agv_main: 收到 downWorker reconnect-down,重启 downWorker");
|
||
downWorker.postMessage({ type: "stop" });
|
||
downWorker.terminate();
|
||
startDownWorker();
|
||
}
|
||
};
|
||
}
|
||
startDownWorker();
|
||
|
||
// 打开 Deno KV 数据库(Deno KV 在最新版本中为内置特性)
|
||
const kv = await Deno.openKv();
|
||
|
||
// // 启动 Web Worker 用于可视化界面
|
||
const webWorker = new Worker(
|
||
new URL("./web_worker.ts", import.meta.url).href,
|
||
{ type: "module" }
|
||
);
|
||
console.log("Web Worker 已启动");
|
||
const masterWorker = new Worker(
|
||
new URL("./vda_worker.ts", import.meta.url).href,
|
||
{ type: "module" }
|
||
);
|
||
const agvWorker = new Worker(
|
||
new URL("./agv_worker.ts", import.meta.url).href,
|
||
{ type: "module" }
|
||
);
|
||
|
||
// 注册所有 Worker 到全局事件管理器
|
||
globalEventManager.registerWorker("webWorker", webWorker);
|
||
globalEventManager.registerWorker("masterWorker", masterWorker);
|
||
globalEventManager.registerWorker("agvWorker", agvWorker);
|
||
|
||
reconnectAllWorker(kv, webWorker, masterWorker, agvWorker, config, mappings, instanceId);
|
||
|
||
// 监听配置文件变化,动态更新设备列表
|
||
const watcher = Deno.watchFs("./devices.json");
|
||
(async () => {
|
||
console.log("开始监控配置文件变化...");
|
||
for await (const event of watcher) {
|
||
if (event.paths.some((p) => p.endsWith("devices.json"))) {
|
||
console.log("检测到设备配置文件变化,更新设备列表...");
|
||
await updateDeviceListFromConfig(masterWorker, config, instanceId);
|
||
}
|
||
}
|
||
})();
|
||
|
||
// 处理 Ctrl+C(SIGINT)退出
|
||
Deno.addSignalListener("SIGINT", () => {
|
||
console.log("接收到 Ctrl+C,主程序通知 Worker 退出...");
|
||
|
||
// 向所有 Worker 发送 shutdown 消息
|
||
agvWorker.postMessage("shutdown");
|
||
masterWorker.postMessage({ type: "shutdown" });
|
||
webWorker.postMessage({ type: "shutdown" });
|
||
// 通知 downWorker 关闭
|
||
downWorker.postMessage({ type: "shutdown" });
|
||
|
||
// 延时后终止 Worker 并退出主程序
|
||
setTimeout(() => {
|
||
agvWorker.terminate();
|
||
masterWorker.terminate();
|
||
webWorker.terminate();
|
||
downWorker.terminate();
|
||
console.log("所有 Worker 已终止,程序退出");
|
||
Deno.exit(0);
|
||
}, 2000);
|
||
});
|
||
|
||
// Web Worker 错误处理
|
||
webWorker.onerror = (error) => {
|
||
console.error("Web Worker 执行错误:", error);
|
||
};
|
||
|
||
// 发送导航订单的函数(示例订单)
|
||
function sendNavigationOrder() {
|
||
// 使用 UUID v4 生成订单号
|
||
const orderId = uuidv4();
|
||
console.log(`创建新的导航订单 ${orderId}`);
|
||
|
||
masterWorker.postMessage({
|
||
type: "sendOrder",
|
||
orderId: orderId,
|
||
nodes: [
|
||
{
|
||
nodeId: "start",
|
||
nodePosition: {
|
||
x: 0.0,
|
||
y: 0.0,
|
||
mapId: "warehouse",
|
||
theta: 0,
|
||
},
|
||
actions: [],
|
||
},
|
||
{
|
||
nodeId: "waypoint1",
|
||
nodePosition: {
|
||
x: 5.0,
|
||
y: 0.0,
|
||
mapId: "warehouse",
|
||
theta: 0,
|
||
},
|
||
actions: [],
|
||
},
|
||
{
|
||
nodeId: "destination",
|
||
nodePosition: {
|
||
x: 10.0,
|
||
y: 5.0,
|
||
mapId: "warehouse",
|
||
theta: 0,
|
||
},
|
||
actions: [],
|
||
},
|
||
],
|
||
});
|
||
}
|
||
|
||
// 取消订单的函数
|
||
function cancelOrder(orderId: string) {
|
||
console.log(`取消订单 ${orderId}`);
|
||
masterWorker.postMessage({
|
||
type: "cancelOrder",
|
||
orderId: orderId,
|
||
});
|
||
}
|
||
|
||
// 发送自定义命令设置给 Worker 的函数
|
||
function sendCustomCommand(cmd: string) {
|
||
console.log(`发送自定义命令设置: ${cmd}`);
|
||
masterWorker.postMessage({
|
||
type: "setCommand",
|
||
command: cmd,
|
||
});
|
||
}
|
||
|
||
// CLI moved to cli.ts
|
||
import { startCli } from "./cli.ts";
|
||
startCli(masterWorker, agvWorker, sendNavigationOrder, cancelOrder, sendCustomCommand, instanceId);
|
||
|
||
console.log("VDA 5050 控制程序已启动,输入命令或按 Ctrl+C 退出程序"); |