diff --git a/react/features/app/components/App.native.js b/react/features/app/components/App.native.js index 8c9d6e2a0..f58bc9b73 100644 --- a/react/features/app/components/App.native.js +++ b/react/features/app/components/App.native.js @@ -8,6 +8,7 @@ import '../../mobile/audio-mode'; import '../../mobile/background'; import '../../mobile/external-api'; import '../../mobile/full-screen'; +import '../../mobile/net-interceptor'; import '../../mobile/permissions'; import '../../mobile/proximity'; import '../../mobile/wake-lock'; diff --git a/react/features/mobile/net-interceptor/actionTypes.js b/react/features/mobile/net-interceptor/actionTypes.js new file mode 100644 index 000000000..1a91cd5d2 --- /dev/null +++ b/react/features/mobile/net-interceptor/actionTypes.js @@ -0,0 +1,11 @@ +/** + * The type of redux action to update the pending network requests mapping. + * + * { + * type: UPDATE_NETWORK_REQUESTS, + * requests: Object + * } + * + * @protected + */ +export const UPDATE_NETWORK_REQUESTS = Symbol('UPDATE_NETWORK_REQUESTS'); diff --git a/react/features/mobile/net-interceptor/functions.js b/react/features/mobile/net-interceptor/functions.js new file mode 100644 index 000000000..931ac73ee --- /dev/null +++ b/react/features/mobile/net-interceptor/functions.js @@ -0,0 +1,75 @@ +import _ from 'lodash'; +import XHRInterceptor from 'react-native/Libraries/Network/XHRInterceptor'; + +import { UPDATE_NETWORK_REQUESTS } from './actionTypes'; + +/** + * Global index for keeping track of XHR requests. + * @type {number} + */ +let reqIndex = 0; + +/** + * Starts intercepting network requests. Only XHR requests are supported at the + * moment. + * + * Ongoing request information is kept in redux, and it's removed as soon as a + * given request is complete. + * + * @param {Object} store - The redux store. + * @returns {void} + */ +export function startNetInterception({ dispatch, getState }) { + XHRInterceptor.setOpenCallback((method, url, xhr) => { + xhr._reqIndex = reqIndex++; + + const requests = getState()['features/net-interceptor'].requests || {}; + const newRequests = _.cloneDeep(requests); + const request = { + method, + url + }; + + newRequests[xhr._reqIndex] = request; + + dispatch({ + type: UPDATE_NETWORK_REQUESTS, + requests: newRequests + }); + }); + + XHRInterceptor.setResponseCallback((...args) => { + const xhr = args.slice(-1)[0]; + + if (typeof xhr._reqIndex === 'undefined') { + return; + } + + const requests = getState()['features/net-interceptor'].requests || {}; + const newRequests = _.cloneDeep(requests); + + delete newRequests[xhr._reqIndex]; + + dispatch({ + type: UPDATE_NETWORK_REQUESTS, + requests: newRequests + }); + }); + + XHRInterceptor.enableInterception(); +} + +/** + * Stops intercepting network requests. + * + * @param {Object} store - The redux store. + * @returns {void} + */ +export function stopNetInterception({ dispatch }) { + XHRInterceptor.disableInterception(); + + dispatch({ + type: UPDATE_NETWORK_REQUESTS, + requests: {} + }); +} diff --git a/react/features/mobile/net-interceptor/index.js b/react/features/mobile/net-interceptor/index.js new file mode 100644 index 000000000..200d25492 --- /dev/null +++ b/react/features/mobile/net-interceptor/index.js @@ -0,0 +1,2 @@ +import './middleware'; +import './reducer'; diff --git a/react/features/mobile/net-interceptor/middleware.js b/react/features/mobile/net-interceptor/middleware.js new file mode 100644 index 000000000..87e80c653 --- /dev/null +++ b/react/features/mobile/net-interceptor/middleware.js @@ -0,0 +1,25 @@ +import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../../app'; +import { MiddlewareRegistry } from '../../base/redux'; + +import { startNetInterception, stopNetInterception } from './functions'; + +/** + * Middleware which captures app startup and conference actions in order to + * clear the image cache. + * + * @returns {Function} + */ +MiddlewareRegistry.register(store => next => action => { + const result = next(action); + + switch (action.type) { + case APP_WILL_MOUNT: + startNetInterception(store); + break; + case APP_WILL_UNMOUNT: + stopNetInterception(store); + break; + } + + return result; +}); diff --git a/react/features/mobile/net-interceptor/reducer.js b/react/features/mobile/net-interceptor/reducer.js new file mode 100644 index 000000000..0f9a4df22 --- /dev/null +++ b/react/features/mobile/net-interceptor/reducer.js @@ -0,0 +1,15 @@ +import { ReducerRegistry } from '../../base/redux'; + +import { UPDATE_NETWORK_REQUESTS } from './actionTypes'; + +ReducerRegistry.register('features/net-interceptor', (state = {}, action) => { + switch (action.type) { + case UPDATE_NETWORK_REQUESTS: + return { + ...state, + requests: action.requests + }; + } + + return state; +});