This commit is contained in:
2023-04-16 09:31:37 +08:00
parent c534b9508b
commit 31109849fe
30 changed files with 369 additions and 144 deletions
-10
View File
@@ -1,10 +0,0 @@
import cc.maxmc.msm.child.misc.SubServer
import kotlin.io.path.Path
suspend fun main() {
val server = SubServer(10086, "test", 25571, Path("/Users/tony_all/Servers/MSM/"))
server.initServer()
server.startServer()
Thread.sleep(10000)
server.cleanup()
}
@@ -2,9 +2,10 @@ package cc.maxmc.msm.child
import cc.maxmc.msm.api.MultiServerManAPIProvider
import cc.maxmc.msm.child.api.APIImpl
import cc.maxmc.msm.child.api.APIPacketListener
import cc.maxmc.msm.child.listener.APIPacketListener
import cc.maxmc.msm.child.command.Api
import cc.maxmc.msm.child.command.Send
import cc.maxmc.msm.child.listener.ProtocolListener
import cc.maxmc.msm.child.netty.NetClient
import cc.maxmc.msm.child.settings.Settings
import cc.maxmc.msm.common.network.netty.NetworkRegistry
@@ -21,8 +22,9 @@ class MultiServerMan : Plugin() {
ProxyServer.getInstance().pluginManager.registerCommand(this, Send)
ProxyServer.getInstance().pluginManager.registerCommand(this, Api)
ProxyServer.getInstance().pluginManager.registerListener(this, APIPacketListener)
ProxyServer.getInstance().pluginManager.registerListener(this, ProtocolListener)
NetworkRegistry
NetClient.start(Settings.Parent.address, Settings.Parent.port)
NetClient.init(Settings.Parent.address, Settings.Parent.port)
}
override fun onDisable() {
@@ -1,7 +1,7 @@
package cc.maxmc.msm.child.api
import cc.maxmc.msm.api.MultiServerManAPI
import cc.maxmc.msm.api.misc.ServerInfo
import cc.maxmc.msm.api.misc.MatchInfo
import cc.maxmc.msm.child.netty.NetClient
import cc.maxmc.msm.common.network.packet.PPacketAPICall
import java.util.*
@@ -13,10 +13,10 @@ object APIImpl : MultiServerManAPI {
val apiCallCache = HashMap<UUID, CompletableFuture<in Any>>()
private const val TIMEOUT = 3L
override fun getServer(type: String, players: MutableList<String>): ServerInfo {
override fun getServer(type: String, players: MutableList<String>): MatchInfo {
val packet = PPacketAPICall.PPacketCallGetServer(type, players)
NetClient.sendPacket(packet)
val future = CompletableFuture<ServerInfo>()
val future = CompletableFuture<MatchInfo>()
apiCallCache[packet.uid] = future as CompletableFuture<Any>
return future.get(TIMEOUT, TimeUnit.SECONDS)
}
@@ -30,10 +30,10 @@ object APIImpl : MultiServerManAPI {
return
}
override fun getPlayerServer(player: String): ServerInfo {
override fun getPlayerServer(player: String): MatchInfo {
val packet = PPacketAPICall.PPacketCallGetPlayerServer(player)
NetClient.sendPacket(packet)
val future = CompletableFuture<ServerInfo>()
val future = CompletableFuture<MatchInfo>()
apiCallCache[packet.uid] = future as CompletableFuture<Any>
return future.get(TIMEOUT, TimeUnit.SECONDS)
}
@@ -1,8 +1,8 @@
package cc.maxmc.msm.child.api
package cc.maxmc.msm.child.listener
import cc.maxmc.msm.child.api.APIImpl
import cc.maxmc.msm.common.event.PacketReceiveEvent
import cc.maxmc.msm.common.network.packet.CPacketAPICallback
import cc.maxmc.msm.common.utils.debug
import net.md_5.bungee.api.plugin.Listener
import net.md_5.bungee.event.EventHandler
@@ -21,12 +21,12 @@ object APIPacketListener : Listener {
}
is CPacketAPICallback.CPacketCallbackGetPlayerServer -> {
future?.complete(packet.serverInfo)
future?.complete(packet.matchInfo)
?: throw IllegalStateException("Packet callback received, however no request")
}
is CPacketAPICallback.CPacketCallbackGetServer -> {
future?.complete(packet.serverInfo)
future?.complete(packet.matchInfo)
?: throw IllegalStateException("Packet callback received, however no request")
}
@@ -0,0 +1,53 @@
package cc.maxmc.msm.child.listener
import cc.maxmc.msm.child.MultiServerMan
import cc.maxmc.msm.child.misc.SubServer
import cc.maxmc.msm.child.netty.NetClient
import cc.maxmc.msm.child.settings.Settings
import cc.maxmc.msm.common.event.ChannelInactiveEvent
import cc.maxmc.msm.common.event.PacketReceiveEvent
import cc.maxmc.msm.common.network.packet.CPacketGetInfo
import cc.maxmc.msm.common.network.packet.CPacketRequestServer
import cc.maxmc.msm.common.network.packet.PPacketChildInfo
import cc.maxmc.msm.common.network.packet.PPacketServerStarted
import cc.maxmc.msm.common.utils.log
import cc.maxmc.msm.common.utils.pluginScope
import kotlinx.coroutines.launch
import net.md_5.bungee.api.plugin.Listener
import net.md_5.bungee.event.EventHandler
import java.util.*
import kotlin.io.path.isDirectory
import kotlin.io.path.listDirectoryEntries
import kotlin.io.path.name
object ProtocolListener : Listener {
val serverCache = HashMap<UUID, SubServer>()
@EventHandler
fun onGetInfo(packetE: PacketReceiveEvent) {
if (packetE.packet !is CPacketGetInfo) return
val types = MultiServerMan.instance.dataFolder.toPath().resolve("patterns").listDirectoryEntries()
.filter { it.isDirectory() }.map { it.name }.toMutableSet()
val packetCallBack = PPacketChildInfo(Settings.portRange.toHashSet(), types)
NetClient.sendPacket(packetCallBack)
}
@EventHandler
fun onRequestServer(packetE: PacketReceiveEvent) {
val packet = packetE.packet as? CPacketRequestServer ?: return
val serverInfo = packet.serverInfo
val subServer = SubServer(serverInfo.uid, packet.type, serverInfo.server!!.split(":")[1].toInt())
pluginScope.launch {
subServer.initServer()
subServer.startServer()
NetClient.sendPacket(PPacketServerStarted(serverInfo))
}
}
fun onDisconnect(packet: ChannelInactiveEvent) {
repeat(10) {
log("Remote Disconnected.")
}
}
}
@@ -5,18 +5,19 @@ import cc.maxmc.msm.child.utils.ScriptRunner
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.nio.file.Path
import java.util.*
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlin.io.path.copyToRecursively
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteRecursively
@OptIn(kotlin.io.path.ExperimentalPathApi::class)
class SubServer(
val id: Int,
val type: String,
val port: Int,
baseFolder: Path = MultiServerMan.instance.dataFolder.toPath()
val uid: UUID, val type: String, val port: Int, baseFolder: Path = MultiServerMan.instance.dataFolder.toPath()
) {
private val serverFolder = baseFolder.resolve("cache").resolve(id.toString()).also { it.createDirectories() }
private val serverFolder =
baseFolder.resolve("cache").resolve(uid.toString().substring(0..7)).also { it.createDirectories() }
private val patternFolder = baseFolder.resolve("pattern").resolve(type).also { it.createDirectories() }
private val runner = ScriptRunner(serverFolder.resolve("start.sh"))
@@ -24,16 +25,15 @@ class SubServer(
patternFolder.copyToRecursively(serverFolder, followLinks = false, overwrite = true)
}
fun startServer() {
suspend fun startServer() = suspendCoroutine {
runner.launch(port.toString())
runner.onOutput("For help, type \"help\" or \"?\"") {
println("Started.")
it.resume(Unit)
}
}
suspend fun cleanup() {
runner.exec("stop")
println("Exec stop")
runner.exit()
serverFolder.deleteRecursively()
}
@@ -2,34 +2,45 @@ package cc.maxmc.msm.child.netty
import cc.maxmc.msm.common.network.BungeePacket
import cc.maxmc.msm.common.network.netty.NetworkRegistry
import cc.maxmc.msm.common.utils.log
import cc.maxmc.msm.common.utils.pipelineInit
import cc.maxmc.msm.common.utils.pluginScope
import io.netty.bootstrap.Bootstrap
import io.netty.channel.Channel
import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelOption
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioSocketChannel
import kotlinx.coroutines.*
object NetClient {
private val loop = NioEventLoopGroup()
private lateinit var channel: Channel
private lateinit var boot: Bootstrap
fun start(address: String, port: Int) {
val future = Bootstrap()
.channel(NioSocketChannel::class.java)
.group(loop)
.handler(pipelineInit(NetworkRegistry.PacketDirection.CHILD_BOUND))
.option(ChannelOption.TCP_NODELAY, true)
fun init(address: String, port: Int) {
boot = Bootstrap().channel(NioSocketChannel::class.java).group(loop)
.handler(pipelineInit(NetworkRegistry.PacketDirection.CHILD_BOUND)).option(ChannelOption.TCP_NODELAY, true)
.remoteAddress(address, port)
.connect().addListener(ChannelFutureListener {
val result = it.cause() ?: return@ChannelFutureListener println(
"§a| §7成功连接到集群的主节点. (${
it.channel().remoteAddress()
})"
)
result.printStackTrace()
})
channel = future.channel()
runBlocking {
connect(0)
}
}
private suspend fun connect(delay: Long = 3000) {
delay(delay)
log("§b| §7正在尝试连接主BC")
val future = boot.connect().await()
val result = future.cause()
if (result == null) {
channel = future.channel()
log("§a| §7成功连接到集群的主节点. (${future.channel().remoteAddress()})")
return
}
log("§c| §7未能连接到主BC,将在 §c3s §7后重新连接。(原因: ${result.message})")
withContext(Dispatchers.IO) {
connect()
}
}
fun sendPacket(packet: BungeePacket) {
+8 -1
View File
@@ -1,7 +1,14 @@
# 主BC的地址及端口
parent:
address: 127.0.0.1
port: 23333
# 该子BC所在机器所能开放的端口
ports:
- 30000
- 30001..30019
- 30443
# 该子BC所支持的服务端模版类型及模版类型启动所需参数
patterns:
main:
args: [ "-ListenPort=${port}", "-usr=usr", "-pwd=pwd" ]