@reactoo/watchtogether-sdk-js 2.5.30 → 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,33 +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
- clearTimeout(this._messageTimeoutId);
968
- clearTimeout(this._dataChannelTimeoutId);
1019
+
1020
+ this._abortController?.abort?.();
969
1021
  this._stopKeepAlive();
970
- 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)))
971
1026
  .finally(() => {
972
1027
  this._wipeListeners();
973
1028
  if (this.ws && this.ws.readyState === 1) {
@@ -975,44 +1030,59 @@ class RoomSession {
975
1030
  this.ws.close();
976
1031
  }
977
1032
  this.sessionId = null;
978
- //TODO: Just in case something crashed along the way
979
- this._isPublished = false;
980
- this._hasJoined = false;
1033
+ this.isPublished = false;
1034
+ this.isConnected = false;
1035
+ this.isDisconnecting = false;
1036
+ this.emit('publishing', false);
981
1037
  this.emit('published', {status: false, hasStream: false});
1038
+ this.emit('joining', false);
982
1039
  this.emit('joined', false);
983
- this.emit('disconnect');
1040
+ this.emit('disconnect', isConnected);
984
1041
  return Promise.resolve('Disconnected');
985
1042
  })
986
- return this.disconnectingPromise;
987
1043
  }
988
1044
 
989
1045
  startStream(streamId, server, iceServers, token, userId) {
990
1046
 
991
- if (this.connectingPromise) {
992
- return this.connectingPromise
1047
+ if (this.isConnecting) {
1048
+ return Promise.reject({type: 'warning', id: 16, message: 'connection error', data: 'Connection is in progress'});
993
1049
  }
994
1050
 
995
- this.emit('streaming', false);
996
1051
  if (this.ws) {
997
1052
  this._wipeListeners();
998
1053
  }
1054
+
999
1055
  this._stopKeepAlive();
1000
- this.disconnectingPromise = null;
1001
- this.sessionId = null;
1056
+ this._abortController = new AbortController();
1002
1057
  this.server = server;
1003
1058
  this.iceServers = iceServers;
1004
1059
  this.token = token;
1005
1060
  this.streamId = streamId;
1006
1061
  this.userId = userId;
1062
+ this.sessionId = null;
1063
+ this.isConnecting = true;
1064
+ this.emit('streamStarting', true);
1065
+ return new Promise((resolve, reject) => {
1007
1066
 
1008
- this.connectingPromise = new Promise((resolve, reject) => {
1009
- this.emit('streamStarting', true);
1010
1067
  this.ws = new WebSocket(this.server, 'janus-protocol');
1011
1068
  this.__connectionClosedBoundFn = this._connectionClosed.bind(this);
1012
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
+
1013
1082
  this.ws.addEventListener('close', this.__connectionClosedBoundFn);
1014
1083
  this.ws.addEventListener('message', this.__handleWsEventsBoundFn);
1015
1084
  this.ws.onopen = () => {
1085
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1016
1086
  this._retries = 0;
1017
1087
  this._send({"janus": "create"})
1018
1088
  .then(json => {
@@ -1027,35 +1097,39 @@ class RoomSession {
1027
1097
  })
1028
1098
  .then(() => this._watchStream(streamId))
1029
1099
  .then(() => {
1030
- this.connectingPromise = null;
1100
+ this.isConnecting = false;
1031
1101
  this.emit('streamStarting', false);
1032
1102
  resolve(this);
1033
1103
  })
1034
1104
  .catch(error => {
1035
- this.connectingPromise = null;
1105
+ this.isConnecting = false;
1036
1106
  this.emit('streamStarting', false);
1037
1107
  reject({type: 'error', id: 13, message: 'connection error', data: error})
1038
1108
  });
1039
1109
  };
1040
1110
  this.ws.onerror = (e) => {
1041
- this.connectingPromise = null;
1111
+ this._abortController.signal.removeEventListener('abort', abortConnect);
1112
+ this.isConnecting = false;
1042
1113
  this.emit('streamStarting', false);
1043
1114
  reject({type: 'error', id: 14, message: 'ws connection error', data: e});
1044
1115
  }
1116
+
1117
+ this._abortController.signal.addEventListener('abort', abortConnect);
1045
1118
  });
1046
- return this.connectingPromise;
1047
1119
  }
1048
1120
 
1049
1121
  stopStream() {
1050
- if (this.disconnectingPromise) {
1051
- return this.disconnectingPromise;
1122
+
1123
+ if (this.isDisconnecting) {
1124
+ return Promise.resolve();
1052
1125
  }
1126
+
1127
+ this._abortController?.abort?.();
1053
1128
  this._stopKeepAlive();
1054
- this.disconnectingPromise = this.sendMessage(this.handleId, {
1055
- body: {
1056
- "request": "stop"
1057
- }
1058
- }, false, true)
1129
+
1130
+ let isStreaming = this.isStreaming;
1131
+ this.isDisconnecting = true;
1132
+ return this.sendMessage(this.handleId, {body: {"request": "stop"}}, false, true)
1059
1133
  .then(() => this._removeParticipant(this.handleId))
1060
1134
  .finally(() => {
1061
1135
  this._wipeListeners();
@@ -1064,15 +1138,13 @@ class RoomSession {
1064
1138
  this.ws.close();
1065
1139
  }
1066
1140
  this.sessionId = null;
1067
- this._isStreaming = false;
1141
+ this.isDisconnecting = false;
1142
+ this.isStreaming = false;
1143
+ this.emit('streamStarting', false);
1068
1144
  this.emit('streaming', false);
1069
- // last event
1070
- this.emit('disconnect');
1071
- this.disconnectingPromise = null;
1145
+ this.emit('disconnect', isStreaming);
1072
1146
  return Promise.resolve('Disconnected');
1073
1147
  });
1074
-
1075
- return this.disconnectingPromise;
1076
1148
  }
1077
1149
 
1078
1150
  destroy() {
@@ -1702,6 +1774,14 @@ class RoomSession {
1702
1774
 
1703
1775
  publishLocal(stream, {keepAudio = false, keepVideo = false} = {}) {
1704
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
+
1705
1785
  this.emit('publishing', true);
1706
1786
 
1707
1787
  let handle = this._getHandle(this.handleId);
@@ -1866,23 +1946,40 @@ class RoomSession {
1866
1946
  return Promise.resolve(r)
1867
1947
  } else {
1868
1948
  return new Promise((resolve, reject) => {
1869
- let __ = (val) => {
1949
+
1950
+ let dataChannelTimeoutId = null;
1951
+
1952
+ let _resolve = (val) => {
1870
1953
  if (val) {
1871
- clearTimeout(this._dataChannelTimeoutId);
1872
- this.off('dataChannel', __, this);
1954
+ clearTimeout(dataChannelTimeoutId);
1955
+ this._abortController.signal.removeEventListener('abort', _rejectAbort);
1956
+ this.off('dataChannel', _resolve, this);
1873
1957
  resolve(this);
1874
1958
  }
1875
1959
  };
1876
- this._dataChannelTimeoutId = setTimeout(() => {
1877
- this.off('dataChannel', __, this);
1960
+
1961
+ let _rejectTimeout = () => {
1962
+ this.off('dataChannel', _resolve, this);
1963
+ this._abortController.signal.removeEventListener('abort', _rejectAbort);
1878
1964
  reject({type: 'error', id: 27, message: 'Data channel did not open', data: null});
1879
- }, 5000);
1880
- 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);
1881
1978
  });
1882
1979
  }
1883
1980
  })
1884
1981
  .then(r => {
1885
- this._isPublished = true;
1982
+ this.isPublished = true;
1886
1983
  if(config.stream) {
1887
1984
  let tracks = config.stream.getTracks();
1888
1985
  tracks.forEach(track => {
@@ -1946,10 +2043,10 @@ class RoomSession {
1946
2043
  }
1947
2044
 
1948
2045
  unpublishLocal(dontWait = false) {
1949
- return this._isPublished
2046
+ return this.isPublished
1950
2047
  ? this.sendMessage(this.handleId, {body: {"request": "unpublish"}}, dontWait)
1951
2048
  .finally(r => {
1952
- this._isPublished = false;
2049
+ this.isPublished = false;
1953
2050
  this.emit('published', {status: false, hasStream: false});
1954
2051
  return r
1955
2052
  })