mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-02-15 07:28:59 +00:00
109 lines
2.8 KiB
TypeScript
109 lines
2.8 KiB
TypeScript
// Copyright 2025 Signal Messenger, LLC
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import type { CallSummary } from '@signalapp/ringrtc';
|
|
import { DAY, SECOND } from './durations/index.std.js';
|
|
import { isFeaturedEnabledNoRedux } from './isFeatureEnabled.dom.js';
|
|
import { isMockEnvironment } from '../environment.std.js';
|
|
import {
|
|
COUNTRY_CODE_FALLBACK,
|
|
getCountryCodeValue,
|
|
getValue,
|
|
} from '../RemoteConfig.dom.js';
|
|
import { getCountryCode } from '../types/PhoneNumber.std.js';
|
|
import { createLogger } from '../logging/log.std.js';
|
|
|
|
const log = createLogger('callQualitySurvey');
|
|
|
|
const FAILURE_END_REASONS: ReadonlySet<string> = new Set([
|
|
'internalFailure',
|
|
'signalingFailure',
|
|
'connectionFailure',
|
|
'iceFailedAfterConnected',
|
|
]);
|
|
|
|
const SURVEY_COOLDOWN = DAY;
|
|
const TEST_SHORT_CALL_THRESHOLD = 30 * SECOND;
|
|
const DEFAULT_PPM = 10000; // 1% default
|
|
|
|
export function isCallFailure(callEndReasonText: string): boolean {
|
|
return FAILURE_END_REASONS.has(callEndReasonText);
|
|
}
|
|
|
|
export function isCallQualitySurveyEnabled(): boolean {
|
|
return isFeaturedEnabledNoRedux({
|
|
betaKey: 'desktop.callQualitySurvey.beta',
|
|
prodKey: 'desktop.callQualitySurvey.prod',
|
|
});
|
|
}
|
|
|
|
export function shouldShowCallQualitySurvey({
|
|
callSummary,
|
|
lastSurveyTime,
|
|
lastFailureSurveyTime,
|
|
e164,
|
|
cqsTestMode,
|
|
}: {
|
|
callSummary: CallSummary;
|
|
lastSurveyTime: number | null;
|
|
lastFailureSurveyTime: number | null;
|
|
e164: string | undefined;
|
|
cqsTestMode?: boolean;
|
|
}): boolean {
|
|
if (
|
|
isMockEnvironment() ||
|
|
!isCallQualitySurveyEnabled() ||
|
|
!callSummary.isSurveyCandidate
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
const now = Date.now();
|
|
const isFailure = isCallFailure(callSummary.callEndReasonText);
|
|
|
|
const canShowFailureSurvey =
|
|
cqsTestMode ||
|
|
lastFailureSurveyTime == null ||
|
|
now - lastFailureSurveyTime > SURVEY_COOLDOWN;
|
|
if (isFailure && canShowFailureSurvey) {
|
|
return true;
|
|
}
|
|
|
|
const canShowGeneralSurvey =
|
|
cqsTestMode ||
|
|
lastSurveyTime == null ||
|
|
now - lastSurveyTime > SURVEY_COOLDOWN;
|
|
if (!canShowGeneralSurvey) {
|
|
return false;
|
|
}
|
|
|
|
const callDuration = callSummary.endTime - callSummary.startTime;
|
|
|
|
if (cqsTestMode && callDuration < TEST_SHORT_CALL_THRESHOLD) {
|
|
return true;
|
|
}
|
|
|
|
return Math.random() < getCallQualitySurveyPPM(e164) / 1_000_000;
|
|
}
|
|
|
|
function getCallQualitySurveyPPM(e164: string | undefined): number {
|
|
const configValue = getValue('desktop.callQualitySurveyPPM');
|
|
if (typeof configValue !== 'string') {
|
|
return DEFAULT_PPM;
|
|
}
|
|
|
|
const countryCode = e164 != null ? getCountryCode(e164) : null;
|
|
const ppm = getCountryCodeValue(
|
|
countryCode ?? COUNTRY_CODE_FALLBACK,
|
|
configValue,
|
|
'callQualitySurveyPPM'
|
|
);
|
|
|
|
if (ppm == null) {
|
|
log.error('getCallQualitySurveyPPM: Could not get PPM from remote config');
|
|
return DEFAULT_PPM;
|
|
}
|
|
|
|
return ppm;
|
|
}
|