@flashphoner/websdk 2.0.265 → 2.0.266

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.
@@ -2,14 +2,25 @@
2
2
 
3
3
  const util = require('./util');
4
4
  const LOG_PREFIX = "stats-collector";
5
+ const CONNECTION_TYPE = {
6
+ WEBSOCKET: "ws",
7
+ HTTP: "http"
8
+ }
9
+ const MAX_SEND_ERRORS = 3;
10
+ const CONNECTION_STATUS = {
11
+ INIT: 0,
12
+ OK: 200,
13
+ BAD_REQUEST: 400,
14
+ INTERNAL_SERVER_ERROR: 500
15
+ };
5
16
 
6
17
  // Collect and send WebRTC statistics periodically
7
- const StreamStatsCollector = function(description, id, mediaConnection, wsConnection, logger) {
18
+ const StreamStatsCollector = function(description, id, mediaConnection, wsConnection, logger, maxErrors) {
8
19
  let statCollector = {
9
20
  description: description,
10
21
  id: id,
11
22
  mediaConnection: mediaConnection,
12
- wsConnection: wsConnection,
23
+ connection: Connection(wsConnection, maxErrors),
13
24
  logger: getLogger(logger),
14
25
  headers: "",
15
26
  compression: "none",
@@ -31,19 +42,27 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
31
42
  if (!statCollector.mediaConnection) {
32
43
  throw new Error(error + "no media connection available");
33
44
  }
34
- if (!statCollector.wsConnection) {
35
- throw new Error(error + "no websocket connection available");
45
+
46
+ statCollector.logger.debug(LOG_PREFIX, "RTCMetricsServerDescription: " + JSON.stringify(statCollector.description));
47
+ if (statCollector.description.ingestPoint) {
48
+ let authHeader = null;
49
+ if (statCollector.description.authorization) {
50
+ authHeader = {
51
+ Authorization: statCollector.description.authorization
52
+ }
53
+ }
54
+ statCollector.connection.setUp(statCollector.description.ingestPoint, authHeader);
36
55
  }
37
56
 
38
57
  await statCollector.updateHeaders();
39
58
  await statCollector.updateCompression();
40
- statCollector.sendHeaders();
59
+ await statCollector.sendHeaders();
41
60
  if (statCollector.description.collect === "on") {
42
61
  statCollector.collect(true);
43
62
  }
44
63
  },
45
64
  collect: function(enable) {
46
- if (enable) {
65
+ if (enable && statCollector.connection.status === CONNECTION_STATUS.OK) {
47
66
  statCollector.startTimer();
48
67
  } else {
49
68
  statCollector.stopTimer();
@@ -55,11 +74,10 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
55
74
  },
56
75
  update: async function(description) {
57
76
  if (!description) {
58
- if (statCollector.logger) {
59
- statCollector.logger.error(LOG_PREFIX + "-" + statCollector.id, "Can't update WebRTC metrics sending: no parameters passed");
60
- return;
61
- }
77
+ statCollector.logger.error(LOG_PREFIX + "-" + statCollector.id, "Can't update WebRTC metrics sending: no parameters passed");
78
+ return;
62
79
  }
80
+ statCollector.logger.debug(LOG_PREFIX, "New RTCMetricsServerDescription: " + JSON.stringify(description));
63
81
  if (description.types || description.compression) {
64
82
  statCollector.stop();
65
83
  if (description.types) {
@@ -70,7 +88,10 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
70
88
  statCollector.description.compression = description.compression;
71
89
  await statCollector.updateCompression();
72
90
  }
73
- statCollector.sendHeaders();
91
+ await statCollector.sendHeaders();
92
+ if (statCollector.connection.status !== CONNECTION_STATUS.OK) {
93
+ return;
94
+ }
74
95
  } else {
75
96
  statCollector.collect(false);
76
97
  }
@@ -188,21 +209,22 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
188
209
  statCollector.compression = "none";
189
210
  }
190
211
  },
191
- sendHeaders: function() {
212
+ sendHeaders: async function() {
192
213
  let data = {
193
214
  mediaSessionId: statCollector.id,
194
215
  compression: statCollector.compression,
195
216
  headers: statCollector.headers
196
217
  };
197
- statCollector.send("webRTCMetricsClientDescription", data);
218
+ await statCollector.send("webRTCMetricsClientDescription", data);
198
219
  },
199
- send: function(message, data) {
200
- statCollector.logger.debug(LOG_PREFIX + "-" + statCollector.id, data);
201
- if (statCollector.wsConnection.readyState === WebSocket.OPEN) {
202
- statCollector.wsConnection.send(JSON.stringify({
203
- message: message,
204
- data: [data]
205
- }));
220
+ send: async function(message, data) {
221
+ if (statCollector.connection.status === CONNECTION_STATUS.INIT || statCollector.connection.status === CONNECTION_STATUS.OK) {
222
+ statCollector.logger.debug(LOG_PREFIX + "-" + statCollector.id, data);
223
+ await statCollector.connection.send(message, data);
224
+ if (statCollector.connection.status !== CONNECTION_STATUS.OK) {
225
+ statCollector.logger.error(LOG_PREFIX + "-" + statCollector.id, "Error " + statCollector.connection.status + " sending RTC metrics to the server, stop sending");
226
+ statCollector.stop();
227
+ }
206
228
  }
207
229
  },
208
230
  startTimer: function() {
@@ -269,7 +291,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
269
291
  // Check if metrics list changed and send a new headers if needed #WCS-4619
270
292
  if (headersUpdated) {
271
293
  statCollector.logger.info(LOG_PREFIX + "-" + statCollector.id, "RTC metrics list has changed, sending a new metrics description");
272
- statCollector.sendHeaders();
294
+ await statCollector.sendHeaders();
273
295
  }
274
296
  statCollector.timerBusy = false;
275
297
  }
@@ -314,7 +336,7 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
314
336
  mediaSessionId: statCollector.id,
315
337
  metrics: metricsData
316
338
  };
317
- statCollector.send("webRTCMetricsBatch", data);
339
+ await statCollector.send("webRTCMetricsBatch", data);
318
340
  }
319
341
  statCollector.cleanBatch();
320
342
  },
@@ -336,6 +358,117 @@ const StreamStatsCollector = function(description, id, mediaConnection, wsConnec
336
358
  return statCollector;
337
359
  }
338
360
 
361
+ // Wrapper to send metrics via Websocket or HTTP POST
362
+ const Connection = function(existingConnection = null, maxErrors = MAX_SEND_ERRORS) {
363
+ const connection = {
364
+ type: "",
365
+ websocket: null,
366
+ http: null,
367
+ maxErrors: maxErrors,
368
+ errorsCount: 0,
369
+ status: CONNECTION_STATUS.INIT,
370
+ setUp: function(url, headers = null, existingConnection = null) {
371
+ if (url.startsWith(CONNECTION_TYPE.WEBSOCKET)) {
372
+ connection.type = CONNECTION_TYPE.WEBSOCKET;
373
+ // ToDo: create a new Websocket connection
374
+ } else if (url.startsWith(CONNECTION_TYPE.HTTP)) {
375
+ connection.type = CONNECTION_TYPE.HTTP
376
+ connection.http = HttpConnection(url, headers);
377
+ } else if (existingConnection) {
378
+ connection.type = CONNECTION_TYPE.WEBSOCKET;
379
+ connection.websocket = WebsocketConnection(existingConnection);
380
+ }
381
+ connection.errorsCount = 0;
382
+ connection.status = CONNECTION_STATUS.INIT;
383
+ },
384
+ send: async function(message, data) {
385
+ let code = CONNECTION_STATUS.BAD_REQUEST;
386
+ switch(connection.type) {
387
+ case CONNECTION_TYPE.WEBSOCKET:
388
+ if (connection.websocket) {
389
+ code = connection.websocket.send(message, data);
390
+ }
391
+ break;
392
+ case CONNECTION_TYPE.HTTP:
393
+ if (connection.http) {
394
+ code = await connection.http.send(message, data);
395
+ }
396
+ break;
397
+ }
398
+ connection.status = code;
399
+ if (connection.status === CONNECTION_STATUS.OK) {
400
+ connection.errorsCount = 0;
401
+ }
402
+ else {
403
+ if (message === "webRTCMetricsBatch") {
404
+ connection.errorsCount++;
405
+ if (connection.errorsCount < connection.maxErrors) {
406
+ connection.status = CONNECTION_STATUS.OK;
407
+ }
408
+ }
409
+ }
410
+ }
411
+ };
412
+ connection.setUp("", null, existingConnection);
413
+ return connection;
414
+ }
415
+
416
+ // Websocket connection (using existing one)
417
+ const WebsocketConnection = function(wsConnection) {
418
+ const connection = {
419
+ websocket: wsConnection,
420
+ send: function(message, data) {
421
+ let code = CONNECTION_STATUS.BAD_REQUEST;
422
+ if (connection.websocket) {
423
+ console.log(connection.websocket);
424
+ if (connection.websocket.readyState === WebSocket.OPEN) {
425
+ connection.websocket.send(JSON.stringify({
426
+ message: message,
427
+ data: [data]
428
+ }));
429
+ }
430
+ code = CONNECTION_STATUS.OK;
431
+ }
432
+ return code;
433
+ }
434
+ }
435
+ return connection;
436
+ }
437
+
438
+ // HTTP connection using Fetch API
439
+ const HttpConnection = function(url, headers) {
440
+ const connection = {
441
+ url: addSlash(url),
442
+ headers: headers,
443
+ send: async function(message, data) {
444
+ let code = CONNECTION_STATUS.BAD_REQUEST;
445
+ if (connection.url) {
446
+ try {
447
+ const httpHeaders = new Headers();
448
+ httpHeaders.append("Content-Type", "application/json");
449
+
450
+ if (connection.headers) {
451
+ for (const [header, value] of Object.entries(connection.headers)) {
452
+ httpHeaders.append(header, value);
453
+ }
454
+ }
455
+ let response = await fetch(connection.url + message,{
456
+ method: "POST",
457
+ headers: httpHeaders,
458
+ mode: "cors",
459
+ body: JSON.stringify(data)
460
+ });
461
+ code = response.status;
462
+ } catch (e) {
463
+ code = CONNECTION_STATUS.INTERNAL_SERVER_ERROR;
464
+ }
465
+ }
466
+ return code;
467
+ }
468
+ }
469
+ return connection;
470
+ }
471
+
339
472
  // Helper function to stringify a value
340
473
  const valueToString = function(value) {
341
474
  let valueString = "undefined";
@@ -365,6 +498,15 @@ const getLogger = function(logger) {
365
498
  };
366
499
  }
367
500
 
501
+ // Helper function to add slash to endpoint
502
+ const addSlash = function(value) {
503
+ let endpoint = value;
504
+ if (endpoint && !endpoint.endsWith("/")) {
505
+ endpoint = endpoint + "/";
506
+ }
507
+ return endpoint;
508
+ }
509
+
368
510
  module.exports = {
369
511
  StreamStatsCollector: StreamStatsCollector
370
512
  }