From 59f2c277bd928c0425788334c7c78efadc75b694 Mon Sep 17 00:00:00 2001 From: NurAlan Date: Mon, 8 Dec 2025 18:53:31 +0700 Subject: [PATCH] fix: handling data error from internal crestron --- src/helpers/utils.ts | 23 ++++++++++++++++++ src/modules/device/commands/command.ts | 17 +++++++++++--- src/modules/device/commands/service.ts | 32 +++++++++----------------- src/modules/device/router.ts | 17 ++++---------- src/modules/device/schema.ts | 6 ++--- 5 files changed, 56 insertions(+), 39 deletions(-) diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index 1d173e2..9546b32 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -1,3 +1,26 @@ export const passwordHash = (password: string) => Bun.password.hashSync(password, { algorithm: 'bcrypt' }) export const passwordVerify = (password: string, hash: string) => Bun.password.verifySync(password, hash) + +export const dataMapping = [ + { + deviceName: 'AC', + command: 'AC=', + }, + { + deviceName: 'L', + command: 'Light=', + }, + { + deviceName: 'DL', + command: 'Doorlock=', + }, + { + deviceName: 'BL', + command: 'Blind=', + }, + { + deviceName: 'BL', + command: 'Blind=', + }, +] diff --git a/src/modules/device/commands/command.ts b/src/modules/device/commands/command.ts index 97e6fc2..4ab3aa9 100644 --- a/src/modules/device/commands/command.ts +++ b/src/modules/device/commands/command.ts @@ -1,7 +1,7 @@ import { httpConfig } from '~/config' import logger from '~/plugins/logger' -export async function sendCommandToThirdParty(topicData: string, payload: string): Promise { +export async function sendCommandToThirdParty(topicData: string, payload: string) { try { const response = await fetch(`${httpConfig.baseUrl}/command`, { method: 'POST', @@ -13,10 +13,21 @@ export async function sendCommandToThirdParty(topicData: string, payload: string payload, }), }) - logger.info({ msg: 'Third-party command sent successfully', topic: topicData, status: response.status }) + if (response.status != 200) { + return { + status: response.status, + message: response.statusText, + data: null, + } + } + return { + status: response.status, + message: response.statusText, + data: await response.json(), + } } catch (error) { logger.error({ msg: 'Failed to send command to third-party service', topic: topicData, error: (error as Error).message }) - throw new Error('third_party_command_failed') + throw error } } diff --git a/src/modules/device/commands/service.ts b/src/modules/device/commands/service.ts index 2dc7bcd..ea0c196 100644 --- a/src/modules/device/commands/service.ts +++ b/src/modules/device/commands/service.ts @@ -1,32 +1,22 @@ +import { dataMapping } from '~/helpers/utils' import { DeviceCommandBody } from '../schema' import { sendCommandToThirdParty } from './command' export default abstract class CommandService { static async sendCommand(body: DeviceCommandBody): Promise<{ - status: 'success' - message: 'Command accepted' + status: string + message: string receivedAt: string }> { - try { - const topicData = `${body.merchantName}/${body.floorName}_${body.unitNumber}-${body.deviceName}-${body.roomName}-${body.deviceType}-${body.commandType}-${body.towerNumber}` - - if (topicData == 'SAVY/L2_01-L-LV-S-C-T1' && ['On', 'Off'].includes(body.payload.action)) { - return { - status: 'success', - message: 'Command accepted', - receivedAt: new Date().toISOString(), - } + const topicData = `${body.merchantName}/${body.floorName}_${body.unitNumber}-${body.deviceName}-${body.roomName}-${body.deviceType}-${body.commandType}-${body.towerNumber}` + const cmd = dataMapping.find((device) => device.deviceName == body.deviceName) + const request = await sendCommandToThirdParty(topicData, `${cmd?.command}${body.payload.action}`) + if (request.status !== 200) { + return { + status: 'error' as const, + message: request.status == 404 ? 'Device not found' : 'Command failed' as const, + receivedAt: new Date().toISOString(), } - if (topicData == 'SAVY/L2_01-BL-LV-S-C-T1' && ['Open', 'Closed'].includes(body.payload.action)) { - return { - status: 'success', - message: 'Command accepted', - receivedAt: new Date().toISOString(), - } - } - await sendCommandToThirdParty(topicData, body.payload.action) - } catch { - throw new Error('internal_error') } return { status: 'success' as const, diff --git a/src/modules/device/router.ts b/src/modules/device/router.ts index 8f7eb3b..14bd4b4 100644 --- a/src/modules/device/router.ts +++ b/src/modules/device/router.ts @@ -12,19 +12,12 @@ export const router = new Elysia({ }) .use(apiKeyAuthMacro) .post('/command', async ({ body, set }) => { - try { - const result = await CommandService.sendCommand(body) - return result - } catch (error) { - if (error instanceof Error && error.message in deviceErrorResponseMap) { - const { status, response } = deviceErrorResponseMap[error.message] - set.status = status - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return response as any - } - set.status = 500 - return { status: 'internal_error', message: 'Server error' } + const result = await CommandService.sendCommand(body) + if (result.status === 'error' && result.message === 'Device not found') { + set.status = 404 + return { status: 'not_found', message: 'Device not found' } } + return result }, { body: deviceCommandBody, response: deviceCommandResponseSchema, diff --git a/src/modules/device/schema.ts b/src/modules/device/schema.ts index a678377..3461e71 100644 --- a/src/modules/device/schema.ts +++ b/src/modules/device/schema.ts @@ -32,8 +32,8 @@ export type DeviceQueryParams = z.infer // Response schemas export const deviceCommandResponseSchema = { 200: z.object({ - status: z.literal('success'), - message: z.literal('Command accepted'), + status: z.string(), + message: z.string(), receivedAt: z.string().datetime(), }), 400: z.object({ @@ -56,7 +56,7 @@ export const deviceCommandResponseSchema = { }), 404: z.object({ status: z.literal('not_found'), - message: z.literal('Device status not found'), + message: z.literal('Device not found'), }), 500: z.object({ status: z.literal('internal_error'),