From b2554eb85cf960ba3721d17836fa789d4c508f8e Mon Sep 17 00:00:00 2001 From: Luca Kellermann Date: Sat, 2 Nov 2024 04:46:45 +0100 Subject: [PATCH] Minimize deprecation code --- voice/src/main/kotlin/VoiceConnection.kt | 34 ++++---- .../src/main/kotlin/streams/DefaultStreams.kt | 58 ++++++------- voice/src/main/kotlin/udp/AudioFrameSender.kt | 10 +-- .../main/kotlin/udp/AudioPacketProvider.kt | 27 +++---- .../kotlin/udp/DefaultAudioFrameSender.kt | 81 +++++++++---------- 5 files changed, 92 insertions(+), 118 deletions(-) diff --git a/voice/src/main/kotlin/VoiceConnection.kt b/voice/src/main/kotlin/VoiceConnection.kt index af342ab13f3..617e1db9649 100644 --- a/voice/src/main/kotlin/VoiceConnection.kt +++ b/voice/src/main/kotlin/VoiceConnection.kt @@ -56,17 +56,6 @@ public class VoiceConnection internal constructor( connectionDetachDuration: Duration, internal val strategy: @Suppress("DEPRECATION") NonceStrategy?, ) { - @Suppress("DeprecatedCallableAddReplaceWith") - @Deprecated( - "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. A 'VoiceConnection' instance " + - "can be created without a 'nonceStrategy' in which case this property throws an " + - "'UnsupportedOperationException'. $XSalsa20_PROPERTY_DEPRECATION", - level = DeprecationLevel.WARNING, - ) - public val nonceStrategy: @Suppress("DEPRECATION") NonceStrategy - get() = strategy - ?: throw UnsupportedOperationException("This VoiceConnection instance was created without a nonceStrategy.") - @Deprecated( "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. Construct a 'VoiceConnection' " + "instance without a 'nonceStrategy' instead. $XSalsa20_CONSTRUCTOR_DEPRECATION", @@ -83,10 +72,8 @@ public class VoiceConnection internal constructor( frameInterceptor: FrameInterceptor, frameSender: AudioFrameSender, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy, connectionDetachDuration: Duration, ) : this( - data = data, gateway = gateway, voiceGateway = voiceGateway, socket = socket, - voiceGatewayConfiguration = voiceGatewayConfiguration, streams = streams, audioProvider = audioProvider, - frameInterceptor = frameInterceptor, frameSender = frameSender, - connectionDetachDuration = connectionDetachDuration, strategy = nonceStrategy, + data, gateway, voiceGateway, socket, voiceGatewayConfiguration, streams, audioProvider, frameInterceptor, + frameSender, connectionDetachDuration, nonceStrategy, ) public constructor( @@ -94,12 +81,21 @@ public class VoiceConnection internal constructor( voiceGatewayConfiguration: VoiceGatewayConfiguration, streams: Streams, audioProvider: AudioProvider, frameInterceptor: FrameInterceptor, frameSender: AudioFrameSender, connectionDetachDuration: Duration, ) : this( - data = data, gateway = gateway, voiceGateway = voiceGateway, socket = socket, - voiceGatewayConfiguration = voiceGatewayConfiguration, streams = streams, audioProvider = audioProvider, - frameInterceptor = frameInterceptor, frameSender = frameSender, - connectionDetachDuration = connectionDetachDuration, strategy = null, + data, gateway, voiceGateway, socket, voiceGatewayConfiguration, streams, audioProvider, frameInterceptor, + frameSender, connectionDetachDuration, strategy = null, ) + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated( + "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. A 'VoiceConnection' instance " + + "can be created without a 'nonceStrategy' in which case this property throws an " + + "'UnsupportedOperationException'. $XSalsa20_PROPERTY_DEPRECATION", + level = DeprecationLevel.WARNING, + ) + public val nonceStrategy: @Suppress("DEPRECATION") NonceStrategy + get() = strategy + ?: throw UnsupportedOperationException("This VoiceConnection instance was created without a nonceStrategy.") + public val scope: CoroutineScope = CoroutineScope(SupervisorJob() + CoroutineName("kord-voice-connection[${data.guildId.value}]")) diff --git a/voice/src/main/kotlin/streams/DefaultStreams.kt b/voice/src/main/kotlin/streams/DefaultStreams.kt index 6eb12305a22..fb428fc32ab 100644 --- a/voice/src/main/kotlin/streams/DefaultStreams.kt +++ b/voice/src/main/kotlin/streams/DefaultStreams.kt @@ -31,17 +31,10 @@ private val defaultStreamsLogger = KotlinLogging.logger { } @KordVoice public class DefaultStreams internal constructor( - gateway: VoiceGateway, - strategy: @Suppress("DEPRECATION") NonceStrategy?, - udpSocket: VoiceUdpSocket, + private val voiceGateway: VoiceGateway, + private val nonceStrategy: @Suppress("DEPRECATION") NonceStrategy?, + private val udp: VoiceUdpSocket, ) : Streams { - private val voiceGateway = gateway - private val udp = udpSocket - private val nonceStrategy = strategy - - public constructor(voiceGateway: VoiceGateway, udp: VoiceUdpSocket) : - this(gateway = voiceGateway, strategy = null, udpSocket = udp) - @Deprecated( "The 'nonceStrategy' parameter is only used for XSalsa20 Poly1305 encryption. Construct a 'DefaultStreams' " + "instance without a 'NonceStrategy' instead. $XSalsa20_CONSTRUCTOR_DEPRECATION", @@ -50,15 +43,14 @@ public class DefaultStreams internal constructor( ) public constructor( voiceGateway: VoiceGateway, udp: VoiceUdpSocket, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy, - ) : this(gateway = voiceGateway, strategy = nonceStrategy, udpSocket = udp) + ) : this(voiceGateway, nonceStrategy, udp) + + public constructor(voiceGateway: VoiceGateway, udp: VoiceUdpSocket) : this(voiceGateway, nonceStrategy = null, udp) internal fun CoroutineScope.listenForIncoming( - udp: VoiceUdpSocket, - key: ByteArray, - server: SocketAddress, + key: ByteArray, server: SocketAddress, @Suppress("LocalVariableName") _incomingAudioPackets: MutableSharedFlow, - nonceStrategy: @Suppress("DEPRECATION") NonceStrategy, - emitVoicePacket: suspend (RTPPacket) -> Unit, + nonceStrategy: @Suppress("DEPRECATION") NonceStrategy, emitVoicePacket: suspend (RTPPacket) -> Unit, ) { udp.incoming .filter { it.address == server } @@ -92,22 +84,6 @@ public class DefaultStreams internal constructor( }.launchIn(this) } - override suspend fun listen(key: ByteArray, server: SocketAddress, encryptionMode: EncryptionMode) { - val decryptionDelegate = @Suppress("DEPRECATION") when (encryptionMode) { - EncryptionMode.AeadAes256GcmRtpSize -> NewDecryptionDelegate(AeadAes256GcmRtpSizeVoicePacketDecryptor(key)) - EncryptionMode.AeadXChaCha20Poly1305RtpSize -> - NewDecryptionDelegate(AeadXChaCha20Poly1305RtpSizeVoicePacketDecryptor(key)) - EncryptionMode.XSalsa20Poly1305 -> - LegacyDecryptionDelegate(key, this, nonceStrategy as? NormalNonceStrategy ?: NormalNonceStrategy()) - EncryptionMode.XSalsa20Poly1305Lite -> - LegacyDecryptionDelegate(key, this, nonceStrategy as? LiteNonceStrategy ?: LiteNonceStrategy()) - EncryptionMode.XSalsa20Poly1305Suffix -> - LegacyDecryptionDelegate(key, this, nonceStrategy as? SuffixNonceStrategy ?: SuffixNonceStrategy()) - is EncryptionMode.Unknown -> throw UnsupportedOperationException("Unknown encryption mode $encryptionMode") - } - listen(decryptionDelegate, server) - } - @Deprecated( "This functions always uses XSalsa20 Poly1305 encryption. Pass an explicit 'EncryptionMode' instead. A " + "'DefaultStreams' instance can be created without a 'NonceStrategy' in which case this function throws " + @@ -124,6 +100,22 @@ public class DefaultStreams internal constructor( listen(LegacyDecryptionDelegate(key, this, strategy), server) } + override suspend fun listen(key: ByteArray, server: SocketAddress, encryptionMode: EncryptionMode) { + val decryptionDelegate = @Suppress("DEPRECATION") when (encryptionMode) { + EncryptionMode.AeadAes256GcmRtpSize -> NewDecryptionDelegate(AeadAes256GcmRtpSizeVoicePacketDecryptor(key)) + EncryptionMode.AeadXChaCha20Poly1305RtpSize -> + NewDecryptionDelegate(AeadXChaCha20Poly1305RtpSizeVoicePacketDecryptor(key)) + EncryptionMode.XSalsa20Poly1305 -> + LegacyDecryptionDelegate(key, this, nonceStrategy as? NormalNonceStrategy ?: NormalNonceStrategy()) + EncryptionMode.XSalsa20Poly1305Lite -> + LegacyDecryptionDelegate(key, this, nonceStrategy as? LiteNonceStrategy ?: LiteNonceStrategy()) + EncryptionMode.XSalsa20Poly1305Suffix -> + LegacyDecryptionDelegate(key, this, nonceStrategy as? SuffixNonceStrategy ?: SuffixNonceStrategy()) + is EncryptionMode.Unknown -> throw UnsupportedOperationException("Unknown encryption mode $encryptionMode") + } + listen(decryptionDelegate, server) + } + private suspend fun listen(delegate: DecryptionDelegate, server: SocketAddress): Unit = coroutineScope { delegate.listenForIncoming(scope = this, udp, server, _incomingAudioPackets, _incomingVoicePackets) listenForUserFrames() @@ -223,7 +215,7 @@ private class LegacyDecryptionDelegate( audioPackets: MutableSharedFlow, voicePackets: MutableSharedFlow, ) = with(streams) { - scope.listenForIncoming(udp, key, server, audioPackets, nonceStrategy) { rtpPacket -> + scope.listenForIncoming(key, server, audioPackets, nonceStrategy) { rtpPacket -> if (voicePackets.subscriptionCount.value > 0) { voicePackets.emit( @OptIn(ExperimentalUnsignedTypes::class) diff --git a/voice/src/main/kotlin/udp/AudioFrameSender.kt b/voice/src/main/kotlin/udp/AudioFrameSender.kt index a61fb224625..e31bd032341 100644 --- a/voice/src/main/kotlin/udp/AudioFrameSender.kt +++ b/voice/src/main/kotlin/udp/AudioFrameSender.kt @@ -24,8 +24,8 @@ public data class AudioFrameSenderConfiguration( public constructor( server: SocketAddress, ssrc: UInt, key: ByteArray, interceptorConfiguration: FrameInterceptorConfiguration, ) : this( - server = server, ssrc = ssrc, key = key, interceptorConfiguration = interceptorConfiguration, - encryptionMode = EncryptionMode.from("AudioFrameSenderConfiguration.encryptionMode placeholder"), + server, ssrc, key, interceptorConfiguration, + EncryptionMode.from("AudioFrameSenderConfiguration.encryptionMode placeholder"), ) @Deprecated( @@ -35,10 +35,8 @@ public data class AudioFrameSenderConfiguration( public fun copy( server: SocketAddress = this.server, ssrc: UInt = this.ssrc, key: ByteArray = this.key, interceptorConfiguration: FrameInterceptorConfiguration = this.interceptorConfiguration, - ): AudioFrameSenderConfiguration = AudioFrameSenderConfiguration( - server = server, ssrc = ssrc, key = key, interceptorConfiguration = interceptorConfiguration, - encryptionMode = this.encryptionMode, - ) + ): AudioFrameSenderConfiguration = + AudioFrameSenderConfiguration(server, ssrc, key, interceptorConfiguration, encryptionMode) } @KordVoice diff --git a/voice/src/main/kotlin/udp/AudioPacketProvider.kt b/voice/src/main/kotlin/udp/AudioPacketProvider.kt index 0b77aa50303..9c8ef56504b 100644 --- a/voice/src/main/kotlin/udp/AudioPacketProvider.kt +++ b/voice/src/main/kotlin/udp/AudioPacketProvider.kt @@ -18,6 +18,15 @@ public abstract class AudioPacketProvider internal constructor( private val strategy: @Suppress("DEPRECATION") NonceStrategy?, public val key: ByteArray, ) { + @Deprecated( + "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. Construct an " + + "'AudioPacketProvider' instance without a 'nonceStrategy' instead. $XSalsa20_CONSTRUCTOR_DEPRECATION", + ReplaceWith("AudioPacketProvider(key)", imports = ["dev.kord.voice.udp.AudioPacketProvider"]), + DeprecationLevel.WARNING, + ) + public constructor(key: ByteArray, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy) : this(nonceStrategy, key) + public constructor(key: ByteArray) : this(strategy = null, key) + @Deprecated( "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. An 'AudioPacketProvider' " + "instance can be created without a 'nonceStrategy' in which case this property throws an " + @@ -29,17 +38,6 @@ public abstract class AudioPacketProvider internal constructor( "This AudioPacketProvider instance was created without a nonceStrategy." ) - @Deprecated( - "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. Construct an " + - "'AudioPacketProvider' instance without a 'nonceStrategy' instead. $XSalsa20_CONSTRUCTOR_DEPRECATION", - ReplaceWith("AudioPacketProvider(key)", imports = ["dev.kord.voice.udp.AudioPacketProvider"]), - DeprecationLevel.WARNING, - ) - public constructor(key: ByteArray, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy) : - this(strategy = nonceStrategy, key = key) - - public constructor(key: ByteArray) : this(strategy = null, key = key) - public abstract fun provide(sequence: UShort, timestamp: UInt, ssrc: UInt, data: ByteArray): ByteArrayView } @@ -47,7 +45,7 @@ private class CouldNotEncryptDataException(data: ByteArray) : RuntimeException("Couldn't encrypt the following data: [${data.joinToString(", ")}]") public class DefaultAudioPacketProvider internal constructor( - key: ByteArray, encryptionMode: EncryptionMode?, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy?, + key: ByteArray, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy?, encryptionMode: EncryptionMode?, ) : AudioPacketProvider(nonceStrategy, key) { @Deprecated( "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. Construct a " + @@ -60,10 +58,9 @@ public class DefaultAudioPacketProvider internal constructor( DeprecationLevel.WARNING, ) public constructor(key: ByteArray, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy) : - this(key = key, encryptionMode = null, nonceStrategy = nonceStrategy) + this(key, nonceStrategy, encryptionMode = null) - public constructor(key: ByteArray, encryptionMode: EncryptionMode) : - this(key = key, encryptionMode = encryptionMode, nonceStrategy = null) + public constructor(key: ByteArray, encryptionMode: EncryptionMode) : this(key, nonceStrategy = null, encryptionMode) private val delegate = if (nonceStrategy != null) { LegacyProviderDelegate(key, nonceStrategy) diff --git a/voice/src/main/kotlin/udp/DefaultAudioFrameSender.kt b/voice/src/main/kotlin/udp/DefaultAudioFrameSender.kt index ea9b9e709e2..18030c144ee 100644 --- a/voice/src/main/kotlin/udp/DefaultAudioFrameSender.kt +++ b/voice/src/main/kotlin/udp/DefaultAudioFrameSender.kt @@ -23,40 +23,6 @@ public class DefaultAudioFrameSenderData private constructor(private val wrapper val nonceStrategy: @Suppress("DEPRECATION") NonceStrategy?, ) - internal val strategy get() = wrapper.nonceStrategy - - public constructor(udp: VoiceUdpSocket, interceptor: FrameInterceptor, provider: AudioProvider) : - this(Wrapper(udp = udp, interceptor = interceptor, provider = provider, nonceStrategy = null)) - - public val udp: VoiceUdpSocket get() = wrapper.udp - public val interceptor: FrameInterceptor get() = wrapper.interceptor - public val provider: AudioProvider get() = wrapper.provider - public operator fun component1(): VoiceUdpSocket = wrapper.udp - public operator fun component2(): FrameInterceptor = wrapper.interceptor - public operator fun component3(): AudioProvider = wrapper.provider - override fun equals(other: Any?): Boolean = other is DefaultAudioFrameSenderData && this.wrapper == other.wrapper - override fun hashCode(): Int = wrapper.hashCode() - override fun toString(): String = when (val n = wrapper.nonceStrategy) { - null -> "DefaultAudioFrameSenderData(udp=${wrapper.udp}, interceptor=${wrapper.interceptor}, " + - "provider=${wrapper.provider})" - else -> "DefaultAudioFrameSenderData(udp=${wrapper.udp}, interceptor=${wrapper.interceptor}, " + - "provider=${wrapper.provider}, nonceStrategy=$n)" - } - - public fun copy( - udp: VoiceUdpSocket = wrapper.udp, interceptor: FrameInterceptor = wrapper.interceptor, - provider: AudioProvider = wrapper.provider, - ): DefaultAudioFrameSenderData = DefaultAudioFrameSenderData( - Wrapper(udp = udp, interceptor = interceptor, provider = provider, nonceStrategy = wrapper.nonceStrategy) - ) - - internal constructor( - udpSocket: VoiceUdpSocket, frameInterceptor: FrameInterceptor, - strategy: @Suppress("DEPRECATION") NonceStrategy?, audioProvider: AudioProvider, - ) : this( - Wrapper(udp = udpSocket, interceptor = frameInterceptor, provider = audioProvider, nonceStrategy = strategy) - ) - @Deprecated( "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. Construct a " + "'DefaultAudioFrameSenderData' instance without a 'nonceStrategy' instead. " + @@ -70,7 +36,15 @@ public class DefaultAudioFrameSenderData private constructor(private val wrapper public constructor( udp: VoiceUdpSocket, interceptor: FrameInterceptor, provider: AudioProvider, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy, - ) : this(Wrapper(udp = udp, interceptor = interceptor, provider = provider, nonceStrategy = nonceStrategy)) + ) : this(udp, interceptor, nonceStrategy, provider) + + internal constructor( + udp: VoiceUdpSocket, interceptor: FrameInterceptor, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy?, + provider: AudioProvider, + ) : this(Wrapper(udp, interceptor, provider, nonceStrategy)) + + public constructor(udp: VoiceUdpSocket, interceptor: FrameInterceptor, provider: AudioProvider) : + this(udp, interceptor, nonceStrategy = null, provider) @Deprecated( "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. A 'DefaultAudioFrameSenderData' " + @@ -83,6 +57,11 @@ public class DefaultAudioFrameSenderData private constructor(private val wrapper "This DefaultAudioFrameSenderData instance was created without a nonceStrategy." ) + public val udp: VoiceUdpSocket get() = wrapper.udp + public val interceptor: FrameInterceptor get() = wrapper.interceptor + public val provider: AudioProvider get() = wrapper.provider + internal val strategy get() = wrapper.nonceStrategy + @Deprecated( "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. A 'DefaultAudioFrameSenderData' " + "instance can be created without a 'nonceStrategy' in which case this function throws an " + @@ -94,6 +73,10 @@ public class DefaultAudioFrameSenderData private constructor(private val wrapper "This DefaultAudioFrameSenderData instance was created without a nonceStrategy." ) + public operator fun component1(): VoiceUdpSocket = udp + public operator fun component2(): FrameInterceptor = interceptor + public operator fun component3(): AudioProvider = provider + @Deprecated( "The 'nonceStrategy' property is only used for XSalsa20 Poly1305 encryption. Create a copy of this " + "'DefaultAudioFrameSenderData' instance without a 'nonceStrategy' instead. $XSalsa20_FUNCTION_DEPRECATION", @@ -101,17 +84,25 @@ public class DefaultAudioFrameSenderData private constructor(private val wrapper DeprecationLevel.WARNING, ) public fun copy( - udp: VoiceUdpSocket = wrapper.udp, interceptor: FrameInterceptor = wrapper.interceptor, - provider: AudioProvider = wrapper.provider, + udp: VoiceUdpSocket = this.udp, interceptor: FrameInterceptor = this.interceptor, + provider: AudioProvider = this.provider, nonceStrategy: @Suppress("DEPRECATION") NonceStrategy = NONCE_STRATEGY_SENTINEL, ): DefaultAudioFrameSenderData = when { - // nonceStrategy was not overridden, keep the old one (which might be null) - nonceStrategy === NONCE_STRATEGY_SENTINEL -> DefaultAudioFrameSenderData( - Wrapper(udp = udp, interceptor = interceptor, provider = provider, nonceStrategy = wrapper.nonceStrategy) - ) - else -> DefaultAudioFrameSenderData( - Wrapper(udp = udp, interceptor = interceptor, provider = provider, nonceStrategy = nonceStrategy) - ) + nonceStrategy === NONCE_STRATEGY_SENTINEL -> // nonceStrategy not specified, keep old one (might be null) + DefaultAudioFrameSenderData(udp, interceptor, strategy, provider) + else -> DefaultAudioFrameSenderData(udp, interceptor, nonceStrategy, provider) + } + + public fun copy( + udp: VoiceUdpSocket = this.udp, interceptor: FrameInterceptor = this.interceptor, + provider: AudioProvider = this.provider, + ): DefaultAudioFrameSenderData = DefaultAudioFrameSenderData(udp, interceptor, strategy, provider) + + override fun equals(other: Any?): Boolean = other is DefaultAudioFrameSenderData && this.wrapper == other.wrapper + override fun hashCode(): Int = wrapper.hashCode() + override fun toString(): String = when (val ns = strategy) { + null -> "DefaultAudioFrameSenderData(udp=$udp, interceptor=$interceptor, provider=$provider)" + else -> "DefaultAudioFrameSenderData(udp=$udp, interceptor=$interceptor, provider=$provider, nonceStrategy=$ns)" } private companion object { @@ -127,7 +118,7 @@ public class DefaultAudioFrameSender( override suspend fun start(configuration: AudioFrameSenderConfiguration): Unit = coroutineScope { var sequence: UShort = Random.nextBits(UShort.SIZE_BITS).toUShort() - val packetProvider = DefaultAudioPacketProvider(configuration.key, configuration.encryptionMode, data.strategy) + val packetProvider = DefaultAudioPacketProvider(configuration.key, data.strategy, configuration.encryptionMode) val frames = Channel(Channel.RENDEZVOUS) with(data.provider) { launch { provideFrames(frames) } }