release 1.2.1

proxy logger calls


fix Exception on startup with invalid / default connection data


also fix Exception when closing Server
release 1.2.1


Merge branch 'dev'
This commit is contained in:
NikkyAI 2018-02-11 03:55:54 +01:00
parent 087d516e3e
commit 1b82b037d6
12 changed files with 165 additions and 71 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@
.idea .idea
out out
build build
classes
#eclipse #eclipse
.project .project

View File

@ -1,5 +1,6 @@
package matterlink package matterlink
import jline.internal.Log
import matterlink.bridge.MessageHandler import matterlink.bridge.MessageHandler
import matterlink.bridge.command.BridgeCommandRegistry import matterlink.bridge.command.BridgeCommandRegistry
import matterlink.bridge.command.HelpCommand import matterlink.bridge.command.HelpCommand
@ -9,6 +10,7 @@ import net.minecraft.util.text.TextComponentString
import net.minecraftforge.fml.common.FMLCommonHandler import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.event.* import net.minecraftforge.fml.common.event.*
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.Logger import org.apache.logging.log4j.Logger
const val MODID = "matterlink" const val MODID = "matterlink"
@ -71,4 +73,6 @@ object MatterLink : IMatterLink() {
return FMLCommonHandler.instance().minecraftServerInstance.playerList.onlinePlayerNames return FMLCommonHandler.instance().minecraftServerInstance.playerList.onlinePlayerNames
} }
override fun log(level: String, formatString: String, vararg data: Any) =
logger.log(Level.toLevel(level, Level.INFO),formatString, *data)
} }

View File

@ -9,6 +9,7 @@ import net.minecraft.util.text.TextComponentString
import net.minecraftforge.fml.common.FMLCommonHandler import net.minecraftforge.fml.common.FMLCommonHandler
import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.event.* import net.minecraftforge.fml.common.event.*
import org.apache.logging.log4j.Level
import org.apache.logging.log4j.Logger import org.apache.logging.log4j.Logger
const val MODID = "matterlink" const val MODID = "matterlink"
@ -45,7 +46,7 @@ object MatterLink : IMatterLink() {
@Mod.EventHandler @Mod.EventHandler
fun serverAboutToStart(event: FMLServerAboutToStartEvent) { fun serverAboutToStart(event: FMLServerAboutToStartEvent) {
MessageHandler.start(clear = true) // MessageHandler.start(clear = true)
} }
@Mod.EventHandler @Mod.EventHandler
@ -71,4 +72,6 @@ object MatterLink : IMatterLink() {
return FMLCommonHandler.instance().minecraftServerInstance.playerList.onlinePlayerNames return FMLCommonHandler.instance().minecraftServerInstance.playerList.onlinePlayerNames
} }
override fun log(level: String, formatString: String, vararg data: Any) =
logger.log(Level.toLevel(level, Level.INFO),formatString, *data)
} }

View File

@ -1,39 +1,31 @@
package matterlink package matterlink
import matterlink.bridge.MessageHandler import matterlink.bridge.MessageHandler
//import org.apache.logging.log4j.Logger
lateinit var instance: IMatterLink lateinit var instance: IMatterLink
//lateinit var logger: Logger
abstract class IMatterLink { abstract class IMatterLink {
var interrupted: Boolean = false // var interrupted: Boolean = false
abstract fun wrappedSendToPlayers(msg: String) abstract fun wrappedSendToPlayers(msg: String)
abstract fun wrappedPlayerList(): Array<String> abstract fun wrappedPlayerList(): Array<String>
fun connect() { fun connect() {
if (MessageHandler.start(clear = true)) { MessageHandler.start(clear = true)
println("Connected to matterbridge relay")
} else {
System.err.println("Connection to matterbridge relay failed.")
}
} }
fun disconnect() { fun disconnect() {
MessageHandler.stop() MessageHandler.stop()
} }
abstract fun log(level: String, formatString: String, vararg data: Any)
fun fatal(formatString: String, vararg data: Any) = log(Level.FATAL.name, formatString, *data)
fun error(formatString: String, vararg data: Any) = log(Level.ERROR.name, formatString, *data)
fun warn(formatString: String, vararg data: Any) = log(Level.WARN.name, formatString, *data)
fun info(formatString: String, vararg data: Any) = log(Level.INFO.name, formatString, *data)
fun debug(formatString: String, vararg data: Any) = log(Level.DEBUG.name, formatString, *data)
fun trace(formatString: String, vararg data: Any) = log(Level.TRACE.name, formatString, *data)
fun reconnect(tick: Int) {
if(tick % 20 == 0 && interrupted) {
println("Trying to reconnect")
if (MessageHandler.start(clear = false)) {
println("Reconnected to matterbridge relay")
} else {
System.err.println("Reconnection to matterbridge relay failed.")
}
}
}
} }

View File

@ -0,0 +1,38 @@
package matterlink
enum class Level(val level: Int) {
/**
* No events will be logged.
*/
OFF(0),
/**
* A severe error that will prevent the application from continuing.
*/
FATAL(1),
/**
* An error in the application, possibly recoverable.
*/
ERROR(2),
/**
* An event that might possible lead to an error.
*/
WARN(3),
/**
* An event for informational purposes.
*/
INFO(4),
/**
* A general debugging event.
*/
DEBUG(5),
/**
* A fine-grained debug message, typically capturing the flow through the application.
*/
TRACE(6),
}

View File

@ -1,7 +1,6 @@
package matterlink.bridge; package matterlink.bridge;
import matterlink.instance import matterlink.instance
//import matterlink.logger
import org.apache.http.client.methods.HttpGet import org.apache.http.client.methods.HttpGet
import org.apache.http.impl.client.HttpClients import org.apache.http.impl.client.HttpClients
import java.io.InputStream import java.io.InputStream
@ -9,7 +8,13 @@ import java.net.SocketException
val BUFFER_SIZE = 1000 val BUFFER_SIZE = 1000
class HttpStreamConnection(getClosure: () -> HttpGet, clearClosure: () -> HttpGet, private val mhandler: (String) -> Unit, private val onClose: () -> Unit, private val clear: Boolean = true) : Thread() { class HttpStreamConnection(getClosure: () -> HttpGet,
clearClosure: () -> HttpGet,
private val mhandler: (String) -> Unit,
private val onClose: () -> Unit,
private val setSuccess: (Boolean) -> Unit,
private val clear: Boolean = true
) : Thread() {
private val client = HttpClients.createDefault() private val client = HttpClients.createDefault()
private var stream: InputStream? = null private var stream: InputStream? = null
@ -18,28 +23,36 @@ class HttpStreamConnection(getClosure: () -> HttpGet, clearClosure: () -> HttpGe
var cancelled: Boolean = false var cancelled: Boolean = false
private set private set
override fun run() { override fun run() {
instance.interrupted = false
if (clear) { if (clear) {
val r = client.execute(clearGet) val r = client.execute(clearGet)
r.entity.content.bufferedReader().forEachLine { r.entity.content.bufferedReader().forEachLine {
println("DEBUG: skipping $it") instance.debug("skipping $it")
} }
} }
try {
val response = client.execute(get) val response = client.execute(get)
if (response.statusLine.statusCode != 200) {
instance.error("Bridge Connection rejected... status code ${response.statusLine.statusCode}")
setSuccess(false) //TODO: pass message
onClose()
return
} else {
setSuccess(true) //TODO: pass message
}
val content = response.entity.content.buffered() val content = response.entity.content.buffered()
stream = content stream = content
//val reader = content.bufferedReader()
var buffer = "" var buffer = ""
val buf = ByteArray(BUFFER_SIZE) val buf = ByteArray(BUFFER_SIZE)
try { instance.info("initialized buffer")
while (!get.isAborted) { while (!get.isAborted) {
val chars = content.read(buf) val chars = content.read(buf)
if (chars > 0) { if (chars > 0) {
buffer += String(buf.dropLast(buf.count() - chars).toByteArray()) buffer += String(buf.dropLast(buf.count() - chars).toByteArray())
println("DEBUG: " + buffer) instance.debug(buffer)
while (buffer.contains("\n")) { while (buffer.contains("\n")) {
val line = buffer.substringBefore("\n") val line = buffer.substringBefore("\n")
@ -50,17 +63,20 @@ class HttpStreamConnection(getClosure: () -> HttpGet, clearClosure: () -> HttpGe
break break
} }
} }
} catch (e: SocketException) {
if (!cancelled) { instance.debug("closing stream")
System.err.println("Bridge Connection interrupted...")
instance.interrupted = true
//TODO: mark connection as interrupted and try to reconnect
}
}
println("DEBUG: closing stream")
content.close() content.close()
println("DEBUG: thread finished")
} catch (e: SocketException) {
instance.info("error {}", e)
if (!cancelled) {
instance.error("Bridge Connection interrupted...")
setSuccess(false)
}
} finally {
instance.debug("thread finished")
onClose() onClose()
}
return return
} }

View File

@ -1,7 +1,7 @@
package matterlink.bridge package matterlink.bridge
import matterlink.config.cfg import matterlink.config.cfg
//import matterlink.logger import matterlink.instance
import org.apache.http.client.methods.HttpGet import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpRequestBase import org.apache.http.client.methods.HttpRequestBase
@ -9,11 +9,15 @@ import org.apache.http.entity.ContentType
import org.apache.http.entity.StringEntity import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.HttpClients import org.apache.http.impl.client.HttpClients
import java.io.IOException import java.io.IOException
import java.net.SocketException
import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.ConcurrentLinkedQueue
object MessageHandler { object MessageHandler {
private var connected = false var connected = false
private var connecting = false
private var enabled = true
private var connectErrors = 0
private var sendErrors = 0 private var sendErrors = 0
private var streamConnection: HttpStreamConnection private var streamConnection: HttpStreamConnection
var rcvQueue = ConcurrentLinkedQueue<ApiMessage>() var rcvQueue = ConcurrentLinkedQueue<ApiMessage>()
@ -30,7 +34,7 @@ object MessageHandler {
} }
private fun createThread(clear: Boolean = true): HttpStreamConnection { private fun createThread(clear: Boolean = true): HttpStreamConnection {
println("Attempting to open bridge connection.") instance.info("Attempting to open bridge connection.")
return HttpStreamConnection( return HttpStreamConnection(
{ {
HttpGet(cfg!!.connect.url + "/api/stream").apply { HttpGet(cfg!!.connect.url + "/api/stream").apply {
@ -46,11 +50,23 @@ object MessageHandler {
rcvQueue.add( rcvQueue.add(
ApiMessage.decode(it) ApiMessage.decode(it)
) )
// println("Received: " + it) instance.debug("Received: " + it)
}, },
{ {
println("Bridge connection closed!") instance.warn("Bridge connection closed!")
connected = false connected = false
connecting = false
},
{ success ->
connecting = false
if (success) {
instance.info("connected successfully")
connectErrors = 0
connected = true
} else {
connectErrors++
connected = false
}
}, },
clear clear
) )
@ -58,27 +74,32 @@ object MessageHandler {
fun transmit(msg: ApiMessage) { fun transmit(msg: ApiMessage) {
if (connected && streamConnection.isAlive) { if (connected && streamConnection.isAlive) {
println("Transmitting: " + msg) instance.debug("Transmitting: " + msg)
transmitMessage(msg) transmitMessage(msg)
} }
} }
fun stop() { fun stop() {
println("Closing bridge connection...") enabled = false
instance.info("Closing bridge connection...")
// MessageHandler.transmit(ApiMessage(text="bridge closing", username="Server")) // MessageHandler.transmit(ApiMessage(text="bridge closing", username="Server"))
try {
streamConnection.close() streamConnection.close()
} catch(e: SocketException) {
instance.error("exception: $e")
}
} }
fun start(clear: Boolean = true): Boolean { fun start(clear: Boolean = true) {
enabled = true
if (!connected) if (!connected)
streamConnection = createThread(clear) streamConnection = createThread(clear)
if (!streamConnection.isAlive) { if (!streamConnection.isAlive) {
connecting = true
streamConnection.start() streamConnection.start()
// MessageHandler.transmit(ApiMessage(text="bridge connected", username="Server")) // MessageHandler.transmit(ApiMessage(text="bridge connected", username="Server"))
connected = true
return connected
} }
return connected
} }
private fun transmitMessage(message: ApiMessage) { private fun transmitMessage(message: ApiMessage) {
@ -93,17 +114,36 @@ object MessageHandler {
val response = client.execute(post) val response = client.execute(post)
val code = response.statusLine.statusCode val code = response.statusLine.statusCode
if (code != 200) { if (code != 200) {
System.err.println("Server returned $code for $post") instance.error("Server returned $code for $post")
sendErrors++
if (sendErrors > 5) {
instance.error("caught too many errors, closing bridge")
stop()
}
} }
sendErrors = 0 sendErrors = 0
} catch (e: IOException) { } catch (e: IOException) {
System.err.println("sending message caused $e") instance.error("sending message caused $e")
sendErrors++ sendErrors++
if (sendErrors > 5) { if (sendErrors > 5) {
System.err.println("caught too many errors, closing bridge") instance.error("caught too many errors, closing bridge")
stop() stop()
} }
} }
} }
fun checkConnection(tick: Int) {
if (enabled && tick % 20 == 0 && !MessageHandler.connected && !connecting) {
if (connectErrors > 5) {
instance.fatal("caught too many errors, closing bridge")
stop()
return
}
instance.info("Trying to reconnect")
MessageHandler.start(clear = false)
}
}
} }

View File

@ -1,6 +1,5 @@
package matterlink.bridge package matterlink.bridge
//import matterlink.logger
import matterlink.instance import matterlink.instance
import matterlink.bridge.command.BridgeCommandRegistry import matterlink.bridge.command.BridgeCommandRegistry
import matterlink.config.cfg import matterlink.config.cfg
@ -11,14 +10,13 @@ object ServerChatHandler {
* This method must be called every server tick with no arguments. * This method must be called every server tick with no arguments.
*/ */
fun writeIncomingToChat(tick: Int) { fun writeIncomingToChat(tick: Int) {
instance.reconnect(tick) MessageHandler.checkConnection(tick)
if (MessageHandler.rcvQueue.isNotEmpty()) if (MessageHandler.rcvQueue.isNotEmpty())
println("incoming: " + MessageHandler.rcvQueue.toString()) instance.debug("incoming: " + MessageHandler.rcvQueue.toString())
val nextMessage = MessageHandler.rcvQueue.poll() val nextMessage = MessageHandler.rcvQueue.poll()
if (nextMessage != null && nextMessage.gateway == cfg!!.connect.gateway) { if (nextMessage != null && nextMessage.gateway == cfg!!.connect.gateway) {
if (!nextMessage.text.isBlank()) { if (!nextMessage.text.isBlank()) {
val section = '\u00A7'
val message = when (nextMessage.event) { val message = when (nextMessage.event) {
"user_action" -> nextMessage.format(cfg!!.formatting.action) "user_action" -> nextMessage.format(cfg!!.formatting.action)
"" -> { "" -> {
@ -30,11 +28,11 @@ object ServerChatHandler {
val user = nextMessage.username val user = nextMessage.username
val text = nextMessage.text val text = nextMessage.text
val json = nextMessage.encode() val json = nextMessage.encode()
println("Threw out message with unhandled event: ${nextMessage.event}") instance.debug("Threw out message with unhandled event: ${nextMessage.event}")
println(" Message contents:") instance.debug(" Message contents:")
println(" User: $user") instance.debug(" User: $user")
println(" Text: $text") instance.debug(" Text: $text")
println(" JSON: $json") instance.debug(" JSON: $json")
return return
} }
} }

View File

@ -1,7 +1,7 @@
package matterlink.bridge.command package matterlink.bridge.command
import matterlink.config.cfg import matterlink.config.cfg
//import matterlink.logger import matterlink.instance
import java.util.* import java.util.*
object BridgeCommandRegistry { object BridgeCommandRegistry {
@ -23,7 +23,7 @@ object BridgeCommandRegistry {
fun register(cmd: IBridgeCommand): Boolean { fun register(cmd: IBridgeCommand): Boolean {
if (cmd.name.isBlank() || commandMap.containsKey(cmd.name)) { if (cmd.name.isBlank() || commandMap.containsKey(cmd.name)) {
System.out.println("Failed to register command: '${cmd.name}'") instance.info("Failed to register command: '${cmd.name}'")
return false return false
} }
commandMap[cmd.name] = cmd commandMap[cmd.name] = cmd

View File

@ -2,7 +2,7 @@ package matterlink.handlers
import matterlink.bridge.ApiMessage import matterlink.bridge.ApiMessage
import matterlink.bridge.MessageHandler import matterlink.bridge.MessageHandler
//import matterlink.logger import matterlink.instance
object ChatHandler { object ChatHandler {
fun handleChat(user: String, msg: String) { fun handleChat(user: String, msg: String) {
@ -12,7 +12,7 @@ object ChatHandler {
username = user, username = user,
text = message text = message
)) ))
else -> println("WARN: dropped blank message by '$user'") else -> instance.warn("WARN: dropped blank message by '$user'")
} }
} }
} }

View File

@ -4,6 +4,8 @@
"description": "Minecraft Server Matterbridge link", "description": "Minecraft Server Matterbridge link",
"version": "${version}", "version": "${version}",
"mcversion": "${mcversion}", "mcversion": "${mcversion}",
"url": "https://github.com/elytra/MatterLink",
"authorList":["Arcanitor", "NikkyAi"], "authorList":["Arcanitor", "NikkyAi"],
"credits": "Blame Nikky for talking me into this." "credits": "Blame Nikky for talking me into this.",
"dependencies": ["forgelin"]
}] }]

View File

@ -1 +1 @@
mod_version = 1.2 mod_version = 1.2.1