Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

IrcClient.kt 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. package com.dmdirc.ktirc
  2. import com.dmdirc.ktirc.events.*
  3. import com.dmdirc.ktirc.io.*
  4. import com.dmdirc.ktirc.messages.*
  5. import com.dmdirc.ktirc.model.*
  6. import kotlinx.coroutines.channels.map
  7. import kotlinx.coroutines.coroutineScope
  8. import kotlinx.coroutines.runBlocking
  9. import java.util.logging.Level
  10. import java.util.logging.LogManager
  11. interface IrcClient {
  12. suspend fun send(message: String)
  13. val serverState: ServerState
  14. val channelState: ChannelStateMap
  15. val userState: UserState
  16. val caseMapping: CaseMapping
  17. get() = serverState.features[ServerFeature.ServerCaseMapping] ?: CaseMapping.Rfc
  18. var eventHandler: EventHandler?
  19. fun isLocalUser(user: User): Boolean = caseMapping.areEquivalent(user.nickname, serverState.localNickname)
  20. }
  21. // TODO: How should alternative nicknames work?
  22. // TODO: Should IRC Client take a pool of servers and rotate through, or make the caller do that?
  23. // TODO: Should there be a default profile?
  24. class IrcClientImpl(private val server: Server, private val profile: Profile) : IrcClient {
  25. var socketFactory: (String, Int) -> LineBufferedSocket = ::KtorLineBufferedSocket
  26. override val serverState = ServerState(profile.initialNick)
  27. override val channelState = ChannelStateMap { caseMapping }
  28. override val userState = UserState { caseMapping }
  29. override var eventHandler: EventHandler? = null
  30. set(value) {
  31. field?.let { messageHandler.handlers.remove(it) }
  32. field = value
  33. field?.let { messageHandler.handlers.add(it) }
  34. }
  35. private val messageHandler = MessageHandler(messageProcessors.toList(), eventHandlers.toMutableList())
  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. sendLine("CAP LS 302")
  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("testnet.inspircd.org", 6667), Profile("KtIrc", "Kotlin!", "kotlin"))
  68. client.eventHandler = object : EventHandler {
  69. override suspend fun processEvent(client: IrcClient, event: IrcEvent) {
  70. when (event) {
  71. is ServerWelcome -> client.send(joinMessage("#ktirc"))
  72. is MessageReceived -> if (event.message == "!test") client.send(privmsgMessage(event.target, "Test successful!"))
  73. }
  74. }
  75. }
  76. client.connect()
  77. }
  78. }
  79. }
  80. }