You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IrcClient.kt 3.0KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package com.dmdirc.ktirc
  2. import com.dmdirc.ktirc.events.EventHandler
  3. import com.dmdirc.ktirc.events.IrcEvent
  4. import com.dmdirc.ktirc.events.ServerWelcome
  5. import com.dmdirc.ktirc.events.eventHandlers
  6. import com.dmdirc.ktirc.io.KtorLineBufferedSocket
  7. import com.dmdirc.ktirc.io.LineBufferedSocket
  8. import com.dmdirc.ktirc.io.MessageHandler
  9. import com.dmdirc.ktirc.io.MessageParser
  10. import com.dmdirc.ktirc.messages.*
  11. import com.dmdirc.ktirc.model.Profile
  12. import com.dmdirc.ktirc.model.Server
  13. import com.dmdirc.ktirc.model.ServerState
  14. import kotlinx.coroutines.channels.map
  15. import kotlinx.coroutines.coroutineScope
  16. import kotlinx.coroutines.runBlocking
  17. import java.util.logging.Level
  18. import java.util.logging.LogManager
  19. interface IrcClient {
  20. suspend fun send(message: String)
  21. val serverState: ServerState
  22. }
  23. // TODO: How should alternative nicknames work?
  24. // TODO: Should IRC Client take a pool of servers and rotate through, or make the caller do that?
  25. // TODO: Should there be a default profile?
  26. class IrcClientImpl(private val server: Server, private val profile: Profile) : IrcClient {
  27. var socketFactory: (String, Int) -> LineBufferedSocket = ::KtorLineBufferedSocket
  28. override val serverState = ServerState(profile.initialNick)
  29. private val messageHandler = MessageHandler(messageProcessors, eventHandlers + object : EventHandler {
  30. override suspend fun processEvent(client: IrcClient, event: IrcEvent) {
  31. when (event) {
  32. is ServerWelcome -> client.send(joinMessage("#mdbot"))
  33. }
  34. }
  35. })
  36. private val parser = MessageParser()
  37. private var socket: LineBufferedSocket? = null
  38. override suspend fun send(message: String) {
  39. socket?.sendLine(message)
  40. }
  41. suspend fun connect() {
  42. // TODO: Concurrency!
  43. check(socket == null)
  44. coroutineScope {
  45. with(socketFactory(server.host, server.port)) {
  46. socket = this
  47. connect()
  48. // TODO: CAP LS
  49. server.password?.let { pass -> sendLine(passwordMessage(pass)) }
  50. sendLine(nickMessage(profile.initialNick))
  51. // TODO: Send correct host
  52. sendLine(userMessage(profile.userName, "localhost", server.host, profile.realName))
  53. // TODO: This should be elsewhere
  54. messageHandler.processMessages(this@IrcClientImpl, readLines(this@coroutineScope).map { parser.parse(it) })
  55. }
  56. }
  57. }
  58. companion object {
  59. @JvmStatic
  60. fun main(args: Array<String>) {
  61. val rootLogger = LogManager.getLogManager().getLogger("")
  62. rootLogger.level = Level.FINEST
  63. for (h in rootLogger.handlers) {
  64. h.level = Level.FINEST
  65. }
  66. runBlocking {
  67. val client = IrcClientImpl(Server("irc.quakenet.org", 6667), Profile("KtIrc", "Kotlin!", "kotlin"))
  68. client.connect()
  69. }
  70. }
  71. }
  72. }