From 0acdc4eae26c1ad55395f1bef2b4d97b17afdb0e Mon Sep 17 00:00:00 2001 From: XL-YiBai Date: Sat, 30 Mar 2024 21:48:29 +0800 Subject: [PATCH] feat(cli): display the reason and code for the disconnection --- cli/src/lib/conn.ts | 10 ++-- cli/src/lib/pub.ts | 8 ++-- cli/src/lib/sub.ts | 8 ++-- cli/src/types/global.d.ts | 9 ++++ cli/src/utils/mqttErrorReason.ts | 48 +++++++++++++++++++ cli/src/utils/signale.ts | 11 +++-- src/lang/connections.ts | 10 ++-- src/views/connections/ConnectionsDetail.vue | 2 +- web/src/lang/connections.ts | 6 +-- .../views/connections/ConnectionsDetail.vue | 2 +- 10 files changed, 87 insertions(+), 27 deletions(-) create mode 100644 cli/src/utils/mqttErrorReason.ts diff --git a/cli/src/lib/conn.ts b/cli/src/lib/conn.ts index ab04ec9d1..00f0186d7 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 f0143fa18..4d23cc308 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 38ac0b222..1aba0fe33 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 127dcf9cf..2df156d08 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 000000000..404175f49 --- /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 de01d795c..017f97965 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 = { diff --git a/src/lang/connections.ts b/src/lang/connections.ts index 65d4c7da9..917e5c59e 100644 --- a/src/lang/connections.ts +++ b/src/lang/connections.ts @@ -846,11 +846,11 @@ export default { hu: 'Üzenetmegőrzés kezelése', }, onDisconnect: { - zh: '服务器已主动断开连接, Reason: {0} (Code: {1})', - en: 'The Broker has actively disconnected, Reason: {0} (Code: {1})', - tr: 'Sunucu aktif bir şekilde bağlantıyı kesmiştir, Reason: {0} (Code: {1})', - ja: 'サーバーから積極的に接続が切断されました, Reason: {0} (Code: {1})', - hu: 'A kiszolgáló aktívan bontotta a kapcsolatot, Reason: {0} (Code: {1})', + zh: '服务器已主动断开连接, Reason: {reason} (Code: {reasonCode})', + en: 'The Broker has actively disconnected, Reason: {reason} (Code: {reasonCode})', + tr: 'Sunucu aktif bir şekilde bağlantıyı kesmiştir, Reason: {reason} (Code: {reasonCode})', + ja: 'サーバーから積極的に接続が切断されました, Reason: {reason} (Code: {reasonCode})', + hu: 'A kiszolgáló aktívan bontotta a kapcsolatot, Reason: {reason} (Code: {reasonCode})', }, hideConnections: { zh: '隐藏连接列表', diff --git a/src/views/connections/ConnectionsDetail.vue b/src/views/connections/ConnectionsDetail.vue index 64be63e46..afa52f523 100644 --- a/src/views/connections/ConnectionsDetail.vue +++ b/src/views/connections/ConnectionsDetail.vue @@ -1106,7 +1106,7 @@ export default class ConnectionsDetail extends Vue { const reasonCode = packet.reasonCode! const reason = reasonCode === 0 ? 'Normal disconnection' : getErrorReason('5.0', reasonCode) this.notifyMsgWithCopilot( - this.$t('connections.onDisconnect', [reason, reasonCode]) as string, + this.$t('connections.onDisconnect', { reason, reasonCode }) as string, JSON.stringify(packet), () => {}, 'warning', diff --git a/web/src/lang/connections.ts b/web/src/lang/connections.ts index a91f10413..b97ca37e7 100644 --- a/web/src/lang/connections.ts +++ b/web/src/lang/connections.ts @@ -425,8 +425,8 @@ export default { ja: '保持メッセージの取り扱い', }, onDisconnect: { - zh: '服务器已主动断开连接, Reason: {0} (Code: {1})', - en: 'The Broker has actively disconnected, Reason: {0} (Code: {1})', - ja: 'サーバーから積極的に接続が切断されました, Reason: {0} (Code: {1})', + zh: '服务器已主动断开连接, Reason: {reason} (Code: {reasonCode})', + en: 'The Broker has actively disconnected, Reason: {reason} (Code: {reasonCode})', + ja: 'サーバーから積極的に接続が切断されました, Reason: {reason} (Code: {reasonCode})', }, } diff --git a/web/src/views/connections/ConnectionsDetail.vue b/web/src/views/connections/ConnectionsDetail.vue index 611e14685..5b13d2461 100644 --- a/web/src/views/connections/ConnectionsDetail.vue +++ b/web/src/views/connections/ConnectionsDetail.vue @@ -739,7 +739,7 @@ export default class ConnectionsDetail extends Vue { const reasonCode = packet.reasonCode! const reason = reasonCode === 0 ? 'Normal disconnection' : getErrorReason('5.0', reasonCode) this.$notify({ - title: this.$t('connections.onDisconnect', [reason, reasonCode]) as string, + title: this.$t('connections.onDisconnect', { reason, reasonCode }) as string, message: '', type: 'warning', duration: 3000,