@reactoo/watchtogether-sdk-js 2.5.32 → 2.5.35

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.
@@ -143,10 +143,12 @@ class RoomSession {
143
143
  this.ws = null;
144
144
  this.isRestarting = false;
145
145
 
146
- //TODO: do it better
147
- // double click prevention
148
- this.connectingPromise = null;
149
- this.disconnectingPromise = null;
146
+ this.isConnecting = false;
147
+ this.isDisconnecting = false;
148
+ this.isConnected = false;
149
+ this.isPublished = false;
150
+ this.isReclaiming = false;
151
+ this.isStreaming = false;
150
152
 
151
153
  this._ipv6Support = false;
152
154
  this._retries = 0;
@@ -156,12 +158,9 @@ class RoomSession {
156
158
  this._observerIds = [];
157
159
  this._talkbackIds = [];
158
160
  this._instuctorId = null;
159
- this._hasJoined = false;
160
- this._isStreaming = false;
161
- this._isPublished = false;
162
161
  this._isDataChannelOpen = false;
163
- this._dataChannelTimeoutId = null;
164
- this._messageTimeoutId = null;
162
+ this._abortController = null;
163
+
165
164
  this.isAudioMuted = false;
166
165
  this.isVideoMuted = false;
167
166
  this.isVideoEnabled = false;
@@ -321,12 +320,25 @@ class RoomSession {
321
320
  transaction,
322
321
  token: this.token, ...((this.sessionId && {'session_id': this.sessionId}) || {})
323
322
  };
323
+
324
+ this._log(requestData);
325
+
324
326
  return new Promise((resolve, reject) => {
327
+ let messageTimeoutId = null;
328
+
329
+ let abortResponse = () => {
330
+ this._abortController.signal.removeEventListener('abort', abortResponse);
331
+ clearTimeout(messageTimeoutId);
332
+ this.ws.removeEventListener('message', parseResponse);
333
+ reject({type: 'warning', id: 17, message: 'connection cancelled'})
334
+ };
335
+
325
336
  let parseResponse = (event) => {
326
337
  let json = JSON.parse(event.data);
327
338
  let r_transaction = json['transaction'];
328
339
  if (r_transaction === transaction && (!dontResolveOnAck || json['janus'] !== 'ack')) {
329
- clearTimeout(this._messageTimeoutId);
340
+ clearTimeout(messageTimeoutId);
341
+ this._abortController.signal.removeEventListener('abort', abortResponse);
330
342
  this.ws.removeEventListener('message', parseResponse);
331
343
  if (json['janus'] === 'error') {
332
344
  if (json?.error?.code == 403) {
@@ -347,11 +359,16 @@ class RoomSession {
347
359
 
348
360
  } else {
349
361
  if (this.ws && this.ws.readyState === 1) {
362
+
350
363
  this.ws.addEventListener('message', parseResponse);
351
- this._messageTimeoutId = setTimeout(() => {
364
+
365
+ messageTimeoutId = setTimeout(() => {
352
366
  this.ws.removeEventListener('message', parseResponse);
367
+ this._abortController.signal.removeEventListener('abort', abortResponse);
353
368
  reject({type: 'error', id: 3, message: 'send timeout', data: requestData});
354
369
  }, 10000);
370
+
371
+ this._abortController.signal.addEventListener('abort', abortResponse);
355
372
  this.ws.send(JSON.stringify(requestData));
356
373
  } else {
357
374
  reject({type: 'warning', id: 29, message: 'No connection to WebSockets', data: requestData});
@@ -361,7 +378,8 @@ class RoomSession {
361
378
  }
362
379
 
363
380
  _connectionClosed() {
364
- if (this.disconnectingPromise || this.connectingPromise) {
381
+
382
+ if (!this.isConnected || this.isConnecting || this.isDisconnecting) {
365
383
  return;
366
384
  }
367
385
 
@@ -484,7 +502,7 @@ class RoomSession {
484
502
  if (event === "joined") {
485
503
  this.id = msg["id"];
486
504
  this.privateId = msg["private_id"];
487
- this._hasJoined = true;
505
+ this.isConnected = true;
488
506
  this.emit('joined', true);
489
507
  this._log('We have successfully joined Room');
490
508
  for (let f in list) {
@@ -593,7 +611,7 @@ class RoomSession {
593
611
  }
594
612
  if (result["status"] === 'started') {
595
613
  this.emit('streaming', true);
596
- this._isStreaming = true;
614
+ this.isStreaming = true;
597
615
  }
598
616
  }
599
617
 
@@ -775,7 +793,7 @@ class RoomSession {
775
793
 
776
794
  if (handleId === this.handleId) {
777
795
  this._isDataChannelOpen = false;
778
- this._isPublished = false;
796
+ this.isPublished = false;
779
797
  this.emit('published', {status: false, hasStream: false});
780
798
  this.emit('removeLocalParticipant', {id: handleId, userId: handle.userId});
781
799
  } else {
@@ -836,10 +854,10 @@ class RoomSession {
836
854
  }
837
855
 
838
856
  _leaveRoom(dontWait = false) {
839
- return this._hasJoined
857
+ return this.isConnected
840
858
  ? this.sendMessage(this.handleId, {body: {"request": "leave"}}, dontWait)
841
859
  .finally(() => {
842
- this._hasJoined = false;
860
+ this.isConnected = false;
843
861
  this.emit('joined', false);
844
862
  })
845
863
  : Promise.resolve();
@@ -849,8 +867,8 @@ class RoomSession {
849
867
 
850
868
  _reconnect() {
851
869
 
852
- if (this.connectingPromise) {
853
- return this.connectingPromise;
870
+ if (this.isReclaiming) {
871
+ return Promise.resolve();
854
872
  }
855
873
 
856
874
  if (this.ws) {
@@ -860,25 +878,39 @@ class RoomSession {
860
878
  }
861
879
  }
862
880
  this._stopKeepAlive();
863
- this.connectingPromise = new Promise((resolve, reject) => {
864
- this.emit('joining', true);
881
+ this.isReclaiming = true;
882
+ this.emit('joining', true);
883
+ return new Promise((resolve, reject) => {
884
+
885
+ let abortReconnect = () => {
886
+ this._abortController.signal.removeEventListener('abort', abortReconnect);
887
+ this.ws.removeEventListener('close', this.__connectionClosedBoundFn);
888
+ this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);
889
+ this.ws.onopen = null;
890
+ this.ws.onerror = null;
891
+ this.isReclaiming = false;
892
+ this.emit('joining', false);
893
+ reject({type: 'warning', id: 17, message: 'Connection cancelled', data: e});
894
+ };
895
+
865
896
  this.ws = new WebSocket(this.server, 'janus-protocol');
866
897
  this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
867
898
  this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);
868
899
  this.ws.addEventListener('close', this.__connectionClosedBoundFn);
869
900
  this.ws.addEventListener('message', this.__handleWsEventsBoundFn);
870
901
  this.ws.onopen = () => {
902
+ this._abortController.signal.removeEventListener('abort', abortReconnect);
871
903
  this._send({"janus": "claim"})
872
904
  .then(json => {
873
905
  this.sessionId = json["session_id"] ? json["session_id"] : json.data["id"];
874
906
  this._startKeepAlive();
875
- this.connectingPromise = null;
907
+ this.isReclaiming = false;
876
908
  this.emit('joining', false);
877
909
  this._retries = 0;
878
910
  resolve(json);
879
911
  })
880
912
  .catch(error => {
881
- this.connectingPromise = null;
913
+ this.isReclaiming = false;
882
914
  this.emit('joining', false);
883
915
  reject({type: 'error', id: 11, message: 'reconnection error', data: error})
884
916
  });
@@ -886,26 +918,27 @@ class RoomSession {
886
918
 
887
919
  // this is called before 'close' event callback so it doesn't break reconnect loop
888
920
  this.ws.onerror = (e) => {
889
- this.connectingPromise = null;
921
+ this._abortController.signal.removeEventListener('abort', abortReconnect);
922
+ this.isReclaiming = false;
890
923
  this.emit('joining', false);
891
924
  reject({type: 'warning', id: 12, message: 'ws reconnection error', data: e});
892
925
  }
926
+
927
+ this._abortController.signal.addEventListener('abort', abortReconnect);
893
928
  });
894
- return this.connectingPromise;
895
929
  }
896
930
 
897
931
  connect(roomId, pin, server, iceServers, token, display, userId, webrtcVersion = 0, initialBitrate = 0, isMonitor, recordingFilename) {
898
932
 
899
- if (this.connectingPromise) {
900
- return this.connectingPromise;
933
+ if (this.isConnecting) {
934
+ return Promise.reject({type: 'warning', id: 16, message: 'connection already in progress'});
901
935
  }
902
936
 
903
- this.emit('joined', false);
904
937
  if (this.ws) {
905
938
  this._wipeListeners();
906
939
  }
907
940
  this._stopKeepAlive();
908
- this.disconnectingPromise = null;
941
+ this._abortController = new AbortController();
909
942
  this.sessionId = null;
910
943
  this.server = server;
911
944
  this.iceServers = iceServers;
@@ -918,15 +951,29 @@ class RoomSession {
918
951
  this.initialBitrate = initialBitrate;
919
952
  this.isMonitor = isMonitor;
920
953
  this.recordingFilename = recordingFilename;
921
- this.disconnectingPromise = null;
922
- this.connectingPromise = new Promise((resolve, reject) => {
923
- this.emit('joining', true);
954
+ this.isConnecting = true;
955
+ this.emit('joining', true);
956
+ return new Promise((resolve, reject) => {
957
+
924
958
  this.ws = new WebSocket(this.server, 'janus-protocol');
925
959
  this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
926
960
  this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);
961
+
962
+ let abortConnect = () => {
963
+ this._abortController.signal.removeEventListener('abort', abortConnect);
964
+ this.ws.removeEventListener('close', this.__connectionClosedBoundFn);
965
+ this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);
966
+ this.ws.onopen = null;
967
+ this.ws.onerror = null;
968
+ this.isConnecting = false;
969
+ this.emit('joining', false);
970
+ reject({type: 'warning', id: 17, message: 'Connection cancelled'});
971
+ };
972
+
927
973
  this.ws.addEventListener('close', this.__connectionClosedBoundFn);
928
974
  this.ws.addEventListener('message', this.__handleWsEventsBoundFn);
929
975
  this.ws.onopen = () => {
976
+ this._abortController.signal.removeEventListener('abort', abortConnect);
930
977
  this._retries = 0;
931
978
  this._send({"janus": "create"})
932
979
  .then(json => {
@@ -941,36 +988,41 @@ class RoomSession {
941
988
  })
942
989
  .then(() => this._joinRoom(roomId, pin, userId, display))
943
990
  .then(() => {
944
- this.connectingPromise = null;
991
+ this.isConnecting = false;
945
992
  this.emit('joining', false);
946
993
  resolve(this);
947
994
  })
948
995
  .catch(error => {
949
- this.connectingPromise = null;
996
+ this.isConnecting = false;
950
997
  this.emit('joining', false);
951
- reject({type: 'error', id: 13, message: 'connection error', data: error})
998
+ reject({type: error?.type === 'warning' ? 'warning' : 'error', id: 13, message: 'connection error', data: error})
952
999
  });
953
1000
  };
1001
+
954
1002
  this.ws.onerror = (e) => {
955
- this.connectingPromise = null;
1003
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1004
+ this.isConnecting = false;
956
1005
  this.emit('joining', false);
957
1006
  reject({type: 'error', id: 14, message: 'ws connection error', data: e});
958
1007
  }
1008
+
1009
+ this._abortController.signal.addEventListener('abort', abortConnect);
1010
+
959
1011
  });
960
- return this.connectingPromise;
961
1012
  }
962
1013
 
963
1014
  disconnect() {
964
- if (this.disconnectingPromise) {
965
- return this.disconnectingPromise;
1015
+
1016
+ if (this.isDisconnecting) {
1017
+ return Promise.resolve();
966
1018
  }
967
1019
 
968
- let _hasJoined = this._hasJoined;
969
-
970
- clearTimeout(this._messageTimeoutId);
971
- clearTimeout(this._dataChannelTimeoutId);
1020
+ this._abortController?.abort?.();
972
1021
  this._stopKeepAlive();
973
- this.disconnectingPromise = Promise.all(this._participants.map(p => this._removeParticipant(p.handleId)))
1022
+
1023
+ let isConnected = this.isConnected;
1024
+ this.isDisconnecting = true;
1025
+ return Promise.all(this._participants.map(p => this._removeParticipant(p.handleId)))
974
1026
  .finally(() => {
975
1027
  this._wipeListeners();
976
1028
  if (this.ws && this.ws.readyState === 1) {
@@ -978,46 +1030,59 @@ class RoomSession {
978
1030
  this.ws.close();
979
1031
  }
980
1032
  this.sessionId = null;
981
- //TODO: Just in case something crashed along the way
982
- this._isPublished = false;
983
- this._hasJoined = false;
1033
+ this.isPublished = false;
1034
+ this.isConnected = false;
1035
+ this.isDisconnecting = false;
984
1036
  this.emit('publishing', false);
985
1037
  this.emit('published', {status: false, hasStream: false});
986
1038
  this.emit('joining', false);
987
1039
  this.emit('joined', false);
988
- this.emit('disconnect', _hasJoined);
1040
+ this.emit('disconnect', isConnected);
989
1041
  return Promise.resolve('Disconnected');
990
1042
  })
991
- return this.disconnectingPromise;
992
1043
  }
993
1044
 
994
1045
  startStream(streamId, server, iceServers, token, userId) {
995
1046
 
996
- if (this.connectingPromise) {
997
- return this.connectingPromise
1047
+ if (this.isConnecting) {
1048
+ return Promise.reject({type: 'warning', id: 16, message: 'connection error', data: 'Connection is in progress'});
998
1049
  }
999
1050
 
1000
- this.emit('streaming', false);
1001
1051
  if (this.ws) {
1002
1052
  this._wipeListeners();
1003
1053
  }
1054
+
1004
1055
  this._stopKeepAlive();
1005
- this.disconnectingPromise = null;
1006
- this.sessionId = null;
1056
+ this._abortController = new AbortController();
1007
1057
  this.server = server;
1008
1058
  this.iceServers = iceServers;
1009
1059
  this.token = token;
1010
1060
  this.streamId = streamId;
1011
1061
  this.userId = userId;
1062
+ this.sessionId = null;
1063
+ this.isConnecting = true;
1064
+ this.emit('streamStarting', true);
1065
+ return new Promise((resolve, reject) => {
1012
1066
 
1013
- this.connectingPromise = new Promise((resolve, reject) => {
1014
- this.emit('streamStarting', true);
1015
1067
  this.ws = new WebSocket(this.server, 'janus-protocol');
1016
1068
  this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
1017
1069
  this.__handleWsEventsBoundFn = this._handleWsEvents.bind(this);
1070
+
1071
+ let abortConnect = () => {
1072
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1073
+ this.ws.removeEventListener('close', this.__connectionClosedBoundFn);
1074
+ this.ws.removeEventListener('message', this.__handleWsEventsBoundFn);
1075
+ this.ws.onopen = null;
1076
+ this.ws.onerror = null;
1077
+ this.isConnecting = false;
1078
+ this.emit('streamStarting', false);
1079
+ reject({type: 'warning', id: 17, message: 'Connection cancelled'});
1080
+ };
1081
+
1018
1082
  this.ws.addEventListener('close', this.__connectionClosedBoundFn);
1019
1083
  this.ws.addEventListener('message', this.__handleWsEventsBoundFn);
1020
1084
  this.ws.onopen = () => {
1085
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1021
1086
  this._retries = 0;
1022
1087
  this._send({"janus": "create"})
1023
1088
  .then(json => {
@@ -1032,38 +1097,39 @@ class RoomSession {
1032
1097
  })
1033
1098
  .then(() => this._watchStream(streamId))
1034
1099
  .then(() => {
1035
- this.connectingPromise = null;
1100
+ this.isConnecting = false;
1036
1101
  this.emit('streamStarting', false);
1037
1102
  resolve(this);
1038
1103
  })
1039
1104
  .catch(error => {
1040
- this.connectingPromise = null;
1105
+ this.isConnecting = false;
1041
1106
  this.emit('streamStarting', false);
1042
1107
  reject({type: 'error', id: 13, message: 'connection error', data: error})
1043
1108
  });
1044
1109
  };
1045
1110
  this.ws.onerror = (e) => {
1046
- this.connectingPromise = null;
1111
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1112
+ this.isConnecting = false;
1047
1113
  this.emit('streamStarting', false);
1048
1114
  reject({type: 'error', id: 14, message: 'ws connection error', data: e});
1049
1115
  }
1116
+
1117
+ this._abortController.signal.addEventListener('abort', abortConnect);
1050
1118
  });
1051
- return this.connectingPromise;
1052
1119
  }
1053
1120
 
1054
1121
  stopStream() {
1055
- if (this.disconnectingPromise) {
1056
- return this.disconnectingPromise;
1057
- }
1058
1122
 
1059
- let _isStreaming = this._isStreaming;
1123
+ if (this.isDisconnecting) {
1124
+ return Promise.resolve();
1125
+ }
1060
1126
 
1127
+ this._abortController?.abort?.();
1061
1128
  this._stopKeepAlive();
1062
- this.disconnectingPromise = this.sendMessage(this.handleId, {
1063
- body: {
1064
- "request": "stop"
1065
- }
1066
- }, false, true)
1129
+
1130
+ let isStreaming = this.isStreaming;
1131
+ this.isDisconnecting = true;
1132
+ return this.sendMessage(this.handleId, {body: {"request": "stop"}}, false, true)
1067
1133
  .then(() => this._removeParticipant(this.handleId))
1068
1134
  .finally(() => {
1069
1135
  this._wipeListeners();
@@ -1072,15 +1138,13 @@ class RoomSession {
1072
1138
  this.ws.close();
1073
1139
  }
1074
1140
  this.sessionId = null;
1075
- this._isStreaming = false;
1141
+ this.isDisconnecting = false;
1142
+ this.isStreaming = false;
1076
1143
  this.emit('streamStarting', false);
1077
1144
  this.emit('streaming', false);
1078
- this.emit('disconnect', _isStreaming);
1079
- this.disconnectingPromise = null;
1145
+ this.emit('disconnect', isStreaming);
1080
1146
  return Promise.resolve('Disconnected');
1081
1147
  });
1082
-
1083
- return this.disconnectingPromise;
1084
1148
  }
1085
1149
 
1086
1150
  destroy() {
@@ -1710,6 +1774,14 @@ class RoomSession {
1710
1774
 
1711
1775
  publishLocal(stream, {keepAudio = false, keepVideo = false} = {}) {
1712
1776
 
1777
+ if(this.isDisconnecting || !this.isConnected) {
1778
+ return Promise.reject({
1779
+ type: 'warning',
1780
+ id: 18,
1781
+ message: 'Either not connected or disconnecting',
1782
+ })
1783
+ }
1784
+
1713
1785
  this.emit('publishing', true);
1714
1786
 
1715
1787
  let handle = this._getHandle(this.handleId);
@@ -1874,23 +1946,40 @@ class RoomSession {
1874
1946
  return Promise.resolve(r)
1875
1947
  } else {
1876
1948
  return new Promise((resolve, reject) => {
1877
- let __ = (val) => {
1949
+
1950
+ let dataChannelTimeoutId = null;
1951
+
1952
+ let _resolve = (val) => {
1878
1953
  if (val) {
1879
- clearTimeout(this._dataChannelTimeoutId);
1880
- this.off('dataChannel', __, this);
1954
+ clearTimeout(dataChannelTimeoutId);
1955
+ this._abortController.signal.removeEventListener('abort', _rejectAbort);
1956
+ this.off('dataChannel', _resolve, this);
1881
1957
  resolve(this);
1882
1958
  }
1883
1959
  };
1884
- this._dataChannelTimeoutId = setTimeout(() => {
1885
- this.off('dataChannel', __, this);
1960
+
1961
+ let _rejectTimeout = () => {
1962
+ this.off('dataChannel', _resolve, this);
1963
+ this._abortController.signal.removeEventListener('abort', _rejectAbort);
1886
1964
  reject({type: 'error', id: 27, message: 'Data channel did not open', data: null});
1887
- }, 5000);
1888
- this.on('dataChannel', __, this);
1965
+ }
1966
+
1967
+ let _rejectAbort = () => {
1968
+ this._abortController.signal.removeEventListener('abort', _rejectAbort);
1969
+ clearTimeout(dataChannelTimeoutId);
1970
+ this.off('dataChannel', _resolve, this);
1971
+ reject({type: 'warning', id: 17, message: 'Connection cancelled'})
1972
+ }
1973
+
1974
+ dataChannelTimeoutId = setTimeout(_rejectTimeout, 5000);
1975
+ this._abortController.signal.addEventListener('abort', _rejectAbort);
1976
+
1977
+ this.on('dataChannel', _resolve, this);
1889
1978
  });
1890
1979
  }
1891
1980
  })
1892
1981
  .then(r => {
1893
- this._isPublished = true;
1982
+ this.isPublished = true;
1894
1983
  if(config.stream) {
1895
1984
  let tracks = config.stream.getTracks();
1896
1985
  tracks.forEach(track => {
@@ -1954,10 +2043,10 @@ class RoomSession {
1954
2043
  }
1955
2044
 
1956
2045
  unpublishLocal(dontWait = false) {
1957
- return this._isPublished
2046
+ return this.isPublished
1958
2047
  ? this.sendMessage(this.handleId, {body: {"request": "unpublish"}}, dontWait)
1959
2048
  .finally(r => {
1960
- this._isPublished = false;
2049
+ this.isPublished = false;
1961
2050
  this.emit('published', {status: false, hasStream: false});
1962
2051
  return r
1963
2052
  })