Browse Source

Expose the local user object directly

tags/v1.1.0
Chris Smith 5 years ago
parent
commit
496b3394ac

+ 2
- 0
CHANGELOG View File

@@ -4,6 +4,8 @@ vNEXT (in development)
4 4
    * Added sendAway() method
5 5
    * Added UserAway event and fanned-out ChannelAway
6 6
    * Away message is now updated in the UserState
7
+ * Added IrcClient.localUser property, returning the local User
8
+ * Deprecated ServerState.localNickname in favour of localUser.
7 9
  * (Internal) improved the way byte buffers are used to
8 10
    reduce array copying and clean up code
9 11
 

+ 29
- 2
docs/index.adoc View File

@@ -414,11 +414,17 @@ Provides an enum containing the current server state. One of:
414 414
 * `Negotiating` - we are logging in, negotiating capabilities, etc
415 415
 * `Ready` - we are connected and commands may be sent
416 416
 
417
-.serverState.localNickname (String)
417
+.serverState.localNickname (String) [DEPRECATED]
418 418
 The current nickname we are using on the IRC server. While connecting this
419 419
 will default to the nickname from the <<User profile>>, but it may be updated
420 420
 if e.g. the nick is in use or not allowed.
421 421
 
422
+[WARNING]
423
+====
424
+This property is deprecated in favour of the <<LocalUser>> property of `IrcClient`.
425
+You should migrate to using `localUser.nickname` in place of `serverSate.localNickname`.
426
+====
427
+
422 428
 .serverState.serverName (String)
423 429
 The name the server uses for itself. While connecting this defaults to the
424 430
 hostname given in the <<Server settings>>, but it will be updated to the
@@ -549,7 +555,7 @@ ircClient.userState[user]
549 555
 ----
550 556
 
551 557
 The UserState returns a `KnownUser` object which exposes a `details`
552
-property containing the user details, and a `channels` property
558
+property containing the <<User>> details, and a `channels` property
553 559
 containing the common channel names. You can also use the `in`
554 560
 operator to check if the user is in a channel:
555 561
 
@@ -571,6 +577,27 @@ ircClient.userState["acidBurn"]?.let { knownUser -> <1>
571 577
 <3> Returns all common channels we share with the user; will never
572 578
     include channels that the KtIrc client is not joined to.
573 579
 
580
+==== User
581
+
582
+User objects have the following properties:
583
+
584
+* `nickname` - the current nickname of the user, always set
585
+* `ident` - the ident (username/"gecos") of the user, if known (null otherwise)
586
+* `hostname` - the hostname of the user, if known (null otherwise)
587
+* `account` - the account of the user, if known (null if account unknown, or user not registered)
588
+* `realName` - the real name of the user, if known (null otherwise)
589
+* `awayMessage` - the away message of the user, if known (null if away state unknown, or user not away)
590
+
591
+=== LocalUser
592
+
593
+Contains a <<User>> instance corresponding to our own details on the IRC
594
+network. This is the same instance that would be returned from
595
+`ircClient.userState[nickname]` for the current nickname.
596
+
597
+While connecting this will default to a User with only a nickname, which will
598
+be taken from the <<User profile>>. It will be updated as more information
599
+is received from the IRC server.
600
+
574 601
 === ChannelState
575 602
 
576 603
 The ChannelState keeps track of the state for all channels that the client

+ 6
- 1
src/main/kotlin/com/dmdirc/ktirc/IrcClient.kt View File

@@ -28,6 +28,11 @@ interface IrcClient {
28 28
      */
29 29
     val userState: UserState
30 30
 
31
+    /**
32
+     * Details of our user on IRC.
33
+     */
34
+    val localUser: User
35
+
31 36
     /**
32 37
      * The configured behaviour of the client.
33 38
      */
@@ -126,7 +131,7 @@ interface IrcClient {
126 131
      * Utility method to determine if the given user is the one we are connected to IRC as. Should only be used after a
127 132
      * [com.dmdirc.ktirc.events.ServerReady] event has been received.
128 133
      */
129
-    fun isLocalUser(nickname: String) = caseMapping.areEquivalent(nickname, serverState.localNickname)
134
+    fun isLocalUser(nickname: String) = caseMapping.areEquivalent(nickname, localUser.nickname)
130 135
 
131 136
     /**
132 137
      * Determines if the given [target] appears to be a channel or not. Should only be used after a

+ 5
- 2
src/main/kotlin/com/dmdirc/ktirc/IrcClientImpl.kt View File

@@ -45,7 +45,8 @@ internal class IrcClientImpl(private val config: IrcClientConfig) : Experimental
45 45
 
46 46
     override val serverState = ServerState(config.profile.nickname, config.server.host, config.sasl)
47 47
     override val channelState = ChannelStateMap { caseMapping }
48
-    override val userState = UserState { caseMapping }
48
+    override val localUser = User(config.profile.nickname)
49
+    override val userState = UserState { caseMapping }.apply { this += localUser }
49 50
 
50 51
     private val messageHandler = MessageHandler(messageProcessors, eventMutators, eventHandlers)
51 52
     private val messageBuilder = MessageBuilder()
@@ -142,7 +143,7 @@ internal class IrcClientImpl(private val config: IrcClientConfig) : Experimental
142 143
         if (command == "PRIVMSG" && behaviour.alwaysEchoMessages && !serverState.capabilities.enabledCapabilities.contains(Capability.EchoMessages)) {
143 144
             emitEvent(MessageReceived(
144 145
                     EventMetadata(currentTimeProvider()),
145
-                    userState[serverState.localNickname]?.details ?: User(serverState.localNickname),
146
+                    localUser,
146 147
                     arguments[0],
147 148
                     arguments[1]
148 149
             ))
@@ -163,6 +164,8 @@ internal class IrcClientImpl(private val config: IrcClientConfig) : Experimental
163 164
         serverState.reset()
164 165
         channelState.clear()
165 166
         userState.reset()
167
+        localUser.reset(config.profile.nickname)
168
+        userState += localUser
166 169
         socket = null
167 170
         connecting.tryLock()
168 171
         connecting.unlock()

+ 1
- 1
src/main/kotlin/com/dmdirc/ktirc/events/EventUtils.kt View File

@@ -46,4 +46,4 @@ fun IrcClient.react(message: MessageReceived, reaction: String) = sendTagMessage
46 46
  * Utility to determine whether the given message is to our local user or not.
47 47
  */
48 48
 internal fun IrcClient.isToMe(message: MessageReceived) =
49
-        caseMapping.areEquivalent(message.target, serverState.localNickname)
49
+        caseMapping.areEquivalent(message.target, localUser.nickname)

+ 6
- 0
src/main/kotlin/com/dmdirc/ktirc/events/handlers/UserStateHandler.kt View File

@@ -2,6 +2,7 @@ package com.dmdirc.ktirc.events.handlers
2 2
 
3 3
 import com.dmdirc.ktirc.IrcClient
4 4
 import com.dmdirc.ktirc.events.*
5
+import com.dmdirc.ktirc.model.User
5 6
 import com.dmdirc.ktirc.model.UserState
6 7
 
7 8
 internal class UserStateHandler : EventHandler {
@@ -17,6 +18,7 @@ internal class UserStateHandler : EventHandler {
17 18
             is UserHostChanged -> handleHostChanged(client, event)
18 19
             is UserQuit -> handleQuit(client.userState, event)
19 20
             is UserAway -> handleAway(client.userState, event)
21
+            is ServerWelcome -> handleServerWelcome(client.localUser, event)
20 22
         }
21 23
     }
22 24
 
@@ -94,4 +96,8 @@ internal class UserStateHandler : EventHandler {
94 96
         }
95 97
     }
96 98
 
99
+    private fun handleServerWelcome(localUser: User, event: ServerWelcome) {
100
+        localUser.nickname = event.localNick
101
+    }
102
+
97 103
 }

+ 3
- 0
src/main/kotlin/com/dmdirc/ktirc/model/ServerState.kt View File

@@ -4,6 +4,7 @@ import com.dmdirc.ktirc.SaslConfig
4 4
 import com.dmdirc.ktirc.events.EventMetadata
5 5
 import com.dmdirc.ktirc.events.IrcEvent
6 6
 import com.dmdirc.ktirc.io.CaseMapping
7
+import com.dmdirc.ktirc.util.RemoveIn
7 8
 import com.dmdirc.ktirc.util.logger
8 9
 import kotlinx.coroutines.channels.SendChannel
9 10
 import java.util.concurrent.atomic.AtomicLong
@@ -33,6 +34,8 @@ class ServerState internal constructor(
33 34
      * in use when connecting. Once you have received a [com.dmdirc.ktirc.events.ServerWelcome] event you can
34 35
      * rely on this value being current.
35 36
      * */
37
+    @RemoveIn("3.0.0")
38
+    @Deprecated("use ircClient.localUser.nickname instead")
36 39
     var localNickname: String = initialNickname
37 40
         internal set
38 41
 

+ 9
- 0
src/main/kotlin/com/dmdirc/ktirc/model/User.kt View File

@@ -19,6 +19,15 @@ data class User(
19 19
         other.realName?.let { realName = it }
20 20
         other.awayMessage?.let { awayMessage = it }
21 21
     }
22
+
23
+    internal fun reset(newNickname: String) {
24
+        nickname = newNickname
25
+        ident = null
26
+        hostname = null
27
+        account = null
28
+        realName = null
29
+        awayMessage = null
30
+    }
22 31
 }
23 32
 
24 33
 internal fun ByteArray.asUser() = String(this).asUser()

+ 19
- 6
src/test/kotlin/com/dmdirc/ktirc/IrcClientImplTest.kt View File

@@ -5,6 +5,7 @@ import com.dmdirc.ktirc.io.CaseMapping
5 5
 import com.dmdirc.ktirc.io.LineBufferedSocket
6 6
 import com.dmdirc.ktirc.messages.tagMap
7 7
 import com.dmdirc.ktirc.model.*
8
+import com.dmdirc.ktirc.util.RemoveIn
8 9
 import com.dmdirc.ktirc.util.currentTimeProvider
9 10
 import com.dmdirc.ktirc.util.generateLabel
10 11
 import io.mockk.*
@@ -286,7 +287,7 @@ internal class IrcClientImplTest {
286 287
     @Test
287 288
     fun `indicates if user is local user or not`() {
288 289
         val client = IrcClientImpl(normalConfig)
289
-        client.serverState.localNickname = "[acidBurn]"
290
+        client.localUser.nickname = "[acidBurn]"
290 291
 
291 292
         assertTrue(client.isLocalUser(User("{acidBurn}", "libby", "root.localhost")))
292 293
         assertFalse(client.isLocalUser(User("acid-Burn", "libby", "root.localhost")))
@@ -295,7 +296,7 @@ internal class IrcClientImplTest {
295 296
     @Test
296 297
     fun `indicates if nickname is local user or not`() {
297 298
         val client = IrcClientImpl(normalConfig)
298
-        client.serverState.localNickname = "[acidBurn]"
299
+        client.localUser.nickname = "[acidBurn]"
299 300
 
300 301
         assertTrue(client.isLocalUser("{acidBurn}"))
301 302
         assertFalse(client.isLocalUser("acid-Burn"))
@@ -304,13 +305,14 @@ internal class IrcClientImplTest {
304 305
     @Test
305 306
     fun `uses current case mapping to check local user`() {
306 307
         val client = IrcClientImpl(normalConfig)
307
-        client.serverState.localNickname = "[acidBurn]"
308
+        client.localUser.nickname = "[acidBurn]"
308 309
         client.serverState.features[ServerFeature.ServerCaseMapping] = CaseMapping.Ascii
309 310
         assertFalse(client.isLocalUser(User("{acidBurn}", "libby", "root.localhost")))
310 311
     }
311 312
 
312 313
     @Test
313
-    @SuppressWarnings("deprecation")
314
+    @Deprecated("Tests deprecated method")
315
+    @RemoveIn("2.0.0")
314 316
     fun `sends text to socket`() = runBlocking {
315 317
         val client = IrcClientImpl(normalConfig)
316 318
         client.socketFactory = mockSocketFactory
@@ -489,11 +491,19 @@ internal class IrcClientImplTest {
489 491
     }
490 492
 
491 493
     @Test
494
+    @Deprecated("Tests deprecated method")
495
+    @RemoveIn("3.0.0")
492 496
     fun `defaults local nickname to profile`() {
493 497
         val client = IrcClientImpl(normalConfig)
494 498
         assertEquals(NICK, client.serverState.localNickname)
495 499
     }
496 500
 
501
+    @Test
502
+    fun `defaults local user to nickname in profile`() {
503
+        val client = IrcClientImpl(normalConfig)
504
+        assertEquals(User(NICK), client.localUser)
505
+    }
506
+
497 507
     @Test
498 508
     fun `defaults server name to host name`() {
499 509
         val client = IrcClientImpl(normalConfig)
@@ -514,14 +524,17 @@ internal class IrcClientImplTest {
514 524
     @Test
515 525
     fun `reset clears all state`() {
516 526
         with(IrcClientImpl(normalConfig)) {
517
-            userState += User("acidBurn")
527
+            userState += User("zeroCool")
518 528
             channelState += ChannelState("#thegibson") { CaseMapping.Rfc }
519 529
             serverState.serverName = "root.$HOST"
530
+            localUser.awayMessage = "Hacking the planet"
531
+
520 532
             reset()
521 533
 
522
-            assertEquals(0, userState.count())
534
+            assertEquals(1, userState.count())
523 535
             assertEquals(0, channelState.count())
524 536
             assertEquals(HOST, serverState.serverName)
537
+            assertEquals(User("AcidBurn"), localUser)
525 538
         }
526 539
     }
527 540
 

+ 5
- 3
src/test/kotlin/com/dmdirc/ktirc/events/EventUtilsTest.kt View File

@@ -15,9 +15,11 @@ import org.junit.jupiter.api.Test
15 15
 internal class EventUtilsTest {
16 16
 
17 17
     private val fakeServerState = ServerState("", "")
18
+    private val fakeLocalUser = User("")
18 19
     private val ircClient = mockk<IrcClient> {
19 20
         every { serverState } returns fakeServerState
20 21
         every { caseMapping } returns CaseMapping.Ascii
22
+        every { localUser } returns fakeLocalUser
21 23
     }
22 24
 
23 25
     @BeforeEach
@@ -66,7 +68,7 @@ internal class EventUtilsTest {
66 68
 
67 69
     @Test
68 70
     fun `reply sends response to user when message is private`() {
69
-        fakeServerState.localNickname = "zeroCool"
71
+        fakeLocalUser.nickname = "zeroCool"
70 72
         val message = MessageReceived(EventMetadata(TestConstants.time), User("acidBurn"), "Zerocool", "Hack the planet!")
71 73
 
72 74
         ircClient.reply(message, "OK")
@@ -97,7 +99,7 @@ internal class EventUtilsTest {
97 99
 
98 100
     @Test
99 101
     fun `reply sends response with message ID to user when message is private`() {
100
-        fakeServerState.localNickname = "zeroCool"
102
+        fakeLocalUser.nickname = "zeroCool"
101 103
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "abc123"), User("acidBurn"), "Zerocool", "Hack the planet!")
102 104
 
103 105
         ircClient.reply(message, "OK")
@@ -129,7 +131,7 @@ internal class EventUtilsTest {
129 131
 
130 132
     @Test
131 133
     fun `react sends response to user when message is private`() {
132
-        fakeServerState.localNickname = "zeroCool"
134
+        fakeLocalUser.nickname = "zeroCool"
133 135
         val message = MessageReceived(EventMetadata(TestConstants.time, messageId = "msgId"), User("acidBurn"), "Zerocool", "Hack the planet!")
134 136
 
135 137
         ircClient.react(message, ":P")

+ 11
- 0
src/test/kotlin/com/dmdirc/ktirc/events/handlers/UserStateHandlerTest.kt View File

@@ -15,12 +15,14 @@ internal class UserStateHandlerTest {
15 15
 
16 16
     private val fakeServerState = ServerState("", "")
17 17
     private val fakeUserState = UserState { CaseMapping.Rfc }
18
+    private val fakeLocalUser = User("?")
18 19
 
19 20
     private val ircClient = mockk<IrcClient> {
20 21
         every { serverState } returns fakeServerState
21 22
         every { userState } returns fakeUserState
22 23
         every { isLocalUser(any<User>()) } answers { arg<User>(0).nickname == "zeroCool" }
23 24
         every { isLocalUser(any<String>()) } answers { arg<String>(0) == "zeroCool" }
25
+        every { localUser } returns fakeLocalUser
24 26
     }
25 27
 
26 28
     private val handler = UserStateHandler()
@@ -269,4 +271,13 @@ internal class UserStateHandlerTest {
269 271
         assertEquals("Hacking the planet", fakeUserState["acidBurn"]?.details?.awayMessage)
270 272
     }
271 273
 
274
+    @Test
275
+    fun `updates local nickname on server welcome`() {
276
+        fakeUserState += User("AcidBurn")
277
+
278
+        handler.processEvent(ircClient, ServerWelcome(EventMetadata(TestConstants.time), "the.gibson", "acidBurn2"))
279
+
280
+        assertEquals("acidBurn2", fakeLocalUser.nickname)
281
+    }
282
+
272 283
 }

+ 7
- 0
src/test/kotlin/com/dmdirc/ktirc/model/UserTest.kt View File

@@ -53,4 +53,11 @@ internal class UserTest {
53 53
         assertEquals("Hacking the planet", user2.awayMessage)
54 54
     }
55 55
 
56
+    @Test
57
+    fun `resets all fields`() {
58
+        val user = User("acidBurn", "acidB", "root.localhost", "acidBurn", "Libby", "Hacking the planet!")
59
+        user.reset("burn")
60
+        assertEquals(User("burn"), user)
61
+    }
62
+
56 63
 }

Loading…
Cancel
Save