Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

IrcClient.kt 3.5KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  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 caseMapping: CaseMapping
  16. get() = serverState.features[ServerFeature.ServerCaseMapping] ?: CaseMapping.Rfc
  17. var eventHandler: EventHandler?
  18. fun isLocalUser(user: User): Boolean = caseMapping.areEquivalent(user.nickname, serverState.localNickname)
  19. }
  20. // TODO: How should alternative nicknames work?
  21. // TODO: Should IRC Client take a pool of servers and rotate through, or make the caller do that?
  22. // TODO: Should there be a default profile?
  23. class IrcClientImpl(private val server: Server, private val profile: Profile) : IrcClient {
  24. var socketFactory: (String, Int) -> LineBufferedSocket = ::KtorLineBufferedSocket
  25. override val serverState = ServerState(profile.initialNick)
  26. override val channelState = ChannelStateMap { caseMapping }
  27. override var eventHandler: EventHandler? = null
  28. set(value) {
  29. field?.let { messageHandler.handlers.remove(it) }
  30. field = value
  31. field?.let { messageHandler.handlers.add(it) }
  32. }
  33. private val messageHandler = MessageHandler(messageProcessors.toList(), eventHandlers.toMutableList())
  34. private val parser = MessageParser()
  35. private var socket: LineBufferedSocket? = null
  36. override suspend fun send(message: String) {
  37. socket?.sendLine(message)
  38. }
  39. suspend fun connect() {
  40. // TODO: Concurrency!
  41. check(socket == null)
  42. coroutineScope {
  43. with(socketFactory(server.host, server.port)) {
  44. socket = this
  45. connect()
  46. sendLine("CAP LS 302")
  47. server.password?.let { pass -> sendLine(passwordMessage(pass)) }
  48. sendLine(nickMessage(profile.initialNick))
  49. // TODO: Send correct host
  50. sendLine(userMessage(profile.userName, "localhost", server.host, profile.realName))
  51. // TODO: This should be elsewhere
  52. messageHandler.processMessages(this@IrcClientImpl, readLines(this@coroutineScope).map { parser.parse(it) })
  53. }
  54. }
  55. }
  56. companion object {
  57. @JvmStatic
  58. fun main(args: Array<String>) {
  59. val rootLogger = LogManager.getLogManager().getLogger("")
  60. rootLogger.level = Level.FINEST
  61. for (h in rootLogger.handlers) {
  62. h.level = Level.FINEST
  63. }
  64. runBlocking {
  65. val client = IrcClientImpl(Server("testnet.inspircd.org", 6667), Profile("KtIrc", "Kotlin!", "kotlin"))
  66. client.eventHandler = object : EventHandler {
  67. override suspend fun processEvent(client: IrcClient, event: IrcEvent) {
  68. when (event) {
  69. is ServerWelcome -> client.send(joinMessage("#ktirc"))
  70. is MessageReceived -> if (event.message == "!test") client.send(privmsgMessage(event.target, "Test successful!"))
  71. }
  72. }
  73. }
  74. client.connect()
  75. }
  76. }
  77. }
  78. }