agora-appbuilder-core 4.1.8 → 4.1.9-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 +1 -1
- package/template/android/app/build.gradle +7 -0
- package/template/bridge/rtm/web/Types.ts +183 -0
- package/template/bridge/rtm/web/index-legacy.ts +540 -0
- package/template/bridge/rtm/web/index.ts +423 -491
- package/template/defaultConfig.js +3 -3
- package/template/ios/Podfile +41 -0
- package/template/package.json +4 -4
- package/template/src/atoms/TextInput.tsx +3 -0
- package/template/src/components/RTMConfigure-legacy.tsx +848 -0
- package/template/src/components/RTMConfigure.tsx +644 -426
- package/template/src/rtm/RTMEngine.ts +130 -33
- package/template/src/rtm-events-api/Events.ts +106 -30
- package/template/src/subComponents/ChatInput.tsx +72 -1
- package/template/src/subComponents/caption/useSTTAPI.tsx +2 -2
- package/template/src/subComponents/caption/utils.ts +50 -14
- package/template/src/utils/useEndCall.ts +1 -1
- package/template/src/utils/useJoinRoom.ts +0 -1
|
@@ -9,21 +9,32 @@
|
|
|
9
9
|
information visit https://appbuilder.agora.io.
|
|
10
10
|
*********************************************
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
import React, {useState, useContext, useEffect, useRef} from 'react';
|
|
14
|
-
import
|
|
14
|
+
import {
|
|
15
|
+
type GetChannelMetadataResponse,
|
|
16
|
+
type GetOnlineUsersResponse,
|
|
17
|
+
type LinkStateEvent,
|
|
18
|
+
type MessageEvent,
|
|
19
|
+
type Metadata,
|
|
20
|
+
type PresenceEvent,
|
|
21
|
+
type SetOrUpdateUserMetadataOptions,
|
|
22
|
+
type StorageEvent,
|
|
23
|
+
type RTMClient,
|
|
24
|
+
type GetUserMetadataResponse,
|
|
25
|
+
} from 'agora-react-native-rtm';
|
|
15
26
|
import {
|
|
16
27
|
ContentInterface,
|
|
17
28
|
DispatchContext,
|
|
18
29
|
PropsContext,
|
|
30
|
+
UidType,
|
|
19
31
|
useLocalUid,
|
|
20
32
|
} from '../../agora-rn-uikit';
|
|
21
33
|
import ChatContext from './ChatContext';
|
|
22
34
|
import {Platform} from 'react-native';
|
|
23
35
|
import {backOff} from 'exponential-backoff';
|
|
24
|
-
import {useString} from '../utils/useString';
|
|
25
36
|
import {isAndroid, isIOS, isWeb, isWebInternal} from '../utils/common';
|
|
26
|
-
import {useContent
|
|
37
|
+
import {useContent} from 'customization-api';
|
|
27
38
|
import {
|
|
28
39
|
safeJsonParse,
|
|
29
40
|
timeNow,
|
|
@@ -31,8 +42,8 @@ import {
|
|
|
31
42
|
getMessageTime,
|
|
32
43
|
get32BitUid,
|
|
33
44
|
} from '../rtm/utils';
|
|
34
|
-
import {EventUtils, EventsQueue
|
|
35
|
-
import
|
|
45
|
+
import {EventUtils, EventsQueue} from '../rtm-events';
|
|
46
|
+
import {PersistanceLevel} from '../rtm-events-api';
|
|
36
47
|
import RTMEngine from '../rtm/RTMEngine';
|
|
37
48
|
import {filterObject} from '../utils';
|
|
38
49
|
import SDKEvents from '../utils/SdkEvents';
|
|
@@ -45,60 +56,79 @@ import {
|
|
|
45
56
|
import LocalEventEmitter, {
|
|
46
57
|
LocalEventsEnum,
|
|
47
58
|
} from '../rtm-events-api/LocalEvents';
|
|
48
|
-
import {PSTNUserLabel} from '../language/default-labels/videoCallScreenLabels';
|
|
49
59
|
import {controlMessageEnum} from '../components/ChatContext';
|
|
50
60
|
import {LogSource, logger} from '../logger/AppBuilderLogger';
|
|
51
61
|
import {RECORDING_BOT_UID} from '../utils/constants';
|
|
62
|
+
import {
|
|
63
|
+
nativeChannelTypeMapping,
|
|
64
|
+
nativeLinkStateMapping,
|
|
65
|
+
nativePresenceEventTypeMapping,
|
|
66
|
+
nativeStorageEventTypeMapping,
|
|
67
|
+
} from '../../bridge/rtm/web/Types';
|
|
52
68
|
|
|
53
69
|
export enum UserType {
|
|
54
70
|
ScreenShare = 'screenshare',
|
|
55
71
|
}
|
|
56
72
|
|
|
73
|
+
const eventTimeouts = new Map<string, ReturnType<typeof setTimeout>>();
|
|
74
|
+
|
|
57
75
|
const RtmConfigure = (props: any) => {
|
|
76
|
+
let engine = useRef<RTMClient>(null!);
|
|
58
77
|
const rtmInitTimstamp = new Date().getTime();
|
|
59
78
|
const localUid = useLocalUid();
|
|
60
79
|
const {callActive} = props;
|
|
61
80
|
const {rtcProps} = useContext(PropsContext);
|
|
62
81
|
const {dispatch} = useContext(DispatchContext);
|
|
63
82
|
const {defaultContent, activeUids} = useContent();
|
|
64
|
-
const defaultContentRef = useRef({defaultContent: defaultContent});
|
|
65
|
-
const activeUidsRef = useRef({activeUids: activeUids});
|
|
66
|
-
|
|
67
83
|
const {
|
|
68
84
|
waitingRoomStatus,
|
|
69
85
|
data: {isHost},
|
|
70
86
|
} = useRoomInfo();
|
|
71
|
-
const
|
|
87
|
+
const [hasUserJoinedRTM, setHasUserJoinedRTM] = useState<boolean>(false);
|
|
88
|
+
const [isInitialQueueCompleted, setIsInitialQueueCompleted] = useState(false);
|
|
89
|
+
const [onlineUsersCount, setTotalOnlineUsers] = useState<number>(0);
|
|
90
|
+
const timerValueRef: any = useRef(5);
|
|
91
|
+
// Track RTM connection state (equivalent to v1.5x connectionState check)
|
|
92
|
+
const [rtmConnectionState, setRtmConnectionState] = useState<number>(0); // 0=IDLE, 2=CONNECTED
|
|
72
93
|
|
|
94
|
+
/**
|
|
95
|
+
* inside event callback state won't have latest value.
|
|
96
|
+
* so creating ref to access the state
|
|
97
|
+
*/
|
|
73
98
|
const isHostRef = useRef({isHost: isHost});
|
|
74
|
-
|
|
75
99
|
useEffect(() => {
|
|
76
100
|
isHostRef.current.isHost = isHost;
|
|
77
101
|
}, [isHost]);
|
|
78
102
|
|
|
103
|
+
const waitingRoomStatusRef = useRef({waitingRoomStatus: waitingRoomStatus});
|
|
79
104
|
useEffect(() => {
|
|
80
105
|
waitingRoomStatusRef.current.waitingRoomStatus = waitingRoomStatus;
|
|
81
106
|
}, [waitingRoomStatus]);
|
|
82
107
|
|
|
83
|
-
|
|
84
|
-
* inside event callback state won't have latest value.
|
|
85
|
-
* so creating ref to access the state
|
|
86
|
-
*/
|
|
108
|
+
const activeUidsRef = useRef({activeUids: activeUids});
|
|
87
109
|
useEffect(() => {
|
|
88
110
|
activeUidsRef.current.activeUids = activeUids;
|
|
89
111
|
}, [activeUids]);
|
|
90
112
|
|
|
113
|
+
const defaultContentRef = useRef({defaultContent: defaultContent});
|
|
91
114
|
useEffect(() => {
|
|
92
115
|
defaultContentRef.current.defaultContent = defaultContent;
|
|
93
116
|
}, [defaultContent]);
|
|
94
117
|
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
118
|
+
// Eventdispatcher timeout refs clean
|
|
119
|
+
const isRTMMounted = useRef(true);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
return () => {
|
|
122
|
+
isRTMMounted.current = false;
|
|
123
|
+
// Clear all pending timeouts on unmount
|
|
124
|
+
for (const timeout of eventTimeouts.values()) {
|
|
125
|
+
clearTimeout(timeout);
|
|
126
|
+
}
|
|
127
|
+
eventTimeouts.clear();
|
|
128
|
+
};
|
|
129
|
+
}, []);
|
|
101
130
|
|
|
131
|
+
// Set online users
|
|
102
132
|
React.useEffect(() => {
|
|
103
133
|
setTotalOnlineUsers(
|
|
104
134
|
Object.keys(
|
|
@@ -107,31 +137,42 @@ const RtmConfigure = (props: any) => {
|
|
|
107
137
|
([k, v]) =>
|
|
108
138
|
v?.type === 'rtc' &&
|
|
109
139
|
!v.offline &&
|
|
110
|
-
activeUids.indexOf(v?.uid) !== -1,
|
|
140
|
+
activeUidsRef.current.activeUids.indexOf(v?.uid) !== -1,
|
|
111
141
|
),
|
|
112
142
|
).length,
|
|
113
143
|
);
|
|
114
144
|
}, [defaultContent]);
|
|
115
145
|
|
|
116
146
|
React.useEffect(() => {
|
|
117
|
-
|
|
147
|
+
// If its not a convo ai project and
|
|
148
|
+
// the platform is web execute the window listeners
|
|
149
|
+
if (!$config.ENABLE_CONVERSATIONAL_AI && isWebInternal()) {
|
|
118
150
|
const handBrowserClose = ev => {
|
|
119
151
|
ev.preventDefault();
|
|
120
152
|
return (ev.returnValue = 'Are you sure you want to exit?');
|
|
121
153
|
};
|
|
122
154
|
const logoutRtm = () => {
|
|
123
|
-
|
|
155
|
+
try {
|
|
156
|
+
if (engine.current && RTMEngine.getInstance().channelUid) {
|
|
157
|
+
// First unsubscribe from channel (like v1.5x leaveChannel)
|
|
158
|
+
engine.current.unsubscribe(RTMEngine.getInstance().channelUid);
|
|
159
|
+
// Then logout
|
|
160
|
+
engine.current.logout();
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
console.error('Error during browser close RTM cleanup:', error);
|
|
164
|
+
}
|
|
124
165
|
};
|
|
125
166
|
|
|
126
|
-
|
|
167
|
+
// Set up window listeners
|
|
127
168
|
window.addEventListener(
|
|
128
169
|
'beforeunload',
|
|
129
170
|
isWeb() && !isSDK() ? handBrowserClose : () => {},
|
|
130
171
|
);
|
|
131
172
|
|
|
132
173
|
window.addEventListener('pagehide', logoutRtm);
|
|
133
|
-
// cleanup this component
|
|
134
174
|
return () => {
|
|
175
|
+
// Remove listeners on unmount
|
|
135
176
|
window.removeEventListener(
|
|
136
177
|
'beforeunload',
|
|
137
178
|
isWeb() && !isSDK() ? handBrowserClose : () => {},
|
|
@@ -141,23 +182,303 @@ const RtmConfigure = (props: any) => {
|
|
|
141
182
|
}
|
|
142
183
|
}, []);
|
|
143
184
|
|
|
185
|
+
const init = async (rtcUid: UidType) => {
|
|
186
|
+
//on sdk due to multiple re-render we are getting rtm error code 8
|
|
187
|
+
//you are joining the same channel too frequently, exceeding the allowed rate of joining the same channel multiple times within a short period
|
|
188
|
+
//so checking rtm connection state before proceed
|
|
189
|
+
|
|
190
|
+
// Check if already connected (equivalent to v1.5x connectionState === 'CONNECTED')
|
|
191
|
+
if (
|
|
192
|
+
rtmConnectionState === nativeLinkStateMapping.CONNECTED &&
|
|
193
|
+
RTMEngine.getInstance().isEngineReady
|
|
194
|
+
) {
|
|
195
|
+
logger.log(
|
|
196
|
+
LogSource.AgoraSDK,
|
|
197
|
+
'Log',
|
|
198
|
+
'🚫 RTM already connected, skipping initialization',
|
|
199
|
+
);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
if (!RTMEngine.getInstance().isEngineReady) {
|
|
205
|
+
RTMEngine.getInstance().setLocalUID(rtcUid);
|
|
206
|
+
logger.log(LogSource.AgoraSDK, 'API', 'RTM local Uid set', rtcUid);
|
|
207
|
+
}
|
|
208
|
+
engine.current = RTMEngine.getInstance().engine;
|
|
209
|
+
// Logout any opened sessions if any
|
|
210
|
+
engine.current.logout();
|
|
211
|
+
logger.log(LogSource.AgoraSDK, 'Log', 'RTM client creation done');
|
|
212
|
+
} catch (error) {
|
|
213
|
+
logger.error(
|
|
214
|
+
LogSource.AgoraSDK,
|
|
215
|
+
'Log',
|
|
216
|
+
'RTM engine initialization failed:',
|
|
217
|
+
{error},
|
|
218
|
+
);
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
engine.current.addEventListener(
|
|
223
|
+
'linkState',
|
|
224
|
+
async (data: LinkStateEvent) => {
|
|
225
|
+
// Update connection state for duplicate initialization prevention
|
|
226
|
+
setRtmConnectionState(data.currentState);
|
|
227
|
+
logger.log(
|
|
228
|
+
LogSource.AgoraSDK,
|
|
229
|
+
'Event',
|
|
230
|
+
`RTM linkState changed: ${data.previousState} -> ${data.currentState}`,
|
|
231
|
+
data,
|
|
232
|
+
);
|
|
233
|
+
if (data.currentState === nativeLinkStateMapping.CONNECTED) {
|
|
234
|
+
// CONNECTED state
|
|
235
|
+
logger.log(LogSource.AgoraSDK, 'Event', 'RTM connected', {
|
|
236
|
+
previousState: data.previousState,
|
|
237
|
+
currentState: data.currentState,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
if (data.currentState === nativeLinkStateMapping.FAILED) {
|
|
241
|
+
// FAILED state
|
|
242
|
+
logger.error(LogSource.AgoraSDK, 'Event', 'RTM connection failed', {
|
|
243
|
+
error: {
|
|
244
|
+
reasonCode: data.reasonCode,
|
|
245
|
+
currentState: data.currentState,
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
engine.current.addEventListener('storage', (storage: StorageEvent) => {
|
|
253
|
+
// when remote user sets/updates metadata - 3
|
|
254
|
+
if (
|
|
255
|
+
storage.eventType === nativeStorageEventTypeMapping.SET ||
|
|
256
|
+
storage.eventType === nativeStorageEventTypeMapping.UPDATE
|
|
257
|
+
) {
|
|
258
|
+
const storageTypeStr = storage.storageType === 1 ? 'user' : 'channel';
|
|
259
|
+
const eventTypeStr = storage.eventType === 2 ? 'SET' : 'UPDATE';
|
|
260
|
+
logger.log(
|
|
261
|
+
LogSource.AgoraSDK,
|
|
262
|
+
'Event',
|
|
263
|
+
`RTM storage event of type: [${eventTypeStr} ${storageTypeStr} metadata]`,
|
|
264
|
+
storage,
|
|
265
|
+
);
|
|
266
|
+
try {
|
|
267
|
+
if (storage.data?.items && Array.isArray(storage.data.items)) {
|
|
268
|
+
storage.data.items.forEach(item => {
|
|
269
|
+
try {
|
|
270
|
+
if (!item || !item.key) {
|
|
271
|
+
logger.warn(
|
|
272
|
+
LogSource.Events,
|
|
273
|
+
'CUSTOM_EVENTS',
|
|
274
|
+
'Invalid storage item:',
|
|
275
|
+
item,
|
|
276
|
+
);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const {key, value, authorUserId, updateTs} = item;
|
|
281
|
+
const timestamp = getMessageTime(updateTs);
|
|
282
|
+
const sender = Platform.OS
|
|
283
|
+
? get32BitUid(authorUserId)
|
|
284
|
+
: parseInt(authorUserId, 10);
|
|
285
|
+
eventDispatcher(
|
|
286
|
+
{
|
|
287
|
+
evt: key,
|
|
288
|
+
value,
|
|
289
|
+
},
|
|
290
|
+
`${sender}`,
|
|
291
|
+
timestamp,
|
|
292
|
+
);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
logger.error(
|
|
295
|
+
LogSource.Events,
|
|
296
|
+
'CUSTOM_EVENTS',
|
|
297
|
+
`Failed to process storage item: ${JSON.stringify(item)}`,
|
|
298
|
+
{error},
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
logger.error(
|
|
305
|
+
LogSource.Events,
|
|
306
|
+
'CUSTOM_EVENTS',
|
|
307
|
+
'error while dispatching through eventDispatcher',
|
|
308
|
+
{error},
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
engine.current.addEventListener(
|
|
315
|
+
'presence',
|
|
316
|
+
async (presence: PresenceEvent) => {
|
|
317
|
+
if (`${localUid}` === presence.publisher) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
// remoteJoinChannel
|
|
321
|
+
if (presence.type === nativePresenceEventTypeMapping.REMOTE_JOIN) {
|
|
322
|
+
logger.log(
|
|
323
|
+
LogSource.AgoraSDK,
|
|
324
|
+
'Event',
|
|
325
|
+
'RTM presenceEvent of type [3 - remoteJoin] (channelMemberJoined)',
|
|
326
|
+
);
|
|
327
|
+
const backoffAttributes = await fetchUserAttributesWithBackoffRetry(
|
|
328
|
+
presence.publisher,
|
|
329
|
+
);
|
|
330
|
+
await processUserUidAttributes(backoffAttributes, presence.publisher);
|
|
331
|
+
}
|
|
332
|
+
// remoteLeaveChannel
|
|
333
|
+
if (presence.type === nativePresenceEventTypeMapping.REMOTE_LEAVE) {
|
|
334
|
+
logger.log(
|
|
335
|
+
LogSource.AgoraSDK,
|
|
336
|
+
'Event',
|
|
337
|
+
'RTM presenceEvent of type [4 - remoteLeave] (channelMemberLeft)',
|
|
338
|
+
presence,
|
|
339
|
+
);
|
|
340
|
+
// Chat of left user becomes undefined. So don't cleanup
|
|
341
|
+
const uid = presence?.publisher
|
|
342
|
+
? parseInt(presence.publisher, 10)
|
|
343
|
+
: undefined;
|
|
344
|
+
|
|
345
|
+
if (!uid) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
SDKEvents.emit('_rtm-left', uid);
|
|
349
|
+
// updating the rtc data
|
|
350
|
+
updateRenderListState(uid, {
|
|
351
|
+
offline: true,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
engine.current.addEventListener('message', (message: MessageEvent) => {
|
|
358
|
+
if (`${localUid}` === message.publisher) {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
// message - 1 (channel)
|
|
362
|
+
if (message.channelType === nativeChannelTypeMapping.MESSAGE) {
|
|
363
|
+
logger.debug(
|
|
364
|
+
LogSource.Events,
|
|
365
|
+
'CUSTOM_EVENTS',
|
|
366
|
+
'messageEvent of type [1 - CHANNEL] (channelMessageReceived)',
|
|
367
|
+
message,
|
|
368
|
+
);
|
|
369
|
+
const {
|
|
370
|
+
publisher: uid,
|
|
371
|
+
channelName: channelId,
|
|
372
|
+
message: text,
|
|
373
|
+
timestamp: ts,
|
|
374
|
+
} = message;
|
|
375
|
+
//whiteboard upload
|
|
376
|
+
if (parseInt(uid, 10) === 1010101) {
|
|
377
|
+
const [err, res] = safeJsonParse(text);
|
|
378
|
+
if (err) {
|
|
379
|
+
logger.error(
|
|
380
|
+
LogSource.Events,
|
|
381
|
+
'CUSTOM_EVENTS',
|
|
382
|
+
'JSON payload incorrect, Error while parsing the payload',
|
|
383
|
+
{error: err},
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
if (res?.data?.data?.images) {
|
|
387
|
+
LocalEventEmitter.emit(
|
|
388
|
+
LocalEventsEnum.WHITEBOARD_FILE_UPLOAD,
|
|
389
|
+
res?.data?.data?.images,
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
const [err, msg] = safeJsonParse(text);
|
|
394
|
+
if (err) {
|
|
395
|
+
logger.error(
|
|
396
|
+
LogSource.Events,
|
|
397
|
+
'CUSTOM_EVENTS',
|
|
398
|
+
'JSON payload incorrect, Error while parsing the payload',
|
|
399
|
+
{error: err},
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const timestamp = getMessageTime(ts);
|
|
404
|
+
const sender = Platform.OS ? get32BitUid(uid) : parseInt(uid, 10);
|
|
405
|
+
|
|
406
|
+
if (channelId === rtcProps.channel) {
|
|
407
|
+
try {
|
|
408
|
+
eventDispatcher(msg, `${sender}`, timestamp);
|
|
409
|
+
} catch (error) {
|
|
410
|
+
logger.error(
|
|
411
|
+
LogSource.Events,
|
|
412
|
+
'CUSTOM_EVENTS',
|
|
413
|
+
'error while dispatching through eventDispatcher',
|
|
414
|
+
{error},
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// message - 3 (user)
|
|
422
|
+
if (message.channelType === nativeChannelTypeMapping.USER) {
|
|
423
|
+
logger.debug(
|
|
424
|
+
LogSource.Events,
|
|
425
|
+
'CUSTOM_EVENTS',
|
|
426
|
+
'messageEvent of type [3- USER] (messageReceived)',
|
|
427
|
+
message,
|
|
428
|
+
);
|
|
429
|
+
const {publisher: peerId, timestamp: ts, message: text} = message;
|
|
430
|
+
const [err, msg] = safeJsonParse(text);
|
|
431
|
+
if (err) {
|
|
432
|
+
logger.error(
|
|
433
|
+
LogSource.Events,
|
|
434
|
+
'CUSTOM_EVENTS',
|
|
435
|
+
'JSON payload incorrect, Error while parsing the payload',
|
|
436
|
+
{error: err},
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const timestamp = getMessageTime(ts);
|
|
441
|
+
|
|
442
|
+
const sender = isAndroid() ? get32BitUid(peerId) : parseInt(peerId, 10);
|
|
443
|
+
|
|
444
|
+
try {
|
|
445
|
+
eventDispatcher(msg, `${sender}`, timestamp);
|
|
446
|
+
} catch (error) {
|
|
447
|
+
logger.error(
|
|
448
|
+
LogSource.Events,
|
|
449
|
+
'CUSTOM_EVENTS',
|
|
450
|
+
'error while dispatching through eventDispatcher',
|
|
451
|
+
{error},
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
await doLoginAndSetupRTM();
|
|
458
|
+
};
|
|
459
|
+
|
|
144
460
|
const doLoginAndSetupRTM = async () => {
|
|
145
461
|
try {
|
|
146
462
|
logger.log(LogSource.AgoraSDK, 'API', 'RTM login starts');
|
|
147
463
|
await engine.current.login({
|
|
148
|
-
|
|
464
|
+
// @ts-ignore
|
|
149
465
|
token: rtcProps.rtm,
|
|
150
466
|
});
|
|
151
467
|
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
468
|
timerValueRef.current = 5;
|
|
469
|
+
// waiting for login to be fully connected
|
|
470
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
155
471
|
await setAttribute();
|
|
156
|
-
logger.log(LogSource.AgoraSDK, 'Log', 'RTM setting attribute done');
|
|
157
472
|
} catch (error) {
|
|
158
|
-
logger.error(
|
|
473
|
+
logger.error(
|
|
474
|
+
LogSource.AgoraSDK,
|
|
475
|
+
'Log',
|
|
476
|
+
'RTM login failed..Trying again',
|
|
477
|
+
{error},
|
|
478
|
+
);
|
|
159
479
|
setTimeout(async () => {
|
|
160
|
-
|
|
480
|
+
// Cap the timer to prevent excessive delays (max 30 seconds)
|
|
481
|
+
timerValueRef.current = Math.min(timerValueRef.current * 2, 30);
|
|
161
482
|
doLoginAndSetupRTM();
|
|
162
483
|
}, timerValueRef.current * 1000);
|
|
163
484
|
}
|
|
@@ -169,7 +490,13 @@ const RtmConfigure = (props: any) => {
|
|
|
169
490
|
{key: 'isHost', value: String(isHostRef.current.isHost)},
|
|
170
491
|
];
|
|
171
492
|
try {
|
|
172
|
-
|
|
493
|
+
const data: Metadata = {
|
|
494
|
+
items: rtmAttributes,
|
|
495
|
+
};
|
|
496
|
+
const options: SetOrUpdateUserMetadataOptions = {
|
|
497
|
+
userId: `${localUid}`,
|
|
498
|
+
};
|
|
499
|
+
await engine.current.storage.setUserMetadata(data, options);
|
|
173
500
|
logger.log(
|
|
174
501
|
LogSource.AgoraSDK,
|
|
175
502
|
'API',
|
|
@@ -179,10 +506,15 @@ const RtmConfigure = (props: any) => {
|
|
|
179
506
|
},
|
|
180
507
|
);
|
|
181
508
|
timerValueRef.current = 5;
|
|
182
|
-
await
|
|
183
|
-
logger.log(
|
|
184
|
-
|
|
185
|
-
|
|
509
|
+
await subscribeChannel();
|
|
510
|
+
logger.log(
|
|
511
|
+
LogSource.AgoraSDK,
|
|
512
|
+
'Log',
|
|
513
|
+
'RTM subscribe, fetch members, reading channel atrributes all done',
|
|
514
|
+
{
|
|
515
|
+
data: rtmAttributes,
|
|
516
|
+
},
|
|
517
|
+
);
|
|
186
518
|
setHasUserJoinedRTM(true);
|
|
187
519
|
await runQueuedEvents();
|
|
188
520
|
setIsInitialQueueCompleted(true);
|
|
@@ -199,184 +531,138 @@ const RtmConfigure = (props: any) => {
|
|
|
199
531
|
LogSource.AgoraSDK,
|
|
200
532
|
'Log',
|
|
201
533
|
'RTM setAttribute failed..Trying again',
|
|
534
|
+
{error},
|
|
202
535
|
);
|
|
203
536
|
setTimeout(async () => {
|
|
204
|
-
|
|
537
|
+
// Cap the timer to prevent excessive delays (max 30 seconds)
|
|
538
|
+
timerValueRef.current = Math.min(timerValueRef.current * 2, 30);
|
|
205
539
|
setAttribute();
|
|
206
540
|
}, timerValueRef.current * 1000);
|
|
207
541
|
}
|
|
208
542
|
};
|
|
209
543
|
|
|
210
|
-
const
|
|
544
|
+
const subscribeChannel = async () => {
|
|
211
545
|
try {
|
|
212
|
-
if (RTMEngine.getInstance().channelUid
|
|
213
|
-
|
|
214
|
-
|
|
546
|
+
if (RTMEngine.getInstance().channelUid === rtcProps.channel) {
|
|
547
|
+
logger.debug(
|
|
548
|
+
LogSource.AgoraSDK,
|
|
549
|
+
'Log',
|
|
550
|
+
'🚫 RTM already subscribed channel skipping',
|
|
551
|
+
rtcProps.channel,
|
|
552
|
+
);
|
|
553
|
+
} else {
|
|
554
|
+
await engine.current.subscribe(rtcProps.channel, {
|
|
555
|
+
withMessage: true,
|
|
556
|
+
withPresence: true,
|
|
557
|
+
withMetadata: true,
|
|
558
|
+
withLock: false,
|
|
559
|
+
});
|
|
560
|
+
logger.log(LogSource.AgoraSDK, 'API', 'RTM subscribeChannel', {
|
|
215
561
|
data: rtcProps.channel,
|
|
216
562
|
});
|
|
563
|
+
|
|
564
|
+
// Set channel ID AFTER successful subscribe (like v1.5x)
|
|
217
565
|
RTMEngine.getInstance().setChannelId(rtcProps.channel);
|
|
218
566
|
logger.log(
|
|
219
567
|
LogSource.AgoraSDK,
|
|
220
568
|
'API',
|
|
221
|
-
'RTM setChannelId',
|
|
569
|
+
'RTM setChannelId as subscribe is successful',
|
|
222
570
|
rtcProps.channel,
|
|
223
571
|
);
|
|
572
|
+
|
|
224
573
|
logger.debug(
|
|
225
574
|
LogSource.SDK,
|
|
226
575
|
'Event',
|
|
227
576
|
'Emitting rtm joined',
|
|
228
577
|
rtcProps.channel,
|
|
229
578
|
);
|
|
579
|
+
// @ts-ignore
|
|
230
580
|
SDKEvents.emit('_rtm-joined', rtcProps.channel);
|
|
231
|
-
|
|
232
|
-
|
|
581
|
+
timerValueRef.current = 5;
|
|
582
|
+
await getMembers();
|
|
583
|
+
await readAllChannelAttributes();
|
|
584
|
+
logger.log(
|
|
233
585
|
LogSource.AgoraSDK,
|
|
234
586
|
'Log',
|
|
235
|
-
'RTM
|
|
236
|
-
rtcProps.channel,
|
|
587
|
+
'RTM readAllChannelAttributes and getMembers done',
|
|
237
588
|
);
|
|
238
589
|
}
|
|
239
|
-
timerValueRef.current = 5;
|
|
240
|
-
await getMembers();
|
|
241
|
-
await readAllChannelAttributes();
|
|
242
|
-
logger.log(LogSource.AgoraSDK, 'Log', 'RTM getMembers done');
|
|
243
590
|
} catch (error) {
|
|
244
591
|
logger.error(
|
|
245
592
|
LogSource.AgoraSDK,
|
|
246
593
|
'Log',
|
|
247
|
-
'RTM
|
|
594
|
+
'RTM subscribeChannel failed..Trying again',
|
|
595
|
+
{error},
|
|
248
596
|
);
|
|
249
597
|
setTimeout(async () => {
|
|
250
|
-
|
|
251
|
-
|
|
598
|
+
// Cap the timer to prevent excessive delays (max 30 seconds)
|
|
599
|
+
timerValueRef.current = Math.min(timerValueRef.current * 2, 30);
|
|
600
|
+
subscribeChannel();
|
|
252
601
|
}, timerValueRef.current * 1000);
|
|
253
602
|
}
|
|
254
603
|
};
|
|
255
604
|
|
|
256
|
-
const updateRenderListState = (
|
|
257
|
-
uid: number,
|
|
258
|
-
data: Partial<ContentInterface>,
|
|
259
|
-
) => {
|
|
260
|
-
dispatch({type: 'UpdateRenderList', value: [uid, data]});
|
|
261
|
-
};
|
|
262
|
-
|
|
263
605
|
const getMembers = async () => {
|
|
264
606
|
try {
|
|
265
607
|
logger.log(
|
|
266
608
|
LogSource.AgoraSDK,
|
|
267
609
|
'API',
|
|
268
|
-
'RTM
|
|
610
|
+
'RTM presence.getOnlineUsers(getMembers) start',
|
|
269
611
|
);
|
|
270
|
-
await engine.current
|
|
271
|
-
.
|
|
272
|
-
.then(async data => {
|
|
612
|
+
await engine.current.presence
|
|
613
|
+
.getOnlineUsers(rtcProps.channel, 1)
|
|
614
|
+
.then(async (data: GetOnlineUsersResponse) => {
|
|
273
615
|
logger.log(
|
|
274
616
|
LogSource.AgoraSDK,
|
|
275
617
|
'API',
|
|
276
|
-
'RTM
|
|
618
|
+
'RTM presence.getOnlineUsers data received',
|
|
277
619
|
data,
|
|
278
620
|
);
|
|
279
621
|
await Promise.all(
|
|
280
|
-
data.
|
|
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
|
-
);
|
|
622
|
+
data.occupants?.map(async member => {
|
|
330
623
|
try {
|
|
331
|
-
const
|
|
332
|
-
|
|
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
|
|
624
|
+
const backoffAttributes =
|
|
625
|
+
await fetchUserAttributesWithBackoffRetry(member.userId);
|
|
349
626
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
};
|
|
355
|
-
updateRenderListState(screenUid, screenShareUser);
|
|
356
|
-
//end - updating screenshare data in rtc
|
|
627
|
+
await processUserUidAttributes(
|
|
628
|
+
backoffAttributes,
|
|
629
|
+
member.userId,
|
|
630
|
+
);
|
|
357
631
|
// setting screenshare data
|
|
358
632
|
// name of the screenUid, isActive: false, (when the user starts screensharing it becomes true)
|
|
359
633
|
// isActive to identify all active screenshare users in the call
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
634
|
+
backoffAttributes?.items?.forEach(item => {
|
|
635
|
+
try {
|
|
636
|
+
if (hasJsonStructure(item.value as string)) {
|
|
637
|
+
const data = {
|
|
638
|
+
evt: item.key, // Use item.key instead of key
|
|
639
|
+
value: item.value, // Use item.value instead of value
|
|
640
|
+
};
|
|
641
|
+
// TODOSUP: Add the data to queue, dont add same mulitple events, use set so as to not repeat events
|
|
642
|
+
EventsQueue.enqueue({
|
|
643
|
+
data: data,
|
|
644
|
+
uid: member.userId,
|
|
645
|
+
ts: timeNow(),
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
} catch (error) {
|
|
649
|
+
logger.error(
|
|
650
|
+
LogSource.AgoraSDK,
|
|
651
|
+
'Log',
|
|
652
|
+
`RTM Failed to process user attribute item for ${
|
|
653
|
+
member.userId
|
|
654
|
+
}: ${JSON.stringify(item)}`,
|
|
655
|
+
{error},
|
|
656
|
+
);
|
|
657
|
+
// Continue processing other items
|
|
372
658
|
}
|
|
373
|
-
}
|
|
659
|
+
});
|
|
374
660
|
} catch (e) {
|
|
375
661
|
logger.error(
|
|
376
662
|
LogSource.AgoraSDK,
|
|
377
663
|
'Log',
|
|
378
|
-
`Could not retrieve name of ${member.
|
|
379
|
-
e,
|
|
664
|
+
`RTM Could not retrieve name of ${member.userId}`,
|
|
665
|
+
{error: e},
|
|
380
666
|
);
|
|
381
667
|
}
|
|
382
668
|
}),
|
|
@@ -390,7 +676,8 @@ const RtmConfigure = (props: any) => {
|
|
|
390
676
|
timerValueRef.current = 5;
|
|
391
677
|
} catch (error) {
|
|
392
678
|
setTimeout(async () => {
|
|
393
|
-
|
|
679
|
+
// Cap the timer to prevent excessive delays (max 30 seconds)
|
|
680
|
+
timerValueRef.current = Math.min(timerValueRef.current * 2, 30);
|
|
394
681
|
await getMembers();
|
|
395
682
|
}, timerValueRef.current * 1000);
|
|
396
683
|
}
|
|
@@ -398,286 +685,169 @@ const RtmConfigure = (props: any) => {
|
|
|
398
685
|
|
|
399
686
|
const readAllChannelAttributes = async () => {
|
|
400
687
|
try {
|
|
401
|
-
await engine.current
|
|
402
|
-
.
|
|
403
|
-
.then(async data => {
|
|
404
|
-
for (const item of data) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
688
|
+
await engine.current.storage
|
|
689
|
+
.getChannelMetadata(rtcProps.channel, 1)
|
|
690
|
+
.then(async (data: GetChannelMetadataResponse) => {
|
|
691
|
+
for (const item of data.items) {
|
|
692
|
+
try {
|
|
693
|
+
const {key, value, authorUserId, updateTs} = item;
|
|
694
|
+
if (hasJsonStructure(value as string)) {
|
|
695
|
+
const evtData = {
|
|
696
|
+
evt: key,
|
|
697
|
+
value,
|
|
698
|
+
};
|
|
699
|
+
// TODOSUP: Add the data to queue, dont add same mulitple events, use set so as to not repeat events
|
|
700
|
+
EventsQueue.enqueue({
|
|
701
|
+
data: evtData,
|
|
702
|
+
uid: authorUserId,
|
|
703
|
+
ts: updateTs,
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
} catch (error) {
|
|
707
|
+
logger.error(
|
|
708
|
+
LogSource.AgoraSDK,
|
|
709
|
+
'Log',
|
|
710
|
+
`RTM Failed to process channel attribute item: ${JSON.stringify(
|
|
711
|
+
item,
|
|
712
|
+
)}`,
|
|
713
|
+
{error},
|
|
714
|
+
);
|
|
715
|
+
// Continue processing other items
|
|
417
716
|
}
|
|
418
717
|
}
|
|
419
718
|
logger.log(
|
|
420
719
|
LogSource.AgoraSDK,
|
|
421
720
|
'API',
|
|
422
|
-
'RTM
|
|
721
|
+
'RTM storage.getChannelMetadata data received',
|
|
423
722
|
data,
|
|
424
723
|
);
|
|
425
724
|
});
|
|
426
725
|
timerValueRef.current = 5;
|
|
427
726
|
} catch (error) {
|
|
428
727
|
setTimeout(async () => {
|
|
429
|
-
|
|
728
|
+
// Cap the timer to prevent excessive delays (max 30 seconds)
|
|
729
|
+
timerValueRef.current = Math.min(timerValueRef.current * 2, 30);
|
|
430
730
|
await readAllChannelAttributes();
|
|
431
731
|
}, timerValueRef.current * 1000);
|
|
432
732
|
}
|
|
433
733
|
};
|
|
434
734
|
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
logger.log(LogSource.AgoraSDK, 'Log', 'RTM engine creation done');
|
|
735
|
+
const fetchUserAttributesWithBackoffRetry = async (
|
|
736
|
+
userId: string,
|
|
737
|
+
): Promise<GetUserMetadataResponse> => {
|
|
738
|
+
return backOff(
|
|
739
|
+
async () => {
|
|
740
|
+
logger.log(
|
|
741
|
+
LogSource.AgoraSDK,
|
|
742
|
+
'API',
|
|
743
|
+
`RTM fetching getUserMetadata for member ${userId}`,
|
|
744
|
+
);
|
|
446
745
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
}
|
|
746
|
+
const attr: GetUserMetadataResponse =
|
|
747
|
+
await engine.current.storage.getUserMetadata({
|
|
748
|
+
userId: userId,
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
if (!attr || !attr.items) {
|
|
471
752
|
logger.log(
|
|
472
753
|
LogSource.AgoraSDK,
|
|
473
754
|
'API',
|
|
474
|
-
|
|
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,
|
|
755
|
+
'RTM attributes for member not found',
|
|
532
756
|
);
|
|
757
|
+
throw attr;
|
|
533
758
|
}
|
|
534
|
-
}
|
|
535
|
-
getname();
|
|
536
|
-
});
|
|
537
759
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
// updating the rtc data
|
|
545
|
-
updateRenderListState(uid, {
|
|
546
|
-
offline: true,
|
|
547
|
-
});
|
|
548
|
-
});
|
|
760
|
+
logger.log(
|
|
761
|
+
LogSource.AgoraSDK,
|
|
762
|
+
'API',
|
|
763
|
+
`RTM getUserMetadata for member ${userId} received`,
|
|
764
|
+
{attr},
|
|
765
|
+
);
|
|
549
766
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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
|
-
);
|
|
767
|
+
if (attr.items && attr.items.length > 0) {
|
|
768
|
+
return attr;
|
|
769
|
+
} else {
|
|
770
|
+
throw attr;
|
|
576
771
|
}
|
|
577
772
|
},
|
|
773
|
+
{
|
|
774
|
+
retry: (e, idx) => {
|
|
775
|
+
logger.debug(
|
|
776
|
+
LogSource.AgoraSDK,
|
|
777
|
+
'Log',
|
|
778
|
+
`RTM [retrying] Attempt ${idx}. Fetching ${userId}'s attributes`,
|
|
779
|
+
e,
|
|
780
|
+
);
|
|
781
|
+
return true;
|
|
782
|
+
},
|
|
783
|
+
},
|
|
578
784
|
);
|
|
785
|
+
};
|
|
579
786
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
)
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
const timestamp = getMessageTime(ts);
|
|
787
|
+
const processUserUidAttributes = async (
|
|
788
|
+
attr: GetUserMetadataResponse,
|
|
789
|
+
userId: string,
|
|
790
|
+
) => {
|
|
791
|
+
try {
|
|
792
|
+
console.log('[user attributes]:', {attr});
|
|
793
|
+
const uid = parseInt(userId, 10);
|
|
794
|
+
const screenUidItem = attr?.items?.find(item => item.key === 'screenUid');
|
|
795
|
+
const isHostItem = attr?.items?.find(item => item.key === 'isHost');
|
|
796
|
+
const screenUid = screenUidItem?.value
|
|
797
|
+
? parseInt(screenUidItem.value, 10)
|
|
798
|
+
: undefined;
|
|
594
799
|
|
|
595
|
-
|
|
800
|
+
//start - updating user data in rtc
|
|
801
|
+
const userData = {
|
|
802
|
+
screenUid: screenUid,
|
|
803
|
+
//below thing for livestreaming
|
|
804
|
+
type: uid === parseInt(RECORDING_BOT_UID, 10) ? 'bot' : 'rtc',
|
|
805
|
+
uid,
|
|
806
|
+
offline: false,
|
|
807
|
+
isHost: isHostItem?.value || false,
|
|
808
|
+
lastMessageTimeStamp: 0,
|
|
809
|
+
};
|
|
810
|
+
updateRenderListState(uid, userData);
|
|
811
|
+
//end- updating user data in rtc
|
|
596
812
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
err,
|
|
605
|
-
);
|
|
813
|
+
//start - updating screenshare data in rtc
|
|
814
|
+
if (screenUid) {
|
|
815
|
+
const screenShareUser = {
|
|
816
|
+
type: UserType.ScreenShare,
|
|
817
|
+
parentUid: uid,
|
|
818
|
+
};
|
|
819
|
+
updateRenderListState(screenUid, screenShareUser);
|
|
606
820
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
evt,
|
|
821
|
+
//end - updating screenshare data in rtc
|
|
822
|
+
} catch (e) {
|
|
823
|
+
logger.error(
|
|
824
|
+
LogSource.AgoraSDK,
|
|
825
|
+
'Event',
|
|
826
|
+
`RTM Failed to process user data for ${userId}`,
|
|
827
|
+
{error: e},
|
|
615
828
|
);
|
|
829
|
+
}
|
|
830
|
+
};
|
|
616
831
|
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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();
|
|
832
|
+
const updateRenderListState = (
|
|
833
|
+
uid: number,
|
|
834
|
+
data: Partial<ContentInterface>,
|
|
835
|
+
) => {
|
|
836
|
+
dispatch({type: 'UpdateRenderList', value: [uid, data]});
|
|
667
837
|
};
|
|
668
838
|
|
|
669
839
|
const runQueuedEvents = async () => {
|
|
670
840
|
try {
|
|
671
841
|
while (!EventsQueue.isEmpty()) {
|
|
672
842
|
const currEvt = EventsQueue.dequeue();
|
|
673
|
-
await eventDispatcher(currEvt.data, currEvt.uid
|
|
843
|
+
await eventDispatcher(currEvt.data, `${currEvt.uid}`, currEvt.ts);
|
|
674
844
|
}
|
|
675
845
|
} catch (error) {
|
|
676
846
|
logger.error(
|
|
677
847
|
LogSource.Events,
|
|
678
848
|
'CUSTOM_EVENTS',
|
|
679
849
|
'error while running queue events',
|
|
680
|
-
error,
|
|
850
|
+
{error},
|
|
681
851
|
);
|
|
682
852
|
}
|
|
683
853
|
};
|
|
@@ -686,11 +856,13 @@ const RtmConfigure = (props: any) => {
|
|
|
686
856
|
data: {
|
|
687
857
|
evt: string;
|
|
688
858
|
value: string;
|
|
859
|
+
feat?: string;
|
|
860
|
+
etyp?: string;
|
|
689
861
|
},
|
|
690
862
|
sender: string,
|
|
691
863
|
ts: number,
|
|
692
864
|
) => {
|
|
693
|
-
console.
|
|
865
|
+
console.log(
|
|
694
866
|
LogSource.Events,
|
|
695
867
|
'CUSTOM_EVENTS',
|
|
696
868
|
'inside eventDispatcher ',
|
|
@@ -698,10 +870,10 @@ const RtmConfigure = (props: any) => {
|
|
|
698
870
|
);
|
|
699
871
|
|
|
700
872
|
let evt = '',
|
|
701
|
-
value =
|
|
873
|
+
value = '';
|
|
702
874
|
|
|
703
|
-
if (data
|
|
704
|
-
if (data
|
|
875
|
+
if (data?.feat === 'WAITING_ROOM') {
|
|
876
|
+
if (data?.etyp === 'REQUEST') {
|
|
705
877
|
const outputData = {
|
|
706
878
|
evt: `${data.feat}_${data.etyp}`,
|
|
707
879
|
payload: JSON.stringify({
|
|
@@ -715,7 +887,7 @@ const RtmConfigure = (props: any) => {
|
|
|
715
887
|
evt = data.feat + '_' + data.etyp; //rename if client side RTM meessage is to be sent for approval
|
|
716
888
|
value = formattedData;
|
|
717
889
|
}
|
|
718
|
-
if (data
|
|
890
|
+
if (data?.etyp === 'RESPONSE') {
|
|
719
891
|
const outputData = {
|
|
720
892
|
evt: `${data.feat}_${data.etyp}`,
|
|
721
893
|
payload: JSON.stringify({
|
|
@@ -756,32 +928,65 @@ const RtmConfigure = (props: any) => {
|
|
|
756
928
|
}
|
|
757
929
|
|
|
758
930
|
try {
|
|
759
|
-
|
|
931
|
+
let parsedValue;
|
|
932
|
+
try {
|
|
933
|
+
parsedValue = typeof value === 'string' ? JSON.parse(value) : value;
|
|
934
|
+
} catch (error) {
|
|
935
|
+
logger.error(
|
|
936
|
+
LogSource.Events,
|
|
937
|
+
'CUSTOM_EVENTS',
|
|
938
|
+
'RTM Failed to parse event value in event dispatcher:',
|
|
939
|
+
{error},
|
|
940
|
+
);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
const {payload, persistLevel, source} = parsedValue;
|
|
760
944
|
// Step 1: Set local attributes
|
|
761
945
|
if (persistLevel === PersistanceLevel.Session) {
|
|
762
946
|
const rtmAttribute = {key: evt, value: value};
|
|
763
|
-
|
|
947
|
+
const options: SetOrUpdateUserMetadataOptions = {
|
|
948
|
+
userId: `${localUid}`,
|
|
949
|
+
};
|
|
950
|
+
await engine.current.storage.setUserMetadata(
|
|
951
|
+
{
|
|
952
|
+
items: [rtmAttribute],
|
|
953
|
+
},
|
|
954
|
+
options,
|
|
955
|
+
);
|
|
764
956
|
}
|
|
765
957
|
// Step 2: Emit the event
|
|
766
|
-
console.
|
|
958
|
+
console.log(LogSource.Events, 'CUSTOM_EVENTS', 'emiting event..: ');
|
|
767
959
|
EventUtils.emitEvent(evt, source, {payload, persistLevel, sender, ts});
|
|
768
960
|
// Because async gets evaluated in a different order when in an sdk
|
|
769
961
|
if (evt === 'name') {
|
|
770
|
-
|
|
962
|
+
// 1. Cancel existing timeout for this sender
|
|
963
|
+
if (eventTimeouts.has(sender)) {
|
|
964
|
+
clearTimeout(eventTimeouts.get(sender)!);
|
|
965
|
+
}
|
|
966
|
+
// 2. Create new timeout with tracking
|
|
967
|
+
const timeout = setTimeout(() => {
|
|
968
|
+
// 3. Guard against unmounted component
|
|
969
|
+
if (!isRTMMounted.current) {
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
771
972
|
EventUtils.emitEvent(evt, source, {
|
|
772
973
|
payload,
|
|
773
974
|
persistLevel,
|
|
774
975
|
sender,
|
|
775
976
|
ts,
|
|
776
977
|
});
|
|
978
|
+
// 4. Clean up after execution
|
|
979
|
+
eventTimeouts.delete(sender);
|
|
777
980
|
}, 200);
|
|
981
|
+
// 5. Track the timeout for cleanup
|
|
982
|
+
eventTimeouts.set(sender, timeout);
|
|
778
983
|
}
|
|
779
984
|
} catch (error) {
|
|
780
985
|
console.error(
|
|
781
986
|
LogSource.Events,
|
|
782
987
|
'CUSTOM_EVENTS',
|
|
783
988
|
'error while emiting event:',
|
|
784
|
-
error,
|
|
989
|
+
{error},
|
|
785
990
|
);
|
|
786
991
|
}
|
|
787
992
|
};
|
|
@@ -790,45 +995,58 @@ const RtmConfigure = (props: any) => {
|
|
|
790
995
|
if (!callActive) {
|
|
791
996
|
return;
|
|
792
997
|
}
|
|
998
|
+
// Destroy and clean up RTM state
|
|
793
999
|
await RTMEngine.getInstance().destroy();
|
|
1000
|
+
// Set the engine as null
|
|
1001
|
+
engine.current = null;
|
|
794
1002
|
logger.log(LogSource.AgoraSDK, 'API', 'RTM destroy done');
|
|
795
1003
|
if (isIOS() || isAndroid()) {
|
|
796
1004
|
EventUtils.clear();
|
|
797
1005
|
}
|
|
798
1006
|
setHasUserJoinedRTM(false);
|
|
1007
|
+
setIsInitialQueueCompleted(false);
|
|
799
1008
|
logger.debug(LogSource.AgoraSDK, 'Log', 'RTM cleanup done');
|
|
800
1009
|
};
|
|
801
1010
|
|
|
802
1011
|
useAsyncEffect(async () => {
|
|
803
1012
|
//waiting room attendee -> rtm login will happen on page load
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
(
|
|
823
|
-
|
|
824
|
-
|
|
1013
|
+
try {
|
|
1014
|
+
if ($config.ENABLE_WAITING_ROOM) {
|
|
1015
|
+
//attendee
|
|
1016
|
+
//for waiting room attendee rtm login will happen on mount
|
|
1017
|
+
if (!isHost && !callActive) {
|
|
1018
|
+
await init(localUid);
|
|
1019
|
+
}
|
|
1020
|
+
//host
|
|
1021
|
+
if (
|
|
1022
|
+
isHost &&
|
|
1023
|
+
($config.AUTO_CONNECT_RTM ||
|
|
1024
|
+
(!$config.AUTO_CONNECT_RTM && callActive))
|
|
1025
|
+
) {
|
|
1026
|
+
await init(localUid);
|
|
1027
|
+
}
|
|
1028
|
+
} else {
|
|
1029
|
+
//non waiting room case
|
|
1030
|
+
//host and attendee
|
|
1031
|
+
if (
|
|
1032
|
+
$config.AUTO_CONNECT_RTM ||
|
|
1033
|
+
(!$config.AUTO_CONNECT_RTM && callActive)
|
|
1034
|
+
) {
|
|
1035
|
+
await init(localUid);
|
|
1036
|
+
}
|
|
825
1037
|
}
|
|
1038
|
+
} catch (error) {
|
|
1039
|
+
logger.error(LogSource.AgoraSDK, 'Log', 'RTM init failed', {error});
|
|
826
1040
|
}
|
|
827
1041
|
return async () => {
|
|
1042
|
+
logger.log(
|
|
1043
|
+
LogSource.AgoraSDK,
|
|
1044
|
+
'Log',
|
|
1045
|
+
'RTM unmounting calling end(destroy) ',
|
|
1046
|
+
);
|
|
828
1047
|
await end();
|
|
829
1048
|
};
|
|
830
|
-
|
|
831
|
-
}, [rtcProps.channel, rtcProps.appId, callActive]);
|
|
1049
|
+
}, [rtcProps.channel, rtcProps.appId, callActive, localUid]);
|
|
832
1050
|
|
|
833
1051
|
return (
|
|
834
1052
|
<ChatContext.Provider
|