Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update dependencies #986

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ kotlin {
}
nonJvmMain {
dependencies {
implementation(libs.ktor.utils)
implementation(libs.bignum)
implementation(libs.stately.collections)
}
Expand Down
23 changes: 17 additions & 6 deletions common/src/nonJvmMain/kotlin/DiscordBitSet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@ package dev.kord.common

import com.ionspin.kotlin.bignum.integer.BigInteger
import com.ionspin.kotlin.bignum.integer.Sign
import io.ktor.utils.io.core.*

internal actual fun formatIntegerFromLittleEndianLongArray(data: LongArray) =
withBuffer(data.size * Long.SIZE_BYTES) {
// need to convert from little-endian data to big-endian expected by BigInteger
writeFully(data.reversedArray())
BigInteger.fromByteArray(readBytes(), Sign.POSITIVE).toString()
internal actual fun formatIntegerFromLittleEndianLongArray(data: LongArray): String {
// need to convert from little-endian data to big-endian expected by BigInteger
val bytes = ByteArray(size = data.size * Long.SIZE_BYTES)
val lastIndex = data.lastIndex
for (i in 0..lastIndex) {
val offset = (lastIndex - i) * Long.SIZE_BYTES
val long = data[i]
bytes[offset] = (long ushr 56).toByte()
bytes[offset + 1] = (long ushr 48).toByte()
bytes[offset + 2] = (long ushr 40).toByte()
bytes[offset + 3] = (long ushr 32).toByte()
bytes[offset + 4] = (long ushr 24).toByte()
bytes[offset + 5] = (long ushr 16).toByte()
bytes[offset + 6] = (long ushr 8).toByte()
bytes[offset + 7] = long.toByte()
}
return BigInteger.fromByteArray(bytes, Sign.POSITIVE).toString()
}

internal actual fun parseNonNegativeIntegerToBigEndianByteArray(value: String): ByteArray = BigInteger
.parseString(value)
Expand Down
1 change: 0 additions & 1 deletion gateway/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ kotlin {
api(projects.common)

api(libs.bundles.ktor.client.serialization)
api(libs.ktor.client.websockets)

implementation(libs.kotlin.logging)

Expand Down
23 changes: 11 additions & 12 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
[versions]

# api dependencies
kotlin = "2.0.20" # https://github.com/JetBrains/kotlin
ktor = "2.3.12" # https://github.com/ktorio/ktor
kotlinx-coroutines = "1.8.1" # https://github.com/Kotlin/kotlinx.coroutines
kotlinx-serialization = "1.7.2" # https://github.com/Kotlin/kotlinx.serialization
kotlin = "2.0.21" # https://github.com/JetBrains/kotlin
ktor = "3.0.0" # https://github.com/ktorio/ktor
kotlinx-coroutines = "1.9.0" # https://github.com/Kotlin/kotlinx.coroutines
kotlinx-serialization = "1.7.3" # https://github.com/Kotlin/kotlinx.serialization
kotlinx-datetime = "0.6.1" # https://github.com/Kotlin/kotlinx-datetime
kord-cache = "0.5.4" # https://github.com/kordlib/cache

# implementation dependencies
kotlin-logging = "7.0.0" # https://github.com/oshai/kotlin-logging
kotlin-logging-old = "3.0.5" # TODO remove after dependency is removed in rest, gateway, voice and core
slf4j = "2.0.16" # https://www.slf4j.org
kotlin-node = "20.14.10-pre.800" # https://github.com/JetBrains/kotlin-wrappers
kotlin-node = "22.5.4-pre.818" # https://github.com/JetBrains/kotlin-wrappers
bignum = "0.3.10" # https://github.com/ionspin/kotlin-multiplatform-bignum
stately = "2.1.0" # https://github.com/touchlab/Stately
fastZlib = "2.0.1" # https://github.com/timotejroiko/fast-zlib

# code generation
ksp = "2.0.20-1.0.24" # https://github.com/google/ksp
ksp = "2.0.21-1.0.25" # https://github.com/google/ksp
kotlinpoet = "1.18.1" # https://github.com/square/kotlinpoet

# tests
junit-jupiter = "5.11.0" # https://github.com/junit-team/junit5
junit-platform = "1.11.0"
mockk = "1.13.12" # https://github.com/mockk/mockk
junit-jupiter = "5.11.2" # https://github.com/junit-team/junit5
junit-platform = "1.11.2"
mockk = "1.13.13" # https://github.com/mockk/mockk
kbson = "0.4.0" # https://github.com/mongodb/kbson

# plugins
dokka = "2.0.0-Beta" # https://github.com/Kotlin/dokka
kotlinx-atomicfu = "0.25.0" # https://github.com/Kotlin/kotlinx-atomicfu
binary-compatibility-validator = "0.16.3" # https://github.com/Kotlin/binary-compatibility-validator
buildconfig = "5.4.0" # https://github.com/gmazzo/gradle-buildconfig-plugin
buildconfig = "5.5.0" # https://github.com/gmazzo/gradle-buildconfig-plugin


[libraries]
Expand All @@ -46,10 +46,9 @@ ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
ktor-client-websockets = { module = "io.ktor:ktor-client-websockets", version.ref = "ktor" }
ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" }
ktor-network = { module = "io.ktor:ktor-network", version.ref = "ktor" }
ktor-utils = { module = "io.ktor:ktor-utils", version.ref = "ktor" }
ktor-io = { module = "io.ktor:ktor-io", version.ref = "ktor" }

# kotlinx
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=5b9c5eb3f9fc2c94abaea57d90bd78747ca117ddbbf96c859d3741181a12bf2a
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
distributionSha256Sum=31c55713e40233a8303827ceb42ca48a47267a0ad4bab9177123121e71524c26
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
1 change: 0 additions & 1 deletion rest/src/commonMain/kotlin/request/KtorRequestHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import io.ktor.client.*
import io.ktor.client.request.*
import io.ktor.client.request.forms.*
import io.ktor.client.statement.*
import io.ktor.content.TextContent
import io.ktor.http.*
import io.ktor.http.content.*
import kotlinx.datetime.Clock
Expand Down
6 changes: 2 additions & 4 deletions rest/src/commonTest/kotlin/request/MessageRequests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import dev.kord.common.entity.Snowflake
import dev.kord.common.entity.optional.Optional
import dev.kord.rest.json.readFile
import dev.kord.rest.service.ChannelService
import dev.kord.test.Platform
import io.ktor.client.*
import io.ktor.client.engine.mock.*
import io.ktor.client.request.forms.*
import io.ktor.utils.io.*
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Clock
import kotlinx.serialization.encodeToString
Expand Down Expand Up @@ -62,10 +62,9 @@ class MessageRequests {

val channelService = ChannelService(KtorRequestHandler(client = HttpClient(mockEngine), token = ""))

val fileChannel = readFile("images/kord.png")
val fileChannel = readFile("images/kord.png").counted()

with(fileChannel) {
if (Platform.IS_JVM) assertFalse(isClosedForWrite) // only read lazily on jvm
assertFalse(isClosedForRead)
assertEquals(0L, totalBytesRead)

Expand All @@ -74,7 +73,6 @@ class MessageRequests {
}
assertEquals(mockMessage, createdMessage)

assertTrue(isClosedForWrite)
assertTrue(isClosedForRead)
assertTrue(totalBytesRead > 0L)
}
Expand Down
2 changes: 1 addition & 1 deletion test-kit/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ kotlin {
commonMain {
dependencies {
api(libs.bundles.test.common)
api(libs.ktor.utils)
api(libs.ktor.io)
}
}
jsMain {
Expand Down
2 changes: 1 addition & 1 deletion voice/api/voice.api
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ public final class dev/kord/voice/udp/RTPPacket$Builder {
}

public final class dev/kord/voice/udp/RTPPacket$Companion {
public final fun fromPacket (Lio/ktor/utils/io/core/ByteReadPacket;)Ldev/kord/voice/udp/RTPPacket;
public final fun fromPacket (Lkotlinx/io/Source;)Ldev/kord/voice/udp/RTPPacket;
}

public final class dev/kord/voice/udp/RTPPacketKt {
Expand Down
35 changes: 17 additions & 18 deletions voice/src/main/kotlin/udp/GlobalVoiceUdpSocket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import io.github.oshai.kotlinlogging.KotlinLogging
import io.ktor.network.selector.*
import io.ktor.network.sockets.*
import io.ktor.utils.io.core.*
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.*
import kotlin.text.String
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.emitAll
import kotlinx.io.Sink
import kotlinx.io.readString
import kotlinx.io.readUShort

private val globalVoiceSocketLogger = KotlinLogging.logger { }

Expand All @@ -32,47 +33,45 @@ public object GlobalVoiceUdpSocket : VoiceUdpSocket {
private val _incoming: MutableSharedFlow<Datagram> = MutableSharedFlow()
override val incoming: SharedFlow<Datagram> = _incoming

private val socket = aSocket(ActorSelectorManager(socketScope.coroutineContext)).udp().bind()
private val socket = socketScope.async {
aSocket(ActorSelectorManager(socketScope.coroutineContext)).udp().bind()
}

private val EMPTY_DATA = ByteArray(DISCOVERY_DATA_SIZE)

init {
socket.incoming
.consumeAsFlow()
.onEach { _incoming.emit(it) }
.launchIn(socketScope)
socketScope.launch { _incoming.emitAll(socket.await().incoming) }
}

@OptIn(ExperimentalUnsignedTypes::class)
override suspend fun discoverIp(address: InetSocketAddress, ssrc: Int): InetSocketAddress {
globalVoiceSocketLogger.trace { "discovering ip" }

send(packet(address) {
writeShort(REQUEST)
writeShort(MESSAGE_LENGTH)
writeInt(ssrc)
writeFully(EMPTY_DATA)
write(EMPTY_DATA)
})

return with(receiveFrom(address).packet) {
require(readShort() == RESPONSE) { "did not receive a response." }
require(readShort() == MESSAGE_LENGTH) { "expected $MESSAGE_LENGTH bytes of data."}
discardExact(4) // ssrc
require(readShort() == MESSAGE_LENGTH) { "expected $MESSAGE_LENGTH bytes of data." }
skip(byteCount = 4) // ssrc

val ip = String(readBytes(64)).trimEnd(0.toChar())
val ip = readString(byteCount = 64).trimEnd(0.toChar())
val port = readUShort().toInt()

InetSocketAddress(ip, port)
}
}

override suspend fun send(packet: Datagram) {
socket.send(packet)
socket.await().send(packet)
}

override suspend fun stop() { /* this doesn't stop until the end of the process */ }

private fun packet(address: SocketAddress, builder: BytePacketBuilder.() -> Unit): Datagram {
private fun packet(address: SocketAddress, builder: Sink.() -> Unit): Datagram {
return Datagram(buildPacket(block = builder), address)
}
}
19 changes: 11 additions & 8 deletions voice/src/main/kotlin/udp/RTPPacket.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import dev.kord.voice.io.ByteArrayView
import dev.kord.voice.io.MutableByteArrayCursor
import dev.kord.voice.io.mutableCursor
import dev.kord.voice.io.view
import io.ktor.utils.io.core.*
import kotlinx.io.Source
import kotlinx.io.readByteArray
import kotlinx.io.readUInt
import kotlinx.io.readUShort
import kotlin.experimental.and

internal const val RTP_HEADER_LENGTH = 12
Expand Down Expand Up @@ -38,8 +41,8 @@ public data class RTPPacket(
public companion object {
internal const val VERSION = 2

public fun fromPacket(packet: ByteReadPacket): RTPPacket? = with(packet) base@{
if (remaining <= 13) return@base null
public fun fromPacket(packet: Source): RTPPacket? = with(packet) base@{
if (!request(byteCount = 14)) return@base null
Comment on lines -41 to +45
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lost-illusi0n was the <= here and below intended? The RTP header is 12 bytes and then you required to have 2 more bytes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I intentionally required it to have at least one more byte (12 byte header + a one byte payload), but wrote it like that. Woops. This could probably be changed, but a one byte payload is unlikely in reality (luckily). To be truly correct, an RTP packet could just be a header, with no payload. Maybe supporting that wouldn't be a bad idea. I just didn't bother (or forgot to) three years ago.

For the second <= case, that was to keep the intentional requirement of a payload in place. Made the same mistake of requiring a two byte payload again though. At least it's consistent)) If the requirement of a payload is dropped, then these extra data requirements can also be dropped. If not, then changing the upper bound of the data checks to one less should be fine too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, thanks for taking a look at this after 3 years :D

I think I'm going to leave the accidental +2 byte requirement in place for now. This PR is supposed to be a dependency upgrade and as you said it's unlikely that this causes problems in practice.

I'm working on the new encryption modes at the moment and I'm considering to touch the RTP logic with that too, so I'd rather bring in the change there.


/*
* first byte | bit table
Expand Down Expand Up @@ -72,15 +75,15 @@ public data class RTPPacket(
payloadType = this and 0x7F
}

val sequence = readShort().toUShort()
val timestamp = readInt().toUInt()
val ssrc = readInt().toUInt()
val sequence = readUShort()
val timestamp = readUInt()
val ssrc = readUInt()

// each csrc takes up 4 bytes, plus more data is required
if (remaining <= csrcCount * 4 + 1) return@base null
if (!request(byteCount = csrcCount * 4L + 2)) return@base null
val csrcIdentifiers = UIntArray(csrcCount.toInt()) { readUInt() }

val payload = readBytes().view()
val payload = readByteArray().view()

val paddingBytes = if (hasPadding) { payload[payload.viewSize - 1] } else 0

Expand Down