From 2186e6c8f546cee2bc22bd5012aa5101adc8007c Mon Sep 17 00:00:00 2001 From: Wong Chi Him Sariel Date: Fri, 13 Sep 2024 19:03:27 +0900 Subject: [PATCH 1/2] feat(decoder): Add MsgPack support for decoding message --- package.json | 1 + src/components/MsgLeftItem.vue | 2 +- src/types/global.d.ts | 2 +- src/views/connections/ConnectionsDetail.vue | 14 ++++- yarn.lock | 63 +++++++++++++++++++++ 5 files changed, 79 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 248053520..266fbb190 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "moment": "^2.29.4", "monaco-editor": "^0.25.2", "mqtt": "4.3.7", + "msgpackr": "^1.11.0", "prismjs": "^1.29.0", "protobufjs": "^7.2.5", "reflect-metadata": "^0.1.13", diff --git a/src/components/MsgLeftItem.vue b/src/components/MsgLeftItem.vue index cdc45fd10..415a67111 100644 --- a/src/components/MsgLeftItem.vue +++ b/src/components/MsgLeftItem.vue @@ -166,7 +166,7 @@ export default class MsgLeftItem extends Vue { return } try { - if (this.payload && ['JSON', 'CBOR'].includes(this.msgType) && !this.msgError) { + if (this.payload && ['JSON', 'CBOR', 'MsgPack'].includes(this.msgType) && !this.msgError) { this.hightlight = true this.$nextTick(() => { Prism.highlightAllUnder(this.$refs.msgLeftItem as HTMLElement) diff --git a/src/types/global.d.ts b/src/types/global.d.ts index c313e878b..74ba3ae90 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -11,7 +11,7 @@ declare global { type Protocol = 'ws' | 'wss' | 'mqtt' | 'mqtts' - type PayloadType = 'Plaintext' | 'Base64' | 'JSON' | 'Hex' | 'CBOR' + type PayloadType = 'Plaintext' | 'Base64' | 'JSON' | 'Hex' | 'CBOR' | 'MsgPack' type QoS = 0 | 1 | 2 diff --git a/src/views/connections/ConnectionsDetail.vue b/src/views/connections/ConnectionsDetail.vue index f1b83c843..771a7bba6 100644 --- a/src/views/connections/ConnectionsDetail.vue +++ b/src/views/connections/ConnectionsDetail.vue @@ -245,7 +245,11 @@ @change="handleReceivedMsgTypeChange" > - + @@ -324,6 +328,7 @@ import _ from 'lodash' import { Subject, fromEvent } from 'rxjs' import { bufferTime, map, filter, takeUntil, shareReplay } from 'rxjs/operators' import cbor from 'cbor' +import { unpack } from 'msgpackr' import time from '@/utils/time' import matchMultipleSearch from '@/utils/matchMultipleSearch' @@ -1770,6 +1775,13 @@ export default class ConnectionsDetail extends Vue { throw error } } + if (receiveType === 'MsgPack') { + try { + return jsonStringify(unpack(receiveValue), null, 2) + } catch (error) { + throw error + } + } return receiveValue.toString() } if (way === 'publish') { diff --git a/yarn.lock b/yarn.lock index e6538945f..e7fb66e18 100644 --- a/yarn.lock +++ b/yarn.lock @@ -977,6 +977,36 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz#9edec61b22c3082018a79f6d1c30289ddf3d9d11" + integrity sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw== + +"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz#33677a275204898ad8acbf62734fc4dc0b6a4855" + integrity sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw== + +"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz#19edf7cdc2e7063ee328403c1d895a86dd28f4bb" + integrity sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg== + +"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz#94fb0543ba2e28766c3fc439cabbe0440ae70159" + integrity sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw== + +"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz#4a0609ab5fe44d07c9c60a11e4484d3c38bbd6e3" + integrity sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg== + +"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz#0aa5502d547b57abfc4ac492de68e2006e417242" + integrity sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -4587,6 +4617,11 @@ detect-libc@^2.0.0: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== +detect-libc@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + detect-node@^2.0.4: version "2.1.0" resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" @@ -8659,6 +8694,27 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +msgpackr-extract@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz#e9d87023de39ce714872f9e9504e3c1996d61012" + integrity sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA== + dependencies: + node-gyp-build-optional-packages "5.2.2" + optionalDependencies: + "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.3" + +msgpackr@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.11.0.tgz#8321d52333048cadc749f56385e3231e65337091" + integrity sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw== + optionalDependencies: + msgpackr-extract "^3.0.2" + multicast-dns-service-types@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" @@ -8757,6 +8813,13 @@ node-forge@^0.10.0: resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== +node-gyp-build-optional-packages@5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz#522f50c2d53134d7f3a76cd7255de4ab6c96a3a4" + integrity sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw== + dependencies: + detect-libc "^2.0.1" + node-gyp@8.x: version "8.4.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" From ca390b1072420042ddfe972b20758305877c02bc Mon Sep 17 00:00:00 2001 From: Wong Chi Him Sariel Date: Fri, 13 Sep 2024 19:34:54 +0900 Subject: [PATCH 2/2] feat(desktop): Add MsgPack support for publishing message --- cli/src/utils/convertPayload.ts | 17 +++++++++++++++++ src/components/MsgPublish.vue | 4 ++-- src/views/connections/ConnectionsDetail.vue | 14 ++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/cli/src/utils/convertPayload.ts b/cli/src/utils/convertPayload.ts index 1531f194c..7d03a4148 100644 --- a/cli/src/utils/convertPayload.ts +++ b/cli/src/utils/convertPayload.ts @@ -1,6 +1,7 @@ import chalk from 'chalk' import { jsonParse, jsonStringify } from './jsonUtils' import cbor from 'cbor' +import { pack, unpack } from 'msgpackr' import { basicLog } from './logWrapper' type Action = 'encode' | 'decode' @@ -42,6 +43,20 @@ const convertCBOR = (value: Buffer | string, action: Action) => { } } +/** + * Converts a MsgPack payload to JSON or vice versa. + * @param value - The MsgPack payload to convert. + * @param action - The action to perform: 'decode' to convert MsgPack to JSON, 'encode' to convert JSON to MsgPack. + * @returns The converted payload. + */ +const convertMsgPack = (value: Buffer | string, action: Action) => { + try { + return action === 'decode' ? jsonStringify(unpack(value as Buffer), null, 2) : pack(JSON.parse(value.toString())) + } catch (err) { + return handleError(err, value, action) + } +} + /** * Converts the payload based on the specified format and action. * @param payload - The payload to be converted. @@ -56,6 +71,7 @@ const convertPayload = (payload: Buffer | string, format?: FormatType, action: A json: () => convertJSON(payload, 'encode'), hex: () => Buffer.from(payload.toString().replace(/\s+/g, ''), 'hex'), cbor: () => convertCBOR(payload, 'encode'), + msgpack: () => convertMsgPack(payload, 'encode'), binary: () => payload, default: () => Buffer.from(payload.toString(), 'utf-8'), }, @@ -64,6 +80,7 @@ const convertPayload = (payload: Buffer | string, format?: FormatType, action: A json: () => convertJSON(payload, 'decode'), hex: () => payload.toString('hex').replace(/(.{4})/g, '$1 '), cbor: () => convertCBOR(payload, 'decode'), + msgpack: () => convertMsgPack(payload, 'decode'), binary: () => payload, default: () => payload.toString('utf-8'), }, diff --git a/src/components/MsgPublish.vue b/src/components/MsgPublish.vue index b9410dab8..d3b89f3ab 100644 --- a/src/components/MsgPublish.vue +++ b/src/components/MsgPublish.vue @@ -302,7 +302,7 @@ export default class MsgPublish extends Vue { } private payloadLang = 'json' private payloadType: PayloadType = 'JSON' - private payloadOptions: PayloadType[] = ['Plaintext', 'JSON', 'Base64', 'Hex', 'CBOR'] + private payloadOptions: PayloadType[] = ['Plaintext', 'JSON', 'Base64', 'Hex', 'CBOR', 'MsgPack'] @Watch('editorHeight') private handleHeightChanged() { @@ -311,7 +311,7 @@ export default class MsgPublish extends Vue { @Watch('payloadType') private handleTypeChange(val: PayloadType, oldVal: PayloadType) { const { payload } = this.msgRecord - if (['CBOR', 'JSON'].includes(val)) { + if (['CBOR', 'JSON', 'MsgPack'].includes(val)) { this.payloadLang = 'json' } else { this.payloadLang = 'plaintext' diff --git a/src/views/connections/ConnectionsDetail.vue b/src/views/connections/ConnectionsDetail.vue index 771a7bba6..af8d39376 100644 --- a/src/views/connections/ConnectionsDetail.vue +++ b/src/views/connections/ConnectionsDetail.vue @@ -328,7 +328,7 @@ import _ from 'lodash' import { Subject, fromEvent } from 'rxjs' import { bufferTime, map, filter, takeUntil, shareReplay } from 'rxjs/operators' import cbor from 'cbor' -import { unpack } from 'msgpackr' +import { pack, unpack } from 'msgpackr' import time from '@/utils/time' import matchMultipleSearch from '@/utils/matchMultipleSearch' @@ -1296,7 +1296,7 @@ export default class ConnectionsDetail extends Vue { this.updateMeta(receivedMessage, 'function', 'received') this.updateMeta(receivedMessage, 'schema', 'received') this.updateMetaMsgType(receivedMessage, this.receivedMsgType) - if (['JSON', 'CBOR'].includes(this.receivedMsgType) && jsonMsgError) { + if (['JSON', 'CBOR', 'MsgPack'].includes(this.receivedMsgType) && jsonMsgError) { this.updateMetaError(receivedMessage, jsonMsgError) } if (isLargeData(receivedMessage.payload)) { @@ -1748,6 +1748,16 @@ export default class ConnectionsDetail extends Vue { return undefined } } + if (publishType === 'MsgPack') { + try { + return pack(JSON.parse(publishValue)) + } catch (error) { + const err = error as Error + let errorMessage = `${this.$t('connections.publishMsg')} ${err.toString()}` + this.$message.error(errorMessage) + return undefined + } + } return publishValue } const genReceivePayload = (receiveType: PayloadType, receiveValue: Buffer) => {