agora-appbuilder-core 4.1.9-beta.3 → 4.1.10-beta.1
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.
- package/package.json +2 -2
- package/template/Gulpfile.js +0 -16
- package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +1 -3
- package/template/agora-rn-uikit/src/Contexts/RtcContext.tsx +1 -2
- package/template/agora-rn-uikit/src/Reducer/index.ts +0 -2
- package/template/agora-rn-uikit/src/Rtc/Join.tsx +11 -25
- package/template/agora-rn-uikit/src/RtcConfigure.tsx +1 -14
- package/template/bridge/rtc/webNg/RtcEngine.ts +2 -2
- package/template/bridge/rtm/web/index.ts +30 -0
- package/template/customization-api/typeDefinition.ts +1 -0
- package/template/defaultConfig.js +3 -2
- package/template/global.d.ts +1 -0
- package/template/package.json +0 -2
- package/template/src/AppRoutes.tsx +3 -3
- package/template/src/ai-agent/components/ControlButtons.tsx +1 -1
- package/template/src/assets/font-styles.css +36 -0
- package/template/src/assets/fonts/icomoon.ttf +0 -0
- package/template/src/assets/selection.json +1 -1
- package/template/src/atoms/CustomIcon.tsx +8 -0
- package/template/src/atoms/Dropdown.tsx +5 -0
- package/template/src/atoms/TertiaryButton.tsx +1 -1
- package/template/src/atoms/UserAvatar.tsx +1 -1
- package/template/src/components/ChatContext.ts +5 -3
- package/template/src/components/Controls.tsx +68 -22
- package/template/src/components/DeviceConfigure.tsx +1 -1
- package/template/src/components/EventsConfigure.tsx +22 -17
- package/template/src/components/Navbar.tsx +14 -11
- package/template/src/components/RTMConfigure.tsx +31 -1036
- package/template/src/components/UserGlobalPreferenceProvider.tsx +227 -0
- package/template/src/components/beauty-effect/useBeautyEffects.tsx +50 -13
- package/template/src/components/breakout-room/BreakoutRoomPanel.tsx +58 -0
- package/template/src/components/breakout-room/context/BreakoutRoomContext.tsx +2508 -0
- package/template/src/components/breakout-room/events/BreakoutRoomEventsConfigure.tsx +272 -0
- package/template/src/components/breakout-room/events/constants.ts +17 -0
- package/template/src/components/breakout-room/hoc/BreakoutRoomNameRenderer.tsx +68 -0
- package/template/src/components/breakout-room/hooks/useBreakoutRoomExit.ts +49 -0
- package/template/src/components/breakout-room/state/reducer.ts +522 -0
- package/template/src/components/breakout-room/state/types.ts +54 -0
- package/template/src/components/breakout-room/ui/BreakoutMeetingTitle.tsx +60 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomActionMenu.tsx +136 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomAnnouncementModal.tsx +135 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomGroupSettings.tsx +588 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomMainRoomUsers.tsx +142 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomMemberActionMenu.tsx +122 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomParticipants.tsx +124 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomRaiseHand.tsx +65 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomRenameModal.tsx +227 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomSettings.tsx +140 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomTransition.tsx +52 -0
- package/template/src/components/breakout-room/ui/BreakoutRoomView.tsx +193 -0
- package/template/src/components/breakout-room/ui/ExitBreakoutRoomIconButton.tsx +79 -0
- package/template/src/components/breakout-room/ui/ParticipantManualAssignmentModal.tsx +638 -0
- package/template/src/components/breakout-room/ui/SelectParticipantAssignmentStrategy.tsx +57 -0
- package/template/src/components/chat/chatConfigure.tsx +7 -1
- package/template/src/components/chat-messages/useChatMessages.tsx +43 -11
- package/template/src/components/common/Dividers.tsx +53 -0
- package/template/src/components/controls/toolbar-items/ExitBreakoutRoomToolbarItem.tsx +13 -0
- package/template/src/components/controls/useControlPermissionMatrix.tsx +32 -4
- package/template/src/components/participants/AllHostParticipants.tsx +10 -2
- package/template/src/components/participants/Participant.tsx +7 -1
- package/template/src/components/participants/UserActionMenuOptions.tsx +12 -2
- package/template/src/components/precall/joinWaitingRoomBtn.native.tsx +12 -8
- package/template/src/components/precall/joinWaitingRoomBtn.tsx +14 -10
- package/template/src/components/raise-hand/RaiseHandButton.tsx +50 -0
- package/template/src/components/raise-hand/RaiseHandProvider.tsx +308 -0
- package/template/src/components/raise-hand/index.ts +14 -0
- package/template/src/components/recordings/RecordingsDateTable.tsx +3 -2
- package/template/src/components/room-info/useCurrentRoomInfo.tsx +42 -0
- package/template/src/components/room-info/useSetBreakoutRoomInfo.tsx +64 -0
- package/template/src/components/useUserPreference.tsx +39 -12
- package/template/src/components/virtual-background/useVB.tsx +18 -0
- package/template/src/components/whiteboard/WhiteboardConfigure.tsx +27 -0
- package/template/src/language/default-labels/videoCallScreenLabels.ts +7 -0
- package/template/src/logger/AppBuilderLogger.tsx +11 -3
- package/template/src/pages/VideoCall.tsx +171 -518
- package/template/src/pages/video-call/BreakoutVideoCall.tsx +213 -0
- package/template/src/pages/video-call/SidePanelHeader.tsx +17 -0
- package/template/src/pages/video-call/VideoCallContent.tsx +211 -0
- package/template/src/pages/video-call/VideoCallScreen.tsx +18 -0
- package/template/src/pages/video-call/VideoCallScreenWrapper.tsx +0 -1
- package/template/src/pages/video-call/VideoCallStateWrapper.tsx +495 -0
- package/template/src/rtm/RTMConfigureBreakoutRoomProvider.tsx +882 -0
- package/template/src/rtm/RTMConfigureMainRoomProvider.tsx +757 -0
- package/template/src/rtm/RTMCoreProvider.tsx +419 -0
- package/template/src/rtm/RTMEngine.ts +188 -60
- package/template/src/rtm/RTMGlobalStateProvider.tsx +706 -0
- package/template/src/rtm/RTMStatusBanner.tsx +99 -0
- package/template/src/rtm/constants.ts +12 -0
- package/template/src/rtm/hooks/useMainRoomUserDisplayName.ts +45 -0
- package/template/src/rtm/rtm-presence-utils.ts +344 -0
- package/template/src/rtm/utils.ts +68 -1
- package/template/src/rtm-events/constants.ts +40 -1
- package/template/src/rtm-events-api/Events.ts +62 -19
- package/template/src/subComponents/ChatBubble.tsx +3 -3
- package/template/src/subComponents/ChatContainer.tsx +19 -9
- package/template/src/subComponents/LocalAudioMute.tsx +2 -2
- package/template/src/subComponents/LocalVideoMute.tsx +2 -2
- package/template/src/subComponents/SidePanelEnum.tsx +1 -0
- package/template/src/subComponents/caption/useCaption.tsx +1 -1
- package/template/src/subComponents/chat/ChatAnnouncementView.tsx +65 -0
- package/template/src/subComponents/chat/ChatSendButton.tsx +1 -0
- package/template/src/subComponents/screenshare/ScreenshareButton.tsx +16 -0
- package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +1 -1
- package/template/src/subComponents/waiting-rooms/WaitingRoomControls.tsx +7 -4
- package/template/src/utils/useDebouncedCallback.tsx +20 -0
- package/template/src/utils/useEndCall.ts +0 -2
- package/template/src/utils/useMuteToggleLocal.ts +14 -10
- package/template/agora-rn-uikit/src/Reducer/Spotlight.ts +0 -11
- package/template/agora-rn-uikit/src/Reducer/UserBanned.ts +0 -11
|
@@ -0,0 +1,882 @@
|
|
|
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
|
+
|
|
13
|
+
import React, {
|
|
14
|
+
useState,
|
|
15
|
+
useContext,
|
|
16
|
+
useEffect,
|
|
17
|
+
useRef,
|
|
18
|
+
createContext,
|
|
19
|
+
useCallback,
|
|
20
|
+
} from 'react';
|
|
21
|
+
import {
|
|
22
|
+
type MessageEvent,
|
|
23
|
+
type PresenceEvent,
|
|
24
|
+
type SetOrUpdateUserMetadataOptions,
|
|
25
|
+
type StorageEvent,
|
|
26
|
+
type RTMClient,
|
|
27
|
+
} from 'agora-react-native-rtm';
|
|
28
|
+
import {
|
|
29
|
+
ContentInterface,
|
|
30
|
+
DispatchContext,
|
|
31
|
+
useLocalUid,
|
|
32
|
+
} from '../../agora-rn-uikit';
|
|
33
|
+
import {Platform} from 'react-native';
|
|
34
|
+
import {isAndroid, isIOS} from '../utils/common';
|
|
35
|
+
import {useContent} from 'customization-api';
|
|
36
|
+
import {
|
|
37
|
+
safeJsonParse,
|
|
38
|
+
timeNow,
|
|
39
|
+
hasJsonStructure,
|
|
40
|
+
getMessageTime,
|
|
41
|
+
get32BitUid,
|
|
42
|
+
isEventForActiveChannel,
|
|
43
|
+
} from '../rtm/utils';
|
|
44
|
+
import {
|
|
45
|
+
fetchChannelAttributesWithRetries,
|
|
46
|
+
clearRoomScopedUserAttributes,
|
|
47
|
+
processUserAttributeForQueue,
|
|
48
|
+
} from './rtm-presence-utils';
|
|
49
|
+
import {EventUtils, EventsQueue} from '../rtm-events';
|
|
50
|
+
import {PersistanceLevel} from '../rtm-events-api';
|
|
51
|
+
import RTMEngine from '../rtm/RTMEngine';
|
|
52
|
+
import {filterObject} from '../utils';
|
|
53
|
+
import {useAsyncEffect} from '../utils/useAsyncEffect';
|
|
54
|
+
import {
|
|
55
|
+
WaitingRoomStatus,
|
|
56
|
+
useRoomInfo,
|
|
57
|
+
} from '../components/room-info/useRoomInfo';
|
|
58
|
+
import LocalEventEmitter, {
|
|
59
|
+
LocalEventsEnum,
|
|
60
|
+
} from '../rtm-events-api/LocalEvents';
|
|
61
|
+
import {controlMessageEnum} from '../components/ChatContext';
|
|
62
|
+
import {LogSource, logger} from '../logger/AppBuilderLogger';
|
|
63
|
+
import {RECORDING_BOT_UID} from '../utils/constants';
|
|
64
|
+
import {
|
|
65
|
+
nativeChannelTypeMapping,
|
|
66
|
+
nativePresenceEventTypeMapping,
|
|
67
|
+
nativeStorageEventTypeMapping,
|
|
68
|
+
} from '../../bridge/rtm/web/Types';
|
|
69
|
+
import {useRTMCore} from '../rtm/RTMCoreProvider';
|
|
70
|
+
import {
|
|
71
|
+
RTM_ROOMS,
|
|
72
|
+
RTM_EVENTS_ATTRIBUTES_TO_RESET_WHEN_ROOM_CHANGES,
|
|
73
|
+
} from './constants';
|
|
74
|
+
import {useUserGlobalPreferences} from '../components/UserGlobalPreferenceProvider';
|
|
75
|
+
import {ToggleState} from '../../agora-rn-uikit';
|
|
76
|
+
import useMuteToggleLocal from '../utils/useMuteToggleLocal';
|
|
77
|
+
import {useRtc} from 'customization-api';
|
|
78
|
+
import {
|
|
79
|
+
fetchOnlineMembersWithRetries,
|
|
80
|
+
fetchUserAttributesWithRetries,
|
|
81
|
+
mapUserAttributesToState,
|
|
82
|
+
} from './rtm-presence-utils';
|
|
83
|
+
|
|
84
|
+
export enum UserType {
|
|
85
|
+
ScreenShare = 'screenshare',
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const eventTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
|
|
89
|
+
|
|
90
|
+
// RTM Breakout Room Context
|
|
91
|
+
export interface RTMBreakoutRoomData {
|
|
92
|
+
hasUserJoinedRTM: boolean;
|
|
93
|
+
isInitialQueueCompleted: boolean;
|
|
94
|
+
onlineUsersCount: number;
|
|
95
|
+
rtmInitTimstamp: number;
|
|
96
|
+
syncUserState: (uid: number, data: Partial<ContentInterface>) => void;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const RTMBreakoutRoomContext = createContext<RTMBreakoutRoomData>({
|
|
100
|
+
hasUserJoinedRTM: false,
|
|
101
|
+
isInitialQueueCompleted: false,
|
|
102
|
+
onlineUsersCount: 0,
|
|
103
|
+
rtmInitTimstamp: 0,
|
|
104
|
+
syncUserState: () => {},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export const useRTMConfigureBreakout = () => {
|
|
108
|
+
const context = useContext(RTMBreakoutRoomContext);
|
|
109
|
+
if (!context) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
'useRTMConfigureBreakout must be used within RTMConfigureBreakoutRoomProvider',
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
return context;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
interface RTMConfigureBreakoutRoomProviderProps {
|
|
118
|
+
callActive: boolean;
|
|
119
|
+
children: React.ReactNode;
|
|
120
|
+
currentChannel: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const RTMConfigureBreakoutRoomProvider = (
|
|
124
|
+
props: RTMConfigureBreakoutRoomProviderProps,
|
|
125
|
+
) => {
|
|
126
|
+
const rtmInitTimstamp = new Date().getTime();
|
|
127
|
+
const localUid = useLocalUid();
|
|
128
|
+
const {callActive, currentChannel} = props;
|
|
129
|
+
const {dispatch} = useContext(DispatchContext);
|
|
130
|
+
const {defaultContent, activeUids} = useContent();
|
|
131
|
+
console.log('rudra-core-client: activeUids: ', activeUids);
|
|
132
|
+
const {
|
|
133
|
+
waitingRoomStatus,
|
|
134
|
+
data: {isHost},
|
|
135
|
+
} = useRoomInfo();
|
|
136
|
+
const {applyUserPreferences, syncUserPreferences} =
|
|
137
|
+
useUserGlobalPreferences();
|
|
138
|
+
const toggleMute = useMuteToggleLocal();
|
|
139
|
+
const [hasUserJoinedRTM, setHasUserJoinedRTM] = useState<boolean>(false);
|
|
140
|
+
const [isInitialQueueCompleted, setIsInitialQueueCompleted] = useState(false);
|
|
141
|
+
const [onlineUsersCount, setTotalOnlineUsers] = useState<number>(0);
|
|
142
|
+
|
|
143
|
+
// Track RTM connection state (equivalent to v1.5x connectionState check)
|
|
144
|
+
const {client, isLoggedIn, registerCallbacks, unregisterCallbacks} =
|
|
145
|
+
useRTMCore();
|
|
146
|
+
const {rtcTracksReady} = useRtc();
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Refs
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
const isRTMMounted = useRef(true);
|
|
153
|
+
|
|
154
|
+
const hasInitRef = useRef(false);
|
|
155
|
+
const subscribeTimerRef: any = useRef(5);
|
|
156
|
+
const subscribeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(
|
|
157
|
+
null,
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
const channelAttributesTimerRef: any = useRef(5);
|
|
161
|
+
const channelAttributesTimeoutRef = useRef<ReturnType<
|
|
162
|
+
typeof setTimeout
|
|
163
|
+
> | null>(null);
|
|
164
|
+
|
|
165
|
+
const membersTimerRef: any = useRef(5);
|
|
166
|
+
const membersTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
167
|
+
|
|
168
|
+
const isHostRef = useRef({isHost: isHost});
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
isHostRef.current.isHost = isHost;
|
|
171
|
+
}, [isHost]);
|
|
172
|
+
|
|
173
|
+
const waitingRoomStatusRef = useRef({waitingRoomStatus: waitingRoomStatus});
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
waitingRoomStatusRef.current.waitingRoomStatus = waitingRoomStatus;
|
|
176
|
+
}, [waitingRoomStatus]);
|
|
177
|
+
|
|
178
|
+
const activeUidsRef = useRef({activeUids: activeUids});
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
activeUidsRef.current.activeUids = activeUids;
|
|
181
|
+
}, [activeUids]);
|
|
182
|
+
|
|
183
|
+
const defaultContentRef = useRef(defaultContent);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
defaultContentRef.current = defaultContent;
|
|
186
|
+
}, [defaultContent]);
|
|
187
|
+
|
|
188
|
+
// Apply user preferences when breakout room mounts
|
|
189
|
+
useEffect(() => {
|
|
190
|
+
if (rtcTracksReady) {
|
|
191
|
+
console.log('supriya-permissions', defaultContentRef.current[localUid]);
|
|
192
|
+
applyUserPreferences(defaultContentRef.current[localUid], toggleMute);
|
|
193
|
+
}
|
|
194
|
+
}, [rtcTracksReady]);
|
|
195
|
+
|
|
196
|
+
// Sync current audio/video state audio video changes
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
const userData = defaultContent[localUid];
|
|
199
|
+
if (rtcTracksReady && userData) {
|
|
200
|
+
console.log('UP: syncing userData: ', userData);
|
|
201
|
+
const preferences = {
|
|
202
|
+
audioMuted: userData.audio === ToggleState.disabled,
|
|
203
|
+
videoMuted: userData.video === ToggleState.disabled,
|
|
204
|
+
};
|
|
205
|
+
console.log('UP: saved preferences: ', preferences);
|
|
206
|
+
syncUserPreferences(preferences);
|
|
207
|
+
}
|
|
208
|
+
}, [defaultContent, localUid, syncUserPreferences, rtcTracksReady]);
|
|
209
|
+
|
|
210
|
+
const syncUserState = useCallback(
|
|
211
|
+
(uid: number, data: Partial<ContentInterface>) => {
|
|
212
|
+
dispatch({type: 'UpdateRenderList', value: [uid, data]});
|
|
213
|
+
},
|
|
214
|
+
[dispatch],
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// Set online users
|
|
218
|
+
React.useEffect(() => {
|
|
219
|
+
setTotalOnlineUsers(
|
|
220
|
+
Object.keys(
|
|
221
|
+
filterObject(
|
|
222
|
+
defaultContent,
|
|
223
|
+
([k, v]) =>
|
|
224
|
+
v?.type === 'rtc' &&
|
|
225
|
+
!v.offline &&
|
|
226
|
+
activeUidsRef.current.activeUids.indexOf(v?.uid) !== -1,
|
|
227
|
+
),
|
|
228
|
+
).length,
|
|
229
|
+
);
|
|
230
|
+
}, [defaultContent, activeUids]);
|
|
231
|
+
|
|
232
|
+
const init = async () => {
|
|
233
|
+
await subscribeChannel();
|
|
234
|
+
await getMembersWithAttributes();
|
|
235
|
+
await getChannelAttributes();
|
|
236
|
+
const result = await RTMEngine.getInstance().engine.presence.whereNow(
|
|
237
|
+
`${localUid}`,
|
|
238
|
+
);
|
|
239
|
+
console.log('rudra-core-client: user is now at channels ', result);
|
|
240
|
+
setHasUserJoinedRTM(true);
|
|
241
|
+
await runQueuedEvents();
|
|
242
|
+
setIsInitialQueueCompleted(true);
|
|
243
|
+
logger.log(LogSource.AgoraSDK, 'Log', 'RTM queued events finished running');
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const subscribeChannel = async () => {
|
|
247
|
+
try {
|
|
248
|
+
if (RTMEngine.getInstance().allChannelIds.includes(currentChannel)) {
|
|
249
|
+
logger.debug(
|
|
250
|
+
LogSource.AgoraSDK,
|
|
251
|
+
'Log',
|
|
252
|
+
'🚫 RTM already subscribed channel skipping',
|
|
253
|
+
currentChannel,
|
|
254
|
+
);
|
|
255
|
+
const channelids = RTMEngine.getInstance().allChannelIds;
|
|
256
|
+
console.log('rudra-core-client: alreadt subscribed', channelids);
|
|
257
|
+
} else {
|
|
258
|
+
await client.subscribe(currentChannel, {
|
|
259
|
+
withMessage: true,
|
|
260
|
+
withPresence: true,
|
|
261
|
+
withMetadata: true,
|
|
262
|
+
withLock: false,
|
|
263
|
+
});
|
|
264
|
+
logger.log(LogSource.AgoraSDK, 'API', 'RTM subscribeChannel', {
|
|
265
|
+
data: currentChannel,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// Set channel ID AFTER successful subscribe (like v1.5x)
|
|
269
|
+
console.log('setting primary channel', currentChannel);
|
|
270
|
+
RTMEngine.getInstance().addChannel(RTM_ROOMS.BREAKOUT, currentChannel);
|
|
271
|
+
RTMEngine.getInstance().setActiveChannelName(RTM_ROOMS.BREAKOUT);
|
|
272
|
+
|
|
273
|
+
// Clear any pending retry timeout since we succeeded
|
|
274
|
+
if (subscribeTimeoutRef.current) {
|
|
275
|
+
clearTimeout(subscribeTimeoutRef.current);
|
|
276
|
+
subscribeTimeoutRef.current = null;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} catch (error) {
|
|
280
|
+
logger.error(
|
|
281
|
+
LogSource.AgoraSDK,
|
|
282
|
+
'Log',
|
|
283
|
+
'RTM subscribeChannel failed..Trying again',
|
|
284
|
+
{error},
|
|
285
|
+
);
|
|
286
|
+
subscribeTimeoutRef.current = setTimeout(async () => {
|
|
287
|
+
// Cap the timer to prevent excessive delays (max 30 seconds)
|
|
288
|
+
subscribeTimerRef.current = Math.min(subscribeTimerRef.current * 2, 30);
|
|
289
|
+
subscribeChannel();
|
|
290
|
+
}, subscribeTimerRef.current * 1000);
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const getMembersWithAttributes = async () => {
|
|
295
|
+
try {
|
|
296
|
+
logger.log(
|
|
297
|
+
LogSource.AgoraSDK,
|
|
298
|
+
'API',
|
|
299
|
+
'RTM presence.getOnlineUsers(getMembers) start',
|
|
300
|
+
);
|
|
301
|
+
console.log(
|
|
302
|
+
'rudra-core-client: fetchOnlineMembersWithRetries inside breakout room ',
|
|
303
|
+
client,
|
|
304
|
+
currentChannel,
|
|
305
|
+
);
|
|
306
|
+
const {allMembers, totalOccupancy} = await fetchOnlineMembersWithRetries(
|
|
307
|
+
client,
|
|
308
|
+
currentChannel,
|
|
309
|
+
{
|
|
310
|
+
onPage: async ({occupants, pageToken}) => {
|
|
311
|
+
console.log(
|
|
312
|
+
'rudra-core-client: fetching user attributes for page: ',
|
|
313
|
+
pageToken,
|
|
314
|
+
occupants,
|
|
315
|
+
);
|
|
316
|
+
await Promise.all(
|
|
317
|
+
occupants.map(async member => {
|
|
318
|
+
try {
|
|
319
|
+
const userAttributes = await fetchUserAttributesWithRetries(
|
|
320
|
+
client,
|
|
321
|
+
member.userId,
|
|
322
|
+
{
|
|
323
|
+
isMounted: () => isRTMMounted.current,
|
|
324
|
+
// 👈 called later if name arrives
|
|
325
|
+
onNameFound: retriedAttributesWithName =>
|
|
326
|
+
mapUserAttributesToState(
|
|
327
|
+
retriedAttributesWithName,
|
|
328
|
+
member.userId,
|
|
329
|
+
syncUserState,
|
|
330
|
+
),
|
|
331
|
+
},
|
|
332
|
+
);
|
|
333
|
+
console.log(
|
|
334
|
+
`rudra-core-client: getting user attributes for user ${member.userId}`,
|
|
335
|
+
userAttributes,
|
|
336
|
+
);
|
|
337
|
+
mapUserAttributesToState(
|
|
338
|
+
userAttributes,
|
|
339
|
+
member.userId,
|
|
340
|
+
syncUserState,
|
|
341
|
+
);
|
|
342
|
+
// setting screenshare data
|
|
343
|
+
// name of the screenUid, isActive: false, (when the user starts screensharing it becomes true)
|
|
344
|
+
// isActive to identify all active screenshare users in the call
|
|
345
|
+
userAttributes?.items?.forEach(item => {
|
|
346
|
+
processUserAttributeForQueue(
|
|
347
|
+
item,
|
|
348
|
+
member.userId,
|
|
349
|
+
RTM_ROOMS.BREAKOUT,
|
|
350
|
+
(eventKey, value, userId) => {
|
|
351
|
+
const data = {evt: eventKey, value};
|
|
352
|
+
EventsQueue.enqueue({
|
|
353
|
+
data,
|
|
354
|
+
uid: userId,
|
|
355
|
+
ts: timeNow(),
|
|
356
|
+
});
|
|
357
|
+
},
|
|
358
|
+
);
|
|
359
|
+
});
|
|
360
|
+
} catch (e) {
|
|
361
|
+
logger.error(
|
|
362
|
+
LogSource.AgoraSDK,
|
|
363
|
+
'Log',
|
|
364
|
+
`RTM Could not retrieve name of ${member.userId}`,
|
|
365
|
+
{error: e},
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
}),
|
|
369
|
+
);
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
);
|
|
373
|
+
console.log(
|
|
374
|
+
'rudra-core-client: totalOccupancy',
|
|
375
|
+
allMembers,
|
|
376
|
+
totalOccupancy,
|
|
377
|
+
);
|
|
378
|
+
logger.debug(
|
|
379
|
+
LogSource.AgoraSDK,
|
|
380
|
+
'Log',
|
|
381
|
+
'RTM fetched all data and user attr...RTM init done',
|
|
382
|
+
);
|
|
383
|
+
membersTimerRef.current = 5;
|
|
384
|
+
// Clear any pending retry timeout since we succeeded
|
|
385
|
+
if (membersTimeoutRef.current) {
|
|
386
|
+
clearTimeout(membersTimeoutRef.current);
|
|
387
|
+
membersTimeoutRef.current = null;
|
|
388
|
+
}
|
|
389
|
+
} catch (error) {
|
|
390
|
+
membersTimeoutRef.current = setTimeout(async () => {
|
|
391
|
+
// Cap the timer to prevent excessive delays (max 30 seconds)
|
|
392
|
+
membersTimerRef.current = Math.min(membersTimerRef.current * 2, 30);
|
|
393
|
+
await getMembersWithAttributes();
|
|
394
|
+
}, membersTimerRef.current * 1000);
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const getChannelAttributes = async () => {
|
|
399
|
+
try {
|
|
400
|
+
await fetchChannelAttributesWithRetries(
|
|
401
|
+
client,
|
|
402
|
+
currentChannel,
|
|
403
|
+
eventData => EventsQueue.enqueue(eventData),
|
|
404
|
+
);
|
|
405
|
+
channelAttributesTimerRef.current = 5;
|
|
406
|
+
// Clear any pending retry timeout since we succeeded
|
|
407
|
+
if (channelAttributesTimeoutRef.current) {
|
|
408
|
+
clearTimeout(channelAttributesTimeoutRef.current);
|
|
409
|
+
channelAttributesTimeoutRef.current = null;
|
|
410
|
+
}
|
|
411
|
+
} catch (error) {
|
|
412
|
+
channelAttributesTimeoutRef.current = setTimeout(async () => {
|
|
413
|
+
// Cap the timer to prevent excessive delays (max 30 seconds)
|
|
414
|
+
channelAttributesTimerRef.current = Math.min(
|
|
415
|
+
channelAttributesTimerRef.current * 2,
|
|
416
|
+
30,
|
|
417
|
+
);
|
|
418
|
+
getChannelAttributes();
|
|
419
|
+
}, channelAttributesTimerRef.current * 1000);
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
const runQueuedEvents = async () => {
|
|
424
|
+
try {
|
|
425
|
+
while (!EventsQueue.isEmpty()) {
|
|
426
|
+
const currEvt = EventsQueue.dequeue();
|
|
427
|
+
await eventDispatcher(currEvt.data, `${currEvt.uid}`, currEvt.ts);
|
|
428
|
+
}
|
|
429
|
+
} catch (error) {
|
|
430
|
+
logger.error(
|
|
431
|
+
LogSource.Events,
|
|
432
|
+
'CUSTOM_EVENTS',
|
|
433
|
+
'error while running queue events',
|
|
434
|
+
{error},
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
const eventDispatcher = async (
|
|
440
|
+
data: {
|
|
441
|
+
evt: string;
|
|
442
|
+
value: string;
|
|
443
|
+
feat?: string;
|
|
444
|
+
etyp?: string;
|
|
445
|
+
},
|
|
446
|
+
sender: string,
|
|
447
|
+
ts: number,
|
|
448
|
+
) => {
|
|
449
|
+
console.log(
|
|
450
|
+
LogSource.Events,
|
|
451
|
+
'CUSTOM_EVENTS',
|
|
452
|
+
'inside eventDispatcher ',
|
|
453
|
+
data,
|
|
454
|
+
);
|
|
455
|
+
console.log('supriya rtm [BREAKOUT] dispatcher: ', data);
|
|
456
|
+
|
|
457
|
+
let evt = '',
|
|
458
|
+
value = '';
|
|
459
|
+
|
|
460
|
+
if (data?.feat === 'BREAKOUT_ROOM') {
|
|
461
|
+
const outputData = {
|
|
462
|
+
evt: `${data.feat}_${data.etyp}`,
|
|
463
|
+
payload: JSON.stringify({
|
|
464
|
+
data: data.data,
|
|
465
|
+
action: data.act,
|
|
466
|
+
}),
|
|
467
|
+
persistLevel: 1,
|
|
468
|
+
source: 'core',
|
|
469
|
+
};
|
|
470
|
+
const formattedData = JSON.stringify(outputData);
|
|
471
|
+
evt = data.feat + '_' + data.etyp;
|
|
472
|
+
value = formattedData;
|
|
473
|
+
} else if (data?.feat === 'WAITING_ROOM') {
|
|
474
|
+
if (data?.etyp === 'REQUEST') {
|
|
475
|
+
const outputData = {
|
|
476
|
+
evt: `${data.feat}_${data.etyp}`,
|
|
477
|
+
payload: JSON.stringify({
|
|
478
|
+
attendee_uid: data.data.data.attendee_uid,
|
|
479
|
+
attendee_screenshare_uid: data.data.data.attendee_screenshare_uid,
|
|
480
|
+
}),
|
|
481
|
+
persistLevel: 1,
|
|
482
|
+
source: 'core',
|
|
483
|
+
};
|
|
484
|
+
const formattedData = JSON.stringify(outputData);
|
|
485
|
+
evt = data.feat + '_' + data.etyp;
|
|
486
|
+
value = formattedData;
|
|
487
|
+
}
|
|
488
|
+
if (data?.etyp === 'RESPONSE') {
|
|
489
|
+
const outputData = {
|
|
490
|
+
evt: `${data.feat}_${data.etyp}`,
|
|
491
|
+
payload: JSON.stringify({
|
|
492
|
+
approved: data.data.data.approved,
|
|
493
|
+
channelName: data.data.data.channel_name,
|
|
494
|
+
mainUser: data.data.data.mainUser,
|
|
495
|
+
screenShare: data.data.data.screenShare,
|
|
496
|
+
whiteboard: data.data.data.whiteboard,
|
|
497
|
+
chat: data.data.data?.chat,
|
|
498
|
+
}),
|
|
499
|
+
persistLevel: 1,
|
|
500
|
+
source: 'core',
|
|
501
|
+
};
|
|
502
|
+
const formattedData = JSON.stringify(outputData);
|
|
503
|
+
evt = data.feat + '_' + data.etyp;
|
|
504
|
+
value = formattedData;
|
|
505
|
+
}
|
|
506
|
+
} else {
|
|
507
|
+
if (
|
|
508
|
+
$config.ENABLE_WAITING_ROOM &&
|
|
509
|
+
!isHostRef.current?.isHost &&
|
|
510
|
+
waitingRoomStatusRef.current?.waitingRoomStatus !==
|
|
511
|
+
WaitingRoomStatus.APPROVED
|
|
512
|
+
) {
|
|
513
|
+
if (
|
|
514
|
+
data.evt === controlMessageEnum.muteAudio ||
|
|
515
|
+
data.evt === controlMessageEnum.muteVideo
|
|
516
|
+
) {
|
|
517
|
+
return;
|
|
518
|
+
} else {
|
|
519
|
+
evt = data.evt;
|
|
520
|
+
value = data.value;
|
|
521
|
+
}
|
|
522
|
+
} else {
|
|
523
|
+
evt = data.evt;
|
|
524
|
+
value = data.value;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
try {
|
|
529
|
+
let parsedValue;
|
|
530
|
+
try {
|
|
531
|
+
parsedValue = typeof value === 'string' ? JSON.parse(value) : value;
|
|
532
|
+
} catch (error) {
|
|
533
|
+
logger.error(
|
|
534
|
+
LogSource.Events,
|
|
535
|
+
'CUSTOM_EVENTS',
|
|
536
|
+
'RTM Failed to parse event value in event dispatcher:',
|
|
537
|
+
{error},
|
|
538
|
+
);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
const {payload, persistLevel, source, _scope, _channelId} = parsedValue;
|
|
542
|
+
|
|
543
|
+
console.log('supriya rtm [BREAKOUT] event data', data);
|
|
544
|
+
console.log(
|
|
545
|
+
'supriya rtm [BREAKOUT] _scope and _channelId: ',
|
|
546
|
+
_scope,
|
|
547
|
+
_channelId,
|
|
548
|
+
currentChannel,
|
|
549
|
+
);
|
|
550
|
+
// Filter if its for this channel
|
|
551
|
+
if (!isEventForActiveChannel(_scope, _channelId, currentChannel)) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Step 1: Set local attributes
|
|
556
|
+
if (persistLevel === PersistanceLevel.Session) {
|
|
557
|
+
// const roomKey = RTM_ROOMS.BREAKOUT;
|
|
558
|
+
// const roomAwareKey = `${roomKey}_${evt}`;
|
|
559
|
+
const rtmAttribute = {key: evt, value: value};
|
|
560
|
+
const options: SetOrUpdateUserMetadataOptions = {
|
|
561
|
+
userId: `${localUid}`,
|
|
562
|
+
};
|
|
563
|
+
await client.storage.setUserMetadata(
|
|
564
|
+
{
|
|
565
|
+
items: [rtmAttribute],
|
|
566
|
+
},
|
|
567
|
+
options,
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
// Step 2: Emit the event
|
|
571
|
+
console.log(LogSource.Events, 'CUSTOM_EVENTS', 'emiting event..: ', evt);
|
|
572
|
+
EventUtils.emitEvent(evt, source, {payload, persistLevel, sender, ts});
|
|
573
|
+
// Because async gets evaluated in a different order when in an sdk
|
|
574
|
+
if (evt === 'name') {
|
|
575
|
+
// 1. Cancel existing timeout for this sender
|
|
576
|
+
if (eventTimeouts.has(sender)) {
|
|
577
|
+
clearTimeout(eventTimeouts.get(sender)!);
|
|
578
|
+
}
|
|
579
|
+
// 2. Create new timeout with tracking
|
|
580
|
+
const timeout = setTimeout(() => {
|
|
581
|
+
// 3. Guard against unmounted component
|
|
582
|
+
if (!isRTMMounted.current) {
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
EventUtils.emitEvent(evt, source, {
|
|
586
|
+
payload,
|
|
587
|
+
persistLevel,
|
|
588
|
+
sender,
|
|
589
|
+
ts,
|
|
590
|
+
});
|
|
591
|
+
// 4. Clean up after execution
|
|
592
|
+
eventTimeouts.delete(sender);
|
|
593
|
+
}, 200);
|
|
594
|
+
// 5. Track the timeout for cleanup
|
|
595
|
+
eventTimeouts.set(sender, timeout);
|
|
596
|
+
}
|
|
597
|
+
} catch (error) {
|
|
598
|
+
console.error(
|
|
599
|
+
LogSource.Events,
|
|
600
|
+
'CUSTOM_EVENTS',
|
|
601
|
+
'error while emiting event:',
|
|
602
|
+
{error},
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
// Listeners
|
|
608
|
+
const handleStorageEvent = (storage: StorageEvent) => {
|
|
609
|
+
// when remote user sets/updates metadata - 3
|
|
610
|
+
if (
|
|
611
|
+
storage.eventType === nativeStorageEventTypeMapping.SET ||
|
|
612
|
+
storage.eventType === nativeStorageEventTypeMapping.UPDATE
|
|
613
|
+
) {
|
|
614
|
+
const storageTypeStr = storage.storageType === 1 ? 'user' : 'channel';
|
|
615
|
+
const eventTypeStr = storage.eventType === 2 ? 'SET' : 'UPDATE';
|
|
616
|
+
logger.log(
|
|
617
|
+
LogSource.AgoraSDK,
|
|
618
|
+
'Event',
|
|
619
|
+
`RTM storage event of type: [${eventTypeStr} ${storageTypeStr} metadata]`,
|
|
620
|
+
storage,
|
|
621
|
+
);
|
|
622
|
+
try {
|
|
623
|
+
if (storage.data?.items && Array.isArray(storage.data.items)) {
|
|
624
|
+
storage.data.items.forEach(item => {
|
|
625
|
+
try {
|
|
626
|
+
if (!item || !item.key) {
|
|
627
|
+
logger.warn(
|
|
628
|
+
LogSource.Events,
|
|
629
|
+
'CUSTOM_EVENTS',
|
|
630
|
+
'Invalid storage item:',
|
|
631
|
+
item,
|
|
632
|
+
);
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
const {key, value, authorUserId, updateTs} = item;
|
|
637
|
+
console.log('supriya-eventDispatcher item: ', item);
|
|
638
|
+
const timestamp = getMessageTime(updateTs);
|
|
639
|
+
const sender = Platform.OS
|
|
640
|
+
? get32BitUid(authorUserId)
|
|
641
|
+
: parseInt(authorUserId, 10);
|
|
642
|
+
eventDispatcher(
|
|
643
|
+
{
|
|
644
|
+
evt: key,
|
|
645
|
+
value,
|
|
646
|
+
},
|
|
647
|
+
`${sender}`,
|
|
648
|
+
timestamp,
|
|
649
|
+
);
|
|
650
|
+
} catch (error) {
|
|
651
|
+
logger.error(
|
|
652
|
+
LogSource.Events,
|
|
653
|
+
'CUSTOM_EVENTS',
|
|
654
|
+
`Failed to process storage item: ${JSON.stringify(item)}`,
|
|
655
|
+
{error},
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
} catch (error) {
|
|
661
|
+
logger.error(
|
|
662
|
+
LogSource.Events,
|
|
663
|
+
'CUSTOM_EVENTS',
|
|
664
|
+
'error while dispatching through eventDispatcher',
|
|
665
|
+
{error},
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const handlePresenceEvent = async (presence: PresenceEvent) => {
|
|
672
|
+
if (presence.type === nativePresenceEventTypeMapping.REMOTE_JOIN) {
|
|
673
|
+
logger.log(
|
|
674
|
+
LogSource.AgoraSDK,
|
|
675
|
+
'Event',
|
|
676
|
+
'RTM presenceEvent of type [3 - remoteJoin] (channelMemberJoined)',
|
|
677
|
+
);
|
|
678
|
+
const useAttributes = await fetchUserAttributesWithRetries(
|
|
679
|
+
client,
|
|
680
|
+
presence.publisher,
|
|
681
|
+
{
|
|
682
|
+
isMounted: () => isRTMMounted.current,
|
|
683
|
+
// This is called later if name arrives and hence we process that attribute
|
|
684
|
+
onNameFound: retriedAttributesWithName =>
|
|
685
|
+
mapUserAttributesToState(
|
|
686
|
+
retriedAttributesWithName,
|
|
687
|
+
presence.publisher,
|
|
688
|
+
syncUserState,
|
|
689
|
+
),
|
|
690
|
+
},
|
|
691
|
+
);
|
|
692
|
+
// This is called as soon as we receive any attributes
|
|
693
|
+
mapUserAttributesToState(
|
|
694
|
+
useAttributes,
|
|
695
|
+
presence.publisher,
|
|
696
|
+
syncUserState,
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
// remoteLeaveChannel
|
|
700
|
+
if (presence.type === nativePresenceEventTypeMapping.REMOTE_LEAVE) {
|
|
701
|
+
logger.log(
|
|
702
|
+
LogSource.AgoraSDK,
|
|
703
|
+
'Event',
|
|
704
|
+
'RTM presenceEvent of type [4 - remoteLeave] (channelMemberLeft)',
|
|
705
|
+
presence,
|
|
706
|
+
);
|
|
707
|
+
// Chat of left user becomes undefined. So don't cleanup
|
|
708
|
+
const uid = presence?.publisher
|
|
709
|
+
? parseInt(presence.publisher, 10)
|
|
710
|
+
: undefined;
|
|
711
|
+
|
|
712
|
+
if (!uid) {
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
// updating the rtc data
|
|
716
|
+
syncUserState(uid, {
|
|
717
|
+
offline: true,
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
};
|
|
721
|
+
|
|
722
|
+
const handleMessageEvent = (message: MessageEvent) => {
|
|
723
|
+
console.log('supriya current message channel: ', currentChannel);
|
|
724
|
+
console.log('supriya message event is', message);
|
|
725
|
+
// message - 1 (channel)
|
|
726
|
+
if (message.channelType === nativeChannelTypeMapping.MESSAGE) {
|
|
727
|
+
// here the channel name will be the channel name
|
|
728
|
+
logger.debug(
|
|
729
|
+
LogSource.Events,
|
|
730
|
+
'CUSTOM_EVENTS',
|
|
731
|
+
'messageEvent of type [1 - CHANNEL] (channelMessageReceived)',
|
|
732
|
+
message,
|
|
733
|
+
);
|
|
734
|
+
const {publisher: uid, message: text, timestamp: ts} = message;
|
|
735
|
+
//whiteboard upload
|
|
736
|
+
if (parseInt(uid, 10) === 1010101) {
|
|
737
|
+
const [err, res] = safeJsonParse(text);
|
|
738
|
+
if (err) {
|
|
739
|
+
logger.error(
|
|
740
|
+
LogSource.Events,
|
|
741
|
+
'CUSTOM_EVENTS',
|
|
742
|
+
'JSON payload incorrect, Error while parsing the payload',
|
|
743
|
+
{error: err},
|
|
744
|
+
);
|
|
745
|
+
}
|
|
746
|
+
if (res?.data?.data?.images) {
|
|
747
|
+
LocalEventEmitter.emit(
|
|
748
|
+
LocalEventsEnum.WHITEBOARD_FILE_UPLOAD,
|
|
749
|
+
res?.data?.data?.images,
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
} else {
|
|
753
|
+
const [err, msg] = safeJsonParse(text);
|
|
754
|
+
if (err) {
|
|
755
|
+
logger.error(
|
|
756
|
+
LogSource.Events,
|
|
757
|
+
'CUSTOM_EVENTS',
|
|
758
|
+
'JSON payload incorrect, Error while parsing the payload',
|
|
759
|
+
{error: err},
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
const timestamp = getMessageTime(ts);
|
|
764
|
+
const sender = Platform.OS ? get32BitUid(uid) : parseInt(uid, 10);
|
|
765
|
+
try {
|
|
766
|
+
eventDispatcher(msg, `${sender}`, timestamp);
|
|
767
|
+
} catch (error) {
|
|
768
|
+
logger.error(
|
|
769
|
+
LogSource.Events,
|
|
770
|
+
'CUSTOM_EVENTS',
|
|
771
|
+
'error while dispatching through eventDispatcher',
|
|
772
|
+
{error},
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// message - 3 (user)
|
|
779
|
+
if (message.channelType === nativeChannelTypeMapping.USER) {
|
|
780
|
+
logger.debug(
|
|
781
|
+
LogSource.Events,
|
|
782
|
+
'CUSTOM_EVENTS',
|
|
783
|
+
'messageEvent of type [3- USER] (messageReceived)',
|
|
784
|
+
message,
|
|
785
|
+
);
|
|
786
|
+
// here the (message.channelname) channel name will be the to UID
|
|
787
|
+
const {publisher: peerId, timestamp: ts, message: text} = message;
|
|
788
|
+
const [err, msg] = safeJsonParse(text);
|
|
789
|
+
if (err) {
|
|
790
|
+
logger.error(
|
|
791
|
+
LogSource.Events,
|
|
792
|
+
'CUSTOM_EVENTS',
|
|
793
|
+
'JSON payload incorrect, Error while parsing the payload',
|
|
794
|
+
{error: err},
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const timestamp = getMessageTime(ts);
|
|
799
|
+
|
|
800
|
+
const sender = isAndroid() ? get32BitUid(peerId) : parseInt(peerId, 10);
|
|
801
|
+
|
|
802
|
+
try {
|
|
803
|
+
eventDispatcher(msg, `${sender}`, timestamp);
|
|
804
|
+
} catch (error) {
|
|
805
|
+
logger.error(
|
|
806
|
+
LogSource.Events,
|
|
807
|
+
'CUSTOM_EVENTS',
|
|
808
|
+
'error while dispatching through eventDispatcher',
|
|
809
|
+
{error},
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
const unsubscribeAndCleanup = async (
|
|
816
|
+
currentClient: RTMClient,
|
|
817
|
+
channel: string,
|
|
818
|
+
) => {
|
|
819
|
+
try {
|
|
820
|
+
setHasUserJoinedRTM(false);
|
|
821
|
+
setIsInitialQueueCompleted(false);
|
|
822
|
+
currentClient.unsubscribe(channel);
|
|
823
|
+
RTMEngine.getInstance().removeChannel(RTM_ROOMS.BREAKOUT);
|
|
824
|
+
logger.log(LogSource.AgoraSDK, 'API', 'RTM destroy done');
|
|
825
|
+
if (isIOS() || isAndroid()) {
|
|
826
|
+
EventUtils.clear();
|
|
827
|
+
}
|
|
828
|
+
logger.debug(LogSource.AgoraSDK, 'Log', 'RTM cleanup done');
|
|
829
|
+
} catch (unsubscribeError) {
|
|
830
|
+
console.log('supriya error while unsubscribing: ', unsubscribeError);
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
|
|
834
|
+
useAsyncEffect(async () => {
|
|
835
|
+
try {
|
|
836
|
+
if (client && isLoggedIn && callActive && currentChannel) {
|
|
837
|
+
hasInitRef.current = true;
|
|
838
|
+
registerCallbacks(currentChannel, {
|
|
839
|
+
storage: handleStorageEvent,
|
|
840
|
+
presence: handlePresenceEvent,
|
|
841
|
+
message: handleMessageEvent,
|
|
842
|
+
});
|
|
843
|
+
await init();
|
|
844
|
+
}
|
|
845
|
+
} catch (error) {
|
|
846
|
+
logger.error(LogSource.AgoraSDK, 'Log', 'RTM init failed', {error});
|
|
847
|
+
}
|
|
848
|
+
return async () => {
|
|
849
|
+
console.log('rudra-core-client: cleaning up for channel', currentChannel);
|
|
850
|
+
const currentClient = RTMEngine.getInstance().engine;
|
|
851
|
+
hasInitRef.current = false;
|
|
852
|
+
isRTMMounted.current = false;
|
|
853
|
+
// Clear all pending timeouts on unmount
|
|
854
|
+
for (const timeout of eventTimeouts.values()) {
|
|
855
|
+
clearTimeout(timeout);
|
|
856
|
+
}
|
|
857
|
+
eventTimeouts.clear();
|
|
858
|
+
if (currentChannel) {
|
|
859
|
+
unregisterCallbacks(currentChannel);
|
|
860
|
+
}
|
|
861
|
+
if (currentClient && callActive && isLoggedIn) {
|
|
862
|
+
await unsubscribeAndCleanup(currentClient, currentChannel);
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
}, [isLoggedIn, callActive, currentChannel, client]);
|
|
866
|
+
|
|
867
|
+
const contextValue: RTMBreakoutRoomData = {
|
|
868
|
+
hasUserJoinedRTM,
|
|
869
|
+
isInitialQueueCompleted,
|
|
870
|
+
onlineUsersCount,
|
|
871
|
+
rtmInitTimstamp,
|
|
872
|
+
syncUserState,
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
return (
|
|
876
|
+
<RTMBreakoutRoomContext.Provider value={contextValue}>
|
|
877
|
+
{props.children}
|
|
878
|
+
</RTMBreakoutRoomContext.Provider>
|
|
879
|
+
);
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
export default RTMConfigureBreakoutRoomProvider;
|