From 466923caf544923359cf498b8dd723c1b20e86f3 Mon Sep 17 00:00:00 2001 From: adrigzr Date: Sun, 19 Mar 2023 11:33:06 +0100 Subject: [PATCH] feat(adapter-tcp): add more packet event handlers --- .../adapter-tcp/src/connection.manager.ts | 14 ++ ...s-connected-event-handler.event-handler.ts | 4 +- .../client-login.event-handler.ts | 7 - .../device-battery-update.event-handler.ts | 2 + ...ice-clean-map-data-report.event-handler.ts | 7 + .../device-clean-map-report.event-handler.ts | 7 + .../device-clean-task-report.event-handler.ts | 7 + ...device-get-all-global-map.event-handler.ts | 15 ++ .../device-locked.event-handler.ts | 6 +- ...p-charger-position-update.event-handler.ts | 26 +++ .../device-map-update.event-handler.ts | 197 ++++++++++++++++++ ...ce-map-work-status-update.event-handler.ts | 64 ++++++ .../device-memory-map-info.event-handler.ts | 15 ++ .../device-offline.event-handler.ts | 2 - .../device-register.event-handler.ts | 2 + .../device-settings-update.event-handler.ts | 2 + .../device-time-update.event-handler.ts | 19 ++ .../device-upgrade-info.event-handler.ts | 17 ++ .../device-version-update.event-handler.ts | 2 + .../device-wlan-update.event-handler.ts | 28 +++ .../src/mappers/device-error.mapper.ts | 7 +- packages/eslint-config/typescript.js | 1 + 22 files changed, 434 insertions(+), 17 deletions(-) create mode 100644 packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-get-all-global-map.event-handler.ts create mode 100644 packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-charger-position-update.event-handler.ts create mode 100644 packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-update.event-handler.ts create mode 100644 packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-work-status-update.event-handler.ts create mode 100644 packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-memory-map-info.event-handler.ts create mode 100644 packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-time-update.event-handler.ts create mode 100644 packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-upgrade-info.event-handler.ts create mode 100644 packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-wlan-update.event-handler.ts diff --git a/packages/adapter-tcp/src/connection.manager.ts b/packages/adapter-tcp/src/connection.manager.ts index 397691b1..02d8c349 100644 --- a/packages/adapter-tcp/src/connection.manager.ts +++ b/packages/adapter-tcp/src/connection.manager.ts @@ -40,11 +40,25 @@ export class ConnectionManager { const count = this.packetEventBus.listenerCount(event); + // Throw an error if there is no event handler for the packet event. if (count === 0) { throw new DomainException(`No event handler found for packet event '${event}'`); } + // Emit the packet event. await this.packetEventBus.emit(event, packetMessage); + + // This is a hack to only mark the device as connected if there is more than one connection. + // Here we should check that the connections are from the same ip address. + if (connection.device && !connection.device.isConnected) { + const connections = this.findConnectionsByDeviceId(connection.device.id); + + if (connections.length > 1) { + connection.device.setAsConnected(); + + await this.deviceRepository.saveOne(connection.device); + } + } }); connection.on('close', () => { diff --git a/packages/adapter-tcp/src/event-handlers/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.ts b/packages/adapter-tcp/src/event-handlers/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.ts index 06906d71..d8a0800f 100644 --- a/packages/adapter-tcp/src/event-handlers/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/domain-event-handlers/lock-device-when-device-is-connected-event-handler.event-handler.ts @@ -7,13 +7,13 @@ export class LockDeviceWhenDeviceIsConnectedEventHandler implements DomainEventH constructor(private readonly connectionManager: ConnectionManager) {} - handle(event: DeviceConnectedDomainEvent): Promise { + async handle(event: DeviceConnectedDomainEvent): Promise { const [connection] = this.connectionManager.findConnectionsByDeviceId(event.aggregateId); if (!connection) { throw new DomainException(`Unable to find a connection for the device with id ${event.aggregateId.value}`); } - return connection.send('DEVICE_CONTROL_LOCK_REQ', {}); + await connection.send('DEVICE_CONTROL_LOCK_REQ', {}); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/client-login.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/client-login.event-handler.ts index 2949a314..ba0477d3 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/client-login.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/client-login.event-handler.ts @@ -1,12 +1,9 @@ import type { PacketEventHandler } from '../../packet.event-handler'; import type { PacketMessage } from '../../packet.message'; -import type { DeviceRepository } from '@agnoc/domain'; export class ClientLoginEventHandler implements PacketEventHandler { readonly eventName = 'CLIENT_ONLINE_REQ'; - constructor(private readonly deviceRepository: DeviceRepository) {} - async handle(message: PacketMessage<'CLIENT_ONLINE_REQ'>): Promise { if (!message.device) { const data = { @@ -18,9 +15,5 @@ export class ClientLoginEventHandler implements PacketEventHandler { } await message.respond('CLIENT_ONLINE_RSP', { result: 0 }); - - message.device.setAsConnected(); - - await this.deviceRepository.saveOne(message.device); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-battery-update.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-battery-update.event-handler.ts index 84f682ae..328ac324 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-battery-update.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-battery-update.event-handler.ts @@ -17,6 +17,8 @@ export class DeviceBatteryUpdateEventHandler implements PacketEventHandler { message.device.updateBattery(this.deviceBatteryMapper.toDomain(data.battery.level)); + // TODO: save the entity and publish domain event + await message.respond('PUSH_DEVICE_BATTERY_INFO_RSP', { result: 0 }); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-map-data-report.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-map-data-report.event-handler.ts index 993b6d35..a7a4fb2f 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-map-data-report.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-map-data-report.event-handler.ts @@ -1,3 +1,4 @@ +import { DomainException } from '@agnoc/toolkit'; import type { PacketEventHandler } from '../../packet.event-handler'; import type { PacketMessage } from '../../packet.message'; @@ -5,8 +6,14 @@ export class DeviceCleanMapDataReportEventHandler implements PacketEventHandler readonly eventName = 'DEVICE_CLEANMAP_BINDATA_REPORT_REQ'; async handle(message: PacketMessage<'DEVICE_CLEANMAP_BINDATA_REPORT_REQ'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + const data = message.packet.payload.object; + // TODO: save device clean map data + await message.respond('DEVICE_CLEANMAP_BINDATA_REPORT_RSP', { result: 0, cleanId: data.cleanId }); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-map-report.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-map-report.event-handler.ts index ed11e4f0..8d39d860 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-map-report.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-map-report.event-handler.ts @@ -1,3 +1,4 @@ +import { DomainException } from '@agnoc/toolkit'; import type { PacketEventHandler } from '../../packet.event-handler'; import type { PacketMessage } from '../../packet.message'; @@ -5,8 +6,14 @@ export class DeviceCleanMapReportEventHandler implements PacketEventHandler { readonly eventName = 'DEVICE_EVENT_REPORT_CLEANMAP'; async handle(message: PacketMessage<'DEVICE_EVENT_REPORT_CLEANMAP'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + const data = message.packet.payload.object; + // TODO: save device clean map data + await message.respond('DEVICE_EVENT_REPORT_RSP', { result: 0, body: { cleanId: data.cleanId } }); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-task-report.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-task-report.event-handler.ts index 27febb0a..91e05319 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-task-report.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-clean-task-report.event-handler.ts @@ -1,3 +1,4 @@ +import { DomainException } from '@agnoc/toolkit'; import type { PacketEventHandler } from '../../packet.event-handler'; import type { PacketMessage } from '../../packet.message'; @@ -5,6 +6,12 @@ export class DeviceCleanTaskReportEventHandler implements PacketEventHandler { readonly eventName = 'DEVICE_EVENT_REPORT_CLEANTASK'; async handle(message: PacketMessage<'DEVICE_EVENT_REPORT_CLEANTASK'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + // TODO: save device clean task data + await message.respond('UNK_11A4', { unk1: 0 }); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-get-all-global-map.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-get-all-global-map.event-handler.ts new file mode 100644 index 00000000..93de0f5d --- /dev/null +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-get-all-global-map.event-handler.ts @@ -0,0 +1,15 @@ +import { DomainException } from '@agnoc/toolkit'; +import type { PacketEventHandler } from '../../packet.event-handler'; +import type { PacketMessage } from '../../packet.message'; + +export class DeviceGetAllGlobalMapEventHandler implements PacketEventHandler { + readonly eventName = 'DEVICE_GET_ALL_GLOBAL_MAP_INFO_RSP'; + + async handle(message: PacketMessage<'DEVICE_GET_ALL_GLOBAL_MAP_INFO_RSP'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + // TODO: investigate the meaning of this packet. + } +} diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-locked.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-locked.event-handler.ts index 140ca53e..e7451f91 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-locked.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-locked.event-handler.ts @@ -13,8 +13,10 @@ export class DeviceLockedEventHandler implements PacketEventHandler { throw new DomainException('Device not found'); } - message.device.setAsLocked(); + if (!message.device.isLocked) { + message.device.setAsLocked(); - await this.deviceRepository.saveOne(message.device); + await this.deviceRepository.saveOne(message.device); + } } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-charger-position-update.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-charger-position-update.event-handler.ts new file mode 100644 index 00000000..2f0be65b --- /dev/null +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-charger-position-update.event-handler.ts @@ -0,0 +1,26 @@ +import { MapPosition } from '@agnoc/domain'; +import { DomainException } from '@agnoc/toolkit'; +import type { PacketEventHandler } from '../../packet.event-handler'; +import type { PacketMessage } from '../../packet.message'; + +export class DeviceMapChargerPositionUpdateEventHandler implements PacketEventHandler { + readonly eventName = 'DEVICE_MAPID_PUSH_CHARGE_POSITION_INFO'; + + async handle(message: PacketMessage<'DEVICE_MAPID_PUSH_CHARGE_POSITION_INFO'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + const data = message.packet.payload.object; + + message.device.map?.updateCharger( + new MapPosition({ + x: data.poseX, + y: data.poseY, + phi: data.posePhi, + }), + ); + + // TODO: save entity and publish domain event + } +} diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-update.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-update.event-handler.ts new file mode 100644 index 00000000..db744e41 --- /dev/null +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-update.event-handler.ts @@ -0,0 +1,197 @@ +import { + DeviceCleanWork, + CleanSize, + DeviceTime, + DeviceMap, + MapCoordinate, + MapPixel, + MapPosition, + Room, + Zone, +} from '@agnoc/domain'; +import { DomainException, ID, isPresent } from '@agnoc/toolkit'; +import type { DeviceBatteryMapper } from '../../mappers/device-battery.mapper'; +import type { DeviceErrorMapper } from '../../mappers/device-error.mapper'; +import type { DeviceFanSpeedMapper } from '../../mappers/device-fan-speed.mapper'; +import type { DeviceModeMapper } from '../../mappers/device-mode.mapper'; +import type { DeviceStateMapper } from '../../mappers/device-state.mapper'; +import type { PacketEventHandler } from '../../packet.event-handler'; +import type { PacketMessage } from '../../packet.message'; + +export class DeviceMapUpdateEventHandler implements PacketEventHandler { + readonly eventName = 'DEVICE_MAPID_GET_GLOBAL_INFO_RSP'; + + constructor( + private readonly deviceBatteryMapper: DeviceBatteryMapper, + private readonly deviceModeMapper: DeviceModeMapper, + private readonly deviceStateMapper: DeviceStateMapper, + private readonly deviceErrorMapper: DeviceErrorMapper, + private readonly deviceFanSpeedMapper: DeviceFanSpeedMapper, + ) {} + + async handle(message: PacketMessage<'DEVICE_MAPID_GET_GLOBAL_INFO_RSP'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + const { + statusInfo, + mapHeadInfo, + mapGrid, + historyHeadInfo, + robotPoseInfo, + robotChargeInfo, + cleanRoomList, + roomSegmentList, + wallListInfo, + spotInfo, + cleanPlanList, + currentPlanId, + } = message.packet.payload.object; + + if (statusInfo) { + const { + batteryPercent: battery, + faultType: type, + workingMode: workMode, + chargeState: chargeStatus, + cleanPreference, + faultCode, + } = statusInfo; + + message.device.updateCurrentClean( + new DeviceCleanWork({ + size: new CleanSize(statusInfo.cleanSize), + time: DeviceTime.fromMinutes(statusInfo.cleanTime), + }), + ); + message.device.updateBattery(this.deviceBatteryMapper.toDomain(battery)); + message.device.updateMode(this.deviceModeMapper.toDomain(workMode)); + message.device.updateState(this.deviceStateMapper.toDomain({ type, workMode, chargeStatus })); + message.device.updateError(this.deviceErrorMapper.toDomain(faultCode)); + message.device.updateFanSpeed(this.deviceFanSpeedMapper.toDomain(cleanPreference)); + } + + let map = message.device.map; + + if (mapHeadInfo && mapGrid) { + const props = { + id: new ID(mapHeadInfo.mapHeadId), + size: new MapPixel({ + x: mapHeadInfo.sizeX, + y: mapHeadInfo.sizeY, + }), + min: new MapCoordinate({ + x: mapHeadInfo.minX, + y: mapHeadInfo.minY, + }), + max: new MapCoordinate({ + x: mapHeadInfo.maxX, + y: mapHeadInfo.maxY, + }), + resolution: mapHeadInfo.resolution, + grid: mapGrid, + rooms: [], + restrictedZones: [], + robotPath: [], + }; + + map = map ? map.clone(props) : new DeviceMap(props); + + message.device.updateMap(map); + } + + if (map) { + if (historyHeadInfo) { + const currentIndex = map.robotPath.length; + + map.updateRobotPath( + map.robotPath.concat( + historyHeadInfo.pointList.slice(currentIndex).map(({ x, y }) => new MapCoordinate({ x, y })), + ), + ); + } + + if (robotPoseInfo) { + map.updateRobot( + new MapPosition({ + x: robotPoseInfo.poseX, + y: robotPoseInfo.poseY, + phi: robotPoseInfo.posePhi, + }), + ); + } + + if (robotChargeInfo) { + map.updateCharger( + new MapPosition({ + x: robotChargeInfo.poseX, + y: robotChargeInfo.poseY, + phi: robotChargeInfo.posePhi, + }), + ); + } + + if (spotInfo) { + map.updateCurrentSpot( + new MapPosition({ + x: spotInfo.poseX, + y: spotInfo.poseY, + phi: spotInfo.posePhi, + }), + ); + } + + if (wallListInfo) { + map.updateRestrictedZones( + wallListInfo.cleanAreaList.map((cleanArea) => { + return new Zone({ + id: new ID(cleanArea.cleanAreaId), + coordinates: cleanArea.coordinateList.map(({ x, y }) => { + return new MapCoordinate({ + x, + y, + }); + }), + }); + }), + ); + } + + if (cleanRoomList && roomSegmentList && cleanPlanList) { + const currentPlan = cleanPlanList.find((plan) => plan.planId === currentPlanId); + + map.updateRooms( + cleanRoomList + .map((cleanRoom) => { + const segment = roomSegmentList.find((roomSegment) => roomSegment.roomId === cleanRoom.roomId); + const roomInfo = currentPlan?.cleanRoomInfoList.find((r) => r.roomId === cleanRoom.roomId); + + if (!segment) { + return undefined; + } + + return new Room({ + id: new ID(cleanRoom.roomId), + name: cleanRoom.roomName, + isEnabled: Boolean(roomInfo?.enable), + center: new MapCoordinate({ + x: cleanRoom.roomX, + y: cleanRoom.roomY, + }), + pixels: segment?.roomPixelList.map((pixel) => { + return new MapPixel({ + x: pixel.x, + y: pixel.y, + }); + }), + }); + }) + .filter(isPresent), + ); + } + } + + // TODO: save entities and publish domain events + } +} diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-work-status-update.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-work-status-update.event-handler.ts new file mode 100644 index 00000000..386fc1cb --- /dev/null +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-map-work-status-update.event-handler.ts @@ -0,0 +1,64 @@ +import { CleanSize, DeviceCleanWork, DeviceTime } from '@agnoc/domain'; +import { DomainException, isPresent } from '@agnoc/toolkit'; +import type { DeviceBatteryMapper } from '../../mappers/device-battery.mapper'; +import type { DeviceErrorMapper } from '../../mappers/device-error.mapper'; +import type { DeviceFanSpeedMapper } from '../../mappers/device-fan-speed.mapper'; +import type { DeviceModeMapper } from '../../mappers/device-mode.mapper'; +import type { DeviceStateMapper } from '../../mappers/device-state.mapper'; +import type { DeviceWaterLevelMapper } from '../../mappers/device-water-level.mapper'; +import type { PacketEventHandler } from '../../packet.event-handler'; +import type { PacketMessage } from '../../packet.message'; + +export class DeviceMapWorkStatusUpdateEventHandler implements PacketEventHandler { + readonly eventName = 'DEVICE_MAPID_WORK_STATUS_PUSH_REQ'; + + constructor( + private readonly deviceStateMapper: DeviceStateMapper, + private readonly deviceModeMapper: DeviceModeMapper, + private readonly deviceErrorMapper: DeviceErrorMapper, + private readonly deviceBatteryMapper: DeviceBatteryMapper, + private readonly deviceFanSpeedMapper: DeviceFanSpeedMapper, + private readonly deviceWaterLevelMapper: DeviceWaterLevelMapper, + ) {} + + async handle(message: PacketMessage<'DEVICE_MAPID_WORK_STATUS_PUSH_REQ'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + const { + battery, + type, + workMode, + chargeStatus, + cleanPreference, + faultCode, + waterLevel, + mopType, + cleanSize, + cleanTime, + } = message.packet.payload.object; + + message.device.updateCurrentClean( + new DeviceCleanWork({ + size: new CleanSize(cleanSize), + time: DeviceTime.fromMinutes(cleanTime), + }), + ); + message.device.updateState(this.deviceStateMapper.toDomain({ type, workMode, chargeStatus })); + message.device.updateMode(this.deviceModeMapper.toDomain(workMode)); + message.device.updateError(this.deviceErrorMapper.toDomain(faultCode)); + message.device.updateBattery(this.deviceBatteryMapper.toDomain(battery)); + message.device.updateFanSpeed(this.deviceFanSpeedMapper.toDomain(cleanPreference)); + + if (isPresent(mopType)) { + message.device.updateHasMopAttached(mopType); + } + + if (isPresent(waterLevel)) { + message.device.updateWaterLevel(this.deviceWaterLevelMapper.toDomain(waterLevel)); + } + + // TODO: save entity and publish domain events + } +} diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-memory-map-info.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-memory-map-info.event-handler.ts new file mode 100644 index 00000000..e7ce14db --- /dev/null +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-memory-map-info.event-handler.ts @@ -0,0 +1,15 @@ +import { DomainException } from '@agnoc/toolkit'; +import type { PacketEventHandler } from '../../packet.event-handler'; +import type { PacketMessage } from '../../packet.message'; + +export class DeviceMemoryMapInfoEventHandler implements PacketEventHandler { + readonly eventName = 'DEVICE_MAPID_PUSH_ALL_MEMORY_MAP_INFO'; + + async handle(message: PacketMessage<'DEVICE_MAPID_PUSH_ALL_MEMORY_MAP_INFO'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + // TODO: save device memory map info + } +} diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-offline.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-offline.event-handler.ts index 2ffaa07a..0bfda3f0 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-offline.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-offline.event-handler.ts @@ -9,7 +9,5 @@ export class DeviceOfflineEventHandler implements PacketEventHandler { if (!message.device) { throw new DomainException('Device not found'); } - - return message.connection.send('DEVICE_CONTROL_LOCK_REQ', {}); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-register.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-register.event-handler.ts index ef6c05ee..77f0db7a 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-register.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-register.event-handler.ts @@ -18,6 +18,8 @@ export class DeviceRegisterEventHandler implements PacketEventHandler { version: new DeviceVersion({ software: data.softwareVersion, hardware: data.hardwareVersion }), }); + // TODO: publish device created domain event + await this.deviceRepository.saveOne(device); const response = { result: 0, device: { id: device.id.value } }; diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-settings-update.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-settings-update.event-handler.ts index 6ece287b..5401371e 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-settings-update.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-settings-update.event-handler.ts @@ -34,6 +34,8 @@ export class DeviceSettingsUpdateEventHandler implements PacketEventHandler { message.device.updateConfig(deviceSettings); + // TODO: save entity and publish domain event + await message.respond('PUSH_DEVICE_AGENT_SETTING_RSP', { result: 0 }); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-time-update.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-time-update.event-handler.ts new file mode 100644 index 00000000..0fdae5b1 --- /dev/null +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-time-update.event-handler.ts @@ -0,0 +1,19 @@ +import { DomainException } from '@agnoc/toolkit'; +import type { PacketEventHandler } from '../../packet.event-handler'; +import type { PacketMessage } from '../../packet.message'; + +export class DeviceTimeUpdateEventHandler implements PacketEventHandler { + readonly eventName = 'DEVICE_GETTIME_RSP'; + + async handle(message: PacketMessage<'DEVICE_GETTIME_RSP'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + // TODO: save device time + // { + // timestamp: object.body.deviceTime * 1000, + // offset: -1 * ((object.body.deviceTimezone || 0) / 60), + // }; + } +} diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-upgrade-info.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-upgrade-info.event-handler.ts new file mode 100644 index 00000000..c2798d20 --- /dev/null +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-upgrade-info.event-handler.ts @@ -0,0 +1,17 @@ +import { DomainException } from '@agnoc/toolkit'; +import type { PacketEventHandler } from '../../packet.event-handler'; +import type { PacketMessage } from '../../packet.message'; + +export class DeviceUpgradeInfoEventHandler implements PacketEventHandler { + readonly eventName = 'PUSH_DEVICE_PACKAGE_UPGRADE_INFO_REQ'; + + async handle(message: PacketMessage<'PUSH_DEVICE_PACKAGE_UPGRADE_INFO_REQ'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + // TODO: save device upgrade info + + await message.connection.send('PUSH_DEVICE_PACKAGE_UPGRADE_INFO_RSP', { result: 0 }); + } +} diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-version-update.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-version-update.event-handler.ts index a5897efa..1d4ce738 100644 --- a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-version-update.event-handler.ts +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-version-update.event-handler.ts @@ -15,6 +15,8 @@ export class DeviceVersionUpdateEventHandler implements PacketEventHandler { message.device.updateVersion(new DeviceVersion({ software: data.softwareVersion, hardware: data.hardwareVersion })); + // TODO: save entity and publish domain event + await message.respond('DEVICE_VERSION_INFO_UPDATE_RSP', { result: 0 }); } } diff --git a/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-wlan-update.event-handler.ts b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-wlan-update.event-handler.ts new file mode 100644 index 00000000..7366b9c9 --- /dev/null +++ b/packages/adapter-tcp/src/event-handlers/packet-event-handlers/device-wlan-update.event-handler.ts @@ -0,0 +1,28 @@ +import { DeviceWlan } from '@agnoc/domain'; +import { DomainException } from '@agnoc/toolkit'; +import type { PacketEventHandler } from '../../packet.event-handler'; +import type { PacketMessage } from '../../packet.message'; + +export class DeviceWlanUpdateEventHandler implements PacketEventHandler { + readonly eventName = 'DEVICE_WLAN_INFO_GETTING_RSP'; + + async handle(message: PacketMessage<'DEVICE_WLAN_INFO_GETTING_RSP'>): Promise { + if (!message.device) { + throw new DomainException('Device not found'); + } + + const data = message.packet.payload.object.body; + + message.device.updateWlan( + new DeviceWlan({ + ipv4: data.ipv4, + ssid: data.ssid, + port: data.port, + mask: data.mask, + mac: data.mac, + }), + ); + + // TODO: save entity and publish domain event + } +} diff --git a/packages/adapter-tcp/src/mappers/device-error.mapper.ts b/packages/adapter-tcp/src/mappers/device-error.mapper.ts index acd8f77f..30593c0c 100644 --- a/packages/adapter-tcp/src/mappers/device-error.mapper.ts +++ b/packages/adapter-tcp/src/mappers/device-error.mapper.ts @@ -2,7 +2,7 @@ import { DeviceError, DeviceErrorValue } from '@agnoc/domain'; import { DomainException, NotImplementedException } from '@agnoc/toolkit'; import type { Mapper } from '@agnoc/toolkit'; -const ROBOT_TO_DOMAIN = { +const ROBOT_TO_DOMAIN: Record = { 0: DeviceErrorValue.None, 2003: DeviceErrorValue.LowPowerPlanDis, 2100: DeviceErrorValue.BrokenGoHome, @@ -53,10 +53,9 @@ export class DeviceErrorMapper implements Mapper { throw new DomainException(`Unable to map error code '${error}' to domain value`); } - const value = ROBOT_TO_DOMAIN[error as keyof typeof ROBOT_TO_DOMAIN]; + const value = ROBOT_TO_DOMAIN[error]; - // @ts-expect-error unknown error - return new DeviceError({ value }); + return new DeviceError(value); } fromDomain(): never { diff --git a/packages/eslint-config/typescript.js b/packages/eslint-config/typescript.js index e168d248..af7c0c2e 100644 --- a/packages/eslint-config/typescript.js +++ b/packages/eslint-config/typescript.js @@ -36,6 +36,7 @@ module.exports = { 'node/no-extraneous-import': 'off', 'node/no-unsupported-features/es-syntax': 'off', 'security/detect-object-injection': 'off', + '@typescript-eslint/require-await': 'off', '@typescript-eslint/explicit-module-boundary-types': 'error', '@typescript-eslint/consistent-type-imports': 'warn', '@typescript-eslint/consistent-type-exports': 'warn',