From 7e29dd1112df2ff00da5d5d2f1f9e4a6b069bb2e Mon Sep 17 00:00:00 2001 From: EmixamPP Date: Thu, 25 Jul 2024 14:02:39 +0200 Subject: [PATCH 1/7] Revert "fix(browser): add `navigator` polifilly for wechat mini (#1796)" This reverts commit c26908a242fa1f573689b03f554bb95d83e61c84. since the polyfill hardcode navigator, it is impossible to determine the userAgent at runtime --- esbuild.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/esbuild.js b/esbuild.js index c05b0bfb1..f157201d7 100644 --- a/esbuild.js +++ b/esbuild.js @@ -21,15 +21,7 @@ const options = { polyfillNode({ polyfills: [ 'readable-stream' - ], - globals: { - global: false, - __dirname: false, - __filename: false, - buffer: true, - process: true, - navigator: true, // Needed for WeChat, ref #1789 - } + ] }), { name: 'resolve-package-json', From 4960dab77bef34d84a74d118a3c94013c8e2b926 Mon Sep 17 00:00:00 2001 From: EmixamPP Date: Thu, 25 Jul 2024 14:08:46 +0200 Subject: [PATCH 2/7] doc(README): update WeChat instructions --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f13a9a98e..f8815485d 100644 --- a/README.md +++ b/README.md @@ -905,6 +905,7 @@ Supports [WeChat Mini Program](https://mp.weixin.qq.com/). Use the `wxs` protoco ```js import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only' // import before mqtt. +import 'esbuild-plugin-polyfill-node/polyfills/navigator' const mqtt = require("mqtt"); const client = mqtt.connect("wxs://test.mosquitto.org", { timerVariant: 'native' // more info ref issue: #1797 From 68370930f2abd4ae5279d09085036d78c38026c9 Mon Sep 17 00:00:00 2001 From: EmixamPP Date: Thu, 25 Jul 2024 15:31:38 +0200 Subject: [PATCH 3/7] feat: add forceNativeWebSocket client option --- README.md | 3 ++- src/lib/client.ts | 6 +++++- src/lib/connect/index.ts | 41 +++++++++++++++++++++------------------- src/lib/connect/ws.ts | 4 ++-- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index f8815485d..a5c2fa7aa 100644 --- a/README.md +++ b/README.md @@ -454,7 +454,7 @@ The arguments are: - `messageExpiryInterval`: value is the lifetime of the Will Message in seconds and is sent as the Publication Expiry Interval when the Server publishes the Will Message `number`, - `contentType`: describing the content of the Will Message `string`, - `responseTopic`: String which is used as the Topic Name for a response message `string`, - - `correlationData`: The Correlation Data is used by the sender of the Request Message to identify which request the Response Message is for when it is received `binary`, + - `correlationData`: The Correlation Data is used b`y the sender of the Request Message to identify which request the Response Message is for when it is received `binary`, - `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` - `transformWsUrl` : optional `(url, options, client) => url` function For ws/wss protocols only. Can be used to implement signing @@ -474,6 +474,7 @@ The arguments are: } ``` + - `forceNativeWebSocket`: set to true if you're having detection issues (i.e. the `ws does not work in the browser` exception) to force the use of native WebSocket. - `unixSocket`: if you want to connect to a unix socket, set this to true In case mqtts (mqtt over tls) is required, the `options` object is passed through to [`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback). If using a **self-signed certificate**, set `rejectUnauthorized: false`. However, be cautious as this exposes you to potential man in the middle attacks and isn't recommended for production. diff --git a/src/lib/client.ts b/src/lib/client.ts index da9597b7f..979153f6e 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -282,6 +282,10 @@ export interface IClientOptions extends ISecureClientOptions { * or pass a custom timer object */ timerVariant?: TimerVariant | Timer + /** + * false, set to true to force the use of native WebSocket if you're having issues with the detection + */ + forceNativeWebSocket?: boolean } export interface IClientPublishOptions { @@ -512,7 +516,7 @@ export default class MqttClient extends TypedEventEmitter = {} - -if (!IS_BROWSER) { - protocols.mqtt = require('./tcp').default - protocols.tcp = require('./tcp').default - protocols.ssl = require('./tls').default - protocols.tls = protocols.ssl - protocols.mqtts = require('./tls').default -} else { - protocols.wx = require('./wx').default - protocols.wxs = require('./wx').default - - protocols.ali = require('./ali').default - protocols.alis = require('./ali').default -} - -protocols.ws = require('./ws').default -protocols.wss = require('./ws').default - /** * Parse the auth attribute and merge username and password in the options object. * @@ -152,6 +133,28 @@ function connect( } } + const protocols: Record = {} + + if (!opts.forceNativeWebSocket && !IS_BROWSER) { + protocols.ws = require('./ws').streamBuilder + protocols.wss = require('./ws').streamBuilder + + protocols.mqtt = require('./tcp').default + protocols.tcp = require('./tcp').default + protocols.ssl = require('./tls').default + protocols.tls = protocols.ssl + protocols.mqtts = require('./tls').default + } else { + protocols.ws = require('./ws').browserStreamBuilder + protocols.wss = require('./ws').browserStreamBuilder + + protocols.wx = require('./wx').default + protocols.wxs = require('./wx').default + + protocols.ali = require('./ali').default + protocols.alis = require('./ali').default + } + if (!protocols[opts.protocol]) { const isSecure = ['mqtts', 'wss'].indexOf(opts.protocol) !== -1 // returns the first available protocol based on available protocols (that depends on environment) diff --git a/src/lib/connect/ws.ts b/src/lib/connect/ws.ts index 1e8060c9e..4437ceea4 100644 --- a/src/lib/connect/ws.ts +++ b/src/lib/connect/ws.ts @@ -44,7 +44,7 @@ function setDefaultOpts(opts: IClientOptions) { if (!opts.wsOptions) { options.wsOptions = {} } - if (!IS_BROWSER && opts.protocol === 'wss') { + if (!IS_BROWSER && !opts.forceNativeWebSocket && opts.protocol === 'wss') { // Add cert/key/ca etc options WSS_OPTIONS.forEach((prop) => { if ( @@ -298,4 +298,4 @@ const browserStreamBuilder: StreamBuilder = (client, opts) => { return stream } -export default IS_BROWSER ? browserStreamBuilder : streamBuilder +export { browserStreamBuilder, streamBuilder }; From d4d3d4b5f1605bdd1068e8423771c2cbd5839163 Mon Sep 17 00:00:00 2001 From: EmixamPP Date: Thu, 25 Jul 2024 15:36:23 +0200 Subject: [PATCH 4/7] Revert "feat: add compatibility with txiki.js (#1895)" This reverts commit 37b08c99fead5282e38b851ce1006f09521b038c. Not special support for txiki.js is required thanks to forceNativeWebSocket client option --- src/lib/is-browser.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/lib/is-browser.ts b/src/lib/is-browser.ts index d614d8be5..cdf926a3e 100644 --- a/src/lib/is-browser.ts +++ b/src/lib/is-browser.ts @@ -25,9 +25,6 @@ const isStandardBrowserEnv = () => { return false } -const isTxikijsEnv = () => - typeof navigator !== 'undefined' && navigator.userAgent === 'txiki.js' - const isWebWorkerEnv = () => Boolean( // eslint-disable-next-line no-restricted-globals @@ -40,10 +37,7 @@ const isReactNativeEnv = () => typeof navigator !== 'undefined' && navigator.product === 'ReactNative' const isBrowser = - isStandardBrowserEnv() || - isWebWorkerEnv() || - isReactNativeEnv() || - isTxikijsEnv() + isStandardBrowserEnv() || isWebWorkerEnv() || isReactNativeEnv() export const isWebWorker = isWebWorkerEnv() From a2b968645188539593132d36c4175f59a57ba4b0 Mon Sep 17 00:00:00 2001 From: EmixamPP Date: Thu, 25 Jul 2024 15:40:34 +0200 Subject: [PATCH 5/7] style: unify import name IS_BROWSER -> isBrowser --- src/lib/connect/index.ts | 4 ++-- src/lib/connect/ws.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/connect/index.ts b/src/lib/connect/index.ts index b4346c227..476cbcad2 100644 --- a/src/lib/connect/index.ts +++ b/src/lib/connect/index.ts @@ -6,7 +6,7 @@ import MqttClient, { MqttClientEventCallbacks, MqttProtocol, } from '../client' -import IS_BROWSER from '../is-browser' +import isBrowser from '../is-browser' import { StreamBuilder } from '../shared' // Handling the process.nextTick is not a function error in react-native applications. @@ -135,7 +135,7 @@ function connect( const protocols: Record = {} - if (!opts.forceNativeWebSocket && !IS_BROWSER) { + if (!opts.forceNativeWebSocket && !isBrowser) { protocols.ws = require('./ws').streamBuilder protocols.wss = require('./ws').streamBuilder diff --git a/src/lib/connect/ws.ts b/src/lib/connect/ws.ts index 4437ceea4..c833c55fa 100644 --- a/src/lib/connect/ws.ts +++ b/src/lib/connect/ws.ts @@ -3,7 +3,7 @@ import { Buffer } from 'buffer' import Ws, { ClientOptions } from 'ws' import _debug from 'debug' import { DuplexOptions, Transform } from 'readable-stream' -import IS_BROWSER from '../is-browser' +import isBrowser from '../is-browser' import MqttClient, { IClientOptions } from '../client' import { BufferedDuplex, writev } from '../BufferedDuplex' @@ -44,7 +44,7 @@ function setDefaultOpts(opts: IClientOptions) { if (!opts.wsOptions) { options.wsOptions = {} } - if (!IS_BROWSER && !opts.forceNativeWebSocket && opts.protocol === 'wss') { + if (!isBrowser && !opts.forceNativeWebSocket && opts.protocol === 'wss') { // Add cert/key/ca etc options WSS_OPTIONS.forEach((prop) => { if ( From 94b8323bdd5543e93b20a4bfa865cfd5c30465f7 Mon Sep 17 00:00:00 2001 From: EmixamPP Date: Thu, 25 Jul 2024 16:02:02 +0200 Subject: [PATCH 6/7] fixup! feat: add forceNativeWebSocket client option style: fix lint --- src/lib/client.ts | 2 +- src/lib/connect/ws.ts | 2 +- test-store_ApvD3c/000003.log | Bin 0 -> 945 bytes test-store_ApvD3c/CURRENT | 1 + test-store_ApvD3c/LOCK | 0 test-store_ApvD3c/LOG | 1 + test-store_ApvD3c/MANIFEST-000002 | Bin 0 -> 50 bytes 7 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 test-store_ApvD3c/000003.log create mode 100644 test-store_ApvD3c/CURRENT create mode 100644 test-store_ApvD3c/LOCK create mode 100644 test-store_ApvD3c/LOG create mode 100644 test-store_ApvD3c/MANIFEST-000002 diff --git a/src/lib/client.ts b/src/lib/client.ts index 979153f6e..4aa70a571 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -516,7 +516,7 @@ export default class MqttClient extends TypedEventEmitter { return stream } -export { browserStreamBuilder, streamBuilder }; +export { browserStreamBuilder, streamBuilder } diff --git a/test-store_ApvD3c/000003.log b/test-store_ApvD3c/000003.log new file mode 100644 index 0000000000000000000000000000000000000000..4d114906705a309c5eb34a68631021e33e1c362b GIT binary patch literal 945 zcmXSjv1xq9z{tn|0Zc%OQCu;RwWPSt(89>VOy`K!O${RhBNJT% zb6q3T5JO`tQ%fsj6FoCS( zW^u;SlKg_qYJ=;L!Rr7oPz=%S?o4EpU6*$N=55hNOBHixFVYT9DvbW1OBX0DHE}SMDg#v#dmT z)|?d28c^<81F&b!N${)@PS56pJ-g(@&$oFDjO<9BWx$n;8K{*qJ56{6ftGR-VW|bF Imf}ny0D(sxBLDyZ literal 0 HcmV?d00001 diff --git a/test-store_ApvD3c/CURRENT b/test-store_ApvD3c/CURRENT new file mode 100644 index 000000000..1a8485221 --- /dev/null +++ b/test-store_ApvD3c/CURRENT @@ -0,0 +1 @@ +MANIFEST-000002 diff --git a/test-store_ApvD3c/LOCK b/test-store_ApvD3c/LOCK new file mode 100644 index 000000000..e69de29bb diff --git a/test-store_ApvD3c/LOG b/test-store_ApvD3c/LOG new file mode 100644 index 000000000..20ad0be8b --- /dev/null +++ b/test-store_ApvD3c/LOG @@ -0,0 +1 @@ +2024/07/25-15:59:34.614236 702a367fe640 Delete type=3 #1 diff --git a/test-store_ApvD3c/MANIFEST-000002 b/test-store_ApvD3c/MANIFEST-000002 new file mode 100644 index 0000000000000000000000000000000000000000..bbbc585686bcbcc33686059c69d80b7b4e1291cd GIT binary patch literal 50 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAe$kRS-TOEg7@3$k8JJmE F7y#sj5K{mE literal 0 HcmV?d00001 From d1adfc26510bb3be381225432b1ce6cb3d37d927 Mon Sep 17 00:00:00 2001 From: EmixamPP Date: Fri, 26 Jul 2024 07:53:04 +0200 Subject: [PATCH 7/7] fixup! fixup! feat: add forceNativeWebSocket client option chore: remove test_store folder pushed refactor: load protocols only once refactor: use forceNativeWebSocket only for ws choice doc(README): typo + update forceNativeWebSocket behaviour description --- README.md | 17 ++++++------- src/lib/client.ts | 2 +- src/lib/connect/index.ts | 40 ++++++++++++++++-------------- test-store_ApvD3c/000003.log | Bin 945 -> 0 bytes test-store_ApvD3c/CURRENT | 1 - test-store_ApvD3c/LOCK | 0 test-store_ApvD3c/LOG | 1 - test-store_ApvD3c/MANIFEST-000002 | Bin 50 -> 0 bytes 8 files changed, 31 insertions(+), 30 deletions(-) delete mode 100644 test-store_ApvD3c/000003.log delete mode 100644 test-store_ApvD3c/CURRENT delete mode 100644 test-store_ApvD3c/LOCK delete mode 100644 test-store_ApvD3c/LOG delete mode 100644 test-store_ApvD3c/MANIFEST-000002 diff --git a/README.md b/README.md index a5c2fa7aa..3012c2e2e 100644 --- a/README.md +++ b/README.md @@ -454,7 +454,7 @@ The arguments are: - `messageExpiryInterval`: value is the lifetime of the Will Message in seconds and is sent as the Publication Expiry Interval when the Server publishes the Will Message `number`, - `contentType`: describing the content of the Will Message `string`, - `responseTopic`: String which is used as the Topic Name for a response message `string`, - - `correlationData`: The Correlation Data is used b`y the sender of the Request Message to identify which request the Response Message is for when it is received `binary`, + - `correlationData`: The Correlation Data is used by the sender of the Request Message to identify which request the Response Message is for when it is received `binary`, - `userProperties`: The User Property is allowed to appear multiple times to represent multiple name, value pairs `object` - `transformWsUrl` : optional `(url, options, client) => url` function For ws/wss protocols only. Can be used to implement signing @@ -467,14 +467,13 @@ The arguments are: - `log`: custom log function. Default uses [debug](https://www.npmjs.com/package/debug) package. - `manualConnect`: prevents the constructor to call `connect`. In this case after the `mqtt.connect` is called you should call `client.connect` manually. - `timerVariant`: defaults to `auto`, which tries to determine which timer is most appropriate for you environment, if you're having detection issues, you can set it to `worker` or `native`. If none suits you, you can pass a timer object with set and clear properties: - ```js - timerVariant: { - set: (func, timer) => setInterval(func, timer), - clear: (id) => clearInterval(id) - } - ``` - - - `forceNativeWebSocket`: set to true if you're having detection issues (i.e. the `ws does not work in the browser` exception) to force the use of native WebSocket. + ```js + timerVariant: { + set: (func, timer) => setInterval(func, timer), + clear: (id) => clearInterval(id) + } + ``` + - `forceNativeWebSocket`: set to true if you're having detection issues (i.e. the `ws does not work in the browser` exception) to force the use of native WebSocket. It is important to note that if set to true for the first client created, then all the clients will use native WebSocket. And conversely, if not set or set to false, all will use the detection result. - `unixSocket`: if you want to connect to a unix socket, set this to true In case mqtts (mqtt over tls) is required, the `options` object is passed through to [`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback). If using a **self-signed certificate**, set `rejectUnauthorized: false`. However, be cautious as this exposes you to potential man in the middle attacks and isn't recommended for production. diff --git a/src/lib/client.ts b/src/lib/client.ts index 4aa70a571..b9fa98480 100644 --- a/src/lib/client.ts +++ b/src/lib/client.ts @@ -516,7 +516,7 @@ export default class MqttClient extends TypedEventEmitter = null + /** * Parse the auth attribute and merge username and password in the options object. * @@ -133,26 +135,28 @@ function connect( } } - const protocols: Record = {} - - if (!opts.forceNativeWebSocket && !isBrowser) { - protocols.ws = require('./ws').streamBuilder - protocols.wss = require('./ws').streamBuilder - - protocols.mqtt = require('./tcp').default - protocols.tcp = require('./tcp').default - protocols.ssl = require('./tls').default - protocols.tls = protocols.ssl - protocols.mqtts = require('./tls').default - } else { - protocols.ws = require('./ws').browserStreamBuilder - protocols.wss = require('./ws').browserStreamBuilder + // only loads the protocols once + if (!protocols) { + protocols = {} + if (!isBrowser && !opts.forceNativeWebSocket) { + protocols.ws = require('./ws').streamBuilder + protocols.wss = require('./ws').streamBuilder + + protocols.mqtt = require('./tcp').default + protocols.tcp = require('./tcp').default + protocols.ssl = require('./tls').default + protocols.tls = protocols.ssl + protocols.mqtts = require('./tls').default + } else { + protocols.ws = require('./ws').browserStreamBuilder + protocols.wss = require('./ws').browserStreamBuilder - protocols.wx = require('./wx').default - protocols.wxs = require('./wx').default + protocols.wx = require('./wx').default + protocols.wxs = require('./wx').default - protocols.ali = require('./ali').default - protocols.alis = require('./ali').default + protocols.ali = require('./ali').default + protocols.alis = require('./ali').default + } } if (!protocols[opts.protocol]) { diff --git a/test-store_ApvD3c/000003.log b/test-store_ApvD3c/000003.log deleted file mode 100644 index 4d114906705a309c5eb34a68631021e33e1c362b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 945 zcmXSjv1xq9z{tn|0Zc%OQCu;RwWPSt(89>VOy`K!O${RhBNJT% zb6q3T5JO`tQ%fsj6FoCS( zW^u;SlKg_qYJ=;L!Rr7oPz=%S?o4EpU6*$N=55hNOBHixFVYT9DvbW1OBX0DHE}SMDg#v#dmT z)|?d28c^<81F&b!N${)@PS56pJ-g(@&$oFDjO<9BWx$n;8K{*qJ56{6ftGR-VW|bF Imf}ny0D(sxBLDyZ diff --git a/test-store_ApvD3c/CURRENT b/test-store_ApvD3c/CURRENT deleted file mode 100644 index 1a8485221..000000000 --- a/test-store_ApvD3c/CURRENT +++ /dev/null @@ -1 +0,0 @@ -MANIFEST-000002 diff --git a/test-store_ApvD3c/LOCK b/test-store_ApvD3c/LOCK deleted file mode 100644 index e69de29bb..000000000 diff --git a/test-store_ApvD3c/LOG b/test-store_ApvD3c/LOG deleted file mode 100644 index 20ad0be8b..000000000 --- a/test-store_ApvD3c/LOG +++ /dev/null @@ -1 +0,0 @@ -2024/07/25-15:59:34.614236 702a367fe640 Delete type=3 #1 diff --git a/test-store_ApvD3c/MANIFEST-000002 b/test-store_ApvD3c/MANIFEST-000002 deleted file mode 100644 index bbbc585686bcbcc33686059c69d80b7b4e1291cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAe$kRS-TOEg7@3$k8JJmE F7y#sj5K{mE