diff --git a/cli/src/lib/conn.ts b/cli/src/lib/conn.ts index ab04ec9d11..00f0186d74 100644 --- a/cli/src/lib/conn.ts +++ b/cli/src/lib/conn.ts @@ -49,8 +49,8 @@ const conn = (options: ConnectOptions) => { basicLog.close() }) - client.on('disconnect', () => { - basicLog.disconnect() + client.on('disconnect', (packet: IDisconnectPacket) => { + basicLog.disconnect(packet) }) } @@ -78,7 +78,7 @@ const benchConn = async (options: BenchConnectOptions) => { const start = Date.now() for (let i = 1; i <= count; i++) { - ;((i: number, connOpts: mqtt.IClientOptions) => { + ; ((i: number, connOpts: mqtt.IClientOptions) => { const opts = { ...connOpts } opts.clientId = clientId.includes('%i') ? clientId.replaceAll('%i', i.toString()) : `${clientId}_${i}` @@ -124,8 +124,8 @@ const benchConn = async (options: BenchConnectOptions) => { benchLog.close(connectedCount, count, opts.clientId!) }) - client.on('disconnect', () => { - basicLog.disconnect(opts.clientId!) + client.on('disconnect', (packet: IDisconnectPacket) => { + basicLog.disconnect(packet, opts.clientId!) }) })(i, connOpts) diff --git a/cli/src/lib/pub.ts b/cli/src/lib/pub.ts index f0143fa181..4d23cc308f 100644 --- a/cli/src/lib/pub.ts +++ b/cli/src/lib/pub.ts @@ -142,8 +142,8 @@ const multisend = ( reconnectPeriod ? sender.cork() : process.exit(1) }) - client.on('disconnect', () => { - basicLog.disconnect() + client.on('disconnect', (packet: IDisconnectPacket) => { + basicLog.disconnect(packet) }) } @@ -354,8 +354,8 @@ const multiPub = async (commandType: CommandType, options: BenchPublishOptions | benchLog.close(connectedCount, count, opts.clientId!) }) - client.on('disconnect', () => { - basicLog.disconnect(opts.clientId!) + client.on('disconnect', (packet: IDisconnectPacket) => { + basicLog.disconnect(packet, opts.clientId!) }) })(i, connOpts) diff --git a/cli/src/lib/sub.ts b/cli/src/lib/sub.ts index 38ac0b222f..1aba0fe33c 100644 --- a/cli/src/lib/sub.ts +++ b/cli/src/lib/sub.ts @@ -145,8 +145,8 @@ const sub = (options: SubscribeOptions) => { !outputModeClean && basicLog.close() }) - client.on('disconnect', () => { - !outputModeClean && basicLog.disconnect() + client.on('disconnect', (packet: IDisconnectPacket) => { + !outputModeClean && basicLog.disconnect(packet) }) } @@ -286,8 +286,8 @@ const benchSub = async (options: BenchSubscribeOptions) => { benchLog.close(connectedCount, count, opts.clientId!) }) - client.on('disconnect', () => { - basicLog.disconnect(opts.clientId!) + client.on('disconnect', (packet: IDisconnectPacket) => { + basicLog.disconnect(packet, opts.clientId!) }) })(i, connOpts) diff --git a/cli/src/types/global.d.ts b/cli/src/types/global.d.ts index 127dcf9cfa..2df156d08a 100644 --- a/cli/src/types/global.d.ts +++ b/cli/src/types/global.d.ts @@ -155,6 +155,15 @@ declare global { interface LsOptions { scenarios: boolean } + + interface IDisconnectPacket { + cmd: 'disconnect', + qos: QoS + dup: boolean + retain: boolean + reasonCode: number, + length: number + } } export {} diff --git a/cli/src/utils/mqttErrorReason.ts b/cli/src/utils/mqttErrorReason.ts new file mode 100644 index 0000000000..404175f497 --- /dev/null +++ b/cli/src/utils/mqttErrorReason.ts @@ -0,0 +1,48 @@ +const mqttErrorReason: Record = { + 4: 'Disconnect with Will Message', + 16: 'No matching subscribers', + 17: 'No subscription existed', + 24: 'Continue authentication', + 25: 'Re-authenticate', + 128: 'Unspecified error', + 129: 'Malformed Packet', + 130: 'Protocol Error', + 131: 'Implementation specific error', + 132: 'Unsupported Protocol Version', + 133: 'Client Identifier not valid', + 134: 'Bad User Name or Password', + 135: 'Not authorized', + 136: 'Server unavailable', + 137: 'Server busy', + 138: 'Banned', + 139: 'Server shutting down', + 140: 'Bad authentication method', + 141: 'Keep Alive timeout', + 142: 'Session taken over', + 143: 'Topic Filter invalid', + 144: 'Topic Name invalid', + 145: 'Packet Identifier in use', + 146: 'Packet Identifier not found', + 147: 'Receive Maximum exceeded', + 148: 'Topic Alias invalid', + 149: 'Packet too large', + 150: 'Message rate too high', + 151: 'Quota exceeded', + 152: 'Administrative action', + 153: 'Payload format invalid', + 154: 'Retain not supported', + 155: 'QoS not supported', + 156: 'Use another server', + 157: 'Server moved', + 158: 'Shared Subscriptions not supported', + 159: 'Connection rate exceeded', + 160: 'Maximum connect time', + 161: 'Subscription Identifiers not supported', + 162: 'Wildcard Subscriptions not supported', +} + +const getErrorReason = (code: number) => { + return mqttErrorReason[code] ?? 'Unknown error' +} + +export default getErrorReason diff --git a/cli/src/utils/signale.ts b/cli/src/utils/signale.ts index de01d795c6..017f979658 100644 --- a/cli/src/utils/signale.ts +++ b/cli/src/utils/signale.ts @@ -1,6 +1,7 @@ import { Signale } from 'signale' import chalk from 'chalk' import { inspect } from 'util' +import getErrorReason from './mqttErrorReason' const option = { config: { @@ -30,8 +31,7 @@ const basicLog = { signale.await('Connecting...') } else { signale.await( - `Connecting using configuration file, host: ${host}, port: ${port}${topic ? `, topic: ${topic}` : ''}${ - message ? `, message: ${message}` : '' + `Connecting using configuration file, host: ${host}, port: ${port}${topic ? `, topic: ${topic}` : ''}${message ? `, message: ${message}` : '' }`, ) } @@ -48,8 +48,11 @@ const basicLog = { close: () => signale.error('Connection closed'), reconnecting: () => signale.await('Reconnecting...'), reconnectTimesLimit: () => signale.error('Exceed the maximum reconnect times limit, stop retry'), - disconnect: (clientId?: string) => - signale.warn(`${clientId ? `Client ID: ${clientId}, ` : ''}The Broker has actively disconnected`), + disconnect: (packet: IDisconnectPacket, clientId?: string) => { + const { reasonCode } = packet + const reason = reasonCode === 0 ? 'Normal disconnection' : getErrorReason(reasonCode) + signale.warn(`${clientId ? `Client ID: ${clientId}, ` : ''}The Broker has actively disconnected, Reason: ${reason} (Code: ${reasonCode})`) + } } const benchLog = {