Browse Source

Add NicknameChangeRequired event

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

+ 3
- 0
CHANGELOG View File

1
 vNEXT (in development)
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
 v0.11.0
6
 v0.11.0
4
 
7
 
5
  * Added SourcedEvent interface for events that have a user source attached
8
  * Added SourcedEvent interface for events that have a user source attached

+ 58
- 1
docs/index.adoc View File

172
 which are documented in the <<Messages>> reference. Other useful methods
172
 which are documented in the <<Messages>> reference. Other useful methods
173
 such as `reply` can be found in the <<Utility methods>> reference.
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
 == IrcClient DSL
200
 == IrcClient DSL
176
 
201
 
177
 The DSL for creating a new `IrcClient` allows you to set a number of
202
 The DSL for creating a new `IrcClient` allows you to set a number of
1039
 TODO
1064
 TODO
1040
 
1065
 
1041
 ==== NicknameChangeFailed
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
 == Messages
1098
 == Messages
1046
 
1099
 
1047
 TODO
1100
 TODO
1048
 
1101
 
1102
+==== sendNickChange
1103
+
1104
+TODO
1105
+
1049
 == Utility methods
1106
 == Utility methods
1050
 
1107
 
1051
 TODO
1108
 TODO

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

297
 
297
 
298
 /**
298
 /**
299
  * Raised when attempting to set or change our nickname fails.
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
 internal val eventMutators = listOf(
14
 internal val eventMutators = listOf(
15
         ServerReadyMutator(),
15
         ServerReadyMutator(),
16
         ChannelFanOutMutator(),
16
         ChannelFanOutMutator(),
17
+        NickChangeRequiredMutator(),
17
         BatchMutator()
18
         BatchMutator()
18
 )
19
 )

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

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
 package com.dmdirc.ktirc.messages.processors
1
 package com.dmdirc.ktirc.messages.processors
2
 
2
 
3
+import com.dmdirc.ktirc.events.NicknameChangeError
3
 import com.dmdirc.ktirc.events.NicknameChangeFailed
4
 import com.dmdirc.ktirc.events.NicknameChangeFailed
4
 import com.dmdirc.ktirc.messages.ERR_ERRONEUSNICKNAME
5
 import com.dmdirc.ktirc.messages.ERR_ERRONEUSNICKNAME
5
 import com.dmdirc.ktirc.messages.ERR_NICKCOLLISION
6
 import com.dmdirc.ktirc.messages.ERR_NICKCOLLISION
13
 
14
 
14
     override fun process(message: IrcMessage) = listOf(NicknameChangeFailed(message.metadata, message.command.toNicknameChangeError()))
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
         else -> throw IllegalArgumentException("Unknown nick change error")
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

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
 package com.dmdirc.ktirc.messages.processors
1
 package com.dmdirc.ktirc.messages.processors
2
 
2
 
3
 import com.dmdirc.ktirc.TestConstants
3
 import com.dmdirc.ktirc.TestConstants
4
-import com.dmdirc.ktirc.events.NicknameChangeFailed
4
+import com.dmdirc.ktirc.events.NicknameChangeError
5
 import com.dmdirc.ktirc.messages.tagMap
5
 import com.dmdirc.ktirc.messages.tagMap
6
 import com.dmdirc.ktirc.model.IrcMessage
6
 import com.dmdirc.ktirc.model.IrcMessage
7
 import com.dmdirc.ktirc.model.MessageTag
7
 import com.dmdirc.ktirc.model.MessageTag
25
     fun `raises error event when nick in use`() {
25
     fun `raises error event when nick in use`() {
26
         val events = processor.process(IrcMessage(tagMap(), null, "433", params("Nickname already in use")))
26
         val events = processor.process(IrcMessage(tagMap(), null, "433", params("Nickname already in use")))
27
         assertEquals(1, events.size)
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
     @Test
31
     @Test
32
     fun `raises error event when nick is erroneous`() {
32
     fun `raises error event when nick is erroneous`() {
33
         val events = processor.process(IrcMessage(tagMap(), null, "432", params("Nickname not allowed")))
33
         val events = processor.process(IrcMessage(tagMap(), null, "432", params("Nickname not allowed")))
34
         assertEquals(1, events.size)
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
     @Test
38
     @Test
39
     fun `raises error event when nick collides`() {
39
     fun `raises error event when nick collides`() {
40
         val events = processor.process(IrcMessage(tagMap(), null, "436", params("Nick collision")))
40
         val events = processor.process(IrcMessage(tagMap(), null, "436", params("Nick collision")))
41
         assertEquals(1, events.size)
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
     @Test
45
     @Test
46
     fun `raises error event when nick not provided`() {
46
     fun `raises error event when nick not provided`() {
47
         val events = processor.process(IrcMessage(tagMap(), null, "431", params("No nickname given")))
47
         val events = processor.process(IrcMessage(tagMap(), null, "431", params("No nickname given")))
48
         assertEquals(1, events.size)
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
     @Test
52
     @Test

Loading…
Cancel
Save