1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 08:27:12 -07:00

Make KobaltServer more resilient.

This commit is contained in:
Cedric Beust 2016-04-23 05:16:50 -08:00
parent 8c13df5be1
commit 1624db10d7

View file

@ -3,6 +3,7 @@ package com.beust.kobalt.app.remote
import com.beust.kobalt.Args import com.beust.kobalt.Args
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.homeDir import com.beust.kobalt.homeDir
import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.remote.CommandData import com.beust.kobalt.internal.remote.CommandData
import com.beust.kobalt.internal.remote.ICommandSender import com.beust.kobalt.internal.remote.ICommandSender
import com.beust.kobalt.internal.remote.PingCommand import com.beust.kobalt.internal.remote.PingCommand
@ -19,8 +20,8 @@ import java.util.*
import javax.inject.Inject import javax.inject.Inject
@Singleton @Singleton
public class KobaltServer @Inject constructor(val args: Args) : Runnable, ICommandSender { public class KobaltServer @Inject constructor(val args: Args, val pluginInfo: PluginInfo) : Runnable, ICommandSender {
var outgoing: PrintWriter? = null // var outgoing: PrintWriter? = null
val pending = arrayListOf<CommandData>() val pending = arrayListOf<CommandData>()
private val COMMAND_CLASSES = listOf(GetDependenciesCommand::class.java, PingCommand::class.java) private val COMMAND_CLASSES = listOf(GetDependenciesCommand::class.java, PingCommand::class.java)
@ -30,8 +31,11 @@ public class KobaltServer @Inject constructor(val args: Args) : Runnable, IComma
override fun run() { override fun run() {
try { try {
createServerFile(args.port) if (createServerFile(args.port)) {
privateRun() privateRun()
}
} catch(ex: Exception) {
ex.printStackTrace()
} finally { } finally {
deleteServerFile() deleteServerFile()
} }
@ -40,11 +44,17 @@ public class KobaltServer @Inject constructor(val args: Args) : Runnable, IComma
val SERVER_FILE = KFiles.joinDir(homeDir(KFiles.KOBALT_DOT_DIR, "kobaltServer.properties")) val SERVER_FILE = KFiles.joinDir(homeDir(KFiles.KOBALT_DOT_DIR, "kobaltServer.properties"))
val KEY_PORT = "port" val KEY_PORT = "port"
private fun createServerFile(port: Int) { private fun createServerFile(port: Int) : Boolean {
Properties().apply { if (File(SERVER_FILE).exists()) {
put(KEY_PORT, port.toString()) log(1, "Server file $SERVER_FILE already exists, is another server running?")
}.store(FileWriter(SERVER_FILE), "") return false
log(2, "KobaltServer created $SERVER_FILE") } else {
Properties().apply {
put(KEY_PORT, port.toString())
}.store(FileWriter(SERVER_FILE), "")
log(2, "KobaltServer created $SERVER_FILE")
return true
}
} }
private fun deleteServerFile() { private fun deleteServerFile() {
@ -52,15 +62,35 @@ public class KobaltServer @Inject constructor(val args: Args) : Runnable, IComma
File(SERVER_FILE).delete() File(SERVER_FILE).delete()
} }
lateinit var serverInfo: ServerInfo
class ServerInfo(val port: Int) {
lateinit var reader: BufferedReader
lateinit var writer: PrintWriter
var serverSocket : ServerSocket? = null
init {
reset()
}
fun reset() {
if (serverSocket != null) {
serverSocket!!.close()
}
serverSocket = ServerSocket(port)
var clientSocket = serverSocket!!.accept()
reader = BufferedReader(InputStreamReader(clientSocket.inputStream))
writer = PrintWriter(clientSocket.outputStream, true)
}
}
private fun privateRun() { private fun privateRun() {
val portNumber = args.port val portNumber = args.port
log(1, "Listening to port $portNumber") log(1, "Listening to port $portNumber")
var quit = false var quit = false
val serverSocket = ServerSocket(portNumber) serverInfo = ServerInfo(portNumber)
var clientSocket = serverSocket.accept()
while (!quit) { while (!quit) {
outgoing = PrintWriter(clientSocket.outputStream, true)
if (pending.size > 0) { if (pending.size > 0) {
log(1, "Emptying the queue, size $pending.size()") log(1, "Emptying the queue, size $pending.size()")
synchronized(pending) { synchronized(pending) {
@ -68,10 +98,9 @@ public class KobaltServer @Inject constructor(val args: Args) : Runnable, IComma
pending.clear() pending.clear()
} }
} }
val ins = BufferedReader(InputStreamReader(clientSocket.inputStream))
var commandName: String? = null var commandName: String? = null
try { try {
var line = ins.readLine() var line = serverInfo.reader.readLine()
while (!quit && line != null) { while (!quit && line != null) {
log(1, "Received from client $line") log(1, "Received from client $line")
val jo = JsonParser().parse(line) as JsonObject val jo = JsonParser().parse(line) as JsonObject
@ -85,15 +114,15 @@ public class KobaltServer @Inject constructor(val args: Args) : Runnable, IComma
// Done, send a quit to the client // Done, send a quit to the client
sendData(CommandData("quit", "")) sendData(CommandData("quit", ""))
line = ins.readLine() line = serverInfo.reader.readLine()
} }
} }
if (line == null) { if (line == null) {
quit = true serverInfo.reset()
} }
} catch(ex: SocketException) { } catch(ex: SocketException) {
log(1, "Client disconnected, resetting") log(1, "Client disconnected, resetting")
clientSocket = serverSocket.accept() serverInfo.reset()
} catch(ex: Throwable) { } catch(ex: Throwable) {
ex.printStackTrace() ex.printStackTrace()
if (commandName != null) { if (commandName != null) {
@ -101,6 +130,8 @@ public class KobaltServer @Inject constructor(val args: Args) : Runnable, IComma
} }
log(1, "Command failed: ${ex.message}") log(1, "Command failed: ${ex.message}")
} }
pluginInfo.shutdown()
} }
} }
@ -115,8 +146,8 @@ public class KobaltServer @Inject constructor(val args: Args) : Runnable, IComma
override fun sendData(commandData: CommandData) { override fun sendData(commandData: CommandData) {
val content = Gson().toJson(commandData) val content = Gson().toJson(commandData)
if (outgoing != null) { if (serverInfo.writer != null) {
outgoing!!.println(content) serverInfo.writer!!.println(content)
} else { } else {
log(1, "Queuing $content") log(1, "Queuing $content")
synchronized(pending) { synchronized(pending) {