Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IMPROVEMENT] Change server while connecting/updating #1981

Merged
merged 7 commits into from
May 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions app/lib/rocketchat.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -142,6 +143,10 @@ const RocketChat = {
}
return result;
} catch (e) {
if (e.message === 'Aborted') {
reduxStore.dispatch(selectServerFailure());
throw e;
}
log(e);
}
return {
Expand All @@ -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) {
Expand Down Expand Up @@ -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();
Expand Down
19 changes: 5 additions & 14 deletions app/sagas/selectServer.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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 });
Expand Down Expand Up @@ -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;
5 changes: 5 additions & 0 deletions app/utils/fetch.js
Original file line number Diff line number Diff line change
@@ -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 = {
Expand All @@ -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);
};
2 changes: 1 addition & 1 deletion app/views/RoomsListView/Header/Header.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
83 changes: 83 additions & 0 deletions patches/@rocket.chat+sdk+1.0.0-dj.15.patch
Original file line number Diff line number Diff line change
@@ -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 (
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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:
[email protected]:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-native-slowlog/-/react-native-slowlog-1.0.2.tgz#5520979e3ef9d5273495d431ff3be34f02e35c89"
integrity sha1-VSCXnj751Sc0ldQx/zvjTwLjXIk=
Expand Down