mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-03 13:31:32 +00:00
DevUpdate Server for Test Server Updates
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
package cloud.kubelet.foundation.core
|
package cloud.kubelet.foundation.core
|
||||||
|
|
||||||
import cloud.kubelet.foundation.core.command.*
|
import cloud.kubelet.foundation.core.command.*
|
||||||
|
import cloud.kubelet.foundation.core.devupdate.DevUpdateServer
|
||||||
import cloud.kubelet.foundation.core.persist.PersistentStore
|
import cloud.kubelet.foundation.core.persist.PersistentStore
|
||||||
import cloud.kubelet.foundation.core.persist.setAllProperties
|
import cloud.kubelet.foundation.core.persist.setAllProperties
|
||||||
import io.papermc.paper.event.player.AsyncChatEvent
|
import io.papermc.paper.event.player.AsyncChatEvent
|
||||||
@ -19,6 +20,8 @@ import java.util.concurrent.ConcurrentHashMap
|
|||||||
class FoundationCorePlugin : JavaPlugin(), Listener {
|
class FoundationCorePlugin : JavaPlugin(), Listener {
|
||||||
internal val persistentStores = ConcurrentHashMap<String, PersistentStore>()
|
internal val persistentStores = ConcurrentHashMap<String, PersistentStore>()
|
||||||
private lateinit var _pluginDataPath: Path
|
private lateinit var _pluginDataPath: Path
|
||||||
|
private lateinit var chatLogStore: PersistentStore
|
||||||
|
private lateinit var devUpdateServer: DevUpdateServer
|
||||||
|
|
||||||
var pluginDataPath: Path
|
var pluginDataPath: Path
|
||||||
/**
|
/**
|
||||||
@ -40,8 +43,6 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
|||||||
*/
|
*/
|
||||||
fun getPersistentStore(name: String) = persistentStores.getOrPut(name) { PersistentStore(this, name) }
|
fun getPersistentStore(name: String) = persistentStores.getOrPut(name) { PersistentStore(this, name) }
|
||||||
|
|
||||||
private lateinit var chatLogStore: PersistentStore
|
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
pluginDataPath = dataFolder.toPath()
|
pluginDataPath = dataFolder.toPath()
|
||||||
val backupPath = pluginDataPath.resolve(BACKUPS_DIRECTORY)
|
val backupPath = pluginDataPath.resolve(BACKUPS_DIRECTORY)
|
||||||
@ -67,11 +68,14 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
|||||||
log.info("Features:")
|
log.info("Features:")
|
||||||
Util.printFeatureStatus(log, "Backup", BACKUP_ENABLED)
|
Util.printFeatureStatus(log, "Backup", BACKUP_ENABLED)
|
||||||
chatLogStore = getPersistentStore("chat-logs")
|
chatLogStore = getPersistentStore("chat-logs")
|
||||||
|
devUpdateServer = DevUpdateServer(this)
|
||||||
|
devUpdateServer.enable()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDisable() {
|
override fun onDisable() {
|
||||||
persistentStores.values.forEach { store -> store.close() }
|
persistentStores.values.forEach { store -> store.close() }
|
||||||
persistentStores.clear()
|
persistentStores.clear()
|
||||||
|
devUpdateServer.disable()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerCommandExecutor(name: String, executor: CommandExecutor) {
|
private fun registerCommandExecutor(name: String, executor: CommandExecutor) {
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package cloud.kubelet.foundation.core.devupdate
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class DevUpdateConfig(
|
||||||
|
val port: Int = 8484,
|
||||||
|
val token: String,
|
||||||
|
val ipAllowList: List<String> = listOf("*")
|
||||||
|
)
|
@ -0,0 +1,89 @@
|
|||||||
|
package cloud.kubelet.foundation.core.devupdate
|
||||||
|
|
||||||
|
import cloud.kubelet.foundation.core.FoundationCorePlugin
|
||||||
|
import cloud.kubelet.foundation.core.Util
|
||||||
|
import com.charleskorn.kaml.Yaml
|
||||||
|
import com.sun.net.httpserver.HttpExchange
|
||||||
|
import com.sun.net.httpserver.HttpServer
|
||||||
|
import java.net.InetSocketAddress
|
||||||
|
import kotlin.io.path.inputStream
|
||||||
|
|
||||||
|
class DevUpdateServer(val plugin: FoundationCorePlugin) {
|
||||||
|
private lateinit var config: DevUpdateConfig
|
||||||
|
private var server: HttpServer? = null
|
||||||
|
|
||||||
|
fun enable() {
|
||||||
|
val configPath = Util.copyDefaultConfig<FoundationCorePlugin>(
|
||||||
|
plugin.slF4JLogger,
|
||||||
|
plugin.pluginDataPath,
|
||||||
|
"devupdate.yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
config = Yaml.default.decodeFromStream(DevUpdateConfig.serializer(), configPath.inputStream())
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun start() {
|
||||||
|
if (config.token.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.token.length < 8) {
|
||||||
|
plugin.slF4JLogger.warn("DevUpdate Token was too short (must be 8 or more characters)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val server = HttpServer.create()
|
||||||
|
server.createContext("/").setHandler { exchange ->
|
||||||
|
val ip = exchange.remoteAddress.address.hostAddress
|
||||||
|
if (!config.ipAllowList.contains("*") && !config.ipAllowList.contains(ip)) {
|
||||||
|
plugin.slF4JLogger.warn("DevUpdate Server received request from IP $ip which is not allowed.")
|
||||||
|
exchange.close()
|
||||||
|
return@setHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.slF4JLogger.info("DevUpdate Server Request $ip ${exchange.requestMethod} ${exchange.requestURI.path}")
|
||||||
|
if (exchange.requestMethod != "POST") {
|
||||||
|
exchange.respond(405, "Method not allowed.")
|
||||||
|
return@setHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange.requestURI.path != "/webhook/update") {
|
||||||
|
exchange.respond(404, "Not Found.")
|
||||||
|
return@setHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exchange.requestURI.query != config.token) {
|
||||||
|
exchange.respond(401, "Unauthorized.")
|
||||||
|
return@setHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange.respond(200, "Success.")
|
||||||
|
plugin.server.scheduler.runTask(plugin) { ->
|
||||||
|
plugin.slF4JLogger.info("DevUpdate Server Restart")
|
||||||
|
try {
|
||||||
|
plugin.server.dispatchCommand(plugin.server.consoleSender, "fupdate")
|
||||||
|
plugin.server.dispatchCommand(plugin.server.consoleSender, "stop")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
plugin.slF4JLogger.error("DevUpdate Server failed to update server.", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server.bind(InetSocketAddress("0.0.0.0", config.port), 0)
|
||||||
|
server.start()
|
||||||
|
this.server = server
|
||||||
|
plugin.slF4JLogger.info("DevUpdate Server listening on port ${config.port}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disable() {
|
||||||
|
server?.stop(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun HttpExchange.respond(code: Int, content: String) {
|
||||||
|
val encoded = content.encodeToByteArray()
|
||||||
|
sendResponseHeaders(code, encoded.size.toLong())
|
||||||
|
responseBody.write(encoded)
|
||||||
|
responseBody.close()
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
12
foundation-core/src/main/resources/devupdate.yaml
Normal file
12
foundation-core/src/main/resources/devupdate.yaml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Server port to listen on.
|
||||||
|
port: 8484
|
||||||
|
|
||||||
|
# An authentication token. Should be random and 8 or more characters.
|
||||||
|
# If empty, the DevUpdate server is not enabled.
|
||||||
|
token: ""
|
||||||
|
|
||||||
|
# IP address allow list.
|
||||||
|
# If * is specified, all addresses are allowed.
|
||||||
|
# Specify IP addresses as a string that should be allowed to update the server.
|
||||||
|
ipAllowList:
|
||||||
|
- "*"
|
Reference in New Issue
Block a user