mirror of
https://github.com/ViaVersion/VIAaaS.git
synced 2024-11-25 12:35:36 +01:00
idk, srv, trying http
This commit is contained in:
parent
9e45c31465
commit
f9fc21dc40
@ -1,2 +0,0 @@
|
|||||||
<doctype html>
|
|
||||||
<!-- insert here online mode auth code with wss -->
|
|
@ -23,11 +23,20 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("us.myles:viaversion:3.1.1-SNAPSHOT")
|
implementation("us.myles:viaversion:3.1.1")
|
||||||
implementation("nl.matsv:viabackwards-all:3.1.1-SNAPSHOT")
|
implementation("nl.matsv:viabackwards-all:3.1.1")
|
||||||
implementation("de.gerrygames:viarewind-all:1.5.1")
|
implementation("de.gerrygames:viarewind-all:1.5.1")
|
||||||
|
implementation("net.md-5:bungeecord-chat:1.16-R0.3")
|
||||||
implementation("io.netty:netty-all:4.1.51.Final")
|
implementation("io.netty:netty-all:4.1.51.Final")
|
||||||
implementation(kotlin("stdlib-jdk8"))
|
implementation(kotlin("stdlib-jdk8"))
|
||||||
|
|
||||||
|
val ktorVersion = "1.4.0"
|
||||||
|
|
||||||
|
implementation("io.ktor:ktor-network-tls-certificates:$ktorVersion")
|
||||||
|
implementation("io.ktor:ktor-server-netty:$ktorVersion")
|
||||||
|
implementation("io.ktor:ktor-websockets:$ktorVersion")
|
||||||
|
implementation("ch.qos.logback:logback-classic:1.2.3")
|
||||||
|
testCompile("io.ktor:ktor-server-test-host:$ktorVersion")
|
||||||
}
|
}
|
||||||
|
|
||||||
val run: JavaExec by tasks
|
val run: JavaExec by tasks
|
||||||
|
@ -24,25 +24,25 @@ object ChannelInit : ChannelInitializer<Channel>() {
|
|||||||
override fun initChannel(ch: Channel) {
|
override fun initChannel(ch: Channel) {
|
||||||
val user = UserConnection(ch)
|
val user = UserConnection(ch)
|
||||||
CloudPipeline(user)
|
CloudPipeline(user)
|
||||||
ch.pipeline().addLast("frame-encoder", FrameEncoder)
|
ch.pipeline().addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
|
||||||
|
.addLast("frame-encoder", FrameEncoder)
|
||||||
.addLast("frame-decoder", FrameDecoder())
|
.addLast("frame-decoder", FrameDecoder())
|
||||||
.addLast("compress", CloudCompressor())
|
.addLast("compress", CloudCompressor())
|
||||||
.addLast("decompress", CloudDecompressor())
|
.addLast("decompress", CloudDecompressor())
|
||||||
|
.addLast("flow-handler", FlowControlHandler())
|
||||||
.addLast("via-encoder", CloudEncodeHandler(user))
|
.addLast("via-encoder", CloudEncodeHandler(user))
|
||||||
.addLast("via-decoder", CloudDecodeHandler(user))
|
.addLast("via-decoder", CloudDecodeHandler(user))
|
||||||
.addLast("flow-handler", FlowControlHandler())
|
|
||||||
.addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
|
|
||||||
.addLast("handler", CloudSideForwarder(user, null))
|
.addLast("handler", CloudSideForwarder(user, null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BackendInit(val user: UserConnection) : ChannelInitializer<Channel>() {
|
class BackendInit(val user: UserConnection) : ChannelInitializer<Channel>() {
|
||||||
override fun initChannel(ch: Channel) {
|
override fun initChannel(ch: Channel) {
|
||||||
ch.pipeline().addLast("frame-encoder", FrameEncoder)
|
ch.pipeline().addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
|
||||||
|
.addLast("frame-encoder", FrameEncoder)
|
||||||
.addLast("frame-decoder", FrameDecoder())
|
.addLast("frame-decoder", FrameDecoder())
|
||||||
.addLast("compress", CloudCompressor())
|
.addLast("compress", CloudCompressor())
|
||||||
.addLast("decompress", CloudDecompressor())
|
.addLast("decompress", CloudDecompressor())
|
||||||
.addLast("timeout", ReadTimeoutHandler(30, TimeUnit.SECONDS))
|
|
||||||
.addLast("handler", CloudSideForwarder(user, null))
|
.addLast("handler", CloudSideForwarder(user, null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ class CloudDecompressor(var threshold: Int = -1) : MessageToMessageDecoder<ByteB
|
|||||||
out.add(input.retain())
|
out.add(input.retain())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (input.readableBytes() != 0) {
|
if (input.isReadable) {
|
||||||
val outLength = Type.VAR_INT.readPrimitive(input)
|
val outLength = Type.VAR_INT.readPrimitive(input)
|
||||||
if (outLength == 0) {
|
if (outLength == 0) {
|
||||||
out.add(input.readBytes(input.readableBytes()))
|
out.add(input.readBytes(input.readableBytes()))
|
||||||
|
@ -12,10 +12,12 @@ import us.myles.ViaVersion.packets.State
|
|||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
|
||||||
val logger = Logger.getLogger("CloudHandler")
|
val logger = Logger.getLogger("CloudHandler")
|
||||||
class CloudSideForwarder(val userConnection: UserConnection, var other: Channel?) : SimpleChannelInboundHandler<ByteBuf>() {
|
|
||||||
|
|
||||||
|
class CloudSideForwarder(val userConnection: UserConnection, var other: Channel?) : SimpleChannelInboundHandler<ByteBuf>() {
|
||||||
override fun channelRead0(ctx: ChannelHandlerContext, msg: ByteBuf) {
|
override fun channelRead0(ctx: ChannelHandlerContext, msg: ByteBuf) {
|
||||||
other?.write(msg.retain())
|
if (!userConnection.isPendingDisconnect) {
|
||||||
|
other!!.write(msg.retain())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun channelInactive(ctx: ChannelHandlerContext) {
|
override fun channelInactive(ctx: ChannelHandlerContext) {
|
||||||
@ -39,17 +41,17 @@ class CloudSideForwarder(val userConnection: UserConnection, var other: Channel?
|
|||||||
cause.printStackTrace()
|
cause.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun disconnect(s: String) {
|
fun disconnect(s: String) {
|
||||||
if (userConnection.channel?.isActive != true) return
|
if (userConnection.channel?.isActive != true) return
|
||||||
|
|
||||||
val msg = "[VIAaaS] $s";
|
|
||||||
logger.info("Disconnecting " + userConnection.channel!!.remoteAddress() + ": " + s)
|
logger.info("Disconnecting " + userConnection.channel!!.remoteAddress() + ": " + s)
|
||||||
when (userConnection.protocolInfo!!.state) {
|
when (userConnection.protocolInfo!!.state) {
|
||||||
State.LOGIN -> {
|
State.LOGIN -> {
|
||||||
val packet = ByteBufAllocator.DEFAULT.buffer()
|
val packet = ByteBufAllocator.DEFAULT.buffer()
|
||||||
try {
|
try {
|
||||||
packet.writeByte(0) // id 0 disconnect
|
packet.writeByte(0) // id 0 disconnect
|
||||||
Type.STRING.write(packet, Gson().toJson(msg))
|
Type.STRING.write(packet, Gson().toJson("[VIAaaS] §c$s"))
|
||||||
userConnection.sendRawPacketFuture(packet.retain()).addListener { userConnection.channel?.close() }
|
userConnection.sendRawPacketFuture(packet.retain()).addListener { userConnection.channel?.close() }
|
||||||
} finally {
|
} finally {
|
||||||
packet.release()
|
packet.release()
|
||||||
@ -60,8 +62,7 @@ class CloudSideForwarder(val userConnection: UserConnection, var other: Channel?
|
|||||||
try {
|
try {
|
||||||
packet.writeByte(0) // id 0 disconnect
|
packet.writeByte(0) // id 0 disconnect
|
||||||
Type.STRING.write(packet, """{"version": {"name": "VIAaaS","protocol": -1},
|
Type.STRING.write(packet, """{"version": {"name": "VIAaaS","protocol": -1},
|
||||||
"players": {"max": 0,"online": 0,"sample": []},
|
"players": {"max": 0,"online": 0,"sample": []},"description": {"text": ${Gson().toJson("§c$s")}}}""")
|
||||||
"description": {"text": ${Gson().toJson(msg)}}}""")
|
|
||||||
userConnection.sendRawPacketFuture(packet.retain()).addListener { userConnection.channel?.close() }
|
userConnection.sendRawPacketFuture(packet.retain()).addListener { userConnection.channel?.close() }
|
||||||
} finally {
|
} finally {
|
||||||
packet.release()
|
packet.release()
|
||||||
|
@ -3,18 +3,25 @@ package com.github.creeper123123321.viaaas
|
|||||||
import io.netty.bootstrap.Bootstrap
|
import io.netty.bootstrap.Bootstrap
|
||||||
import io.netty.buffer.ByteBufAllocator
|
import io.netty.buffer.ByteBufAllocator
|
||||||
import io.netty.channel.Channel
|
import io.netty.channel.Channel
|
||||||
|
import io.netty.channel.ChannelOption
|
||||||
import io.netty.channel.socket.SocketChannel
|
import io.netty.channel.socket.SocketChannel
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel
|
import io.netty.channel.socket.nio.NioSocketChannel
|
||||||
import us.myles.ViaVersion.api.PacketWrapper
|
import us.myles.ViaVersion.api.PacketWrapper
|
||||||
import us.myles.ViaVersion.api.Via
|
import us.myles.ViaVersion.api.Via
|
||||||
import us.myles.ViaVersion.api.data.UserConnection
|
import us.myles.ViaVersion.api.data.UserConnection
|
||||||
import us.myles.ViaVersion.api.protocol.*
|
import us.myles.ViaVersion.api.protocol.Protocol
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolPipeline
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolRegistry
|
||||||
|
import us.myles.ViaVersion.api.protocol.SimpleProtocol
|
||||||
import us.myles.ViaVersion.api.remapper.PacketRemapper
|
import us.myles.ViaVersion.api.remapper.PacketRemapper
|
||||||
import us.myles.ViaVersion.api.type.Type
|
import us.myles.ViaVersion.api.type.Type
|
||||||
import us.myles.ViaVersion.packets.State
|
import us.myles.ViaVersion.packets.State
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
|
import javax.naming.NameNotFoundException
|
||||||
|
import javax.naming.directory.InitialDirContext
|
||||||
|
|
||||||
|
|
||||||
class CloudPipeline(userConnection: UserConnection) : ProtocolPipeline(userConnection) {
|
class CloudPipeline(userConnection: UserConnection) : ProtocolPipeline(userConnection) {
|
||||||
override fun registerPackets() {
|
override fun registerPackets() {
|
||||||
@ -35,63 +42,42 @@ object CloudHandlerProtocol : SimpleProtocol() {
|
|||||||
this.registerIncoming(State.HANDSHAKE, 0, 0, object : PacketRemapper() {
|
this.registerIncoming(State.HANDSHAKE, 0, 0, object : PacketRemapper() {
|
||||||
override fun registerMap() {
|
override fun registerMap() {
|
||||||
handler { wrapper: PacketWrapper ->
|
handler { wrapper: PacketWrapper ->
|
||||||
|
wrapper.cancel()
|
||||||
val playerVer = wrapper.passthrough(Type.VAR_INT)
|
val playerVer = wrapper.passthrough(Type.VAR_INT)
|
||||||
val addr = wrapper.passthrough(Type.STRING) // Server Address
|
val addr = wrapper.passthrough(Type.STRING) // Server Address
|
||||||
wrapper.passthrough(Type.UNSIGNED_SHORT)
|
wrapper.passthrough(Type.UNSIGNED_SHORT)
|
||||||
val nextState = wrapper.passthrough(Type.VAR_INT)
|
val nextState = wrapper.passthrough(Type.VAR_INT)
|
||||||
|
|
||||||
val addrParts = addr.split(0.toChar())[0].split(".")
|
val parsed = ViaaaSAddress().parse(addr)
|
||||||
var foundDomain = false
|
|
||||||
var foundOptions = false
|
|
||||||
var port = 25565
|
|
||||||
var online = true // todo implement this between proxy and player
|
|
||||||
var backProtocol = 47 // todo auto protocol
|
|
||||||
var backAddr = ""
|
|
||||||
addrParts.reversed().forEach {
|
|
||||||
if (foundDomain) {
|
|
||||||
if (!foundOptions) {
|
|
||||||
if (it.startsWith("_")) {
|
|
||||||
val arg = it.substring(2)
|
|
||||||
when {
|
|
||||||
it.startsWith("_p", ignoreCase = true) -> port = arg.toInt()
|
|
||||||
it.startsWith("_o", ignoreCase = true) -> online = arg.toBoolean()
|
|
||||||
it.startsWith("_v", ignoreCase = true) -> {
|
|
||||||
try {
|
|
||||||
backProtocol = Integer.parseInt(arg)
|
|
||||||
} catch (e: NumberFormatException) {
|
|
||||||
val closest = ProtocolVersion.getClosest(arg.replace("_", "."))
|
|
||||||
if (closest != null) {
|
|
||||||
backProtocol = closest.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
foundOptions = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (foundOptions) {
|
|
||||||
backAddr = "$it.$backAddr"
|
|
||||||
}
|
|
||||||
} else if (it.equals("viaaas", ignoreCase = true)) {
|
|
||||||
foundDomain = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
backAddr = backAddr.replace(Regex("\\.$"), "")
|
|
||||||
|
|
||||||
logger.info("connecting ${wrapper.user().channel!!.remoteAddress()} ($playerVer) to $backAddr:$port ($backProtocol)")
|
logger.info("connecting ${wrapper.user().channel!!.remoteAddress()} ($playerVer) to ${parsed.realAddress}:${parsed.port} (${parsed.protocol})")
|
||||||
|
|
||||||
wrapper.user().channel!!.setAutoRead(false)
|
wrapper.user().channel!!.setAutoRead(false)
|
||||||
wrapper.user().put(CloudData(
|
wrapper.user().put(CloudData(
|
||||||
backendVer = backProtocol,
|
backendVer = parsed.protocol,
|
||||||
userConnection = wrapper.user(),
|
userConnection = wrapper.user(),
|
||||||
frontOnline = online
|
frontOnline = parsed.online
|
||||||
))
|
))
|
||||||
|
|
||||||
Via.getPlatform().runAsync {
|
Via.getPlatform().runAsync {
|
||||||
val frontForwarder = wrapper.user().channel!!.pipeline().get(CloudSideForwarder::class.java)
|
val frontForwarder = wrapper.user().channel!!.pipeline().get(CloudSideForwarder::class.java)
|
||||||
try {
|
try {
|
||||||
val socketAddr = InetSocketAddress(InetAddress.getByName(backAddr), port)
|
var srvResolvedAddr = parsed.realAddress
|
||||||
|
var srvResolvedPort = parsed.port
|
||||||
|
if (srvResolvedPort == 25565) {
|
||||||
|
try {
|
||||||
|
// https://github.com/GeyserMC/Geyser/blob/99e72f35b308542cf0dbfb5b58816503c3d6a129/connector/src/main/java/org/geysermc/connector/GeyserConnector.java
|
||||||
|
val ctx = InitialDirContext()
|
||||||
|
val attr = ctx.getAttributes("dns:///_minecraft._tcp.${parsed.realAddress}", arrayOf("SRV"))["SRV"]
|
||||||
|
if (attr != null && attr.size() > 0) {
|
||||||
|
val record = (attr.get(0) as String).split(" ").toTypedArray()
|
||||||
|
srvResolvedAddr = record[3]
|
||||||
|
srvResolvedPort = record[2].toInt()
|
||||||
|
}
|
||||||
|
} catch (ignored: NameNotFoundException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val socketAddr = InetSocketAddress(InetAddress.getByName(srvResolvedAddr), srvResolvedPort)
|
||||||
val addrInfo = socketAddr.address
|
val addrInfo = socketAddr.address
|
||||||
if (addrInfo.isSiteLocalAddress
|
if (addrInfo.isSiteLocalAddress
|
||||||
|| addrInfo.isLoopbackAddress
|
|| addrInfo.isLoopbackAddress
|
||||||
@ -100,6 +86,7 @@ object CloudHandlerProtocol : SimpleProtocol() {
|
|||||||
val bootstrap = Bootstrap().handler(BackendInit(wrapper.user()))
|
val bootstrap = Bootstrap().handler(BackendInit(wrapper.user()))
|
||||||
.channel(NioSocketChannel::class.java)
|
.channel(NioSocketChannel::class.java)
|
||||||
.group(wrapper.user().channel!!.eventLoop())
|
.group(wrapper.user().channel!!.eventLoop())
|
||||||
|
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 15_000) // Half of mc timeout
|
||||||
.connect(socketAddr)
|
.connect(socketAddr)
|
||||||
|
|
||||||
bootstrap.addListener {
|
bootstrap.addListener {
|
||||||
@ -110,28 +97,23 @@ object CloudHandlerProtocol : SimpleProtocol() {
|
|||||||
frontForwarder.other = chann
|
frontForwarder.other = chann
|
||||||
val backHandshake = ByteBufAllocator.DEFAULT.buffer()
|
val backHandshake = ByteBufAllocator.DEFAULT.buffer()
|
||||||
try {
|
try {
|
||||||
|
val nullParts = addr.split(0.toChar())
|
||||||
backHandshake.writeByte(0) // Packet 0 handshake
|
backHandshake.writeByte(0) // Packet 0 handshake
|
||||||
val connProto =
|
val connProto = if (ProtocolRegistry.getProtocolPath(playerVer, parsed.protocol) != null) parsed.protocol else playerVer
|
||||||
if (ProtocolRegistry.getProtocolPath(playerVer, backProtocol) != null) {
|
|
||||||
backProtocol
|
|
||||||
} else playerVer
|
|
||||||
Type.VAR_INT.writePrimitive(backHandshake, connProto)
|
Type.VAR_INT.writePrimitive(backHandshake, connProto)
|
||||||
val nullPos = addr.indexOf(0.toChar())
|
Type.STRING.write(backHandshake, srvResolvedAddr + (if (nullParts.size == 2) 0.toChar() + nullParts[1] else "")) // Server Address
|
||||||
Type.STRING.write(backHandshake, backAddr
|
backHandshake.writeShort(srvResolvedPort)
|
||||||
+ (if (nullPos != -1) addr.substring(nullPos) else "")) // Server Address
|
|
||||||
backHandshake.writeShort(port)
|
|
||||||
Type.VAR_INT.writePrimitive(backHandshake, nextState)
|
Type.VAR_INT.writePrimitive(backHandshake, nextState)
|
||||||
chann.writeAndFlush(backHandshake.retain())
|
chann.writeAndFlush(backHandshake.retain())
|
||||||
} finally {
|
} finally {
|
||||||
backHandshake.release()
|
backHandshake.release()
|
||||||
}
|
}
|
||||||
|
wrapper.user().channel!!.setAutoRead(true)
|
||||||
} else {
|
} else {
|
||||||
wrapper.user().channel!!.eventLoop().submit {
|
wrapper.user().channel!!.eventLoop().submit {
|
||||||
frontForwarder.disconnect("Couldn't connect: " + it.cause().toString())
|
frontForwarder.disconnect("Couldn't connect: " + it.cause().toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper.user().channel!!.setAutoRead(true)
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
wrapper.user().channel!!.eventLoop().submit {
|
wrapper.user().channel!!.eventLoop().submit {
|
||||||
@ -156,9 +138,9 @@ object CloudHandlerProtocol : SimpleProtocol() {
|
|||||||
pipe.get(CloudCompressor::class.java).threshold = threshold
|
pipe.get(CloudCompressor::class.java).threshold = threshold
|
||||||
pipe.get(CloudDecompressor::class.java).threshold = threshold
|
pipe.get(CloudDecompressor::class.java).threshold = threshold
|
||||||
|
|
||||||
val backPipe = pipe.get(CloudSideForwarder::class.java).other?.pipeline()
|
val backPipe = pipe.get(CloudSideForwarder::class.java).other!!.pipeline()
|
||||||
backPipe?.get(CloudCompressor::class.java)?.threshold = threshold
|
backPipe.get(CloudCompressor::class.java)?.threshold = threshold
|
||||||
backPipe?.get(CloudDecompressor::class.java)?.threshold = threshold
|
backPipe.get(CloudDecompressor::class.java)?.threshold = threshold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1,16 +1,31 @@
|
|||||||
package com.github.creeper123123321.viaaas
|
package com.github.creeper123123321.viaaas
|
||||||
|
|
||||||
import de.gerrygames.viarewind.api.ViaRewindConfigImpl
|
import de.gerrygames.viarewind.api.ViaRewindConfigImpl
|
||||||
|
import io.ktor.application.*
|
||||||
|
import io.ktor.features.*
|
||||||
|
import io.ktor.http.cio.websocket.*
|
||||||
|
import io.ktor.http.content.*
|
||||||
|
import io.ktor.network.tls.certificates.*
|
||||||
|
import io.ktor.routing.*
|
||||||
|
import io.ktor.server.netty.*
|
||||||
|
import io.ktor.websocket.*
|
||||||
import io.netty.bootstrap.ServerBootstrap
|
import io.netty.bootstrap.ServerBootstrap
|
||||||
import io.netty.channel.nio.NioEventLoopGroup
|
import io.netty.channel.nio.NioEventLoopGroup
|
||||||
import io.netty.channel.socket.nio.NioServerSocketChannel
|
import io.netty.channel.socket.nio.NioServerSocketChannel
|
||||||
|
import kotlinx.coroutines.channels.consumeEach
|
||||||
import us.myles.ViaVersion.ViaManager
|
import us.myles.ViaVersion.ViaManager
|
||||||
import us.myles.ViaVersion.api.Via
|
import us.myles.ViaVersion.api.Via
|
||||||
import us.myles.ViaVersion.api.data.MappingDataLoader
|
import us.myles.ViaVersion.api.data.MappingDataLoader
|
||||||
|
import us.myles.ViaVersion.api.protocol.ProtocolVersion
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.InetAddress
|
||||||
|
import java.time.Duration
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
fun main() {
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val args = args.mapIndexed { i, content -> i to content }.toMap()
|
||||||
Via.init(ViaManager.builder()
|
Via.init(ViaManager.builder()
|
||||||
.injector(CloudInjector)
|
.injector(CloudInjector)
|
||||||
.loader(CloudLoader)
|
.loader(CloudLoader)
|
||||||
@ -30,9 +45,11 @@ fun main() {
|
|||||||
val future = ServerBootstrap().group(boss, worker)
|
val future = ServerBootstrap().group(boss, worker)
|
||||||
.channel(NioServerSocketChannel::class.java)
|
.channel(NioServerSocketChannel::class.java)
|
||||||
.childHandler(ChannelInit)
|
.childHandler(ChannelInit)
|
||||||
.bind(25565)
|
.bind(InetAddress.getByName(args[0] ?: "::"), args[1]?.toIntOrNull() ?: 25565)
|
||||||
.addListener { println(it) }
|
|
||||||
|
|
||||||
|
println("Binded minecraft into " + future.sync().channel().localAddress())
|
||||||
|
|
||||||
|
Thread { EngineMain.main(arrayOf()) }.start()
|
||||||
|
|
||||||
loop@ while (true) {
|
loop@ while (true) {
|
||||||
try {
|
try {
|
||||||
@ -55,3 +72,155 @@ fun main() {
|
|||||||
exitProcess(0) // todo what's stucking?
|
exitProcess(0) // todo what's stucking?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ViaaaSAddress {
|
||||||
|
var protocol = 0
|
||||||
|
var viaSuffix: String? = null
|
||||||
|
var realAddress: String? = null
|
||||||
|
var port: Int = 25565
|
||||||
|
var online: Boolean = false
|
||||||
|
fun parse(address: String): ViaaaSAddress {
|
||||||
|
val parts = address.split('.')
|
||||||
|
var foundDomain = false
|
||||||
|
var foundOptions = false
|
||||||
|
val ourParts = StringBuilder()
|
||||||
|
val realAddrBuilder = StringBuilder()
|
||||||
|
for (i in parts.indices.reversed()) {
|
||||||
|
val part = parts[i]
|
||||||
|
var realAddrPart = false
|
||||||
|
if (foundDomain) {
|
||||||
|
if (!foundOptions) {
|
||||||
|
if (part.startsWith("_")) {
|
||||||
|
val arg = part.substring(2)
|
||||||
|
when {
|
||||||
|
part.startsWith("_p", ignoreCase = true) -> port = arg.toInt()
|
||||||
|
part.startsWith("_o", ignoreCase = true) -> online = arg.toBoolean()
|
||||||
|
part.startsWith("_v", ignoreCase = true) -> {
|
||||||
|
try {
|
||||||
|
protocol = arg.toInt()
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
val closest = ProtocolVersion.getClosest(arg.replace("_", "."))
|
||||||
|
if (closest != null) {
|
||||||
|
protocol = closest.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foundOptions = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (foundOptions) {
|
||||||
|
realAddrPart = true
|
||||||
|
}
|
||||||
|
} else if (part.equals("viaaas", ignoreCase = true)) {
|
||||||
|
foundDomain = true
|
||||||
|
}
|
||||||
|
if (realAddrPart) {
|
||||||
|
realAddrBuilder.insert(0, "$part.")
|
||||||
|
} else {
|
||||||
|
ourParts.insert(0, "$part.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val realAddr = realAddrBuilder.toString().replace("\\.$".toRegex(), "")
|
||||||
|
val suffix = ourParts.toString().replace("\\.$".toRegex(), "")
|
||||||
|
if (realAddr.isEmpty()) {
|
||||||
|
realAddress = address
|
||||||
|
} else {
|
||||||
|
realAddress = realAddr
|
||||||
|
viaSuffix = suffix
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Application.mainWeb() {
|
||||||
|
ViaWebApp().apply { main() }
|
||||||
|
}
|
||||||
|
|
||||||
|
class ViaWebApp {
|
||||||
|
data class WebSession(val id: String)
|
||||||
|
|
||||||
|
val server = WebDashboardServer()
|
||||||
|
|
||||||
|
fun Application.main() {
|
||||||
|
install(DefaultHeaders)
|
||||||
|
install(CallLogging)
|
||||||
|
install(WebSockets) {
|
||||||
|
pingPeriod = Duration.ofMinutes(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
routing {
|
||||||
|
webSocket("/ws") {
|
||||||
|
server.connected(this)
|
||||||
|
|
||||||
|
try {
|
||||||
|
incoming.consumeEach { frame ->
|
||||||
|
if (frame is Frame.Text) {
|
||||||
|
server.onMessage(this, frame.readText())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
server.disconnected(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
defaultResource("auth.html", "web")
|
||||||
|
resources("web")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebDashboardServer {
|
||||||
|
val clients = ConcurrentHashMap<WebSocketSession, WebClient>()
|
||||||
|
suspend fun connected(ws: WebSocketSession) {
|
||||||
|
clients[ws] = WebClient(ws, WebLogin())
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun onMessage(ws: WebSocketSession, msg: String) {
|
||||||
|
val client = clients[ws]!!
|
||||||
|
client.state.onMessage(client, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun disconnected(ws: WebSocketSession) {
|
||||||
|
val client = clients[ws]!!
|
||||||
|
client.state.disconnected(client)
|
||||||
|
clients.remove(ws)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data class WebClient(val ws: WebSocketSession, val state: WebState) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface WebState {
|
||||||
|
fun onMessage(webClient: WebClient, msg: String)
|
||||||
|
fun disconnected(webClient: WebClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebLogin : WebState {
|
||||||
|
override fun onMessage(webClient: WebClient, msg: String) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun disconnected(webClient: WebClient) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
object CertificateGenerator {
|
||||||
|
@JvmStatic
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val jksFile = File("build/temporary.jks").apply {
|
||||||
|
parentFile.mkdirs()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jksFile.exists()) {
|
||||||
|
generateCertificate(jksFile) // Generates the certificate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
19
src/main/resources/application.conf
Normal file
19
src/main/resources/application.conf
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# You can read more about this file: https://ktor.io/servers/configuration.html#hocon-file
|
||||||
|
ktor {
|
||||||
|
deployment {
|
||||||
|
sslPort = 8443
|
||||||
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
modules = [ com.github.creeper123123321.viaaas.ViaaaSKt.mainWeb ]
|
||||||
|
}
|
||||||
|
|
||||||
|
security {
|
||||||
|
ssl {
|
||||||
|
keyStore = build/temporary.jks
|
||||||
|
keyAlias = mykey
|
||||||
|
keyStorePassword = changeit
|
||||||
|
privateKeyPassword = changeit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
src/main/resources/web/auth.html
Normal file
43
src/main/resources/web/auth.html
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<!-- insert here online mode auth code with wss -->
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script>
|
||||||
|
// Global variable to hold the websocket.
|
||||||
|
var socket = null;
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
console.log("Begin connect");
|
||||||
|
socket = new WebSocket("wss://" + window.location.host + "/ws");
|
||||||
|
|
||||||
|
socket.onerror = function() {
|
||||||
|
console.log("socket error");
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.onopen = function() {
|
||||||
|
console.log("Connected");
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.onclose = function(evt) {
|
||||||
|
// Try to gather an explanation about why this was closed.
|
||||||
|
var explanation = "";
|
||||||
|
if (evt.reason && evt.reason.length > 0) {
|
||||||
|
explanation = "reason: " + evt.reason;
|
||||||
|
} else {
|
||||||
|
explanation = "without a reason specified";
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Disconnected with close code " + evt.code + " and " + explanation);
|
||||||
|
setTimeout(connect, 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
socket.onmessage = function(event) {
|
||||||
|
console.log(event.data.toString());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
connect();
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user