From edd358c7b8dacc5a03884e3fc5ca5d2151621705 Mon Sep 17 00:00:00 2001 From: bbaldino Date: Wed, 29 Jul 2020 12:33:18 -0700 Subject: [PATCH] Port JVB configs to new metaconfig lib (#1351) * add metaconfig dep * (temporarily) add a new core JitsiConfig and a TypesafeConfigSource eventually these will both be done in Jicoco * port health config over to metaconfig * port octo config to metaconfig * fix octo config * port expire thread config to metaconfig * port endpointconnectionstatusconfig to metaconfig * use NewJitsiConfig from jicoco * inject new legacy config service from NewJitsiConfig * port ice config to metaconfig * fix iceconfig enum parsing * fix ice config * port bandwidthprobing config to metaconfig * port xmpp client connection config to metaconfig * port websocketserviceconfig to metaconfig * port videobridge config to metaconfig * change xhow mppclientconnectionconfig builds the client configs from a legacy source * wip: port stats config * port stats manager bundle activator config to metaconfig * we no longer need to use new forks of the jvm to run tests (thanks to differences in metaconfig vs old config). * remove unneeded NewTypesafeConfigSource (moved to jicoco) * add OctoConfig tests, fix a bug with legacy 'enabled' prop definition * add xmppclientconnectionconfigtests, fix bug for filtering incomplete configs * tweak method used for ConfigTest * point to jitpack for metaconfig * remove config debug logs * port transportconfig * port bitratecontrollerconfig * port jvbapiconfig * fixup: port bitratecontrollerconfig cont. * update to new config class names in jicoco * updates tests to new config class names in jicoco * fix name of StatsManagerBundleActivatorConfig * fix name of StatsManagerBundleActivatorConfig * fix typos * revert back to using string/conversion for enums (see https://github.com/jitsi/jitsi-metaconfig/issues/14) * add missing retrieve in nominationStrategy config * remove (old) reload of config before initializing ice4j the new legacy shim acts like the old one, so it actively checks the system properties when retrieving (whereas the old-new config cached them) so this is no longer necessary. * remove (old) reload before starting jvb the (old-new) config cached system properties on start, so a reload was needed before reading them if we change them. the new legacy config shim still reads system props on demand, so the reload isn't needed. * update XmppClientConnectionConfig to new config syntax * update WebsocketServiceConfig to new config syntax * update EndpointConnectionStatusConfig to new config syntax * update VideobridgeConfig to new config syntax * update VideobridgeExpireThreadConfig to new config syntax * update BandwidthProbingConfig to new config syntax * update BitrateControllerConfig to new config syntax * update HealthConfig to new config syntax * update IceConfig to new config syntax * update OctoConfig to new config syntax * update StatsManagerBundleActivatorConfig to new config syntax * update jmc version * update jicoco version * update jmt dep * remove extra spaces * move iceconfig member to iceconfig class * re-add license header * wire up metaconfig logger --- jvb/pom.xml | 9 +- .../java/org/jitsi/videobridge/Endpoint.java | 2 +- .../videobridge/EndpointConnectionStatus.java | 15 +- .../main/java/org/jitsi/videobridge/Main.java | 34 ++- .../org/jitsi/videobridge/TransportConfig.kt | 23 +- .../jitsi/videobridge/VideoConstraints.java | 2 +- .../VideoConstraintsCompatibility.java | 10 +- .../org/jitsi/videobridge/Videobridge.java | 31 +-- .../videobridge/VideobridgeExpireThread.java | 8 +- .../videobridge/cc/BandwidthProbing.java | 9 +- .../videobridge/cc/BitrateController.java | 11 +- .../eventadmin/callstats/Activator.java | 7 +- .../org/jitsi/videobridge/health/Health.java | 12 +- .../org/jitsi/videobridge/ice/Harvesters.java | 16 +- .../videobridge/octo/ConfOctoTransport.java | 2 +- .../osgi/ConfigurationActivator.java | 4 +- .../jitsi/videobridge/shim/ContentShim.java | 2 +- .../stats/StatsManagerBundleActivator.java | 11 +- .../stats/VideobridgeStatistics.java | 2 +- .../websocket/ColibriWebSocketService.java | 17 +- .../xmpp/ClientConnectionImpl.java | 7 +- .../EndpointConnectionStatusConfig.kt | 57 +---- .../jitsi/videobridge/VideobridgeConfig.kt | 42 ++++ .../VideobridgeExpireThreadConfig.kt | 42 +--- .../cc/config/BandwidthProbingConfig.kt | 42 +--- .../cc/config/BitrateControllerConfig.kt | 202 +++++++-------- .../videobridge/health/config/HealthConfig.kt | 79 ++---- .../org/jitsi/videobridge/ice/IceConfig.kt | 238 ++++++------------ .../videobridge/octo/OctoRelayService.kt | 10 +- .../videobridge/octo/config/OctoConfig.kt | 198 +++++---------- .../octo/config/OctoRtpReceiver.kt | 3 +- .../videobridge/signaling/api/JvbApiConfig.kt | 16 +- .../StatsManagerBundleActivatorConfig.kt | 235 ++++++----------- .../videobridge/transport/ice/IceTransport.kt | 26 +- .../config/WebsocketServiceConfig.kt | 146 +++-------- .../xmpp/config/XmppClientConnectionConfig.kt | 44 ++-- .../jitsi/videobridge/BridgeShutdownTest.java | 15 +- jvb/src/test/kotlin/org/jitsi/ConfigTest.kt | 46 ++++ .../jitsi/TestReadOnlyConfigurationService.kt | 30 +++ .../org/jitsi/videobridge/JitsiConfigTest.kt | 50 ---- .../health/config/HealthConfigTest.kt | 69 ++--- .../videobridge/octo/config/OctoConfigTest.kt | 91 +++++++ .../StatsManagerBundleActivatorConfigTest.kt | 177 +++++++------ .../config/WebsocketServiceConfigTest.kt | 167 ++++-------- .../config/XmppClientConnectionConfigTest.kt | 177 +++++++++++++ pom.xml | 15 +- 46 files changed, 1151 insertions(+), 1300 deletions(-) create mode 100644 jvb/src/main/kotlin/org/jitsi/videobridge/VideobridgeConfig.kt create mode 100644 jvb/src/test/kotlin/org/jitsi/ConfigTest.kt create mode 100644 jvb/src/test/kotlin/org/jitsi/TestReadOnlyConfigurationService.kt delete mode 100644 jvb/src/test/kotlin/org/jitsi/videobridge/JitsiConfigTest.kt create mode 100644 jvb/src/test/kotlin/org/jitsi/videobridge/octo/config/OctoConfigTest.kt create mode 100644 jvb/src/test/kotlin/org/jitsi/videobridge/xmpp/config/XmppClientConnectionConfigTest.kt diff --git a/jvb/pom.xml b/jvb/pom.xml index a5d0b21c16..c763932fc5 100644 --- a/jvb/pom.xml +++ b/jvb/pom.xml @@ -154,6 +154,10 @@ ${project.groupId} jitsi-utils-kotlin + + ${project.groupId} + jitsi-metaconfig + org.osgi org.osgi.core @@ -284,7 +288,7 @@ test - org.jitsi + ${project.groupId} jicoco-test-kotlin ${jicoco.version} test @@ -488,9 +492,6 @@ org.apache.maven.plugins maven-surefire-plugin 2.22.2 - - false - com.github.spotbugs diff --git a/jvb/src/main/java/org/jitsi/videobridge/Endpoint.java b/jvb/src/main/java/org/jitsi/videobridge/Endpoint.java index 72592653d6..f5022278b6 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/Endpoint.java +++ b/jvb/src/main/java/org/jitsi/videobridge/Endpoint.java @@ -294,7 +294,7 @@ public void trace(@NotNull Function0 f) getClass().getSimpleName() + "-outgoing-packet-queue", TaskPools.IO_POOL, this::doSendSrtp, - TransportConfig.Config.queueSize() + TransportConfig.getQueueSize() ); outgoingSrtpPacketQueue.setErrorHandler(queueErrorCounter); diff --git a/jvb/src/main/java/org/jitsi/videobridge/EndpointConnectionStatus.java b/jvb/src/main/java/org/jitsi/videobridge/EndpointConnectionStatus.java index 64e427c537..f9752faeb8 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/EndpointConnectionStatus.java +++ b/jvb/src/main/java/org/jitsi/videobridge/EndpointConnectionStatus.java @@ -26,8 +26,6 @@ import java.util.*; import java.util.stream.*; -import static org.jitsi.videobridge.EndpointConnectionStatusConfig.*; - /** * This module monitors all endpoints across all conferences currently hosted * on the bridge for their connectivity status and sends notifications through @@ -35,7 +33,8 @@ * * An endpoint's connectivity status is considered connected as long as there * is any traffic activity seen on any of its endpoints. When there is no - * activity for longer than the value of {@link Config#getMaxInactivityLimit()}, it + * activity for longer than the value of + * {@link EndpointConnectionStatusConfig#getMaxInactivityLimit()}, it * will be assumed that the endpoint is having some connectivity issues. Those * may be temporary or permanent. When that happens there will be a Colibri * message broadcast to all conference endpoints. The Colibri class name of @@ -78,6 +77,8 @@ public class EndpointConnectionStatus */ private Timer timer; + private final EndpointConnectionStatusConfig config = new EndpointConnectionStatusConfig(); + /** * The {@link Clock} used by this class */ @@ -123,12 +124,12 @@ public void run() logger.error("Endpoint connection monitoring is already running"); } - if (Config.getFirstTransferTimeout().compareTo(Config.getMaxInactivityLimit()) <= 0) + if (config.getFirstTransferTimeout().compareTo(config.getMaxInactivityLimit()) <= 0) { throw new IllegalArgumentException( String.format("first transfer timeout(%s) must be greater" + " than max inactivity limit(%s)", - Config.getFirstTransferTimeout(), Config.getMaxInactivityLimit())); + config.getFirstTransferTimeout(), config.getMaxInactivityLimit())); } super.start(bundleContext); @@ -206,7 +207,7 @@ private void monitorEndpointActivity(AbstractEndpoint abstractEndpoint) // We're doing that by checking how much time has elapsed since // the first endpoint's channel has been created. Duration timeSinceCreated = Duration.between(mostRecentChannelCreated, now); - if (timeSinceCreated.compareTo(Config.getFirstTransferTimeout()) > 0) + if (timeSinceCreated.compareTo(config.getFirstTransferTimeout()) > 0) { if (logger.isDebugEnabled()) logger.debug( @@ -228,7 +229,7 @@ private void monitorEndpointActivity(AbstractEndpoint abstractEndpoint) } Duration noActivityTime = Duration.between(lastActivity, now); - boolean inactive = noActivityTime.compareTo(Config.getMaxInactivityLimit()) > 0; + boolean inactive = noActivityTime.compareTo(config.getMaxInactivityLimit()) > 0; boolean changed = false; synchronized (inactiveEndpoints) { diff --git a/jvb/src/main/java/org/jitsi/videobridge/Main.java b/jvb/src/main/java/org/jitsi/videobridge/Main.java index 99c531b07d..b235f2d07c 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/Main.java +++ b/jvb/src/main/java/org/jitsi/videobridge/Main.java @@ -15,9 +15,12 @@ */ package org.jitsi.videobridge; +import kotlin.jvm.functions.*; +import org.jetbrains.annotations.*; import org.jitsi.cmd.*; -import org.jitsi.config.*; import org.jitsi.meet.*; +import org.jitsi.metaconfig.*; +import org.jitsi.utils.logging2.*; import org.jitsi.videobridge.osgi.*; /** @@ -59,6 +62,8 @@ public static void main(String[] args) cmdLine.parse(args); + setupMetaconfigLogger(); + // Parse the command-line arguments. String apis = cmdLine.getOptionValue(APIS_ARG_NAME); @@ -77,12 +82,33 @@ public static void main(String[] args) Videobridge.REST_API_PNAME, Boolean.toString(apis.contains(Videobridge.REST_API))); - // Need to force a reload to see the updated system properties - JitsiConfig.Companion.reload(); - ComponentMain main = new ComponentMain(); BundleConfig osgiBundles = new BundleConfig(); main.runMainProgramLoop(osgiBundles); } + + private static void setupMetaconfigLogger() { + Logger configLogger = new LoggerImpl("org.jitsi.config"); + MetaconfigSettings.Companion.setLogger(new MetaconfigLogger() + { + @Override + public void warn(@NotNull Function0 function0) + { + configLogger.warn(function0::invoke); + } + + @Override + public void error(@NotNull Function0 function0) + { + configLogger.error(function0::invoke); + } + + @Override + public void debug(@NotNull Function0 function0) + { + configLogger.debug(function0::invoke); + } + }); + } } diff --git a/jvb/src/main/java/org/jitsi/videobridge/TransportConfig.kt b/jvb/src/main/java/org/jitsi/videobridge/TransportConfig.kt index 0c564b9f36..c946f2d82e 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/TransportConfig.kt +++ b/jvb/src/main/java/org/jitsi/videobridge/TransportConfig.kt @@ -15,24 +15,13 @@ */ package org.jitsi.videobridge -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.SimpleProperty +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config +import org.jitsi.metaconfig.from class TransportConfig { - class Config { - companion object { - - class QueueSizeProperty : SimpleProperty( - newConfigAttributes { - name("videobridge.transport.send.queue-size") - readOnce() - } - ) - - private val queueSizeProperty = QueueSizeProperty() - - @JvmStatic - fun queueSize() = queueSizeProperty.value - } + companion object { + @JvmStatic + val queueSize: Int by config("videobridge.transport.send.queue-size".from(JitsiConfig.newConfig)) } } diff --git a/jvb/src/main/java/org/jitsi/videobridge/VideoConstraints.java b/jvb/src/main/java/org/jitsi/videobridge/VideoConstraints.java index c97d2c4866..7ccc2192e5 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/VideoConstraints.java +++ b/jvb/src/main/java/org/jitsi/videobridge/VideoConstraints.java @@ -29,7 +29,7 @@ public class VideoConstraints * Static instance for the default constraints for a thumbnail. */ public static final VideoConstraints thumbnailVideoConstraints = - new VideoConstraints(BitrateControllerConfig.Config.thumbnailMaxHeightPx()); + new VideoConstraints(BitrateControllerConfig.thumbnailMaxHeightPx()); /** * The ideal height of the constrained endpoint. The bridge tries to send an diff --git a/jvb/src/main/java/org/jitsi/videobridge/VideoConstraintsCompatibility.java b/jvb/src/main/java/org/jitsi/videobridge/VideoConstraintsCompatibility.java index 6846b8fc42..771bcc38d3 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/VideoConstraintsCompatibility.java +++ b/jvb/src/main/java/org/jitsi/videobridge/VideoConstraintsCompatibility.java @@ -104,7 +104,7 @@ Map computeVideoConstraints() { final VideoConstraints pinnedEndpointConstraints = new VideoConstraints(Math.min( - BitrateControllerConfig.Config.thumbnailMaxHeightPx(), maxFrameHeightCopy)); + BitrateControllerConfig.thumbnailMaxHeightPx(), maxFrameHeightCopy)); Map pinnedVideoConstraintsMap = pinnedEndpointsCopy @@ -144,16 +144,16 @@ Map computeVideoConstraints() // nor the preferred frame-rate because we want even even // distribution of bandwidth among all the tiles to avoid ninjas. selectedEndpointConstraints = new VideoConstraints( - Math.min(BitrateControllerConfig.Config.onstageIdealHeightPx(), + Math.min(BitrateControllerConfig.onstageIdealHeightPx(), maxFrameHeightCopy)); } else { selectedEndpointConstraints = new VideoConstraints( - Math.min(BitrateControllerConfig.Config.onstageIdealHeightPx(), + Math.min(BitrateControllerConfig.onstageIdealHeightPx(), maxFrameHeightCopy), - BitrateControllerConfig.Config.onstagePreferredHeightPx(), - BitrateControllerConfig.Config.onstagePreferredFramerate()); + BitrateControllerConfig.onstagePreferredHeightPx(), + BitrateControllerConfig.onstagePreferredFramerate()); } Map selectedVideoConstraintsMap diff --git a/jvb/src/main/java/org/jitsi/videobridge/Videobridge.java b/jvb/src/main/java/org/jitsi/videobridge/Videobridge.java index ffd3368321..2156b7736a 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/Videobridge.java +++ b/jvb/src/main/java/org/jitsi/videobridge/Videobridge.java @@ -138,6 +138,8 @@ public class Videobridge */ private VideobridgeExpireThread videobridgeExpireThread; + private final VideobridgeConfig config = new VideobridgeConfig(); + /** * The shim which handles Colibri-related logic for this * {@link Videobridge}. @@ -484,13 +486,13 @@ private String getHealthStatus() public IQ handleShutdownIQ(ShutdownIQ shutdownIQ) { // Security not configured - service unavailable - if (shutdownSourcePattern == null) + if (config.getShutdownSourcePattern() == null) { return IQUtils.createError(shutdownIQ, XMPPError.Condition.service_unavailable); } // Check if source matches pattern Jid from = shutdownIQ.getFrom(); - if (from != null && shutdownSourcePattern.matcher(from).matches()) + if (from != null && config.getShutdownSourcePattern().matcher(from).matches()) { logger.info("Accepted shutdown request from: " + from); if (shutdownIQ.isGracefulShutdown()) @@ -573,29 +575,8 @@ void start(final BundleContext bundleContext) UlimitCheck.printUlimits(); - ConfigurationService cfg = getConfigurationService(); - videobridgeExpireThread.start(); - String shutdownSourcesRegexp - = (cfg == null) - ? null - : cfg.getString(SHUTDOWN_ALLOWED_SOURCE_REGEXP_PNAME); - - if (!StringUtils.isBlank(shutdownSourcesRegexp)) - { - try - { - shutdownSourcePattern = Pattern.compile(shutdownSourcesRegexp); - } - catch (PatternSyntaxException exc) - { - logger.error( - "Error parsing enableGracefulShutdownMode sources reg expr: " - + shutdownSourcesRegexp, exc); - } - } - // ProviderManager.addIQProvider( ColibriConferenceIQ.ELEMENT_NAME, @@ -633,6 +614,7 @@ void start(final BundleContext bundleContext) HealthCheckIQ.NAMESPACE, new HealthCheckIQProvider()); + ConfigurationService cfg = getConfigurationService(); startIce4j(bundleContext, cfg); } @@ -668,9 +650,6 @@ private void startIce4j( } } } - - // Reload for all the new system properties to be seen - JitsiConfig.Companion.reload(); } // Initialize the the host candidate interface filters in the ice4j diff --git a/jvb/src/main/java/org/jitsi/videobridge/VideobridgeExpireThread.java b/jvb/src/main/java/org/jitsi/videobridge/VideobridgeExpireThread.java index 05f361fdb1..47e68d817f 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/VideobridgeExpireThread.java +++ b/jvb/src/main/java/org/jitsi/videobridge/VideobridgeExpireThread.java @@ -19,14 +19,10 @@ import java.util.*; import java.util.concurrent.*; -import org.jitsi.osgi.*; -import org.jitsi.service.configuration.*; import org.jitsi.utils.concurrent.*; import org.jitsi.utils.logging2.*; import org.osgi.framework.*; -import static org.jitsi.videobridge.VideobridgeExpireThreadConfig.*; - /** * Implements a Thread which expires the {@link AbstractEndpoint}s and * {@link Conference}s of a specific Videobridge. @@ -70,6 +66,8 @@ public class VideobridgeExpireThread */ private Videobridge videobridge; + public static final VideobridgeExpireThreadConfig config = new VideobridgeExpireThreadConfig(); + /** * Initializes a new {@link VideobridgeExpireThread} instance which is to * expire the {@link Conference}s of a specific {@link Videobridge}. @@ -88,7 +86,7 @@ public VideobridgeExpireThread(Videobridge videobridge) */ void start() { - Duration expireCheckSleepDuration = Config.interval(); + Duration expireCheckSleepDuration = config.getInterval(); logger.info( "Starting with " + expireCheckSleepDuration.getSeconds() + " second interval."); diff --git a/jvb/src/main/java/org/jitsi/videobridge/cc/BandwidthProbing.java b/jvb/src/main/java/org/jitsi/videobridge/cc/BandwidthProbing.java index 0cdd7e7dd3..d15123e63c 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/cc/BandwidthProbing.java +++ b/jvb/src/main/java/org/jitsi/videobridge/cc/BandwidthProbing.java @@ -19,12 +19,11 @@ import org.jitsi.nlj.util.*; import org.jitsi.utils.concurrent.*; import org.jitsi.utils.logging.*; +import org.jitsi.videobridge.cc.config.*; import org.json.simple.*; import java.util.*; -import static org.jitsi.videobridge.cc.config.BandwidthProbingConfig.*; - /** * @author George Politis */ @@ -63,13 +62,15 @@ public class BandwidthProbing private ProbingDataSender probingDataSender; + private static final BandwidthProbingConfig config = new BandwidthProbingConfig(); + /** * Ctor. * */ public BandwidthProbing(ProbingDataSender probingDataSender) { - super(Config.paddingPeriodMs()); + super(config.getPaddingPeriodMs()); this.probingDataSender = probingDataSender; } @@ -156,7 +157,7 @@ public void run() // XXX a signed int is practically sufficient, as it can represent up to // ~ 2GB - int bytes = (int) (Config.paddingPeriodMs() * paddingBps / 1000 / 8); + int bytes = (int) (config.getPaddingPeriodMs() * paddingBps / 1000 / 8); if (!bitrateControllerStatus.activeSsrcs.isEmpty()) { diff --git a/jvb/src/main/java/org/jitsi/videobridge/cc/BitrateController.java b/jvb/src/main/java/org/jitsi/videobridge/cc/BitrateController.java index d5fd214731..530c50c71c 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/cc/BitrateController.java +++ b/jvb/src/main/java/org/jitsi/videobridge/cc/BitrateController.java @@ -26,6 +26,7 @@ import org.jitsi.utils.logging.*; import org.jitsi.utils.logging2.Logger; import org.jitsi.videobridge.*; +import org.jitsi.videobridge.cc.config.*; import org.json.simple.*; import java.lang.*; @@ -174,7 +175,7 @@ public class BitrateController * constraints. */ private static final VideoConstraints defaultVideoConstraints - = new VideoConstraints(Config.thumbnailMaxHeightPx()); + = new VideoConstraints(BitrateControllerConfig.thumbnailMaxHeightPx()); /** * The map of endpoint id to video constraints that contains the video @@ -266,7 +267,7 @@ private static boolean changeIsLargerThanThreshold( // the risk of clogging the receiver's pipe. return deltaBwe > 0 - || deltaBwe < -1 * previousBwe * Config.bweChangeThresholdPct() / 100; + || deltaBwe < -1 * previousBwe * BitrateControllerConfig.bweChangeThresholdPct() / 100; } /** @@ -455,7 +456,7 @@ public JSONObject getDebugState() { JSONObject debugState = new JSONObject(); debugState.put("forwardedEndpoints", forwardedEndpointIds.toString()); - debugState.put("trustBwe", Config.trustBwe()); + debugState.put("trustBwe", BitrateControllerConfig.trustBwe()); debugState.put("lastBwe", lastBwe); debugState.put("videoConstraints", videoConstraintsMap); debugState.put("lastN", lastN); @@ -577,7 +578,7 @@ StatusSnapshot getStatusSnapshot() */ private long getAvailableBandwidth(long nowMs) { - boolean trustBwe = Config.trustBwe(); + boolean trustBwe = BitrateControllerConfig.trustBwe(); if (trustBwe) { // Ignore the bandwidth estimations in the first 10 seconds because @@ -1409,7 +1410,7 @@ private void improve(long maxBps) if (ratedTargetIdx == -1 && ratedPreferredIdx > -1) { - if (!Config.enableOnstageVideoSuspend()) + if (!BitrateControllerConfig.enableOnstageVideoSuspend()) { ratedTargetIdx = 0; oversending = ratedIndices[0].bps > maxBps; diff --git a/jvb/src/main/java/org/jitsi/videobridge/eventadmin/callstats/Activator.java b/jvb/src/main/java/org/jitsi/videobridge/eventadmin/callstats/Activator.java index 9a6a109020..24e0132f94 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/eventadmin/callstats/Activator.java +++ b/jvb/src/main/java/org/jitsi/videobridge/eventadmin/callstats/Activator.java @@ -21,8 +21,7 @@ import org.jitsi.stats.media.*; import org.jitsi.utils.*; import org.jitsi.videobridge.stats.*; -import org.jitsi.videobridge.stats.config.StatsManagerBundleActivatorConfig; -import org.jitsi.videobridge.stats.config.StatsTransportConfig; +import org.jitsi.videobridge.stats.config.*; import org.osgi.framework.*; import java.time.Duration; @@ -132,11 +131,11 @@ public void serviceChanged(ServiceEvent ev) CallStatsIOTransport.DEFAULT_BRIDGE_ID); // Update with per stats transport interval if available. - Duration intervalDuration = StatsManagerBundleActivatorConfig.Config.transportConfigs().stream() + Duration intervalDuration = StatsManagerBundleActivator.config.getTransportConfigs().stream() .filter(tc -> tc instanceof StatsTransportConfig.CallStatsIoStatsTransportConfig) .map(StatsTransportConfig::getInterval) .findFirst() - .orElse(StatsManagerBundleActivatorConfig.Config.statsInterval()); + .orElse(StatsManagerBundleActivator.config.getInterval()); int interval = (int)intervalDuration.toMillis(); String conferenceIDPrefix = ConfigUtils.getString( cfg, diff --git a/jvb/src/main/java/org/jitsi/videobridge/health/Health.java b/jvb/src/main/java/org/jitsi/videobridge/health/Health.java index 7f35f41946..f61aec2fb0 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/health/Health.java +++ b/jvb/src/main/java/org/jitsi/videobridge/health/Health.java @@ -19,13 +19,12 @@ import org.jitsi.health.*; import org.jitsi.osgi.*; import org.jitsi.videobridge.*; +import org.jitsi.videobridge.health.config.*; import org.jitsi.videobridge.ice.*; import org.osgi.framework.*; import java.util.*; -import static org.jitsi.videobridge.health.config.HealthConfig.*; - /** * Checks the health of {@link Videobridge}. * @@ -109,13 +108,20 @@ private static String generateEndpointID() private Videobridge videobridge; + private static final HealthConfig healthConfig = new HealthConfig(); + /** * Initializes a new {@link Health} instance for a specific * {@link Videobridge}. */ public Health() { - super(Config.getInterval(), Config.getTimeout(), Config.getMaxCheckDuration(), Config.stickyFailures()); + super( + healthConfig.getInterval(), + healthConfig.getTimeout(), + healthConfig.getMaxCheckDuration(), + healthConfig.getStickyFailures() + ); } @Override diff --git a/jvb/src/main/java/org/jitsi/videobridge/ice/Harvesters.java b/jvb/src/main/java/org/jitsi/videobridge/ice/Harvesters.java index 12ede7e533..1891a2507a 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/ice/Harvesters.java +++ b/jvb/src/main/java/org/jitsi/videobridge/ice/Harvesters.java @@ -17,14 +17,12 @@ package org.jitsi.videobridge.ice; import org.ice4j.ice.harvest.*; -import org.jitsi.service.configuration.*; import org.jitsi.utils.logging2.*; +import org.jitsi.videobridge.transport.ice.*; import java.io.*; import java.util.*; -import static org.jitsi.videobridge.ice.IceConfig.*; - public class Harvesters { /** @@ -83,7 +81,7 @@ public static void initializeStaticConfiguration() singlePortHarvesters - = SinglePortUdpHarvester.createHarvesters(Config.port()); + = SinglePortUdpHarvester.createHarvesters(IceConfig.config.getPort()); if (singlePortHarvesters.isEmpty()) { singlePortHarvesters = null; @@ -92,14 +90,14 @@ public static void initializeStaticConfiguration() healthy = singlePortHarvesters != null; - if (Config.tcpEnabled()) + if (IceConfig.config.getTcpEnabled()) { - int port = Config.tcpPort(); + int port = IceConfig.config.getTcpPort(); try { - tcpHarvester = new TcpHarvester(port, Config.iceSslTcp()); + tcpHarvester = new TcpHarvester(port, IceConfig.config.getIceSslTcp()); classLogger.info("Initialized TCP harvester on port " - + port + ", ssltcp=" + Config.iceSslTcp()); + + port + ", ssltcp=" + IceConfig.config.getIceSslTcp()); } catch (IOException ioe) @@ -108,7 +106,7 @@ public static void initializeStaticConfiguration() "Failed to initialize TCP harvester on port " + port); } - Integer mappedPort = Config.tcpMappedPort(); + Integer mappedPort = IceConfig.config.getTcpMappedPort(); if (mappedPort != null) { tcpHarvester.addMappedPort(mappedPort); diff --git a/jvb/src/main/java/org/jitsi/videobridge/octo/ConfOctoTransport.java b/jvb/src/main/java/org/jitsi/videobridge/octo/ConfOctoTransport.java index 5a2925a4c1..d6e122ac33 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/octo/ConfOctoTransport.java +++ b/jvb/src/main/java/org/jitsi/videobridge/octo/ConfOctoTransport.java @@ -495,7 +495,7 @@ private PacketInfoQueue createQueue(String epId) "octo-tentacle-outgoing-packet-queue", TaskPools.IO_POOL, this::doSend, - OctoConfig.Config.sendQueueSize()); + OctoConfig.config.getSendQueueSize()); q.setErrorHandler(queueErrorCounter); return q; } diff --git a/jvb/src/main/java/org/jitsi/videobridge/osgi/ConfigurationActivator.java b/jvb/src/main/java/org/jitsi/videobridge/osgi/ConfigurationActivator.java index 8870e78e88..72f0fa5c13 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/osgi/ConfigurationActivator.java +++ b/jvb/src/main/java/org/jitsi/videobridge/osgi/ConfigurationActivator.java @@ -40,9 +40,9 @@ public void start(BundleContext bundleContext) { bundleContext.registerService( ConfigurationService.class.getName(), - JitsiConfig.getLegacyConfigShim(), + JitsiConfig.getSipCommunicatorProps(), null); - logger.info("Registered the LegacyConfigurationServiceShim in OSGi."); + logger.info("Registered the legacy ConfigurationService in OSGi."); } @Override diff --git a/jvb/src/main/java/org/jitsi/videobridge/shim/ContentShim.java b/jvb/src/main/java/org/jitsi/videobridge/shim/ContentShim.java index 605d2e4ad0..b9c7d4f20a 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/shim/ContentShim.java +++ b/jvb/src/main/java/org/jitsi/videobridge/shim/ContentShim.java @@ -424,7 +424,7 @@ private static boolean setExpire(ChannelShim channelShim, int expire) else { channelShim.setExpire( - (int)VideobridgeExpireThreadConfig.Config.inactivityTimeout().getSeconds()); + (int)VideobridgeExpireThread.config.getInactivityTimeout().getSeconds()); } return true; diff --git a/jvb/src/main/java/org/jitsi/videobridge/stats/StatsManagerBundleActivator.java b/jvb/src/main/java/org/jitsi/videobridge/stats/StatsManagerBundleActivator.java index 8a203f3f94..996958bb3f 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/stats/StatsManagerBundleActivator.java +++ b/jvb/src/main/java/org/jitsi/videobridge/stats/StatsManagerBundleActivator.java @@ -17,12 +17,11 @@ import org.jitsi.utils.logging2.Logger; import org.jitsi.utils.logging2.LoggerImpl; +import org.jitsi.videobridge.stats.config.*; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; -import static org.jitsi.videobridge.stats.config.StatsManagerBundleActivatorConfig.Config; - /** * Implements a BundleActivator for StatsManager which starts * and stops it in a BundleContext. @@ -70,6 +69,8 @@ public static BundleContext getBundleContext() */ private ServiceRegistration serviceRegistration; + public static final StatsManagerBundleActivatorConfig config = new StatsManagerBundleActivatorConfig(); + /** * Starts the StatsManager OSGi bundle in a BundleContext. * Initializes and starts a new StatsManager instance and registers @@ -83,7 +84,7 @@ public static BundleContext getBundleContext() public void start(BundleContext bundleContext) throws Exception { - if (Config.enabled()) + if (config.getEnabled()) { StatsManagerBundleActivator.bundleContext = bundleContext; @@ -126,10 +127,10 @@ private void start() // // XXX Consequently, the default Statistics instance is to be added to // StatsManager before adding any StatsTransport instances. - statsMgr.addStatistics(new VideobridgeStatistics(), Config.statsInterval().toMillis()); + statsMgr.addStatistics(new VideobridgeStatistics(), config.getInterval().toMillis()); // Add StatsTransports to StatsManager. - Config.transportConfigs().forEach(transportConfig -> { + config.getTransportConfigs().forEach(transportConfig -> { statsMgr.addTransport(transportConfig.toStatsTransport(), transportConfig.getInterval().toMillis()); }); diff --git a/jvb/src/main/java/org/jitsi/videobridge/stats/VideobridgeStatistics.java b/jvb/src/main/java/org/jitsi/videobridge/stats/VideobridgeStatistics.java index 84e917163c..40f5fb0dc4 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/stats/VideobridgeStatistics.java +++ b/jvb/src/main/java/org/jitsi/videobridge/stats/VideobridgeStatistics.java @@ -57,7 +57,7 @@ public class VideobridgeStatistics /** * The currently configured region. */ - private static final String region = OctoConfig.Config.region(); + private static final String region = OctoConfig.config.getRegion(); public static final String EPS_NO_MSG_TRANSPORT_AFTER_DELAY = diff --git a/jvb/src/main/java/org/jitsi/videobridge/websocket/ColibriWebSocketService.java b/jvb/src/main/java/org/jitsi/videobridge/websocket/ColibriWebSocketService.java index 6f53e70e36..f389aa6d0b 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/websocket/ColibriWebSocketService.java +++ b/jvb/src/main/java/org/jitsi/videobridge/websocket/ColibriWebSocketService.java @@ -17,10 +17,9 @@ import org.eclipse.jetty.servlet.*; import org.jitsi.utils.logging2.*; +import org.jitsi.videobridge.websocket.config.*; import org.osgi.framework.*; -import static org.jitsi.videobridge.websocket.config.WebsocketServiceConfig.Config; - /** * @author Boris Grozev */ @@ -46,29 +45,31 @@ public class ColibriWebSocketService */ private final String serverId; + private final WebsocketServiceConfig config = new WebsocketServiceConfig(); + /** * Initializes a {@link ColibriWebSocketService} in a specific * {@link BundleContext}. * * @param tls whether to use "ws" or "wss" in advertised URLs in the absence * of configuration which overrides it (see - * {@link WebsocketServiceConfig.Config#useTls()}). + * {@link WebsocketServiceConfig#getUseTls()}). */ public ColibriWebSocketService(boolean tls) { // The domain name is currently a required property. - if (Config.enabled()) + if (config.getEnabled()) { - String domain = Config.domain(); + String domain = config.getDomain(); // We default to matching the protocol used by the local jetty // instance, but we allow for the configuration via properties // to override it since certain use-cases require it. - Boolean tlsProp = Config.useTls(); + Boolean tlsProp = config.getUseTls(); tls = tlsProp != null ? tlsProp : tls; // The server ID is not critical, just use a default string // unless configured. - serverId = Config.serverId(); + serverId = config.getServerId(); String scheme = tls ? "wss://" : "ws://"; baseUrl = scheme + domain + COLIBRI_WS_PATH + serverId + "/"; @@ -129,7 +130,7 @@ ServletHolder initializeColibriWebSocketServlet( { ServletHolder holder = null; - if (baseUrl != null && Config.enabled()) + if (baseUrl != null && config.getEnabled()) { logger.info("Starting colibri websocket service with baseUrl: " + baseUrl); diff --git a/jvb/src/main/java/org/jitsi/videobridge/xmpp/ClientConnectionImpl.java b/jvb/src/main/java/org/jitsi/videobridge/xmpp/ClientConnectionImpl.java index c5d6473189..6c87fe47bd 100644 --- a/jvb/src/main/java/org/jitsi/videobridge/xmpp/ClientConnectionImpl.java +++ b/jvb/src/main/java/org/jitsi/videobridge/xmpp/ClientConnectionImpl.java @@ -18,6 +18,7 @@ import edu.umd.cs.findbugs.annotations.*; import org.jitsi.osgi.*; import org.jitsi.utils.logging2.*; +import org.jitsi.videobridge.xmpp.config.*; import org.jitsi.xmpp.extensions.colibri.*; import org.jitsi.xmpp.extensions.health.*; import org.jitsi.xmpp.mucclient.*; @@ -27,8 +28,6 @@ import java.util.*; -import static org.jitsi.videobridge.xmpp.config.XmppClientConnectionConfig.*; - /** * Provides jitsi-videobridge functions through an XMPP client connection. * @@ -58,6 +57,8 @@ public class ClientConnectionImpl */ private final XmppCommon common = new XmppCommon(); + private final XmppClientConnectionConfig config = new XmppClientConnectionConfig(); + /** * Starts this bundle. */ @@ -85,7 +86,7 @@ public void start(BundleContext bundleContext) ShutdownIQ.createGracefulShutdownIQ()); mucClientManager.setIQListener(this); - Config.getClientConfigs() + config.getClientConfigs() .forEach(cfg -> mucClientManager.addMucClient(cfg)); serviceRegistration diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/EndpointConnectionStatusConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/EndpointConnectionStatusConfig.kt index 5520c3cefd..83c2ac1945 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/EndpointConnectionStatusConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/EndpointConnectionStatusConfig.kt @@ -16,53 +16,22 @@ package org.jitsi.videobridge -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config import java.time.Duration class EndpointConnectionStatusConfig { - class Config { - companion object { - /** - * How long it can take an endpoint to send first data before it will - * be marked as inactive. - */ - class FirstTransferTimeoutProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.EndpointConnectionStatus.FIRST_TRANSFER_TIMEOUT") - readOnce() - retrievedAs() convertedBy { Duration.ofMillis(it) } - }, - newConfigAttributes { - name("videobridge.ep-connection-status.first-transfer-timeout") - readOnce() - } - ) - private val firstTransferTimeout = FirstTransferTimeoutProperty() - - @JvmStatic - fun getFirstTransferTimeout(): Duration = firstTransferTimeout.value - - /** - * How long an endpoint can be inactive before it wil be considered - * disconnected. - */ - class MaxInactivityLimitProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.EndpointConnectionStatus.MAX_INACTIVITY_LIMIT") - readOnce() - retrievedAs() convertedBy { Duration.ofMillis(it) } - }, - newConfigAttributes { - name("videobridge.ep-connection-status.max-inactivity-limit") - readOnce() - } - ) - private val maxInactivityLimit = MaxInactivityLimitProperty() + val firstTransferTimeout: Duration by config { + "org.jitsi.videobridge.EndpointConnectionStatus.FIRST_TRANSFER_TIMEOUT" + .from(JitsiConfig.legacyConfig) + .convertFrom(Duration::ofMillis) + "videobridge.ep-connection-status.first-transfer-timeout".from(JitsiConfig.newConfig) + } - @JvmStatic - fun getMaxInactivityLimit(): Duration = maxInactivityLimit.value - } + val maxInactivityLimit: Duration by config { + "org.jitsi.videobridge.EndpointConnectionStatus.MAX_INACTIVITY_LIMIT" + .from(JitsiConfig.legacyConfig) + .convertFrom(Duration::ofMillis) + "videobridge.ep-connection-status.max-inactivity-limit".from(JitsiConfig.newConfig) } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/VideobridgeConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/VideobridgeConfig.kt new file mode 100644 index 0000000000..755a118972 --- /dev/null +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/VideobridgeConfig.kt @@ -0,0 +1,42 @@ +/* + * Copyright @ 2018 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi.videobridge + +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.ConfigException +import org.jitsi.metaconfig.optionalconfig +import java.util.regex.Pattern +import java.util.regex.PatternSyntaxException + +class VideobridgeConfig { + val shutdownSourcePattern: Pattern? by optionalconfig { + "org.jitsi.videobridge.shutdown.ALLOWED_SOURCE_REGEXP" + .from(JitsiConfig.legacyConfig) + .convertFrom { + if (it.isNotBlank()) { + try { + Pattern.compile(it) + } catch (e: PatternSyntaxException) { + throw ConfigException.UnableToRetrieve.WrongType( + "shutdownSourceRegex expected valid regex pattern: $e") + } + } else { + throw ConfigException.UnableToRetrieve.NotFound("not found") + } + } + } +} diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/VideobridgeExpireThreadConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/VideobridgeExpireThreadConfig.kt index 46e5039ff4..48036d670b 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/VideobridgeExpireThreadConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/VideobridgeExpireThreadConfig.kt @@ -16,43 +16,17 @@ package org.jitsi.videobridge -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty -import org.jitsi.utils.config.SimpleProperty +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config +import org.jitsi.metaconfig.from import java.time.Duration class VideobridgeExpireThreadConfig { - class Config { - companion object { - class InactivityTimeoutProperty : SimpleProperty( - newConfigAttributes { - name("videobridge.entity-expiration.timeout") - readOnce() - } - ) + val inactivityTimeout: Duration by config("videobridge.entity-expiration.timeout".from(JitsiConfig.newConfig)) - private val inactivityTimeoutProp = InactivityTimeoutProperty() - - @JvmStatic - fun inactivityTimeout() = inactivityTimeoutProp.value - - class ExpireThreadIntervalProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.EXPIRE_CHECK_SLEEP_SEC") - readOnce() - retrievedAs() convertedBy { Duration.ofSeconds(it) } - }, - newConfigAttributes { - name("videobridge.entity-expiration.check-interval") - readOnce() - } - ) - - private val expireThreadIntervalProp = ExpireThreadIntervalProperty() - - @JvmStatic - fun interval(): Duration = expireThreadIntervalProp.value - } + val interval: Duration by config { + "org.jitsi.videobridge.EXPIRE_CHECK_SLEEP_SEC".from(JitsiConfig.legacyConfig) + .convertFrom(Duration::ofSeconds) + "videobridge.entity-expiration.check-interval".from(JitsiConfig.newConfig) } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/cc/config/BandwidthProbingConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/cc/config/BandwidthProbingConfig.kt index bafc84b827..3a024eebe6 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/cc/config/BandwidthProbingConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/cc/config/BandwidthProbingConfig.kt @@ -16,41 +16,17 @@ package org.jitsi.videobridge.cc.config -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty -import org.jitsi.utils.config.SimpleProperty +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config import java.time.Duration class BandwidthProbingConfig { - class Config { - companion object { - /** - * How often we check to send probing data - */ - class PaddingPeriodProperty : FallbackProperty( - legacyConfigAttributes { - readOnce() - name("org.jitsi.videobridge.PADDING_PERIOD_MS") - }, - newConfigAttributes { - readOnce() - name("videobridge.cc.padding-period") - retrievedAs() convertedBy { it.toMillis() } - } - ) - private val paddingPeriodProp = PaddingPeriodProperty() - - @JvmStatic - fun paddingPeriodMs() = paddingPeriodProp.value - - class DisableRtxProbingProperty : SimpleProperty( - legacyConfigAttributes { - readOnce() - name("org.jitsi.videobridge.DISABLE_RTX_PROBING") - deprecated("RTX probing is always used when RTX is supported.") - } - ) - } + /** + * How often we check to send probing data + */ + val paddingPeriodMs: Long by config { + "org.jitsi.videobridge.PADDING_PERIOD_MS".from(JitsiConfig.legacyConfig) + "videobridge.cc.padding-period" + .from(JitsiConfig.newConfig).convertFrom { it.toMillis() } } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/cc/config/BitrateControllerConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/cc/config/BitrateControllerConfig.kt index ef163ea1a6..6f4f86ffc5 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/cc/config/BitrateControllerConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/cc/config/BitrateControllerConfig.kt @@ -16,124 +16,94 @@ package org.jitsi.videobridge.cc.config -import org.jitsi.config.LegacyFallbackConfigProperty -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.SimpleProperty +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config +import org.jitsi.metaconfig.from class BitrateControllerConfig { - class Config { - companion object { - /** - * The property that holds the bandwidth estimation threshold. - * - * In order to limit the resolution changes due to bandwidth changes we - * react to bandwidth changes greater bweChangeThresholdPct / 100 of the - * last bandwidth estimation. - */ - class BweChangeThresholdPercentProperty : LegacyFallbackConfigProperty( - Int::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.BWE_CHANGE_THRESHOLD_PCT", - newName = "videobridge.cc.bwe-change-threshold-pct" - ) - private val bweChangeThresholdPctProp = BweChangeThresholdPercentProperty() - - @JvmStatic - fun bweChangeThresholdPct() = bweChangeThresholdPctProp.value - - /** - * The property for the max resolution to allocate for the thumbnails. - */ - class ThumbnailMaxHeightPixelsProperty : LegacyFallbackConfigProperty( - Int::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.THUMBNAIL_MAX_HEIGHT", - newName = "videobridge.cc.thumbnail-max-height-px" - ) - - private val thumbnailMaxHeightPxProp = ThumbnailMaxHeightPixelsProperty() - - @JvmStatic - fun thumbnailMaxHeightPx() = thumbnailMaxHeightPxProp.value - - /** - * The default preferred resolution to allocate for the onstage participant, - * before allocating bandwidth for the thumbnails. - */ - class OnstagePreferredHeightPixelsProperty : LegacyFallbackConfigProperty( - Int::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.ONSTAGE_PREFERRED_HEIGHT", - newName = "videobridge.cc.onstage-preferred-height-px" - ) - private val onstagePreferredHeightPxProp = OnstagePreferredHeightPixelsProperty() - - @JvmStatic - fun onstagePreferredHeightPx() = onstagePreferredHeightPxProp.value - - /** - * The preferred frame rate to allocate for the onstage participant. - */ - class OnstagePreferredFramerateProperty : LegacyFallbackConfigProperty( - Double::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.ONSTAGE_PREFERRED_FRAME_RATE", - newName = "videobridge.cc.onstage-preferred-framerate" - ) - private val onstagePreferredFramerate = OnstagePreferredFramerateProperty() - - @JvmStatic - fun onstagePreferredFramerate() = onstagePreferredFramerate.value - - /** - * Whether or not we're allowed to suspend the video of the - * on-stage participant. - */ - class EnableOnstageVideoSuspendProperty : LegacyFallbackConfigProperty( - Boolean::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.ENABLE_ONSTAGE_VIDEO_SUSPEND", - newName = "videobridge.cc.enable-onstage-video-suspend" - ) - private val enableOnstageVideoSuspendProp = EnableOnstageVideoSuspendProperty() - - @JvmStatic - fun enableOnstageVideoSuspend() = enableOnstageVideoSuspendProp.value - - /** - * Whether or not we should trust the bandwidth - * estimations. If this is se to false, then we assume a bandwidth - * estimation of Long.MAX_VALUE. - */ - class TrustBweProperty : LegacyFallbackConfigProperty( - Boolean::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.TRUST_BWE", - newName = "videobridge.cc.trust-bwe" - ) - - private val trustBweProp = TrustBweProperty() - - @JvmStatic - fun trustBwe() = trustBweProp.value - - /** - * The property for the max resolution to allocate for the onstage - * participant. - */ - class OnstageIdealHeightPixelsProperty : SimpleProperty( - newConfigAttributes { - readOnce() - name("videobridge.cc.onstage-ideal-height-px") - } - ) - - private val onstageIdealHeightPxProp = OnstageIdealHeightPixelsProperty() - - @JvmStatic - fun onstageIdealHeightPx(): Int { - return onstageIdealHeightPxProp.value - } + companion object { + /** + * The bandwidth estimation threshold. + * + * In order to limit the resolution changes due to bandwidth changes we + * react to bandwidth changes greater bweChangeThresholdPct / 100 of the + * last bandwidth estimation. + */ + private val bweChangeThresholdPct: Int by config { + "org.jitsi.videobridge.BWE_CHANGE_THRESHOLD_PCT".from(JitsiConfig.legacyConfig) + "videobridge.cc.bwe-change-threshold-pct".from(JitsiConfig.newConfig) } + + @JvmStatic + fun bweChangeThresholdPct() = bweChangeThresholdPct + + /** + * The max resolution to allocate for the thumbnails. + */ + private val thumbnailMaxHeightPx: Int by config { + "org.jitsi.videobridge.THUMBNAIL_MAX_HEIGHT".from(JitsiConfig.legacyConfig) + "videobridge.cc.thumbnail-max-height-px".from(JitsiConfig.newConfig) + } + + @JvmStatic + fun thumbnailMaxHeightPx() = thumbnailMaxHeightPx + + /** + * The default preferred resolution to allocate for the onstage participant, + * before allocating bandwidth for the thumbnails. + */ + private val onstagePreferredHeightPx: Int by config { + "org.jitsi.videobridge.ONSTAGE_PREFERRED_HEIGHT".from(JitsiConfig.legacyConfig) + "videobridge.cc.onstage-preferred-height-px".from(JitsiConfig.newConfig) + } + + @JvmStatic + fun onstagePreferredHeightPx() = onstagePreferredHeightPx + + /** + * The preferred frame rate to allocate for the onstage participant. + */ + private val onstagePreferredFramerate: Double by config { + "org.jitsi.videobridge.ONSTAGE_PREFERRED_FRAME_RATE".from(JitsiConfig.legacyConfig) + "videobridge.cc.onstage-preferred-framerate".from(JitsiConfig.newConfig) + } + + @JvmStatic + fun onstagePreferredFramerate() = onstagePreferredFramerate + + /** + * Whether or not we're allowed to suspend the video of the + * on-stage participant. + */ + private val enableOnstageVideoSuspend: Boolean by config { + "org.jitsi.videobridge.ENABLE_ONSTAGE_VIDEO_SUSPEND".from(JitsiConfig.legacyConfig) + "videobridge.cc.enable-onstage-video-suspend".from(JitsiConfig.newConfig) + } + + @JvmStatic + fun enableOnstageVideoSuspend(): Boolean = enableOnstageVideoSuspend + + /** + * Whether or not we should trust the bandwidth + * estimations. If this is se to false, then we assume a bandwidth + * estimation of Long.MAX_VALUE. + */ + private val trustBwe: Boolean by config { + "org.jitsi.videobridge.TRUST_BWE".from(JitsiConfig.legacyConfig) + "videobridge.cc.trust-bwe".from(JitsiConfig.newConfig) + } + + @JvmStatic + fun trustBwe(): Boolean = trustBwe + + /** + * The property for the max resolution to allocate for the onstage + * participant. + */ + private val onstageIdealHeightPx: Int by + config("videobridge.cc.onstage-ideal-height-px".from(JitsiConfig.newConfig)) + + @JvmStatic + fun onstageIdealHeightPx() = onstageIdealHeightPx } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/health/config/HealthConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/health/config/HealthConfig.kt index 78a3144000..7f93be5267 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/health/config/HealthConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/health/config/HealthConfig.kt @@ -16,73 +16,28 @@ package org.jitsi.videobridge.health.config -import org.jitsi.config.LegacyFallbackConfigProperty -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty -import org.jitsi.utils.config.SimpleProperty +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config +import org.jitsi.metaconfig.from import java.time.Duration class HealthConfig { - class Config { - companion object { - class HealthIntervalProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.health.INTERVAL") - readOnce() - retrievedAs() convertedBy { Duration.ofMillis(it) } - }, - newConfigAttributes { - name("videobridge.health.interval") - readOnce() - } - ) - - private val intervalProperty = HealthIntervalProperty() - - @JvmStatic - fun getInterval(): Duration = intervalProperty.value - - class TimeoutProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.health.TIMEOUT") - readOnce() - retrievedAs() convertedBy { Duration.ofMillis(it) } - }, - newConfigAttributes { - name("videobridge.health.timeout") - readOnce() - } - ) - - private val timeoutProperty = TimeoutProperty() - - @JvmStatic - fun getTimeout(): Duration = timeoutProperty.value - - class MaxCheckDurationProperty : SimpleProperty( - newConfigAttributes { - name("videobridge.health.max-check-duration") - readOnce() - } - ) - - private val maxCheckDurationProperty = MaxCheckDurationProperty() - - @JvmStatic - fun getMaxCheckDuration(): Duration = maxCheckDurationProperty.value + val interval: Duration by config { + "org.jitsi.videobridge.health.INTERVAL" + .from(JitsiConfig.legacyConfig).convertFrom(Duration::ofMillis) + "videobridge.health.interval".from(JitsiConfig.newConfig) + } - class StickyFailuresProperty : LegacyFallbackConfigProperty( - Boolean::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.health.STICKY_FAILURES", - newName = "videobridge.health.sticky-failures" - ) + val timeout: Duration by config { + "org.jitsi.videobridge.health.TIMEOUT" + .from(JitsiConfig.legacyConfig).convertFrom(Duration::ofMillis) + "videobridge.health.timeout".from(JitsiConfig.newConfig) + } - private val stickyFailures = StickyFailuresProperty() + val maxCheckDuration: Duration by config("videobridge.health.max-check-duration".from(JitsiConfig.newConfig)) - @JvmStatic - fun stickyFailures() = stickyFailures.value - } + val stickyFailures: Boolean by config { + "org.jitsi.videobridge.health.STICKY_FAILURES".from(JitsiConfig.legacyConfig) + "videobridge.health.sticky-failures".from(JitsiConfig.newConfig) } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/ice/IceConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/ice/IceConfig.kt index 2af10f4948..d463aff14d 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/ice/IceConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/ice/IceConfig.kt @@ -13,179 +13,99 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.jitsi.videobridge.ice import org.ice4j.ice.KeepAliveStrategy import org.ice4j.ice.NominationStrategy -import org.jitsi.config.LegacyFallbackConfigProperty -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty -import org.jitsi.utils.config.SimpleProperty -import java.util.Objects +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config +import org.jitsi.metaconfig.from +import org.jitsi.metaconfig.optionalconfig class IceConfig { - class Config { - companion object { - /** - * The property which enables ICE/TCP. - */ - class TcpEnabledProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.DISABLE_TCP_HARVESTER") - readOnce() - // The old property is named 'disable', while the new one - // is 'enable', so invert the old value - transformedBy { !it } - }, - newConfigAttributes { - name("videobridge.ice.tcp.enabled") - readOnce() - } - ) - private val tcpEnabledProp = TcpEnabledProperty() - - @JvmStatic - fun tcpEnabled() = tcpEnabledProp.value - - /** - * The property which configures the ICE/TCP port. - */ - class TcpPortProperty : LegacyFallbackConfigProperty( - Int::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.TCP_HARVESTER_PORT", - newName = "videobridge.ice.tcp.port" - ) - private val tcpPortProperty = TcpPortProperty() - - @JvmStatic - fun tcpPort() = tcpPortProperty.value - - /** - * The property which configures an additional port to advertise. - */ - class TcpMappedPortProperty : LegacyFallbackConfigProperty( - Int::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.TCP_HARVESTER_MAPPED_PORT", - newName = "videobridge.ice.tcp.mapped-port" - ) - private val tcpMappedPortProperty = TcpMappedPortProperty() - - /** - * Returns the additional port to advertise, or [null] if none is configured. - */ - @JvmStatic - fun tcpMappedPort(): Int? = try { - tcpMappedPortProperty.value - } catch (e: Throwable) { - null - } - - /** - * The property that configures whether ICE/TCP should use "ssltcp" or not. - */ - class SslTcpProperty : LegacyFallbackConfigProperty( - Boolean::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.TCP_HARVESTER_SSLTCP", - newName = "videobridge.ice.tcp.ssltcp" - ) - private val sslTcpProperty = SslTcpProperty() - - @JvmStatic - fun iceSslTcp() = sslTcpProperty.value - - /** - * The property that configures the ICE UDP port. - */ - class PortProperty : LegacyFallbackConfigProperty( - Int::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.SINGLE_PORT_HARVESTER_PORT", - newName = "videobridge.ice.udp.port" - ) - private val portProperty = PortProperty() - - @JvmStatic - fun port() = portProperty.value - - /** - * The property that configures the prefix to STUN username fragments we generate. - */ - class UfragPrefixProperty : LegacyFallbackConfigProperty( - String::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.ICE_UFRAG_PREFIX", - newName = "videobridge.ice.ufrag-prefix" - ) - private val ufragPrefixProperty = UfragPrefixProperty() + /** + * Is ICE/TCP enabled. + */ + val tcpEnabled: Boolean by config { + // The old property is named 'disable', while the new one + // is 'enable', so invert the old value + "org.jitsi.videobridge.DISABLE_TCP_HARVESTER".from(JitsiConfig.legacyConfig).transformedBy { !it } + "videobridge.ice.tcp.enabled".from(JitsiConfig.newConfig) + } - @JvmStatic - fun ufragPrefix(): String? = try { - ufragPrefixProperty.value - } catch (e: Throwable) { - null - } + /** + * The ICE/TCP port. + */ + val tcpPort: Int by config { + "org.jitsi.videobridge.TCP_HARVESTER_PORT".from(JitsiConfig.legacyConfig) + "videobridge.ice.tcp.port".from(JitsiConfig.newConfig) + } - /** - * The property that configures the prefix to STUN username fragments we generate. - */ - class KeepAliveStrategyProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.KEEP_ALIVE_STRATEGY") - readOnce() - retrievedAs() convertedBy { Objects.requireNonNull(KeepAliveStrategy.fromString(it)) } - }, - newConfigAttributes { - name("videobridge.ice.keep-alive-strategy") - readOnce() - retrievedAs() convertedBy { Objects.requireNonNull(KeepAliveStrategy.fromString(it)) } - } - ) - private val keepAliveStrategyProperty = KeepAliveStrategyProperty() + /** + * The additional port to advertise, or null if none is configured. + */ + val tcpMappedPort: Int? by optionalconfig { + "org.jitsi.videobridge.TCP_HARVESTER_MAPPED_PORT".from(JitsiConfig.legacyConfig) + "videobridge.ice.tcp.mapped-port".from(JitsiConfig.newConfig) + } - @JvmStatic - fun keepAliveStrategy() = keepAliveStrategyProperty.value + /** + * Whether ICE/TCP should use "ssltcp" or not. + */ + val iceSslTcp: Boolean by config { + "org.jitsi.videobridge.TCP_HARVESTER_SSLTCP".from(JitsiConfig.legacyConfig) + "videobridge.ice.tcp.ssltcp".from(JitsiConfig.newConfig) + } - /** - * The property that configures whether the ice4j "component socket" mode is used. - */ - class ComponentSocketProperty : LegacyFallbackConfigProperty( - Boolean::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.USE_COMPONENT_SOCKET", - newName = "videobridge.ice.use-component-socket" - ) - private val componentSocketProperty = ComponentSocketProperty() + /** + * The ICE UDP port. + */ + val port: Int by config { + "org.jitsi.videobridge.SINGLE_PORT_HARVESTER_PORT".from(JitsiConfig.legacyConfig) + "videobridge.ice.udp.port".from(JitsiConfig.newConfig) + } - @JvmStatic - fun useComponentSocket() = componentSocketProperty.value + /** + * The prefix to STUN username fragments we generate. + */ + val ufragPrefix: String? by optionalconfig { + "org.jitsi.videobridge.ICE_UFRAG_PREFIX".from(JitsiConfig.legacyConfig) + "videobridge.ice.ufrag-prefix".from(JitsiConfig.newConfig) + } - class ResolveRemoteCandidatesProperty : SimpleProperty( - newConfigAttributes { - name("videobridge.ice.resolve-remote-candidates") - readOnce() - }) - private val resolveRemoteCandidatesProperty = ResolveRemoteCandidatesProperty() + val keepAliveStrategy: KeepAliveStrategy by config { + "org.jitsi.videobridge.KEEP_ALIVE_STRATEGY" + .from(JitsiConfig.legacyConfig) + .convertFrom { KeepAliveStrategy.fromString(it) } + "videobridge.ice.keep-alive-strategy" + .from(JitsiConfig.newConfig) + .convertFrom { KeepAliveStrategy.fromString(it) } + } - @JvmStatic - fun resolveRemoteCandidates() = resolveRemoteCandidatesProperty.value + /** + * Whether the ice4j "component socket" mode is used. + */ + val useComponentSocket: Boolean by config { + "org.jitsi.videobridge.USE_COMPONENT_SOCKET".from(JitsiConfig.legacyConfig) + "videobridge.ice.use-component-socket".from(JitsiConfig.newConfig) + } - /** - * The property that configures the ice4j nomination strategy policy. - */ - class NominationStrategyProperty : SimpleProperty( - newConfigAttributes { - name("videobridge.ice.nomination-strategy") - readOnce() - retrievedAs() convertedBy { Objects.requireNonNull(NominationStrategy.fromString(it)) } - }) - private val nominationStrategyProperty = NominationStrategyProperty() + val resolveRemoteCandidates: Boolean by config( + "videobridge.ice.resolve-remote-candidates".from(JitsiConfig.newConfig) + ) + + /** + * The ice4j nomination strategy policy. + */ + val nominationStrategy: NominationStrategy by config { + "videobridge.ice.nomination-strategy" + .from(JitsiConfig.newConfig) + .convertFrom { NominationStrategy.fromString(it) } + } - @JvmStatic - fun nominationStrategy() = nominationStrategyProperty.value - } + companion object { + @JvmField + val config = IceConfig() } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/octo/OctoRelayService.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/octo/OctoRelayService.kt index 0e91d6427a..6b37efddbf 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/octo/OctoRelayService.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/octo/OctoRelayService.kt @@ -17,7 +17,7 @@ package org.jitsi.videobridge.octo import org.jitsi.utils.logging2.LoggerImpl -import org.jitsi.videobridge.octo.config.OctoConfig.Config +import org.jitsi.videobridge.octo.config.OctoConfig import org.jitsi.videobridge.transport.octo.BridgeOctoTransport import org.jitsi.videobridge.transport.udp.UdpTransport import org.jitsi.videobridge.util.TaskPools @@ -41,14 +41,14 @@ class OctoRelayService : BundleActivator { private set override fun start(bundleContext: BundleContext) { - if (!Config.enabled()) { + if (!OctoConfig.config.enabled) { logger.info("Octo relay is disabled") return } - val address = Config.bindAddress() - val publicAddress = Config.publicAddress() - val port = Config.bindPort() + val address = OctoConfig.config.bindAddress + val publicAddress = OctoConfig.config.publicAddress + val port = OctoConfig.config.bindPort try { udpTransport = UdpTransport(address, port, logger, OCTO_SO_RCVBUF, OCTO_SO_SNDBUF) diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/octo/config/OctoConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/octo/config/OctoConfig.kt index ef3462f25d..e9b6d9530b 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/octo/config/OctoConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/octo/config/OctoConfig.kt @@ -16,151 +16,75 @@ package org.jitsi.videobridge.octo.config -import com.typesafe.config.ConfigObject -import org.jitsi.config.LegacyFallbackConfigProperty -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty -import org.jitsi.utils.config.SimpleProperty -import org.jitsi.utils.config.exception.ConfigValueParsingException +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.ConfigException +import org.jitsi.metaconfig.config +import org.jitsi.metaconfig.from +import org.jitsi.metaconfig.optionalconfig class OctoConfig { - class Config { - companion object { - - class RecvQueueSizeProperty : SimpleProperty( - newConfigAttributes { - name("videobridge.octo.recv-queue-size") - readOnce() - } - ) - - private val recvQueueSizeProperty = RecvQueueSizeProperty() - - @JvmStatic - fun recvQueueSize() = recvQueueSizeProperty.value - - class SendQueueSizeProperty : SimpleProperty( - newConfigAttributes { - name("videobridge.octo.send-queue-size") - readOnce() - } - ) - - private val sendQueueSizeProperty = SendQueueSizeProperty() - - @JvmStatic - fun sendQueueSize() = sendQueueSizeProperty.value - - class EnabledProperty : FallbackProperty( - // The legacy config file doesn't have an 'enabled' property, - // instead it was based on the values of the parameters. Here, - // we simulate a legacy 'enabled' value based on the results - // of validating the other properties in the legacy config - // file. - legacyConfigAttributes { - name("org.jitsi.videobridge.octo") - readOnce() - retrievedAs() convertedBy { - val cfg = it.toConfig() - if (cfg.hasPath("BIND_ADDRESS") && cfg.hasPath("BIND_PORT")) { - val bindAddress = cfg.getString("BIND_ADDRESS") - val bindPort = cfg.getInt("BIND_PORT") - bindAddress != null && (bindPort.isUnprivilegedPort()) - } else { - false - } - } - }, - newConfigAttributes { - name("videobridge.octo.enabled") - readOnce() - } - ) - - private val enabledProp = EnabledProperty() - - @JvmStatic - fun enabled() = enabledProp.value - - class RegionProperty : LegacyFallbackConfigProperty( - String::class, - "org.jitsi.videobridge.REGION", - "videobridge.octo.region", - readOnce = true - ) - - private val regionProp = RegionProperty() - - @JvmStatic - fun region(): String? { - return try { - regionProp.value - } catch (t: Throwable) { - null - } + val recvQueueSize: Int by config("videobridge.octo.recv-queue-size".from(JitsiConfig.newConfig)) + + val sendQueueSize: Int by config("videobridge.octo.send-queue-size".from(JitsiConfig.newConfig)) + + // We grab these two properties from the legacy config separately here + // because we use them to infer a legacy value of 'enabled' (which was + // based on the presence of these properties) and as potential values + // in each of the individual bindAddress and bindPort properties. + private val legacyBindAddress: String? by optionalconfig( + "org.jitsi.videobridge.octo.BIND_ADDRESS".from(JitsiConfig.legacyConfig)) + private val legacyBindPort: Int? by optionalconfig( + "org.jitsi.videobridge.octo.BIND_PORT".from(JitsiConfig.legacyConfig)) + + val enabled: Boolean by config { + // The legacy config file doesn't have an 'enabled' property, + // instead it was based on the values of the parameters. Here, + // we simulate a legacy 'enabled' value based on the results + // of validating the other properties in the legacy config + // file. If neither property is present, we consider the field + // "not found" in the legacy config. + "Legacy Octo relay enabled" { + if (legacyBindAddress == null && legacyBindPort == null) { + throw ConfigException.UnableToRetrieve.NotFound("not found") } + legacyBindAddress != null && legacyBindPort?.isUnprivilegedPort() == true + } + "videobridge.octo.enabled".from(JitsiConfig.newConfig) + } - class BindAddressProperty : LegacyFallbackConfigProperty( - String::class, - "org.jitsi.videobridge.octo.BIND_ADDRESS", - "videobridge.octo.bind-address", - readOnce = true - ) - - private val bindAddressProp = BindAddressProperty() - - @JvmStatic - fun bindAddress(): String = bindAddressProp.value - - class BindPortProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.octo.BIND_PORT") - readOnce() - retrievedAs() convertedBy { - if (!it.isUnprivilegedPort()) { - throw ConfigValueParsingException("Octo bind port " + - "must be in the unprivileged port space") - } - it - } - }, - newConfigAttributes { - name("videobridge.octo.bind-port") - readOnce() - } - ) - - private val bindPortProp = BindPortProperty() + val region: String? by optionalconfig { + "org.jitsi.videobridge.REGION".from(JitsiConfig.legacyConfig) + "videobridge.octo.region".from(JitsiConfig.newConfig) + } - @JvmStatic - fun bindPort(): Int = bindPortProp.value + val bindAddress: String by config { + "bind address from legacy config" { legacyBindAddress!! } + "videobridge.octo.bind-address".from(JitsiConfig.newConfig) + } - class PublicAddressProperty : LegacyFallbackConfigProperty( - String::class, - "org.jitsi.videobridge.octo.PUBLIC_ADDRESS", - "videobridge.octo.public-address", - readOnce = true - ) + val bindPort: Int by config { + "bind port from legacy config" { legacyBindPort!! } + "videobridge.octo.bind-port".from(JitsiConfig.newConfig) + } - private val publicAddressProp = PublicAddressProperty() + /** + * If publicAddress doesn't have a value, default to the value of bindAddress. + * Note: we can't use a substitution in reference.conf because that won't take into account + * reading a value from the legacy config file + */ + val publicAddress: String by config { + "org.jitsi.videobridge.octo.PUBLIC_ADDRESS".from(JitsiConfig.legacyConfig) + "videobridge.octo.public-address".from(JitsiConfig.newConfig) + "bindAddress" { bindAddress } + } - /** - * If publicAddress doesn't have a value, default to the - * value of bindAddress. - * Note: we can't use a substitution in reference.conf - * because that won't take into account reading a value - * from the legacy config file - */ - @JvmStatic - fun publicAddress(): String { - return try { - publicAddressProp.value - } catch (t: Throwable) { - bindAddressProp.value - } - } - } + companion object { + /** + * NOTE(brian): Define this here because many classes want to access it from a static context, but + * I think we could tweak that if we wanted. + */ + @JvmField + val config = OctoConfig() } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/octo/config/OctoRtpReceiver.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/octo/config/OctoRtpReceiver.kt index 62f42e79d7..e5dd511b52 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/octo/config/OctoRtpReceiver.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/octo/config/OctoRtpReceiver.kt @@ -51,7 +51,6 @@ import org.jitsi.rtp.extensions.looksLikeRtp import org.jitsi.utils.logging2.Logger import org.jitsi.utils.logging2.createChildLogger import org.jitsi.utils.queue.CountingErrorHandler -import org.jitsi.videobridge.octo.config.OctoConfig.Config import org.jitsi.videobridge.util.ByteBufferPool import org.jitsi.videobridge.util.TaskPools import java.util.concurrent.atomic.AtomicBoolean @@ -72,7 +71,7 @@ class OctoRtpReceiver( "octo-transceiver-incoming-packet-queue", TaskPools.CPU_POOL, this::handleIncomingPacket, - Config.recvQueueSize() + OctoConfig.config.recvQueueSize ).apply { setErrorHandler(queueErrorCounter) } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/signaling/api/JvbApiConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/signaling/api/JvbApiConfig.kt index 99aabd8528..f7623f9109 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/signaling/api/JvbApiConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/signaling/api/JvbApiConfig.kt @@ -16,21 +16,15 @@ package org.jitsi.videobridge.signaling.api -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.SimpleProperty +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config +import org.jitsi.metaconfig.from class JvbApiConfig { companion object { - class EnabledProperty : SimpleProperty( - newConfigAttributes { - readOnce() - name("videobridge.apis.jvb-api.enabled") - } - ) - - private val enabledProperty = EnabledProperty() + private val enabled: Boolean by config("videobridge.apis.jvb-api.enabled".from(JitsiConfig.newConfig)) @JvmStatic - fun enabled(): Boolean = enabledProperty.value + fun enabled() = enabled } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/stats/config/StatsManagerBundleActivatorConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/stats/config/StatsManagerBundleActivatorConfig.kt index e8490ca461..50bd312295 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/stats/config/StatsManagerBundleActivatorConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/stats/config/StatsManagerBundleActivatorConfig.kt @@ -16,141 +16,97 @@ package org.jitsi.videobridge.stats.config +import com.typesafe.config.Config import com.typesafe.config.ConfigList import com.typesafe.config.ConfigObject -import org.jitsi.config.LegacyFallbackConfigProperty -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty -import org.jitsi.utils.config.SimpleProperty -import org.jitsi.utils.config.exception.ConfigPropertyNotFoundException -import org.jitsi.videobridge.config.ConditionalProperty -import org.jitsi.videobridge.config.ResettableSingleton +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.ConfigException +import org.jitsi.metaconfig.config import org.jitsi.videobridge.stats.CallStatsIOTransport import org.jitsi.videobridge.stats.MucStatsTransport import org.jitsi.videobridge.stats.StatsTransport import java.time.Duration class StatsManagerBundleActivatorConfig { - class Config { - companion object { - /** - * Whether or not the stats are enabled - */ - class EnabledProperty : LegacyFallbackConfigProperty( - Boolean::class, - "org.jitsi.videobridge.ENABLE_STATISTICS", - "videobridge.stats.enabled", - readOnce = true - ) - - private val enabledProp = ResettableSingleton { EnabledProperty() } - - @JvmStatic - fun enabled() = enabledProp.get().value - - /** - * The interval at which the stats are pushed - */ - class StatsIntervalProperty : ConditionalProperty( - ::enabled, - StatsInterval(), - "Stats interval property is only parsed when stats are enabled" - ) - - private val statsIntervalProp = ResettableSingleton { StatsIntervalProperty() } - - @JvmStatic - fun statsInterval(): Duration = statsIntervalProp.get().value - - private class StatsInterval : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.STATISTICS_INTERVAL") - readOnce() - retrievedAs() convertedBy { Duration.ofMillis(it) } - }, - newConfigAttributes { - name("videobridge.stats.interval") - readOnce() - } - ) - - /** - * The enabled stat transports - */ - class StatsTransportsProperty : ConditionalProperty>( - ::enabled, - StatsTransports(), - "Stats transports property is only parsed when stats are enabled" - ) - - private val statsTransportsProp = StatsTransportsProperty() + /** + * Whether or not the stats are enabled + */ + val enabled: Boolean by config { + "org.jitsi.videobridge.ENABLE_STATISTICS".from(JitsiConfig.legacyConfig) + "videobridge.stats.enabled".from(JitsiConfig.newConfig) + } - @JvmStatic - fun transportConfigs() = statsTransportsProp.value + /** + * The interval at which the stats are pushed + */ + val interval: Duration by config { + onlyIf("Stats are enabled", ::enabled) { + "org.jitsi.videobridge.STATISTICS_INTERVAL" + .from(JitsiConfig.legacyConfig) + .convertFrom(Duration::ofMillis) + "videobridge.stats.interval".from(JitsiConfig.newConfig) + } + } - /** - * Note that if 'org.jitsi.videobridge.STATISTICS_TRANSPORT' is present at all - * in the legacy config, we won't search the new config (we don't support merging - * stats transport configs from old and new config together). - */ - // TODO: currently we silently swallow all errors. Can we propagate up in a useful way? If - // we throw then I think things will be 'catastrophic' (prevent accessing this config at all), so - // not sure we want that. Other option would be to create a logger here? - private class StatsTransports : FallbackProperty>( - // NOTE: Do NOT mark *these* legacy attributes as deprecated. When we - // want to mark the old stats transport config as deprecated, use the - // classes defined below. - legacyConfigAttributes { - name("org.jitsi.videobridge") - readOnce() - retrievedAs() convertedBy { cfg -> - // Note: if the 'STATISTICS_TRANSPORT' property isn't found [fromLegacyConfig] - // will throw an that will bubble up to here so we fall through to the - // new config - StatsTransportConfig.fromLegacyConfig(cfg.toConfig()) + /** + * The enabled stat transports + * + * Note that if 'org.jitsi.videobridge.STATISTICS_TRANSPORT' is present at all + * in the legacy config, we won't search the new config (we don't support merging + * stats transport configs from old and new config together). + */ + val transportConfigs: List by config { + onlyIf("Stats transports are enabled", ::enabled) { + "org.jitsi.videobridge." + .from(JitsiConfig.legacyConfig) + .convertFrom> { + if ("org.jitsi.videobridge.STATISTICS_TRANSPORT" in it) { + it.toStatsTransportConfig() + } else { + throw ConfigException.UnableToRetrieve.NotFound("not found in legacy config") } - }, - // Note: the implementation of this can be simplified when we get support for - // List types (we'll be able to parse 'videobridge.stats.transports' directly - // as a ConfigObjectList) - newConfigAttributes { - name("videobridge.stats") - readOnce() - retrievedAs() convertedBy { cfg -> - val transports = cfg["transports"] - ?: throw ConfigPropertyNotFoundException("Could not find transports within stats") - transports as ConfigList - transports.map { it as ConfigObject } + } + "videobridge.stats" + .from(JitsiConfig.newConfig) + .convertFrom { cfg -> + val transports = cfg["transports"] + ?: throw ConfigException.UnableToRetrieve.NotFound("Could not find transports within stats") + transports as ConfigList + transports.map { it as ConfigObject } .map { it.toConfig() } - .mapNotNull { StatsTransportConfig.fromNewConfig(it) } - } + .mapNotNull { it.toStatsTransportConfig() } } - ) + } + } - /** - * Note: These three classes exist only for the purposes of validation - * and future deprecation. IN the legacy config file, the properties - * for stats transports are spread across these 3 values, making it - * difficult to encompass in a single property. We could read the property - * at the level of 'org.jitsi.videobridge", but that has the following - * issues: - * - * 1) It won't register correctly in validation that these specific properties - * are read - * 2) When we want to mark them as deprecated, we'd be marking the entire chunk - * as deprecated instead of the specific properties - * - * Because of that, we define these here to handle the above use cases, but - * implement the property that's used differently (see above) - */ - @Suppress("unused") - private class LegacyStatsTransportsProperty : SimpleProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.STATISTICS_TRANSPORT") - readOnce() - } - ) + /** + * From a map of properties pulled from the legacy config file, create a list of [StatsTransportConfig] + */ + private fun Map.toStatsTransportConfig(): List { + val transportTypes = + this["org.jitsi.videobridge.STATISTICS_TRANSPORT"]?.split(",") ?: return listOf() + return transportTypes.mapNotNull { transportType -> + val interval = this["org.jitsi.videobridge.STATISTICS_INTERVAL.$transportType"]?.let { + Duration.ofMillis(it.toLong()) + } ?: this@StatsManagerBundleActivatorConfig.interval + when (transportType) { + "muc" -> StatsTransportConfig.MucStatsTransportConfig(interval) + "callstats.io" -> StatsTransportConfig.CallStatsIoStatsTransportConfig(interval) + else -> null + } + } + } + + private fun Config.toStatsTransportConfig(): StatsTransportConfig? { + val interval = if (hasPath("interval")) { + getDuration("interval") + } else { + this@StatsManagerBundleActivatorConfig.interval + } + return when (getString("type")) { + "muc" -> StatsTransportConfig.MucStatsTransportConfig(interval) + "callstatsio" -> StatsTransportConfig.CallStatsIoStatsTransportConfig(interval) + else -> null } } } @@ -166,43 +122,8 @@ sealed class StatsTransportConfig( class MucStatsTransportConfig(interval: Duration) : StatsTransportConfig(interval) { override fun toStatsTransport(): StatsTransport = MucStatsTransport() } + class CallStatsIoStatsTransportConfig(interval: Duration) : StatsTransportConfig(interval) { override fun toStatsTransport(): StatsTransport = CallStatsIOTransport() } - companion object { - /** - * [config] will represent an object within the "videobridge.stats.transports" list - */ - fun fromNewConfig(config: com.typesafe.config.Config): StatsTransportConfig? { - val interval = if (config.hasPath("interval")) { - config.getDuration("interval") - } else { - StatsManagerBundleActivatorConfig.Config.statsInterval() - } - return when (config.getString("type")) { - "muc" -> MucStatsTransportConfig(interval) - "callstatsio" -> CallStatsIoStatsTransportConfig(interval) - else -> null - } - } - - /** - * [config] will represent the "org.jitsi.videobridge" object - */ - fun fromLegacyConfig(config: com.typesafe.config.Config): List { - val transportStrings = config.getString("STATISTICS_TRANSPORT").split(",") - return transportStrings.mapNotNull { - val interval = if (config.hasPath("STATISTICS_INTERVAL.$it")) { - Duration.ofMillis(config.getLong("STATISTICS_INTERVAL.$it")) - } else { - StatsManagerBundleActivatorConfig.Config.statsInterval() - } - when (it) { - "muc" -> MucStatsTransportConfig(interval) - "callstats.io" -> CallStatsIoStatsTransportConfig(interval) - else -> null - } - } - } - } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/transport/ice/IceTransport.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/transport/ice/IceTransport.kt index 5ec2d2c290..de22acc075 100755 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/transport/ice/IceTransport.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/transport/ice/IceTransport.kt @@ -31,7 +31,7 @@ import org.jitsi.utils.logging2.Logger import org.jitsi.utils.logging2.cdebug import org.jitsi.utils.logging2.createChildLogger import org.jitsi.videobridge.ice.Harvesters -import org.jitsi.videobridge.ice.IceConfig.Config +import org.jitsi.videobridge.ice.IceConfig import org.jitsi.videobridge.ice.TransportUtils import org.jitsi.xmpp.extensions.jingle.CandidatePacketExtension import org.jitsi.xmpp.extensions.jingle.IceUdpTransportPacketExtension @@ -96,11 +96,11 @@ class IceTransport @JvmOverloads constructor( */ private val running = AtomicBoolean(true) - private val iceAgent = Agent(Config.ufragPrefix(), logger).apply { + private val iceAgent = Agent(IceConfig.config.ufragPrefix, logger).apply { appendHarvesters(this) isControlling = controlling performConsentFreshness = true - nominationStrategy = Config.nominationStrategy() + nominationStrategy = IceConfig.config.nominationStrategy addStateChangeListener(this@IceTransport::iceStateChanged) }.also { logger.addContext("local_ufrag", it.localUfrag) @@ -112,13 +112,13 @@ class IceTransport @JvmOverloads constructor( } private val iceComponent = iceAgent.createComponent( - iceStream, - Transport.UDP, - -1, - -1, - -1, - Config.keepAliveStrategy(), - Config.useComponentSocket() + iceStream, + Transport.UDP, + -1, + -1, + -1, + IceConfig.config.keepAliveStrategy, + IceConfig.config.useComponentSocket ) private val packetStats = PacketStats() @@ -240,8 +240,8 @@ class IceTransport @JvmOverloads constructor( } fun getDebugState(): OrderedJsonObject = OrderedJsonObject().apply { - put("useComponentSocket", Config.useComponentSocket()) - put("keepAliveStrategy", Config.keepAliveStrategy().toString()) + put("useComponentSocket", IceConfig.config.useComponentSocket) + put("keepAliveStrategy", IceConfig.config.keepAliveStrategy.toString()) put("closed", !running.get()) put("iceConnected", iceConnected.get()) put("iceFailed", iceFailed.get()) @@ -279,7 +279,7 @@ class IceTransport @JvmOverloads constructor( if (candidate.generation != iceAgent.generation) { return@forEach } - if (candidate.ipNeedsResolution() && !Config.resolveRemoteCandidates()) { + if (candidate.ipNeedsResolution() && !IceConfig.config.resolveRemoteCandidates) { logger.cdebug { "Ignoring remote candidate with non-literal address: ${candidate.ip}" } return@forEach } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/websocket/config/WebsocketServiceConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/websocket/config/WebsocketServiceConfig.kt index adf7930e4e..97bfa63f87 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/websocket/config/WebsocketServiceConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/websocket/config/WebsocketServiceConfig.kt @@ -16,119 +16,49 @@ package org.jitsi.videobridge.websocket.config -import org.jitsi.config.LegacyFallbackConfigProperty -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty -import org.jitsi.videobridge.config.ConditionalProperty -import org.jitsi.videobridge.config.ConditionalPropertyConditionNotMetException -import org.jitsi.videobridge.config.ResettableSingleton +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.config +import org.jitsi.metaconfig.optionalconfig class WebsocketServiceConfig { - class Config { - companion object { - /** - * The name of the property which enables the - * [org.jitsi.videobridge.websocket.ColibriWebSocketService] - */ - class EnabledProperty : FallbackProperty( - legacyConfigAttributes { - name("org.jitsi.videobridge.rest.COLIBRI_WS_DISABLE") - readOnce() - // The old property is named 'disable', while the new one - // is 'enable', so invert the old value - transformedBy { !it } - }, - newConfigAttributes { - name("videobridge.websockets.enabled") - readOnce() - } - ) - private val enabledProp = ResettableSingleton { EnabledProperty() } - - @JvmStatic - fun enabled() = enabledProp.get().value - - /** - * The property which controls the domain name used in URLs - * advertised for COLIBRI WebSockets. - */ - class DomainProperty : ConditionalProperty( - Companion::enabled, - object : LegacyFallbackConfigProperty( - String::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.rest.COLIBRI_WS_DOMAIN", - newName = "videobridge.websockets.domain" - ) {}, - "Websocket domain property is only parsed when websockets are enabled" - ) - - private val domainProp = - DomainProperty() - - /** - * Note, should only be accessed after verifying [enabled] is true - */ - @JvmStatic - fun domain() = domainProp.value - - /** - * The property which controls whether URLs advertised for - * COLIBRI WebSockets should use the "ws" (if false) or "wss" (if true) - * schema. - */ - class TlsProperty : ConditionalProperty( - Companion::enabled, - object : LegacyFallbackConfigProperty( - Boolean::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.rest.COLIBRI_WS_TLS", - newName = "videobridge.websockets.tls" - ) {}, - "Websocket TLS property is only parsed when websockets are enabled" - ) - private val tlsProp = - TlsProperty() + /** + * Whether [org.jitsi.videobridge.websocket.ColibriWebSocketService] is enabled + */ + val enabled: Boolean by config { + // The old property is named 'disable', while the new one + // is 'enable', so invert the old value + "org.jitsi.videobridge.rest.COLIBRI_WS_DISABLE" + .from(JitsiConfig.legacyConfig).transformedBy { !it } + "videobridge.websockets.enabled".from(JitsiConfig.newConfig) + } - /** - * Note, should only be accessed after verifying [enabled] is true. - * Also: we support the field not being defined. See its usage. - */ - @JvmStatic - fun useTls(): Boolean? { - return try { - tlsProp.value - } catch (t: Throwable) { - when (t) { - is ConditionalPropertyConditionNotMetException -> throw t - else -> null - } - } - } + /** + * The domain name used in URLs advertised for COLIBRI WebSockets. + */ + val domain: String by config { + onlyIf("Websockets are enabled", ::enabled) { + "org.jitsi.videobridge.rest.COLIBRI_WS_DOMAIN".from(JitsiConfig.legacyConfig) + "videobridge.websockets.domain".from(JitsiConfig.newConfig) + } + } - /** - * The name of the property which controls the server ID used in URLs - * advertised for COLIBRI WebSockets. - */ - class ServerIdProperty : ConditionalProperty( - Companion::enabled, - object : LegacyFallbackConfigProperty( - String::class, - readOnce = true, - legacyName = "org.jitsi.videobridge.rest.COLIBRI_WS_SERVER_ID", - newName = "videobridge.websockets.server-id" - ) {}, - "Websocket server ID property is only parsed when websockets are enabled" - ) - private val serverIdProp = - ServerIdProperty() + /** + * Whether the "wss" or "ws" protocol should be used for websockets + */ + val useTls: Boolean? by optionalconfig { + onlyIf("Websockets are enabled", ::enabled) { + "org.jitsi.videobridge.rest.COLIBRI_WS_TLS".from(JitsiConfig.legacyConfig) + "videobridge.websockets.tls".from(JitsiConfig.newConfig) + } + } - /** - * Note, should only be accessed after verifying [enabled] is true - */ - @JvmStatic - fun serverId() = serverIdProp.value + /** + * The server ID used in URLs advertised for COLIBRI WebSockets. + */ + val serverId: String by config { + onlyIf("Websockets are enabled", ::enabled) { + "org.jitsi.videobridge.rest.COLIBRI_WS_SERVER_ID".from(JitsiConfig.legacyConfig) + "videobridge.websockets.server-id".from(JitsiConfig.newConfig) } } } diff --git a/jvb/src/main/kotlin/org/jitsi/videobridge/xmpp/config/XmppClientConnectionConfig.kt b/jvb/src/main/kotlin/org/jitsi/videobridge/xmpp/config/XmppClientConnectionConfig.kt index 3f1cbcfed9..97b68309c7 100644 --- a/jvb/src/main/kotlin/org/jitsi/videobridge/xmpp/config/XmppClientConnectionConfig.kt +++ b/jvb/src/main/kotlin/org/jitsi/videobridge/xmpp/config/XmppClientConnectionConfig.kt @@ -18,36 +18,26 @@ package org.jitsi.videobridge.xmpp.config import com.typesafe.config.ConfigObject import com.typesafe.config.ConfigValue -import org.jitsi.config.legacyConfigAttributes -import org.jitsi.config.newConfigAttributes -import org.jitsi.utils.config.FallbackProperty +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.ConfigException +import org.jitsi.metaconfig.config import org.jitsi.xmpp.mucclient.MucClientConfiguration class XmppClientConnectionConfig { - class Config { - companion object { - class ClientConnectionConfigsProperty : FallbackProperty>( - legacyConfigAttributes { - name("org.jitsi.videobridge.xmpp.user") - readOnce() - retrievedAs() convertedBy { cfg -> - cfg.entries.map { it.toMucClientConfiguration() } - } - }, - newConfigAttributes { - name("videobridge.apis.xmpp-client.configs") - readOnce() - retrievedAs() convertedBy { cfg -> - cfg.entries.map { it.toMucClientConfiguration() } - } - } - ) - private val clientConnectionConfigs = ClientConnectionConfigsProperty() - - @JvmStatic - fun getClientConfigs(): List = - clientConnectionConfigs.value - } + val clientConfigs: List by config { + "org.jitsi.videobridge.xmpp.user." + .from(JitsiConfig.legacyConfig) + .convertFrom> { propsMap -> + MucClientConfiguration.loadFromMap(propsMap, "org.jitsi.videobridge.xmpp.user.", true) + .toList() + .takeIf { it.isNotEmpty() } ?: throw ConfigException.UnableToRetrieve.NotFound("no configs found") + } + "videobridge.apis.xmpp-client.configs".from(JitsiConfig.newConfig) + .convertFrom { cfg -> + cfg.entries + .map { it.toMucClientConfiguration() } + .filter { it.isComplete } + } } } diff --git a/jvb/src/test/java/org/jitsi/videobridge/BridgeShutdownTest.java b/jvb/src/test/java/org/jitsi/videobridge/BridgeShutdownTest.java index 0ba295fe20..00447684a6 100644 --- a/jvb/src/test/java/org/jitsi/videobridge/BridgeShutdownTest.java +++ b/jvb/src/test/java/org/jitsi/videobridge/BridgeShutdownTest.java @@ -15,8 +15,11 @@ */ package org.jitsi.videobridge; +import org.jitsi.*; import org.jitsi.config.*; import org.jitsi.meet.*; +import org.jitsi.metaconfig.*; +import org.jitsi.utils.collections.*; import org.jitsi.xmpp.extensions.colibri.*; import org.jivesoftware.smack.packet.*; import org.jivesoftware.smack.util.*; @@ -26,6 +29,7 @@ import org.xmlpull.v1.*; import java.io.*; +import java.util.*; import static org.junit.Assert.*; @@ -50,12 +54,11 @@ public class BridgeShutdownTest public static void setUp() throws InterruptedException { - // Allow focus JID - System.setProperty( - Videobridge.SHUTDOWN_ALLOWED_SOURCE_REGEXP_PNAME, - "focus.*"); - JitsiConfig.Companion.reload(); - + Properties props = new Properties(); + props.put(Videobridge.SHUTDOWN_ALLOWED_SOURCE_REGEXP_PNAME, "focus.*"); + ConfigSource config = new ConfigurationServiceConfigSource("test", new TestReadOnlyConfigurationService(props)); + JitsiConfig.Companion.setLegacyConfig(config); + osgiHandler.start(); bridge = osgiHandler.getService(Videobridge.class); diff --git a/jvb/src/test/kotlin/org/jitsi/ConfigTest.kt b/jvb/src/test/kotlin/org/jitsi/ConfigTest.kt new file mode 100644 index 0000000000..77a8c8f3c4 --- /dev/null +++ b/jvb/src/test/kotlin/org/jitsi/ConfigTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright @ 2018 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi + +import com.typesafe.config.ConfigFactory +import io.kotlintest.Spec +import io.kotlintest.specs.ShouldSpec +import org.jitsi.config.ConfigurationServiceConfigSource +import org.jitsi.config.JitsiConfig +import org.jitsi.config.TypesafeConfigSource +import java.io.StringReader + +/** + * A helper class for testing configuration properties + */ +abstract class ConfigTest : ShouldSpec() { + private val legacyService = TestReadOnlyConfigurationService() + private val legacyConfig = ConfigurationServiceConfigSource("legacy", legacyService) + + override fun beforeSpec(spec: Spec) { + super.beforeSpec(spec) + JitsiConfig.legacyConfig = legacyConfig + } + + fun withLegacyConfig(props: String) { + legacyService.props.load(StringReader(props)) + } + + fun withNewConfig(config: String) { + JitsiConfig.newConfig = TypesafeConfigSource("new", ConfigFactory.parseString(config)) + } +} diff --git a/jvb/src/test/kotlin/org/jitsi/TestReadOnlyConfigurationService.kt b/jvb/src/test/kotlin/org/jitsi/TestReadOnlyConfigurationService.kt new file mode 100644 index 0000000000..f8a6978ae6 --- /dev/null +++ b/jvb/src/test/kotlin/org/jitsi/TestReadOnlyConfigurationService.kt @@ -0,0 +1,30 @@ +/* + * Copyright @ 2018 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi + +import org.jitsi.config.AbstractReadOnlyConfigurationService +import java.util.Properties + +class TestReadOnlyConfigurationService( + override var properties: Properties = Properties() +) : AbstractReadOnlyConfigurationService() { + + val props: Properties + get() = properties + + override fun reloadConfiguration() {} +} diff --git a/jvb/src/test/kotlin/org/jitsi/videobridge/JitsiConfigTest.kt b/jvb/src/test/kotlin/org/jitsi/videobridge/JitsiConfigTest.kt deleted file mode 100644 index d89b737a5f..0000000000 --- a/jvb/src/test/kotlin/org/jitsi/videobridge/JitsiConfigTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright @ 2018 - present 8x8, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jitsi.videobridge - -import io.kotlintest.Spec -import org.jitsi.config.ConfigSourceWrapper -import org.jitsi.config.ConfigTest -import org.jitsi.config.JitsiConfigFactory -import org.jitsi.utils.config.ConfigSource - -/** - * This class is/should be a duplicate of the one in jicoco-kotlin. We can't - * move it to jicoco-test-kotlin because it would cause a circular maven - * dependency - */ -abstract class JitsiConfigTest : ConfigTest() { - - override fun withLegacyConfig(configSource: ConfigSource) { - legacyConfigWrapper.innerConfig = configSource - } - - override fun withNewConfig(configSource: ConfigSource) { - newConfigWrapper.innerConfig = configSource - } - - override fun beforeSpec(spec: Spec) { - super.beforeSpec(spec) - JitsiConfigFactory.legacyConfigSupplier = { legacyConfigWrapper } - JitsiConfigFactory.newConfigSupplier = { newConfigWrapper } - } - - companion object { - private val legacyConfigWrapper = ConfigSourceWrapper() - private val newConfigWrapper = ConfigSourceWrapper() - } -} diff --git a/jvb/src/test/kotlin/org/jitsi/videobridge/health/config/HealthConfigTest.kt b/jvb/src/test/kotlin/org/jitsi/videobridge/health/config/HealthConfigTest.kt index b6f913fc8d..7d2853601d 100644 --- a/jvb/src/test/kotlin/org/jitsi/videobridge/health/config/HealthConfigTest.kt +++ b/jvb/src/test/kotlin/org/jitsi/videobridge/health/config/HealthConfigTest.kt @@ -16,40 +16,47 @@ package org.jitsi.videobridge.health.config -import org.jitsi.config.BooleanMockConfigValueGenerator -import org.jitsi.config.DurationMockConfigValueGenerator -import org.jitsi.config.LongToDurationMockConfigValueGenerator -import org.jitsi.config.runBasicTests -import org.jitsi.videobridge.JitsiConfigTest +import io.kotlintest.IsolationMode +import io.kotlintest.Spec +import io.kotlintest.shouldBe +import io.kotlintest.specs.ShouldSpec +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.MapConfigSource +import java.time.Duration + +class HealthConfigTest : ShouldSpec() { + override fun isolationMode(): IsolationMode? = IsolationMode.InstancePerLeaf + + private val legacyConfig = MapConfigSource("legacy") + private val newConfig = MapConfigSource("new") + + override fun beforeSpec(spec: Spec) { + super.beforeSpec(spec) + JitsiConfig.legacyConfig = legacyConfig + JitsiConfig.newConfig = newConfig + } + + override fun afterSpec(spec: Spec) { + super.afterSpec(spec) + JitsiConfig.legacyConfig = JitsiConfig.SipCommunicatorPropsConfigSource + JitsiConfig.newConfig = JitsiConfig.TypesafeConfig + } -class HealthConfigTest : JitsiConfigTest() { init { "health interval" { - runBasicTests( - legacyConfigName = "org.jitsi.videobridge.health.INTERVAL", - legacyValueGenerator = LongToDurationMockConfigValueGenerator, - newConfigName = "videobridge.health.interval", - newConfigValueGenerator = DurationMockConfigValueGenerator, - propCreator = { HealthConfig.Config.Companion.HealthIntervalProperty() } - ) - } - "health timeout" { - runBasicTests( - legacyConfigName = "org.jitsi.videobridge.health.TIMEOUT", - legacyValueGenerator = LongToDurationMockConfigValueGenerator, - newConfigName = "videobridge.health.timeout", - newConfigValueGenerator = DurationMockConfigValueGenerator, - propCreator = { HealthConfig.Config.Companion.TimeoutProperty() } - ) - } - "sticky failures" { - runBasicTests( - legacyConfigName = "org.jitsi.videobridge.health.STICKY_FAILURES", - legacyValueGenerator = BooleanMockConfigValueGenerator(), - newConfigName = "videobridge.health.sticky-failures", - newConfigValueGenerator = BooleanMockConfigValueGenerator(), - propCreator = { HealthConfig.Config.Companion.StickyFailuresProperty() } - ) + "when legacy config and new config define a value" { + legacyConfig["org.jitsi.videobridge.health.INTERVAL"] = 1000L + newConfig["videobridge.health.interval"] = Duration.ofSeconds(5) + should("use the value from legacy config") { + HealthConfig().interval shouldBe Duration.ofSeconds(1) + } + } + "when only new config defines a value" { + newConfig["videobridge.health.interval"] = Duration.ofSeconds(5) + should("use the value from the new config") { + HealthConfig().interval shouldBe Duration.ofSeconds(5) + } + } } } } diff --git a/jvb/src/test/kotlin/org/jitsi/videobridge/octo/config/OctoConfigTest.kt b/jvb/src/test/kotlin/org/jitsi/videobridge/octo/config/OctoConfigTest.kt new file mode 100644 index 0000000000..15e9e9b96d --- /dev/null +++ b/jvb/src/test/kotlin/org/jitsi/videobridge/octo/config/OctoConfigTest.kt @@ -0,0 +1,91 @@ +package org.jitsi.videobridge.octo.config + +import io.kotlintest.IsolationMode +import io.kotlintest.shouldBe +import org.jitsi.ConfigTest + +internal class OctoConfigTest : ConfigTest() { + override fun isolationMode(): IsolationMode? = IsolationMode.InstancePerLeaf + + init { + "enabled" { + "when bind address and bind port are defined in legacy config" { + withLegacyConfig(legacyConfigWithBindAddressAndBindPort) + withNewConfig(newConfigOctoDisabled) + should("be true") { + OctoConfig().enabled shouldBe true + } + } + "when bind address is set in legacy config but not bind port" { + withLegacyConfig(legacyConfigWithBindAddressNoBindPort) + should("be false") { + OctoConfig().enabled shouldBe false + } + "and set as true in new config" { + withNewConfig(newConfigOctoEnabled) + should("be false") { + OctoConfig().enabled shouldBe false + } + } + } + "when bind port is set in legacy config but not bind address" { + withLegacyConfig(legacyConfigWithBindPortNoBindAddress) + withNewConfig(newConfigOctoEnabled) + should("be false") { + OctoConfig().enabled shouldBe false + } + } + "when enabled is set to true in new config and bind address/bind port are not defined in old config" { + withNewConfig(newConfigOctoEnabled) + should("be true") { + OctoConfig().enabled shouldBe true + } + } + } + "bindAddress" { + "when the value isn't set in legacy config" { + withNewConfig(newConfigBindAddress) + should("be the value from new config") { + OctoConfig().bindAddress shouldBe "127.0.0.1" + } + } + } + } +} + +private val legacyConfigWithBindAddressAndBindPort = """ + org.jitsi.videobridge.octo.BIND_ADDRESS=127.0.0.1 + org.jitsi.videobridge.octo.BIND_PORT=8080 +""".trimIndent() + +private val legacyConfigWithBindAddressNoBindPort = """ + org.jitsi.videobridge.octo.BIND_ADDRESS=127.0.0.1 +""".trimIndent() + +private val legacyConfigWithBindPortNoBindAddress = """ + org.jitsi.videobridge.octo.BIND_PORT=8080 +""".trimIndent() + +private val newConfigOctoDisabled = """ + videobridge { + octo { + enabled=false + } + } +""".trimIndent() + +private val newConfigOctoEnabled = """ + videobridge { + octo { + enabled=true + } + } +""".trimIndent() + +private val newConfigBindAddress = """ + videobridge { + octo { + bind-address = "127.0.0.1" + } + } +""".trimIndent() diff --git a/jvb/src/test/kotlin/org/jitsi/videobridge/stats/config/StatsManagerBundleActivatorConfigTest.kt b/jvb/src/test/kotlin/org/jitsi/videobridge/stats/config/StatsManagerBundleActivatorConfigTest.kt index d67788d2e6..d254358271 100644 --- a/jvb/src/test/kotlin/org/jitsi/videobridge/stats/config/StatsManagerBundleActivatorConfigTest.kt +++ b/jvb/src/test/kotlin/org/jitsi/videobridge/stats/config/StatsManagerBundleActivatorConfigTest.kt @@ -17,67 +17,80 @@ package org.jitsi.videobridge.stats.config import com.typesafe.config.ConfigFactory -import io.kotlintest.TestCase +import io.kotlintest.Spec import io.kotlintest.inspectors.forOne import io.kotlintest.matchers.collections.shouldHaveSize import io.kotlintest.seconds import io.kotlintest.shouldBe import io.kotlintest.shouldThrow +import io.kotlintest.specs.ShouldSpec +import org.jitsi.config.AbstractReadOnlyConfigurationService +import org.jitsi.config.ConfigurationServiceConfigSource +import org.jitsi.config.JitsiConfig import org.jitsi.config.TypesafeConfigSource -import org.jitsi.utils.config.ConfigSource -import org.jitsi.videobridge.JitsiConfigTest -import org.jitsi.videobridge.config.ConditionalPropertyConditionNotMetException -import org.jitsi.videobridge.testutils.resetSingleton +import org.jitsi.metaconfig.ConfigException +import org.jitsi.metaconfig.ConfigSource +import org.jitsi.metaconfig.MapConfigSource import java.util.Properties -import org.jitsi.videobridge.stats.config.StatsManagerBundleActivatorConfig.Config.Companion as Config +import kotlin.reflect.KType -class StatsManagerBundleActivatorConfigTest : JitsiConfigTest() { +internal class StatsManagerBundleActivatorConfigTest : ShouldSpec() { + private val legacyConfig = ConfigSourceWrapper(MapConfigSource("legacy")) + private val newConfig = ConfigSourceWrapper(MapConfigSource("new")) - override fun beforeTest(testCase: TestCase) { - resetSingletons() + override fun beforeSpec(spec: Spec) { + super.beforeSpec(spec) + JitsiConfig.legacyConfig = legacyConfig + JitsiConfig.newConfig = newConfig + } + + override fun afterSpec(spec: Spec) { + super.afterSpec(spec) + JitsiConfig.legacyConfig = JitsiConfig.SipCommunicatorPropsConfigSource + JitsiConfig.newConfig = JitsiConfig.TypesafeConfig } init { "When only new config contains stats transport config" { withLegacyConfig(legacyConfigNoStatsTransports) - "A stats transport config" { - "with a multiple, valid stats transport configured" { + "a stats transport config" { + "with multiple, valid stats transports configured" { withNewConfig(newConfigAllStatsTransports()) - should("parse the transport correctly") { - val cfg = Config.StatsTransportsProperty() + val cfg = StatsManagerBundleActivatorConfig() - cfg.value shouldHaveSize 2 - cfg.value.forOne { - it as StatsTransportConfig.MucStatsTransportConfig - it.interval shouldBe 5.seconds - } - cfg.value.forOne { - it as StatsTransportConfig.CallStatsIoStatsTransportConfig - it.interval shouldBe 5.seconds - } + cfg.transportConfigs shouldHaveSize 2 + cfg.transportConfigs.forOne { + it as StatsTransportConfig.MucStatsTransportConfig + it.interval shouldBe 5.seconds + } + cfg.transportConfigs.forOne { + it as StatsTransportConfig.CallStatsIoStatsTransportConfig + it.interval shouldBe 5.seconds } } "with an invalid stats transport configured" { withNewConfig(newConfigInvalidStatsTransports()) should("ignore the invalid config and parse the valid transport correctly") { - val cfg = Config.StatsTransportsProperty() + val cfg = StatsManagerBundleActivatorConfig() - cfg.value shouldHaveSize 1 - cfg.value.forOne { it as StatsTransportConfig.MucStatsTransportConfig } + cfg.transportConfigs shouldHaveSize 1 + cfg.transportConfigs.forOne { it as StatsTransportConfig.MucStatsTransportConfig } } } - "which have valid transports but stats are disabled" { - withNewConfig(newConfigAllStatsTransports(enabled = false)) + "which has valid transports but stats are disabled" { + withNewConfig(newConfigInvalidStatsTransports(enabled = false)) should("throw when trying to access the stats transports") { - val cfg = Config.StatsTransportsProperty() - shouldThrow { cfg.value } + val cfg = StatsManagerBundleActivatorConfig() + shouldThrow { + cfg.transportConfigs + } } } "which has a custom interval" { withNewConfig(newConfigOneStatsTransportCustomInterval()) should("reflect the custom interval") { - val cfg = Config.StatsTransportsProperty() - cfg.value.forOne { + val cfg = StatsManagerBundleActivatorConfig() + cfg.transportConfigs.forOne { it as StatsTransportConfig.MucStatsTransportConfig it.interval shouldBe 10.seconds } @@ -85,45 +98,42 @@ class StatsManagerBundleActivatorConfigTest : JitsiConfigTest() { } } } - "When old and new config contain stats transport config" { + "When old and new config contain stats transport configs" { withLegacyConfig(legacyConfigAllStatsTransports()) withNewConfig(newConfigOneStatsTransport()) should("use the values from the old config") { - val cfg = Config.StatsTransportsProperty() + val cfg = StatsManagerBundleActivatorConfig() - cfg.value shouldHaveSize 2 - cfg.value.forOne { it as StatsTransportConfig.MucStatsTransportConfig } - cfg.value.forOne { it as StatsTransportConfig.CallStatsIoStatsTransportConfig } + cfg.transportConfigs shouldHaveSize 2 + cfg.transportConfigs.forOne { it as StatsTransportConfig.MucStatsTransportConfig } + cfg.transportConfigs.forOne { it as StatsTransportConfig.CallStatsIoStatsTransportConfig } } "and it's disabled in old config but enabled in new config" { withLegacyConfig(legacyConfigStatsEnabled(enabled = false)) withNewConfig(newConfigOneStatsTransport()) - should("throw when trying to access the stats transports") { - val cfg = Config.StatsTransportsProperty() - shouldThrow { cfg.value } + should("throw when trying to access the stats transports field") { + val cfg = StatsManagerBundleActivatorConfig() + shouldThrow { cfg.transportConfigs } } } } } - private fun createConfigFrom(configString: String): ConfigSource = - TypesafeConfigSource("testConfig") { ConfigFactory.parseString(configString) } - - private fun createConfigFrom(configProps: Properties): ConfigSource = - TypesafeConfigSource("testConfig") { ConfigFactory.parseProperties(configProps) } - - private fun resetSingletons() { - resetSingleton( - "enabledProp", - Config - ) - resetSingleton( - "statsIntervalProp", - Config - ) + private fun withNewConfig(config: ConfigSource) { + newConfig.innerConfigSource = config } + private fun withLegacyConfig(config: ConfigSource) { + legacyConfig.innerConfigSource = config + } +} - private fun newConfigAllStatsTransports(enabled: Boolean = true) = createConfigFrom(""" +private fun createConfigFrom(configString: String): ConfigSource = + TypesafeConfigSource("testConfig", ConfigFactory.parseString(configString)) + +private fun createConfigFrom(configProps: Properties): ConfigSource = + ConfigurationServiceConfigSource("legacyConfig", TestReadOnlyConfigurationService(configProps)) + +private fun newConfigAllStatsTransports(enabled: Boolean = true) = createConfigFrom(""" videobridge { stats { interval=5 seconds @@ -139,8 +149,8 @@ class StatsManagerBundleActivatorConfigTest : JitsiConfigTest() { } } """.trimIndent() - ) - private fun newConfigOneStatsTransport(enabled: Boolean = true) = createConfigFrom(""" +) +private fun newConfigOneStatsTransport(enabled: Boolean = true) = createConfigFrom(""" videobridge { stats { enabled=$enabled @@ -153,8 +163,8 @@ class StatsManagerBundleActivatorConfigTest : JitsiConfigTest() { } } """.trimIndent() - ) - private fun newConfigOneStatsTransportCustomInterval(enabled: Boolean = true) = createConfigFrom(""" +) +private fun newConfigOneStatsTransportCustomInterval(enabled: Boolean = true) = createConfigFrom(""" videobridge { stats { enabled=$enabled @@ -168,8 +178,8 @@ class StatsManagerBundleActivatorConfigTest : JitsiConfigTest() { } } """.trimIndent() - ) - private fun newConfigInvalidStatsTransports(enabled: Boolean = true) = createConfigFrom(""" +) +private fun newConfigInvalidStatsTransports(enabled: Boolean = true) = createConfigFrom(""" videobridge { stats { interval=5 seconds @@ -185,17 +195,36 @@ class StatsManagerBundleActivatorConfigTest : JitsiConfigTest() { } } """.trimIndent() - ) - private val legacyConfigNoStatsTransports = createConfigFrom(Properties().apply { - setProperty("org.jitsi.videobridge.some_other_prop=", "42") - }) - - private fun legacyConfigStatsEnabled(enabled: Boolean = true) = createConfigFrom(Properties().apply { - setProperty("org.jitsi.videobridge.ENABLE_STATISTICS", "$enabled") - }) - - private fun legacyConfigAllStatsTransports(enabled: Boolean = true) = createConfigFrom(Properties().apply { - setProperty("org.jitsi.videobridge.ENABLE_STATISTICS", "$enabled") - setProperty("org.jitsi.videobridge.STATISTICS_TRANSPORT", "muc,callstats.io") - }) +) +private val legacyConfigNoStatsTransports = createConfigFrom(Properties().apply { + setProperty("org.jitsi.videobridge.some_other_prop=", "42") +}) + +private fun legacyConfigStatsEnabled(enabled: Boolean = true) = createConfigFrom(Properties().apply { + setProperty("org.jitsi.videobridge.ENABLE_STATISTICS", "$enabled") +}) + +private fun legacyConfigAllStatsTransports(enabled: Boolean = true) = createConfigFrom(Properties().apply { + setProperty("org.jitsi.videobridge.ENABLE_STATISTICS", "$enabled") + setProperty("org.jitsi.videobridge.STATISTICS_TRANSPORT", "muc,callstats.io") +}) + +// TODO(brian): ideally move to jicoco-test-kotlin. See note below. +private class ConfigSourceWrapper( + var innerConfigSource: ConfigSource +) : ConfigSource { + override val name: String + get() = innerConfigSource.name + + override fun getterFor(type: KType): (String) -> Any = innerConfigSource.getterFor(type) +} + +// TODO(brian): ideally move to jicoco-test-kotlin, but it depends on jicoco (where +// AbstractReadOnlyConfigurationService is defined) which already depends on jicoco-test-kotlin. +// Once old config is removed, I think we can break the jicoco -> jicoco-test-kotlin dependency. +private class TestReadOnlyConfigurationService( + override var properties: Properties +) : AbstractReadOnlyConfigurationService() { + + override fun reloadConfiguration() { } } diff --git a/jvb/src/test/kotlin/org/jitsi/videobridge/websocket/config/WebsocketServiceConfigTest.kt b/jvb/src/test/kotlin/org/jitsi/videobridge/websocket/config/WebsocketServiceConfigTest.kt index 647782abcc..98079a15c9 100644 --- a/jvb/src/test/kotlin/org/jitsi/videobridge/websocket/config/WebsocketServiceConfigTest.kt +++ b/jvb/src/test/kotlin/org/jitsi/videobridge/websocket/config/WebsocketServiceConfigTest.kt @@ -16,134 +16,75 @@ package org.jitsi.videobridge.websocket.config +import io.kotlintest.IsolationMode +import io.kotlintest.Spec +import io.kotlintest.TestCase import io.kotlintest.shouldBe import io.kotlintest.shouldThrow -import org.jitsi.config.BooleanMockConfigValueGenerator -import org.jitsi.config.MockConfigSource -import org.jitsi.config.MockConfigValue -import org.jitsi.config.MockConfigValueGenerator -import org.jitsi.config.runBasicTests -import org.jitsi.videobridge.JitsiConfigTest -import org.jitsi.videobridge.config.ConditionalPropertyConditionNotMetException -import org.jitsi.videobridge.testutils.resetSingleton +import io.kotlintest.specs.ShouldSpec +import org.jitsi.config.JitsiConfig +import org.jitsi.metaconfig.ConfigException +import org.jitsi.metaconfig.MapConfigSource -class WebsocketServiceConfigTest : JitsiConfigTest() { - // By default install config sources which can be modified later - private val legacyConfig = MockConfigSource("legacy", mapOf()) - private val newConfig = MockConfigSource("new", mapOf()) +class WebsocketServiceConfigTest : ShouldSpec() { + override fun isolationMode(): IsolationMode? = IsolationMode.InstancePerLeaf + + private val newConfig = MapConfigSource("new") + private val legacyConfig = MapConfigSource("legacy") + private lateinit var config: WebsocketServiceConfig + + override fun beforeSpec(spec: Spec) { + super.beforeSpec(spec) + JitsiConfig.legacyConfig = legacyConfig + JitsiConfig.newConfig = newConfig + } + + override fun beforeTest(testCase: TestCase) { + super.beforeTest(testCase) + config = WebsocketServiceConfig() + } + + override fun afterSpec(spec: Spec) { + super.afterSpec(spec) + JitsiConfig.legacyConfig = JitsiConfig.SipCommunicatorPropsConfigSource + JitsiConfig.newConfig = JitsiConfig.TypesafeConfig + } init { - withLegacyConfig(legacyConfig) - withNewConfig(newConfig) - "enabled" { - runBasicTests( - legacyConfigName = "org.jitsi.videobridge.rest.COLIBRI_WS_DISABLE", - legacyValueGenerator = InvertedBooleanMockConfigValueGenerator(), - newConfigName = "videobridge.websockets.enabled", - newConfigValueGenerator = BooleanMockConfigValueGenerator(), - propCreator = { WebsocketServiceConfig.Config.Companion.EnabledProperty() } - ) - } - "domain" { - val propCreator = { WebsocketServiceConfig.Config.Companion.DomainProperty() } - "when websockets are disabled" { - disableWebsockets(legacyConfig) - val prop = propCreator() - shouldThrow { - prop.value - } - } - "when websockets are enabled" { - enableWebsockets(legacyConfig) - "and websocket domain is set in old config" { - legacyConfig["org.jitsi.videobridge.rest.COLIBRI_WS_DOMAIN"] = "domain" - val prop = propCreator() - prop.value shouldBe "domain" - } - "and websocket domain is set in new config" { - newConfig["videobridge.websockets.domain"] = "new_domain" - val prop = propCreator() - prop.value shouldBe "new_domain" - } - } - } - "tls" { - val propCreator = { WebsocketServiceConfig.Config.Companion.TlsProperty() } - "when websockets are disabled" { - disableWebsockets(legacyConfig) - // Even if config is set - legacyConfig["org.jitsi.videobridge.rest.COLIBRI_WS_TLS"] = true - val prop = propCreator() - shouldThrow { - val ignore = prop.value - ignore + "when websockets are disabled" { + newConfig["videobridge.websockets.enabled"] = false + "accessing domain should throw" { + shouldThrow { + config.domain } } - "when websockets are enabled" { - enableWebsockets(legacyConfig) - "and websocket domain is set in old config" { - legacyConfig["org.jitsi.videobridge.rest.COLIBRI_WS_TLS"] = true - val prop = propCreator() - prop.value shouldBe true - } - "and websocket domain is set in new config" { - newConfig["videobridge.websockets.tls"] = false - val prop = propCreator() - prop.value shouldBe false + "accessing useTls should throw" { + shouldThrow { + config.useTls } } } - "server id" { - val propCreator = { WebsocketServiceConfig.Config.Companion.ServerIdProperty() } - "when websockets are disabled" { - disableWebsockets(legacyConfig) - // Even if config is set - legacyConfig["org.jitsi.videobridge.rest.COLIBRI_WS_SERVER_ID"] = "server_id" - val prop = propCreator() - shouldThrow { - prop.value + "when websockets are enabled" { + newConfig["videobridge.websockets.enabled"] = true + "accessing domain" { + newConfig["videobridge.websockets.domain"] = "new_domain" + should("get the right value") { + config.domain shouldBe "new_domain" } } - "when websockets are enabled" { - enableWebsockets(legacyConfig) - "and websocket domain is set in old config" { - legacyConfig["org.jitsi.videobridge.rest.COLIBRI_WS_SERVER_ID"] = "server_id" - val prop = propCreator() - prop.value shouldBe "server_id" + "accessing useTls" { + "when no value has been set" { + should("return null") { + config.useTls shouldBe null + } } - "and websocket domain is set in new config" { - newConfig["videobridge.websockets.server-id"] = "new_server_id" - val prop = propCreator() - prop.value shouldBe "new_server_id" + "when a value has been set" { + newConfig["videobridge.websockets.tls"] = true + should("get the right value xx") { + config.useTls shouldBe true + } } } } } - - private fun enableWebsockets(legacyConfig: MockConfigSource) { - legacyConfig["org.jitsi.videobridge.rest.COLIBRI_WS_DISABLE"] = false - resetEnabledProperty() - } - - private fun disableWebsockets(legacyConfig: MockConfigSource) { - legacyConfig["org.jitsi.videobridge.rest.COLIBRI_WS_DISABLE"] = true - resetEnabledProperty() - } - - private fun resetEnabledProperty() { - resetSingleton( - "enabledProp", - WebsocketServiceConfig.Config.Companion - ) - } - - private class InvertedBooleanMockConfigValueGenerator : MockConfigValueGenerator { - private var currValue: Boolean = true - - override fun gen(): MockConfigValue { - return MockConfigValue(currValue, !currValue).also { - currValue = !currValue - } - } - } } diff --git a/jvb/src/test/kotlin/org/jitsi/videobridge/xmpp/config/XmppClientConnectionConfigTest.kt b/jvb/src/test/kotlin/org/jitsi/videobridge/xmpp/config/XmppClientConnectionConfigTest.kt new file mode 100644 index 0000000000..231f372c9a --- /dev/null +++ b/jvb/src/test/kotlin/org/jitsi/videobridge/xmpp/config/XmppClientConnectionConfigTest.kt @@ -0,0 +1,177 @@ +/* + * Copyright @ 2018 - present 8x8, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jitsi.videobridge.xmpp.config + +import io.kotlintest.IsolationMode +import io.kotlintest.matchers.collections.shouldContainExactly +import io.kotlintest.matchers.collections.shouldHaveSize +import io.kotlintest.shouldBe +import org.jitsi.ConfigTest + +internal class XmppClientConnectionConfigTest : ConfigTest() { + override fun isolationMode(): IsolationMode? = IsolationMode.InstancePerLeaf + + init { + "Connection configs" { + "when defined in the legacy config" { + withLegacyConfig(legacyConfigSingleXmppConnection) + should("parse things correctly") { + val configs = XmppClientConnectionConfig().clientConfigs + configs shouldHaveSize 1 + with(configs[0]) { + this.id shouldBe "shard" + this.mucNickname shouldBe "test_nick" + this.disableCertificateVerification shouldBe true + this.domain shouldBe "auth.some.domain.net" + this.hostname shouldBe "localhost" + this.username shouldBe "jvb" + this.password shouldBe "s3cr3t" + this.mucJids shouldContainExactly listOf("JvbBrewery@internal.some.domain.net") + this.iqHandlerMode shouldBe "sync" + } + } + } + "when multiple are defined in legacy and one is incomplete" { + withLegacyConfig(legacyConfigOneCompleteConnectionOneIncomplete) + should("only parse the complete one") { + val configs = XmppClientConnectionConfig().clientConfigs + configs shouldHaveSize 1 + with(configs[0]) { + this.id shouldBe "shard" + this.mucNickname shouldBe "test_nick" + this.disableCertificateVerification shouldBe true + this.domain shouldBe "auth.some.domain.net" + this.hostname shouldBe "localhost" + this.username shouldBe "jvb" + this.password shouldBe "s3cr3t" + this.mucJids shouldContainExactly listOf("JvbBrewery@internal.some.domain.net") + this.iqHandlerMode shouldBe "sync" + } + } + } + "when defined in new config" { + withNewConfig(newConfigSingleXmppConnection) + should("parse things correctly") { + val configs = XmppClientConnectionConfig().clientConfigs + configs shouldHaveSize 1 + with(configs[0]) { + this.id shouldBe "shard" + this.mucNickname shouldBe "test_nick" + this.disableCertificateVerification shouldBe true + this.domain shouldBe "auth.some.domain.net" + this.hostname shouldBe "localhost" + this.username shouldBe "jvb" + this.password shouldBe "s3cr3t" + this.mucJids shouldContainExactly listOf("JvbBrewery@internal.some.domain.net") + this.iqHandlerMode shouldBe "sync" + } + } + } + "when defined in new config with some incomplete" { + withNewConfig(newConfigOneCompleteConnectionOneIncomplete) + should("parse things correctly") { + val configs = XmppClientConnectionConfig().clientConfigs + configs shouldHaveSize 1 + with(configs[0]) { + this.id shouldBe "shard" + this.mucNickname shouldBe "test_nick" + this.disableCertificateVerification shouldBe true + this.domain shouldBe "auth.some.domain.net" + this.hostname shouldBe "localhost" + this.username shouldBe "jvb" + this.password shouldBe "s3cr3t" + this.mucJids shouldContainExactly listOf("JvbBrewery@internal.some.domain.net") + this.iqHandlerMode shouldBe "sync" + } + } + } + } + } +} + +private val legacyConfigSingleXmppConnection = """ + org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.some.domain.net + org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.some.domain.net + org.jitsi.videobridge.xmpp.user.shard.MUC=JvbBrewery@internal.some.domain.net + org.jitsi.videobridge.xmpp.user.shard.DISABLE_CERTIFICATE_VERIFICATION=true + org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=localhost + org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb + org.jitsi.videobridge.xmpp.user.shard.PASSWORD=s3cr3t + org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME=test_nick + org.jitsi.videobridge.xmpp.user.shard.IQ_HANDLER_MODE=sync +""".trimIndent() + +private val legacyConfigOneCompleteConnectionOneIncomplete = """ + org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.some.domain.net + org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.some.domain.net + org.jitsi.videobridge.xmpp.user.shard.MUC=JvbBrewery@internal.some.domain.net + org.jitsi.videobridge.xmpp.user.shard.DISABLE_CERTIFICATE_VERIFICATION=true + org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=localhost + org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb + org.jitsi.videobridge.xmpp.user.shard.PASSWORD=s3cr3t + org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME=test_nick + org.jitsi.videobridge.xmpp.user.shard.IQ_HANDLER_MODE=sync + + org.jitsi.videobridge.xmpp.user.incomlpete.USERNAME=jvb +""".trimIndent() + +private val newConfigSingleXmppConnection = """ + videobridge { + apis { + xmpp-client { + configs { + shard { + DOMAIN=auth.some.domain.net + MUC_JIDS="JvbBrewery@internal.some.domain.net" + MUC="JvbBrewery@internal.some.domain.net" + DISABLE_CERTIFICATE_VERIFICATION=true + HOSTNAME="localhost" + USERNAME="jvb" + PASSWORD="s3cr3t" + MUC_NICKNAME="test_nick" + IQ_HANDLER_MODE="sync" + } + } + } + } + } +""".trimIndent() + +private val newConfigOneCompleteConnectionOneIncomplete = """ + videobridge { + apis { + xmpp-client { + configs { + shard { + DOMAIN=auth.some.domain.net + MUC_JIDS="JvbBrewery@internal.some.domain.net" + MUC="JvbBrewery@internal.some.domain.net" + DISABLE_CERTIFICATE_VERIFICATION=true + HOSTNAME="localhost" + USERNAME="jvb" + PASSWORD="s3cr3t" + MUC_NICKNAME="test_nick" + IQ_HANDLER_MODE="sync" + } + incomplete { + DOMAIN="incomplete" + } + } + } + } + } +""".trimIndent() diff --git a/pom.xml b/pom.xml index 105f4d1761..60ec095b8e 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ 1.3.71 UTF-8 4.2.4-47d17fc - 1.1-36-gecd3e61 + 1.1-37-g95fd201 1.0-55-g21baf6e 3.2.2 4.0.1 @@ -61,6 +61,11 @@ jitsi-utils-kotlin ${jitsi.utils.version} + + ${project.groupId} + jitsi-metaconfig + 1.0 + ${project.groupId} ice4j @@ -74,7 +79,7 @@ ${project.groupId} jitsi-media-transform - 1.0-164-g031788f + 1.0-166-g5924c16 ${project.groupId} @@ -88,5 +93,11 @@ + + + jitpack.io + https://jitpack.io + +