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 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package com.dmdirc.ktirc
  2. import com.dmdirc.ktirc.events.IrcEvent
  3. import com.dmdirc.ktirc.io.CaseMapping
  4. import com.dmdirc.ktirc.messages.sendJoin
  5. import com.dmdirc.ktirc.model.*
  6. import com.dmdirc.ktirc.util.RemoveIn
  7. import kotlinx.coroutines.Deferred
  8. /**
  9. * Primary interface for interacting with KtIrc.
  10. */
  11. interface IrcClient {
  12. /**
  13. * Holds state relating to the current server, its features, and capabilities.
  14. */
  15. val serverState: ServerState
  16. /**
  17. * Holds the state for each channel we are currently joined to.
  18. */
  19. val channelState: ChannelStateMap
  20. /**
  21. * Holds the state for all known users (those in common channels).
  22. */
  23. val userState: UserState
  24. /**
  25. * The configured behaviour of the client.
  26. */
  27. val behaviour: ClientBehaviour
  28. /**
  29. * The current case-mapping of the server, defining how uppercase and lowercase nicks/channels/etc are mapped
  30. * to one another.
  31. *
  32. * This may change over the lifetime of an [IrcClient]. It should not be stored, and should be checked each
  33. * time it is needed.
  34. */
  35. val caseMapping: CaseMapping
  36. get() = serverState.features[ServerFeature.ServerCaseMapping] ?: CaseMapping.Rfc
  37. /**
  38. * Begins a connection attempt to the IRC server.
  39. *
  40. * This method will return immediately, and the attempt to connect will be executed in a coroutine on the
  41. * IO scheduler. To check the status of the connection, monitor events using [onEvent].
  42. */
  43. fun connect()
  44. /**
  45. * Disconnect immediately from the IRC server, without sending a QUIT.
  46. */
  47. fun disconnect()
  48. /**
  49. * Sends the given raw line to the IRC server, followed by a carriage return and line feed.
  50. *
  51. * Standard IRC messages can be constructed using the methods in [com.dmdirc.ktirc.messages]
  52. * such as [sendJoin].
  53. *
  54. * @param message The line to be sent to the IRC server.
  55. */
  56. @Deprecated("Use structured send instead", ReplaceWith("send(command, arguments)"))
  57. @RemoveIn("2.0.0")
  58. fun send(message: String)
  59. /**
  60. * Sends the given command to the IRC server.
  61. *
  62. * This should only be needed to send raw/custom commands; standard messages can be sent using the
  63. * extension methods in [com.dmdirc.ktirc.messages] such as [sendJoin].
  64. *
  65. * This method will return immediately; the message will be delivered by a coroutine. Messages
  66. * are guaranteed to be delivered in order when this method is called multiple times.
  67. *
  68. * @param tags The IRCv3 tags to prefix the message with, if any.
  69. * @param command The command to be sent.
  70. * @param arguments The arguments to the command.
  71. */
  72. fun send(tags: Map<MessageTag, String>, command: String, vararg arguments: String)
  73. /**
  74. * Sends the given command to the IRC server.
  75. *
  76. * This should only be needed to send raw/custom commands; standard messages can be sent using the
  77. * extension methods in [com.dmdirc.ktirc.messages] such as [sendJoin].
  78. *
  79. * This method will return immediately; the message will be delivered by a coroutine. Messages
  80. * are guaranteed to be delivered in order when this method is called multiple times.
  81. *
  82. * @param command The command to be sent.
  83. * @param arguments The arguments to the command.
  84. */
  85. fun send(command: String, vararg arguments: String) = send(emptyMap(), command, *arguments)
  86. /**
  87. * Registers a new handler for all events on this connection.
  88. *
  89. * All events are subclasses of [IrcEvent]; the idiomatic way to handle them is using a `when` statement:
  90. *
  91. * ```
  92. * client.onEvent {
  93. * when(it) {
  94. * is MessageReceived -> println(it.message)
  95. * }
  96. * }
  97. * ```
  98. *
  99. * *Note*: at present handlers cannot be removed; they last the lifetime of the [IrcClient].
  100. *
  101. * @param handler The method to call when a new event occurs.
  102. */
  103. fun onEvent(handler: (IrcEvent) -> Unit)
  104. /**
  105. * Utility method to determine if the given user is the one we are connected to IRC as. Should only be used after a
  106. * [com.dmdirc.ktirc.events.ServerReady] event has been received.
  107. */
  108. fun isLocalUser(user: User) = isLocalUser(user.nickname)
  109. /**
  110. * Utility method to determine if the given user is the one we are connected to IRC as. Should only be used after a
  111. * [com.dmdirc.ktirc.events.ServerReady] event has been received.
  112. */
  113. fun isLocalUser(nickname: String) = caseMapping.areEquivalent(nickname, serverState.localNickname)
  114. /**
  115. * Determines if the given [target] appears to be a channel or not. Should only be used after a
  116. * [com.dmdirc.ktirc.events.ServerReady] event has been received.
  117. */
  118. fun isChannel(target: String) = target.isNotEmpty() && serverState.channelTypes.contains(target[0])
  119. }
  120. internal interface ExperimentalIrcClient : IrcClient {
  121. /**
  122. * Sends the given command to the IRC server, and waits for a response back.
  123. *
  124. * This should only be needed to send raw/custom commands; standard messages can be sent using the
  125. * extension methods in [com.dmdirc.ktirc.messages] such as TODO: sendJoinAsync.
  126. *
  127. * This method will return immediately. If the server supports the labeled-responses capability,
  128. * the returned [Deferred] will be eventually populated with the response from the server. If
  129. * the server does not support the capability, or the response times out, `null` will be supplied.
  130. *
  131. * @param command The command to be sent.
  132. * @param arguments The arguments to the command.
  133. * @return A deferred [IrcEvent]? that contains the server's response to the command.
  134. */
  135. fun sendAsync(command: String, vararg arguments: String) = sendAsync(emptyMap(), command, *arguments)
  136. /**
  137. * Sends the given command to the IRC server, and waits for a response back.
  138. *
  139. * This should only be needed to send raw/custom commands; standard messages can be sent using the
  140. * extension methods in [com.dmdirc.ktirc.messages] such as TODO: sendJoinAsync.
  141. *
  142. * This method will return immediately. If the server supports the labeled-responses capability,
  143. * the returned [Deferred] will be eventually populated with the response from the server. If
  144. * the server does not support the capability, or the response times out, `null` will be supplied.
  145. *
  146. * @param tags The IRCv3 tags to prefix the message with, if any.
  147. * @param command The command to be sent.
  148. * @param arguments The arguments to the command.
  149. * @return A deferred [IrcEvent]? that contains the server's response to the command.
  150. */
  151. fun sendAsync(tags: Map<MessageTag, String>, command: String, vararg arguments: String): Deferred<IrcEvent?>
  152. }
  153. /**
  154. * Defines the behaviour of an [IrcClient].
  155. */
  156. interface ClientBehaviour {
  157. /** Whether or not to request channel modes when we join a channel. */
  158. val requestModesOnJoin: Boolean
  159. /**
  160. * If enabled, all messages (`PRIVMSG`s) sent by the client will always be "echoed" back as a MessageReceived
  161. * event.
  162. *
  163. * This makes the behaviour consistent across ircds that support the echo-message capability and those that
  164. * don't. If disabled, messages will only be echoed back when the server supports the capability.
  165. */
  166. val alwaysEchoMessages: Boolean
  167. }
  168. /**
  169. * Constructs a new [IrcClient] using a configuration DSL.
  170. *
  171. * See [IrcClientConfigBuilder] for details of all options
  172. */
  173. @IrcClientDsl
  174. @Suppress("FunctionName")
  175. fun IrcClient(block: IrcClientConfigBuilder.() -> Unit): IrcClient =
  176. IrcClientImpl(IrcClientConfigBuilder().apply(block).build())