feat(M06-C): 完成设备协议适配与消息幂等

This commit is contained in:
Codex
2026-06-22 18:29:07 +08:00
parent c96045f6ef
commit e795cdb693
15 changed files with 867 additions and 17 deletions
+17 -3
View File
@@ -26,6 +26,7 @@ export interface MqttClientLike {
}
export type MqttClientFactory = (url: string, options: IClientOptions) => MqttClientLike;
export type MqttMessageHandler = (topic: string, payload: Buffer) => Promise<void>;
export interface MqttHealthSnapshot {
configured: boolean;
@@ -39,7 +40,14 @@ export interface MqttHealthSnapshot {
lastError: string | null;
}
export class MqttService {
export interface MqttTransport {
start(): void;
stop(): Promise<void>;
publishDeviceCommand(deviceId: string, payload: Buffer | string): Promise<void>;
health(): MqttHealthSnapshot;
}
export class MqttService implements MqttTransport {
private client: MqttClientLike | null = null;
private subscriptionsReady = false;
private reconnectCount = 0;
@@ -51,7 +59,8 @@ export class MqttService {
constructor(
private readonly config: AppConfig['mqtt'],
private readonly clientFactory: MqttClientFactory = connect as MqttClientFactory
private readonly clientFactory: MqttClientFactory = connect as MqttClientFactory,
private readonly messageHandler?: MqttMessageHandler
) {}
start(): void {
@@ -89,7 +98,7 @@ export class MqttService {
this.client.on('error', (error: Error) => {
this.lastError = sanitizeError(error);
});
this.client.on('message', (_topic: string, payload: Buffer) => {
this.client.on('message', (topic: string, payload: Buffer) => {
if (payload.length > this.config.maxMessageBytes) {
this.rejectedOversizeMessages += 1;
this.lastError = `MQTT message exceeded ${this.config.maxMessageBytes} bytes`;
@@ -97,6 +106,11 @@ export class MqttService {
}
this.receivedMessages += 1;
this.lastMessageAt = new Date().toISOString();
void this.messageHandler?.(topic, payload).catch((error: unknown) => {
this.lastError = sanitizeError(
error instanceof Error ? error : new Error('MQTT message handler failed')
);
});
});
}