diff --git a/src/main/kotlin/com/shr4pnel/ferretirc/net/ClientMessage.kt b/src/main/kotlin/com/shr4pnel/ferretirc/net/ClientMessage.kt deleted file mode 100644 index 2588ffa..0000000 --- a/src/main/kotlin/com/shr4pnel/ferretirc/net/ClientMessage.kt +++ /dev/null @@ -1,64 +0,0 @@ -package com.shr4pnel.ferretirc.net - -import io.ktor.network.selector.SelectorManager -import kotlinx.coroutines.Dispatchers - -/** - * IRC Messages sent by the client - */ -sealed class ClientMessage(val strName: String) { - abstract fun toWire(): ByteArray - - companion object Util { - val selectorManager = SelectorManager(Dispatchers.IO) - } - - class Ping(val token: String?) : ClientMessage("PING") { - init { - require(token?.isNotEmpty() ?: true) { - "Token to PING should be null or a non-empty string" - } - } - - override fun toWire() = "$strName $token\r\n".encodeToByteArray() - } - - sealed class Cap : ClientMessage("CAP") { - val validSubcommands = listOf("LS", "LIST", "REQ", "END") - - override fun toWire() = when (this) { - is LS -> "CAP LS $version\r\n".encodeToByteArray() - is REQ -> TODO() - } - - class LS(val version: Int = 302) : Cap() { - val subcommand = "LS" - } - - class REQ(val version: Int?) : Cap() { - val subcommand = "REQ" - } - - class END { - val subcommand = "END" - } - -// init { -// require(validSubcommands.contains(subcommand.toUpperCasePreservingASCIIRules())) { -// "$subcommand is not a valid subcommand to CAP" -// } -// } - } - - class Nick(val nickname: String) : ClientMessage("NICK") { - override fun toWire() = "NICK $nickname\r\n".encodeToByteArray() - - init { - require(nickname.length < 10) { "\"$nickname\" exceeds IRCs maximum nickname length of 9" } - require(!nickname.startsWith(":") && !nickname.startsWith("#")) { "\"$nickname\" may not begin with : or #" } // TODO THIS SHOULD BLACKLIST ALL PREFIXES NAMED IN CHANTYPES PARAMETER - require(!nickname.contains(" ")) { "$nickname may not contain a space" } - } - } - - -} \ No newline at end of file diff --git a/src/main/kotlin/com/shr4pnel/ferretirc/net/messages/ClientMessage.kt b/src/main/kotlin/com/shr4pnel/ferretirc/net/messages/ClientMessage.kt new file mode 100644 index 0000000..1231bb1 --- /dev/null +++ b/src/main/kotlin/com/shr4pnel/ferretirc/net/messages/ClientMessage.kt @@ -0,0 +1,69 @@ +package com.shr4pnel.ferretirc.net.messages + +import io.ktor.network.selector.SelectorManager +import kotlinx.coroutines.Dispatchers + +/** + * IRC Messages sent by the client + */ +sealed class ClientMessage(val strName: String) { + abstract fun toWireIntermediate(): String + fun toWire() = "${toWireIntermediate()}\r\n".encodeToByteArray() + + companion object Util { + val selectorManager = SelectorManager(Dispatchers.IO) + } + + class Ping(val token: String? = null) : ClientMessage("PING") { + init { + require(token?.isNotEmpty() ?: true) { + "Token to PING should be null or a non-empty string" + } + } + + override fun toWireIntermediate() = "$strName ${token.orEmpty()}" + } + + sealed class Cap : ClientMessage("CAP") { + val validSubcommands = listOf("LS", "LIST", "REQ", "END") + + override fun toWireIntermediate() = when (this) { + is LS -> "CAP LS $version" + is REQ -> TODO() + is END -> "CAP END" + is LIST -> TODO() + } + + class LS(val version: Int = 302) : Cap() + class LIST : Cap() + class REQ(val version: Int?) : Cap() + class END : Cap() + } + + class Nick(val nickname: String) : ClientMessage("NICK") { + override fun toWireIntermediate() = "NICK $nickname" + + init { + require(nickname.length < 10) { "\"$nickname\" exceeds IRCs maximum nickname length of 9" } + require(!nickname.startsWith(":") && !nickname.startsWith("#")) { "\"$nickname\" may not begin with : or #" } // TODO THIS SHOULD BLACKLIST ALL PREFIXES NAMED IN CHANTYPES PARAMETER + require(!nickname.contains(" ")) { "$nickname may not contain a space" } + } + } + + class User(val username: String, val realName: String) : ClientMessage("USER") { + // TODO GET USERNAME INITIALISATION CHECK PARAMETERS FROM USERLEN RPL_ISUPPORT + init { + require(username.isNotEmpty()) { "Username may not be blank" } + } + + override fun toWireIntermediate() = "USER $username 0 * :$realName" + } + + class Pass(val password: String) : ClientMessage("PASS") { + override fun toWireIntermediate() = "PASS $password" + } + + class UNIMPLEMENTED() : ClientMessage("") { + override fun toWireIntermediate() = "" + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/shr4pnel/ferretirc/net/MessageIO.kt b/src/main/kotlin/com/shr4pnel/ferretirc/net/messages/MessageIO.kt similarity index 75% rename from src/main/kotlin/com/shr4pnel/ferretirc/net/MessageIO.kt rename to src/main/kotlin/com/shr4pnel/ferretirc/net/messages/MessageIO.kt index 511b667..e9ef863 100644 --- a/src/main/kotlin/com/shr4pnel/ferretirc/net/MessageIO.kt +++ b/src/main/kotlin/com/shr4pnel/ferretirc/net/messages/MessageIO.kt @@ -1,12 +1,12 @@ -package com.shr4pnel.ferretirc.net +package com.shr4pnel.ferretirc.net.messages import io.ktor.network.sockets.Socket import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job import kotlinx.coroutines.channels.Channel abstract class MessageIO(val socket: Socket, val scope: CoroutineScope) { val incomingMessages = Channel(Channel.BUFFERED) val outgoingMessages = Channel(Channel.BUFFERED) - - abstract suspend fun start() + abstract fun start(): Job } \ No newline at end of file diff --git a/src/main/kotlin/com/shr4pnel/ferretirc/net/messages/ServerMessage.kt b/src/main/kotlin/com/shr4pnel/ferretirc/net/messages/ServerMessage.kt new file mode 100644 index 0000000..4eec7a4 --- /dev/null +++ b/src/main/kotlin/com/shr4pnel/ferretirc/net/messages/ServerMessage.kt @@ -0,0 +1,7 @@ +package com.shr4pnel.ferretirc.net.messages + +sealed class ServerMessage { + class Cap() : ServerMessage() + class Pong(val token: String? = null) : ServerMessage() + class UNIMPLEMENTED(val msg: String) : ServerMessage() +} \ No newline at end of file