[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 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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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}
|
||||
>
|
||||
<HeaderTitle connecting={connecting} isFetching={isFetching} theme={theme} />
|
||||
<View style={styles.button}>
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
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=
|
||||
|
|
Loading…
Reference in New Issue