diff --git a/src/main/kotlin/com/shr4pnel/ferretirc/IrcClient.kt b/src/main/kotlin/com/shr4pnel/ferretirc/IrcClient.kt index 0f47812..09abbd4 100644 --- a/src/main/kotlin/com/shr4pnel/ferretirc/IrcClient.kt +++ b/src/main/kotlin/com/shr4pnel/ferretirc/IrcClient.kt @@ -1,39 +1,58 @@ package com.shr4pnel.ferretirc -import com.shr4pnel.ferretirc.net.ClientMessage +import com.shr4pnel.ferretirc.net.messages.ClientMessage import com.shr4pnel.ferretirc.net.Connection -import com.shr4pnel.ferretirc.net.MessageReader -import com.shr4pnel.ferretirc.net.MessageWriter +import com.shr4pnel.ferretirc.net.messages.ServerMessage +import io.github.oshai.kotlinlogging.KotlinLoggingConfiguration import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.launch -import java.net.URL - -class IrcClient(val nick: String, val sock: URL) { - val port: Int = sock.port - val hostname: String = sock.host - val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) - private val connection = Connection(hostname, port, scope) - lateinit var messages: Channel +class IrcClient(hostname: String, port: Int) { init { - require(port != -1, fun() = "A port must be specified in your argument to IRCClient") - require(hostname.isNotEmpty(), fun() = "A port must be specified in your argument to IRCClient") + KotlinLoggingConfiguration.logStartupMessage = false } + val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + @PublishedApi + internal val connection = Connection(hostname, port, scope) + suspend fun connect() { connection.connect() - messages = connection.reader.incomingMessages } - fun queueMessage(message: ClientMessage) = scope.launch { + suspend fun queueMessage(message: ClientMessage) { connection.writer.outgoingMessages.send(message) } + suspend fun queueMessages(vararg messages: ClientMessage) { + messages.forEach { + connection.writer.outgoingMessages.send(it) + } + } + fun close() { scope.cancel() } + + /** + * Return the next Server Message meeting condition + * @param predicate A function to filter a message based on its parameters + */ + suspend inline fun waitForNext(noinline predicate: (T) -> Boolean = { true }): T = + connection.reader.waitForNext(T::class, predicate) + + suspend fun register(nick: String, realName: String? = null, password: String? = null) { + val messages = buildList { + if (!password.isNullOrEmpty()) add(ClientMessage.Pass(password)) + add(ClientMessage.Cap.LS()) + add(ClientMessage.Nick(nick)) + if (!realName.isNullOrEmpty()) add(ClientMessage.User(nick, realName)) + else add(ClientMessage.User(nick, nick)) + add(ClientMessage.Cap.END()) + } + queueMessages(*messages.toTypedArray()) + } } \ No newline at end of file diff --git a/src/main/kotlin/com/shr4pnel/ferretirc/net/Connection.kt b/src/main/kotlin/com/shr4pnel/ferretirc/net/Connection.kt index c34fa6c..7770c6d 100644 --- a/src/main/kotlin/com/shr4pnel/ferretirc/net/Connection.kt +++ b/src/main/kotlin/com/shr4pnel/ferretirc/net/Connection.kt @@ -1,5 +1,6 @@ package com.shr4pnel.ferretirc.net +import com.shr4pnel.ferretirc.net.messages.ClientMessage import io.ktor.network.sockets.Socket import io.ktor.network.sockets.aSocket import kotlinx.coroutines.CoroutineScope diff --git a/src/main/kotlin/com/shr4pnel/ferretirc/net/MessageWriter.kt b/src/main/kotlin/com/shr4pnel/ferretirc/net/MessageWriter.kt index e1753a7..f797815 100644 --- a/src/main/kotlin/com/shr4pnel/ferretirc/net/MessageWriter.kt +++ b/src/main/kotlin/com/shr4pnel/ferretirc/net/MessageWriter.kt @@ -1,5 +1,7 @@ package com.shr4pnel.ferretirc.net +import com.shr4pnel.ferretirc.net.messages.MessageIO +import io.github.oshai.kotlinlogging.KotlinLogging import io.ktor.network.sockets.Socket import io.ktor.network.sockets.openWriteChannel import io.ktor.utils.io.ByteWriteChannel @@ -7,16 +9,17 @@ import io.ktor.utils.io.writeFully import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -class MessageWriter(socket: Socket, scope: CoroutineScope): MessageIO(socket, scope) { +class MessageWriter(socket: Socket, scope: CoroutineScope) : MessageIO(socket, scope) { private lateinit var send: ByteWriteChannel + private val logger = KotlinLogging.logger("MessageWriter") - override suspend fun start() { + override fun start() = scope.launch { send = socket.openWriteChannel() - scope.launch { - for (msg in outgoingMessages) { - send.writeFully(msg.toWire()) - send.flush() - } + + for (msg in outgoingMessages) { + logger.debug { msg.toWireIntermediate() } + send.writeFully(msg.toWire()) + send.flush() } } -} \ No newline at end of file +}