2022-10-19 11:42:54 +03:00
|
|
|
// @ts-expect-error
|
2020-07-21 14:19:07 +02:00
|
|
|
import { API_ID } from '../../../modules/API/constants';
|
2020-07-23 12:07:30 +02:00
|
|
|
import { getName as getAppName } from '../app/functions';
|
2022-09-06 15:51:50 +03:00
|
|
|
import { IStore } from '../app/types';
|
2022-09-30 12:08:03 +03:00
|
|
|
import { getAnalyticsRoomName } from '../base/conference/functions';
|
2022-11-01 13:36:32 +01:00
|
|
|
import checkChromeExtensionsInstalled from '../base/environment/checkChromeExtensionsInstalled';
|
2020-05-20 12:57:03 +02:00
|
|
|
import {
|
|
|
|
|
isMobileBrowser
|
|
|
|
|
} from '../base/environment/utils';
|
2017-10-10 18:43:22 -05:00
|
|
|
import JitsiMeetJS, {
|
|
|
|
|
analytics,
|
2022-04-08 15:24:58 +03:00
|
|
|
browser
|
2017-10-10 18:43:22 -05:00
|
|
|
} from '../base/lib-jitsi-meet';
|
2022-09-30 12:08:03 +03:00
|
|
|
import { isAnalyticsEnabled } from '../base/lib-jitsi-meet/functions.any';
|
2022-09-06 15:51:50 +03:00
|
|
|
import { getJitsiMeetGlobalNS } from '../base/util/helpers';
|
2022-05-23 13:28:34 +02:00
|
|
|
import { inIframe } from '../base/util/iframeUtils';
|
2022-10-19 11:42:54 +03:00
|
|
|
import { loadScript } from '../base/util/loadScript';
|
2024-11-22 17:32:33 -06:00
|
|
|
import { parseURLParams } from '../base/util/parseURLParams';
|
2022-09-06 15:51:50 +03:00
|
|
|
import { parseURIString } from '../base/util/uri';
|
2023-12-06 13:03:33 -06:00
|
|
|
import { isPrejoinPageVisible } from '../prejoin/functions';
|
2020-05-20 12:57:03 +02:00
|
|
|
|
2022-09-06 15:51:50 +03:00
|
|
|
import AmplitudeHandler from './handlers/AmplitudeHandler';
|
|
|
|
|
import MatomoHandler from './handlers/MatomoHandler';
|
2019-08-21 16:50:00 +02:00
|
|
|
import logger from './logger';
|
2017-09-01 14:14:03 -05:00
|
|
|
|
2017-10-20 14:30:43 -05:00
|
|
|
/**
|
2018-01-03 15:24:07 -06:00
|
|
|
* Sends an event through the lib-jitsi-meet AnalyticsAdapter interface.
|
2017-10-20 14:30:43 -05:00
|
|
|
*
|
2018-01-03 15:24:07 -06:00
|
|
|
* @param {Object} event - The event to send. It should be formatted as
|
|
|
|
|
* described in AnalyticsAdapter.js in lib-jitsi-meet.
|
|
|
|
|
* @returns {void}
|
2017-10-20 14:30:43 -05:00
|
|
|
*/
|
2018-01-03 15:24:07 -06:00
|
|
|
export function sendAnalytics(event: Object) {
|
2018-01-17 16:58:21 +01:00
|
|
|
try {
|
|
|
|
|
analytics.sendEvent(event);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.warn(`Error sending analytics event: ${e}`);
|
|
|
|
|
}
|
2017-10-20 14:30:43 -05:00
|
|
|
}
|
2017-10-10 18:43:22 -05:00
|
|
|
|
2020-07-15 18:22:00 +03:00
|
|
|
/**
|
|
|
|
|
* Return saved amplitude identity info such as session id, device id and user id. We assume these do not change for
|
|
|
|
|
* the duration of the conference.
|
|
|
|
|
*
|
|
|
|
|
* @returns {Object}
|
|
|
|
|
*/
|
|
|
|
|
export function getAmplitudeIdentity() {
|
|
|
|
|
return analytics.amplitudeIdentityProps;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-24 15:37:55 +00:00
|
|
|
/**
|
|
|
|
|
* Resets the analytics adapter to its initial state - removes handlers, cache,
|
|
|
|
|
* disabled state, etc.
|
|
|
|
|
*
|
|
|
|
|
* @returns {void}
|
|
|
|
|
*/
|
|
|
|
|
export function resetAnalytics() {
|
|
|
|
|
analytics.reset();
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-01 14:14:03 -05:00
|
|
|
/**
|
2020-01-30 16:57:41 +00:00
|
|
|
* Creates the analytics handlers.
|
2017-09-01 14:14:03 -05:00
|
|
|
*
|
2020-01-30 16:57:41 +00:00
|
|
|
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
|
|
|
|
|
* @returns {Promise} Resolves with the handlers that have been successfully loaded.
|
2017-09-01 14:14:03 -05:00
|
|
|
*/
|
2023-04-04 17:08:59 +03:00
|
|
|
export async function createHandlers({ getState }: IStore) {
|
2017-09-01 14:14:03 -05:00
|
|
|
getJitsiMeetGlobalNS().analyticsHandlers = [];
|
|
|
|
|
|
2020-01-30 16:57:41 +00:00
|
|
|
if (!isAnalyticsEnabled(getState)) {
|
2020-09-24 11:55:03 +02:00
|
|
|
// Avoid all analytics processing if there are no handlers, since no event would be sent.
|
|
|
|
|
analytics.dispose();
|
|
|
|
|
|
|
|
|
|
return [];
|
2017-09-01 14:14:03 -05:00
|
|
|
}
|
|
|
|
|
|
2017-11-28 20:57:13 -06:00
|
|
|
const state = getState();
|
|
|
|
|
const config = state['features/base/config'];
|
2019-01-24 15:37:55 +00:00
|
|
|
const { locationURL } = state['features/base/connection'];
|
|
|
|
|
const host = locationURL ? locationURL.host : '';
|
2019-01-03 14:48:41 +00:00
|
|
|
const {
|
|
|
|
|
analytics: analyticsConfig = {},
|
|
|
|
|
deploymentInfo
|
|
|
|
|
} = config;
|
2019-01-03 13:54:02 +00:00
|
|
|
const {
|
|
|
|
|
amplitudeAPPKey,
|
2023-09-05 14:20:31 +03:00
|
|
|
amplitudeIncludeUTM,
|
2019-08-30 16:16:05 +01:00
|
|
|
blackListedEvents,
|
2019-01-03 14:48:41 +00:00
|
|
|
scriptURLs,
|
2020-04-28 13:23:04 +02:00
|
|
|
matomoEndpoint,
|
|
|
|
|
matomoSiteID,
|
2019-08-30 16:16:05 +01:00
|
|
|
whiteListedEvents
|
2019-01-03 14:48:41 +00:00
|
|
|
} = analyticsConfig;
|
2020-01-30 16:57:41 +00:00
|
|
|
const { group, user } = state['features/base/jwt'];
|
2017-09-01 14:14:03 -05:00
|
|
|
const handlerConstructorOptions = {
|
2019-01-03 13:54:02 +00:00
|
|
|
amplitudeAPPKey,
|
2023-09-05 14:20:31 +03:00
|
|
|
amplitudeIncludeUTM,
|
2019-08-30 16:16:05 +01:00
|
|
|
blackListedEvents,
|
2022-09-08 12:52:36 +03:00
|
|
|
envType: deploymentInfo?.envType || 'dev',
|
2020-04-28 13:23:04 +02:00
|
|
|
matomoEndpoint,
|
|
|
|
|
matomoSiteID,
|
2018-01-04 09:11:35 -06:00
|
|
|
group,
|
2019-01-24 15:37:55 +00:00
|
|
|
host,
|
2022-09-08 12:52:36 +03:00
|
|
|
product: deploymentInfo?.product,
|
|
|
|
|
subproduct: deploymentInfo?.environment,
|
|
|
|
|
user: user?.id,
|
2019-08-30 16:16:05 +01:00
|
|
|
version: JitsiMeetJS.version,
|
|
|
|
|
whiteListedEvents
|
2017-09-01 14:14:03 -05:00
|
|
|
};
|
2020-01-30 16:57:41 +00:00
|
|
|
const handlers = [];
|
2017-09-01 14:14:03 -05:00
|
|
|
|
2020-09-24 11:55:03 +02:00
|
|
|
if (amplitudeAPPKey) {
|
|
|
|
|
try {
|
|
|
|
|
const amplitude = new AmplitudeHandler(handlerConstructorOptions);
|
|
|
|
|
|
|
|
|
|
analytics.amplitudeIdentityProps = amplitude.getIdentityProps();
|
2020-01-30 16:57:41 +00:00
|
|
|
|
2020-09-24 11:55:03 +02:00
|
|
|
handlers.push(amplitude);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error('Failed to initialize Amplitude handler', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-15 18:22:00 +03:00
|
|
|
|
2020-09-24 11:55:03 +02:00
|
|
|
if (matomoEndpoint && matomoSiteID) {
|
|
|
|
|
try {
|
|
|
|
|
const matomo = new MatomoHandler(handlerConstructorOptions);
|
2020-01-30 16:57:41 +00:00
|
|
|
|
2020-09-24 11:55:03 +02:00
|
|
|
handlers.push(matomo);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error('Failed to initialize Matomo handler', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Array.isArray(scriptURLs) && scriptURLs.length > 0) {
|
|
|
|
|
let externalHandlers;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
externalHandlers = await _loadHandlers(scriptURLs, handlerConstructorOptions);
|
|
|
|
|
handlers.push(...externalHandlers);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error('Failed to initialize external analytics handlers', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Avoid all analytics processing if there are no handlers, since no event would be sent.
|
|
|
|
|
if (handlers.length === 0) {
|
|
|
|
|
analytics.dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logger.info(`Initialized ${handlers.length} analytics handlers`);
|
2020-01-24 14:43:42 -06:00
|
|
|
|
2020-09-24 11:55:03 +02:00
|
|
|
return handlers;
|
2020-01-30 16:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 10:49:52 -06:00
|
|
|
/**
|
|
|
|
|
* Checks whether a url is a data URL or not.
|
|
|
|
|
*
|
|
|
|
|
* @param {string} url - The URL to be checked.
|
|
|
|
|
* @returns {boolean}
|
|
|
|
|
*/
|
|
|
|
|
function isDataURL(url?: string): boolean {
|
|
|
|
|
if (typeof url !== 'string') { // The icon will be ignored
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const urlObject = new URL(url);
|
|
|
|
|
|
|
|
|
|
if (urlObject.protocol === 'data:') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-30 16:57:41 +00:00
|
|
|
/**
|
|
|
|
|
* Inits JitsiMeetJS.analytics by setting permanent properties and setting the handlers from the loaded scripts.
|
|
|
|
|
* NOTE: Has to be used after JitsiMeetJS.init. Otherwise analytics will be null.
|
|
|
|
|
*
|
|
|
|
|
* @param {Store} store - The redux store in which the specified {@code action} is being dispatched.
|
|
|
|
|
* @param {Array<Object>} handlers - The analytics handlers.
|
2023-12-20 16:54:18 -06:00
|
|
|
* @returns {boolean} - True if the analytics were successfully initialized and false otherwise.
|
2020-01-30 16:57:41 +00:00
|
|
|
*/
|
2023-12-20 16:54:18 -06:00
|
|
|
export function initAnalytics(store: IStore, handlers: Array<Object>): boolean {
|
2022-06-21 09:53:07 +03:00
|
|
|
const { getState, dispatch } = store;
|
|
|
|
|
|
2020-01-30 16:57:41 +00:00
|
|
|
if (!isAnalyticsEnabled(getState) || handlers.length === 0) {
|
2023-12-20 16:54:18 -06:00
|
|
|
return false;
|
2020-01-30 16:57:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const state = getState();
|
|
|
|
|
const config = state['features/base/config'];
|
|
|
|
|
const {
|
|
|
|
|
deploymentInfo
|
|
|
|
|
} = config;
|
|
|
|
|
const { group, server } = state['features/base/jwt'];
|
2022-09-06 15:51:50 +03:00
|
|
|
const { locationURL = { href: '' } } = state['features/base/connection'];
|
2020-12-09 17:25:55 -06:00
|
|
|
const { tenant } = parseURIString(locationURL.href) || {};
|
2024-11-22 17:32:33 -06:00
|
|
|
const params = parseURLParams(locationURL.href) ?? {};
|
2023-05-17 13:05:47 +03:00
|
|
|
const permanentProperties: {
|
|
|
|
|
appName?: string;
|
|
|
|
|
externalApi?: boolean;
|
|
|
|
|
group?: string;
|
|
|
|
|
inIframe?: boolean;
|
2023-12-06 13:03:33 -06:00
|
|
|
isPromotedFromVisitor?: boolean;
|
|
|
|
|
isVisitor?: boolean;
|
2024-12-18 16:12:20 -06:00
|
|
|
overwritesCustomButtonsWithURL?: boolean;
|
2025-01-08 10:49:52 -06:00
|
|
|
overwritesCustomParticipantButtonsWithURL?: boolean;
|
2024-11-22 17:32:33 -06:00
|
|
|
overwritesDefaultLogoUrl?: boolean;
|
|
|
|
|
overwritesDeploymentUrls?: boolean;
|
2024-12-18 16:12:20 -06:00
|
|
|
overwritesEtherpadBase?: boolean;
|
|
|
|
|
overwritesHosts?: boolean;
|
|
|
|
|
overwritesIceServers?: boolean;
|
2024-11-22 17:32:33 -06:00
|
|
|
overwritesLiveStreamingUrls?: boolean;
|
|
|
|
|
overwritesPeopleSearchUrl?: boolean;
|
|
|
|
|
overwritesPrejoinConfigICEUrl?: boolean;
|
|
|
|
|
overwritesSalesforceUrl?: boolean;
|
|
|
|
|
overwritesSupportUrl?: boolean;
|
2024-12-18 16:12:20 -06:00
|
|
|
overwritesWatchRTCConfigParams?: boolean;
|
|
|
|
|
overwritesWatchRTCProxyUrl?: boolean;
|
|
|
|
|
overwritesWatchRTCWSUrl?: boolean;
|
2023-05-17 13:05:47 +03:00
|
|
|
server?: string;
|
|
|
|
|
tenant?: string;
|
2023-12-06 13:03:33 -06:00
|
|
|
wasLobbyVisible?: boolean;
|
|
|
|
|
wasPrejoinDisplayed?: boolean;
|
2023-05-17 13:05:47 +03:00
|
|
|
websocket?: boolean;
|
|
|
|
|
} & typeof deploymentInfo = {};
|
2020-01-30 16:57:41 +00:00
|
|
|
|
|
|
|
|
if (server) {
|
|
|
|
|
permanentProperties.server = server;
|
|
|
|
|
}
|
|
|
|
|
if (group) {
|
|
|
|
|
permanentProperties.group = group;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-23 12:07:30 +02:00
|
|
|
// Report the application name
|
|
|
|
|
permanentProperties.appName = getAppName();
|
|
|
|
|
|
|
|
|
|
// Report if user is using websocket
|
2020-08-25 13:43:31 -05:00
|
|
|
permanentProperties.websocket = typeof config.websocket === 'string';
|
2020-01-30 16:57:41 +00:00
|
|
|
|
2020-07-23 12:07:30 +02:00
|
|
|
// Report if user is using the external API
|
2020-06-16 09:35:12 -05:00
|
|
|
permanentProperties.externalApi = typeof API_ID === 'number';
|
|
|
|
|
|
|
|
|
|
// Report if we are loaded in iframe
|
2021-10-27 10:53:14 +03:00
|
|
|
permanentProperties.inIframe = inIframe();
|
2020-06-16 09:35:12 -05:00
|
|
|
|
2020-12-09 17:25:55 -06:00
|
|
|
// Report the tenant from the URL.
|
|
|
|
|
permanentProperties.tenant = tenant || '/';
|
|
|
|
|
|
2023-12-06 13:03:33 -06:00
|
|
|
permanentProperties.wasPrejoinDisplayed = isPrejoinPageVisible(state);
|
|
|
|
|
|
|
|
|
|
// Currently we don't know if there will be lobby. We will update it to true if we go through lobby.
|
|
|
|
|
permanentProperties.wasLobbyVisible = false;
|
|
|
|
|
|
|
|
|
|
// Setting visitor properties to false by default. We will update them later if it turns out we are visitor.
|
|
|
|
|
permanentProperties.isVisitor = false;
|
|
|
|
|
permanentProperties.isPromotedFromVisitor = false;
|
|
|
|
|
|
2024-11-22 17:32:33 -06:00
|
|
|
// TODO: Temporary metric. To be removed once we don't need it.
|
|
|
|
|
permanentProperties.overwritesSupportUrl = 'interfaceConfig.SUPPORT_URL' in params;
|
|
|
|
|
permanentProperties.overwritesSalesforceUrl = 'config.salesforceUrl' in params;
|
|
|
|
|
permanentProperties.overwritesPeopleSearchUrl = 'config.peopleSearchUrl' in params;
|
|
|
|
|
permanentProperties.overwritesDefaultLogoUrl = 'config.defaultLogoUrl' in params;
|
2024-12-18 16:12:20 -06:00
|
|
|
permanentProperties.overwritesEtherpadBase = 'config.etherpad_base' in params;
|
|
|
|
|
const hosts = params['config.hosts'] ?? {};
|
|
|
|
|
const hostsProps = [ 'anonymousdomain', 'authdomain', 'domain', 'focus', 'muc', 'visitorFocus' ];
|
|
|
|
|
|
|
|
|
|
permanentProperties.overwritesHosts = 'config.hosts' in params
|
|
|
|
|
|| Boolean(hostsProps.find(p => `config.hosts.${p}` in params || (typeof hosts === 'object' && p in hosts)));
|
|
|
|
|
|
|
|
|
|
permanentProperties.overwritesWatchRTCConfigParams = 'config.watchRTCConfigParams' in params;
|
|
|
|
|
const watchRTCConfigParams = params['config.watchRTCConfigParams'] ?? {};
|
|
|
|
|
|
|
|
|
|
permanentProperties.overwritesWatchRTCProxyUrl = ('config.watchRTCConfigParams.proxyUrl' in params)
|
|
|
|
|
|| (typeof watchRTCConfigParams === 'object' && 'proxyUrl' in watchRTCConfigParams);
|
|
|
|
|
permanentProperties.overwritesWatchRTCWSUrl = ('config.watchRTCConfigParams.wsUrl' in params)
|
|
|
|
|
|| (typeof watchRTCConfigParams === 'object' && 'wsUrl' in watchRTCConfigParams);
|
|
|
|
|
|
2024-11-22 17:32:33 -06:00
|
|
|
const prejoinConfig = params['config.prejoinConfig'] ?? {};
|
|
|
|
|
|
|
|
|
|
permanentProperties.overwritesPrejoinConfigICEUrl = ('config.prejoinConfig.preCallTestICEUrl' in params)
|
|
|
|
|
|| (typeof prejoinConfig === 'object' && 'preCallTestICEUrl' in prejoinConfig);
|
|
|
|
|
const deploymentUrlsConfig = params['config.deploymentUrls'] ?? {};
|
|
|
|
|
|
|
|
|
|
permanentProperties.overwritesDeploymentUrls
|
|
|
|
|
= 'config.deploymentUrls.downloadAppsUrl' in params || 'config.deploymentUrls.userDocumentationURL' in params
|
|
|
|
|
|| (typeof deploymentUrlsConfig === 'object'
|
|
|
|
|
&& ('downloadAppsUrl' in deploymentUrlsConfig || 'userDocumentationURL' in deploymentUrlsConfig));
|
|
|
|
|
const liveStreamingConfig = params['config.liveStreaming'] ?? {};
|
|
|
|
|
|
|
|
|
|
permanentProperties.overwritesLiveStreamingUrls
|
|
|
|
|
= ('interfaceConfig.LIVE_STREAMING_HELP_LINK' in params)
|
|
|
|
|
|| ('config.liveStreaming.termsLink' in params)
|
|
|
|
|
|| ('config.liveStreaming.dataPrivacyLink' in params)
|
|
|
|
|
|| ('config.liveStreaming.helpLink' in params)
|
|
|
|
|
|| (typeof params['config.liveStreaming'] === 'object' && 'config.liveStreaming' in params
|
|
|
|
|
&& (
|
|
|
|
|
'termsLink' in liveStreamingConfig
|
|
|
|
|
|| 'dataPrivacyLink' in liveStreamingConfig
|
|
|
|
|
|| 'helpLink' in liveStreamingConfig
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
2024-12-18 16:12:20 -06:00
|
|
|
permanentProperties.overwritesIceServers = Boolean(Object.keys(params).find(k => k.startsWith('iceServers')));
|
|
|
|
|
|
|
|
|
|
const customToolbarButtons = params['config.customToolbarButtons'] ?? [];
|
|
|
|
|
|
|
|
|
|
permanentProperties.overwritesCustomButtonsWithURL = Boolean(
|
2025-01-08 10:49:52 -06:00
|
|
|
customToolbarButtons.find(({ icon }: { icon: string; }) => isDataURL(icon)));
|
2024-12-18 16:12:20 -06:00
|
|
|
|
2025-01-08 10:49:52 -06:00
|
|
|
const customParticipantMenuButtons = params['config.customParticipantMenuButtons'] ?? [];
|
2024-12-18 16:12:20 -06:00
|
|
|
|
2025-01-08 10:49:52 -06:00
|
|
|
permanentProperties.overwritesCustomParticipantButtonsWithURL = Boolean(
|
|
|
|
|
customParticipantMenuButtons.find(({ icon }: { icon: string; }) => isDataURL(icon)));
|
2024-12-18 16:12:20 -06:00
|
|
|
|
2020-01-30 16:57:41 +00:00
|
|
|
// Optionally, include local deployment information based on the
|
|
|
|
|
// contents of window.config.deploymentInfo.
|
|
|
|
|
if (deploymentInfo) {
|
|
|
|
|
for (const key in deploymentInfo) {
|
|
|
|
|
if (deploymentInfo.hasOwnProperty(key)) {
|
2023-05-17 13:05:47 +03:00
|
|
|
permanentProperties[key as keyof typeof deploymentInfo] = deploymentInfo[
|
|
|
|
|
key as keyof typeof deploymentInfo];
|
2017-09-01 14:14:03 -05:00
|
|
|
}
|
2020-01-30 16:57:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
2017-09-01 14:14:03 -05:00
|
|
|
|
2023-12-20 16:54:18 -06:00
|
|
|
analytics.addPermanentProperties({
|
|
|
|
|
...permanentProperties,
|
|
|
|
|
...getState()['features/analytics'].initialPermanentProperties
|
|
|
|
|
});
|
|
|
|
|
|
2022-06-21 09:53:07 +03:00
|
|
|
analytics.setConferenceName(getAnalyticsRoomName(state, dispatch));
|
2018-01-03 15:24:07 -06:00
|
|
|
|
2020-01-30 16:57:41 +00:00
|
|
|
// Set the handlers last, since this triggers emptying of the cache
|
|
|
|
|
analytics.setAnalyticsHandlers(handlers);
|
2020-02-25 14:41:13 +02:00
|
|
|
|
2023-09-26 19:31:26 +03:00
|
|
|
if (!isMobileBrowser() && browser.isChromiumBased()) {
|
2020-02-25 14:41:13 +02:00
|
|
|
const bannerCfg = state['features/base/config'].chromeExtensionBanner;
|
|
|
|
|
|
|
|
|
|
checkChromeExtensionsInstalled(bannerCfg).then(extensionsInstalled => {
|
|
|
|
|
if (extensionsInstalled?.length) {
|
|
|
|
|
analytics.addPermanentProperties({
|
|
|
|
|
hasChromeExtension: extensionsInstalled.some(ext => ext)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2023-12-20 16:54:18 -06:00
|
|
|
|
|
|
|
|
return true;
|
2017-09-01 14:14:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-09-24 11:57:47 +02:00
|
|
|
* Tries to load the scripts for the external analytics handlers and creates them.
|
2017-09-01 14:14:03 -05:00
|
|
|
*
|
|
|
|
|
* @param {Array} scriptURLs - The array of script urls to load.
|
2020-01-30 16:57:41 +00:00
|
|
|
* @param {Object} handlerConstructorOptions - The default options to pass when creating handlers.
|
2017-09-01 14:14:03 -05:00
|
|
|
* @private
|
2020-01-30 16:57:41 +00:00
|
|
|
* @returns {Promise} Resolves with the handlers that have been successfully loaded and rejects if there are no handlers
|
|
|
|
|
* loaded or the analytics is disabled.
|
2017-09-01 14:14:03 -05:00
|
|
|
*/
|
2023-05-17 13:05:47 +03:00
|
|
|
function _loadHandlers(scriptURLs: string[] = [], handlerConstructorOptions: Object) {
|
2023-04-04 17:08:59 +03:00
|
|
|
const promises: Promise<{ error?: Error; type: string; url?: string; }>[] = [];
|
2017-09-01 14:14:03 -05:00
|
|
|
|
|
|
|
|
for (const url of scriptURLs) {
|
|
|
|
|
promises.push(
|
|
|
|
|
loadScript(url).then(
|
|
|
|
|
() => {
|
|
|
|
|
return { type: 'success' };
|
|
|
|
|
},
|
2022-09-06 15:51:50 +03:00
|
|
|
(error: Error) => {
|
2017-09-01 14:14:03 -05:00
|
|
|
return {
|
|
|
|
|
type: 'error',
|
|
|
|
|
error,
|
|
|
|
|
url
|
|
|
|
|
};
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Promise.all(promises).then(values => {
|
|
|
|
|
for (const el of values) {
|
2023-04-04 17:08:59 +03:00
|
|
|
if (el.type === 'error') {
|
2017-09-01 14:14:03 -05:00
|
|
|
logger.warn(`Failed to load ${el.url}: ${el.error}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-04 17:36:09 -05:00
|
|
|
const handlers = [];
|
2017-09-01 14:14:03 -05:00
|
|
|
|
2022-07-12 16:48:27 +02:00
|
|
|
for (const Handler of getJitsiMeetGlobalNS().analyticsHandlers) {
|
2017-10-04 17:36:09 -05:00
|
|
|
// Catch any error while loading to avoid skipping analytics in case
|
|
|
|
|
// of multiple scripts.
|
|
|
|
|
try {
|
|
|
|
|
handlers.push(new Handler(handlerConstructorOptions));
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.warn(`Error creating analytics handler: ${error}`);
|
|
|
|
|
}
|
2017-09-01 14:14:03 -05:00
|
|
|
}
|
2020-09-24 11:57:47 +02:00
|
|
|
logger.debug(`Loaded ${handlers.length} external analytics handlers`);
|
2017-10-04 17:36:09 -05:00
|
|
|
|
|
|
|
|
return handlers;
|
2017-09-01 14:14:03 -05:00
|
|
|
});
|
|
|
|
|
}
|