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 +14 -1
- package/lib/consumer.js +27 -13
- package/lib/message.js +11 -30
- package/package.json +3 -3
- package/types/index.d.ts +591 -1
- package/types/message.in.d.ts +1370 -0
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?.
|
|
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
|
|
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
|
-
/**
|
|
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(
|
|
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(
|
|
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].',
|
|
127
|
-
this[kWebSocket]?.pong(data,
|
|
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.',
|
|
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(
|
|
136
|
-
logger.onclose('The channel is onclose(%s), let us reconnect.',
|
|
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]) {
|
|
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](
|
|
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,
|
|
186
|
+
Reflect.set(msg[CONTENT], CONTENT, parse(msg[CONTENT][CONTENT]));
|
|
173
187
|
}
|
|
174
188
|
|
|
175
|
-
logger.onmessage[msg[TYPE]](
|
|
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
|
-
|
|
33
|
-
|
|
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
|
-
|
|
97
|
-
this[kData][
|
|
98
|
-
|
|
99
|
-
this[kData][
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
+
"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.
|
|
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": "
|
|
37
|
+
"@types/node": ">=11.9.0",
|
|
38
38
|
"eslint": "^8.25.0",
|
|
39
39
|
"eslint-config-airbnb-base": "^15.0.0"
|
|
40
40
|
},
|