agora-react-native-rtm
Version:
React Native around the Agora RTM SDKs for Android and iOS agora
299 lines (286 loc) • 8.4 kB
JavaScript
import { Buffer } from 'buffer';
import base64 from 'base64-js';
import EventEmitter from 'eventemitter3';
import { NativeEventEmitter } from 'react-native';
import { cleanIrisExtraData, processRTMClientEventMap } from '../api/RTMEvents';
import AgoraRtmNg from '../specs';
import { RtmClientInternal } from './RtmClientInternal';
// Request queue for handling async operations
export class RequestQueue {
_requestMap = new Map();
constructor() {}
static get instance() {
if (!RequestQueue._instance) {
RequestQueue._instance = new RequestQueue();
}
return RequestQueue._instance;
}
addRequest(callbackName, timeoutMs, externalRequestId) {
const requestId = externalRequestId;
let promiseResolve;
let promiseReject;
const promise = new Promise((resolve, reject) => {
promiseResolve = resolve;
promiseReject = reject;
});
promise.requestId = requestId;
let timeout;
if (timeoutMs > 0) {
timeout = setTimeout(() => {
const item = this._requestMap.get(requestId);
if (item) {
this._requestMap.delete(requestId);
console.log(`Request timeout: ${requestId}`);
item.reject(new Error(`Request ${requestId} timed out after ${timeoutMs}ms`));
}
}, timeoutMs);
}
this._requestMap.set(requestId, {
resolve: promiseResolve,
reject: promiseReject,
callbackName,
timeout
});
return promise;
}
resolveRequest(requestId, errorCode, callbackName, ...args) {
const request = this._requestMap.get(requestId);
if (!request) {
console.log(`Request not found: ${requestId}`);
return false;
}
// Check if callback name matches
if (request.callbackName !== callbackName) {
console.log(`Callback name mismatch: expected ${request.callbackName}, actual ${callbackName}`);
return false;
}
console.log(`Resolving request: ${requestId}, callback: ${callbackName}, error code: ${errorCode}`);
if (request.timeout) {
clearTimeout(request.timeout);
}
this._requestMap.delete(requestId);
if (errorCode === 0) {
request.resolve(...args);
} else {
request.reject(...args);
}
return true;
}
}
// @ts-ignore
export const DeviceEventEmitter = new EventEmitter();
const AgoraEventEmitter = new NativeEventEmitter(AgoraRtmNg);
AgoraEventEmitter.addListener('AgoraRtmNg:onEvent', handleEvent);
let debuggable = false;
/**
* @internal
*/
export function setDebuggable(flag) {
debuggable = flag;
}
/**
* @internal
*/
export function isDebuggable() {
return debuggable && __DEV__;
}
/**
* @internal
*/
export let EVENT_TYPE = /*#__PURE__*/function (EVENT_TYPE) {
EVENT_TYPE[EVENT_TYPE["RTMEvent"] = 0] = "RTMEvent";
return EVENT_TYPE;
}({});
/**
* @internal
*/
export const EVENT_PROCESSORS = {
RTMClientEventMap: {
suffix: 'RtmEventHandler_',
type: () => EVENT_TYPE.RTMEvent,
func: [processRTMClientEventMap],
handlers: () => RtmClientInternal._event_handlers,
preprocess: (event, data, buffers) => {
var _buffers$;
switch (event) {
case 'onMessageEvent':
console.log('onMessageEvent', data.event.message, buffers);
data.event.message = (_buffers$ = buffers[0]) === null || _buffers$ === void 0 ? void 0 : _buffers$.toString();
break;
}
return {
event,
data,
buffers
};
}
}
};
function handleEvent({
event,
data,
buffers
}) {
if (debuggable) {
console.info('onEvent', event, data, buffers);
}
let _data;
try {
_data = JSON.parse(data) ?? {};
} catch (e) {
_data = {};
}
let _event = event;
let processor = EVENT_PROCESSORS.RTMClientEventMap;
Object.values(EVENT_PROCESSORS).some(it => {
const p = it;
if (_event.startsWith(p.suffix) && processor.handlers(_data) !== undefined) {
processor = p;
const reg = new RegExp(`^${processor.suffix}`, 'g');
_event = _event.replace(reg, '');
return true;
}
return false;
});
// for new IrisType, but this is temporary
if (_event.includes('_')) {
_event = _event.substring(0, _event.indexOf('_'));
}
const _buffers = buffers === null || buffers === void 0 ? void 0 : buffers.map(value => {
return Buffer.from(value, 'base64');
});
if (processor.preprocess) {
processor.preprocess(_event, _data, _buffers);
}
if (processor.handlers) {
var _processor$handlers;
(_processor$handlers = processor.handlers(_data)) === null || _processor$handlers === void 0 || _processor$handlers.map(value => {
if (value) {
processor.func.map(it => {
it(value, _event, _data);
});
}
});
}
const requestId = _data.requestId;
if (requestId !== undefined && _data.errorCode !== undefined) {
const requestQueue = RequestQueue.instance;
requestQueue.resolveRequest(requestId, _data.errorCode, _event, _data);
}
emitEvent(_event, processor, _data);
}
/**
* @internal
*/
export function callIrisApi(funcName, params) {
try {
const buffers = [];
if (funcName.startsWith('StreamChannel_')) {
var _params$toJSON;
params.channelName = this.channelName;
const json = (_params$toJSON = params.toJSON) === null || _params$toJSON === void 0 ? void 0 : _params$toJSON.call();
params.toJSON = function () {
return {
...json,
channelName: params.channelName
};
};
}
if (funcName === 'RtmClient_publish_2d36e93' || funcName === 'StreamChannel_publishTopicMessage_a31773e') {
var _params$toJSON2;
if (typeof params.message === 'string') {
let uint8Array = new Uint8Array(Buffer.from(params.message));
let buffer = base64.fromByteArray(uint8Array);
console.log(uint8Array, buffer);
buffers.push(buffer);
params.length = base64.byteLength(buffer);
} else {
let buffer = base64.fromByteArray(params.message);
console.log(params.message, buffer);
buffers.push(buffer);
params.length = base64.byteLength(buffer);
}
delete params.message;
const json = (_params$toJSON2 = params.toJSON) === null || _params$toJSON2 === void 0 ? void 0 : _params$toJSON2.call();
delete json.message;
params.toJSON = function () {
return {
...json,
length: params.length
};
};
}
// RTM_ERROR_DUPLICATE_OPERATION
if (funcName === 'RtmClient_create') {
AgoraRtmNg.newIrisRtmEngine();
}
let ret = AgoraRtmNg.callApi({
funcName,
params: JSON.stringify(params),
buffers
});
if (funcName === 'RtmClient_release') {
AgoraRtmNg.destroyIrisRtmEngine();
}
if (ret !== undefined && ret !== null && ret !== '' && ret !== 'null') {
const retObj = JSON.parse(ret);
if (isDebuggable()) {
if (typeof retObj.result === 'number' && retObj.result < 0) {
console.error('callApi', funcName, JSON.stringify(params), ret);
} else {
console.log('callApi', funcName, JSON.stringify(params), ret);
}
}
return retObj;
}
} catch (e) {
if (isDebuggable()) {
console.error('callApi', funcName, JSON.stringify(params), e);
} else {
console.warn('callApi', funcName, JSON.stringify(params), e);
}
}
return {};
}
/**
* @internal
*/
export function emitEvent(eventType, eventProcessor, data) {
DeviceEventEmitter.emit(eventType, eventProcessor, data);
}
/**
* @internal
*/
export async function wrapRtmResult(data, operation, callbackName, withCallbackResult = false) {
if (data.result < 0) {
throw {
error: true,
reason: 'iris call failed',
operation,
errorCode: data.result
};
} else {
let result = await RequestQueue.instance.addRequest(callbackName, 60000, data.requestId);
if (withCallbackResult) {
result = cleanIrisExtraData(result);
}
return {
timestamp: 0,
...(withCallbackResult ? {
callBackResult: result
} : {})
};
}
}
/**
* @internal
*/
export function handleError(data, operation) {
return {
error: true,
reason: data,
operation: operation,
errorCode: data === null || data === void 0 ? void 0 : data.errorCode
};
}
//# sourceMappingURL=IrisRtmEngine.js.map