[IMPROVEMENT] Change server while connecting/updating (#1981)
* [IMPROVEMENT] Change server while connecting * [FIX] Not login/reconnect to previous server * [FIX] Abort all fetch while connecting * [FIX] Abort sdk fetch * [FIX] Patch-package * Add comments Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
ee5b7592b4
commit
c578f1bbe8
|
@ -47,6 +47,7 @@ import { getDeviceToken } from '../notifications/push';
|
||||||
import { setActiveUsers } from '../actions/activeUsers';
|
import { setActiveUsers } from '../actions/activeUsers';
|
||||||
import I18n from '../i18n';
|
import I18n from '../i18n';
|
||||||
import { twoFactor } from '../utils/twoFactor';
|
import { twoFactor } from '../utils/twoFactor';
|
||||||
|
import { selectServerFailure } from '../actions/server';
|
||||||
import { useSsl } from '../utils/url';
|
import { useSsl } from '../utils/url';
|
||||||
|
|
||||||
const TOKEN_KEY = 'reactnativemeteor_usertoken';
|
const TOKEN_KEY = 'reactnativemeteor_usertoken';
|
||||||
|
@ -142,6 +143,10 @@ const RocketChat = {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e.message === 'Aborted') {
|
||||||
|
reduxStore.dispatch(selectServerFailure());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
log(e);
|
log(e);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
@ -155,6 +160,16 @@ const RocketChat = {
|
||||||
stopListener(listener) {
|
stopListener(listener) {
|
||||||
return listener && listener.stop();
|
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 }) {
|
connect({ server, user, logoutOnError = false }) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (!this.sdk || this.sdk.client.host !== server) {
|
if (!this.sdk || this.sdk.client.host !== server) {
|
||||||
|
@ -201,17 +216,21 @@ const RocketChat = {
|
||||||
|
|
||||||
const sdkConnect = () => this.sdk.connect()
|
const sdkConnect = () => this.sdk.connect()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (user && user.token) {
|
const { server: currentServer } = reduxStore.getState().server;
|
||||||
|
if (user && user.token && server === currentServer) {
|
||||||
reduxStore.dispatch(loginRequest({ resume: user.token }, logoutOnError));
|
reduxStore.dispatch(loginRequest({ resume: user.token }, logoutOnError));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log('connect error', err);
|
console.log('connect error', err);
|
||||||
|
|
||||||
// when `connect` raises an error, we try again in 10 seconds
|
const { server: currentServer } = reduxStore.getState().server;
|
||||||
this.connectTimeout = setTimeout(() => {
|
if (server === currentServer) {
|
||||||
sdkConnect();
|
// when `connect` raises an error, we try again in 10 seconds
|
||||||
}, 10000);
|
this.connectTimeout = setTimeout(() => {
|
||||||
|
sdkConnect();
|
||||||
|
}, 10000);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sdkConnect();
|
sdkConnect();
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
import {
|
import { put, takeLatest } from 'redux-saga/effects';
|
||||||
put, take, takeLatest, fork, cancel, race
|
|
||||||
} from 'redux-saga/effects';
|
|
||||||
import { Alert } from 'react-native';
|
import { Alert } from 'react-native';
|
||||||
import RNUserDefaults from 'rn-user-defaults';
|
import RNUserDefaults from 'rn-user-defaults';
|
||||||
import { sanitizedRaw } from '@nozbe/watermelondb/RawRecord';
|
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 }`);
|
const basicAuth = yield RNUserDefaults.get(`${ BASIC_AUTH_KEY }-${ server }`);
|
||||||
setBasicAuth(basicAuth);
|
setBasicAuth(basicAuth);
|
||||||
|
|
||||||
|
// Check for running requests and abort them before connecting to the server
|
||||||
|
RocketChat.abort();
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
yield put(clearSettings());
|
yield put(clearSettings());
|
||||||
yield RocketChat.connect({ server, user, logoutOnError: true });
|
yield RocketChat.connect({ server, user, logoutOnError: true });
|
||||||
|
@ -152,16 +153,6 @@ const handleServerRequest = function* handleServerRequest({ server, certificate
|
||||||
|
|
||||||
const root = function* root() {
|
const root = function* root() {
|
||||||
yield takeLatest(SERVER.REQUEST, handleServerRequest);
|
yield takeLatest(SERVER.REQUEST, handleServerRequest);
|
||||||
|
yield takeLatest(SERVER.SELECT_REQUEST, handleSelectServer);
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
export default root;
|
export default root;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Platform } from 'react-native';
|
import { Platform } from 'react-native';
|
||||||
import DeviceInfo from 'react-native-device-info';
|
import DeviceInfo from 'react-native-device-info';
|
||||||
import { settings as RocketChatSettings } from '@rocket.chat/sdk';
|
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"
|
// this form is required by Rocket.Chat's parser in "app/statistics/server/lib/UAParserCustom.js"
|
||||||
export const headers = {
|
export const headers = {
|
||||||
|
@ -25,5 +26,9 @@ export default (url, options = {}) => {
|
||||||
if (options && options.headers) {
|
if (options && options.headers) {
|
||||||
customOptions = { ...customOptions, headers: { ...options.headers, ...customOptions.headers } };
|
customOptions = { ...customOptions, headers: { ...options.headers, ...customOptions.headers } };
|
||||||
}
|
}
|
||||||
|
if (RocketChat.controller) {
|
||||||
|
const { signal } = RocketChat.controller;
|
||||||
|
customOptions = { ...customOptions, signal };
|
||||||
|
}
|
||||||
return fetch(url, customOptions);
|
return fetch(url, customOptions);
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,7 +56,7 @@ const Header = React.memo(({
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
testID='rooms-list-header-server-dropdown-button'
|
testID='rooms-list-header-server-dropdown-button'
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
disabled={connecting || isFetching}
|
// disabled={connecting || isFetching}
|
||||||
>
|
>
|
||||||
<HeaderTitle connecting={connecting} isFetching={isFetching} theme={theme} />
|
<HeaderTitle connecting={connecting} isFetching={isFetching} theme={theme} />
|
||||||
<View style={styles.button}>
|
<View style={styles.button}>
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
"react-native-responsive-ui": "^1.1.1",
|
"react-native-responsive-ui": "^1.1.1",
|
||||||
"react-native-screens": "^2.0.0-alpha.3",
|
"react-native-screens": "^2.0.0-alpha.3",
|
||||||
"react-native-scrollable-tab-view": "^1.0.0",
|
"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-unimodules": "0.5.3",
|
||||||
"react-native-vector-icons": "6.6.0",
|
"react-native-vector-icons": "6.6.0",
|
||||||
"react-native-webview": "7.5.1",
|
"react-native-webview": "7.5.1",
|
||||||
|
|
|
@ -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<any> {
|
||||||
|
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<any> {
|
||||||
|
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<any> {
|
||||||
|
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 (
|
|
@ -10072,7 +10072,7 @@ react-native-scrollable-tab-view@^1.0.0:
|
||||||
prop-types "^15.6.0"
|
prop-types "^15.6.0"
|
||||||
react-timer-mixin "^0.13.3"
|
react-timer-mixin "^0.13.3"
|
||||||
|
|
||||||
react-native-slowlog@^1.0.2:
|
react-native-slowlog@1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-native-slowlog/-/react-native-slowlog-1.0.2.tgz#5520979e3ef9d5273495d431ff3be34f02e35c89"
|
resolved "https://registry.yarnpkg.com/react-native-slowlog/-/react-native-slowlog-1.0.2.tgz#5520979e3ef9d5273495d431ff3be34f02e35c89"
|
||||||
integrity sha1-VSCXnj751Sc0ldQx/zvjTwLjXIk=
|
integrity sha1-VSCXnj751Sc0ldQx/zvjTwLjXIk=
|
||||||
|
|
Loading…
Reference in New Issue