Apply linting and clearer log messages
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
package com.shr4pnel.ferretirc.net
|
package com.shr4pnel.ferretirc.net
|
||||||
|
|
||||||
import com.shr4pnel.ferretirc.net.messages.ServerMessage
|
import com.shr4pnel.ferretirc.net.messages.ServerMessage
|
||||||
|
import com.shr4pnel.ferretirc.net.messages.ServerMessage.*
|
||||||
|
import com.shr4pnel.ferretirc.net.messages.ServerMessage.Numeric.*
|
||||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
import io.github.oshai.kotlinlogging.slf4j.logger
|
import io.github.oshai.kotlinlogging.slf4j.logger
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
@@ -18,7 +20,10 @@ class MessageParser(val incoming: Channel<String>, enableLogging: Boolean = fals
|
|||||||
abstract class Command(open val command: String, open val parameters: List<String>) {
|
abstract class Command(open val command: String, open val parameters: List<String>) {
|
||||||
abstract fun toServerMessage(): ServerMessage
|
abstract fun toServerMessage(): ServerMessage
|
||||||
|
|
||||||
fun getTrailingParameterIndex() = parameters.indexOfFirst { it.startsWith(":") }
|
fun getTrailingParameterIndex(): Int {
|
||||||
|
val index = parameters.indexOfFirst { it.startsWith(":") }
|
||||||
|
return if (index != -1) index else 0
|
||||||
|
}
|
||||||
|
|
||||||
fun getTrailingParameterString() =
|
fun getTrailingParameterString() =
|
||||||
parameters
|
parameters
|
||||||
@@ -26,48 +31,57 @@ class MessageParser(val incoming: Channel<String>, enableLogging: Boolean = fals
|
|||||||
.joinToString(" ")
|
.joinToString(" ")
|
||||||
.removePrefix(":")
|
.removePrefix(":")
|
||||||
|
|
||||||
fun getNonTrailingParameterString() =
|
fun getNonTrailingParameterString(startIndex: Int = 0) =
|
||||||
parameters
|
parameters
|
||||||
.subList(0, getTrailingParameterIndex())
|
.subList(startIndex, getTrailingParameterIndex())
|
||||||
.joinToString(" ")
|
.joinToString(" ")
|
||||||
.removePrefix(":")
|
.removePrefix(":")
|
||||||
|
|
||||||
fun getNonTrailingParameters() = getNonTrailingParameterString().split(" ")
|
fun getNonTrailingParameters() =
|
||||||
|
getNonTrailingParameterString()
|
||||||
|
.split(" ")
|
||||||
|
|
||||||
class NamedCommand(override val command: String, override val parameters: List<String>) : Command(command, parameters) {
|
class NamedCommand(override val command: String, override val parameters: List<String>) : Command(command, parameters) {
|
||||||
override fun toServerMessage() =
|
override fun toServerMessage() =
|
||||||
when (command.uppercase()) {
|
when (command.uppercase()) {
|
||||||
"PONG" -> ServerMessage.Pong(getTrailingParameterString().removePrefix(":"))
|
"PONG" -> Pong(getTrailingParameterString().removePrefix(":"))
|
||||||
|
"MODE" -> Mode(
|
||||||
// TODO MODE, CHANMODE, LOCALMODE
|
parameters.first(), // TODO MODE, CHANMODE, LOCALMODE
|
||||||
"MODE" ->
|
parameters.last().removePrefix(":"),
|
||||||
ServerMessage.Mode(
|
)
|
||||||
parameters.first(),
|
"NOTICE" -> Notice(
|
||||||
parameters.last().removePrefix(":"),
|
getNonTrailingParameters(),
|
||||||
)
|
getTrailingParameterString(),
|
||||||
|
)
|
||||||
"NOTICE" ->
|
"PRIVMSG" -> PrivMsg(
|
||||||
ServerMessage.Notice(
|
getNonTrailingParameters(),
|
||||||
getNonTrailingParameters(),
|
getTrailingParameterString(),
|
||||||
getTrailingParameterString(),
|
)
|
||||||
)
|
"JOIN" -> Join(getTrailingParameterString())
|
||||||
|
"CAP" -> Cap(getTrailingParameterString())
|
||||||
"PRIVMSG" ->
|
"PING" -> Ping(getTrailingParameterString())
|
||||||
ServerMessage.PrivMsg(
|
"ERROR" -> Error(getTrailingParameterString())
|
||||||
getNonTrailingParameters(),
|
else -> UNIMPLEMENTED("$command ${getTrailingParameterString()}")
|
||||||
getTrailingParameterString(),
|
|
||||||
)
|
|
||||||
|
|
||||||
else -> ServerMessage.UNIMPLEMENTED("$command ${parameters.joinToString(" ")}")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NumericCommand(override val command: String, override val parameters: List<String>) : Command(command, parameters) {
|
class NumericCommand(override val command: String, override val parameters: List<String>) : Command(command, parameters) {
|
||||||
private enum class RPL(val underlying: Int) {
|
private enum class RPL(val underlying: Int) {
|
||||||
|
WELCOME(1),
|
||||||
|
YOURHOST(2),
|
||||||
|
CREATED(3),
|
||||||
|
MYINFO(4),
|
||||||
ISUPPORT(5),
|
ISUPPORT(5),
|
||||||
|
BOUNCE(10),
|
||||||
|
STATSCOMMANDS(212),
|
||||||
|
ENDOFSTATS(219),
|
||||||
LISTSTART(321),
|
LISTSTART(321),
|
||||||
LIST(322),
|
LIST(322),
|
||||||
LISTEND(323),
|
LISTEND(323),
|
||||||
|
TOPIC(332),
|
||||||
|
TOPICWHOTIME(333),
|
||||||
|
NAMREPLY(353),
|
||||||
|
ENDOFNAMES(366),
|
||||||
NONE(0xbeef), ;
|
NONE(0xbeef), ;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -79,38 +93,31 @@ class MessageParser(val incoming: Channel<String>, enableLogging: Boolean = fals
|
|||||||
|
|
||||||
override fun toServerMessage() =
|
override fun toServerMessage() =
|
||||||
when (RPL from command) {
|
when (RPL from command) {
|
||||||
RPL.ISUPPORT -> ServerMessage.Numeric.RPL_ISUPPORT(getNonTrailingParameterString())
|
RPL.WELCOME -> RPL_WELCOME(getTrailingParameterString())
|
||||||
RPL.LISTSTART -> ServerMessage.Numeric.RPL_LISTSTART()
|
RPL.YOURHOST -> RPL_YOURHOST(getTrailingParameterString())
|
||||||
RPL.LIST -> ServerMessage.Numeric.RPL_LIST(
|
RPL.CREATED -> RPL_CREATED(getTrailingParameterString())
|
||||||
|
RPL.MYINFO -> RPL_MYINFO(getTrailingParameterString())
|
||||||
|
RPL.BOUNCE -> UNIMPLEMENTED(parameters.toString())
|
||||||
|
RPL.ISUPPORT -> RPL_ISUPPORT(getNonTrailingParameterString(1).split(" "))
|
||||||
|
RPL.LISTSTART -> RPL_LISTSTART
|
||||||
|
RPL.LIST -> RPL_LIST(
|
||||||
parameters[1],
|
parameters[1],
|
||||||
parameters[2].toInt(),
|
parameters[2].toInt(),
|
||||||
getTrailingParameterString(),
|
getTrailingParameterString(),
|
||||||
)
|
)
|
||||||
RPL.LISTEND -> ServerMessage.Numeric.RPL_LISTEND()
|
RPL.LISTEND -> RPL_LISTEND
|
||||||
RPL.NONE -> ServerMessage.UNIMPLEMENTED(parameters.toString())
|
RPL.STATSCOMMANDS -> UNIMPLEMENTED(parameters.toString())
|
||||||
|
RPL.ENDOFSTATS -> UNIMPLEMENTED(parameters.toString())
|
||||||
|
RPL.TOPIC -> RPL_TOPIC(getTrailingParameterString())
|
||||||
|
RPL.TOPICWHOTIME -> UNIMPLEMENTED(parameters.toString())
|
||||||
|
RPL.NAMREPLY -> UNIMPLEMENTED(parameters.toString())
|
||||||
|
RPL.ENDOFNAMES -> RPL_ENDOFNAMES
|
||||||
|
RPL.NONE -> UNIMPLEMENTED(parameters.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Messages have this format, as rough ABNF:
|
|
||||||
*
|
|
||||||
* message ::= ['@' <tags> SPACE] [':' <source> SPACE] <command> <parameters> <crlf>
|
|
||||||
* SPACE ::= %x20 *( %x20 ) ; space character(s)
|
|
||||||
* crlf ::= %x0D %x0A ; "carriage return" "linefeed"
|
|
||||||
*
|
|
||||||
* The specific parts of an IRC message are:
|
|
||||||
*
|
|
||||||
* tags: Optional metadata on a message, starting with ('@', 0x40).
|
|
||||||
*
|
|
||||||
* source: Optional note of where the message came from, starting with (':', 0x3A).
|
|
||||||
*
|
|
||||||
* command: The specific command this message represents.
|
|
||||||
*
|
|
||||||
* parameters: If it exists, data relevant to this specific command.
|
|
||||||
*
|
|
||||||
* ===================
|
|
||||||
*
|
|
||||||
* Convert line from server into tokens split on strings and remove elements that belong
|
* Convert line from server into tokens split on strings and remove elements that belong
|
||||||
* to different segments of the IRC message e.g. tags, prefixes etc
|
* to different segments of the IRC message e.g. tags, prefixes etc
|
||||||
*/
|
*/
|
||||||
@@ -118,31 +125,28 @@ class MessageParser(val incoming: Channel<String>, enableLogging: Boolean = fals
|
|||||||
val tokens = commandList.toMutableList()
|
val tokens = commandList.toMutableList()
|
||||||
|
|
||||||
// remove tags from strlist if present
|
// remove tags from strlist if present
|
||||||
tags =
|
tags = if (tokens.first().startsWith("@")) {
|
||||||
if (tokens.first().startsWith("@")) {
|
tokens.removeFirst()
|
||||||
tokens.removeFirst()
|
} else {
|
||||||
} else {
|
null
|
||||||
null
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// remove client prefix (nick&opt hostname) if present
|
// remove client prefix (nick&opt hostname) if present
|
||||||
prefix =
|
prefix = if (tokens.first().startsWith(":")) {
|
||||||
if (tokens.first().startsWith(":")) {
|
tokens.removeFirst()
|
||||||
tokens.removeFirst()
|
} else {
|
||||||
} else {
|
null
|
||||||
null
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// get command e.g. PING
|
// get command e.g. PING, 005
|
||||||
val commandStr = tokens.removeFirst()
|
val commandStr = tokens.removeFirst()
|
||||||
|
|
||||||
// Check if command is a numeric (RPL/ERR) or named
|
// Check if command is a numeric (RPL/ERR) or named
|
||||||
command =
|
command = if (commandStr.toIntOrNull() == null) {
|
||||||
if (commandStr.toIntOrNull() == null) {
|
Command.NamedCommand(commandStr, tokens)
|
||||||
Command.NamedCommand(commandStr, tokens)
|
} else {
|
||||||
} else {
|
Command.NumericCommand(commandStr, tokens)
|
||||||
Command.NumericCommand(commandStr, tokens)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return command.toServerMessage()
|
return command.toServerMessage()
|
||||||
}
|
}
|
||||||
@@ -153,8 +157,14 @@ class MessageParser(val incoming: Channel<String>, enableLogging: Boolean = fals
|
|||||||
suspend fun start() {
|
suspend fun start() {
|
||||||
val builder = MessageBuilder()
|
val builder = MessageBuilder()
|
||||||
for (msg in incoming) {
|
for (msg in incoming) {
|
||||||
logger.debug { "Receiving: $msg" }
|
logger.trace { "Receiving: $msg" }
|
||||||
incomingParsedMessages.send(builder.build(msg))
|
val parsed = builder.build(msg)
|
||||||
|
if (parsed is UNIMPLEMENTED) {
|
||||||
|
logger.warn { "[S->C]: Left unparsed: $msg" }
|
||||||
|
} else {
|
||||||
|
logger.debug { "[S->C]: Got $parsed" }
|
||||||
|
}
|
||||||
|
incomingParsedMessages.send(parsed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user