feat: report analytics for the network connection
Will emit new 'network.info' action with the online/offline status and extra details for native like the network type and 'isConnectionExpensive' flag.
This commit is contained in:
parent
2c70388a9e
commit
6ae9bbe0c5
|
@ -56,6 +56,7 @@ dependencies {
|
|||
implementation project(':react-native-background-timer')
|
||||
implementation project(':react-native-calendar-events')
|
||||
implementation project(':react-native-community-async-storage')
|
||||
implementation project(':react-native-community_netinfo')
|
||||
implementation project(':react-native-immersive')
|
||||
implementation project(':react-native-keep-awake')
|
||||
implementation project(':react-native-linear-gradient')
|
||||
|
|
|
@ -193,6 +193,7 @@ class ReactInstanceManagerHolder {
|
|||
new com.oblador.vectoricons.VectorIconsPackage(),
|
||||
new com.ocetnik.timer.BackgroundTimerPackage(),
|
||||
new com.reactnativecommunity.asyncstorage.AsyncStoragePackage(),
|
||||
new com.reactnativecommunity.netinfo.NetInfoPackage(),
|
||||
new com.reactnativecommunity.webview.RNCWebViewPackage(),
|
||||
new com.rnimmersive.RNImmersivePackage(),
|
||||
new com.zmxv.RNSound.RNSoundPackage(),
|
||||
|
|
|
@ -7,6 +7,8 @@ include ':react-native-calendar-events'
|
|||
project(':react-native-calendar-events').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-calendar-events/android')
|
||||
include ':react-native-community-async-storage'
|
||||
project(':react-native-community-async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android')
|
||||
include ':react-native-community_netinfo'
|
||||
project(':react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android')
|
||||
include ':react-native-google-signin'
|
||||
project(':react-native-google-signin').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-google-signin/android')
|
||||
include ':react-native-immersive'
|
||||
|
|
|
@ -47,6 +47,7 @@ target 'JitsiMeet' do
|
|||
pod 'react-native-background-timer', :path => '../node_modules/react-native-background-timer'
|
||||
pod 'react-native-calendar-events', :path => '../node_modules/react-native-calendar-events'
|
||||
pod 'react-native-keep-awake', :path => '../node_modules/react-native-keep-awake'
|
||||
pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo'
|
||||
pod 'react-native-webview', :path => '../node_modules/react-native-webview'
|
||||
pod 'react-native-webrtc', :path => '../node_modules/react-native-webrtc'
|
||||
pod 'BVLinearGradient', :path => '../node_modules/react-native-linear-gradient'
|
||||
|
|
|
@ -139,6 +139,8 @@ PODS:
|
|||
- React
|
||||
- react-native-keep-awake (4.0.0):
|
||||
- React
|
||||
- react-native-netinfo (4.1.5):
|
||||
- React
|
||||
- react-native-webrtc (1.69.2):
|
||||
- React
|
||||
- react-native-webview (5.8.1):
|
||||
|
@ -203,6 +205,7 @@ DEPENDENCIES:
|
|||
- react-native-background-timer (from `../node_modules/react-native-background-timer`)
|
||||
- react-native-calendar-events (from `../node_modules/react-native-calendar-events`)
|
||||
- react-native-keep-awake (from `../node_modules/react-native-keep-awake`)
|
||||
- react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)
|
||||
- react-native-webrtc (from `../node_modules/react-native-webrtc`)
|
||||
- react-native-webview (from `../node_modules/react-native-webview`)
|
||||
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
|
||||
|
@ -271,6 +274,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native-calendar-events"
|
||||
react-native-keep-awake:
|
||||
:path: "../node_modules/react-native-keep-awake"
|
||||
react-native-netinfo:
|
||||
:path: "../node_modules/@react-native-community/netinfo"
|
||||
react-native-webrtc:
|
||||
:path: "../node_modules/react-native-webrtc"
|
||||
react-native-webview:
|
||||
|
@ -340,6 +345,7 @@ SPEC CHECKSUMS:
|
|||
react-native-background-timer: 0d34748e53a972507c66963490c775321a88f6f2
|
||||
react-native-calendar-events: 2fe35a9294af05de0ed819d3a1b5dac048d2c010
|
||||
react-native-keep-awake: eba3137546b10003361b37c761f6c429b59814ae
|
||||
react-native-netinfo: 8d8db463bcc5db66a8ac5c48a7d86beb3b92f61a
|
||||
react-native-webrtc: 1415d2a54b2246dd85ba95eb3e4bf2b66533f951
|
||||
react-native-webview: a95842e3f351a6d2c8bc8bcc9eab689c7e7e5ad4
|
||||
React-RCTActionSheet: b0f1ea83f4bf75fb966eae9bfc47b78c8d3efd90
|
||||
|
@ -359,6 +365,6 @@ SPEC CHECKSUMS:
|
|||
RNWatch: 09738b339eceb66e4d80a2371633ca5fb380fa42
|
||||
yoga: 312528f5bbbba37b4dcea5ef00e8b4033fdd9411
|
||||
|
||||
PODFILE CHECKSUM: 6b6e260b4be4e86f9d05c0d7dab40f60118bb355
|
||||
PODFILE CHECKSUM: 0907bfe60b5b5f11dbdc6b4e65d40a248d000513
|
||||
|
||||
COCOAPODS: 1.7.2
|
||||
|
|
|
@ -3055,6 +3055,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@react-native-community/netinfo": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-4.1.5.tgz",
|
||||
"integrity": "sha512-lagdZr9UiVAccNXYfTEj+aUcPCx9ykbMe9puffeIyF3JsRuMmlu3BjHYx1klUHX7wNRmFNC8qVP0puxUt1sZ0A=="
|
||||
},
|
||||
"@segment/top-domain": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@segment/top-domain/-/top-domain-3.0.0.tgz",
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
"@atlaskit/tooltip": "12.1.13",
|
||||
"@microsoft/microsoft-graph-client": "1.1.0",
|
||||
"@react-native-community/async-storage": "1.3.4",
|
||||
"@react-native-community/netinfo": "4.1.5",
|
||||
"@tensorflow-models/body-pix": "^1.0.1",
|
||||
"@tensorflow/tfjs": "^1.1.2",
|
||||
"@webcomponents/url": "0.7.1",
|
||||
|
|
|
@ -271,6 +271,27 @@ export function createInviteDialogEvent(
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an event which reports about the current network information reported by the operating system.
|
||||
*
|
||||
* @param {boolean} isOnline - Tells whether or not the internet is reachable.
|
||||
* @param {string} [networkType] - Network type, see {@code NetworkInfo} type defined by the 'base/net-info' feature.
|
||||
* @param {Object} [details] - Extra info, see {@code NetworkInfo} type defined by the 'base/net-info' feature.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function createNetworkInfoEvent({ isOnline, networkType, details }) {
|
||||
const attributes = { isOnline };
|
||||
|
||||
// Do no include optional stuff or Amplitude handler will log warnings.
|
||||
networkType && (attributes.networkType = networkType);
|
||||
details && (attributes.details = details);
|
||||
|
||||
return {
|
||||
action: 'network.info',
|
||||
attributes
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an "offer/answer failure" event.
|
||||
*
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
SET_ROOM
|
||||
} from '../base/conference';
|
||||
import { SET_CONFIG } from '../base/config';
|
||||
import { SET_NETWORK_INFO } from '../base/net-info';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import {
|
||||
getLocalAudioTrack,
|
||||
|
@ -16,7 +17,7 @@ import {
|
|||
} from '../base/tracks';
|
||||
|
||||
import { UPDATE_LOCAL_TRACKS_DURATION } from './actionTypes';
|
||||
import { createLocalTracksDurationEvent } from './AnalyticsEvents';
|
||||
import { createLocalTracksDurationEvent, createNetworkInfoEvent } from './AnalyticsEvents';
|
||||
import { initAnalytics, resetAnalytics, sendAnalytics } from './functions';
|
||||
|
||||
/**
|
||||
|
@ -127,6 +128,14 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
});
|
||||
break;
|
||||
}
|
||||
case SET_NETWORK_INFO:
|
||||
sendAnalytics(
|
||||
createNetworkInfoEvent({
|
||||
isOnline: action.isOnline,
|
||||
details: action.details,
|
||||
networkType: action.networkType
|
||||
}));
|
||||
break;
|
||||
case SET_ROOM: {
|
||||
initAnalytics(store);
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
// @flow
|
||||
import EventEmitter from 'events';
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
import type { NetInfoState, NetInfoSubscription } from '@react-native-community/netinfo';
|
||||
|
||||
import { ONLINE_STATE_CHANGED_EVENT } from './events';
|
||||
|
||||
import type { NetworkInfo } from './types';
|
||||
|
||||
/**
|
||||
* The network info service implementation for iOS and Android. 'react-native-netinfo' seems to support windows as well,
|
||||
* but that has not been tested and is nto used by jitsi-meet.
|
||||
*/
|
||||
export default class NetworkInfoService extends EventEmitter {
|
||||
/**
|
||||
* Stores the native subscription for future cleanup.
|
||||
*/
|
||||
_subscription: NetInfoSubscription;
|
||||
|
||||
/**
|
||||
* Converts library's structure to {@link NetworkInfo} used by jitsi-meet.
|
||||
*
|
||||
* @param {NetInfoState} netInfoState - The new state given by the native library.
|
||||
* @private
|
||||
* @returns {NetworkInfo}
|
||||
*/
|
||||
static _convertNetInfoState(netInfoState: NetInfoState): NetworkInfo {
|
||||
return {
|
||||
isOnline: netInfoState.isInternetReachable,
|
||||
details: netInfoState.details,
|
||||
networkType: netInfoState.type
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for support.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isSupported() {
|
||||
return Boolean(NetInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the service.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
start() {
|
||||
this._subscription = NetInfo.addEventListener(netInfoState => {
|
||||
this.emit(ONLINE_STATE_CHANGED_EVENT, NetworkInfoService._convertNetInfoState(netInfoState));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the service.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
stop() {
|
||||
if (this._subscription) {
|
||||
this._subscription();
|
||||
this._subscription = undefined;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
import EventEmitter from 'events';
|
||||
|
||||
import { ONLINE_STATE_CHANGED_EVENT } from './events';
|
||||
|
||||
/**
|
||||
* The network info service implementation for web (Chrome, Firefox and Safari).
|
||||
*/
|
||||
export default class NetworkInfoService extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Creates new instance...
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
this._onlineStateListener = this._handleOnlineStatusChange.bind(this, /* online */ true);
|
||||
this._offlineStateListener = this._handleOnlineStatusChange.bind(this, /* offline */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to track the online state.
|
||||
*
|
||||
* @param {boolean} isOnline - Is the browser online or not.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
_handleOnlineStatusChange(isOnline) {
|
||||
this.emit(ONLINE_STATE_CHANGED_EVENT, { isOnline });
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for support.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isSupported() {
|
||||
return window.addEventListener && typeof navigator.onLine !== 'undefined';
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the service.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
start() {
|
||||
window.addEventListener('online', this._onlineStateListener);
|
||||
window.addEventListener('offline', this._offlineStateListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the service.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
stop() {
|
||||
window.removeEventListener('online', this._onlineStateListener);
|
||||
window.removeEventListener('offline', this._offlineStateListener);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* The action dispatched when the {@link NetworkInfo} structure is being updated.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
export const SET_NETWORK_INFO = 'SET_NETWORK_INFO';
|
||||
|
||||
/**
|
||||
* Tha action dispatched by 'base/net-info' middleware in order to store the cleanup function for later use.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
export const _STORE_NETWORK_INFO_CLEANUP = 'STORE_NETWORK_INFO_CLEANUP';
|
|
@ -0,0 +1,42 @@
|
|||
// @flow
|
||||
|
||||
import { SET_NETWORK_INFO, _STORE_NETWORK_INFO_CLEANUP } from './actionTypes';
|
||||
|
||||
import type { NetworkInfo } from './types';
|
||||
|
||||
/**
|
||||
* Up[dates the network info state.
|
||||
*
|
||||
* @param {NetworkInfo} networkInfo - The new network state to be set.
|
||||
* @returns {{
|
||||
* type: SET_NETWORK_INFO,
|
||||
* isOnline: boolean,
|
||||
* networkType: string,
|
||||
* details: Object
|
||||
* }}
|
||||
*/
|
||||
export function setNetworkInfo({ isOnline, networkType, details }: NetworkInfo): Object {
|
||||
return {
|
||||
type: SET_NETWORK_INFO,
|
||||
isOnline,
|
||||
networkType,
|
||||
details
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Stored the cleanup function used to shutdown the {@code NetworkInfoService}.
|
||||
*
|
||||
* @param {Function} cleanup - The cleanup function to be called on {@code APP_WILL_UNMOUNT}.
|
||||
* @returns {{
|
||||
* type: _STORE_NETWORK_INFO_CLEANUP,
|
||||
* cleanup: Function
|
||||
* }}
|
||||
* @private
|
||||
*/
|
||||
export function _storeNetworkInfoCleanup(cleanup: Function): Object {
|
||||
return {
|
||||
type: _STORE_NETWORK_INFO_CLEANUP,
|
||||
cleanup
|
||||
};
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/**
|
||||
* The name for Redux store key used by the 'base/net-info' feature.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
export const STORE_NAME = 'features/base/net-info';
|
|
@ -0,0 +1 @@
|
|||
export const ONLINE_STATE_CHANGED_EVENT = 'network-info-online-status-change';
|
|
@ -0,0 +1,4 @@
|
|||
export * from './actionTypes';
|
||||
|
||||
import './middleware';
|
||||
import './reducer';
|
|
@ -0,0 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import { getLogger } from '../logging/functions';
|
||||
|
||||
export default getLogger('features/base/net-info');
|
|
@ -0,0 +1,64 @@
|
|||
// @flow
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
|
||||
import { _storeNetworkInfoCleanup, setNetworkInfo } from './actions';
|
||||
import { STORE_NAME } from './constants';
|
||||
import { ONLINE_STATE_CHANGED_EVENT } from './events';
|
||||
import logger from './logger';
|
||||
import NetworkInfoService from './NetworkInfoService';
|
||||
import type { NetworkInfo } from './types';
|
||||
|
||||
/**
|
||||
* Middleware for 'base/net-info' feature.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @returns {Function}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT:
|
||||
if (NetworkInfoService.isSupported()) {
|
||||
const networkInfoService = new NetworkInfoService();
|
||||
const stop = () => {
|
||||
networkInfoService.stop();
|
||||
networkInfoService.removeAllListeners();
|
||||
};
|
||||
|
||||
networkInfoService.addListener(
|
||||
ONLINE_STATE_CHANGED_EVENT,
|
||||
({ isOnline, networkType, details }: NetworkInfo) => {
|
||||
logger.info('Network changed', JSON.stringify({
|
||||
isOnline,
|
||||
details,
|
||||
networkType
|
||||
}));
|
||||
dispatch(setNetworkInfo({
|
||||
isOnline,
|
||||
networkType,
|
||||
details
|
||||
}));
|
||||
});
|
||||
|
||||
dispatch(_storeNetworkInfoCleanup(stop));
|
||||
|
||||
networkInfoService.start();
|
||||
}
|
||||
break;
|
||||
case APP_WILL_UNMOUNT: {
|
||||
const { _cleanup } = getState()[STORE_NAME];
|
||||
|
||||
if (_cleanup) {
|
||||
_cleanup();
|
||||
dispatch(_storeNetworkInfoCleanup(undefined));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
// @flow
|
||||
import { assign, ReducerRegistry } from '../redux';
|
||||
|
||||
import { SET_NETWORK_INFO, _STORE_NETWORK_INFO_CLEANUP } from './actionTypes';
|
||||
import { STORE_NAME } from './constants';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
isOnline: true
|
||||
};
|
||||
|
||||
/**
|
||||
* The base/net-info feature's reducer.
|
||||
*/
|
||||
ReducerRegistry.register(STORE_NAME, (state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case SET_NETWORK_INFO:
|
||||
return assign(state, {
|
||||
isOnline: action.isOnline,
|
||||
networkType: action.networkType,
|
||||
cellularGeneration: action.cellularGeneration,
|
||||
details: action.details
|
||||
});
|
||||
case _STORE_NETWORK_INFO_CLEANUP:
|
||||
return assign(state, {
|
||||
_cleanup: action.cleanup
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
// @flow
|
||||
|
||||
import { NetInfoCellularGeneration, NetInfoStateType } from '@react-native-community/netinfo';
|
||||
|
||||
/**
|
||||
* Describes the structure which is used by jitsi-meet to store information about the current network type and
|
||||
* conditions.
|
||||
*/
|
||||
export type NetworkInfo = {
|
||||
|
||||
/**
|
||||
* Tells whether or not the internet is reachable.
|
||||
*/
|
||||
isOnline: boolean,
|
||||
|
||||
/**
|
||||
* The network type. Currently reported only on Android/iOS. Can be one of the constants defined by
|
||||
* the 'react-native-netinfo' library.
|
||||
*/
|
||||
networkType: ?NetInfoStateType,
|
||||
|
||||
/**
|
||||
* Any extra info provided by the OS. Should be JSON and is OS specific. Reported only by iOS and Android and
|
||||
* the format is whatever comes out of the 'react-native-netinfo' library which is network type dependent.
|
||||
*/
|
||||
details: ?{
|
||||
|
||||
/**
|
||||
* If {@link networkType} is {@link NetInfoStateType.cellular} then it may provide the info about the type of
|
||||
* cellular network.
|
||||
*/
|
||||
cellularGeneration: ?NetInfoCellularGeneration;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the connection is expensive.
|
||||
*/
|
||||
isConnectionExpensive: ?boolean;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue