agora-appbuilder-core 4.1.11 → 4.1.12

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.
@@ -0,0 +1,848 @@
1
+ /*
2
+ ********************************************
3
+ Copyright © 2021 Agora Lab, Inc., all rights reserved.
4
+ AppBuilder and all associated components, source code, APIs, services, and documentation
5
+ (the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
6
+ accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
7
+ Use without a license or in violation of any license terms and conditions (including use for
8
+ any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
9
+ information visit https://appbuilder.agora.io.
10
+ *********************************************
11
+ */
12
+ // @ts-nocheck
13
+ import React, {useState, useContext, useEffect, useRef} from 'react';
14
+ import RtmEngine, {RtmChannelAttribute} from 'agora-react-native-rtm';
15
+ import {
16
+ ContentInterface,
17
+ DispatchContext,
18
+ PropsContext,
19
+ useLocalUid,
20
+ } from '../../agora-rn-uikit';
21
+ import ChatContext from './ChatContext';
22
+ import {Platform} from 'react-native';
23
+ import {backOff} from 'exponential-backoff';
24
+ import {useString} from '../utils/useString';
25
+ import {isAndroid, isIOS, isWeb, isWebInternal} from '../utils/common';
26
+ import {useContent, useIsAttendee, useUserName} from 'customization-api';
27
+ import {
28
+ safeJsonParse,
29
+ timeNow,
30
+ hasJsonStructure,
31
+ getMessageTime,
32
+ get32BitUid,
33
+ } from '../rtm/utils';
34
+ import {EventUtils, EventsQueue, EventNames} from '../rtm-events';
35
+ import events, {PersistanceLevel} from '../rtm-events-api';
36
+ import RTMEngine from '../rtm/RTMEngine';
37
+ import {filterObject} from '../utils';
38
+ import SDKEvents from '../utils/SdkEvents';
39
+ import isSDK from '../utils/isSDK';
40
+ import {useAsyncEffect} from '../utils/useAsyncEffect';
41
+ import {
42
+ WaitingRoomStatus,
43
+ useRoomInfo,
44
+ } from '../components/room-info/useRoomInfo';
45
+ import LocalEventEmitter, {
46
+ LocalEventsEnum,
47
+ } from '../rtm-events-api/LocalEvents';
48
+ import {PSTNUserLabel} from '../language/default-labels/videoCallScreenLabels';
49
+ import {controlMessageEnum} from '../components/ChatContext';
50
+ import {LogSource, logger} from '../logger/AppBuilderLogger';
51
+ import {RECORDING_BOT_UID} from '../utils/constants';
52
+
53
+ export enum UserType {
54
+ ScreenShare = 'screenshare',
55
+ }
56
+
57
+ const RtmConfigure = (props: any) => {
58
+ const rtmInitTimstamp = new Date().getTime();
59
+ const localUid = useLocalUid();
60
+ const {callActive} = props;
61
+ const {rtcProps} = useContext(PropsContext);
62
+ const {dispatch} = useContext(DispatchContext);
63
+ const {defaultContent, activeUids} = useContent();
64
+ const defaultContentRef = useRef({defaultContent: defaultContent});
65
+ const activeUidsRef = useRef({activeUids: activeUids});
66
+
67
+ const {
68
+ waitingRoomStatus,
69
+ data: {isHost},
70
+ } = useRoomInfo();
71
+ const waitingRoomStatusRef = useRef({waitingRoomStatus: waitingRoomStatus});
72
+
73
+ const isHostRef = useRef({isHost: isHost});
74
+
75
+ useEffect(() => {
76
+ isHostRef.current.isHost = isHost;
77
+ }, [isHost]);
78
+
79
+ useEffect(() => {
80
+ waitingRoomStatusRef.current.waitingRoomStatus = waitingRoomStatus;
81
+ }, [waitingRoomStatus]);
82
+
83
+ /**
84
+ * inside event callback state won't have latest value.
85
+ * so creating ref to access the state
86
+ */
87
+ useEffect(() => {
88
+ activeUidsRef.current.activeUids = activeUids;
89
+ }, [activeUids]);
90
+
91
+ useEffect(() => {
92
+ defaultContentRef.current.defaultContent = defaultContent;
93
+ }, [defaultContent]);
94
+
95
+ const [hasUserJoinedRTM, setHasUserJoinedRTM] = useState<boolean>(false);
96
+ const [isInitialQueueCompleted, setIsInitialQueueCompleted] = useState(false);
97
+ const [onlineUsersCount, setTotalOnlineUsers] = useState<number>(0);
98
+
99
+ let engine = useRef<RtmEngine>(null!);
100
+ const timerValueRef: any = useRef(5);
101
+
102
+ React.useEffect(() => {
103
+ setTotalOnlineUsers(
104
+ Object.keys(
105
+ filterObject(
106
+ defaultContent,
107
+ ([k, v]) =>
108
+ v?.type === 'rtc' &&
109
+ !v.offline &&
110
+ activeUids.indexOf(v?.uid) !== -1,
111
+ ),
112
+ ).length,
113
+ );
114
+ }, [defaultContent]);
115
+
116
+ React.useEffect(() => {
117
+ if (!$config.ENABLE_CONVERSATIONAL_AI) {
118
+ const handBrowserClose = ev => {
119
+ ev.preventDefault();
120
+ return (ev.returnValue = 'Are you sure you want to exit?');
121
+ };
122
+ const logoutRtm = () => {
123
+ engine.current.leaveChannel(rtcProps.channel);
124
+ };
125
+
126
+ if (!isWebInternal()) return;
127
+ window.addEventListener(
128
+ 'beforeunload',
129
+ isWeb() && !isSDK() ? handBrowserClose : () => {},
130
+ );
131
+
132
+ window.addEventListener('pagehide', logoutRtm);
133
+ // cleanup this component
134
+ return () => {
135
+ window.removeEventListener(
136
+ 'beforeunload',
137
+ isWeb() && !isSDK() ? handBrowserClose : () => {},
138
+ );
139
+ window.removeEventListener('pagehide', logoutRtm);
140
+ };
141
+ }
142
+ }, []);
143
+
144
+ const doLoginAndSetupRTM = async () => {
145
+ try {
146
+ logger.log(LogSource.AgoraSDK, 'API', 'RTM login starts');
147
+ await engine.current.login({
148
+ uid: localUid.toString(),
149
+ token: rtcProps.rtm,
150
+ });
151
+ logger.log(LogSource.AgoraSDK, 'API', 'RTM login done');
152
+ RTMEngine.getInstance().setLocalUID(localUid.toString());
153
+ logger.log(LogSource.AgoraSDK, 'API', 'RTM local Uid set');
154
+ timerValueRef.current = 5;
155
+ await setAttribute();
156
+ logger.log(LogSource.AgoraSDK, 'Log', 'RTM setting attribute done');
157
+ } catch (error) {
158
+ logger.error(LogSource.AgoraSDK, 'Log', 'RTM login failed..Trying again');
159
+ setTimeout(async () => {
160
+ timerValueRef.current = timerValueRef.current + timerValueRef.current;
161
+ doLoginAndSetupRTM();
162
+ }, timerValueRef.current * 1000);
163
+ }
164
+ };
165
+
166
+ const setAttribute = async () => {
167
+ const rtmAttributes = [
168
+ {key: 'screenUid', value: String(rtcProps.screenShareUid)},
169
+ {key: 'isHost', value: String(isHostRef.current.isHost)},
170
+ ];
171
+ try {
172
+ await engine.current.setLocalUserAttributes(rtmAttributes);
173
+ logger.log(
174
+ LogSource.AgoraSDK,
175
+ 'API',
176
+ 'RTM setting local user attributes',
177
+ {
178
+ attr: rtmAttributes,
179
+ },
180
+ );
181
+ timerValueRef.current = 5;
182
+ await joinChannel();
183
+ logger.log(LogSource.AgoraSDK, 'Log', 'RTM join channel done', {
184
+ data: rtmAttributes,
185
+ });
186
+ setHasUserJoinedRTM(true);
187
+ await runQueuedEvents();
188
+ setIsInitialQueueCompleted(true);
189
+ logger.log(
190
+ LogSource.AgoraSDK,
191
+ 'Log',
192
+ 'RTM queued events finished running',
193
+ {
194
+ attr: rtmAttributes,
195
+ },
196
+ );
197
+ } catch (error) {
198
+ logger.error(
199
+ LogSource.AgoraSDK,
200
+ 'Log',
201
+ 'RTM setAttribute failed..Trying again',
202
+ );
203
+ setTimeout(async () => {
204
+ timerValueRef.current = timerValueRef.current + timerValueRef.current;
205
+ setAttribute();
206
+ }, timerValueRef.current * 1000);
207
+ }
208
+ };
209
+
210
+ const joinChannel = async () => {
211
+ try {
212
+ if (RTMEngine.getInstance().channelUid !== rtcProps.channel) {
213
+ await engine.current.joinChannel(rtcProps.channel);
214
+ logger.log(LogSource.AgoraSDK, 'API', 'RTM joinChannel', {
215
+ data: rtcProps.channel,
216
+ });
217
+ RTMEngine.getInstance().setChannelId(rtcProps.channel);
218
+ logger.log(
219
+ LogSource.AgoraSDK,
220
+ 'API',
221
+ 'RTM setChannelId',
222
+ rtcProps.channel,
223
+ );
224
+ logger.debug(
225
+ LogSource.SDK,
226
+ 'Event',
227
+ 'Emitting rtm joined',
228
+ rtcProps.channel,
229
+ );
230
+ SDKEvents.emit('_rtm-joined', rtcProps.channel);
231
+ } else {
232
+ logger.debug(
233
+ LogSource.AgoraSDK,
234
+ 'Log',
235
+ 'RTM already joined channel skipping',
236
+ rtcProps.channel,
237
+ );
238
+ }
239
+ timerValueRef.current = 5;
240
+ await getMembers();
241
+ await readAllChannelAttributes();
242
+ logger.log(LogSource.AgoraSDK, 'Log', 'RTM getMembers done');
243
+ } catch (error) {
244
+ logger.error(
245
+ LogSource.AgoraSDK,
246
+ 'Log',
247
+ 'RTM joinChannel failed..Trying again',
248
+ );
249
+ setTimeout(async () => {
250
+ timerValueRef.current = timerValueRef.current + timerValueRef.current;
251
+ joinChannel();
252
+ }, timerValueRef.current * 1000);
253
+ }
254
+ };
255
+
256
+ const updateRenderListState = (
257
+ uid: number,
258
+ data: Partial<ContentInterface>,
259
+ ) => {
260
+ dispatch({type: 'UpdateRenderList', value: [uid, data]});
261
+ };
262
+
263
+ const getMembers = async () => {
264
+ try {
265
+ logger.log(
266
+ LogSource.AgoraSDK,
267
+ 'API',
268
+ 'RTM getChannelMembersByID(getMembers) start',
269
+ );
270
+ await engine.current
271
+ .getChannelMembersBychannelId(rtcProps.channel)
272
+ .then(async data => {
273
+ logger.log(
274
+ LogSource.AgoraSDK,
275
+ 'API',
276
+ 'RTM getChannelMembersByID data received',
277
+ data,
278
+ );
279
+ await Promise.all(
280
+ data.members.map(async (member: any) => {
281
+ const backoffAttributes = backOff(
282
+ async () => {
283
+ logger.log(
284
+ LogSource.AgoraSDK,
285
+ 'API',
286
+ `RTM fetching getUserAttributesByUid for member ${member.uid}`,
287
+ );
288
+ const attr = await engine.current.getUserAttributesByUid(
289
+ member.uid,
290
+ );
291
+ if (!attr || !attr.attributes) {
292
+ logger.log(
293
+ LogSource.AgoraSDK,
294
+ 'API',
295
+ 'RTM attributes for member not found',
296
+ );
297
+ throw attr;
298
+ }
299
+ logger.log(
300
+ LogSource.AgoraSDK,
301
+ 'API',
302
+ `RTM getUserAttributesByUid for member ${member.uid} received`,
303
+ {
304
+ attr,
305
+ },
306
+ );
307
+ for (const key in attr.attributes) {
308
+ if (
309
+ attr.attributes.hasOwnProperty(key) &&
310
+ attr.attributes[key]
311
+ ) {
312
+ return attr;
313
+ } else {
314
+ throw attr;
315
+ }
316
+ }
317
+ },
318
+ {
319
+ retry: (e, idx) => {
320
+ logger.debug(
321
+ LogSource.AgoraSDK,
322
+ 'Log',
323
+ `[retrying] Attempt ${idx}. Fetching ${member.uid}'s name`,
324
+ e,
325
+ );
326
+ return true;
327
+ },
328
+ },
329
+ );
330
+ try {
331
+ const attr = await backoffAttributes;
332
+ console.log('[user attributes]:', {attr});
333
+ //RTC layer uid type is number. so doing the parseInt to convert to number
334
+ //todo hari check android uid comparsion
335
+ const uid = parseInt(member.uid);
336
+ const screenUid = parseInt(attr?.attributes?.screenUid);
337
+ //start - updating user data in rtc
338
+ const userData = {
339
+ screenUid: screenUid,
340
+ //below thing for livestreaming
341
+ type: uid === parseInt(RECORDING_BOT_UID) ? 'bot' : 'rtc',
342
+ uid,
343
+ offline: false,
344
+ isHost: attr?.attributes?.isHost,
345
+ lastMessageTimeStamp: 0,
346
+ };
347
+ updateRenderListState(uid, userData);
348
+ //end- updating user data in rtc
349
+
350
+ //start - updating screenshare data in rtc
351
+ const screenShareUser = {
352
+ type: UserType.ScreenShare,
353
+ parentUid: uid,
354
+ };
355
+ updateRenderListState(screenUid, screenShareUser);
356
+ //end - updating screenshare data in rtc
357
+ // setting screenshare data
358
+ // name of the screenUid, isActive: false, (when the user starts screensharing it becomes true)
359
+ // isActive to identify all active screenshare users in the call
360
+ for (const [key, value] of Object.entries(attr?.attributes)) {
361
+ if (hasJsonStructure(value as string)) {
362
+ const data = {
363
+ evt: key,
364
+ value: value,
365
+ };
366
+ // TODOSUP: Add the data to queue, dont add same mulitple events, use set so as to not repeat events
367
+ EventsQueue.enqueue({
368
+ data: data,
369
+ uid: member.uid,
370
+ ts: timeNow(),
371
+ });
372
+ }
373
+ }
374
+ } catch (e) {
375
+ logger.error(
376
+ LogSource.AgoraSDK,
377
+ 'Log',
378
+ `Could not retrieve name of ${member.uid}`,
379
+ e,
380
+ );
381
+ }
382
+ }),
383
+ );
384
+ logger.debug(
385
+ LogSource.AgoraSDK,
386
+ 'Log',
387
+ 'RTM fetched all data and user attr...RTM init done',
388
+ );
389
+ });
390
+ timerValueRef.current = 5;
391
+ } catch (error) {
392
+ setTimeout(async () => {
393
+ timerValueRef.current = timerValueRef.current + timerValueRef.current;
394
+ await getMembers();
395
+ }, timerValueRef.current * 1000);
396
+ }
397
+ };
398
+
399
+ const readAllChannelAttributes = async () => {
400
+ try {
401
+ await engine.current
402
+ .getChannelAttributes(rtcProps.channel)
403
+ .then(async data => {
404
+ for (const item of data) {
405
+ const {key, value, lastUpdateTs, lastUpdateUserId} = item;
406
+ if (hasJsonStructure(value as string)) {
407
+ const evtData = {
408
+ evt: key,
409
+ value,
410
+ };
411
+ // TODOSUP: Add the data to queue, dont add same mulitple events, use set so as to not repeat events
412
+ EventsQueue.enqueue({
413
+ data: evtData,
414
+ uid: lastUpdateUserId,
415
+ ts: lastUpdateTs,
416
+ });
417
+ }
418
+ }
419
+ logger.log(
420
+ LogSource.AgoraSDK,
421
+ 'API',
422
+ 'RTM getChannelAttributes data received',
423
+ data,
424
+ );
425
+ });
426
+ timerValueRef.current = 5;
427
+ } catch (error) {
428
+ setTimeout(async () => {
429
+ timerValueRef.current = timerValueRef.current + timerValueRef.current;
430
+ await readAllChannelAttributes();
431
+ }, timerValueRef.current * 1000);
432
+ }
433
+ };
434
+
435
+ const init = async () => {
436
+ //on sdk due to multiple re-render we are getting rtm error code 8
437
+ //you are joining the same channel too frequently, exceeding the allowed rate of joining the same channel multiple times within a short period
438
+ //so checking rtm connection state before proceed
439
+ if (engine?.current?.client?.connectionState === 'CONNECTED') {
440
+ return;
441
+ }
442
+ logger.log(LogSource.AgoraSDK, 'Log', 'RTM creating engine...');
443
+ engine.current = RTMEngine.getInstance().engine;
444
+ RTMEngine.getInstance();
445
+ logger.log(LogSource.AgoraSDK, 'Log', 'RTM engine creation done');
446
+
447
+ engine.current.on('connectionStateChanged', (evt: any) => {
448
+ //console.log(evt);
449
+ });
450
+ engine.current.on('error', (evt: any) => {
451
+ // console.log(evt);
452
+ });
453
+ engine.current.on('channelMemberJoined', (data: any) => {
454
+ logger.log(LogSource.AgoraSDK, 'Event', 'channelMemberJoined', data);
455
+ const backoffAttributes = backOff(
456
+ async () => {
457
+ logger.log(
458
+ LogSource.AgoraSDK,
459
+ 'API',
460
+ `RTM fetching getUserAttributesByUid for member ${data.uid}`,
461
+ );
462
+ const attr = await engine.current.getUserAttributesByUid(data.uid);
463
+ if (!attr || !attr.attributes) {
464
+ logger.log(
465
+ LogSource.AgoraSDK,
466
+ 'API',
467
+ 'RTM attributes for member not found',
468
+ );
469
+ throw attr;
470
+ }
471
+ logger.log(
472
+ LogSource.AgoraSDK,
473
+ 'API',
474
+ `RTM getUserAttributesByUid for member ${data.uid} received`,
475
+ {
476
+ attr,
477
+ },
478
+ );
479
+ for (const key in attr.attributes) {
480
+ if (attr.attributes.hasOwnProperty(key) && attr.attributes[key]) {
481
+ return attr;
482
+ } else {
483
+ throw attr;
484
+ }
485
+ }
486
+ },
487
+ {
488
+ retry: (e, idx) => {
489
+ logger.debug(
490
+ LogSource.AgoraSDK,
491
+ 'Log',
492
+ `[retrying] Attempt ${idx}. Fetching ${data.uid}'s name`,
493
+ e,
494
+ );
495
+ return true;
496
+ },
497
+ },
498
+ );
499
+ async function getname() {
500
+ try {
501
+ const attr = await backoffAttributes;
502
+ console.log('[user attributes]:', {attr});
503
+ const uid = parseInt(data.uid);
504
+ const screenUid = parseInt(attr?.attributes?.screenUid);
505
+
506
+ //start - updating user data in rtc
507
+ const userData = {
508
+ screenUid: screenUid,
509
+ //below thing for livestreaming
510
+ type: uid === parseInt(RECORDING_BOT_UID) ? 'bot' : 'rtc',
511
+ uid,
512
+ offline: false,
513
+ lastMessageTimeStamp: 0,
514
+ isHost: attr?.attributes?.isHost,
515
+ };
516
+ updateRenderListState(uid, userData);
517
+ //end- updating user data in rtc
518
+
519
+ //start - updating screenshare data in rtc
520
+ const screenShareUser = {
521
+ type: UserType.ScreenShare,
522
+ parentUid: uid,
523
+ };
524
+ updateRenderListState(screenUid, screenShareUser);
525
+ //end - updating screenshare data in rtc
526
+ } catch (e) {
527
+ logger.error(
528
+ LogSource.AgoraSDK,
529
+ 'Event',
530
+ `Failed to retrive name of ${data.uid}`,
531
+ e,
532
+ );
533
+ }
534
+ }
535
+ getname();
536
+ });
537
+
538
+ engine.current.on('channelMemberLeft', (data: any) => {
539
+ logger.debug(LogSource.AgoraSDK, 'Event', 'channelMemberLeft', data);
540
+ // Chat of left user becomes undefined. So don't cleanup
541
+ const uid = data?.uid ? parseInt(data?.uid) : undefined;
542
+ if (!uid) return;
543
+ SDKEvents.emit('_rtm-left', uid);
544
+ // updating the rtc data
545
+ updateRenderListState(uid, {
546
+ offline: true,
547
+ });
548
+ });
549
+
550
+ engine.current.addListener(
551
+ 'ChannelAttributesUpdated',
552
+ (attributeList: RtmChannelAttribute[]) => {
553
+ try {
554
+ attributeList.map((attribute: RtmChannelAttribute) => {
555
+ const {key, value, lastUpdateTs, lastUpdateUserId} = attribute;
556
+ const timestamp = getMessageTime(lastUpdateTs);
557
+ const sender = Platform.OS
558
+ ? get32BitUid(lastUpdateUserId)
559
+ : parseInt(lastUpdateUserId);
560
+ eventDispatcher(
561
+ {
562
+ evt: key,
563
+ value,
564
+ },
565
+ sender,
566
+ timestamp,
567
+ );
568
+ });
569
+ } catch (error) {
570
+ logger.error(
571
+ LogSource.Events,
572
+ 'CUSTOM_EVENTS',
573
+ 'error while dispatching through eventDispatcher',
574
+ error,
575
+ );
576
+ }
577
+ },
578
+ );
579
+
580
+ engine.current.on('messageReceived', (evt: any) => {
581
+ logger.debug(LogSource.Events, 'CUSTOM_EVENTS', 'messageReceived', evt);
582
+ const {peerId, ts, text} = evt;
583
+ const [err, msg] = safeJsonParse(text);
584
+ if (err) {
585
+ logger.error(
586
+ LogSource.Events,
587
+ 'CUSTOM_EVENTS',
588
+ 'JSON payload incorrect, Error while parsing the payload',
589
+ err,
590
+ );
591
+ }
592
+
593
+ const timestamp = getMessageTime(ts);
594
+
595
+ const sender = isAndroid() ? get32BitUid(peerId) : parseInt(peerId);
596
+
597
+ try {
598
+ eventDispatcher(msg, sender, timestamp);
599
+ } catch (error) {
600
+ logger.error(
601
+ LogSource.Events,
602
+ 'CUSTOM_EVENTS',
603
+ 'error while dispatching through eventDispatcher',
604
+ err,
605
+ );
606
+ }
607
+ });
608
+
609
+ engine.current.on('channelMessageReceived', evt => {
610
+ logger.debug(
611
+ LogSource.Events,
612
+ 'CUSTOM_EVENTS',
613
+ 'channelMessageReceived',
614
+ evt,
615
+ );
616
+
617
+ const {uid, channelId, text, ts} = evt;
618
+ //whiteboard upload
619
+ if (uid == 1010101) {
620
+ const [err, res] = safeJsonParse(text);
621
+ if (err) {
622
+ logger.error(
623
+ LogSource.Events,
624
+ 'CUSTOM_EVENTS',
625
+ 'JSON payload incorrect, Error while parsing the payload',
626
+ err,
627
+ );
628
+ }
629
+
630
+ if (res?.data?.data?.images) {
631
+ LocalEventEmitter.emit(
632
+ LocalEventsEnum.WHITEBOARD_FILE_UPLOAD,
633
+ res?.data?.data?.images,
634
+ );
635
+ }
636
+ } else {
637
+ const [err, msg] = safeJsonParse(text);
638
+ if (err) {
639
+ logger.error(
640
+ LogSource.Events,
641
+ 'CUSTOM_EVENTS',
642
+ 'JSON payload incorrect, Error while parsing the payload',
643
+ err,
644
+ );
645
+ }
646
+
647
+ const timestamp = getMessageTime(ts);
648
+
649
+ const sender = Platform.OS ? get32BitUid(uid) : parseInt(uid);
650
+
651
+ if (channelId === rtcProps.channel) {
652
+ try {
653
+ eventDispatcher(msg, sender, timestamp);
654
+ } catch (error) {
655
+ logger.error(
656
+ LogSource.Events,
657
+ 'CUSTOM_EVENTS',
658
+ 'error while dispatching through eventDispatcher',
659
+ error,
660
+ );
661
+ }
662
+ }
663
+ }
664
+ });
665
+
666
+ await doLoginAndSetupRTM();
667
+ };
668
+
669
+ const runQueuedEvents = async () => {
670
+ try {
671
+ while (!EventsQueue.isEmpty()) {
672
+ const currEvt = EventsQueue.dequeue();
673
+ await eventDispatcher(currEvt.data, currEvt.uid, currEvt.ts);
674
+ }
675
+ } catch (error) {
676
+ logger.error(
677
+ LogSource.Events,
678
+ 'CUSTOM_EVENTS',
679
+ 'error while running queue events',
680
+ error,
681
+ );
682
+ }
683
+ };
684
+
685
+ const eventDispatcher = async (
686
+ data: {
687
+ evt: string;
688
+ value: string;
689
+ },
690
+ sender: string,
691
+ ts: number,
692
+ ) => {
693
+ console.debug(
694
+ LogSource.Events,
695
+ 'CUSTOM_EVENTS',
696
+ 'inside eventDispatcher ',
697
+ data,
698
+ );
699
+
700
+ let evt = '',
701
+ value = {};
702
+
703
+ if (data.feat === 'WAITING_ROOM') {
704
+ if (data.etyp === 'REQUEST') {
705
+ const outputData = {
706
+ evt: `${data.feat}_${data.etyp}`,
707
+ payload: JSON.stringify({
708
+ attendee_uid: data.data.data.attendee_uid,
709
+ attendee_screenshare_uid: data.data.data.attendee_screenshare_uid,
710
+ }),
711
+ persistLevel: 1,
712
+ source: 'core',
713
+ };
714
+ const formattedData = JSON.stringify(outputData);
715
+ evt = data.feat + '_' + data.etyp; //rename if client side RTM meessage is to be sent for approval
716
+ value = formattedData;
717
+ }
718
+ if (data.etyp === 'RESPONSE') {
719
+ const outputData = {
720
+ evt: `${data.feat}_${data.etyp}`,
721
+ payload: JSON.stringify({
722
+ approved: data.data.data.approved,
723
+ channelName: data.data.data.channel_name,
724
+ mainUser: data.data.data.mainUser,
725
+ screenShare: data.data.data.screenShare,
726
+ whiteboard: data.data.data.whiteboard,
727
+ chat: data.data.data?.chat,
728
+ }),
729
+ persistLevel: 1,
730
+ source: 'core',
731
+ };
732
+ const formattedData = JSON.stringify(outputData);
733
+ evt = data.feat + '_' + data.etyp;
734
+ value = formattedData;
735
+ }
736
+ } else {
737
+ if (
738
+ $config.ENABLE_WAITING_ROOM &&
739
+ !isHostRef.current?.isHost &&
740
+ waitingRoomStatusRef.current?.waitingRoomStatus !==
741
+ WaitingRoomStatus.APPROVED
742
+ ) {
743
+ if (
744
+ data.evt === controlMessageEnum.muteAudio ||
745
+ data.evt === controlMessageEnum.muteVideo
746
+ ) {
747
+ return;
748
+ } else {
749
+ evt = data.evt;
750
+ value = data.value;
751
+ }
752
+ } else {
753
+ evt = data.evt;
754
+ value = data.value;
755
+ }
756
+ }
757
+
758
+ try {
759
+ const {payload, persistLevel, source} = JSON.parse(value);
760
+ // Step 1: Set local attributes
761
+ if (persistLevel === PersistanceLevel.Session) {
762
+ const rtmAttribute = {key: evt, value: value};
763
+ await engine.current.addOrUpdateLocalUserAttributes([rtmAttribute]);
764
+ }
765
+ // Step 2: Emit the event
766
+ console.debug(LogSource.Events, 'CUSTOM_EVENTS', 'emiting event..: ');
767
+ EventUtils.emitEvent(evt, source, {payload, persistLevel, sender, ts});
768
+ // Because async gets evaluated in a different order when in an sdk
769
+ if (evt === 'name') {
770
+ setTimeout(() => {
771
+ EventUtils.emitEvent(evt, source, {
772
+ payload,
773
+ persistLevel,
774
+ sender,
775
+ ts,
776
+ });
777
+ }, 200);
778
+ }
779
+ } catch (error) {
780
+ console.error(
781
+ LogSource.Events,
782
+ 'CUSTOM_EVENTS',
783
+ 'error while emiting event:',
784
+ error,
785
+ );
786
+ }
787
+ };
788
+
789
+ const end = async () => {
790
+ if (!callActive) {
791
+ return;
792
+ }
793
+ await RTMEngine.getInstance().destroy();
794
+ logger.log(LogSource.AgoraSDK, 'API', 'RTM destroy done');
795
+ if (isIOS() || isAndroid()) {
796
+ EventUtils.clear();
797
+ }
798
+ setHasUserJoinedRTM(false);
799
+ logger.debug(LogSource.AgoraSDK, 'Log', 'RTM cleanup done');
800
+ };
801
+
802
+ useAsyncEffect(async () => {
803
+ //waiting room attendee -> rtm login will happen on page load
804
+ if ($config.ENABLE_WAITING_ROOM) {
805
+ //attendee
806
+ //for waiting room attendee rtm login will happen on mount
807
+ if (!isHost && !callActive) {
808
+ await init();
809
+ }
810
+ //host
811
+ if (
812
+ isHost &&
813
+ ($config.AUTO_CONNECT_RTM || (!$config.AUTO_CONNECT_RTM && callActive))
814
+ ) {
815
+ await init();
816
+ }
817
+ } else {
818
+ //non waiting room case
819
+ //host and attendee
820
+ if (
821
+ $config.AUTO_CONNECT_RTM ||
822
+ (!$config.AUTO_CONNECT_RTM && callActive)
823
+ ) {
824
+ await init();
825
+ }
826
+ }
827
+ return async () => {
828
+ await end();
829
+ };
830
+ // eslint-disable-next-line react-hooks/exhaustive-deps
831
+ }, [rtcProps.channel, rtcProps.appId, callActive]);
832
+
833
+ return (
834
+ <ChatContext.Provider
835
+ value={{
836
+ isInitialQueueCompleted,
837
+ rtmInitTimstamp,
838
+ hasUserJoinedRTM,
839
+ engine: engine.current,
840
+ localUid: localUid,
841
+ onlineUsersCount,
842
+ }}>
843
+ {props.children}
844
+ </ChatContext.Provider>
845
+ );
846
+ };
847
+
848
+ export default RtmConfigure;