tmc.js 0.3.3 → 0.3.5

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
@@ -60,6 +60,24 @@ new Tmc('your_app_key', 'your_app_secret')
60
60
 
61
61
  消费端发起建立连接 `onopen` 事件,`address` 默认为 `ws://mc.api.taobao.com/`。
62
62
 
63
+ **`tmc.send(msg: Message, options?: { mask?: true, binary?: true }, cb?: (err: Error) => void) => void`**
64
+
65
+ 实例化后,当自动应答确认消息无法满足需求的时候,比如消息处理失败,需要`Publisher`再次重推消息,在实例初始化时置`options.autoReplyConfirmation=false`,则在消息处理函数内,可以通过 `this.send()` 函数回复`确认`或者`失败`消息。例如:
66
+
67
+ ```js
68
+ new Tmc('your_app_key', 'your_app_secret', { autoReplyConfirmation: false })
69
+ .taobao_trade_TradeDelayConfirmPay(function needDoubleReriesThenConfirm(msg) {
70
+ if (msg instanceof Message && msg.content?.retried === 0) {
71
+ this.send(
72
+ new Message(MessageType.SENDACK, MessageKind.Failed)
73
+ .with(MessageFields.ID, msg.content?.id)
74
+ .with(MessageFields.MSG, 'Something went wrong, please retries this ID.')
75
+ );
76
+ }
77
+ })
78
+ .connect();
79
+ ```
80
+
63
81
  <details><summary>可选设置的 NODE_DEBUG=< label > 环境变量</summary>
64
82
 
65
83
  | label | 说明 |
@@ -69,7 +87,7 @@ new Tmc('your_app_key', 'your_app_secret')
69
87
  | `tmc:onpull` | 开启 `onpull` 时的日志
70
88
  | `tmc:onerror` | 开启 `onerror` 时的日志
71
89
  | `tmc:onclose` | 开启 `onclose` 时的日志
72
- | `tmc:onmessage` | 开启全部 `onmessage` 时的日志(即`From`淘宝消息)
90
+ | `tmc:onmessage*` | 开启全部 `onmessage` 时的日志(即`From`淘宝消息)
73
91
  | `tmc:onmessage:connect` | 开启消费端发起连接 `connect` 时的日志
74
92
  | `tmc:onmessage:connectack` | 开启消费端回复连接 `connectack` 时的日志
75
93
  | `tmc:onmessage:send` | 开启消费端接收到(即`From`淘宝) `send` 的消息时的日志
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');
@@ -92,6 +92,17 @@ class TaoMessageConsumer extends EventEmitter {
92
92
  ).update(sk).digest('hex').toUpperCase();
93
93
  }
94
94
 
95
+ /**
96
+ * @param {Message} data - The data
97
+ * @param {object|Function} [options] - The options
98
+ * @param {Function} [cb] - The Callback
99
+ * @returns {void}
100
+ * @since v0.3.4
101
+ */
102
+ send(data, options = { mask: true, binary: true }, cb = undefined) {
103
+ if (data instanceof Message) { this[kWebSocket]?.send(data.with(TOKEN, this[kToken]).buffer, options, cb); }
104
+ }
105
+
95
106
  onopen() {
96
107
  const now = `${Date.now()}`;
97
108
  const msg = new Message(CONNECT)
@@ -102,9 +113,9 @@ class TaoMessageConsumer extends EventEmitter {
102
113
  .with(SDK, this.constructor.name)
103
114
  .with(INTRANET_IP, ipAddr());
104
115
 
105
- logger.onopen(JSONB.stringify(msg));
116
+ logger.onopen(stringify(msg));
106
117
 
107
- this[kWebSocket]?.send(msg.buffer, { mask: true, binary: true });
118
+ this.send(msg);
108
119
 
109
120
  if (this[kOptions].intervalId) { clearInterval(this[kOptions].intervalId); }
110
121
 
@@ -113,22 +124,22 @@ class TaoMessageConsumer extends EventEmitter {
113
124
 
114
125
  onpull() {
115
126
  const msg = new Message(SEND, PullRequest).with(TOKEN, this[kToken]);
116
- logger.onpull(JSONB.stringify(msg));
117
- this[kWebSocket]?.send(msg.buffer, { mask: true, binary: true });
127
+ logger.onpull(stringify(msg));
128
+ this.send(msg);
118
129
  }
119
130
 
120
131
  onping(data) {
121
- logger.onping('The channel is onping with data [%s].', JSONB.stringify(data));
122
- this[kWebSocket]?.pong(data, { mask: true }, true);
132
+ logger.onping('The channel is onping with data [%s].', stringify(data));
133
+ this[kWebSocket]?.pong(data, true);
123
134
  }
124
135
 
125
136
  onerror(err) {
126
- logger.onerror('The channel is onerror(%s), let us reconnect.', JSONB.stringify(err));
137
+ logger.onerror('The channel is onerror(%s), let us reconnect.', stringify(err));
127
138
  this.reconnect(this[kOptions].onErrorReconnection);
128
139
  }
129
140
 
130
141
  onclose(...arg) {
131
- logger.onclose('The channel is onclose(%s), let us reconnect.', JSONB.stringify(arg));
142
+ logger.onclose('The channel is onclose(%s), let us reconnect.', stringify(arg));
132
143
  this.reconnect(this[kOptions].onCloseReconnection);
133
144
  }
134
145
 
@@ -141,8 +152,8 @@ class TaoMessageConsumer extends EventEmitter {
141
152
 
142
153
  if (this[kOptions].autoReplyConfirmation && msg && msg[CONTENT] && msg[CONTENT][ID]) {
143
154
  const reply = new Message(SEND, Confirm).with(TOKEN, this[kToken]).with(ID, msg[CONTENT][ID]);
144
- logger.onmessage[SEND][Confirm](JSONB.stringify(reply));
145
- this[kWebSocket]?.send(reply.buffer, { mask: true, binary: true });
155
+ logger.onmessage[SEND][Confirm](stringify(reply));
156
+ this.send(reply);
146
157
  }
147
158
  }
148
159
 
@@ -164,10 +175,10 @@ class TaoMessageConsumer extends EventEmitter {
164
175
  && msg[CONTENT][CONTENT]
165
176
  && typeof msg[CONTENT][CONTENT] === 'string'
166
177
  && /^\{.*\}$/.test(msg[CONTENT][CONTENT])) {
167
- Reflect.set(msg[CONTENT], CONTENT, JSONB.parse(msg[CONTENT][CONTENT]));
178
+ Reflect.set(msg[CONTENT], CONTENT, parse(msg[CONTENT][CONTENT]));
168
179
  }
169
180
 
170
- logger.onmessage[msg[TYPE]](JSONB.stringify(msg));
181
+ logger.onmessage[msg[TYPE]](stringify(msg));
171
182
 
172
183
  this[`process${msg[TYPE]}`](msg);
173
184
  }
@@ -178,6 +189,7 @@ class TaoMessageConsumer extends EventEmitter {
178
189
  if (this[kOptions].intervalId) { this[kOptions].intervalId = clearInterval(this[kOptions].intervalId); }
179
190
  if (this[kOptions].timeoutId) { this[kOptions].timeoutId = clearTimeout(this[kOptions].timeoutId); }
180
191
 
192
+ this[kToken] = undefined;
181
193
  this[kWebSocket] = undefined;
182
194
  this[kOptions].timeoutId = setTimeout(() => this.connect(), ms);
183
195
 
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.3",
3
+ "version": "0.3.5",
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
  },
package/types/index.d.ts CHANGED
@@ -26,6 +26,10 @@ declare interface ConsumerOptions {
26
26
  declare interface TaoMessageConstractor extends EventEmitter {
27
27
  new (appKey: string, appSecret: BinaryLike, groupName?: string | ConsumerOptions, options?: ConsumerOptions): TaoMessageConsumer;
28
28
  sign(timestamp: string): string;
29
+ /** @since v0.3.4 */
30
+ send(data: Message, cb?: (err?: Error) => void): void;
31
+ /** @since v0.3.4 */
32
+ send(data: Message, options?: { mask?: true, binary?: true, compress?: boolean, fin?: boolean }, cb?: (err: Error) => void): void;
29
33
  onopen(): void;
30
34
  onpull(): void;
31
35
  onping(data: Buffer): void;