Update submodule name
This commit is contained in:
38 files changed
+7
-3
No files matched your search
@@ -0,0 +1,28 @@
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
kotlin {
|
||||
explicitApi()
|
||||
|
||||
linuxX64()
|
||||
linuxArm64()
|
||||
macosArm64()
|
||||
mingwX64()
|
||||
iosArm64()
|
||||
iosSimulatorArm64()
|
||||
jvm { compilerOptions.jvmTarget = JvmTarget.JVM_1_8 }
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(project(":common"))
|
||||
}
|
||||
|
||||
jvmMain.dependencies {
|
||||
|
||||
}
|
||||
|
||||
commonTest.dependencies {
|
||||
implementation(kotlin("test"))
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/4
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.mcping.rconlib
|
||||
|
||||
import cn.rtast.libmc.common._Buffer
|
||||
|
||||
internal fun _Buffer.writeNull() = writeByte(0x00)
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/4
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.mcping.rconlib
|
||||
|
||||
import cn.rtast.libmc.common.ByteOrder
|
||||
import cn.rtast.libmc.common._Buffer
|
||||
import cn.rtast.libmc.common._ReadChannel
|
||||
import cn.rtast.libmc.common._WriteChannel
|
||||
|
||||
internal abstract class Packet {
|
||||
abstract val requestId: Int
|
||||
abstract val type: Int
|
||||
abstract val payload: String
|
||||
|
||||
protected val payloadBytes: ByteArray by lazy { payload.encodeToByteArray() }
|
||||
|
||||
val payloadLength: Int
|
||||
get() = payloadBytes.size
|
||||
|
||||
open val length: Int
|
||||
get() = 4 + 4 + payloadLength + 2
|
||||
|
||||
fun writePayload(buf: _Buffer) {
|
||||
buf.writeInt(length, ByteOrder.LITTLE_ENDIAN)
|
||||
buf.writeInt(requestId, ByteOrder.LITTLE_ENDIAN)
|
||||
buf.writeInt(type, ByteOrder.LITTLE_ENDIAN)
|
||||
buf.writeBytes(payloadBytes)
|
||||
buf.writeNull()
|
||||
buf.writeNull()
|
||||
}
|
||||
|
||||
companion object Codec {
|
||||
fun decode(channel: _ReadChannel): ResponsePacket {
|
||||
val length = channel.readInt(ByteOrder.LITTLE_ENDIAN)
|
||||
val requestId = channel.readInt(ByteOrder.LITTLE_ENDIAN)
|
||||
val type = channel.readInt(ByteOrder.LITTLE_ENDIAN)
|
||||
val payloadBuffer = _Buffer()
|
||||
while (true) {
|
||||
val b = channel.readByte()
|
||||
if (b == 0x00.toByte()) break
|
||||
payloadBuffer.writeByte(b)
|
||||
}
|
||||
channel.readByte() // consume last null byte
|
||||
return ResponsePacket(length, requestId, type, payloadBuffer.toByteArray().decodeToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal data class AuthPacket(
|
||||
override val payload: String,
|
||||
override val requestId: Int = 1,
|
||||
) : Packet() {
|
||||
override val type: Int = PacketType.AUTH
|
||||
}
|
||||
|
||||
internal data class ExecCommandPacket(
|
||||
override val payload: String,
|
||||
override val requestId: Int,
|
||||
) : Packet() {
|
||||
override val type: Int = PacketType.EXEC_COMMAND
|
||||
}
|
||||
|
||||
internal data class ResponsePacket(
|
||||
override val length: Int,
|
||||
override val requestId: Int,
|
||||
override val type: Int,
|
||||
override val payload: String,
|
||||
) : Packet()
|
||||
|
||||
|
||||
internal fun _WriteChannel.sendPacket(packet: Packet) {
|
||||
val buf = _Buffer()
|
||||
packet.writePayload(buf)
|
||||
writeFully(buf.toByteArray())
|
||||
flush()
|
||||
}
|
||||
|
||||
internal fun _ReadChannel.readPacket(): ResponsePacket = Packet.decode(this)
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/4
|
||||
*/
|
||||
|
||||
|
||||
package cn.rtast.libmc.mcping.rconlib
|
||||
|
||||
internal object PacketType {
|
||||
const val AUTH = 3
|
||||
const val EXEC_COMMAND = 2
|
||||
const val RESPONSE = 1
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/4
|
||||
*/
|
||||
|
||||
@file:JvmName("Rconlib")
|
||||
|
||||
package cn.rtast.libmc.mcping.rconlib
|
||||
|
||||
import cn.rtast.libmc.common.LibMCContext
|
||||
import cn.rtast.libmc.common._ReadChannel
|
||||
import cn.rtast.libmc.common._Socket
|
||||
import cn.rtast.libmc.common._WriteChannel
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.jvm.JvmOverloads
|
||||
|
||||
public class RCONClient internal constructor(
|
||||
private val host: String,
|
||||
private val port: Int,
|
||||
private val context: LibMCContext,
|
||||
) : AutoCloseable {
|
||||
private var socket: _Socket? = null
|
||||
private var readChannel: _ReadChannel? = null
|
||||
private var writeChannel: _WriteChannel? = null
|
||||
private var currentRequestId = 1
|
||||
|
||||
public fun connect(password: String): Boolean {
|
||||
socket = _Socket(host, port, context)
|
||||
readChannel = socket!!.openReadChannel()
|
||||
writeChannel = socket!!.openWriteChannel()
|
||||
val authPacket = AuthPacket(password, currentRequestId)
|
||||
writeChannel!!.sendPacket(authPacket)
|
||||
return readChannel!!.readPacket().requestId != -1
|
||||
}
|
||||
|
||||
public fun command(command: String): String {
|
||||
val reqId = currentRequestId++
|
||||
val commandPacket = ExecCommandPacket(command, reqId)
|
||||
writeChannel!!.sendPacket(commandPacket)
|
||||
return readChannel!!.readPacket().payload
|
||||
}
|
||||
|
||||
public override fun close() {
|
||||
socket?.close()
|
||||
socket = null
|
||||
readChannel = null
|
||||
writeChannel = null
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
public fun rconClient(host: String, port: Int, context: LibMCContext = LibMCContext()): RCONClient =
|
||||
RCONClient(host, port, context)
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/4
|
||||
*/
|
||||
|
||||
|
||||
package test
|
||||
|
||||
import cn.rtast.libmc.mcping.rconlib.rconClient
|
||||
import kotlin.test.Test
|
||||
|
||||
class TestRCON {
|
||||
|
||||
@Test
|
||||
fun `test rcon client`() {
|
||||
val host = "127.0.0.1"
|
||||
val port = 25575
|
||||
val client = rconClient(host, port)
|
||||
val authed = client.connect("123456")
|
||||
if (authed) println(client.command("list")) else throw IllegalArgumentException("incorrect password")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright © 2026 RTAkland
|
||||
* Author: RTAkland
|
||||
* Date: 2026/9/4
|
||||
*/
|
||||
|
||||
|
||||
package test;
|
||||
|
||||
import cn.rtast.libmc.mcping.rconlib.RCONClient;
|
||||
import cn.rtast.libmc.mcping.rconlib.Rconlib;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestRconClientOnJava {
|
||||
|
||||
@Test
|
||||
public void testRconClient() {
|
||||
String host = "127.0.0.1";
|
||||
int port = 25575;
|
||||
String password = "123456";
|
||||
RCONClient rconClient = Rconlib.rconClient(host, port);
|
||||
boolean authed = rconClient.connect(password);
|
||||
if (authed) {
|
||||
System.out.println(rconClient.command("list"));
|
||||
} else {
|
||||
throw new IllegalStateException("incorrect password");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user