sip-lab 1.8.0 → 1.11.0
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 +26 -12
- package/binding.gyp +1 -0
- package/index.js +2 -0
- package/package.json +1 -1
- package/samples/fax_doc.tiff +0 -0
- package/samples/g729.js +0 -2
- package/samples/late_negotiation.js +0 -4
- package/samples/reinvite_and_dtmf.js +291 -0
- package/samples/send_and_receive_fax.js +143 -0
- package/samples/simple.js +0 -171
- package/samples/sip_cancel.js +0 -2
- package/src/addon.cpp +67 -0
- package/src/event_templates.cpp +4 -0
- package/src/event_templates.hpp +2 -0
- package/src/pjmedia/Makefile +3 -1
- package/src/pjmedia/include/chainlink/chainlink_fax.h +25 -0
- package/src/pjmedia/src/chainlink/chainlink_fax.c +274 -0
- package/src/sip.cpp +144 -6
- package/src/sip.hpp +2 -0
package/README.md
CHANGED
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
A nodejs module that helps to write functional tests for SIP systems (including media operations).
|
|
6
6
|
It uses pjproject for SIP and media processing.
|
|
7
7
|
|
|
8
|
+
It permits to:
|
|
9
|
+
- send and receive DTMF inband/RFC2833/INFO.
|
|
10
|
+
- play/record wav file on a call
|
|
11
|
+
- send/receive fax (T.30 only)
|
|
12
|
+
|
|
13
|
+
|
|
8
14
|
### Installation
|
|
9
15
|
|
|
10
16
|
This will require for you to have some libraries installed. So do:
|
|
@@ -24,26 +30,34 @@ Then install sip-lab by doing:
|
|
|
24
30
|
npm install sip-lab
|
|
25
31
|
```
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
To test from within this repo just build and install by doing:
|
|
28
34
|
```
|
|
29
|
-
npm install -g
|
|
35
|
+
npm install -g node-gyp
|
|
36
|
+
npm install --unsafe-perm
|
|
30
37
|
```
|
|
31
|
-
|
|
32
|
-
But if you do so, you will need to set NODE_PATH for node to find it by doing:
|
|
38
|
+
And run some sample script from subfolder samples:
|
|
33
39
|
```
|
|
34
|
-
|
|
40
|
+
node samples/simple.js
|
|
35
41
|
```
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
The module is known to work properly in Ubuntu 18.04.4, Ubuntu 20.04.4, Debian 8 and Debian 10 (and it is expected to work in Debian 9).
|
|
44
|
+
It was originally developed with node v.10 and tested with v.12 and it is expected to work with latest versions of node.
|
|
45
|
+
(it is known to not work with node v.8)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
Since running
|
|
38
49
|
```
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
npm install sip-lab
|
|
51
|
+
```
|
|
52
|
+
takes some time to fetch and build pjproject and the node addon for it, you could install sip-lab globally:
|
|
41
53
|
|
|
42
|
-
|
|
54
|
+
```
|
|
55
|
+
npm install -g sip-lab
|
|
43
56
|
```
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
(
|
|
58
|
+
But if you do so, you will need to set NODE_PATH for node to find it by doing:
|
|
59
|
+
```
|
|
60
|
+
export NODE_PATH=$(npm root --quiet -g)
|
|
61
|
+
```
|
|
48
62
|
|
|
49
63
|
|
package/binding.gyp
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
'src/pjmedia/src/chainlink/chainlink_wav_player.c',
|
|
15
15
|
'src/pjmedia/src/chainlink/chainlink_wav_writer.c',
|
|
16
16
|
'src/pjmedia/src/chainlink/chainlink_wire_port.c',
|
|
17
|
+
'src/pjmedia/src/chainlink/chainlink_fax.c',
|
|
17
18
|
],
|
|
18
19
|
'include_dirs': [
|
|
19
20
|
"pjproject/pjsip/include",
|
package/index.js
CHANGED
|
@@ -59,6 +59,8 @@ addon.call = {
|
|
|
59
59
|
start_playing: addon.call_start_play_wav,
|
|
60
60
|
stop_recording: addon.call_stop_record_wav,
|
|
61
61
|
stop_playing: addon.call_stop_play_wav,
|
|
62
|
+
start_fax: addon.call_start_fax,
|
|
63
|
+
stop_fax: addon.call_stop_fax,
|
|
62
64
|
get_stream_stat: addon.call_get_stream_stat,
|
|
63
65
|
refer: addon.call_refer,
|
|
64
66
|
get_info: addon.call_get_info,
|
package/package.json
CHANGED
|
Binary file
|
package/samples/g729.js
CHANGED
|
@@ -208,8 +208,6 @@ async function test() {
|
|
|
208
208
|
},
|
|
209
209
|
], 500)
|
|
210
210
|
|
|
211
|
-
await z.sleep(100)
|
|
212
|
-
|
|
213
211
|
sip.call.reinvite(oc.id, false, flags)
|
|
214
212
|
|
|
215
213
|
await z.wait([
|
|
@@ -275,8 +273,6 @@ async function test() {
|
|
|
275
273
|
},
|
|
276
274
|
], 1000)
|
|
277
275
|
|
|
278
|
-
await z.sleep(1000)
|
|
279
|
-
|
|
280
276
|
console.log("Success")
|
|
281
277
|
|
|
282
278
|
sip.stop()
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
var sip = require ('../index.js')
|
|
2
|
+
var Zester = require('zester')
|
|
3
|
+
var z = new Zester()
|
|
4
|
+
var m = require('data-matching')
|
|
5
|
+
var sip_msg = require('sip-matching')
|
|
6
|
+
|
|
7
|
+
async function test() {
|
|
8
|
+
//sip.set_log_level(6)
|
|
9
|
+
sip.dtmf_aggregation_on(500)
|
|
10
|
+
|
|
11
|
+
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
12
|
+
var e = evt.args[0]
|
|
13
|
+
return e
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
console.log(sip.start((data) => { console.log(data)} ))
|
|
17
|
+
|
|
18
|
+
t1 = sip.transport.create("127.0.0.1", 5090, 1)
|
|
19
|
+
t2 = sip.transport.create("127.0.0.1", 5092, 1)
|
|
20
|
+
|
|
21
|
+
console.log("t1", t1)
|
|
22
|
+
console.log("t2", t2)
|
|
23
|
+
|
|
24
|
+
flags = 0
|
|
25
|
+
|
|
26
|
+
oc = sip.call.create(t1.id, flags, 'sip:a@t', 'sip:b@127.0.0.1:5092')
|
|
27
|
+
|
|
28
|
+
await z.wait([
|
|
29
|
+
{
|
|
30
|
+
event: "incoming_call",
|
|
31
|
+
call_id: m.collect("call_id"),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
event: 'response',
|
|
35
|
+
call_id: oc.id,
|
|
36
|
+
method: 'INVITE',
|
|
37
|
+
msg: sip_msg({
|
|
38
|
+
$rs: '100',
|
|
39
|
+
$rr: 'Trying',
|
|
40
|
+
'$(hdrcnt(via))': 1,
|
|
41
|
+
'$hdr(call-id)': m.collect('sip_call_id'),
|
|
42
|
+
$fU: 'a',
|
|
43
|
+
$fd: 't',
|
|
44
|
+
$tU: 'b',
|
|
45
|
+
'$hdr(l)': '0',
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
], 1000)
|
|
49
|
+
|
|
50
|
+
ic = {
|
|
51
|
+
id: z.store.call_id,
|
|
52
|
+
sip_call_id: z.store.sip_call_id,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
sip.call.respond(ic.id, 200, 'OK')
|
|
56
|
+
|
|
57
|
+
await z.wait([
|
|
58
|
+
{
|
|
59
|
+
event: 'media_status',
|
|
60
|
+
call_id: oc.id,
|
|
61
|
+
status: 'setup_ok',
|
|
62
|
+
local_mode: 'sendrecv',
|
|
63
|
+
remote_mode: 'sendrecv',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
event: 'media_status',
|
|
67
|
+
call_id: ic.id,
|
|
68
|
+
status: 'setup_ok',
|
|
69
|
+
local_mode: 'sendrecv',
|
|
70
|
+
remote_mode: 'sendrecv',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
event: 'response',
|
|
74
|
+
call_id: oc.id,
|
|
75
|
+
method: 'INVITE',
|
|
76
|
+
msg: sip_msg({
|
|
77
|
+
$rs: '200',
|
|
78
|
+
$rr: 'OK',
|
|
79
|
+
'$(hdrcnt(VIA))': 1,
|
|
80
|
+
$fU: 'a',
|
|
81
|
+
$fd: 't',
|
|
82
|
+
$tU: 'b',
|
|
83
|
+
'$hdr(content-type)': 'application/sdp',
|
|
84
|
+
$rb: '!{_}a=sendrecv',
|
|
85
|
+
}),
|
|
86
|
+
},
|
|
87
|
+
], 1000)
|
|
88
|
+
|
|
89
|
+
sip.call.send_dtmf(oc.id, '1234', 0)
|
|
90
|
+
sip.call.send_dtmf(ic.id, '4321', 1)
|
|
91
|
+
|
|
92
|
+
await z.wait([
|
|
93
|
+
{
|
|
94
|
+
event: 'dtmf',
|
|
95
|
+
call_id: ic.id,
|
|
96
|
+
digits: '1234',
|
|
97
|
+
mode: 0,
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
event: 'dtmf',
|
|
101
|
+
call_id: oc.id,
|
|
102
|
+
digits: '4321',
|
|
103
|
+
mode: 1,
|
|
104
|
+
},
|
|
105
|
+
], 2000)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
sip.call.reinvite(oc.id, true, 0)
|
|
109
|
+
|
|
110
|
+
await z.wait([
|
|
111
|
+
{
|
|
112
|
+
event: 'response',
|
|
113
|
+
call_id: oc.id,
|
|
114
|
+
method: 'INVITE',
|
|
115
|
+
msg: sip_msg({
|
|
116
|
+
$rs: '200',
|
|
117
|
+
$rr: 'OK',
|
|
118
|
+
$rb: '!{_}a=recvonly',
|
|
119
|
+
}),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
event: 'media_status',
|
|
123
|
+
call_id: oc.id,
|
|
124
|
+
status: 'setup_ok',
|
|
125
|
+
local_mode: 'sendonly',
|
|
126
|
+
remote_mode: 'recvonly',
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
event: 'media_status',
|
|
130
|
+
call_id: ic.id,
|
|
131
|
+
status: 'setup_ok',
|
|
132
|
+
local_mode: 'recvonly',
|
|
133
|
+
remote_mode: 'sendonly',
|
|
134
|
+
},
|
|
135
|
+
], 500)
|
|
136
|
+
|
|
137
|
+
sip.call.send_dtmf(oc.id, '1234', 0)
|
|
138
|
+
sip.call.send_dtmf(ic.id, '4321', 1) // this will not generate event 'dtmf' as the call is on hold
|
|
139
|
+
|
|
140
|
+
await z.wait([
|
|
141
|
+
{
|
|
142
|
+
event: 'dtmf',
|
|
143
|
+
call_id: ic.id,
|
|
144
|
+
digits: '1234',
|
|
145
|
+
mode: 0,
|
|
146
|
+
},
|
|
147
|
+
], 2000)
|
|
148
|
+
|
|
149
|
+
sip.call.reinvite(ic.id, false, 0)
|
|
150
|
+
|
|
151
|
+
await z.wait([
|
|
152
|
+
{
|
|
153
|
+
event: 'response',
|
|
154
|
+
call_id: ic.id,
|
|
155
|
+
method: 'INVITE',
|
|
156
|
+
msg: sip_msg({
|
|
157
|
+
$rs: '200',
|
|
158
|
+
$rr: 'OK',
|
|
159
|
+
$rb: '!{_}a=sendonly',
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
event: 'media_status',
|
|
164
|
+
call_id: oc.id,
|
|
165
|
+
status: 'setup_ok',
|
|
166
|
+
local_mode: 'sendonly',
|
|
167
|
+
remote_mode: 'recvonly',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
event: 'media_status',
|
|
171
|
+
call_id: ic.id,
|
|
172
|
+
status: 'setup_ok',
|
|
173
|
+
local_mode: 'recvonly',
|
|
174
|
+
remote_mode: 'sendonly',
|
|
175
|
+
},
|
|
176
|
+
], 500)
|
|
177
|
+
|
|
178
|
+
sip.call.send_dtmf(oc.id, '1234', 0)
|
|
179
|
+
sip.call.send_dtmf(ic.id, '4321', 1) // this will not generate event 'dtmf' as the call is on hold
|
|
180
|
+
|
|
181
|
+
await z.wait([
|
|
182
|
+
{
|
|
183
|
+
event: 'dtmf',
|
|
184
|
+
call_id: ic.id,
|
|
185
|
+
digits: '1234',
|
|
186
|
+
mode: 0,
|
|
187
|
+
},
|
|
188
|
+
], 2000)
|
|
189
|
+
|
|
190
|
+
sip.call.send_request(oc.id, 'INFO')
|
|
191
|
+
|
|
192
|
+
await z.wait([
|
|
193
|
+
{
|
|
194
|
+
event: 'request',
|
|
195
|
+
call_id: ic.id,
|
|
196
|
+
msg: sip_msg({
|
|
197
|
+
$rm: 'INFO',
|
|
198
|
+
}),
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
event: 'response',
|
|
202
|
+
call_id: oc.id,
|
|
203
|
+
method: 'INFO',
|
|
204
|
+
msg: sip_msg({
|
|
205
|
+
$rs: '200',
|
|
206
|
+
$rr: 'OK',
|
|
207
|
+
}),
|
|
208
|
+
},
|
|
209
|
+
], 500)
|
|
210
|
+
|
|
211
|
+
sip.call.reinvite(oc.id, false, 0)
|
|
212
|
+
|
|
213
|
+
await z.wait([
|
|
214
|
+
{
|
|
215
|
+
event: 'response',
|
|
216
|
+
call_id: oc.id,
|
|
217
|
+
method: 'INVITE',
|
|
218
|
+
msg: sip_msg({
|
|
219
|
+
$rs: '200',
|
|
220
|
+
$rr: 'OK',
|
|
221
|
+
$rb: '!{_}a=sendrecv',
|
|
222
|
+
}),
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
event: 'media_status',
|
|
226
|
+
call_id: oc.id,
|
|
227
|
+
status: 'setup_ok',
|
|
228
|
+
local_mode: 'sendrecv',
|
|
229
|
+
remote_mode: 'sendrecv',
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
event: 'media_status',
|
|
233
|
+
call_id: ic.id,
|
|
234
|
+
status: 'setup_ok',
|
|
235
|
+
local_mode: 'sendrecv',
|
|
236
|
+
remote_mode: 'sendrecv',
|
|
237
|
+
},
|
|
238
|
+
], 500)
|
|
239
|
+
|
|
240
|
+
sip.call.send_dtmf(oc.id, '1234', 0)
|
|
241
|
+
sip.call.send_dtmf(ic.id, '4321', 1)
|
|
242
|
+
|
|
243
|
+
await z.wait([
|
|
244
|
+
{
|
|
245
|
+
event: 'dtmf',
|
|
246
|
+
call_id: ic.id,
|
|
247
|
+
digits: '1234',
|
|
248
|
+
mode: 0,
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
event: 'dtmf',
|
|
252
|
+
call_id: oc.id,
|
|
253
|
+
digits: '4321',
|
|
254
|
+
mode: 1,
|
|
255
|
+
},
|
|
256
|
+
], 2000)
|
|
257
|
+
|
|
258
|
+
sip.call.terminate(oc.id)
|
|
259
|
+
|
|
260
|
+
await z.wait([
|
|
261
|
+
{
|
|
262
|
+
event: 'call_ended',
|
|
263
|
+
call_id: oc.id,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
event: 'call_ended',
|
|
267
|
+
call_id: ic.id,
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
event: 'response',
|
|
271
|
+
call_id: oc.id,
|
|
272
|
+
method: 'BYE',
|
|
273
|
+
msg: sip_msg({
|
|
274
|
+
$rs: '200',
|
|
275
|
+
$rr: 'OK',
|
|
276
|
+
}),
|
|
277
|
+
},
|
|
278
|
+
], 1000)
|
|
279
|
+
|
|
280
|
+
console.log("Success")
|
|
281
|
+
|
|
282
|
+
sip.stop()
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
test()
|
|
287
|
+
.catch(e => {
|
|
288
|
+
console.error(e)
|
|
289
|
+
process.exit(1)
|
|
290
|
+
})
|
|
291
|
+
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
var sip = require ('../index.js')
|
|
2
|
+
var Zester = require('zester')
|
|
3
|
+
var z = new Zester()
|
|
4
|
+
var m = require('data-matching')
|
|
5
|
+
var sip_msg = require('sip-matching')
|
|
6
|
+
|
|
7
|
+
async function test() {
|
|
8
|
+
//sip.set_log_level(6)
|
|
9
|
+
sip.dtmf_aggregation_on(500)
|
|
10
|
+
|
|
11
|
+
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
12
|
+
var e = evt.args[0]
|
|
13
|
+
return e
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
console.log(sip.start((data) => { console.log(data)} ))
|
|
17
|
+
|
|
18
|
+
t1 = sip.transport.create("127.0.0.1", 5090, 1)
|
|
19
|
+
t2 = sip.transport.create("127.0.0.1", 5092, 1)
|
|
20
|
+
|
|
21
|
+
console.log("t1", t1)
|
|
22
|
+
console.log("t2", t2)
|
|
23
|
+
|
|
24
|
+
flags = 0
|
|
25
|
+
|
|
26
|
+
oc = sip.call.create(t1.id, flags, 'sip:a@t', 'sip:b@127.0.0.1:5092')
|
|
27
|
+
|
|
28
|
+
await z.wait([
|
|
29
|
+
{
|
|
30
|
+
event: "incoming_call",
|
|
31
|
+
call_id: m.collect("call_id"),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
event: 'response',
|
|
35
|
+
call_id: oc.id,
|
|
36
|
+
method: 'INVITE',
|
|
37
|
+
msg: sip_msg({
|
|
38
|
+
$rs: '100',
|
|
39
|
+
$rr: 'Trying',
|
|
40
|
+
'$(hdrcnt(via))': 1,
|
|
41
|
+
'$hdr(call-id)': m.collect('sip_call_id'),
|
|
42
|
+
$fU: 'a',
|
|
43
|
+
$fd: 't',
|
|
44
|
+
$tU: 'b',
|
|
45
|
+
'$hdr(l)': '0',
|
|
46
|
+
}),
|
|
47
|
+
},
|
|
48
|
+
], 1000)
|
|
49
|
+
|
|
50
|
+
ic = {
|
|
51
|
+
id: z.store.call_id,
|
|
52
|
+
sip_call_id: z.store.sip_call_id,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
sip.call.respond(ic.id, 200, 'OK')
|
|
56
|
+
|
|
57
|
+
await z.wait([
|
|
58
|
+
{
|
|
59
|
+
event: 'media_status',
|
|
60
|
+
call_id: oc.id,
|
|
61
|
+
status: 'setup_ok',
|
|
62
|
+
local_mode: 'sendrecv',
|
|
63
|
+
remote_mode: 'sendrecv',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
event: 'media_status',
|
|
67
|
+
call_id: ic.id,
|
|
68
|
+
status: 'setup_ok',
|
|
69
|
+
local_mode: 'sendrecv',
|
|
70
|
+
remote_mode: 'sendrecv',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
event: 'response',
|
|
74
|
+
call_id: oc.id,
|
|
75
|
+
method: 'INVITE',
|
|
76
|
+
msg: sip_msg({
|
|
77
|
+
$rs: '200',
|
|
78
|
+
$rr: 'OK',
|
|
79
|
+
'$(hdrcnt(VIA))': 1,
|
|
80
|
+
$fU: 'a',
|
|
81
|
+
$fd: 't',
|
|
82
|
+
$tU: 'b',
|
|
83
|
+
'$hdr(content-type)': 'application/sdp',
|
|
84
|
+
$rb: '!{_}a=sendrecv',
|
|
85
|
+
}),
|
|
86
|
+
},
|
|
87
|
+
], 1000)
|
|
88
|
+
|
|
89
|
+
await z.sleep(1000)
|
|
90
|
+
|
|
91
|
+
var is_sender = true
|
|
92
|
+
|
|
93
|
+
sip.call.start_fax(oc.id, is_sender, 'samples/fax_doc.tiff')
|
|
94
|
+
await z.sleep(100)
|
|
95
|
+
sip.call.start_fax(ic.id, !is_sender, 'received.tiff')
|
|
96
|
+
|
|
97
|
+
await z.wait([
|
|
98
|
+
{
|
|
99
|
+
event: 'fax_result',
|
|
100
|
+
call_id: oc.id,
|
|
101
|
+
result: 0,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
event: 'fax_result',
|
|
105
|
+
call_id: ic.id,
|
|
106
|
+
result: 0,
|
|
107
|
+
},
|
|
108
|
+
], 60 * 1000)
|
|
109
|
+
|
|
110
|
+
sip.call.terminate(oc.id)
|
|
111
|
+
|
|
112
|
+
await z.wait([
|
|
113
|
+
{
|
|
114
|
+
event: 'call_ended',
|
|
115
|
+
call_id: oc.id,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
event: 'call_ended',
|
|
119
|
+
call_id: ic.id,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
event: 'response',
|
|
123
|
+
call_id: oc.id,
|
|
124
|
+
method: 'BYE',
|
|
125
|
+
msg: sip_msg({
|
|
126
|
+
$rs: '200',
|
|
127
|
+
$rr: 'OK',
|
|
128
|
+
}),
|
|
129
|
+
},
|
|
130
|
+
], 1000)
|
|
131
|
+
|
|
132
|
+
console.log("Success")
|
|
133
|
+
|
|
134
|
+
sip.stop()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
test()
|
|
139
|
+
.catch(e => {
|
|
140
|
+
console.error(e)
|
|
141
|
+
process.exit(1)
|
|
142
|
+
})
|
|
143
|
+
|