diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 5bef3ad8..80fd2972 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -47,6 +47,7 @@ import { getDeviceToken } from '../notifications/push';
import { setActiveUsers } from '../actions/activeUsers';
import I18n from '../i18n';
import { twoFactor } from '../utils/twoFactor';
+import { selectServerFailure } from '../actions/server';
import { useSsl } from '../utils/url';
const TOKEN_KEY = 'reactnativemeteor_usertoken';
@@ -142,6 +143,10 @@ const RocketChat = {
}
return result;
} catch (e) {
+ if (e.message === 'Aborted') {
+ reduxStore.dispatch(selectServerFailure());
+ throw e;
+ }
log(e);
}
return {
@@ -155,6 +160,16 @@ const RocketChat = {
stopListener(listener) {
return listener && listener.stop();
},
+ // Abort all requests and create a new AbortController
+ abort() {
+ if (this.controller) {
+ this.controller.abort();
+ if (this.sdk) {
+ this.sdk.abort();
+ }
+ }
+ this.controller = new AbortController();
+ },
connect({ server, user, logoutOnError = false }) {
return new Promise((resolve) => {
if (!this.sdk || this.sdk.client.host !== server) {
@@ -201,17 +216,21 @@ const RocketChat = {
const sdkConnect = () => this.sdk.connect()
.then(() => {
- if (user && user.token) {
+ const { server: currentServer } = reduxStore.getState().server;
+ if (user && user.token && server === currentServer) {
reduxStore.dispatch(loginRequest({ resume: user.token }, logoutOnError));
}
})
.catch((err) => {
console.log('connect error', err);
- // when `connect` raises an error, we try again in 10 seconds
- this.connectTimeout = setTimeout(() => {
- sdkConnect();
- }, 10000);
+ const { server: currentServer } = reduxStore.getState().server;
+ if (server === currentServer) {
+ // when `connect` raises an error, we try again in 10 seconds
+ this.connectTimeout = setTimeout(() => {
+ sdkConnect();
+ }, 10000);
+ }
});
sdkConnect();
diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js
index ed26c454..7596e05d 100644
--- a/app/sagas/selectServer.js
+++ b/app/sagas/selectServer.js
@@ -1,6 +1,4 @@
-import {
- put, take, takeLatest, fork, cancel, race
-} from 'redux-saga/effects';
+import { put, takeLatest } from 'redux-saga/effects';
import { Alert } from 'react-native';
import RNUserDefaults from 'rn-user-defaults';
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
@@ -98,6 +96,9 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch
const basicAuth = yield RNUserDefaults.get(`${ BASIC_AUTH_KEY }-${ server }`);
setBasicAuth(basicAuth);
+ // Check for running requests and abort them before connecting to the server
+ RocketChat.abort();
+
if (user) {
yield put(clearSettings());
yield RocketChat.connect({ server, user, logoutOnError: true });
@@ -152,16 +153,6 @@ const handleServerRequest = function* handleServerRequest({ server, certificate
const root = function* root() {
yield takeLatest(SERVER.REQUEST, handleServerRequest);
-
- while (true) {
- const params = yield take(SERVER.SELECT_REQUEST);
- const selectServerTask = yield fork(handleSelectServer, params);
- yield race({
- request: take(SERVER.SELECT_REQUEST),
- success: take(SERVER.SELECT_SUCCESS),
- failure: take(SERVER.SELECT_FAILURE)
- });
- yield cancel(selectServerTask);
- }
+ yield takeLatest(SERVER.SELECT_REQUEST, handleSelectServer);
};
export default root;
diff --git a/app/utils/fetch.js b/app/utils/fetch.js
index 7b0fae13..a804e0a1 100644
--- a/app/utils/fetch.js
+++ b/app/utils/fetch.js
@@ -1,6 +1,7 @@
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';
// this form is required by Rocket.Chat's parser in "app/statistics/server/lib/UAParserCustom.js"
export const headers = {
@@ -25,5 +26,9 @@ export default (url, options = {}) => {
if (options && options.headers) {
customOptions = { ...customOptions, headers: { ...options.headers, ...customOptions.headers } };
}
+ if (RocketChat.controller) {
+ const { signal } = RocketChat.controller;
+ customOptions = { ...customOptions, signal };
+ }
return fetch(url, customOptions);
};
diff --git a/app/views/RoomsListView/Header/Header.ios.js b/app/views/RoomsListView/Header/Header.ios.js
index 31f887cf..35a8a65d 100644
--- a/app/views/RoomsListView/Header/Header.ios.js
+++ b/app/views/RoomsListView/Header/Header.ios.js
@@ -56,7 +56,7 @@ const Header = React.memo(({
onPress={onPress}
testID='rooms-list-header-server-dropdown-button'
style={styles.container}
- disabled={connecting || isFetching}
+ // disabled={connecting || isFetching}
>
diff --git a/package.json b/package.json
index c431048d..d1719e29 100644
--- a/package.json
+++ b/package.json
@@ -85,7 +85,7 @@
"react-native-responsive-ui": "^1.1.1",
"react-native-screens": "^2.0.0-alpha.3",
"react-native-scrollable-tab-view": "^1.0.0",
- "react-native-slowlog": "^1.0.2",
+ "react-native-slowlog": "1.0.2",
"react-native-unimodules": "0.5.3",
"react-native-vector-icons": "6.6.0",
"react-native-webview": "7.5.1",
diff --git a/patches/@rocket.chat+sdk+1.0.0-dj.15.patch b/patches/@rocket.chat+sdk+1.0.0-dj.15.patch
new file mode 100644
index 00000000..cf698fd9
--- /dev/null
+++ b/patches/@rocket.chat+sdk+1.0.0-dj.15.patch
@@ -0,0 +1,83 @@
+diff --git a/node_modules/@rocket.chat/sdk/lib/api/api.ts b/node_modules/@rocket.chat/sdk/lib/api/api.ts
+index 17c2c2b..cb094e8 100644
+--- a/node_modules/@rocket.chat/sdk/lib/api/api.ts
++++ b/node_modules/@rocket.chat/sdk/lib/api/api.ts
+@@ -117,24 +117,31 @@ class Client implements IClient {
+ JSON.stringify(data)
+ }
+
++ getSignal (options?: any): AbortSignal {
++ return options && options.signal;
++ }
++
+ get (url: string, data: any, options?: any): Promise {
+ return fetch(`${this.host}/api/v1/${encodeURI(url)}?${this.getParams(data)}`, {
+ method: 'GET',
+- headers: this.getHeaders(options)
++ headers: this.getHeaders(options),
++ signal: this.getSignal(options)
+ }).then(this.handle)
+ }
+ post (url: string, data: any, options?: any): Promise {
+ return fetch(`${this.host}/api/v1/${encodeURI(url)}`, {
+ method: 'POST',
+ body: this.getBody(data),
+- headers: this.getHeaders(options)
++ headers: this.getHeaders(options),
++ signal: this.getSignal(options)
+ }).then(this.handle)
+ }
+ put (url: string, data: any, options?: any): Promise {
+ return fetch(`${this.host}/api/v1/${encodeURI(url)}`, {
+ method: 'PUT',
+ body: this.getBody(data),
+- headers: this.getHeaders(options)
++ headers: this.getHeaders(options),
++ signal: this.getSignal(options)
+ }).then(this.handle)
+ }
+
+@@ -142,7 +149,8 @@ class Client implements IClient {
+ return fetch(`${this.host}/api/v1/${encodeURI(url)}`, {
+ method: 'DELETE',
+ body: this.getBody(data),
+- headers: this.getHeaders(options)
++ headers: this.getHeaders(options),
++ signal: this.getSignal(options)
+ }).then(this.handle)
+ }
+ private async handle (r: any) {
+@@ -176,11 +184,13 @@ export default class Api extends EventEmitter {
+ authToken: string,
+ result: ILoginResultAPI
+ } | null = null
++ controller: AbortController
+
+ constructor ({ client, host, logger = Logger }: any) {
+ super()
+ this.client = client || new Client({ host } as any)
+ this.logger = Logger
++ this.controller = new AbortController();
+ }
+
+ get username () {
+@@ -212,6 +222,10 @@ export default class Api extends EventEmitter {
+ if (auth && !this.loggedIn()) {
+ throw new Error('')
+ }
++
++ const { signal } = this.controller;
++ options = { ...options, signal };
++
+ let result
+ switch (method) {
+ case 'GET': result = await this.client.get(endpoint, data, options); break
+@@ -242,6 +256,8 @@ export default class Api extends EventEmitter {
+ /** Do a DELETE request to an API endpoint. */
+ del: IAPIRequest = (endpoint, data, auth, ignore, options = {}) => this.request('DELETE', endpoint, data, auth, ignore, options)
+
++ abort = (): void => this.controller.abort()
++
+ /** Check result data for success, allowing override to ignore some errors */
+ success (result: any, ignore?: RegExp) {
+ return (
diff --git a/yarn.lock b/yarn.lock
index 6341ed12..deea80c0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10072,7 +10072,7 @@ react-native-scrollable-tab-view@^1.0.0:
prop-types "^15.6.0"
react-timer-mixin "^0.13.3"
-react-native-slowlog@^1.0.2:
+react-native-slowlog@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-native-slowlog/-/react-native-slowlog-1.0.2.tgz#5520979e3ef9d5273495d431ff3be34f02e35c89"
integrity sha1-VSCXnj751Sc0ldQx/zvjTwLjXIk=