123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- package com.dmdirc.ktirc
-
- import com.dmdirc.ktirc.events.IrcEvent
- import com.dmdirc.ktirc.io.CaseMapping
- import com.dmdirc.ktirc.messages.sendJoin
- import com.dmdirc.ktirc.messages.tagMap
- import com.dmdirc.ktirc.model.*
- import com.dmdirc.ktirc.util.RemoveIn
- import kotlinx.coroutines.Deferred
-
- /**
- * Primary interface for interacting with KtIrc.
- */
- interface IrcClient {
-
- /**
- * Holds state relating to the current server, its features, and capabilities.
- */
- val serverState: ServerState
-
- /**
- * Holds the state for each channel we are currently joined to.
- */
- val channelState: ChannelStateMap
-
- /**
- * Holds the state for all known users (those in common channels).
- */
- val userState: UserState
-
- /**
- * The configured behaviour of the client.
- */
- val behaviour: ClientBehaviour
-
- /**
- * The current case-mapping of the server, defining how uppercase and lowercase nicks/channels/etc are mapped
- * to one another.
- *
- * This may change over the lifetime of an [IrcClient]. It should not be stored, and should be checked each
- * time it is needed.
- */
- val caseMapping: CaseMapping
- get() = serverState.features[ServerFeature.ServerCaseMapping] ?: CaseMapping.Rfc
-
- /**
- * Begins a connection attempt to the IRC server.
- *
- * This method will return immediately, and the attempt to connect will be executed in a coroutine on the
- * IO scheduler. To check the status of the connection, monitor events using [onEvent].
- */
- fun connect()
-
- /**
- * Disconnect immediately from the IRC server, without sending a QUIT.
- */
- fun disconnect()
-
- /**
- * Sends the given raw line to the IRC server, followed by a carriage return and line feed.
- *
- * Standard IRC messages can be constructed using the methods in [com.dmdirc.ktirc.messages]
- * such as [sendJoin].
- *
- * @param message The line to be sent to the IRC server.
- */
- @Deprecated("Use structured send instead", ReplaceWith("send(command, arguments)"))
- @RemoveIn("2.0.0")
- fun send(message: String)
-
- /**
- * Sends the given command to the IRC server.
- *
- * This should only be needed to send raw/custom commands; standard messages can be sent using the
- * extension methods in [com.dmdirc.ktirc.messages] such as [sendJoin].
- *
- * This method will return immediately; the message will be delivered by a coroutine. Messages
- * are guaranteed to be delivered in order when this method is called multiple times.
- *
- * @param tags The IRCv3 tags to prefix the message with, if any.
- * @param command The command to be sent.
- * @param arguments The arguments to the command.
- */
- fun send(tags: Map<MessageTag, String>, command: String, vararg arguments: String)
-
- /**
- * Sends the given command to the IRC server.
- *
- * This should only be needed to send raw/custom commands; standard messages can be sent using the
- * extension methods in [com.dmdirc.ktirc.messages] such as [sendJoin].
- *
- * This method will return immediately; the message will be delivered by a coroutine. Messages
- * are guaranteed to be delivered in order when this method is called multiple times.
- *
- * @param command The command to be sent.
- * @param arguments The arguments to the command.
- */
- fun send(command: String, vararg arguments: String) = send(emptyMap(), command, *arguments)
-
- /**
- * Registers a new handler for all events on this connection.
- *
- * All events are subclasses of [IrcEvent]; the idiomatic way to handle them is using a `when` statement:
- *
- * ```
- * client.onEvent {
- * when(it) {
- * is MessageReceived -> println(it.message)
- * }
- * }
- * ```
- *
- * *Note*: at present handlers cannot be removed; they last the lifetime of the [IrcClient].
- *
- * @param handler The method to call when a new event occurs.
- */
- fun onEvent(handler: (IrcEvent) -> Unit)
-
- /**
- * Utility method to determine if the given user is the one we are connected to IRC as. Should only be used after a
- * [com.dmdirc.ktirc.events.ServerReady] event has been received.
- */
- fun isLocalUser(user: User) = isLocalUser(user.nickname)
-
- /**
- * Utility method to determine if the given user is the one we are connected to IRC as. Should only be used after a
- * [com.dmdirc.ktirc.events.ServerReady] event has been received.
- */
- fun isLocalUser(nickname: String) = caseMapping.areEquivalent(nickname, serverState.localNickname)
-
- /**
- * Determines if the given [target] appears to be a channel or not. Should only be used after a
- * [com.dmdirc.ktirc.events.ServerReady] event has been received.
- */
- fun isChannel(target: String) = target.isNotEmpty() && serverState.channelTypes.contains(target[0])
-
- }
-
- internal interface ExperimentalIrcClient : IrcClient {
-
- /**
- * Sends the given command to the IRC server, and waits for a response back.
- *
- * This should only be needed to send raw/custom commands; standard messages can be sent using the
- * extension methods in [com.dmdirc.ktirc.messages] such as TODO: sendJoinAsync.
- *
- * This method will return immediately. The returned [Deferred] will eventually be populated with
- * the server's response. If the server supports the labeled-responses capability, a label will
- * be added to the outgoing message to identify the correct response; otherwise the [matcher]
- * will be invoked on all incoming events to select the appropriate response.
- *
- * If the response times out, `null` will be supplied instead of an event.
- *
- * @param command The command to be sent.
- * @param arguments The arguments to the command.
- * @param matcher The matcher to use to find a matching event.
- * @return A deferred [IrcEvent]? that contains the server's response to the command.
- */
- fun sendAsync(command: String, arguments: Array<String>, matcher: (IrcEvent) -> Boolean) = sendAsync(tagMap(), command, arguments, matcher)
-
- /**
- * Sends the given command to the IRC server, and waits for a response back.
- *
- * This should only be needed to send raw/custom commands; standard messages can be sent using the
- * extension methods in [com.dmdirc.ktirc.messages] such as TODO: sendJoinAsync.
- *
- * This method will return immediately. The returned [Deferred] will eventually be populated with
- * the server's response. If the server supports the labeled-responses capability, a label will
- * be added to the outgoing message to identify the correct response; otherwise the [matcher]
- * will be invoked on all incoming events to select the appropriate response.
- *
- * If the response times out, `null` will be supplied instead of an event.
- *
- * @param tags The IRCv3 tags to prefix the message with, if any.
- * @param command The command to be sent.
- * @param arguments The arguments to the command.
- * @param matcher The matcher to use to find a matching event.
- * @return A deferred [IrcEvent]? that contains the server's response to the command.
- */
- fun sendAsync(tags: Map<MessageTag, String>, command: String, arguments: Array<String>, matcher: (IrcEvent) -> Boolean): Deferred<IrcEvent?>
-
- }
-
- /**
- * Defines the behaviour of an [IrcClient].
- */
- interface ClientBehaviour {
-
- /** Whether or not to request channel modes when we join a channel. */
- val requestModesOnJoin: Boolean
-
- /**
- * If enabled, all messages (`PRIVMSG`s) sent by the client will always be "echoed" back as a MessageReceived
- * event.
- *
- * This makes the behaviour consistent across ircds that support the echo-message capability and those that
- * don't. If disabled, messages will only be echoed back when the server supports the capability.
- */
- val alwaysEchoMessages: Boolean
-
- }
-
- /**
- * Constructs a new [IrcClient] using a configuration DSL.
- *
- * See [IrcClientConfigBuilder] for details of all options
- */
- @IrcClientDsl
- @Suppress("FunctionName")
- fun IrcClient(block: IrcClientConfigBuilder.() -> Unit): IrcClient =
- IrcClientImpl(IrcClientConfigBuilder().apply(block).build())
|