snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
Some checks failed
Prosody Plugin Tests / test (push) Failing after 10m11s
Close stale issues and PRs / stale (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-15 15:56:32 +05:00
commit 1d2bfcac0c
3159 changed files with 464524 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
import { BUTTON_TYPES } from '../base/ui/constants.native';
import { openURLInBrowser } from '../base/util/openURLInBrowser';
import { INotificationProps } from '../notifications/types';
/**
* Builds the description of a notification about missing capabilities. A URL is shown as a button, because the native
* notification renders text only, and we do not want to show a URL to the user.
*
* @param {string} text - The text which describes the missing capabilities.
* @param {string|undefined} url - A URL with more information, if the server sent one.
* @param {Function} _t - The translation function. Not needed here, the button uses a translation key.
* @returns {Object} The description properties of the notification.
*/
export function getDescriptionProps(text: string, url: string | undefined, _t: Function): INotificationProps {
if (!url) {
return { description: text };
}
return {
customActionHandler: [ () => {
openURLInBrowser(url);
return false;
} ],
customActionNameKey: [ 'clientRequirements.seeDetails' ],
customActionType: [ BUTTON_TYPES.PRIMARY ],
description: text
};
}

View File

@@ -0,0 +1,32 @@
import React from 'react';
import { INotificationProps } from '../notifications/types';
/**
* Builds the description of a notification about missing capabilities. The link is rendered around a part of the
* text, so that no URL is shown to the user.
*
* @param {string} text - The text which describes the missing capabilities.
* @param {string|undefined} url - A URL with more information, if the server sent one.
* @param {Function} t - The translation function.
* @returns {Object} The description properties of the notification.
*/
export function getDescriptionProps(text: string, url: string | undefined, t: Function): INotificationProps {
if (!url) {
return { description: text };
}
return {
description: (
<span>
{ `${text} ` }
<a
href = { url }
rel = 'noopener noreferrer'
target = '_blank'>
{ t('clientRequirements.seeDetails') }
</a>
</span>
)
};
}

View File

@@ -0,0 +1,3 @@
import { getLogger } from '../base/logging/functions';
export default getLogger('app:clientRequirements');

View File

@@ -0,0 +1,93 @@
import i18n from 'i18next';
import { IStore } from '../app/types';
import { CONFERENCE_JOINED } from '../base/conference/actionTypes';
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
import { showErrorNotification, showWarningNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { getDescriptionProps } from './functions';
import logger from './logger';
import { IClientRequirements, IMissingFeature } from './types';
/**
* Middleware that handles the server signaling that this client does not advertise capabilities that the deployment
* requires.
*
* @param {IStore} store - The redux store.
* @returns {Function}
*/
MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: any) => {
switch (action.type) {
case CONFERENCE_JOINED: {
action.conference.on(
JitsiConferenceEvents.CLIENT_REQUIREMENTS_NOT_MET,
(requirements: IClientRequirements) => _onClientRequirements(store, requirements));
break;
}
}
return next(action);
});
/**
* Describes a missing capability to the user. Uses a translation for the capability if this client has one, and
* otherwise the description that the server sent.
*
* @param {IMissingFeature} missingFeature - The missing capability.
* @returns {string}
*/
function _getFeatureText(missingFeature: IMissingFeature): string {
const key = `clientRequirements.features.${missingFeature.name}`;
if (missingFeature.name && i18n.exists(key)) {
return i18n.t(key);
}
return missingFeature.details ?? missingFeature.name ?? missingFeature.feature;
}
/**
* Notifies the user that this client does not advertise capabilities that the deployment requires.
*
* @param {IStore} store - The redux store.
* @param {IClientRequirements} requirements - The capabilities that the client is missing, and what the server did
* about it.
* @returns {void}
*/
function _onClientRequirements({ dispatch, getState }: IStore, requirements: IClientRequirements) {
const { action, features } = requirements;
if (!features?.length) {
return;
}
logger.warn(`This client is missing required capabilities (action=${action}): `
+ `${features.map(f => f.name ?? f.feature).join(', ')}`);
const isReject = action === 'reject';
if (!isReject && getState()['features/base/config'].hideMissingCapabilityWarnings) {
return;
}
const descriptionKey = isReject ? 'clientRequirements.rejectDescription' : 'clientRequirements.warnDescription';
const text = [ i18n.t(descriptionKey) ].concat(features.map(_getFeatureText)).join(' ');
// The first URL that the server sent, if any.
const url = features.find(feature => feature.url)?.url;
const notification = {
...getDescriptionProps(text, url, i18n.t.bind(i18n)),
hideErrorSupportLink: true,
titleKey: isReject ? 'clientRequirements.rejectTitle' : 'clientRequirements.warnTitle'
};
if (isReject) {
// We are not in the conference and can not send or receive media. Show this even if warnings are hidden.
dispatch(showErrorNotification(notification, NOTIFICATION_TIMEOUT_TYPE.STICKY));
} else {
dispatch(showWarningNotification(notification, NOTIFICATION_TIMEOUT_TYPE.LONG));
}
}

View File

@@ -0,0 +1,46 @@
/**
* A capability that this client does not advertise, but the deployment requires.
*/
export interface IMissingFeature {
/**
* Text (in English) from the server, which describes how to add support for the capability.
*/
details?: string;
/**
* The XMPP feature (the disco#info "var"), e.g. "http://jitsi.org/ssrc-rewriting-1".
*/
feature: string;
/**
* How severe the missing capability is. With 'hard' the client is not invited to the conference.
*/
level: string;
/**
* A stable symbolic name for the capability, e.g. "SSRC_REWRITING_V1". Used as a translation key.
*/
name?: string;
/**
* A URL with more information.
*/
url?: string;
}
/**
* The capabilities that this client is missing, and what the server did about it.
*/
export interface IClientRequirements {
/**
* Either 'reject' (this client is not invited to the conference, i.e. it can not send or receive media) or 'warn'.
*/
action: string;
/**
* The capabilities that this client does not advertise.
*/
features: IMissingFeature[];
}