Skip to content
Open
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
57 changes: 27 additions & 30 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,44 +1,41 @@
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(kotlin("gradle-plugin", version = "1.4.21"))
}
plugins {
base
application
kotlin("jvm") version "2.0.21"
}

plugins {
kotlin("jvm") version "1.4.21"
application {
mainClass.set("world.gregs.rs2.file.Main")
}

kotlin {
jvmToolchain(21)
}

group = "world.gregs.rs2.file"
group = "world.gregs"
group = "1.0.0"

repositories {
mavenCentral()
}

dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation("com.displee:rs-cache-library:6.7")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2")
implementation("io.ktor:ktor-server-core:1.5.0")
implementation("io.ktor:ktor-network:1.5.0")

implementation("ch.qos.logback:logback-classic:1.2.3")
implementation("com.michael-bull.kotlin-inline-logger:kotlin-inline-logger-jvm:1.0.2")

testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.2")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.6.2")
testImplementation("io.mockk:mockk:1.10.0")
implementation("com.displee:rs-cache-library:7.1.8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
implementation("io.ktor:ktor-server-core:3.0.1")
implementation("io.ktor:ktor-network:3.0.1")

implementation("ch.qos.logback:logback-classic:1.5.12")
implementation("com.michael-bull.kotlin-inline-logger:kotlin-inline-logger-jvm:1.0.5")

testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.3")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.11.3")
testImplementation("org.junit.jupiter:junit-jupiter")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation("io.mockk:mockk:1.13.13")
}

tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
tasks.test {
useJUnitPlatform()
}
4 changes: 2 additions & 2 deletions file-server.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
port=43594
revision=634
revision=592
cachePath=./cache/
rsaModulus=d6808be939bbfd2ec4e96b1581ce3e1144b526e7643a72e3c64fbb902724fbfcf14ab601da6d6f8dbb57d1c369d080d9fc392abeb7886e0076d07f2aea5810e540d2817fd1967e35b39cc95cf7c9170b5fb55f5bf95524b60e938f0d64614bc365b87d66963a8cc8664e32875366099ef297180d01c7c3842162865e11d92299
rsaPrivate=bd7a119cf43de5f90141fb30a5582ca58e5ec2bdd560780a522c2e4fb8f4478f790978db0c3a6d36f28d31a2ff7e89c384b46ed8c740c182b1719d53a86c2086f376d1c213785fd35c2aac5648195d10681d00a8c801dcebc1c7645daad5824c95430324a71228bb43be1bb7df6ac6ca8587f0848cf765fb850f40486b5475ed
prefetchKeys=104,79328,55571,46770,24563,299978,44375,0,4177,2822,99906,617909,155187,282646,330116,682557,18883,19031,16187,1248,6254,526,119,741135,821698,3671,2908
prefetchKeys=
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
15 changes: 11 additions & 4 deletions src/main/kotlin/world/gregs/rs2/file/FileServer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,16 @@ class FileServer(
val compression = data[0].toInt()
val size = getInt(data[1], data[2], data[3], data[4]) + if (compression != 0) 8 else 4
logger.trace { "Serving file $index $archive - $size." }
write.writeByte(index)
write.writeShort(archive)
write.writeByte(if (prefetch) compression or 0x80 else compression)
write.writeByte(index.toByte())
write.writeShort(archive.toShort())

val compressionByte = if (prefetch) {
compression or 0x80
} else {
compression
}.toByte()

write.writeByte(compressionByte)
serve(write, HEADER, data, OFFSET, size, SPLIT)
}

Expand All @@ -52,7 +59,7 @@ class FileServer(
write.writeFully(source, offset, length)
var written = length
while (written < size) {
write.writeByte(SEPARATOR)
write.writeByte(SEPARATOR.toByte())

length = if (size - written < split) size - written else split - 1
write.writeFully(source, written + offset, length)
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/world/gregs/rs2/file/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ object Main {
logger.info { "Settings loaded." }

val cache = CacheLibrary(cachePath)
val versionTable = cache.generateNewUkeys(exponent, modulus)
logger.debug { "Version table generated: ${versionTable.contentToString()}" }
val versionTable = cache.generateUkeys(false)
logger.info { "Version table generated: ${versionTable.contentToString()}" }

if (prefetchKeys == null) {
prefetchKeys = generatePrefetchKeys(cache)
Expand Down
10 changes: 6 additions & 4 deletions src/main/kotlin/world/gregs/rs2/file/Network.kt
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ class Network(
* Verify status updates and pass requests onto the [server] to fulfill
*/
suspend fun readRequest(read: ByteReadChannel, write: ByteWriteChannel) {
when (val opcode = read.readByte().toInt()) {
val opcode = read.readByte().toInt()

when (opcode) {
STATUS_LOGGED_OUT, STATUS_LOGGED_IN -> verify(read, write, statusId)
PRIORITY_REQUEST, PREFETCH_REQUEST -> server.fulfill(read, write, opcode == PREFETCH_REQUEST)
else -> {
Expand All @@ -151,8 +153,8 @@ class Network(
const val ACKNOWLEDGE = 6

// Response codes
private const val GAME_UPDATED = 6
private const val BAD_SESSION_ID = 10
private const val REJECT_SESSION = 11
private const val GAME_UPDATED: Byte = 6
private const val BAD_SESSION_ID: Byte = 10
private const val REJECT_SESSION: Byte = 11
}
}
15 changes: 8 additions & 7 deletions src/test/kotlin/world/gregs/rs2/file/FileServerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import io.ktor.utils.io.*
import io.mockk.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Test

Expand Down Expand Up @@ -62,7 +63,7 @@ internal class FileServerTest {
}

@Test
fun `Encode header for prefetch request`() = runBlockingTest {
fun `Encode header for prefetch request`() = runTest {
val server = spyk(FileServer(mockk(), byteArrayOf()))
val write: ByteWriteChannel = mockk()
val file = byteArrayOf(2, 0, 0, -44, 49)
Expand All @@ -77,13 +78,13 @@ internal class FileServerTest {
coVerifyOrder {
write.writeByte(1)
write.writeShort(2)
write.writeByte(130)
write.writeByte(130.toByte())
server.serve(write, 4, file, 1, 54329, 512)
}
}

@Test
fun `Encode header for priority request`() = runBlockingTest {
fun `Encode header for priority request`() = runTest {
val server = spyk(FileServer(mockk(), byteArrayOf()))
val write: ByteWriteChannel = mockk()
val file = byteArrayOf(0, 0, 0, 0, 10)
Expand All @@ -104,7 +105,7 @@ internal class FileServerTest {
}

@Test
fun `Encode small single sector`() = runBlockingTest {
fun `Encode small single sector`() = runTest {
val data = byteArrayOf(1, 2, 3, 4, 5)
val server = FileServer(mockk(), byteArrayOf())
val write: ByteWriteChannel = mockk()
Expand All @@ -118,7 +119,7 @@ internal class FileServerTest {
}

@Test
fun `Encode fixed size single sector`() = runBlockingTest {
fun `Encode fixed size single sector`() = runTest {
val data = byteArrayOf(1, 2, 3, 4, 5)
val server = FileServer(mockk(), byteArrayOf())
val write: ByteWriteChannel = mockk()
Expand All @@ -132,7 +133,7 @@ internal class FileServerTest {
}

@Test
fun `Encode two sectors`() = runBlockingTest {
fun `Encode two sectors`() = runTest {
val data = byteArrayOf(1, 2, 3, 4, 5, 6, 7)
val server = FileServer(mockk(), byteArrayOf())
val write: ByteWriteChannel = mockk()
Expand All @@ -143,7 +144,7 @@ internal class FileServerTest {

coVerifyOrder {
write.writeFully(data, 2, 4)
write.writeByte(255)
write.writeByte(255.toByte())
write.writeFully(data, 6, 1)
}
}
Expand Down
32 changes: 16 additions & 16 deletions src/test/kotlin/world/gregs/rs2/file/NetworkTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.ktor.network.sockets.*
import io.ktor.utils.io.*
import io.mockk.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.DynamicTest.dynamicTest
import org.junit.jupiter.api.Test
Expand All @@ -14,7 +14,7 @@ import org.junit.jupiter.api.TestFactory
internal class NetworkTest {

@Test
fun `Connect, sync, ack and fulfill`() = runBlockingTest {
fun `Connect, sync, ack and fulfill`() = runTest {
mockkStatic("world.gregs.rs2.file.JagexTypesKt")
mockkStatic("io.ktor.network.sockets.SocketsKt")
val network = spyk(Network(mockk(), intArrayOf(), 0, 0, 0))
Expand All @@ -39,7 +39,7 @@ internal class NetworkTest {
}

@Test
fun `Failed ack won't fulfill`() = runBlockingTest {
fun `Failed ack won't fulfill`() = runTest {
mockkStatic("world.gregs.rs2.file.JagexTypesKt")
mockkStatic("io.ktor.network.sockets.SocketsKt")
val network = spyk(Network(mockk(), intArrayOf(), 0, 0, 0))
Expand All @@ -66,7 +66,7 @@ internal class NetworkTest {
}

@Test
fun `Synchronise client and server`() = runBlockingTest {
fun `Synchronise client and server`() = runTest {
val revision = 1337
val keys = intArrayOf(0xffff, 0xfff, 0xff, 0xf)
val network = Network(mockk(), keys, revision, 0, 0)
Expand All @@ -91,14 +91,14 @@ internal class NetworkTest {
}

@Test
fun `Fail to synchronise with wrong revision`() = runBlockingTest {
fun `Fail to synchronise with wrong revision`() = runTest {
val revision = 10
val network = Network(mockk(), intArrayOf(), revision, 0, 0)
val read: ByteReadChannel = mockk()
val write: ByteWriteChannel = mockk()

coEvery { write.writeByte(any()) } just Runs
coEvery { write.close() } returns true
coEvery { write.close() } just Runs

coEvery { read.readByte() } returns 15
coEvery { read.readInt() } returns 13
Expand All @@ -115,14 +115,14 @@ internal class NetworkTest {
}

@Test
fun `Fail to synchronise with wrong id`() = runBlockingTest {
fun `Fail to synchronise with wrong id`() = runTest {
val revision = 420
val network = Network(mockk(), intArrayOf(), revision, 0, 0)
val read: ByteReadChannel = mockk()
val write: ByteWriteChannel = mockk()

coEvery { write.writeByte(any()) } just Runs
coEvery { write.close() } returns true
coEvery { write.close() } just Runs

coEvery { read.readByte() } returns 123

Expand All @@ -136,7 +136,7 @@ internal class NetworkTest {
}

@Test
fun `Acknowledge client`() = runBlockingTest {
fun `Acknowledge client`() = runTest {
mockkStatic("world.gregs.rs2.file.JagexTypesKt")
val network = Network(mockk(), intArrayOf(), 0, 3, 0)
val read: ByteReadChannel = mockk()
Expand All @@ -151,13 +151,13 @@ internal class NetworkTest {
}

@Test
fun `Don't acknowledge wrong opcode`() = runBlockingTest {
fun `Don't acknowledge wrong opcode`() = runTest {
val network = Network(mockk(), intArrayOf(), 0, 3, 0)
val read: ByteReadChannel = mockk()
val write: ByteWriteChannel = mockk()

coEvery { write.writeByte(any()) } just Runs
coEvery { write.close() } returns true
coEvery { write.close() } just Runs

coEvery { read.readByte() } returns 5

Expand All @@ -171,14 +171,14 @@ internal class NetworkTest {
}

@Test
fun `Don't acknowledge wrong session id`() = runBlockingTest {
fun `Don't acknowledge wrong session id`() = runTest {
mockkStatic("world.gregs.rs2.file.JagexTypesKt")
val network = Network(mockk(), intArrayOf(), 0, 0, 0)
val read: ByteReadChannel = mockk()
val write: ByteWriteChannel = mockk()

coEvery { write.writeByte(any()) } just Runs
coEvery { write.close() } returns true
coEvery { write.close() } just Runs

coEvery { read.readByte() } returns 6
coEvery { read.readMedium() } returns 12
Expand All @@ -196,7 +196,7 @@ internal class NetworkTest {
fun `Verify status update`() = intArrayOf(3, 2).map { opcode ->
mockkStatic("world.gregs.rs2.file.JagexTypesKt")
dynamicTest("Verify status logged ${if (opcode == 3) "out" else "in"}") {
runBlockingTest {
runTest {
val network = Network(mockk(), intArrayOf(), 0, 0, 0)
val read: ByteReadChannel = mockk()
val write: ByteWriteChannel = mockk()
Expand All @@ -220,13 +220,13 @@ internal class NetworkTest {
fun `Invalid status update session id`() = intArrayOf(3, 2).map { opcode ->
mockkStatic("world.gregs.rs2.file.JagexTypesKt")
dynamicTest("Invalid status logged ${if (opcode == 3) "out" else "in"}") {
runBlockingTest {
runTest {
val network = Network(mockk(), intArrayOf(), 0, 0, 0)
val read: ByteReadChannel = mockk()
val write: ByteWriteChannel = mockk()

coEvery { write.writeByte(any()) } just Runs
coEvery { write.close() } returns true
coEvery { write.close() } just Runs

coEvery { read.readByte() } returns opcode.toByte()
coEvery { read.readMedium() } returns 123
Expand Down