Browse Source

Add NicknameChangeRequired event

tags/v1.0.0
Chris Smith 5 years ago
parent
commit
2e8b1cf7b0

+ 3
- 0
CHANGELOG View File

@@ -1,5 +1,8 @@
1 1
 vNEXT (in development)
2 2
 
3
+ * Added NicknameChangeRequired event for the case when a nickname is
4
+   not allowed during connection and *MUST* be changed
5
+
3 6
 v0.11.0
4 7
 
5 8
  * Added SourcedEvent interface for events that have a user source attached

+ 58
- 1
docs/index.adoc View File

@@ -172,6 +172,31 @@ commands that KtIrc supports can be invoked using the `send*` methods,
172 172
 which are documented in the <<Messages>> reference. Other useful methods
173 173
 such as `reply` can be found in the <<Utility methods>> reference.
174 174
 
175
+=== Mandatory event handling
176
+
177
+In order to properly connect to IRC, stay connected, and handle
178
+incoming messages properly, the following events MUST be handled:
179
+
180
+.<<NicknameChangeRequired>>
181
+The nickname change required event occurs when connecting to a server
182
+if our initial nickname is taken. A new nickname must be supplied
183
+to continue connecting.
184
+
185
+.<<ServerDisconnected>>
186
+When KtIrc becomes disconnected from a server, or fails a connection
187
+attempt, it will raise this event. If you wish to stay connected
188
+to IRC you must call the `connect()` method to start a reconnection
189
+attempt after an appropriate delay.
190
+
191
+.<<BatchReceived>>
192
+On servers that support the IRCv3 batch capability, some incoming
193
+messages may be sent inside a batch. These could include join or
194
+quit messages during a netsplit, or other important messages you
195
+may need to process. At minimum, when receiving a BatchReceived
196
+event you should apply your normal processing to all the events
197
+contained within.
198
+
199
+
175 200
 == IrcClient DSL
176 201
 
177 202
 The DSL for creating a new `IrcClient` allows you to set a number of
@@ -1039,13 +1064,45 @@ TODO
1039 1064
 TODO
1040 1065
 
1041 1066
 ==== NicknameChangeFailed
1067
+* Type: IrcEvent
1068
+* Properties:
1069
+** `cause`: `NicknameChangeError` - the reason the nickname must be changed
1042 1070
 
1043
-TODO
1071
+Raised when the server informs us that our desired nickname is not available
1072
+for some reason. The `cause` parameter will contain a specific reason given
1073
+by the server:
1074
+
1075
+* `ErroneousNickname` - the nickname is not allowed by the server (e.g. it used
1076
+  restricted characters)
1077
+* `AlreadyInUse` - the nickname is already in use
1078
+* `Collision` - the nickname has collided with another somehow
1079
+* `NoNicknameGiven` - no nickname was provided
1080
+
1081
+==== NicknameChangeRequired
1082
+* Type: IrcEvent, NicknameChangeFailed
1083
+* Properties:
1084
+** `cause`: `NicknameChangeError` - the reason the nickname must be changed
1085
+
1086
+Raised during a connection attempt when there is a problem with the nickname
1087
+that KtIrc was told to use. The exact problem will be detailed in the `cause`
1088
+parameter, and has the same options as the <<NicknameChangeFailed>> event.
1089
+
1090
+Upon receiving this event, a new nickname MUST be chosen and sent to the
1091
+server with the <<sendNickChange>> method. Failure to do so will result
1092
+in the IRC server terminating the connection.
1093
+
1094
+WARNING: `NicknameChangeRequired` currently extends `NicknameChangeFailed`
1095
+for backwards compatibility. This will be removed in KtIrc 2.0.0, and
1096
+both events will need to be handled separately.
1044 1097
 
1045 1098
 == Messages
1046 1099
 
1047 1100
 TODO
1048 1101
 
1102
+==== sendNickChange
1103
+
1104
+TODO
1105
+
1049 1106
 == Utility methods
1050 1107
 
1051 1108
 TODO

+ 22
- 15
src/main/kotlin/com/dmdirc/ktirc/events/Events.kt View File

@@ -297,20 +297,27 @@ class BatchReceived(metadata: EventMetadata, val type: String, val params: Array
297 297
 
298 298
 /**
299 299
  * Raised when attempting to set or change our nickname fails.
300
- *
301
- * If this happens before {ServerReady], the nickname must be changed for registration to continue.
302 300
  */
303
-class NicknameChangeFailed(metadata: EventMetadata, val cause: NicknameChangeError) : IrcEvent(metadata) {
304
-    /** Reasons a nick change may fail. */
305
-    enum class NicknameChangeError {
306
-        /** The nickname is not allowed by the server. */
307
-        ErroneousNickname,
308
-        /** The nickname is already in use. */
309
-        AlreadyInUse,
310
-        /** The nickname has collided with another somehow. */
311
-        Collision,
312
-        /** No nickname was provided. */
313
-        NoNicknameGiven
314
-    }
315
-}
301
+open class NicknameChangeFailed(metadata: EventMetadata, val cause: NicknameChangeError) : IrcEvent(metadata)
316 302
 
303
+/**
304
+ * Raised during a connection attempt if the nickname we wanted is not available.
305
+ *
306
+ * The nickname must be changed to continue connecting.
307
+ *
308
+ * In 2.0.0 this will no longer extend [NicknameChangeFailed] and will have to be handled separately.
309
+ */
310
+@RemoveIn("2.0.0")
311
+class NicknameChangeRequired(metadata: EventMetadata, cause: NicknameChangeError) : NicknameChangeFailed(metadata, cause)
312
+
313
+/** Reasons a nick change may fail. */
314
+enum class NicknameChangeError {
315
+    /** The nickname is not allowed by the server. */
316
+    ErroneousNickname,
317
+    /** The nickname is already in use. */
318
+    AlreadyInUse,
319
+    /** The nickname has collided with another somehow. */
320
+    Collision,
321
+    /** No nickname was provided. */
322
+    NoNicknameGiven
323
+}

+ 1
- 0
src/main/kotlin/com/dmdirc/ktirc/events/mutators/EventMutator.kt View File

@@ -14,5 +14,6 @@ internal interface EventMutator {
14 14
 internal val eventMutators = listOf(
15 15
         ServerReadyMutator(),
16 16
         ChannelFanOutMutator(),
17
+        NickChangeRequiredMutator(),
17 18
         BatchMutator()
18 19
 )

+ 19
- 0
src/main/kotlin/com/dmdirc/ktirc/events/mutators/NickChangeRequiredMutator.kt View File

@@ -0,0 +1,19 @@
1
+package com.dmdirc.ktirc.events.mutators
2
+
3
+import com.dmdirc.ktirc.IrcClient
4
+import com.dmdirc.ktirc.events.IrcEvent
5
+import com.dmdirc.ktirc.events.NicknameChangeFailed
6
+import com.dmdirc.ktirc.events.NicknameChangeRequired
7
+import com.dmdirc.ktirc.io.MessageEmitter
8
+import com.dmdirc.ktirc.model.ServerStatus
9
+
10
+internal class NickChangeRequiredMutator : EventMutator {
11
+
12
+    override fun mutateEvent(client: IrcClient, messageEmitter: MessageEmitter, event: IrcEvent) =
13
+            if (event is NicknameChangeFailed && client.serverState.status < ServerStatus.Ready) {
14
+                listOf(NicknameChangeRequired(event.metadata, event.cause))
15
+            } else {
16
+                listOf(event)
17
+            }
18
+
19
+}

+ 6
- 5
src/main/kotlin/com/dmdirc/ktirc/messages/processors/NickChangeErrorProcessor.kt View File

@@ -1,5 +1,6 @@
1 1
 package com.dmdirc.ktirc.messages.processors
2 2
 
3
+import com.dmdirc.ktirc.events.NicknameChangeError
3 4
 import com.dmdirc.ktirc.events.NicknameChangeFailed
4 5
 import com.dmdirc.ktirc.messages.ERR_ERRONEUSNICKNAME
5 6
 import com.dmdirc.ktirc.messages.ERR_NICKCOLLISION
@@ -13,11 +14,11 @@ internal class NickChangeErrorProcessor : MessageProcessor {
13 14
 
14 15
     override fun process(message: IrcMessage) = listOf(NicknameChangeFailed(message.metadata, message.command.toNicknameChangeError()))
15 16
 
16
-    private fun String.toNicknameChangeError(): NicknameChangeFailed.NicknameChangeError = when(this) {
17
-        ERR_ERRONEUSNICKNAME -> NicknameChangeFailed.NicknameChangeError.ErroneousNickname
18
-        ERR_NICKCOLLISION -> NicknameChangeFailed.NicknameChangeError.Collision
19
-        ERR_NICKNAMEINUSE -> NicknameChangeFailed.NicknameChangeError.AlreadyInUse
20
-        ERR_NONICKNAMEGIVEN -> NicknameChangeFailed.NicknameChangeError.NoNicknameGiven
17
+    private fun String.toNicknameChangeError(): NicknameChangeError = when(this) {
18
+        ERR_ERRONEUSNICKNAME -> NicknameChangeError.ErroneousNickname
19
+        ERR_NICKCOLLISION -> NicknameChangeError.Collision
20
+        ERR_NICKNAMEINUSE -> NicknameChangeError.AlreadyInUse
21
+        ERR_NONICKNAMEGIVEN -> NicknameChangeError.NoNicknameGiven
21 22
         else -> throw IllegalArgumentException("Unknown nick change error")
22 23
     }
23 24
 

+ 61
- 0
src/test/kotlin/com/dmdirc/ktirc/events/mutators/NickChangeRequiredMutatorTest.kt View File

@@ -0,0 +1,61 @@
1
+package com.dmdirc.ktirc.events.mutators
2
+
3
+import com.dmdirc.ktirc.IrcClient
4
+import com.dmdirc.ktirc.TestConstants
5
+import com.dmdirc.ktirc.events.*
6
+import com.dmdirc.ktirc.io.MessageEmitter
7
+import com.dmdirc.ktirc.model.ServerState
8
+import com.dmdirc.ktirc.model.ServerStatus
9
+import io.mockk.every
10
+import io.mockk.mockk
11
+import org.junit.jupiter.api.Assertions.assertEquals
12
+import org.junit.jupiter.api.Test
13
+
14
+internal class NickChangeRequiredMutatorTest {
15
+
16
+    private val mutator = NickChangeRequiredMutator()
17
+    private val fakeServerState = ServerState("acidBurn", "the.gibson")
18
+    private val mockClient = mockk<IrcClient> {
19
+        every { serverState } returns fakeServerState
20
+    }
21
+    private val mockEmitter = mockk<MessageEmitter>()
22
+
23
+    @Test
24
+    fun `returns other events before server ready`() {
25
+        fakeServerState.status = ServerStatus.Negotiating
26
+        val event = ServerConnected(EventMetadata(TestConstants.time))
27
+        val events = mutator.mutateEvent(mockClient, mockEmitter, event)
28
+        assertEquals(1, events.size)
29
+        assertEquals(event, events[0])
30
+    }
31
+
32
+    @Test
33
+    fun `returns other events after server ready`() {
34
+        fakeServerState.status = ServerStatus.Ready
35
+        val event = ServerConnected(EventMetadata(TestConstants.time))
36
+        val events = mutator.mutateEvent(mockClient, mockEmitter, event)
37
+        assertEquals(1, events.size)
38
+        assertEquals(event, events[0])
39
+    }
40
+
41
+    @Test
42
+    fun `returns nick change failed events after server ready`() {
43
+        fakeServerState.status = ServerStatus.Ready
44
+        val event = NicknameChangeFailed(EventMetadata(TestConstants.time), NicknameChangeError.AlreadyInUse)
45
+        val events = mutator.mutateEvent(mockClient, mockEmitter, event)
46
+        assertEquals(1, events.size)
47
+        assertEquals(event, events[0])
48
+    }
49
+
50
+    @Test
51
+    fun `returns nick change required event before server ready`() {
52
+        fakeServerState.status = ServerStatus.Negotiating
53
+        val event = NicknameChangeFailed(EventMetadata(TestConstants.time), NicknameChangeError.AlreadyInUse)
54
+        val events = mutator.mutateEvent(mockClient, mockEmitter, event)
55
+        assertEquals(1, events.size)
56
+        val received = events[0] as NicknameChangeRequired
57
+        assertEquals(event.metadata, received.metadata)
58
+        assertEquals(event.cause, received.cause)
59
+    }
60
+
61
+}

+ 5
- 5
src/test/kotlin/com/dmdirc/ktirc/messages/processors/NickChangeErrorProcessorTest.kt View File

@@ -1,7 +1,7 @@
1 1
 package com.dmdirc.ktirc.messages.processors
2 2
 
3 3
 import com.dmdirc.ktirc.TestConstants
4
-import com.dmdirc.ktirc.events.NicknameChangeFailed
4
+import com.dmdirc.ktirc.events.NicknameChangeError
5 5
 import com.dmdirc.ktirc.messages.tagMap
6 6
 import com.dmdirc.ktirc.model.IrcMessage
7 7
 import com.dmdirc.ktirc.model.MessageTag
@@ -25,28 +25,28 @@ internal class NickChangeErrorProcessorTest {
25 25
     fun `raises error event when nick in use`() {
26 26
         val events = processor.process(IrcMessage(tagMap(), null, "433", params("Nickname already in use")))
27 27
         assertEquals(1, events.size)
28
-        assertEquals(NicknameChangeFailed.NicknameChangeError.AlreadyInUse, events[0].cause)
28
+        assertEquals(NicknameChangeError.AlreadyInUse, events[0].cause)
29 29
     }
30 30
 
31 31
     @Test
32 32
     fun `raises error event when nick is erroneous`() {
33 33
         val events = processor.process(IrcMessage(tagMap(), null, "432", params("Nickname not allowed")))
34 34
         assertEquals(1, events.size)
35
-        assertEquals(NicknameChangeFailed.NicknameChangeError.ErroneousNickname, events[0].cause)
35
+        assertEquals(NicknameChangeError.ErroneousNickname, events[0].cause)
36 36
     }
37 37
 
38 38
     @Test
39 39
     fun `raises error event when nick collides`() {
40 40
         val events = processor.process(IrcMessage(tagMap(), null, "436", params("Nick collision")))
41 41
         assertEquals(1, events.size)
42
-        assertEquals(NicknameChangeFailed.NicknameChangeError.Collision, events[0].cause)
42
+        assertEquals(NicknameChangeError.Collision, events[0].cause)
43 43
     }
44 44
 
45 45
     @Test
46 46
     fun `raises error event when nick not provided`() {
47 47
         val events = processor.process(IrcMessage(tagMap(), null, "431", params("No nickname given")))
48 48
         assertEquals(1, events.size)
49
-        assertEquals(NicknameChangeFailed.NicknameChangeError.NoNicknameGiven, events[0].cause)
49
+        assertEquals(NicknameChangeError.NoNicknameGiven, events[0].cause)
50 50
     }
51 51
 
52 52
     @Test

Loading…
Cancel
Save