@cc-livekit/ttsignal 1.0.6 → 1.0.8

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/index.js CHANGED
@@ -1,91 +1,33 @@
1
- "use strict";
2
-
3
1
  /*******************************************************************************
4
2
  * javascript glue wrapper of ttsignal module
5
3
  * @module index.js
6
- * @author antoniozhou.
7
- ******************************************************************************/
8
-
9
- // var util = require('util');
10
- const EventEmitter = require("events").EventEmitter;
11
- const fs = require("fs");
12
- const path = require("path");
13
- const Module = require("module");
14
-
15
- const PLATFORM = process.platform;
16
- const ARCH = process.arch;
17
- const ADDON_BASENAME = `ttsignal.${PLATFORM}.${ARCH}.node`;
18
-
19
- function expandAsar(candidate) {
20
- if (!candidate) return candidate;
21
- const idx = candidate.indexOf(".asar/");
22
- if (idx === -1) return candidate;
23
- return candidate.replace(".asar/", ".asar.unpacked/");
24
- }
4
+ * @author anto.
5
+ *******************************************************************************/
25
6
 
26
- function resolveAddonPath() {
27
- const candidates = [];
28
- if (process.env.TTSIGNAL_NATIVE_PATH) {
29
- candidates.push(process.env.TTSIGNAL_NATIVE_PATH);
30
- }
31
-
32
- const baseDir = __dirname;
33
- const searchRoots = [
34
- path.join(baseDir, "build", "Release"),
35
- path.join(baseDir, "dist", "build", "Release"),
36
- path.join(baseDir, "..", "build", "Release"),
37
- path.join(baseDir, "..", "dist", "build", "Release"),
38
- ];
39
-
40
- for (const root of searchRoots) {
41
- candidates.push(path.join(root, ADDON_BASENAME));
42
- }
43
-
44
- const unique = [...new Set(candidates.filter(Boolean))];
45
-
46
- for (const candidate of unique) {
47
- if (fs.existsSync(candidate)) {
48
- return candidate;
49
- }
50
- const unpacked = expandAsar(candidate);
51
- if (unpacked !== candidate && fs.existsSync(unpacked)) {
52
- return unpacked;
53
- }
54
- }
55
-
56
- const tried = unique.concat(unique.map(expandAsar)).filter(Boolean);
57
- throw new Error(
58
- `Unable to locate ttsignal native addon (${PLATFORM}/${ARCH}). Tried: ${tried.join(
59
- ", "
60
- )}`
61
- );
62
- }
7
+ var util = require('util');
8
+ var EventEmitter = require('events').EventEmitter;
63
9
 
64
- function loadNativeAddon() {
65
- const createRequire =
66
- Module.createRequire ||
67
- Module.createRequireFromPath ||
68
- require("module").createRequire;
69
- const req = createRequire(__filename);
70
- const addonPath = resolveAddonPath();
71
- return req(addonPath);
72
- }
10
+ var ttsignal = null;
73
11
 
74
- const ttsignal = loadNativeAddon();
12
+ if (process.ttsBuildType == 'debug') {
13
+ ttsignal = require('./Debug/ttsignal.'+process.platform+'.'+process.arch+'.node');
14
+ } else {
15
+ ttsignal = require('./Release/ttsignal.'+process.platform+'.'+process.arch+'.node');
16
+ }
75
17
 
76
18
  const CONST = {
77
- TTS_TYPE_COMMAND: 0x01,
78
- TTS_TYPE_MESSAGE: 0x02,
79
- TTS_TYPE_USER_CONTROL: 0x03,
80
- TTS_CC_BBR: 0x62,
81
- TTS_CC_BBR2: 0x42,
82
- TTS_CC_CUBIC: 0x63,
83
- TTS_CC_RENO: 0x72,
84
- LOG_LEVEL_DEBUG: 0x01,
85
- LOG_LEVEL_INFO: 0x02,
86
- LOG_LEVEL_WARN: 0x03,
87
- LOG_LEVEL_ERROR: 0x04,
88
- LOG_LEVEL_FATAL: 0x05,
19
+ TTS_TYPE_COMMAND : 0x01,
20
+ TTS_TYPE_MESSAGE : 0x02,
21
+ TTS_TYPE_USER_CONTROL : 0x03,
22
+ TTS_CC_BBR : 0x62,
23
+ TTS_CC_BBR2 : 0x42,
24
+ TTS_CC_CUBIC : 0x63,
25
+ TTS_CC_RENO : 0x72,
26
+ LOG_LEVEL_DEBUG : 0x01,
27
+ LOG_LEVEL_INFO : 0x02,
28
+ LOG_LEVEL_WARN : 0x03,
29
+ LOG_LEVEL_ERROR : 0x04,
30
+ LOG_LEVEL_FATAL : 0x05
89
31
  };
90
32
 
91
33
  //*******************************************************************************
@@ -93,47 +35,45 @@ const CONST = {
93
35
  //*******************************************************************************
94
36
 
95
37
  function copyProperties(target, source) {
96
- for (var k in source) {
97
- if (source.hasOwnProperty(k)) {
98
- target[k] = source[k];
38
+ for (var k in source){
39
+ if (source.hasOwnProperty(k)) {
40
+ target[k] = source[k];
41
+ }
99
42
  }
100
- }
101
43
  }
102
44
  copyProperties(ttsignal, CONST);
103
45
 
104
46
  function inherits(target, source) {
105
- for (var k in source.prototype) target.prototype[k] = source.prototype[k];
47
+ for (var k in source.prototype)
48
+ target.prototype[k] = source.prototype[k];
106
49
  }
107
50
  inherits(ttsignal.Connector, EventEmitter);
108
51
  inherits(ttsignal.Connection, EventEmitter);
109
52
  inherits(ttsignal.Server, EventEmitter);
110
53
  inherits(ttsignal.ServerConnection, EventEmitter);
111
54
 
55
+
112
56
  /*******************************************************************************
113
- * @class ttsignal.Connector
114
- *******************************************************************************/
57
+ * @class ttsignal.Connector
58
+ *******************************************************************************/
115
59
 
116
60
  /**
117
61
  * @method _internalCallback
118
62
  * @private
119
- *
120
- *
63
+ *
64
+ *
121
65
  **/
122
- ttsignal.Connector.prototype._internalCallback = function (
123
- type,
124
- __arg2,
125
- __arg3
126
- ) {
127
- switch (type) {
128
- case "close":
129
- this.emit("close");
130
- break;
131
- }
132
- };
66
+ ttsignal.Connector.prototype._internalCallback = function(type, __arg2, __arg3){
67
+ switch(type){
68
+ case 'close':
69
+ this.emit('close');
70
+ break;
71
+ }
72
+ }
133
73
 
134
74
  /**
135
75
  * 为特定事件添加一个监听处理程序.
136
- * 当前支持除'_error/_result/onStatus/error/close'等事件之外的
76
+ * 当前支持除'_error/_result/onStatus/error/close'等事件之外的
137
77
  * 任何自定义事件.上述事件为内部保留事件,用户不应定义与这些事件同名的
138
78
  * 远程调用函数名。与用户自定义事件相对应的事件处理函数的参数列表与远端
139
79
  * 调用时传入的参数列表一致。
@@ -184,17 +124,17 @@ ttsignal.Connector.prototype._internalCallback = function (
184
124
  * @example
185
125
  * press.createConnection(config);
186
126
  **/
187
- ttsignal.Connector.prototype.createConnection = function (config) {
188
- if (typeof config != "object") {
189
- throw Error("Invalid args value.");
190
- }
191
- var default_config = {
192
- c_cong_ctl: CONST.TTS_CC_BBR2,
193
- };
194
- copyProperties(default_config, config);
195
- let conn = this.__createConnection__(default_config);
196
- return conn;
197
- };
127
+ ttsignal.Connector.prototype.createConnection = function(config){
128
+ if (typeof(config) != 'object'){
129
+ throw Error('Invalid args value.');
130
+ }
131
+ var default_config = {
132
+ c_cong_ctl : CONST.TTS_CC_BBR2
133
+ }
134
+ copyProperties(default_config, config);
135
+ let conn = this.__createConnection__(default_config);
136
+ return conn;
137
+ }
198
138
 
199
139
  /**
200
140
  * 关闭。
@@ -205,73 +145,84 @@ ttsignal.Connector.prototype.createConnection = function (config) {
205
145
  * @example
206
146
  * connector.close();
207
147
  **/
208
- ttsignal.Connector.prototype.close = function () {
209
- this.__close__();
210
- };
148
+ ttsignal.Connector.prototype.close = function(){
149
+ this.__close__();
150
+ }
151
+
211
152
 
212
153
  /*******************************************************************************
213
- * @class ttsignal.Connection
214
- *******************************************************************************/
154
+ * @class ttsignal.Connection
155
+ *******************************************************************************/
215
156
 
216
157
  /**
217
158
  * @method _internalCallback
218
159
  * @private
219
- *
220
- *
160
+ *
161
+ *
221
162
  **/
222
- ttsignal.Connection.prototype._internalCallback = function (
223
- type,
224
- __arg2,
225
- __arg3
226
- ) {
227
- let self = this;
228
- switch (type) {
229
- case "handshakeFinished":
230
- this.streams = {};
231
- this.emit("handshakeFinished");
232
- break;
233
- case "streamCreated":
234
- if (this.streams.hasOwnProperty(__arg2)) {
235
- break;
236
- }
237
- var stream = new ttsignal.Stream(this, __arg2);
238
- this.streams[__arg2] = stream;
239
- this.emit("streamCreated", stream);
240
- break;
241
- case "streamClosed":
242
- if (!this.streams.hasOwnProperty(__arg2)) {
243
- break;
244
- }
245
- var stream = this.streams[__arg2];
246
- delete this.streams[__arg2];
247
- stream.onClose();
248
- break;
249
- case "command":
250
- if (!this.streams.hasOwnProperty(__arg2)) {
251
- break;
252
- }
253
- var stream = this.streams[__arg2];
254
- stream.onCommand(__arg3);
255
- break;
256
- case "data":
257
- if (!this.streams.hasOwnProperty(__arg2)) {
258
- break;
259
- }
260
- var stream = this.streams[__arg2];
261
- stream.onData(__arg3);
262
- break;
263
- case "restart":
264
- this.emit("restart", __arg2, __arg3);
265
- break;
266
- case "close":
267
- this.emit("close", __arg2);
268
- break;
269
- }
270
- };
163
+ ttsignal.Connection.prototype._internalCallback = function(type, __arg2, __arg3, __arg4, __arg5){
164
+ let self = this;
165
+ switch(type){
166
+ case 'handshakeFinished':
167
+ this.streams = {};
168
+ this.emit('handshakeFinished');
169
+ break;
170
+ case 'streamCreated':
171
+ if (this.streams.hasOwnProperty(__arg2)) {
172
+ break;
173
+ }
174
+ var stream = new ttsignal.Stream(this, __arg2);
175
+ this.streams[__arg2] = stream;
176
+ this.emit('streamCreated', stream);
177
+ break;
178
+ case 'streamClosed':
179
+ if (!this.streams.hasOwnProperty(__arg2)) {
180
+ break;
181
+ }
182
+ var stream = this.streams[__arg2];
183
+ delete this.streams[__arg2];
184
+ stream.onClose();
185
+ break;
186
+ case 'streamDataAcked':
187
+ if (!this.streams.hasOwnProperty(__arg2)) {
188
+ break;
189
+ }
190
+ var stream = this.streams[__arg2];
191
+ stream.onDataAcked(__arg3, __arg4, __arg5);
192
+ break;
193
+ case 'streamDataSent':
194
+ if (!this.streams.hasOwnProperty(__arg2)) {
195
+ break;
196
+ }
197
+ var stream = this.streams[__arg2];
198
+ stream.onDataSent(__arg3, __arg4);
199
+ break;
200
+ case 'command':
201
+ if (!this.streams.hasOwnProperty(__arg2)) {
202
+ break;
203
+ }
204
+ var stream = this.streams[__arg2];
205
+ stream.onCommand(__arg3);
206
+ break;
207
+ case 'data':
208
+ if (!this.streams.hasOwnProperty(__arg2)) {
209
+ break;
210
+ }
211
+ var stream = this.streams[__arg2];
212
+ stream.onData(__arg3, __arg4);
213
+ break;
214
+ case 'restart':
215
+ this.emit('restart', __arg2, __arg3);
216
+ break;
217
+ case 'close':
218
+ this.emit('close', __arg2);
219
+ break;
220
+ }
221
+ }
271
222
 
272
223
  /**
273
224
  * 为特定事件添加一个监听处理程序.
274
- * 当前支持除'_error/_result/onStatus/error/close'等事件之外的
225
+ * 当前支持除'_error/_result/onStatus/error/close'等事件之外的
275
226
  * 任何自定义事件.上述事件为内部保留事件,用户不应定义与这些事件同名的
276
227
  * 远程调用函数名。与用户自定义事件相对应的事件处理函数的参数列表与远端
277
228
  * 调用时传入的参数列表一致。
@@ -336,31 +287,26 @@ ttsignal.Connection.prototype._internalCallback = function (
336
287
  * console.log(result);
337
288
  * });
338
289
  **/
339
- ttsignal.Connection.prototype.connect = function (
340
- url,
341
- args,
342
- timeoutInMs,
343
- callback
344
- ) {
345
- if (typeof url != "string") {
346
- throw Error("Invalid url value.");
347
- }
348
- if (typeof callback != "function") {
349
- throw Error("Invalid callback value.");
350
- }
351
- this.__connect__(url, JSON.stringify(args), timeoutInMs, (err, response) => {
352
- if (typeof response == "string") {
353
- try {
354
- props = JSON.parse(response);
355
- callback(err, props);
356
- } catch (e) {
357
- callback(err, response);
358
- }
359
- } else {
360
- callback(err, null);
290
+ ttsignal.Connection.prototype.connect = function(url, args, timeoutInMs, callback){
291
+ if (typeof(url) != 'string'){
292
+ throw Error('Invalid url value.');
361
293
  }
362
- });
363
- };
294
+ if (typeof(callback) != 'function'){
295
+ throw Error('Invalid callback value.');
296
+ }
297
+ this.__connect__(url, JSON.stringify(args), timeoutInMs, (err, response)=>{
298
+ if (typeof response == 'string') {
299
+ try {
300
+ props = JSON.parse(response);
301
+ callback(err, props);
302
+ } catch (e) {
303
+ callback(err, response);
304
+ }
305
+ } else {
306
+ callback(err, null);
307
+ }
308
+ });
309
+ }
364
310
 
365
311
  /**
366
312
  * 重新创建底层socket。
@@ -371,9 +317,9 @@ ttsignal.Connection.prototype.connect = function (
371
317
  * @example
372
318
  * conn.restart();
373
319
  **/
374
- ttsignal.Connection.prototype.restart = function () {
375
- this.__restart__();
376
- };
320
+ ttsignal.Connection.prototype.restart = function(){
321
+ this.__restart__();
322
+ }
377
323
 
378
324
  /**
379
325
  * 关闭。
@@ -384,175 +330,345 @@ ttsignal.Connection.prototype.restart = function () {
384
330
  * @example
385
331
  * conn.close();
386
332
  **/
387
- ttsignal.Connection.prototype.close = function () {
388
- this.__close__();
389
- };
333
+ ttsignal.Connection.prototype.close = function(){
334
+ this.__close__();
335
+ }
390
336
 
391
337
  /*******************************************************************************
392
- * @class ttsignal.Stream
393
- *******************************************************************************/
394
-
395
- class Stream extends EventEmitter {
396
- constructor(conn, streamId) {
397
- super();
398
- this.conn = conn;
399
- this.streamId = streamId;
400
- this.nextTransId = 2;
401
- this.stubs = {};
402
- }
403
-
404
- onCommand(cmdStr) {
405
- let self = this;
406
- try {
407
- cmd = JSON.parse(cmdStr);
408
- if (typeof cmd != "object") {
409
- throw Error("Invalid command value." + __arg2);
410
- }
411
- if (!cmd.hasOwnProperty("name")) {
412
- throw Error(
413
- 'Invalid command value, MUST have "name" property.' + __arg2
414
- );
415
- }
416
- if (cmd.name == "_error" || cmd.name == "_result") {
417
- if (self.stubs.hasOwnProperty(cmd.transId)) {
418
- self.stubs[cmd.transId](cmd);
419
- delete self.stubs[cmd.transId];
338
+ * @class ttsignal.Stream
339
+ *******************************************************************************/
340
+
341
+ class Stream extends EventEmitter {
342
+ constructor(conn, streamId){
343
+ super();
344
+ this.conn = conn;
345
+ this.streamId = streamId;
346
+ this.nextTransId = 2;
347
+ this.stubs = {};
348
+ this.dataStreams = {};
349
+ }
350
+ onCommand(cmdStr){
351
+ let self = this;
352
+ try {
353
+ let cmd = JSON.parse(cmdStr)
354
+ if (typeof(cmd) != 'object') {
355
+ throw Error('Invalid command value.' + __arg2);
356
+ }
357
+ if (!cmd.hasOwnProperty('name')){
358
+ throw Error('Invalid command value, MUST have "name" property.' + __arg2);
359
+ }
360
+ if (cmd.name == '_error' || cmd.name == '_result' || cmd.name == 'onStatus'){
361
+ if (self.stubs.hasOwnProperty(cmd.transId)) {
362
+ self.stubs[cmd.transId](cmd);
363
+ let keepStub = cmd.name == 'onStatus'
364
+ if (!keepStub) {
365
+ delete self.stubs[cmd.transId];
366
+ }
367
+ }
368
+ } else {
369
+ if (cmd.hasOwnProperty('transId')) {
370
+ cmd.echoResult = function(result){
371
+ self.sendCommand({
372
+ name: '_result',
373
+ transId: cmd.transId,
374
+ result: result
375
+ });
376
+ }
377
+ cmd.echoError = function(error){
378
+ self.sendCommand({
379
+ name: '_error',
380
+ transId: cmd.transId,
381
+ error: error
382
+ });
383
+ }
384
+ } else {
385
+ cmd.echoResult = ()=>{};
386
+ cmd.echoError = ()=>{};
387
+ }
388
+ self.emit(cmd.name, cmd);
389
+ }
390
+ } catch (error) {
391
+ console.error('parse command failed', error);
392
+ return;
420
393
  }
421
- } else {
422
- if (cmd.hasOwnProperty("transId")) {
423
- cmd.echoResult = function (result) {
424
- self.sendCommand({
425
- name: "_result",
426
- transId: cmd.transId,
427
- result: result,
428
- });
429
- };
430
- cmd.echoError = function (error) {
431
- self.sendCommand({
432
- name: "_error",
433
- transId: cmd.transId,
434
- error: error,
435
- });
436
- };
437
- } else {
438
- cmd.echoResult = () => {};
439
- cmd.echoError = () => {};
394
+ }
395
+ onData(data, transId){
396
+ if (transId && this.dataStreams.hasOwnProperty(transId)) {
397
+ let ds = this.dataStreams[transId];
398
+ if (data.length === 0) {
399
+ delete this.dataStreams[transId];
400
+ ds.emit('end');
401
+ } else {
402
+ ds.emit('data', data);
403
+ }
404
+ return;
440
405
  }
441
- self.emit(cmd.name, cmd);
442
- }
443
- } catch (error) {
444
- console.error("parse command failed", error);
445
- return;
406
+ this.emit('data', data);
446
407
  }
447
- }
448
-
449
- onData(data) {
450
- this.emit("data", data);
451
- }
452
-
453
- onClose() {
454
- this.emit("close");
455
- }
456
-
457
- /**
458
- * 发送命令.
459
- *
460
- * @method sendCommand
461
- * @public
462
- * @param timestamp {Number} timestamp.
463
- * @param cmd {Buffer} commnd to send.
464
- * @example
465
- * conn.sendCommand(cmd);
466
- **/
467
- sendCommand(cmd, callback) {
468
- if (typeof cmd != "object") {
469
- throw Error("Invalid command value.");
408
+
409
+ onClose(){
410
+ for (let tid in this.dataStreams) {
411
+ this.dataStreams[tid].emit('end');
412
+ }
413
+ this.dataStreams = {};
414
+ this.emit('close');
470
415
  }
471
- if (!cmd.hasOwnProperty("name")) {
472
- throw Error('Invalid command value, MUST have "name" property.');
416
+
417
+ /** QUIC 发送侧:数据确认回调;emit `dataAcked`(ackDelayTimeµs, ackedBytes, inflightBytes)。 */
418
+ onDataAcked(ackDelayTime, ackedBytes, inflightBytes){
419
+ this.emit('dataAcked', ackDelayTime, ackedBytes, inflightBytes);
473
420
  }
474
- if (typeof callback === "function") {
475
- cmd.transId = this.nextTransId++;
476
- this.stubs[cmd.transId] = callback;
421
+
422
+ /** QUIC 发送侧:数据已从待发队列写入传输;emit `dataSent`(nTransId, size)。putFile 返回的 ws 仅转发本 transId 为 `dataSent`(size)。 */
423
+ onDataSent(nTransId, size){
424
+ this.emit('dataSent', nTransId, size);
477
425
  }
478
- let msg = JSON.stringify(cmd);
479
- let buf = Buffer.from(msg, "utf8");
480
- this.conn.__sendPacket__(
481
- CONST.TTS_TYPE_COMMAND,
482
- new Date().getTime(),
483
- 0,
484
- this.streamId,
485
- buf
486
- );
487
- }
488
-
489
- /**
490
- * 发送数据.
491
- *
492
- * @method sendData
493
- * @public
494
- * @param timestamp {Number} timestamp.
495
- * @param data {Buffer} data to send.
496
- * @example
497
- * conn.sendData(data);
498
- **/
499
- sendData(data) {
500
- if (data instanceof Buffer == false) {
501
- throw Error("Invalid data type, MUST be Buffer.");
426
+
427
+ /**
428
+ * 发送命令.
429
+ *
430
+ * @method sendCommand
431
+ * @public
432
+ * @param cmd {Object} command to send.
433
+ * @param callback {Function} callback function.
434
+ * @example
435
+ * conn.sendCommand(cmd);
436
+ **/
437
+ sendCommand(cmd, callback){
438
+ if (typeof(cmd) != 'object') {
439
+ throw Error('Invalid command value.');
440
+ }
441
+ if (!cmd.hasOwnProperty('name')){
442
+ throw Error('Invalid command value, MUST have "name" property.');
443
+ }
444
+ if (typeof callback === 'function') {
445
+ cmd.transId = this.nextTransId++;
446
+ this.stubs[cmd.transId] = callback;
447
+ }
448
+ let msg = JSON.stringify(cmd);
449
+ let buf = Buffer.from(msg, 'utf8');
450
+ this.conn.__sendPacket__(CONST.TTS_TYPE_COMMAND, (new Date).getTime(),
451
+ cmd.transId, this.streamId, buf);
452
+ }
453
+
454
+ /**
455
+ * 发送数据.
456
+ *
457
+ * @method sendData
458
+ * @public
459
+ * @param timestamp {Number} timestamp.
460
+ * @param data {Buffer} data to send.
461
+ * @example
462
+ * conn.sendData(data);
463
+ **/
464
+ sendData(data){
465
+ if (data instanceof Buffer == false) {
466
+ throw Error('Invalid data type, MUST be Buffer.');
467
+ }
468
+ this.conn.__sendPacket__(CONST.TTS_TYPE_MESSAGE, (new Date).getTime(),
469
+ 0, this.streamId, data);
470
+ }
471
+
472
+ /**
473
+ * 请求文件(数据流下载)。
474
+ *
475
+ * @method getFile
476
+ * @public
477
+ * @param req {Object} 请求参数,如 {path:"index.html"}
478
+ * @param callback {Function} 命令响应回调,透传给底层 __sendPacket__
479
+ * @return {EventEmitter} 数据流对象,支持 'data' 和 'end' 事件
480
+ * @example
481
+ * let ds = stream.getFile({path:"index.html"}, (cmd)=>{
482
+ * console.log('response:', cmd);
483
+ * });
484
+ * ds.on('data', (chunk) => { ... });
485
+ * ds.on('end', () => { ... });
486
+ **/
487
+ getFile(args, callback){
488
+ if (typeof(args) != 'object') {
489
+ throw Error('Invalid request value.');
490
+ }
491
+ if (!args.hasOwnProperty('path')) {
492
+ throw Error('Invalid request value, MUST have "path" property.');
493
+ }
494
+ args.method = 'GET';
495
+ let req = {
496
+ name: 'staticFile',
497
+ props: args
498
+ };
499
+ let self = this;
500
+ let transId = this.nextTransId++;
501
+ req.transId = transId;
502
+ if (typeof callback === 'function') {
503
+ this.stubs[transId] = callback;
504
+ }
505
+ let ds = new EventEmitter();
506
+ ds.once('end', () => { delete self.dataStreams[transId]; });
507
+ this.dataStreams[transId] = ds;
508
+ let msg = JSON.stringify(req);
509
+ let buf = Buffer.from(msg, 'utf8');
510
+ this.conn.__sendPacket__(CONST.TTS_TYPE_COMMAND, (new Date).getTime(),
511
+ transId, this.streamId, buf);
512
+ return ds;
513
+ }
514
+
515
+ /**
516
+ * 上传文件(数据流上传)。
517
+ *
518
+ * @method putFile
519
+ * @public
520
+ * @param req {Object} 请求参数,如 {path:"upload.bin"}
521
+ * @param callback {Function} 命令响应回调
522
+ * @return {events.EventEmitter} 写入流:write(data)、end(),并可 on('dataSent', (size)=>{})(仅本 putFile 事务)。
523
+ * @example
524
+ * let ws = stream.putFile({path:"upload.bin"}, (cmd)=>{
525
+ * console.log('response:', cmd);
526
+ * });
527
+ * ws.on('dataSent', (size) => {});
528
+ * ws.write(chunk1);
529
+ * ws.write(chunk2);
530
+ * ws.end();
531
+ **/
532
+ putFile(args, callback){
533
+ if (typeof(args) != 'object') {
534
+ throw Error('Invalid request value.');
535
+ }
536
+ if (!args.hasOwnProperty('path')) {
537
+ throw Error('Invalid request value, MUST have "path" property.');
538
+ }
539
+ if (!args.hasOwnProperty('size')) {
540
+ throw Error('Invalid request value, MUST have "path" property.');
541
+ }
542
+ args.method = 'PUT';
543
+ let req = {
544
+ name: 'staticFile',
545
+ props: args
546
+ };
547
+ let self = this;
548
+ let transId = this.nextTransId++;
549
+ req.transId = transId;
550
+ if (typeof callback === 'function') {
551
+ this.stubs[transId] = callback;
552
+ }
553
+ let msg = JSON.stringify(req);
554
+ let buf = Buffer.from(msg, 'utf8');
555
+ this.conn.__sendPacket__(CONST.TTS_TYPE_COMMAND, (new Date).getTime(),
556
+ transId, this.streamId, buf);
557
+ let ended = false;
558
+ let ws = new EventEmitter();
559
+ let onDataSent = (nTransId, size) => {
560
+ if (nTransId == transId) {
561
+ ws.emit('dataSent', size);
562
+ }
563
+ }
564
+ this.on('dataSent', onDataSent);
565
+ ws.write = (data) => {
566
+ if (ended) {
567
+ throw Error('Write after end.');
568
+ }
569
+ if (data instanceof Buffer == false) {
570
+ throw Error('Invalid data type, MUST be Buffer.');
571
+ }
572
+ self.conn.__sendPacket__(CONST.TTS_TYPE_MESSAGE, (new Date).getTime(),
573
+ transId, self.streamId, data);
574
+ }
575
+ ws.end = () => {
576
+ if (ended) return;
577
+ ended = true;
578
+ self.conn.__sendPacket__(CONST.TTS_TYPE_MESSAGE, (new Date).getTime(),
579
+ transId, self.streamId, Buffer.alloc(0));
580
+ self.removeListener('dataSent', onDataSent);
581
+ }
582
+ return ws;
583
+ }
584
+
585
+ /**
586
+ * 请求文件(数据流下载)。
587
+ *
588
+ * @method getLogFile
589
+ * @public
590
+ * @param req {Object} 请求参数,如 {path:"room_name"}
591
+ * @param callback {Function} 命令响应回调,透传给底层 __sendPacket__
592
+ * @return {EventEmitter} 数据流对象,支持 'data' 和 'end' 事件
593
+ * @example
594
+ * let ds = stream.getLogFile({path:"room_name"}, (cmd)=>{
595
+ * console.log('response:', cmd);
596
+ * });
597
+ * ds.on('data', (chunk) => { ... });
598
+ * ds.on('end', () => { ... });
599
+ **/
600
+ getLogFile(args, callback){
601
+ if (typeof(args) != 'object') {
602
+ throw Error('Invalid request value.');
603
+ }
604
+ if (!args.hasOwnProperty('roomId')) {
605
+ throw Error('Invalid request value, MUST have "roomId" property.');
606
+ }
607
+ args.method = 'GET';
608
+ let req = {
609
+ name: 'logFile',
610
+ props: args
611
+ };
612
+ let self = this;
613
+ let transId = this.nextTransId++;
614
+ req.transId = transId;
615
+ if (typeof callback === 'function') {
616
+ this.stubs[transId] = callback;
617
+ }
618
+ let ds = new EventEmitter();
619
+ ds.once('end', () => { delete self.dataStreams[transId]; });
620
+ this.dataStreams[transId] = ds;
621
+ let msg = JSON.stringify(req);
622
+ let buf = Buffer.from(msg, 'utf8');
623
+ this.conn.__sendPacket__(CONST.TTS_TYPE_COMMAND, (new Date).getTime(),
624
+ transId, this.streamId, buf);
625
+ return ds;
626
+ }
627
+
628
+ /**
629
+ * 关闭。
630
+ *
631
+ * @method close
632
+ * @public
633
+ * @sync
634
+ * @example
635
+ * conn.close();
636
+ **/
637
+ close(){
638
+ this.conn.__closeStream__(this.streamId);
502
639
  }
503
- this.conn.__sendPacket__(
504
- CONST.TTS_TYPE_MESSAGE,
505
- new Date().getTime(),
506
- 0,
507
- this.streamId,
508
- data
509
- );
510
- }
511
-
512
- /**
513
- * 关闭。
514
- *
515
- * @method close
516
- * @public
517
- * @sync
518
- * @example
519
- * conn.close();
520
- **/
521
- close() {
522
- this.conn.__closeStream__(this.streamId);
523
- }
524
640
  }
525
641
  ttsignal.Stream = Stream;
526
642
 
527
643
  /*******************************************************************************
528
- * @class ttsignal.Server
529
- *******************************************************************************/
644
+ * @class ttsignal.Server
645
+ *******************************************************************************/
530
646
 
531
647
  /**
532
648
  * @method _internalCallback
533
649
  * @private
534
- *
535
- *
650
+ *
651
+ *
536
652
  **/
537
- ttsignal.Server.prototype._internalCallback = function (type, __arg2, __arg3) {
538
- switch (type) {
539
- case "connection":
540
- if (__arg2 instanceof ttsignal.ServerConnection) {
541
- let conn = __arg2;
542
- conn.nextTransId = 2;
543
- conn.stubs = {};
544
- this.emit("connection", conn);
545
- }
546
- break;
547
- case "close":
548
- this.emit("close");
549
- break;
550
- }
551
- };
653
+ ttsignal.Server.prototype._internalCallback = function(type, __arg2, __arg3){
654
+ switch(type){
655
+ case 'connection':
656
+ if (__arg2 instanceof ttsignal.ServerConnection) {
657
+ let conn = __arg2;
658
+ conn.nextTransId = 2;
659
+ conn.stubs = {};
660
+ this.emit('connection', conn);
661
+ }
662
+ break;
663
+ case 'close':
664
+ this.emit('close');
665
+ break;
666
+ }
667
+ }
552
668
 
553
669
  /**
554
670
  * 为特定事件添加一个监听处理程序.
555
- * 当前支持除'_error/_result/onStatus/error/close'等事件之外的
671
+ * 当前支持除'_error/_result/onStatus/error/close'等事件之外的
556
672
  * 任何自定义事件.上述事件为内部保留事件,用户不应定义与这些事件同名的
557
673
  * 远程调用函数名。与用户自定义事件相对应的事件处理函数的参数列表与远端
558
674
  * 调用时传入的参数列表一致。
@@ -603,9 +719,9 @@ ttsignal.Server.prototype._internalCallback = function (type, __arg2, __arg3) {
603
719
  * @example
604
720
  * connector.start();
605
721
  **/
606
- ttsignal.Server.prototype.start = function () {
607
- this.__start__();
608
- };
722
+ ttsignal.Server.prototype.start = function(){
723
+ this.__start__();
724
+ }
609
725
 
610
726
  /**
611
727
  * 关闭服务器。
@@ -616,93 +732,88 @@ ttsignal.Server.prototype.start = function () {
616
732
  * @example
617
733
  * connector.close();
618
734
  **/
619
- ttsignal.Server.prototype.close = function () {
620
- this.__close__();
621
- };
735
+ ttsignal.Server.prototype.close = function(){
736
+ this.__close__();
737
+ }
738
+
622
739
 
623
740
  /*******************************************************************************
624
- * @class ttsignal.ServerConnection
625
- *******************************************************************************/
741
+ * @class ttsignal.ServerConnection
742
+ *******************************************************************************/
626
743
 
627
744
  /**
628
745
  * @method _internalCallback
629
746
  * @private
630
- *
631
- *
747
+ *
748
+ *
632
749
  **/
633
- ttsignal.ServerConnection.prototype._internalCallback = function (
634
- type,
635
- __arg2,
636
- __arg3
637
- ) {
638
- var self = this;
639
- switch (type) {
640
- case "handshakeFinished":
641
- this.emit("handshakeFinished");
642
- break;
643
- case "connect":
644
- try {
645
- props = JSON.parse(__arg2);
646
- this.emit("connect", props);
647
- } catch (e) {
648
- this.emit("connect", e);
649
- }
650
- break;
651
- case "command":
652
- try {
653
- cmd = JSON.parse(__arg2);
654
- if (typeof cmd != "object") {
655
- throw Error("Invalid command value." + __arg2);
656
- }
657
- if (!cmd.hasOwnProperty("name")) {
658
- throw Error(
659
- 'Invalid command value, MUST have "name" property.' + __arg2
660
- );
661
- }
662
- if (cmd.name == "_error" || cmd.name == "_result") {
663
- if (self.stubs.hasOwnProperty(cmd.transId)) {
664
- self.stubs[cmd.transId](cmd);
665
- delete self.stubs[cmd.transId];
666
- }
667
- } else {
668
- if (cmd.hasOwnProperty("transId")) {
669
- cmd.echoResult = function (result) {
670
- self.sendCommand({
671
- name: "_result",
672
- transId: cmd.transId,
673
- result: result,
674
- });
675
- };
676
- cmd.echoError = function (error) {
677
- self.sendCommand({
678
- name: "_error",
679
- transId: cmd.transId,
680
- error: error,
681
- });
682
- };
683
- } else {
684
- cmd.echoResult = () => {};
685
- cmd.echoError = () => {};
686
- }
687
- self.emit(cmd.name, cmd);
688
- }
689
- } catch (error) {
690
- console.error("parse command failed", error);
691
- return;
692
- }
693
- break;
694
- case "data":
695
- this.emit("data", __arg2);
696
- break;
697
- case "close":
698
- this.emit("close", __arg2);
699
- break;
700
- }
701
- };
750
+ ttsignal.ServerConnection.prototype._internalCallback = function(type, __arg2, __arg3){
751
+ var self = this;
752
+ switch(type){
753
+ case 'handshakeFinished':
754
+ this.emit('handshakeFinished');
755
+ break;
756
+ case 'connect':
757
+ try {
758
+ props = JSON.parse(__arg2);
759
+ this.emit('connect', props);
760
+ } catch (e) {
761
+ this.emit('connect', e);
762
+ }
763
+ break;
764
+ case 'command':
765
+ try {
766
+ cmd = JSON.parse(__arg2);
767
+ if (typeof(cmd) != 'object') {
768
+ throw Error('Invalid command value.' + __arg2);
769
+ }
770
+ if (!cmd.hasOwnProperty('name')){
771
+ throw Error('Invalid command value, MUST have "name" property.' + __arg2);
772
+ }
773
+ if (cmd.name == '_error' || cmd.name == '_result'){
774
+ if (self.stubs.hasOwnProperty(cmd.transId)) {
775
+ self.stubs[cmd.transId](cmd);
776
+ delete self.stubs[cmd.transId];
777
+ }
778
+ } else {
779
+ if (cmd.hasOwnProperty('transId')) {
780
+ cmd.echoResult = function(result){
781
+ self.sendCommand({
782
+ name: '_result',
783
+ transId: cmd.transId,
784
+ result: result
785
+ });
786
+ }
787
+ cmd.echoError = function(error){
788
+ self.sendCommand({
789
+ name: '_error',
790
+ transId: cmd.transId,
791
+ error: error
792
+ });
793
+ }
794
+ } else {
795
+ cmd.echoResult = ()=>{};
796
+ cmd.echoError = ()=>{};
797
+ }
798
+ self.emit(cmd.name, cmd);
799
+ }
800
+ } catch (error) {
801
+ console.error('parse command failed', error);
802
+ return;
803
+ }
804
+ break;
805
+ case 'data':
806
+ this.emit('data', __arg2);
807
+ break;
808
+ case 'close':
809
+ this.emit('close', __arg2);
810
+ break;
811
+ }
812
+ }
702
813
 
703
814
  /**
704
815
  * 为特定事件添加一个监听处理程序.
705
- * 当前支持除'_error/_result/onStatus/error/close'等事件之外的
816
+ * 当前支持除'_error/_result/onStatus/error/close'等事件之外的
706
817
  * 任何自定义事件.上述事件为内部保留事件,用户不应定义与这些事件同名的
707
818
  * 远程调用函数名。与用户自定义事件相对应的事件处理函数的参数列表与远端
708
819
  * 调用时传入的参数列表一致。
@@ -749,26 +860,28 @@ ttsignal.ServerConnection.prototype._internalCallback = function (
749
860
  *
750
861
  * @method sendCommand
751
862
  * @public
752
- * @param timestamp {Number} timestamp.
753
- * @param cmd {Buffer} commnd to send.
863
+ * @param cmd {Object} command to send.
864
+ * @param callback {Function} callback function.
754
865
  * @example
755
- * conn.sendCommand(cmd);
866
+ * conn.sendCommand(cmd, function(result){
867
+ * console.log(result);
868
+ * });
756
869
  **/
757
- ttsignal.ServerConnection.prototype.sendCommand = function (cmd) {
758
- if (typeof cmd != "object") {
759
- throw Error("Invalid command value.");
760
- }
761
- if (!cmd.hasOwnProperty("name")) {
762
- throw Error('Invalid command value, MUST have "name" property.');
763
- }
764
- if (typeof callback === "function") {
765
- cmd.transId = this.nextTransId++;
766
- this.stubs[cmd.transId] = callback;
767
- }
768
- let msg = JSON.stringify(cmd);
769
- let buf = Buffer.from(msg, "utf8");
770
- this.__sendPacket__(CONST.TTS_TYPE_COMMAND, new Date().getTime(), 0, buf);
771
- };
870
+ ttsignal.ServerConnection.prototype.sendCommand = function(cmd, callback){
871
+ if (typeof(cmd) != 'object') {
872
+ throw Error('Invalid command value.');
873
+ }
874
+ if (!cmd.hasOwnProperty('name')){
875
+ throw Error('Invalid command value, MUST have "name" property.');
876
+ }
877
+ if (typeof callback === 'function') {
878
+ cmd.transId = this.nextTransId++;
879
+ this.stubs[cmd.transId] = callback;
880
+ }
881
+ let msg = JSON.stringify(cmd);
882
+ let buf = Buffer.from(msg, 'utf8');
883
+ this.__sendPacket__(CONST.TTS_TYPE_COMMAND, (new Date).getTime(), cmd.transId, 0, buf);
884
+ }
772
885
 
773
886
  /**
774
887
  * 发送数据.
@@ -780,12 +893,12 @@ ttsignal.ServerConnection.prototype.sendCommand = function (cmd) {
780
893
  * @example
781
894
  * conn.sendData(data);
782
895
  **/
783
- ttsignal.ServerConnection.prototype.sendData = function (data) {
784
- if (data instanceof Buffer == false) {
785
- throw Error("Invalid data type, MUST be Buffer.");
786
- }
787
- this.__sendPacket__(CONST.TTS_TYPE_MESSAGE, new Date().getTime(), 0, data);
788
- };
896
+ ttsignal.ServerConnection.prototype.sendData = function(data){
897
+ if (data instanceof Buffer == false) {
898
+ throw Error('Invalid data type, MUST be Buffer.');
899
+ }
900
+ this.__sendPacket__(CONST.TTS_TYPE_MESSAGE, (new Date).getTime(), 0, data);
901
+ }
789
902
 
790
903
  /**
791
904
  * 接受连接。
@@ -796,12 +909,12 @@ ttsignal.ServerConnection.prototype.sendData = function (data) {
796
909
  * @example
797
910
  * conn.accept(true, { server_param: 'server param' });
798
911
  **/
799
- ttsignal.ServerConnection.prototype.accept = function (accept, result) {
800
- if (typeof accept != "boolean") {
801
- throw Error("Invalid accept value.");
802
- }
803
- this.__accept__(accept, JSON.stringify(result));
804
- };
912
+ ttsignal.ServerConnection.prototype.accept = function(accept, result){
913
+ if (typeof(accept) != 'boolean') {
914
+ throw Error('Invalid accept value.');
915
+ }
916
+ this.__accept__(accept, JSON.stringify(result));
917
+ }
805
918
 
806
919
  /**
807
920
  * 关闭。
@@ -812,13 +925,13 @@ ttsignal.ServerConnection.prototype.accept = function (accept, result) {
812
925
  * @example
813
926
  * conn.close();
814
927
  **/
815
- ttsignal.ServerConnection.prototype.close = function () {
816
- this.__close__();
817
- };
928
+ ttsignal.ServerConnection.prototype.close = function(){
929
+ this.__close__();
930
+ }
818
931
 
819
932
  /*******************************************************************************
820
- * @class
821
- *******************************************************************************/
933
+ * @class
934
+ *******************************************************************************/
822
935
 
823
936
  /**
824
937
  * 创建连接器.
@@ -826,18 +939,36 @@ ttsignal.ServerConnection.prototype.close = function () {
826
939
  * @method createConnector
827
940
  * @public
828
941
  * @param config {Object} configure info.
942
+ * @param config.alpn {String} required, ALPN string ('ttsignal' on the wire regardless).
943
+ * @param config.ca_cert_pem {String=} optional, custom root CA in PEM format.
944
+ * @param config.disableAutoRestart {Boolean=} optional, default `false`.
945
+ * When `false` (default) ttsignal starts a platform-native path-change
946
+ * monitor (NWPathMonitor on macOS, NETLINK_ROUTE on Linux,
947
+ * NotifyIpInterfaceChange on Windows) and automatically restarts the
948
+ * underlying UDP socket whenever the OS reports a different default
949
+ * interface (Wi-Fi <-> ethernet, Wi-Fi <-> wired, VPN up/down). Each
950
+ * auto-restart fires the existing `connection.on('restart', cb)` event,
951
+ * so application code does NOT need to call `connection.restart()`
952
+ * manually. Set `disableAutoRestart: true` for long-lived server
953
+ * deployments where the box never roams.
829
954
  * @example
830
- * var succeed = ttsignal.createConnector(config);
955
+ * var connector = ttsignal.createConnector({
956
+ * alpn: 'ttsignal',
957
+ * disableAutoRestart: false, // default
958
+ * });
831
959
  **/
832
- ttsignal.createConnector = function (config) {
833
- if (typeof config !== "object") {
834
- throw Error("Invalid config.");
835
- }
836
- if (!config.alpn) {
837
- throw Error("Invalid alpn value.");
838
- }
839
- return ttsignal.__createConnector__(config);
840
- };
960
+ ttsignal.createConnector = function(config){
961
+ if (typeof config !== 'object') {
962
+ throw Error('Invalid config.');
963
+ }
964
+ if (!config.alpn){
965
+ throw Error('Invalid alpn value.');
966
+ }
967
+ if (config.caCertPem && !config.ca_cert_pem) {
968
+ config.ca_cert_pem = config.caCertPem;
969
+ }
970
+ return ttsignal.__createConnector__(config);
971
+ }
841
972
 
842
973
  /**
843
974
  * 创建服务器.
@@ -848,23 +979,21 @@ ttsignal.createConnector = function (config) {
848
979
  * @example
849
980
  * var succeed = ttsignal.createServer(config);
850
981
  **/
851
- ttsignal.createServer = function (config) {
852
- if (typeof config !== "object") {
853
- throw Error("Invalid config.");
854
- }
855
- if (!config.alpn) {
856
- throw Error("Invalid alpn value.");
857
- }
858
- return ttsignal.__createServer__(config);
859
- };
982
+ ttsignal.createServer = function(config){
983
+ if (typeof config !== 'object') {
984
+ throw Error('Invalid config.');
985
+ }
986
+ if (!config.alpn){
987
+ throw Error('Invalid alpn value.');
988
+ }
989
+ return ttsignal.__createServer__(config);
990
+ }
860
991
 
861
992
  //*******************************************************************************
862
- // Exports :
993
+ // Exports :
863
994
  //*******************************************************************************
864
995
 
865
- // Export for both CommonJS (require) and ESM (dynamic import default)
866
- // module.exports = ttsignal;
867
- exports.ttsignal = ttsignal;
996
+ module.exports = ttsignal;
868
997
 
869
998
  //*******************************************************************************
870
999
  // End of file : ttsignal.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cc-livekit/ttsignal",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"