@wazo/sdk 0.37.20 → 0.37.24

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.
Files changed (147) hide show
  1. package/dist/wazo-sdk.js +6 -6
  2. package/esm/__tests__/api-client.test.js +91 -21
  3. package/esm/__tests__/web-rtc-client.test.js +214 -165
  4. package/esm/api/agentd.js +25 -2
  5. package/esm/api/amid.js +26 -3
  6. package/esm/api/application.js +25 -2
  7. package/esm/api/auth.js +25 -2
  8. package/esm/api/call-logd.js +34 -4
  9. package/esm/api/calld.js +35 -2
  10. package/esm/api/chatd.js +32 -2
  11. package/esm/api/confd.js +56 -9
  12. package/esm/api/ctid-ng.js +38 -5
  13. package/esm/api/dird.js +29 -3
  14. package/esm/api/webhookd.js +26 -3
  15. package/esm/api-client.js +91 -21
  16. package/esm/checker/Checker.js +241 -190
  17. package/esm/checker/checks/aor.js +91 -21
  18. package/esm/checker/checks/api.js +91 -21
  19. package/esm/checker/checks/index.js +231 -180
  20. package/esm/checker/checks/wazo-websocket.js +42 -17
  21. package/esm/checker/checks/webrtc-transport.js +214 -165
  22. package/esm/checker/checks/webrtc.js +214 -165
  23. package/esm/domain/AdHocAPIConference.js +91 -21
  24. package/esm/domain/Call.js +3 -0
  25. package/esm/domain/CallLog.js +8 -1
  26. package/esm/domain/ChatMessage.js +4 -0
  27. package/esm/domain/ChatRoom.js +3 -0
  28. package/esm/domain/Contact.js +4 -1
  29. package/esm/domain/Features.js +91 -21
  30. package/esm/domain/Meeting.js +28 -5
  31. package/esm/domain/Phone/CTIPhone.js +109 -35
  32. package/esm/domain/Phone/WebRTCPhone.js +159 -102
  33. package/esm/domain/Recording.js +3 -0
  34. package/esm/domain/Voicemail.js +3 -0
  35. package/esm/domain/__tests__/Call.test.js +3 -0
  36. package/esm/domain/__tests__/CallLog.test.js +8 -1
  37. package/esm/domain/__tests__/Contact.test.js +4 -1
  38. package/esm/domain/__tests__/Meeting.test.js +144 -0
  39. package/esm/domain/__tests__/Voicemail.test.js +3 -0
  40. package/esm/index.js +509 -414
  41. package/esm/lib/WazoSessionDescriptionHandler.js +26 -41
  42. package/esm/service/CallApi.js +91 -21
  43. package/esm/service/IssueReporter.js +26 -3
  44. package/esm/service/__tests__/IssueReporter.test.js +26 -3
  45. package/esm/service/getApiClient.js +91 -21
  46. package/esm/simple/Auth.js +499 -404
  47. package/esm/simple/Configuration.js +499 -404
  48. package/esm/simple/Directory.js +91 -21
  49. package/esm/simple/Phone.js +499 -404
  50. package/esm/simple/Websocket.js +45 -19
  51. package/esm/simple/index.js +503 -408
  52. package/esm/simple/room/LocalParticipant.js +503 -408
  53. package/esm/simple/room/Participant.js +503 -408
  54. package/esm/simple/room/RemoteParticipant.js +503 -408
  55. package/esm/simple/room/Room.js +504 -409
  56. package/esm/simple/room/SipRoom.js +503 -408
  57. package/esm/simple/room/Stream.js +503 -408
  58. package/esm/simple/room/__tests__/RemoteParticipant.test.js +503 -408
  59. package/esm/simple/utils.js +503 -408
  60. package/esm/types/WebSocketMessage.js +1 -1
  61. package/esm/utils/__tests__/api-requester.test.js +25 -2
  62. package/esm/utils/api-requester.js +25 -2
  63. package/esm/web-rtc-client.js +214 -165
  64. package/esm/websocket-client.js +43 -18
  65. package/lib/__tests__/api-client.test.js +91 -21
  66. package/lib/__tests__/web-rtc-client.test.js +214 -165
  67. package/lib/api/agentd.js +25 -2
  68. package/lib/api/amid.js +26 -3
  69. package/lib/api/application.js +25 -2
  70. package/lib/api/auth.js +25 -2
  71. package/lib/api/call-logd.js +34 -4
  72. package/lib/api/calld.js +35 -2
  73. package/lib/api/chatd.js +32 -2
  74. package/lib/api/confd.js +56 -9
  75. package/lib/api/ctid-ng.js +38 -5
  76. package/lib/api/dird.js +29 -3
  77. package/lib/api/webhookd.js +26 -3
  78. package/lib/api-client.js +91 -21
  79. package/lib/checker/Checker.js +241 -190
  80. package/lib/checker/checks/aor.js +91 -21
  81. package/lib/checker/checks/api.js +91 -21
  82. package/lib/checker/checks/index.js +231 -180
  83. package/lib/checker/checks/wazo-websocket.js +42 -17
  84. package/lib/checker/checks/webrtc-transport.js +214 -165
  85. package/lib/checker/checks/webrtc.js +214 -165
  86. package/lib/domain/AdHocAPIConference.js +91 -21
  87. package/lib/domain/Call.js +3 -0
  88. package/lib/domain/CallLog.js +8 -1
  89. package/lib/domain/ChatMessage.js +4 -0
  90. package/lib/domain/ChatRoom.js +3 -0
  91. package/lib/domain/Contact.js +4 -1
  92. package/lib/domain/Features.js +91 -21
  93. package/lib/domain/Meeting.js +32 -5
  94. package/lib/domain/Phone/CTIPhone.js +109 -35
  95. package/lib/domain/Phone/WebRTCPhone.js +159 -102
  96. package/lib/domain/Recording.js +3 -0
  97. package/lib/domain/Voicemail.js +3 -0
  98. package/lib/domain/__tests__/Call.test.js +3 -0
  99. package/lib/domain/__tests__/CallLog.test.js +8 -1
  100. package/lib/domain/__tests__/Contact.test.js +4 -1
  101. package/lib/domain/__tests__/Meeting.test.js +150 -0
  102. package/lib/domain/__tests__/Voicemail.test.js +3 -0
  103. package/lib/index.js +509 -414
  104. package/lib/lib/WazoSessionDescriptionHandler.js +26 -41
  105. package/lib/service/CallApi.js +91 -21
  106. package/lib/service/IssueReporter.js +26 -3
  107. package/lib/service/__tests__/IssueReporter.test.js +26 -3
  108. package/lib/service/getApiClient.js +91 -21
  109. package/lib/simple/Auth.js +499 -404
  110. package/lib/simple/Configuration.js +499 -404
  111. package/lib/simple/Directory.js +91 -21
  112. package/lib/simple/Phone.js +499 -404
  113. package/lib/simple/Websocket.js +45 -19
  114. package/lib/simple/index.js +503 -408
  115. package/lib/simple/room/LocalParticipant.js +503 -408
  116. package/lib/simple/room/Participant.js +503 -408
  117. package/lib/simple/room/RemoteParticipant.js +503 -408
  118. package/lib/simple/room/Room.js +504 -409
  119. package/lib/simple/room/SipRoom.js +503 -408
  120. package/lib/simple/room/Stream.js +503 -408
  121. package/lib/simple/room/__tests__/RemoteParticipant.test.js +503 -408
  122. package/lib/simple/utils.js +503 -408
  123. package/lib/types/WebSocketMessage.js +2 -0
  124. package/lib/utils/__tests__/api-requester.test.js +25 -2
  125. package/lib/utils/api-requester.js +25 -2
  126. package/lib/web-rtc-client.js +214 -165
  127. package/lib/websocket-client.js +43 -17
  128. package/package.json +1 -1
  129. package/src/api/confd.js +5 -2
  130. package/src/domain/Call.js +3 -0
  131. package/src/domain/CallLog.js +4 -0
  132. package/src/domain/ChatMessage.js +4 -0
  133. package/src/domain/ChatRoom.js +3 -0
  134. package/src/domain/Contact.js +3 -0
  135. package/src/domain/Meeting.js +28 -5
  136. package/src/domain/Phone/CTIPhone.js +4 -0
  137. package/src/domain/Phone/Phone.js +2 -0
  138. package/src/domain/Phone/WebRTCPhone.js +49 -15
  139. package/src/domain/Recording.js +3 -0
  140. package/src/domain/Voicemail.js +3 -0
  141. package/src/domain/__tests__/Meeting.test.js +50 -0
  142. package/src/lib/WazoSessionDescriptionHandler.js +1 -35
  143. package/src/service/IssueReporter.js +25 -2
  144. package/src/simple/Phone.js +5 -0
  145. package/src/types/WebSocketMessage.js +5 -1
  146. package/src/web-rtc-client.js +41 -24
  147. package/src/websocket-client.js +2 -0
@@ -45,7 +45,7 @@ const isMobile = () => typeof navigator !== 'undefined' && navigator.product ===
45
45
 
46
46
  /* */
47
47
 
48
- IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
48
+ const logger = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
49
49
 
50
50
  // Use a function here to be able to mock it in tests
51
51
  const realFetch = () => {
@@ -131,6 +131,7 @@ class IssueReporter {
131
131
 
132
132
 
133
133
 
134
+
134
135
 
135
136
  constructor() {
136
137
  addLevelsTo(this);
@@ -142,12 +143,17 @@ class IssueReporter {
142
143
  this.bufferTimeout = null;
143
144
  this._boundProcessBuffer = this._processBuffer.bind(this);
144
145
  this._boundParseLoggerBody = this._parseLoggerBody.bind(this);
146
+ this._callback = null;
145
147
  }
146
148
 
147
149
  init() {
148
150
  this._catchConsole();
149
151
  }
150
152
 
153
+ setCallback(cb ) {
154
+ this._callback = cb;
155
+ }
156
+
151
157
  configureRemoteClient(configuration = { tag: 'wazo-sdk', host: null, port: null, level: null, extra: {} }) {
152
158
  this.remoteClientConfiguration = configuration;
153
159
  }
@@ -183,6 +189,7 @@ class IssueReporter {
183
189
 
184
190
  // Handle category label
185
191
  let category = null;
192
+ let skipSendToRemote = false;
186
193
  let extra = {};
187
194
  if (args[0].indexOf(CATEGORY_PREFIX) === 0) {
188
195
  category = args[0].split('=')[1];
@@ -198,6 +205,7 @@ class IssueReporter {
198
205
  errorMessage: lastArg.message,
199
206
  errorStack: lastArg.stack,
200
207
  errorType: lastArg.constructor.name,
208
+ skipSendToRemote: lastArg.skipSendToRemote,
201
209
  };
202
210
  } else {
203
211
  extra = lastArg;
@@ -206,6 +214,11 @@ class IssueReporter {
206
214
  args.splice(1, 1);
207
215
  }
208
216
 
217
+ if (extra.skipSendToRemote) {
218
+ skipSendToRemote = true;
219
+ delete extra.skipSendToRemote;
220
+ }
221
+
209
222
  const date = moment__default['default']().format('YYYY-MM-DD HH:mm:ss.SSS');
210
223
  const message = args.join(', ');
211
224
  let consoleMessage = message;
@@ -226,7 +239,13 @@ class IssueReporter {
226
239
  const oldMethod = this.oldConsoleMethods[consoleLevel] || this.oldConsoleMethods.log;
227
240
  oldMethod.apply(oldMethod, [date, consoleMessage]);
228
241
 
229
- this._sendToRemoteLogger(level, { date, message, category, ...extra });
242
+ if (this._callback) {
243
+ this._callback(level, consoleMessage);
244
+ }
245
+
246
+ if (!skipSendToRemote) {
247
+ this._sendToRemoteLogger(level, { date, message, category, ...extra });
248
+ }
230
249
  }
231
250
 
232
251
  logRequest(url , options , response , start ) {
@@ -371,7 +390,11 @@ class IssueReporter {
371
390
  },
372
391
  // $FlowFixMe
373
392
  body,
374
- }).catch(() => {
393
+ }).catch((e ) => {
394
+ // $FlowFixMe
395
+ e.skipSendToRemote = true;
396
+ this.log('error', this._makeCategory('grafana'), 'Sending log to grafana, error', e);
397
+
375
398
  setTimeout(() => {
376
399
  if (isArray) {
377
400
  payload = payload.map(message => {
@@ -588,6 +611,7 @@ const AGENT_PAUSED = 'agent_paused';
588
611
  const AGENT_UNPAUSED = 'agent_unpaused';
589
612
  const CONFERENCE_ADHOC_PARTICIPANT_LEFT = 'conference_adhoc_participant_left';
590
613
  const CONFERENCE_ADHOC_DELETED = 'conference_adhoc_deleted';
614
+ const MEETING_USER_PROGRESS = 'meeting_user_progress';
591
615
 
592
616
  const BLACKLIST_EVENTS = [
593
617
  CHAT_MESSAGE_SENT,
@@ -597,7 +621,7 @@ const BLACKLIST_EVENTS = [
597
621
  ];
598
622
 
599
623
  const HEARTBEAT_ENGINE_VERSION = '20.09';
600
- const logger = IssueReporter$1.loggerFor('wazo-ws');
624
+ const logger$1 = IssueReporter$1.loggerFor('wazo-ws');
601
625
  const messageLogger = IssueReporter$1.loggerFor('wazo-ws-message');
602
626
 
603
627
  class WebSocketClient extends Emitter {
@@ -646,19 +670,19 @@ class WebSocketClient extends Emitter {
646
670
  }
647
671
 
648
672
  connect() {
649
- logger.info('connect method started', { host: this.host, token: this.token });
673
+ logger$1.info('connect method started', { host: this.host, token: this.token });
650
674
  this.socket = new ReconnectingWebSocket__default['default'](this._getUrl.bind(this), [], this.options);
651
675
  if (this.options.binaryType) {
652
676
  this.socket.binaryType = this.options.binaryType;
653
677
  }
654
678
 
655
679
  this.socket.onopen = () => {
656
- logger.info('on Wazo WS open', { method: 'connect', host: this.host });
680
+ logger$1.info('on Wazo WS open', { method: 'connect', host: this.host });
657
681
  this.eventEmitter.emit(SOCKET_EVENTS.ON_OPEN);
658
682
  };
659
683
 
660
684
  this.socket.onerror = event => {
661
- logger.error('on Wazo WS error', event.target);
685
+ logger$1.error('on Wazo WS error', event.target);
662
686
  this.eventEmitter.emit(SOCKET_EVENTS.ON_ERROR, event);
663
687
  };
664
688
 
@@ -688,7 +712,7 @@ class WebSocketClient extends Emitter {
688
712
 
689
713
  this.socket.onclose = event => {
690
714
  // Can't be converted to JSON (circular structure)
691
- logger.info('on Wazo WS close', {
715
+ logger$1.info('on Wazo WS close', {
692
716
  reason: event.reason,
693
717
  code: event.code,
694
718
  readyState: event.target.readyState,
@@ -706,12 +730,12 @@ class WebSocketClient extends Emitter {
706
730
  };
707
731
 
708
732
  this.socket.onerror = event => {
709
- logger.info('Wazo WS error', { message: event.message, code: event.code, readyState: event.target.readyState });
733
+ logger$1.info('Wazo WS error', { message: event.message, code: event.code, readyState: event.target.readyState });
710
734
  };
711
735
  }
712
736
 
713
737
  close(force = false) {
714
- logger.info('Wazo WS close', { socket: !!this.socket, host: this.host, token: this.token });
738
+ logger$1.info('Wazo WS close', { socket: !!this.socket, host: this.host, token: this.token });
715
739
 
716
740
  if (!this.socket) {
717
741
  return;
@@ -729,7 +753,7 @@ class WebSocketClient extends Emitter {
729
753
 
730
754
  updateToken(token ) {
731
755
  this.token = token;
732
- logger.info('Wazo WS updating token', { url: this._getUrl(), token, socket: !!this.socket });
756
+ logger$1.info('Wazo WS updating token', { url: this._getUrl(), token, socket: !!this.socket });
733
757
 
734
758
  if (this.socket) {
735
759
  // If still connected, send the token to the WS
@@ -747,7 +771,7 @@ class WebSocketClient extends Emitter {
747
771
  }
748
772
 
749
773
  startHeartbeat() {
750
- logger.info('Wazo WS start heartbeat', { host: this.host, token: this.token });
774
+ logger$1.info('Wazo WS start heartbeat', { host: this.host, token: this.token });
751
775
 
752
776
  if (!this.socket) {
753
777
  this.heartbeat.stop();
@@ -761,7 +785,7 @@ class WebSocketClient extends Emitter {
761
785
  }
762
786
 
763
787
  stopHeartbeat() {
764
- logger.info('Wazo WS stop heartbeat', { host: this.host, token: this.token });
788
+ logger$1.info('Wazo WS stop heartbeat', { host: this.host, token: this.token });
765
789
 
766
790
  this.heartbeat.stop();
767
791
  }
@@ -791,7 +815,7 @@ class WebSocketClient extends Emitter {
791
815
  }
792
816
 
793
817
  reconnect(reason ) {
794
- logger.info('Wazo WS reconnect', { reason, socket: !!this.socket, host: this.host, token: this.token });
818
+ logger$1.info('Wazo WS reconnect', { reason, socket: !!this.socket, host: this.host, token: this.token });
795
819
  if (!this.socket) {
796
820
  return;
797
821
  }
@@ -847,7 +871,7 @@ class WebSocketClient extends Emitter {
847
871
  this.close();
848
872
  }
849
873
  const url = `wss://${this.host || ''}/api/websocketd/?token=${this.token || ''}&version=${this.version}`;
850
- logger.log('Wazo WS url computed to reconnect', { url });
874
+ logger$1.log('Wazo WS url computed to reconnect', { url });
851
875
 
852
876
  return url;
853
877
  }
@@ -855,12 +879,12 @@ class WebSocketClient extends Emitter {
855
879
  _onHeartbeat(message ) {
856
880
  if (message.payload === 'pong') {
857
881
  this.heartbeat.onHeartbeat();
858
- logger.log('on heartbeat received from Wazo WS');
882
+ logger$1.log('on heartbeat received from Wazo WS');
859
883
  }
860
884
  }
861
885
 
862
886
  async _onHeartbeatTimeout() {
863
- logger.log('heartbeat timed out', { host: this.host, token: this.token });
887
+ logger$1.log('heartbeat timed out', { host: this.host, token: this.token });
864
888
 
865
889
  this.close();
866
890
  this.eventEmitter.emit(SOCKET_EVENTS.ON_CLOSE, new Error('Websocket ping failure.'));
@@ -938,6 +962,7 @@ WebSocketClient.eventLists = [
938
962
  AGENT_UNPAUSED,
939
963
  CONFERENCE_ADHOC_PARTICIPANT_LEFT,
940
964
  CONFERENCE_ADHOC_DELETED,
965
+ MEETING_USER_PROGRESS,
941
966
  ];
942
967
 
943
968
  exports.AGENT_PAUSED = AGENT_PAUSED;
@@ -993,6 +1018,7 @@ exports.HEARTBEAT_ENGINE_VERSION = HEARTBEAT_ENGINE_VERSION;
993
1018
  exports.LINE_STATUS_UPDATED = LINE_STATUS_UPDATED;
994
1019
  exports.MEETING_USER_PARTICIPANT_JOINED = MEETING_USER_PARTICIPANT_JOINED;
995
1020
  exports.MEETING_USER_PARTICIPANT_LEFT = MEETING_USER_PARTICIPANT_LEFT;
1021
+ exports.MEETING_USER_PROGRESS = MEETING_USER_PROGRESS;
996
1022
  exports.SOCKET_EVENTS = SOCKET_EVENTS;
997
1023
  exports.SWITCHBOARD_HELD_CALLS_UPDATED = SWITCHBOARD_HELD_CALLS_UPDATED;
998
1024
  exports.SWITCHBOARD_HELD_CALL_ANSWERED = SWITCHBOARD_HELD_CALL_ANSWERED;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wazo/sdk",
3
- "version": "0.37.20",
3
+ "version": "0.37.24",
4
4
  "description": "Wazo's JavaScript Software Development Kit.",
5
5
  "main": "dist/wazo-sdk.js",
6
6
  "author": "Wazo (http://wazo.io)",
package/src/api/confd.js CHANGED
@@ -69,8 +69,11 @@ export default (client: ApiRequester, baseUrl: string) => ({
69
69
  }
70
70
  },
71
71
 
72
- createMyMeeting: (name: string): Promise<Meeting> =>
73
- client.post(`${baseUrl}/users/me/meetings`, { name }).then(Meeting.parse),
72
+ getMyMeetings: (): Promise<Meeting> =>
73
+ client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
74
+
75
+ createMyMeeting: (name: string, persistent: boolean): Promise<Meeting> =>
76
+ client.post(`${baseUrl}/users/me/meetings`, { name, persistent }).then(Meeting.parse),
74
77
 
75
78
  deleteMyMeeting: (meetingUuid: string): Promise<Meeting> =>
76
79
  client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
@@ -61,6 +61,9 @@ export default class Call {
61
61
  recording: boolean;
62
62
 
63
63
  static parseMany(plain: Array<CallResponse>): Array<Call> {
64
+ if (!plain) {
65
+ return [];
66
+ }
64
67
  return plain.map((plainCall: CallResponse) => Call.parse(plainCall));
65
68
  }
66
69
 
@@ -84,6 +84,10 @@ export default class CallLog {
84
84
  }
85
85
 
86
86
  static parseMany(plain: Response): Array<CallLog> {
87
+ if (!plain || !plain.items) {
88
+ return [];
89
+ }
90
+
87
91
  return plain.items.map(item => CallLog.parse(item));
88
92
  }
89
93
 
@@ -42,6 +42,10 @@ export default class ChatMessage {
42
42
  read: boolean;
43
43
 
44
44
  static parseMany(plain: ChatMessageListResponse): Array<ChatMessage> {
45
+ if (!plain || !plain.items) {
46
+ return [];
47
+ }
48
+
45
49
  return plain.items.map(item => ChatMessage.parse(item));
46
50
  }
47
51
 
@@ -22,6 +22,9 @@ export default class ChatRoom {
22
22
  users: Array<ChatUser>;
23
23
 
24
24
  static parseMany(plain: RootListResponse): Array<ChatRoom> {
25
+ if (!plain || !plain.items) {
26
+ return [];
27
+ }
25
28
  return plain.items.map(item => ChatRoom.parse(item));
26
29
  }
27
30
 
@@ -281,6 +281,9 @@ export default class Contact {
281
281
  }
282
282
 
283
283
  static parseMany(response: ContactsResponse): Array<Contact> {
284
+ if (!response || !response.results) {
285
+ return [];
286
+ }
284
287
  return response.results.map(r => Contact.parse(r, response.column_types));
285
288
  }
286
289
 
@@ -1,4 +1,6 @@
1
1
  // @flow
2
+ import moment from 'moment';
3
+
2
4
  import newFrom from '../utils/new-from';
3
5
 
4
6
  export type MeetingCreationResponse = {
@@ -8,8 +10,9 @@ export type MeetingCreationResponse = {
8
10
  owner_uuids: Array<string>,
9
11
  port: string,
10
12
  uuid: string,
11
- number: string,
13
+ exten: string,
12
14
  persistent: boolean,
15
+ creation_time: string,
13
16
  }
14
17
 
15
18
  export default class Meeting {
@@ -20,9 +23,10 @@ export default class Meeting {
20
23
  uuid: string;
21
24
  name: string;
22
25
  port: string;
23
- number: string;
26
+ extension: string;
24
27
  persistent: boolean;
25
28
  ownerUuids: Array<string>;
29
+ creationTime: Date;
26
30
 
27
31
  static parse(plain: MeetingCreationResponse): Meeting {
28
32
  return new Meeting({
@@ -32,24 +36,43 @@ export default class Meeting {
32
36
  ownerUuids: plain.owner_uuids,
33
37
  port: plain.port,
34
38
  uuid: plain.uuid,
35
- number: plain.number,
39
+ extension: plain.exten,
36
40
  persistent: plain.persistent,
41
+ creationTime: moment(plain.creation_time).toDate(),
37
42
  });
38
43
  }
39
44
 
45
+ static parseMany(items: MeetingCreationResponse[]): Array<Meeting> {
46
+ if (!items) {
47
+ return [];
48
+ }
49
+ return items.map(plain => Meeting.parse(plain));
50
+ }
51
+
40
52
  static newFrom(meeting: Meeting) {
41
53
  return newFrom(meeting, Meeting);
42
54
  }
43
55
 
44
- constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, uri, number, persistent }: Object = {}) {
56
+ constructor({
57
+ uuid,
58
+ name,
59
+ guestSipAuthorization,
60
+ ownerUuids,
61
+ port,
62
+ uri,
63
+ extension,
64
+ persistent,
65
+ creationTime,
66
+ }: Object = {}) {
45
67
  this.guestSipAuthorization = guestSipAuthorization;
46
68
  this.uri = uri;
47
69
  this.name = name;
48
70
  this.ownerUuids = ownerUuids;
49
71
  this.port = port;
50
72
  this.uuid = uuid;
51
- this.number = number;
73
+ this.extension = extension;
52
74
  this.persistent = persistent;
75
+ this.creationTime = creationTime;
53
76
 
54
77
  // Useful to compare instead of instanceof with minified code
55
78
  this.type = 'Meeting';
@@ -280,6 +280,10 @@ export default class CTIPhone extends Emitter implements Phone {
280
280
  return false;
281
281
  }
282
282
 
283
+ hasAVideoTrack(): boolean {
284
+ return false;
285
+ }
286
+
283
287
  getLocalStreamForCall(): ?MediaStream {
284
288
  return null;
285
289
  }
@@ -80,6 +80,8 @@ export interface Phone {
80
80
 
81
81
  hasVideo(callSession: CallSession): boolean;
82
82
 
83
+ hasAVideoTrack(callSession: CallSession): boolean;
84
+
83
85
  isWebRTC(): boolean;
84
86
 
85
87
  getUserAgent(): string;
@@ -306,6 +306,11 @@ export default class WebRTCPhone extends Emitter implements Phone {
306
306
 
307
307
  this.client.downgradeToAudio(sipSession);
308
308
 
309
+ if (callSession) {
310
+ callSession.cameraEnabled = false;
311
+ this._updateCallSession(callSession);
312
+ }
313
+
309
314
  if (withMessage) {
310
315
  this._sendReinviteMessage(callSession, false);
311
316
  }
@@ -333,6 +338,11 @@ export default class WebRTCPhone extends Emitter implements Phone {
333
338
 
334
339
  const newStream = await this.client.upgradeToVideo(sipSession, constraints, isConference);
335
340
 
341
+ if (callSession) {
342
+ callSession.cameraEnabled = true;
343
+ this._updateCallSession(callSession);
344
+ }
345
+
336
346
  // If no stream is returned, it means we have to reinvite
337
347
  if (!newStream) {
338
348
  return true;
@@ -385,7 +395,10 @@ export default class WebRTCPhone extends Emitter implements Phone {
385
395
 
386
396
  onCancel(message);
387
397
  const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
388
- this.eventEmitter.emit(ON_CALL_CANCELED, this._createCallSession(sipSession), elsewhere);
398
+ const callSession = this._createCallSession(sipSession);
399
+ delete this.callSessions[callSession.getId()];
400
+
401
+ this.eventEmitter.emit(ON_CALL_CANCELED, callSession, elsewhere);
389
402
  };
390
403
  } else if (sipSession instanceof Invitation) {
391
404
  console.warn('sipSession._onCancel not found, please update the wazo SDK accordingly');
@@ -414,9 +427,11 @@ export default class WebRTCPhone extends Emitter implements Phone {
414
427
  case SessionState.Terminated: {
415
428
  logger.info('WebRTC phone - call terminated', { sipId: sipSession.id });
416
429
 
430
+ // Should be called before `_onCallTerminated` or the callCount will not decrement...
431
+ const callSession = this._createCallSession(sipSession);
417
432
  const wasCurrentSession = this._onCallTerminated(sipSession);
418
433
 
419
- return this.eventEmitter.emit(ON_CALL_ENDED, this._createCallSession(sipSession), wasCurrentSession);
434
+ return this.eventEmitter.emit(ON_CALL_ENDED, callSession, wasCurrentSession);
420
435
  }
421
436
  default:
422
437
  break;
@@ -566,18 +581,20 @@ export default class WebRTCPhone extends Emitter implements Phone {
566
581
  screenTrack,
567
582
  });
568
583
 
569
- screenTrack.onended = () => {
570
- logger.info('WebRTC phone - on screenshare ended', {
571
- hadVideo,
572
- id: this.getSipSessionId(sipSession),
573
- screenTrack,
574
- });
575
-
576
- this.eventEmitter.emit(
577
- ON_SHARE_SCREEN_ENDING,
578
- this._createCallSession(sipSession, callSession),
579
- );
580
- };
584
+ if (screenTrack) {
585
+ screenTrack.onended = () => {
586
+ logger.info('WebRTC phone - on screenshare ended', {
587
+ hadVideo,
588
+ id: this.getSipSessionId(sipSession),
589
+ screenTrack,
590
+ });
591
+
592
+ this.eventEmitter.emit(
593
+ ON_SHARE_SCREEN_ENDING,
594
+ this._createCallSession(sipSession, callSession),
595
+ );
596
+ };
597
+ }
581
598
 
582
599
  this.currentScreenShare = {
583
600
  stream: screenStream,
@@ -1366,6 +1383,10 @@ export default class WebRTCPhone extends Emitter implements Phone {
1366
1383
  return callSession ? this.client.getRemoteVideoStream(callSession.sipCallId) : null;
1367
1384
  }
1368
1385
 
1386
+ getRemoteVideoStreamFromPc(callSession: CallSession): ?MediaStream {
1387
+ return callSession ? this.client.getRemoteVideoStreamFromPc(callSession.sipCallId) : null;
1388
+ }
1389
+
1369
1390
  hasRemoteVideo(callSession: CallSession): boolean {
1370
1391
  return callSession ? this.client.hasRemoteVideo(callSession.sipCallId) : false;
1371
1392
  }
@@ -1466,9 +1487,13 @@ export default class WebRTCPhone extends Emitter implements Phone {
1466
1487
  if (this.shouldSendReinvite && this.currentSipSession
1467
1488
  && this.currentSipSession.state === SessionState.Established) {
1468
1489
  this.shouldSendReinvite = false;
1490
+ const pc = this.currentSipSession.sessionDescriptionHandler.peerConnection;
1491
+ const isConference = pc ? pc.sfu : false;
1492
+ const hasVideo = this.currentCallSession && this.currentCallSession.cameraEnabled;
1493
+
1469
1494
  try {
1470
1495
  // Send reinvite with iceRestart
1471
- this.sendReinvite(this.currentCallSession, null, false, false, true);
1496
+ this.sendReinvite(this.currentCallSession, null, isConference, !hasVideo, true);
1472
1497
  } catch (e) {
1473
1498
  logger.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
1474
1499
  }
@@ -1552,6 +1577,15 @@ export default class WebRTCPhone extends Emitter implements Phone {
1552
1577
  return this.client.getSipSessionId(sipSession);
1553
1578
  }
1554
1579
 
1580
+ _updateCallSession(callSession: CallSession) {
1581
+ const sipSession = this.findSipSession(callSession);
1582
+ const sipSessionId = sipSession ? this.getSipSessionId(sipSession) : null;
1583
+
1584
+ if (sipSessionId) {
1585
+ this.callSessions[sipSessionId] = callSession;
1586
+ }
1587
+ }
1588
+
1555
1589
  _onMessage(message: Message) {
1556
1590
  if (!message || message.method !== 'MESSAGE') {
1557
1591
  return;
@@ -25,6 +25,9 @@ export default class Recording {
25
25
  uuid: string;
26
26
 
27
27
  static parseMany(recordings: RecordingResponse[] = []): Recording[] {
28
+ if (!recordings) {
29
+ return [];
30
+ }
28
31
  return recordings.map(item => Recording.parse(item));
29
32
  }
30
33
 
@@ -61,6 +61,9 @@ export default class Voicemail {
61
61
  }
62
62
 
63
63
  static parseMany(plain: Response): Array<Voicemail> {
64
+ if (!plain) {
65
+ return [];
66
+ }
64
67
  const plainUnread = plain.folders.filter(folder => folder.type === 'new')[0].messages;
65
68
  const plainRead = plain.folders.filter(folder => folder.type === 'old')[0].messages;
66
69
 
@@ -0,0 +1,50 @@
1
+ // @flow
2
+ /* global btoa */
3
+
4
+ import Meeting from '../Meeting';
5
+
6
+ describe('Meeting domain', () => {
7
+ it('can return username and secret from an base64 encrypted string', () => {
8
+ const USERNAME = 'username';
9
+ const SECRET = 'secret';
10
+
11
+ const args = {
12
+ guest_sip_authorization: btoa(`${USERNAME}:${SECRET}`),
13
+ creation_time: '',
14
+ ingress_http_uri: '',
15
+ name: '',
16
+ owner_uuids: [],
17
+ port: '',
18
+ uuid: '',
19
+ exten: '',
20
+ persistent: false,
21
+ };
22
+
23
+ const meeting = Meeting.parse(args);
24
+
25
+ const { username, secret } = meeting.getGuestSipCredentials();
26
+
27
+ expect(username).toEqual(USERNAME);
28
+ expect(secret).toEqual(SECRET);
29
+ });
30
+
31
+ it('should return a date from a string', () => {
32
+ const args = {
33
+ creation_time: '2021-12-21T15:56:42.880Z',
34
+ guest_sip_authorization: '',
35
+ ingress_http_uri: '',
36
+ name: '',
37
+ owner_uuids: [],
38
+ port: '',
39
+ uuid: '',
40
+ exten: '',
41
+ persistent: false,
42
+ };
43
+
44
+ const { creationTime } = Meeting.parse(args);
45
+
46
+ expect(creationTime.getDate()).toEqual(21);
47
+ expect(creationTime.getFullYear()).toEqual(2021);
48
+ expect(creationTime.getMonth()).toEqual(11);
49
+ });
50
+ });
@@ -12,11 +12,9 @@ import { SessionDescriptionHandler }
12
12
  import { SessionDescriptionHandlerOptions }
13
13
  from 'sip.js/lib/platform/web/session-description-handler/session-description-handler-options';
14
14
  import IssueReporter from '../service/IssueReporter';
15
- import { areCandidateValid, fixSdp, parseCandidate } from '../utils/sdp';
15
+ import { fixSdp, parseCandidate } from '../utils/sdp';
16
16
 
17
17
  const wazoLogger = IssueReporter ? IssueReporter.loggerFor('webrtc-sdh') : console;
18
- const MAX_WAIT_FOR_ICE_TRIES = 20;
19
- const WAIT_FOR_ICE_TIMEOUT = 500;
20
18
 
21
19
  // Customized mediaStreamFactory allowing to send screensharing stream directory when upgrading
22
20
  export const wazoMediaStreamFactory = (constraints: Object): Promise<MediaStream> => {
@@ -206,38 +204,6 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
206
204
  this._peerConnection = undefined;
207
205
  }
208
206
 
209
- async _waitForValidGatheredIce(): Object {
210
- let tries = 0;
211
-
212
- while (!areCandidateValid(this.gatheredCandidates) && tries < MAX_WAIT_FOR_ICE_TRIES) {
213
- wazoLogger.trace('SessionDescriptionHandler._waitForValidGatheredIce, waiting for ice', {
214
- tries,
215
- max: MAX_WAIT_FOR_ICE_TRIES,
216
- });
217
-
218
- tries++;
219
-
220
- // eslint-disable-next-line no-await-in-loop
221
- await new Promise(resolve => setTimeout(resolve, WAIT_FOR_ICE_TIMEOUT));
222
- }
223
-
224
- if (tries >= MAX_WAIT_FOR_ICE_TRIES) {
225
- const errorMsg = 'No valid candidates found, can\'t answer the call';
226
- const error = new Error(errorMsg);
227
- wazoLogger.error(errorMsg, { tries, max: MAX_WAIT_FOR_ICE_TRIES });
228
-
229
- // Emit an error, because sip.js catches the exception and switch to status Terminated.
230
- this.eventEmitter.emit('error', error);
231
-
232
- wazoLogger.error('No valid candidates found', { tries, candidates: JSON.stringify(this.gatheredCandidates) });
233
- }
234
-
235
- // eslint-disable-next-line
236
- wazoLogger.trace('Found valid candidates', { tries, candidates: JSON.stringify(this.gatheredCandidates) });
237
-
238
- return this.getLocalSessionDescription();
239
- }
240
-
241
207
  // Overridden to send `inactive` in conference
242
208
  updateDirection(options?: SessionDescriptionHandlerOptions, isConference: boolean = false,
243
209
  audioOnly: boolean = false): Promise<void> {