tmc.js 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,14 +43,27 @@ new Tmc('your_app_key', 'your_app_secret')
43
43
  | options.onCloseReconnection | `number` | 当消费端断开连接,重试连接间隔(默认`3000`毫秒) |
44
44
  | options.autoParseContentJson | `boolean` | 自动解析推送消息`$.content.content`字段为对象(默认`true`) |
45
45
  | options.autoReplyConfirmation | `boolean` | 以推送的`$.content.id`字段自动`Confirm`消息(默认`true`) |
46
+ | options.autoGroupedEmitting | `boolean` | 以`/^(([^_]+)_[^_]+)_.+/`规则切分`$.content.topic`主题,开关消费端多维监听功能(默认`true`) |
46
47
 
47
48
  **`tmc.on(topic: string, listener: (this: Tmc, message: Message) => void) => Tmc`**
48
49
 
49
50
  注册 `topic` 消息通知处理函数,默认已内置 [消息](./types/message.in.d.ts) 说明。
51
+ 自`v0.3.6`起,默认开启消费端多维监听功能,`topic`字符串也可以是`BU`及`BU_G`单位,例如:
52
+
53
+ ```js
54
+ .on('taobao', console.info)
55
+ .on('alibaba_einvoice', console.info)
56
+ ```
50
57
 
51
58
  **`tmc[<topic>](fn: (this: Tmc, message: Message) => void) => Tmc`**
52
59
 
53
60
  直接以 `topic` 为键值,注册消息通知处理函数。
61
+ 自`v0.3.6`起,默认开启消费端多维监听功能,`topic`字符串也可以是`BU`及`BU_G`单位,例如:
62
+
63
+ ```js
64
+ .taobao(console.info)
65
+ .alibaba_einvoice(console.info)
66
+ ```
54
67
 
55
68
  **`tmc.reconnect(ms: number) => Tmc`**
56
69
 
@@ -67,7 +80,7 @@ new Tmc('your_app_key', 'your_app_secret')
67
80
  ```js
68
81
  new Tmc('your_app_key', 'your_app_secret', { autoReplyConfirmation: false })
69
82
  .taobao_trade_TradeDelayConfirmPay(function needDoubleReriesThenConfirm(msg) {
70
- if (msg instanceof Message && msg.content?.reried === 0) {
83
+ if (msg instanceof Message && msg.content?.retried === 0) {
71
84
  this.send(
72
85
  new Message(MessageType.SENDACK, MessageKind.Failed)
73
86
  .with(MessageFields.ID, msg.content?.id)
package/lib/consumer.js CHANGED
@@ -3,7 +3,7 @@ const { networkInterfaces } = require('os');
3
3
  const { EventEmitter, captureRejectionSymbol } = require('events');
4
4
 
5
5
  const WebSocket = require('ws');
6
- const JSONB = require('json-bigint')({ useNativeBigInt: true });
6
+ const { stringify, parse } = require('json-bigint')({ useNativeBigInt: true });
7
7
 
8
8
  const logger = require('./logger');
9
9
  const Message = require('./message');
@@ -46,6 +46,8 @@ class TaoMessageConsumer extends EventEmitter {
46
46
  onCloseReconnection: 3e3,
47
47
  autoParseContentJson: true,
48
48
  autoReplyConfirmation: true,
49
+ /** @since v0.3.6 */
50
+ autoGroupedEmitting: true,
49
51
  };
50
52
 
51
53
  [kWebSocket];
@@ -92,7 +94,13 @@ class TaoMessageConsumer extends EventEmitter {
92
94
  ).update(sk).digest('hex').toUpperCase();
93
95
  }
94
96
 
95
- /** @since v0.3.4 */
97
+ /**
98
+ * @param {Message} data - The data
99
+ * @param {object|Function} [options] - The options
100
+ * @param {Function} [cb] - The Callback
101
+ * @returns {void}
102
+ * @since v0.3.4
103
+ */
96
104
  send(data, options = { mask: true, binary: true }, cb = undefined) {
97
105
  if (data instanceof Message) { this[kWebSocket]?.send(data.with(TOKEN, this[kToken]).buffer, options, cb); }
98
106
  }
@@ -107,7 +115,7 @@ class TaoMessageConsumer extends EventEmitter {
107
115
  .with(SDK, this.constructor.name)
108
116
  .with(INTRANET_IP, ipAddr());
109
117
 
110
- logger.onopen(JSONB.stringify(msg));
118
+ logger.onopen(stringify(msg));
111
119
 
112
120
  this.send(msg);
113
121
 
@@ -118,22 +126,22 @@ class TaoMessageConsumer extends EventEmitter {
118
126
 
119
127
  onpull() {
120
128
  const msg = new Message(SEND, PullRequest).with(TOKEN, this[kToken]);
121
- logger.onpull(JSONB.stringify(msg));
129
+ logger.onpull(stringify(msg));
122
130
  this.send(msg);
123
131
  }
124
132
 
125
133
  onping(data) {
126
- logger.onping('The channel is onping with data [%s].', JSONB.stringify(data));
127
- this[kWebSocket]?.pong(data, { mask: true }, true);
134
+ logger.onping('The channel is onping with data [%s].', data);
135
+ this[kWebSocket]?.pong(data, true);
128
136
  }
129
137
 
130
138
  onerror(err) {
131
- logger.onerror('The channel is onerror(%s), let us reconnect.', JSONB.stringify(err));
139
+ logger.onerror('The channel is onerror(%s), let us reconnect.', stringify(err));
132
140
  this.reconnect(this[kOptions].onErrorReconnection);
133
141
  }
134
142
 
135
- onclose(...arg) {
136
- logger.onclose('The channel is onclose(%s), let us reconnect.', JSONB.stringify(arg));
143
+ onclose(code, reason) {
144
+ logger.onclose('The channel is onclose(%d: %s), let us reconnect.', code, reason);
137
145
  this.reconnect(this[kOptions].onCloseReconnection);
138
146
  }
139
147
 
@@ -142,11 +150,17 @@ class TaoMessageConsumer extends EventEmitter {
142
150
  }
143
151
 
144
152
  [`process${SEND}`](msg) {
145
- if (msg && msg[CONTENT] && msg[CONTENT][TOPIC]) { this.emit(msg[CONTENT][TOPIC], msg); }
153
+ if (msg && msg[CONTENT] && msg[CONTENT][TOPIC]) {
154
+ [msg[CONTENT][TOPIC]].concat(
155
+ this[kOptions].autoGroupedEmitting
156
+ ? msg[CONTENT][TOPIC].split(/^(([^_]+)_[^_]+)_.+/).slice(1, -1)
157
+ : [],
158
+ ).forEach((t) => this.emit(t, msg));
159
+ }
146
160
 
147
161
  if (this[kOptions].autoReplyConfirmation && msg && msg[CONTENT] && msg[CONTENT][ID]) {
148
162
  const reply = new Message(SEND, Confirm).with(TOKEN, this[kToken]).with(ID, msg[CONTENT][ID]);
149
- logger.onmessage[SEND][Confirm](JSONB.stringify(reply));
163
+ logger.onmessage[SEND][Confirm](stringify(reply));
150
164
  this.send(reply);
151
165
  }
152
166
  }
@@ -169,10 +183,10 @@ class TaoMessageConsumer extends EventEmitter {
169
183
  && msg[CONTENT][CONTENT]
170
184
  && typeof msg[CONTENT][CONTENT] === 'string'
171
185
  && /^\{.*\}$/.test(msg[CONTENT][CONTENT])) {
172
- Reflect.set(msg[CONTENT], CONTENT, JSONB.parse(msg[CONTENT][CONTENT]));
186
+ Reflect.set(msg[CONTENT], CONTENT, parse(msg[CONTENT][CONTENT]));
173
187
  }
174
188
 
175
- logger.onmessage[msg[TYPE]](JSONB.stringify(msg));
189
+ logger.onmessage[msg[TYPE]](stringify(msg));
176
190
 
177
191
  this[`process${msg[TYPE]}`](msg);
178
192
  }
package/lib/message.js CHANGED
@@ -29,10 +29,8 @@ class Message {
29
29
  [CONTENT] = {};
30
30
 
31
31
  constructor(type, kind) {
32
- /* eslint-disable-next-line no-unused-expressions */
33
- MessageType.includes(type) && Reflect.set(this, TYPE, type);
34
- /* eslint-disable-next-line no-unused-expressions */
35
- MessageKind.includes(kind) && Reflect.set(this[CONTENT], MessageKind, kind);
32
+ if (MessageType.includes(type)) { this[TYPE] = type; }
33
+ if (MessageKind.includes(kind)) { this[CONTENT][MessageKind] = kind; }
36
34
  }
37
35
 
38
36
  with(key, value) {
@@ -93,14 +91,10 @@ class Encoder {
93
91
 
94
92
  compress() {
95
93
  this.put(this[kData].protocolVersion).put(this[kData][TYPE]);
96
- /* eslint-disable-next-line no-unused-expressions */
97
- this[kData][CODE] && this.putShort(StatusCode).putShort(this[kData][CODE]);
98
- /* eslint-disable-next-line no-unused-expressions */
99
- this[kData][PHRASE] && this.putShort(StatusPhrase).writeCountedString(this[kData][PHRASE]);
100
- /* eslint-disable-next-line no-unused-expressions */
101
- this[kData][FLAG] && this.putShort(Flag).putInt(this[kData][FLAG]);
102
- /* eslint-disable-next-line no-unused-expressions */
103
- this[kData][TOKEN] && this.putShort(Token).writeCountedString(this[kData][TOKEN]);
94
+ if (this[kData][CODE]) { this.putShort(StatusCode).putShort(this[kData][CODE]); }
95
+ if (this[kData][PHRASE]) { this.putShort(StatusPhrase).writeCountedString(this[kData][PHRASE]); }
96
+ if (this[kData][FLAG]) { this.putShort(Flag).putInt(this[kData][FLAG]); }
97
+ if (this[kData][TOKEN]) { this.putShort(Token).writeCountedString(this[kData][TOKEN]); }
104
98
  Object.entries(this[kData][CONTENT] || {}).forEach(([k, v]) => this.putShort(Custom).writeCountedString(k).writeCustomValue(v));
105
99
  this.putShort(EndOfHeaders);
106
100
 
@@ -134,8 +128,7 @@ class Encoder {
134
128
  writeCountedString(value) {
135
129
  const len = value ? Buffer.byteLength(value) : 0;
136
130
  this.putInt(len);
137
- /* eslint-disable-next-line no-unused-expressions */
138
- len && this[kBuffer].push(pick(len, write, value, utf8));
131
+ if (len) { this[kBuffer].push(pick(len, write, value, utf8)); }
139
132
 
140
133
  return this;
141
134
  }
@@ -187,18 +180,6 @@ class Encoder {
187
180
 
188
181
  const kOffset = Symbol('kOffset');
189
182
 
190
- const readInt8 = 'readInt8';
191
-
192
- const readInt16LE = 'readInt16LE';
193
-
194
- const readInt32LE = 'readInt32LE';
195
-
196
- const readBigInt64LE = 'readBigInt64LE';
197
-
198
- function read(buffer, method, offset, ...extra) {
199
- return buffer[method](offset, ...extra);
200
- }
201
-
202
183
  class Decoder {
203
184
  [kOffset] = 1;
204
185
 
@@ -245,25 +226,25 @@ class Decoder {
245
226
  }
246
227
 
247
228
  get() {
248
- const value = read(this[kBuffer], readInt8, this[kOffset]);
229
+ const value = this[kBuffer].readInt8(this[kOffset]);
249
230
  this[kOffset] += 1;
250
231
  return Number(value);
251
232
  }
252
233
 
253
234
  getShort() {
254
- const value = read(this[kBuffer], readInt16LE, this[kOffset]);
235
+ const value = this[kBuffer].readInt16LE(this[kOffset]);
255
236
  this[kOffset] += 2;
256
237
  return Number(value);
257
238
  }
258
239
 
259
240
  getInt() {
260
- const value = read(this[kBuffer], readInt32LE, this[kOffset]);
241
+ const value = this[kBuffer].readInt32LE(this[kOffset]);
261
242
  this[kOffset] += 4;
262
243
  return Number(value);
263
244
  }
264
245
 
265
246
  getLong() {
266
- const value = read(this[kBuffer], readBigInt64LE, this[kOffset]);
247
+ const value = this[kBuffer].readBigInt64LE(this[kOffset]);
267
248
  this[kOffset] += 8;
268
249
  return BigInt(value);
269
250
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tmc.js",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Events driven and chained Taobao Message Channel(TMC) for NodeJS",
5
5
  "author": "James ZHANG",
6
6
  "license": "MIT",
@@ -30,11 +30,11 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "json-bigint": "^1.0.0",
33
- "ws": "^8.11.0"
33
+ "ws": "^5.2.2 || ^6.2.1 || ^7.4.5 || ^8.0.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@babel/eslint-parser": "^7.19.1",
37
- "@types/node": "^18.8.3",
37
+ "@types/node": ">=11.9.0",
38
38
  "eslint": "^8.25.0",
39
39
  "eslint-config-airbnb-base": "^15.0.0"
40
40
  },