14 changed files with 490 additions and 228 deletions
@ -0,0 +1,233 @@ |
|||
import type Viewport from '@/core/engine/Viewport.ts' |
|||
import { worldModel } from '@/core/manager/WorldModel.ts' |
|||
import mqtt, { type IConnackPacket, type IPublishPacket } from 'mqtt' |
|||
import type { Cl2Task } from '@/modules/cl2/Cl23dObject.ts' |
|||
import type { ErrorWithReasonCode } from 'mqtt/src/lib/shared.ts' |
|||
import type Cl23dObject from '@/modules/cl2/Cl23dObject.ts' |
|||
import { Request } from '@ease-forge/shared' |
|||
|
|||
export default class EnvManager { |
|||
private viewport: Viewport |
|||
private client: mqtt.MqttClient = null |
|||
|
|||
init(viewport: Viewport): void { |
|||
this.viewport = viewport |
|||
} |
|||
|
|||
// 从后台读取所有车
|
|||
async loadExecutors() { |
|||
const res = await Request.request.post('/api/workbench/EnvController@getAllExecutor', { |
|||
projectUuid: worldModel.state.project_uuid, |
|||
catalogCode: worldModel.state.catalogCode, |
|||
envId: worldModel.state.runState.currentEnvId |
|||
}) |
|||
for (const row of res.data) { |
|||
const executor_id = row.executor_id |
|||
const payload = JSON.parse(row.virtual_executor_payload) |
|||
const wayPointId = row.virtual_location_at |
|||
|
|||
const point = Model.find(wayPointId) |
|||
if (!point) { |
|||
console.error(`Waypoint with ID ${wayPointId} not found for executor ${executor_id}.`) |
|||
continue |
|||
} |
|||
|
|||
const item = _.cloneDeep(payload) |
|||
item.id = executor_id |
|||
item.tf[0] = _.cloneDeep(point.tf[0]) |
|||
Model.createExecutor(item) |
|||
} |
|||
} |
|||
|
|||
// 从后台读取所有库存
|
|||
async loadInv() { |
|||
const res = await Request.request.post('/api/workbench/EnvController@getAllInv', { |
|||
projectUuid: worldModel.state.project_uuid, |
|||
catalogCode: worldModel.state.catalogCode, |
|||
envId: worldModel.state.runState.currentEnvId |
|||
}) |
|||
for (const row of res.data) { |
|||
const bay = row.bay |
|||
const cell = row.cell // : 0
|
|||
const level = row.level // : 0
|
|||
const loc_code = row.loc_code // : "rack1_0_0_0"
|
|||
const lpn = row.lpn // : "LPN1"
|
|||
const rack = row.rack // : "rack1"
|
|||
const container_type = row.container_type // : "pallet"
|
|||
Model.createInv(container_type, lpn, rack, bay, level, cell) |
|||
} |
|||
} |
|||
|
|||
appendExecutor(id) { |
|||
const obj = this.viewport.entityManager.findObjectById(id) |
|||
const item = this.viewport.entityManager.findItemById(id) |
|||
if (item.t == 'cl2' && obj.userData.t === 'cl2') { |
|||
debugger |
|||
|
|||
const cl2 = obj as Cl23dObject |
|||
cl2.onMqttConnect(item, this.client) |
|||
// this.client.subscribe(['/wcs_server/' + cl2.id], { qos: 0 })
|
|||
// this.client.publish('/agv_robot/status', JSON.stringify(m20020), { retain: true })
|
|||
} |
|||
} |
|||
|
|||
onMqttConnect = (packet: IConnackPacket) => { |
|||
console.log('Connected') |
|||
} |
|||
|
|||
onMqttMessage = (topic: string, payload: Buffer, packet: IPublishPacket) => { |
|||
console.log(`[${topic}] ${msg}`) |
|||
debugger |
|||
const a: Cl2Task = JSON.parse(msg.toString()) |
|||
this.handleMessage(a) |
|||
} |
|||
|
|||
onMqttError = (error: Error | ErrorWithReasonCode) => { |
|||
console.error('Error:', error) |
|||
} |
|||
|
|||
async start(env: EnvInfo) { |
|||
if (!env) { |
|||
system.showErrorDialog('Environment is not specified, cannot start EnvManager.') |
|||
return |
|||
} |
|||
if (!worldModel.state.isOpened) { |
|||
system.showErrorDialog('WorldModel is not opened, cannot start EnvManager.') |
|||
return |
|||
} |
|||
if (!this.viewport) { |
|||
system.showErrorDialog('Viewport is not initialized, cannot start EnvManager.') |
|||
return |
|||
} |
|||
if (!worldModel.state.runState.currentEnvId) { |
|||
system.showErrorDialog('Current environment ID is not set, cannot start EnvManager.') |
|||
return |
|||
} |
|||
if (worldModel.state.runState.isRunning) { |
|||
system.showErrorDialog('EnvManager is already running, cannot start again.') |
|||
return |
|||
} |
|||
const payload = env.env_payload |
|||
const brokerUrl = payload?.mqtt?.websocket |
|||
const username = payload?.mqtt?.username |
|||
const password = payload?.mqtt?.password |
|||
|
|||
if (!brokerUrl || !username || !password) { |
|||
system.showErrorDialog('MQTT broker URL, username, or password is not set in the environment payload.') |
|||
return |
|||
} |
|||
|
|||
this.stop() |
|||
|
|||
system.showLoading() |
|||
worldModel.state.runState.isLoading = true |
|||
worldModel.state.runState.currentEnv = Object.freeze(env) |
|||
try { |
|||
await this.loadExecutors() |
|||
await this.loadInv() |
|||
|
|||
this.client = mqtt.connect(brokerUrl, { |
|||
path: '/mqtt', |
|||
clientId: system.createUUID(), |
|||
clean: true, |
|||
connectTimeout: 300, |
|||
username, |
|||
password, |
|||
unixSocket: true, |
|||
keepalive: 60 |
|||
}) |
|||
|
|||
this.client.on('connect', this.onMqttConnect) |
|||
this.client.on('message', this.onMqttMessage) |
|||
this.client.on('error', this.onMqttError) |
|||
worldModel.state.runState.isRunning = true |
|||
|
|||
} finally { |
|||
system.clearLoading() |
|||
worldModel.state.runState.isLoading = false |
|||
} |
|||
} |
|||
|
|||
async stop() { |
|||
system.showLoading() |
|||
try { |
|||
if (worldModel.state.runState.isRunning) { |
|||
worldModel.state.runState.isRunning = false |
|||
} |
|||
worldModel.state.runState.currentEnv = null |
|||
if (this.client) { |
|||
this.client.removeAllListeners() |
|||
this.client.end() |
|||
this.client = null |
|||
} |
|||
|
|||
this.clearExecutors() |
|||
this.clearInv() |
|||
this.viewport.runtimeManager.clear() |
|||
|
|||
} finally { |
|||
system.clearLoading() |
|||
worldModel.state.runState.isLoading = false |
|||
} |
|||
} |
|||
|
|||
clearInv() { |
|||
|
|||
} |
|||
|
|||
clearExecutors() { |
|||
|
|||
} |
|||
|
|||
static CURRENT_ALL_ENV: EnvInfo[] |
|||
|
|||
/** |
|||
* 创建运行环境 |
|||
* @param worldId 世界ID |
|||
* @param envName 运行环境名称 |
|||
* @param isVirtual 是否是虚拟环境 |
|||
*/ |
|||
static async createEnv(worldId: string, envName: string, isVirtual: boolean) { |
|||
throw new Error('Method not implemented.') |
|||
} |
|||
|
|||
/** |
|||
* 获取所有运行环境 |
|||
*/ |
|||
static async getAllEnv(worldId: string): Promise<ServerResponse<EnvInfo[]>> { |
|||
// system.invokeServer('')
|
|||
if (!worldId) { |
|||
return Promise.resolve({ success: true, data: [], msg: '' }) |
|||
} |
|||
const res = await Request.request.post('/api/workbench/EnvController@getAllEnv', { |
|||
worldId: worldId |
|||
}) |
|||
if (res.success) { |
|||
EnvManager.CURRENT_ALL_ENV = res.data |
|||
for (const env of res.data) { |
|||
// payload 转换为 json 数据
|
|||
if (env.env_payload) { |
|||
try { |
|||
env.env_payload = JSON.parse(env.env_payload) |
|||
} catch (e) { |
|||
console.error('解析环境负载失败:', e) |
|||
env.env_payload = {} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return res |
|||
} |
|||
|
|||
EnvManager.CURRENT_ALL_ENV = [] |
|||
return res |
|||
} |
|||
|
|||
/** |
|||
* 卸载资源 |
|||
*/ |
|||
dispose(): void { |
|||
this.viewport = null |
|||
this.stop() |
|||
} |
|||
} |
|||
@ -1,67 +0,0 @@ |
|||
import { Request } from '@ease-forge/shared' |
|||
|
|||
/** |
|||
* 运行管理器 |
|||
*/ |
|||
class RunManager { |
|||
|
|||
// 是否正在运行
|
|||
isRunning: boolean = false |
|||
|
|||
/** |
|||
* 获取所有运行环境 |
|||
*/ |
|||
async getAllEnv(worldId: string): Promise<ServerResponse<EnvInfo[]>> { |
|||
// system.invokeServer('')
|
|||
if (!worldId) { |
|||
return Promise.resolve({ success: true, data: [], msg: '' }) |
|||
} |
|||
const res = await Request.request.post('/api/workbench/EnvController@getAllEnv', { |
|||
worldId: worldId |
|||
}) |
|||
for (const env of res.data) { |
|||
// payload 转换为 json 数据
|
|||
if (env.env_payload) { |
|||
try { |
|||
env.env_payload = JSON.parse(env.env_payload) |
|||
} catch (e) { |
|||
console.error('解析环境负载失败:', e) |
|||
env.env_payload = {} |
|||
} |
|||
} |
|||
} |
|||
|
|||
return res |
|||
} |
|||
|
|||
/** |
|||
* 创建运行环境 |
|||
* @param worldId 世界ID |
|||
* @param envName 运行环境名称 |
|||
* @param isVirtual 是否是虚拟环境 |
|||
*/ |
|||
async createEnv(worldId: string, envName: string, isVirtual: boolean) { |
|||
throw new Error('Method not implemented.') |
|||
} |
|||
|
|||
/** |
|||
* 开始运行 |
|||
*/ |
|||
async run(timeRate: number, envId: number) { |
|||
if (this.isRunning) { |
|||
await this.stop() |
|||
} |
|||
|
|||
// 启动 websocket 监听等等
|
|||
} |
|||
|
|||
/** |
|||
* 停止运行 |
|||
*/ |
|||
async stop() { |
|||
// 停止 websocket 监听等等
|
|||
} |
|||
} |
|||
|
|||
const runManager = new RunManager() |
|||
export default runManager |
|||
Loading…
Reference in new issue