diff --git a/app/definitions/IRocketChat.ts b/app/definitions/IRocketChat.ts deleted file mode 100644 index 6fb88a263..000000000 --- a/app/definitions/IRocketChat.ts +++ /dev/null @@ -1,19 +0,0 @@ -import rocketchat from '../lib/rocketchat'; - -export type TRocketChat = typeof rocketchat; - -export interface IRocketChat extends TRocketChat { - closeListener: any; - usersListener: any; - notifyAllListener: any; - rolesListener: any; - notifyLoggedListener: any; - activeUsers: any; - _setUserTimer: any; - connectedListener: any; - connectingListener: any; - connectTimeout: any; - sdk: any; - activeUsersSubTimeout: any; - roomsSub: any; -} diff --git a/app/definitions/index.ts b/app/definitions/index.ts index a0d9d3ea9..4f7d7c3d3 100644 --- a/app/definitions/index.ts +++ b/app/definitions/index.ts @@ -22,7 +22,6 @@ export * from './IUser'; export * from './IServer'; export * from './ILoggedUser'; export * from './IServerHistory'; -export * from './IRocketChat'; export * from './ICertificate'; export * from './IUrl'; export * from './ICredentials'; diff --git a/app/lib/methods/getUsersPresence.ts b/app/lib/methods/getUsersPresence.ts index a416d11bf..1396ca563 100644 --- a/app/lib/methods/getUsersPresence.ts +++ b/app/lib/methods/getUsersPresence.ts @@ -6,20 +6,24 @@ import { store as reduxStore } from '../store/auxStore'; import { setActiveUsers } from '../../actions/activeUsers'; import { setUser } from '../../actions/login'; import database from '../database'; -import { IRocketChat, IUser } from '../../definitions'; +import { IUser } from '../../definitions'; import sdk from '../services/sdk'; import { compareServerVersion } from './helpers/compareServerVersion'; -export function subscribeUsersPresence(this: IRocketChat) { +export const _activeUsersSubTimeout: { activeUsersSubTimeout: boolean | ReturnType } = { + activeUsersSubTimeout: false +}; + +export function subscribeUsersPresence() { const serverVersion = reduxStore.getState().server.version as string; // if server is lower than 1.1.0 if (compareServerVersion(serverVersion, 'lowerThan', '1.1.0')) { - if (this.activeUsersSubTimeout) { - clearTimeout(this.activeUsersSubTimeout); - this.activeUsersSubTimeout = false; + if (_activeUsersSubTimeout.activeUsersSubTimeout) { + clearTimeout(_activeUsersSubTimeout.activeUsersSubTimeout as number); + _activeUsersSubTimeout.activeUsersSubTimeout = false; } - this.activeUsersSubTimeout = setTimeout(() => { + _activeUsersSubTimeout.activeUsersSubTimeout = setTimeout(() => { sdk.subscribe('activeUsers'); }, 5000); } else if (compareServerVersion(serverVersion, 'lowerThan', '4.1.0')) { diff --git a/app/lib/methods/index.ts b/app/lib/methods/index.ts index f90a2f085..72478500e 100644 --- a/app/lib/methods/index.ts +++ b/app/lib/methods/index.ts @@ -34,3 +34,4 @@ export * from './userPreferences'; export * from './userPreferencesMethods'; export * from './crashReport'; export * from './parseSettings'; +export * from './subscribeRooms'; diff --git a/app/lib/methods/logout.ts b/app/lib/methods/logout.ts index 4a84b6421..d36b0864b 100644 --- a/app/lib/methods/logout.ts +++ b/app/lib/methods/logout.ts @@ -8,11 +8,13 @@ import { BASIC_AUTH_KEY } from '../../utils/fetch'; import database, { getDatabase } from '../database'; import { isSsl } from '../../utils/url'; import log from '../../utils/log'; -import { ICertificate, IRocketChat } from '../../definitions'; +import { ICertificate } from '../../definitions'; import sdk from '../services/sdk'; import { CURRENT_SERVER, E2E_PRIVATE_KEY, E2E_PUBLIC_KEY, E2E_RANDOM_PASSWORD_KEY, TOKEN_KEY } from '../constants'; import UserPreferences from './userPreferences'; import { Services } from '../services'; +import { roomsSubscription } from './subscriptions/rooms'; +import { _activeUsersSubTimeout } from '.'; function removeServerKeys({ server, userId }: { server: string; userId?: string | null }) { UserPreferences.removeItem(`${TOKEN_KEY}-${server}`); @@ -98,15 +100,14 @@ export async function removeServer({ server }: { server: string }): Promise { - if (this.roomsSub) { - this.roomsSub.stop(); - this.roomsSub = null; +export async function logout({ server }: { server: string }): Promise { + if (roomsSubscription?.stop) { + roomsSubscription.stop(); } - if (this.activeUsersSubTimeout) { - clearTimeout(this.activeUsersSubTimeout); - this.activeUsersSubTimeout = false; + if (_activeUsersSubTimeout.activeUsersSubTimeout) { + clearTimeout(_activeUsersSubTimeout.activeUsersSubTimeout as number); + _activeUsersSubTimeout.activeUsersSubTimeout = false; } try { diff --git a/app/lib/methods/setUser.ts b/app/lib/methods/setUser.ts index 5d7f16752..0dc836cde 100644 --- a/app/lib/methods/setUser.ts +++ b/app/lib/methods/setUser.ts @@ -2,16 +2,35 @@ import { InteractionManager } from 'react-native'; import { setActiveUsers } from '../../actions/activeUsers'; import { setUser } from '../../actions/login'; +import { IUser } from '../../definitions'; import { store as reduxStore } from '../store/auxStore'; import { compareServerVersion } from './helpers/compareServerVersion'; -// TODO -export function _setUser(this: any, ddpMessage: { fields: any; id: any; cleared: any }) { - this.activeUsers = this.activeUsers || {}; +export interface IActiveUsers { + [key: string]: { status: string; statusText?: string } | string | boolean; + msg: string; + collection: string; + id: string; + cleared: boolean; + fields: { + emails: { + address: string; + verified: boolean; + }[]; + username: string; + status: string; + }; +} + +export const _activeUsers = { activeUsers: {} as IActiveUsers }; +export const _setUserTimer: { setUserTimer: null | ReturnType } = { setUserTimer: null }; + +export function _setUser(ddpMessage: IActiveUsers): void { + _activeUsers.activeUsers = _activeUsers.activeUsers || {}; const { user } = reduxStore.getState().login; if (ddpMessage.fields && user && user.id === ddpMessage.id) { - reduxStore.dispatch(setUser(ddpMessage.fields)); + reduxStore.dispatch(setUser(ddpMessage.fields as Partial)); } if (ddpMessage.cleared && user && user.id === ddpMessage.id) { @@ -20,21 +39,22 @@ export function _setUser(this: any, ddpMessage: { fields: any; id: any; cleared: const serverVersion = reduxStore.getState().server.version; if (compareServerVersion(serverVersion, 'lowerThan', '4.1.0')) { - if (!this._setUserTimer) { - this._setUserTimer = setTimeout(() => { - const activeUsersBatch = this.activeUsers; + if (!_setUserTimer.setUserTimer) { + _setUserTimer.setUserTimer = setTimeout(() => { + const activeUsersBatch = _activeUsers.activeUsers; InteractionManager.runAfterInteractions(() => { + // @ts-ignore reduxStore.dispatch(setActiveUsers(activeUsersBatch)); }); - this._setUserTimer = null; - return (this.activeUsers = {}); + _setUserTimer.setUserTimer = null; + _activeUsers.activeUsers = {} as IActiveUsers; }, 10000); } } if (!ddpMessage.fields) { - this.activeUsers[ddpMessage.id] = { status: 'offline' }; + _activeUsers.activeUsers[ddpMessage.id] = { status: 'offline' }; } else if (ddpMessage.fields.status) { - this.activeUsers[ddpMessage.id] = { status: ddpMessage.fields.status }; + _activeUsers.activeUsers[ddpMessage.id] = { status: ddpMessage.fields.status }; } } diff --git a/app/lib/methods/subscribeRooms.ts b/app/lib/methods/subscribeRooms.ts index 8d34195fa..8b8aab23d 100644 --- a/app/lib/methods/subscribeRooms.ts +++ b/app/lib/methods/subscribeRooms.ts @@ -1,22 +1,18 @@ import log from '../../utils/log'; -import subscribeRoomsTmp from './subscriptions/rooms'; +import subscribeRoomsTmp, { roomsSubscription } from './subscriptions/rooms'; -// TODO: remove this -export async function subscribeRooms(this: any) { - if (!this.roomsSub) { +export async function subscribeRooms(): Promise { + if (!roomsSubscription?.stop) { try { - // TODO: We need to change this naming. Maybe move this logic to the SDK? - this.roomsSub = await subscribeRoomsTmp.call(this); + await subscribeRoomsTmp(); } catch (e) { log(e); } } } -// TODO: remove this -export function unsubscribeRooms(this: any) { - if (this.roomsSub) { - this.roomsSub.stop(); - this.roomsSub = null; +export function unsubscribeRooms(): void { + if (roomsSubscription?.stop) { + roomsSubscription.stop(); } } diff --git a/app/lib/methods/subscriptions/rooms.ts b/app/lib/methods/subscriptions/rooms.ts index 001e07d42..7172cb458 100644 --- a/app/lib/methods/subscriptions/rooms.ts +++ b/app/lib/methods/subscriptions/rooms.ts @@ -44,6 +44,8 @@ let queue: { [key: string]: ISubscription | IRoom } = {}; let subTimer: number | null | false = null; const WINDOW_TIME = 500; +export let roomsSubscription: { stop: () => void } | null = null; + const createOrUpdateSubscription = async (subscription: ISubscription, room: IServerRoom | IRoom) => { try { const db = database.active; @@ -404,6 +406,7 @@ export default function subscribeRooms() { clearTimeout(subTimer); subTimer = false; } + roomsSubscription = null; }; streamListener = sdk.onStreamData('stream-notify-user', handleStreamMessageReceived); @@ -412,10 +415,8 @@ export default function subscribeRooms() { // set the server that started this task subServer = sdk.current.client.host; sdk.current.subscribeNotifyUser().catch((e: unknown) => console.log(e)); - - return { - stop: () => stop() - }; + roomsSubscription = { stop: () => stop() }; + return null; } catch (e) { log(e); return Promise.reject(); diff --git a/app/lib/rocketchat.ts b/app/lib/rocketchat.ts deleted file mode 100644 index e5fd4900d..000000000 --- a/app/lib/rocketchat.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { _setUser } from './methods/setUser'; -import { logout } from './methods/logout'; -import { subscribeRooms, unsubscribeRooms } from './methods/subscribeRooms'; -import { subscribeUsersPresence } from './methods/getUsersPresence'; -import { connect } from './services/connect'; - -const RocketChat = { - logout, - subscribeRooms, - unsubscribeRooms, - _setUser, - subscribeUsersPresence, - connect -}; - -export default RocketChat; diff --git a/app/lib/services/connect.ts b/app/lib/services/connect.ts index 875e0844b..229be4204 100644 --- a/app/lib/services/connect.ts +++ b/app/lib/services/connect.ts @@ -14,8 +14,7 @@ import { store } from '../store/auxStore'; import { loginRequest, setLoginServices, setUser } from '../../actions/login'; import sdk from './sdk'; import I18n from '../../i18n'; -import RocketChat from '../rocketchat'; -import { ICredentials, ILoggedUser, IRocketChat, STATUSES } from '../../definitions'; +import { ICredentials, ILoggedUser, STATUSES } from '../../definitions'; import { isIOS } from '../../utils/deviceInfo'; import { connectRequest, connectSuccess, disconnect as disconnectAction } from '../../actions/connect'; import { updatePermission } from '../../actions/permissions'; @@ -24,7 +23,7 @@ import { updateSettings } from '../../actions/settings'; import { defaultSettings, MIN_ROCKETCHAT_VERSION } from '../constants'; import { compareServerVersion } from '../methods/helpers/compareServerVersion'; import { onRolesChanged } from '../methods/getRoles'; -import { getSettings } from '../methods'; +import { getSettings, IActiveUsers, unsubscribeRooms, _activeUsers, _setUser, _setUserTimer } from '../methods'; interface IServices { [index: string]: string | boolean; @@ -35,11 +34,15 @@ interface IServices { service: string; } -// FIXME: Remove `this` context -function connect( - this: IRocketChat, - { server, logoutOnError = false }: { server: string; logoutOnError: boolean } -): Promise { +let connectingListener: any; +let connectedListener: any; +let closeListener: any; +let usersListener: any; +let notifyAllListener: any; +let rolesListener: any; +let notifyLoggedListener: any; + +function connect({ server, logoutOnError = false }: { server: string; logoutOnError: boolean }): Promise { return new Promise(resolve => { if (sdk.current?.client?.host === server) { return resolve(); @@ -49,39 +52,40 @@ function connect( store.dispatch(connectRequest()); - if (this.connectTimeout) { - clearTimeout(this.connectTimeout); + // It's not called anywhere else + // if (this.connectTimeout) { + // clearTimeout(this.connectTimeout); + // } + + if (connectingListener) { + connectingListener.then(stopListener); } - if (this.connectingListener) { - this.connectingListener.then(stopListener); + if (connectedListener) { + connectedListener.then(stopListener); } - if (this.connectedListener) { - this.connectedListener.then(stopListener); + if (closeListener) { + closeListener.then(stopListener); } - if (this.closeListener) { - this.closeListener.then(stopListener); + if (usersListener) { + usersListener.then(stopListener); } - if (this.usersListener) { - this.usersListener.then(stopListener); + if (notifyAllListener) { + notifyAllListener.then(stopListener); } - if (this.notifyAllListener) { - this.notifyAllListener.then(stopListener); + if (rolesListener) { + rolesListener.then(stopListener); } - if (this.rolesListener) { - this.rolesListener.then(stopListener); + if (notifyLoggedListener) { + notifyLoggedListener.then(stopListener); } - if (this.notifyLoggedListener) { - this.notifyLoggedListener.then(stopListener); - } - - this.unsubscribeRooms(); + unsubscribeRooms(); EventEmitter.emit('INQUIRY_UNSUBSCRIBE'); @@ -97,11 +101,11 @@ function connect( console.log('connect error', err); }); - this.connectingListener = sdk.current.onStreamData('connecting', () => { + connectingListener = sdk.current.onStreamData('connecting', () => { store.dispatch(connectRequest()); }); - this.connectedListener = sdk.current.onStreamData('connected', () => { + connectedListener = sdk.current.onStreamData('connected', () => { const { connected } = store.getState().meteor; if (connected) { return; @@ -113,16 +117,16 @@ function connect( } }); - this.closeListener = sdk.current.onStreamData('close', () => { + closeListener = sdk.current.onStreamData('close', () => { store.dispatch(disconnectAction()); }); - this.usersListener = sdk.current.onStreamData( + usersListener = sdk.current.onStreamData( 'users', - protectedFunction((ddpMessage: any) => RocketChat._setUser(ddpMessage)) + protectedFunction((ddpMessage: any) => _setUser(ddpMessage)) ); - this.notifyAllListener = sdk.current.onStreamData( + notifyAllListener = sdk.current.onStreamData( 'stream-notify-all', protectedFunction(async (ddpMessage: { fields: { args?: any; eventName: string } }) => { const { eventName } = ddpMessage.fields; @@ -150,7 +154,7 @@ function connect( }) ); - this.rolesListener = sdk.current.onStreamData( + rolesListener = sdk.current.onStreamData( 'stream-roles', protectedFunction((ddpMessage: any) => onRolesChanged(ddpMessage)) ); @@ -171,27 +175,29 @@ function connect( } }); - this.notifyLoggedListener = sdk.current.onStreamData( + notifyLoggedListener = sdk.current.onStreamData( 'stream-notify-logged', protectedFunction(async (ddpMessage: { fields: { args?: any; eventName?: any } }) => { const { eventName } = ddpMessage.fields; // `user-status` event is deprecated after RC 4.1 in favor of `stream-user-presence/${uid}` if (/user-status/.test(eventName)) { - this.activeUsers = this.activeUsers || {}; - if (!this._setUserTimer) { - this._setUserTimer = setTimeout(() => { - const activeUsersBatch = this.activeUsers; + _activeUsers.activeUsers = _activeUsers.activeUsers || {}; + if (!_setUserTimer.setUserTimer) { + _setUserTimer.setUserTimer = setTimeout(() => { + const activeUsersBatch = _activeUsers.activeUsers; InteractionManager.runAfterInteractions(() => { + // @ts-ignore store.dispatch(setActiveUsers(activeUsersBatch)); }); - this._setUserTimer = null; - return (this.activeUsers = {}); + _setUserTimer.setUserTimer = null; + _activeUsers.activeUsers = {} as IActiveUsers; + return null; }, 10000); } const userStatus = ddpMessage.fields.args[0]; const [id, , status, statusText] = userStatus; - this.activeUsers[id] = { status: STATUSES[status], statusText }; + _activeUsers.activeUsers[id] = { status: STATUSES[status], statusText }; const { user: loggedUser } = store.getState().login; if (loggedUser && loggedUser.id === id) { diff --git a/app/lib/services/restApi.ts b/app/lib/services/restApi.ts index 04f4ca967..58eac22c4 100644 --- a/app/lib/services/restApi.ts +++ b/app/lib/services/restApi.ts @@ -16,10 +16,9 @@ import { TParams } from '../../definitions/ILivechatEditView'; import { store as reduxStore } from '../store/auxStore'; import { getDeviceToken } from '../notifications'; import { getBundleId, isIOS } from '../../utils/deviceInfo'; -import { RoomTypes, roomTypeToApiType } from '../methods'; +import { RoomTypes, roomTypeToApiType, unsubscribeRooms } from '../methods'; import sdk from './sdk'; import { compareServerVersion } from '../methods/helpers/compareServerVersion'; -import RocketChat from '../rocketchat'; export const createChannel = ({ name, @@ -807,7 +806,7 @@ export const emitTyping = (room: IRoom, typing = true) => { export function e2eResetOwnKey(): Promise { // {} when TOTP is enabled - RocketChat.unsubscribeRooms(); + unsubscribeRooms(); // RC 0.72.0 return sdk.methodCallWrapper('e2e.resetOwnE2EKey'); diff --git a/app/sagas/login.js b/app/sagas/login.js index 4ff0a6ba5..1d11d98a3 100644 --- a/app/sagas/login.js +++ b/app/sagas/login.js @@ -7,7 +7,6 @@ import { appStart } from '../actions/app'; import { selectServerRequest, serverFinishAdd } from '../actions/server'; import { loginFailure, loginSuccess, logout as logoutAction, setUser } from '../actions/login'; import { roomsRequest } from '../actions/rooms'; -import RocketChat from '../lib/rocketchat'; import log, { events, logEvent } from '../utils/log'; import I18n, { setLanguage } from '../i18n'; import database from '../lib/database'; @@ -30,14 +29,16 @@ import { getSlashCommands, getUserPresence, isOmnichannelModuleAvailable, - subscribeSettings + logout, + subscribeSettings, + subscribeUsersPresence } from '../lib/methods'; import { Services } from '../lib/services'; const getServer = state => state.server.server; const loginWithPasswordCall = args => Services.loginWithPassword(args); const loginCall = (credentials, isFromWebView) => Services.login(credentials, isFromWebView); -const logoutCall = args => RocketChat.logout(args); +const logoutCall = args => logout(args); const handleLoginRequest = function* handleLoginRequest({ credentials, logoutOnError = false, isFromWebView = false }) { logEvent(events.LOGIN_DEFAULT_LOGIN); @@ -114,7 +115,7 @@ const registerPushTokenFork = function* registerPushTokenFork() { }; const fetchUsersPresenceFork = function* fetchUsersPresenceFork() { - RocketChat.subscribeUsersPresence(); + subscribeUsersPresence(); }; const fetchEnterpriseModulesFork = function* fetchEnterpriseModulesFork({ user }) { diff --git a/app/sagas/rooms.js b/app/sagas/rooms.js index ee7cacef4..ffe1a4a8c 100644 --- a/app/sagas/rooms.js +++ b/app/sagas/rooms.js @@ -7,9 +7,8 @@ import { roomsFailure, roomsRefresh, roomsSuccess } from '../actions/rooms'; import database from '../lib/database'; import log from '../utils/log'; import mergeSubscriptionsRooms from '../lib/methods/helpers/mergeSubscriptionsRooms'; -import RocketChat from '../lib/rocketchat'; import buildMessage from '../lib/methods/helpers/buildMessage'; -import { getRooms } from '../lib/methods'; +import { getRooms, subscribeRooms } from '../lib/methods'; const updateRooms = function* updateRooms({ server, newRoomsUpdatedAt }) { const serversDB = database.servers; @@ -30,7 +29,7 @@ const updateRooms = function* updateRooms({ server, newRoomsUpdatedAt }) { const handleRoomsRequest = function* handleRoomsRequest({ params }) { try { const serversDB = database.servers; - RocketChat.subscribeRooms(); + subscribeRooms(); const newRoomsUpdatedAt = new Date(); let roomsUpdatedAt; const server = yield select(state => state.server.server); diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js index ee211c1e9..8dcdf4894 100644 --- a/app/sagas/selectServer.js +++ b/app/sagas/selectServer.js @@ -11,7 +11,6 @@ import { selectServerFailure, selectServerRequest, selectServerSuccess, serverFa import { clearSettings } from '../actions/settings'; import { clearUser, setUser } from '../actions/login'; import { clearActiveUsers } from '../actions/activeUsers'; -import RocketChat from '../lib/rocketchat'; import database from '../lib/database'; import log, { logServerVersion } from '../utils/log'; import I18n from '../i18n'; @@ -25,6 +24,7 @@ import { RootEnum } from '../definitions'; import { CERTIFICATE_KEY, CURRENT_SERVER, TOKEN_KEY } from '../lib/constants'; import { getLoginSettings, setCustomEmojis, setEnterpriseModules, setPermissions, setRoles, setSettings } from '../lib/methods'; import { Services } from '../lib/services'; +import { connect } from '../lib/services/connect'; const getServerInfo = function* getServerInfo({ server, raiseError = true }) { try { @@ -115,11 +115,11 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch if (user) { yield put(clearSettings()); yield put(setUser(user)); - yield RocketChat.connect({ server, logoutOnError: true }); + yield connect({ server, logoutOnError: true }); yield put(appStart({ root: RootEnum.ROOT_INSIDE })); } else { yield put(clearUser()); - yield RocketChat.connect({ server }); + yield connect({ server }); yield put(appStart({ root: RootEnum.ROOT_OUTSIDE })); } diff --git a/app/utils/fetch.ts b/app/utils/fetch.ts index 17569798e..706f2c3d9 100644 --- a/app/utils/fetch.ts +++ b/app/utils/fetch.ts @@ -2,8 +2,6 @@ import { Platform } from 'react-native'; import DeviceInfo from 'react-native-device-info'; import { settings as RocketChatSettings } from '@rocket.chat/sdk'; -import RocketChat from '../lib/rocketchat'; - export type TMethods = 'POST' | 'GET' | 'DELETE' | 'PUT' | 'post' | 'get' | 'delete' | 'put'; interface CustomHeaders { @@ -46,13 +44,11 @@ export default (url: string, options: IOptions = {}): Promise => { if (options && options.headers) { customOptions = { ...customOptions, headers: { ...options.headers, ...customOptions.headers } }; } - // TODO: Refactor when migrate rocketchat.js - // @ts-ignore - // WHAT? - if (RocketChat.controller) { - // @ts-ignore - const { signal } = RocketChat.controller; - customOptions = { ...customOptions, signal }; - } + // TODO: Check if this really works and if anyone else has complained about this problem. + // if (RocketChat.controller) { + // // @ts-ignore + // const { signal } = RocketChat.controller; + // customOptions = { ...customOptions, signal }; + // } return fetch(url, customOptions); };