UNPKG

@asteriskzuo/react-native-easemob

Version:
693 lines (642 loc) 21.9 kB
import { EmitterSubscription, EventEmitter, NativeEventEmitter, NativeModules, Platform, } from 'react-native'; import { ChatConnectionListener, ChatContactGroupEventFromNumber, ChatCustomListener, ChatMultiDeviceListener, } from './ChatEvents'; import { ChatManager } from './ChatManager'; import { ChatDeviceInfo } from './common/ChatDeviceInfo'; import type { ChatOptions } from './common/ChatOptions'; import { MethodTypechangeAppKey, MethodTypecompressLogs, MethodTypecreateAccount, MethodTypegetCurrentUser, MethodTypegetLoggedInDevicesFromServer, MethodTypegetToken, MethodTypeinit, MethodTypeisConnected, MethodTypeisLoggedInBefore, MethodTypekickAllDevices, MethodTypekickDevice, MethodTypelogin, MethodTypeloginWithAgoraToken, MethodTypelogout, MethodTypeonConnected, MethodTypeonDisconnected, MethodTypeonMultiDeviceEvent, MethodTypeonSendDataToFlutter, MethodTypeonTokenDidExpire, MethodTypeonTokenWillExpire, MethodTyperefreshAgoraToken, } from './_internal/Consts'; import { Native } from './_internal/Native'; const LINKING_ERROR = `The package 'react-native-easemob' doesn't seem to be linked. Make sure: \n\n` + Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo managed workflow\n'; const ExtSdkApiRN = NativeModules.ExtSdkApiRN ? NativeModules.ExtSdkApiRN : new Proxy( {}, { get() { throw new Error(LINKING_ERROR); }, } ); const eventEmitter = new NativeEventEmitter(ExtSdkApiRN); console.log('eventEmitter: ', eventEmitter); export class ChatClient extends Native { public static eventType = 2; // 1.remove 2.subscription(suggested) private static TAG = 'ChatClient'; private static _instance: ChatClient; private _connectionSubscriptions: Map<string, EmitterSubscription>; public static getInstance(): ChatClient { if (ChatClient._instance == null || ChatClient._instance === undefined) { ChatClient._instance = new ChatClient(); } return ChatClient._instance; } private setEventEmitter(): void { console.log(`${ChatClient.TAG}: setEventEmitter: `); this.setNativeListener(this.getEventEmitter()); this._chatManager.setNativeListener(this.getEventEmitter()); console.log('eventEmitter has finished.'); } public getEventEmitter(): EventEmitter { return eventEmitter; } // private _eventEmitter: NativeEventEmitter; private _chatManager: ChatManager; // todo: no implement // private _contactManager: ChatContactManager; // private _chatRoomManager: ChatChatRoomManager; // private _groupManager: ChatGroupManager;` // private _pushManager: ChatPushManager; // private _userInfoManager: ChatUserInfoManager; // private _conversationManager: ChatConversationManager; private _connectionListeners: Set<ChatConnectionListener>; // todo: no implement private _multiDeviceListeners: Set<ChatMultiDeviceListener>; private _customListeners: Set<ChatCustomListener>; // 1.主动登录 2.主动退出 3.被动退出 private _options?: ChatOptions; private _sdkVersion: string = '1.0.0'; private _isInit: boolean = false; private _currentUsername: string = ''; private constructor() { super(); this._chatManager = new ChatManager(); // todo: no implement // this._contactManager = new ChatContactManager(); // this._chatRoomManager = new ChatChatRoomManager(); // this._groupManager = new ChatGroupManager(); // this._pushManager = new ChatPushManager(); // this._userInfoManager = new ChatUserInfoManager(); // this._conversationManager = new ChatConversationManager(); this._connectionListeners = new Set<ChatConnectionListener>(); this._connectionSubscriptions = new Map<string, EmitterSubscription>(); this._multiDeviceListeners = new Set<ChatMultiDeviceListener>(); this._customListeners = new Set<ChatCustomListener>(); this.setEventEmitter(); } private setConnectNativeListener(event: EventEmitter): void { console.log(`${ChatClient.TAG}: setConnectNativeListener: `); this._connectionSubscriptions.forEach( ( value: EmitterSubscription, key: string, map: Map<string, EmitterSubscription> ) => { console.log( `${ChatClient.TAG}: setConnectNativeListener: ${key}, ${value}, ${map}` ); value.remove(); } ); this._connectionSubscriptions.clear(); // let s: EmitterSubscription[] | undefined = eventEmitter?.listeners( // MethodTypeonConnected // ); // console.log(`${s?.length}`); // let s: EmitterSubscription = event.addListener( // MethodTypeonConnected, // (params: any[]): any => { // console.log('etst', params); // s.remove(); // } // ); this._connectionSubscriptions.set( MethodTypeonConnected, event.addListener(MethodTypeonConnected, this.onConnected.bind(this)) ); this._connectionSubscriptions.set( MethodTypeonDisconnected, event.addListener( MethodTypeonDisconnected, this.onDisconnected.bind(this) ) ); this._connectionSubscriptions.set( MethodTypeonTokenDidExpire, event.addListener( MethodTypeonTokenDidExpire, this.onTokenDidExpire.bind(this) ) ); this._connectionSubscriptions.set( MethodTypeonTokenWillExpire, event.addListener( MethodTypeonTokenWillExpire, this.onTokenWillExpire.bind(this) ) ); this._connectionSubscriptions.set( MethodTypeonMultiDeviceEvent, event.addListener( MethodTypeonMultiDeviceEvent, this.onMultiDeviceEvent.bind(this) ) ); this._connectionSubscriptions.set( MethodTypeonSendDataToFlutter, event.addListener( MethodTypeonSendDataToFlutter, this.onCustomEvent.bind(this) ) ); console.log(`${ChatClient.TAG}: setConnectNativeListener: `, event); } private setNativeListener(event: NativeEventEmitter): void { console.log( `${ChatClient.TAG}: setNativeListener: ${ChatClient.eventType}` ); if (ChatClient.eventType === 1) { event.removeAllListeners(MethodTypeonConnected); event.addListener(MethodTypeonConnected, this.onConnected.bind(this)); event.removeAllListeners(MethodTypeonDisconnected); event.addListener( MethodTypeonDisconnected, this.onDisconnected.bind(this) ); event.removeAllListeners(MethodTypeonTokenDidExpire); event.addListener( MethodTypeonTokenDidExpire, this.onTokenDidExpire.bind(this) ); event.removeAllListeners(MethodTypeonTokenWillExpire); event.addListener( MethodTypeonTokenWillExpire, this.onTokenWillExpire.bind(this) ); event.removeAllListeners(MethodTypeonMultiDeviceEvent); event.addListener( MethodTypeonMultiDeviceEvent, this.onMultiDeviceEvent.bind(this) ); event.removeAllListeners(MethodTypeonSendDataToFlutter); event.addListener( MethodTypeonSendDataToFlutter, this.onCustomEvent.bind(this) ); } else if (ChatClient.eventType === 2) { this.setConnectNativeListener(event); } else { throw new Error('This type is not supported.'); } } public onConnected(): void { console.log(`${ChatClient.TAG}: onConnected: `); this._connectionListeners.forEach((element) => { element.onConnected(); }); } private onDisconnected(params?: any): void { console.log(`${ChatClient.TAG}: onDisconnected: ${params}`); this._connectionListeners.forEach((element) => { let ec = params?.errorCode as number; element.onDisconnected(ec); }); } private onTokenWillExpire(params?: any): void { console.log(`${ChatClient.TAG}: onTokenWillExpire: ${params}`); this._connectionListeners.forEach((element) => { element.onTokenWillExpire(); }); } private onTokenDidExpire(params?: any): void { console.log(`${ChatClient.TAG}: onTokenDidExpire: ${params}`); this._connectionListeners.forEach((element) => { element.onTokenDidExpire(); }); } private onMultiDeviceEvent(params?: any): void { console.log(`${ChatClient.TAG}: onMultiDeviceEvent: ${params}`); this._multiDeviceListeners.forEach((element) => { let event = params?.event as number; if (event > 10) { element.onGroupEvent( ChatContactGroupEventFromNumber(event), params?.target, params?.userNames ); } else { element.onContactEvent( ChatContactGroupEventFromNumber(event), params?.target, params?.userNames ); } }); } private onCustomEvent(params: any): void { console.log(`${ChatClient.TAG}: onCustomEvent: ${params}`); this._customListeners.forEach((element) => { element.onDataReceived(params); }); } private reset(): void { this._currentUsername = ''; } /** * Get SDK Configurations. Make sure to set the param, see {@link EMOptions}. * * @returns The configurations. */ public get options(): ChatOptions | undefined { return this._options; } /** * Get SDK version. */ public get sdkVersion(): string { return this._sdkVersion; } /** * Get current user name. * * The value is valid after successful login. */ public get currentUserName(): string { return this._currentUsername; } /** * Get React-native SDK version. */ public get rnSdkVersion(): string { return this._sdkVersion; } /** * Make sure to initialize the SDK in the main thread. Make sure to set the param, see {@link ChatOptions}. * * **note** * * **This method must be called before any method can be called.** * * @param options The configurations. * * @throws Error, see {@link ChatError} */ public async init(options: ChatOptions): Promise<void> { console.log(`${ChatClient.TAG}: init: ${options}`); this._options = options; await Native._callMethod(MethodTypeinit, { options }); this._isInit = true; } /** * Check whether you have successfully connected to the server. * * @returns * - `true`: The server has been connected. * - `false`: The server is not connected. * * @throws Error, see {@link ChatError} */ public async isConnected(): Promise<boolean> { console.log(`${ChatClient.TAG}: isConnected: `); let result: any = await Native._callMethod(MethodTypeisConnected); ChatClient.hasErrorFromResult(result); let _connected = result?.[MethodTypeisConnected] as boolean; return _connected; } /** * Get current user name from native. Get cache see {@link currentUserName} * @returns The user name. * * @throws Error, see {@link ChatError} */ public async getCurrentUsername(): Promise<string> { console.log(`${ChatClient.TAG}: getCurrentUsername: `); let result: any = await Native._callMethod(MethodTypegetCurrentUser); ChatClient.hasErrorFromResult(result); let userName = result?.[MethodTypegetCurrentUser] as string; if (userName && userName.length !== 0) { if (userName !== this._currentUsername) { this._currentUsername = userName; } } return this._currentUsername; } /** * Get login state. * * @returns * - `true`: In automatic login mode, the value is true before successful login and false otherwise. * - `false`: In non-automatic login mode, the value is false. * * @throws Error, see {@link ChatError} */ public async isLoginBefore(): Promise<boolean> { console.log(`${ChatClient.TAG}: isLoginBefore: `); let result: any = await Native._callMethod(MethodTypeisLoggedInBefore); ChatClient.hasErrorFromResult(result); let _isLoginBefore = result?.[MethodTypeisLoggedInBefore] as boolean; return _isLoginBefore; } /** * Get login access token. * * @returns The token value. * * @throws Error, see {@link ChatError} */ public async getAccessToken(): Promise<string> { console.log(`${ChatClient.TAG}: isLoginBefore: `); let result: any = await Native._callMethod(MethodTypegetToken); ChatClient.hasErrorFromResult(result); let _token = result?.[MethodTypegetToken] as string; return _token; } /** * Register a new user with your chat network. * * @param username The username. The maximum length is 64 characters. Ensure that you set this parameter. Supported characters include the 26 English letters (a-z), the ten numbers (0-9), the underscore (_), the hyphen (-), and the English period (.). This parameter is case insensitive, and upper-case letters are automatically changed to low-case ones. If you want to set this parameter as a regular expression, set it as ^[a-zA-Z0-9_-]+$. * @param password The password. The maximum length is 64 characters. Ensure that you set this parameter. * * @throws Error, see {@link ChatError} */ public async createAccount( username: string, password: string ): Promise<void> { console.log(`${ChatClient.TAG}: createAccount: ${username}, ${password}`); let result: any = await Native._callMethod(MethodTypecreateAccount, { [MethodTypecreateAccount]: { username: username, password: password, }, }); ChatClient.hasErrorFromResult(result); } /** * An app user logs in to the chat server with a password or token. * * @param userName The username, see {@link createAccount}. * @param pwdOrToken The password or token, see {@link createAccount} or {@link getAccessToken} * @param isPassword The password or token flag. true is the password, otherwise it is the token. * * @throws Error, see {@link ChatError} */ public async login( userName: string, pwdOrToken: string, isPassword: boolean = true ): Promise<void> { console.log( `${ChatClient.TAG}: login: ${userName}, ${pwdOrToken}, ${isPassword}` ); let result: any = await Native._callMethod(MethodTypelogin, { [MethodTypelogin]: { username: userName, pwdOrToken: pwdOrToken, isPassword: isPassword, }, }); ChatClient.hasErrorFromResult(result); result = result?.[MethodTypelogin]; this._currentUsername = result?.username; console.log( `${ChatClient.TAG}: login: ${result?.username}, ${result?.token}` ); } /** * An app user logs in to the chat server with a agora token. * * @param userName The username, see {@link createAccount}. * @param agoraToken The token from agora api. * * @throws Error, see {@link ChatError} */ public async loginWithAgoraToken( userName: string, agoraToken: string ): Promise<void> { console.log( `${ChatClient.TAG}: loginWithAgoraToken: ${userName}, ${agoraToken}` ); let result: any = await Native._callMethod(MethodTypeloginWithAgoraToken, { [MethodTypeloginWithAgoraToken]: { username: userName, agoraToken: agoraToken, }, }); ChatClient.hasErrorFromResult(result); this._currentUsername = result?.username; } /** * Renew token. * * When a user is in the Agora token login state and receives a callback * notification of the token is to be expired in the {@link ChatConnectionListener} * implementation class, this API can be called to update the token to * avoid unknown problems caused by the token invalidation. * * @param agoraToken The new token. * * @throws Error, see {@link ChatError} */ public async renewAgoraToken(agoraToken: string): Promise<void> { console.log(`${ChatClient.TAG}: renewAgoraToken: ${agoraToken}`); let result: any = await Native._callMethod(MethodTyperefreshAgoraToken, { [MethodTyperefreshAgoraToken]: { agoraToken: agoraToken, }, }); ChatClient.hasErrorFromResult(result); } /** * An app user logs out and returns the result. * * @param unbindDeviceToken Whether to unbind the token. * - `true`: means to unbind the device token when logout. * - `false`: means to not unbind the device token when logout. * @throws Error, see {@link ChatError} */ public async logout(unbindDeviceToken: boolean = true): Promise<void> { console.log(`${ChatClient.TAG}: logout: ${unbindDeviceToken}`); let result: any = await Native._callMethod(MethodTypelogout, { [MethodTypelogout]: { unbindToken: unbindDeviceToken, }, }); ChatClient.hasErrorFromResult(result); this.reset(); } /** * Update the App Key, which is the unique identifier used to access Agora Chat. * * You retrieve the new App Key from Agora Console. * * As this key controls all access to Agora Chat for your app, you can only update the key when the current user is logged out. * * Also, you can set App Key by the following method when logged out {@link ChatOptions#appKey}. * * @param newAppKey The App Key, make sure to set the param. * * @throws Error, see {@link ChatError} */ public async changeAppKey(newAppKey: string): Promise<void> { console.log(`${ChatClient.TAG}: changeAppKey: ${newAppKey}`); let r: any = await Native._callMethod(MethodTypechangeAppKey, { appKey: newAppKey, }); ChatClient.hasErrorFromResult(r); } /** * Compresses the debug log into a gzip archive. * * Best practice is to delete this debug archive as soon as it is no longer used. * * @returns The path of the compressed gz file. * * @throws Error, see {@link ChatError} */ public async compressLogs(): Promise<string | undefined> { console.log(`${ChatClient.TAG}: compressLogs:`); let r: any = await Native._callMethod(MethodTypecompressLogs); ChatClient.hasErrorFromResult(r); return r?.[MethodTypecompressLogs]; } /** * Gets all the information about the logged in devices under the specified account. * * @param username The user ID you want to get the device information. * @param password The password. * @returns The list of the online devices. * * @throws Error, see {@link ChatError} */ public async getLoggedInDevicesFromServer( username: string, password: string ): Promise<Array<ChatDeviceInfo>> { console.log( `${ChatClient.TAG}: getLoggedInDevicesFromServer: ${username}, ${password}` ); let result: any = await Native._callMethod( MethodTypegetLoggedInDevicesFromServer, { [MethodTypegetLoggedInDevicesFromServer]: { username: username, password: password, }, } ); ChatClient.hasErrorFromResult(result); let r = new Array<ChatDeviceInfo>(1); let list: Array<any> = result?.[MethodTypegetLoggedInDevicesFromServer]; list.forEach((element) => { r.push(new ChatDeviceInfo(element)); }); return r; } /** * Force the specified account to logout from the specified device, to fetch the device ID: {@link ChatDeviceInfo#resource}. * * @param username The account you want to force logout. * @param password The account's password. * @param resource The device ID, see {@link ChatDeviceInfo#resource}. * * @throws Error, see {@link ChatError} */ public async kickDevice( username: string, password: string, resource: string ): Promise<void> { console.log( `${ChatClient.TAG}: kickDevice: ${username}, ${password}, ${resource}` ); let r: any = await Native._callMethod(MethodTypekickDevice, { [MethodTypekickDevice]: { username: username, password: password, resource: resource, }, }); ChatClient.hasErrorFromResult(r); } /** * Kicks out all the devices logged in under the specified account. * * @param username The account you want to log out from all the devices. * @param password The account's password. * * @throws Error, see {@link ChatError} */ public async kickAllDevices( username: string, password: string ): Promise<void> { console.log(`${ChatClient.TAG}: kickAllDevices: ${username}, ${password}`); let r: any = await Native._callMethod(MethodTypekickAllDevices, { [MethodTypekickAllDevices]: { username: username, password: password, }, }); ChatClient.hasErrorFromResult(r); } public addConnectionListener(listener: ChatConnectionListener): void { console.log(`${ChatClient.TAG}: addConnectionListener: `); this._connectionListeners.add(listener); } public removeConnectionListener(listener: ChatConnectionListener): void { console.log(`${ChatClient.TAG}: removeConnectionListener: `); this._connectionListeners.delete(listener); } public removeAllConnectionListener(): void { console.log(`${ChatClient.TAG}: removeAllConnectionListener: `); this._connectionListeners.clear(); } public addMultiDeviceListener(listener: ChatMultiDeviceListener): void { this._multiDeviceListeners.add(listener); } public removeMultiDeviceListener(listener: ChatMultiDeviceListener): void { this._multiDeviceListeners.delete(listener); } public removeAllMultiDeviceListener(): void { this._multiDeviceListeners.clear(); } public addCustomListener(listener: ChatCustomListener): void { this._customListeners.add(listener); } public removeCustomListener(listener: ChatCustomListener): void { this._customListeners.delete(listener); } public removeAllCustomListener(): void { this._customListeners.clear(); } public get chatManager(): ChatManager { return this._chatManager; } }