From 63a6a9ee91a38c04fcb603a63ec9ff89c3fe25ef Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Tue, 19 Jun 2018 13:08:34 -0400 Subject: [PATCH] Replacing fetch with RNFetchBlob (#1782) --- app/fetch_preconfig.js | 96 ++++++++++++++++++++++++++++++ app/mattermost.js | 1 + app/screens/permalink/permalink.js | 21 +++++-- package-lock.json | 4 +- package.json | 2 +- 5 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 app/fetch_preconfig.js diff --git a/app/fetch_preconfig.js b/app/fetch_preconfig.js new file mode 100644 index 000000000..c3c8af3e7 --- /dev/null +++ b/app/fetch_preconfig.js @@ -0,0 +1,96 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import RNFetchBlob from 'react-native-fetch-blob'; + +import {Client4} from 'mattermost-redux/client'; +import {General} from 'mattermost-redux/constants'; +import EventEmitter from 'mattermost-redux/utils/event_emitter'; + +const HEADER_X_VERSION_ID = 'X-Version-Id'; +const HEADER_X_CLUSTER_ID = 'X-Cluster-Id'; +const HEADER_TOKEN = 'Token'; + +Client4.doFetchWithResponse = async (url, options) => { + if (!Client4.online) { + throw { + message: 'no internet connection', + url, + }; + } + const response = await fetch(url, Client4.getOptions(options)); + const headers = response.headers; + + let data; + try { + data = await response.json(); + } catch (err) { + if (response && response.resp && response.resp.data && response.resp.data.includes('SSL certificate')) { + throw { + message: 'You need to use a valid client certificate in order to connect to this Mattermost server', + status_code: 401, + url, + }; + } + + throw { + intl: { + id: 'mobile.request.invalid_response', + defaultMessage: 'Received invalid response from the server.', + }, + }; + } + + // Need to only accept version in the header from requests that are not cached + // to avoid getting an old version from a cached response + if ((headers[HEADER_X_VERSION_ID] || headers[HEADER_X_VERSION_ID.toLowerCase()]) && + (!headers['Cache-Control'] && !headers['cache-control'])) { + const serverVersion = headers[HEADER_X_VERSION_ID] || headers[HEADER_X_VERSION_ID.toLowerCase()]; + if (serverVersion && this.serverVersion !== serverVersion) { + this.serverVersion = serverVersion; + EventEmitter.emit(General.SERVER_VERSION_CHANGED, serverVersion); + } + } + + if (headers[HEADER_X_CLUSTER_ID] || headers[HEADER_X_CLUSTER_ID.toLowerCase()]) { + const clusterId = headers[HEADER_X_CLUSTER_ID] || headers[HEADER_X_CLUSTER_ID.toLowerCase()]; + if (clusterId && this.clusterId !== clusterId) { + this.clusterId = clusterId; + } + } + + if (headers[HEADER_TOKEN] || headers[HEADER_TOKEN.toLowerCase()]) { + const token = headers[HEADER_TOKEN] || headers[HEADER_TOKEN.toLowerCase()]; + Client4.setToken(token); + } + + if (response.ok) { + const headersMap = new Map(); + Object.keys(headers).forEach((key) => { + headersMap.set(key, headers[key]); + }); + + return { + response, + headers: headersMap, + data, + }; + } + + const msg = data.message || ''; + + if (Client4.logToConsole) { + console.error(msg); // eslint-disable-line no-console + } + + throw { + message: msg, + server_error_id: data.id, + status_code: data.status_code, + url, + }; +}; + +window.fetch = new RNFetchBlob.polyfill.Fetch({ + auto: true, +}).build(); diff --git a/app/mattermost.js b/app/mattermost.js index 23a234bd4..326e14af6 100644 --- a/app/mattermost.js +++ b/app/mattermost.js @@ -48,6 +48,7 @@ import avoidNativeBridge from 'app/utils/avoid_native_bridge'; import LocalConfig from 'assets/config'; import App from './app'; +import './fetch_preconfig'; const AUTHENTICATION_TIMEOUT = 5 * 60 * 1000; diff --git a/app/screens/permalink/permalink.js b/app/screens/permalink/permalink.js index 9dde08fc5..88963a3e2 100644 --- a/app/screens/permalink/permalink.js +++ b/app/screens/permalink/permalink.js @@ -103,21 +103,23 @@ export default class Permalink extends PureComponent { } componentWillMount() { + this.mounted = true; + if (this.state.loading) { this.loadPosts(this.props); } } componentWillReceiveProps(nextProps) { - if (nextProps.channelId === '') { + if (nextProps.channelId === '' && this.mounted) { this.handleClose(); } - if (this.props.channelName !== nextProps.channelName) { + if (this.props.channelName !== nextProps.channelName && this.mounted) { this.setState({title: nextProps.channelName}); } - if (this.props.focusedPostId !== nextProps.focusedPostId) { + if (this.props.focusedPostId !== nextProps.focusedPostId && this.mounted) { this.setState({loading: true}); if (nextProps.postIds && nextProps.postIds.length < 10) { this.loadPosts(nextProps); @@ -127,6 +129,10 @@ export default class Permalink extends PureComponent { } } + componentWillUnmount() { + this.mounted = false; + } + goToThread = preventDoubleTap((post) => { const {actions, navigator, theme} = this.props; const channelId = post.channel_id; @@ -157,6 +163,7 @@ export default class Permalink extends PureComponent { handleClose = () => { const {actions, navigator, onClose} = this.props; if (this.refs.view) { + this.mounted = false; this.refs.view.zoomOut().then(() => { actions.selectPost(''); navigator.dismissModal({animationType: 'none'}); @@ -233,7 +240,7 @@ export default class Permalink extends PureComponent { let focusChannelId = channelId; const post = await actions.getPostThread(focusedPostId, false); - if (post.error && (!postIds || !postIds.length)) { + if (this.mounted && post.error && (!postIds || !postIds.length)) { if (isPermalink && post.error.message.toLowerCase() !== 'network request failed') { this.setState({ error: formatMessage({ @@ -281,8 +288,10 @@ export default class Permalink extends PureComponent { }; retry = () => { - this.setState({loading: true, error: null, retry: false}); - this.loadPosts(this.props); + if (this.mounted) { + this.setState({loading: true, error: null, retry: false}); + this.loadPosts(this.props); + } }; render() { diff --git a/package-lock.json b/package-lock.json index e6e7aaf7b..fbacbd451 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14484,8 +14484,8 @@ } }, "react-native-fetch-blob": { - "version": "github:enahum/react-native-fetch-blob#2e8f9b05b012496bd3ff9790aace3f2b462e2fee", - "from": "react-native-fetch-blob@github:enahum/react-native-fetch-blob#2e8f9b05b012496bd3ff9790aace3f2b462e2fee", + "version": "github:enahum/react-native-fetch-blob#c4c798032d9c255fbae75d13a0a985af9b8b42ca", + "from": "github:enahum/react-native-fetch-blob#c4c798032d9c255fbae75d13a0a985af9b8b42ca", "requires": { "base-64": "0.1.0", "glob": "7.0.6" diff --git a/package.json b/package.json index 9684edde4..25b80372b 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "react-native-drawer": "2.5.0", "react-native-exception-handler": "2.7.5", "react-native-fast-image": "4.0.8", - "react-native-fetch-blob": "enahum/react-native-fetch-blob.git#2e8f9b05b012496bd3ff9790aace3f2b462e2fee", + "react-native-fetch-blob": "enahum/react-native-fetch-blob.git#c4c798032d9c255fbae75d13a0a985af9b8b42ca", "react-native-image-gallery": "enahum/react-native-image-gallery#a98b1051e94f5a394541ca1ff9b15e2c9ffed84f", "react-native-image-picker": "0.26.7", "react-native-keyboard-aware-scroll-view": "0.5.0",