diff --git a/apps/backend/src/adapters/inbound/websocket/robot.gateway.ts b/apps/backend/src/adapters/inbound/websocket/robot.gateway.ts index 6a2de95..0e9a806 100644 --- a/apps/backend/src/adapters/inbound/websocket/robot.gateway.ts +++ b/apps/backend/src/adapters/inbound/websocket/robot.gateway.ts @@ -11,6 +11,7 @@ import { Inject, Logger, forwardRef } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { Server, Socket } from 'socket.io'; import { DeviceService } from '../../../core/services/device.service'; +import { DeviceStatus } from '../../../core/domain/entities/device.entity'; import { JwtPayload } from '../rest/auth/strategies/jwt.strategy'; import { IConversationPort, CONVERSATION_PORT } from '../../../core/ports/inbound/conversation.port'; import { IDeviceGatewayPort } from '../../../core/ports/outbound/device-gateway.port'; @@ -76,7 +77,7 @@ export class RobotGateway implements OnGatewayConnection, OnGatewayDisconnect, I client.data.homeId = payload.homeId; this.connectedDevices.set(payload.sub, client); - await this.deviceService.updateLastSeen(payload.sub); + await this.deviceService.setStatus(payload.sub, DeviceStatus.ONLINE); this.logger.log(`Device connected: ${device.name} (${payload.sub})`); client.emit('status', { state: 'idle' as RobotState }); @@ -86,11 +87,16 @@ export class RobotGateway implements OnGatewayConnection, OnGatewayDisconnect, I } } - handleDisconnect(client: AuthenticatedSocket) { + async handleDisconnect(client: AuthenticatedSocket) { const deviceId = client.data?.deviceId; if (deviceId) { this.connectedDevices.delete(deviceId); this.conversationPort.interrupt(deviceId); + try { + await this.deviceService.setStatus(deviceId, DeviceStatus.OFFLINE); + } catch (err) { + this.logger.warn(`Failed to mark ${deviceId} offline: ${String(err)}`); + } this.logger.log(`Device disconnected: ${deviceId}`); } } diff --git a/apps/backend/src/core/services/device.service.ts b/apps/backend/src/core/services/device.service.ts index 05897cd..425badd 100644 --- a/apps/backend/src/core/services/device.service.ts +++ b/apps/backend/src/core/services/device.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import * as bcrypt from 'bcrypt'; -import { Device } from '../domain/entities/device.entity'; +import { Device, DeviceStatus } from '../domain/entities/device.entity'; @Injectable() export class DeviceService { @@ -37,4 +37,11 @@ export class DeviceService { async updateLastSeen(id: string): Promise { await this.deviceRepository.update(id, { lastSeenAt: new Date() }); } + + async setStatus(id: string, status: DeviceStatus): Promise { + await this.deviceRepository.update(id, { + status, + lastSeenAt: new Date(), + }); + } }