Browse Source

Added pong handling, docs for sendPings

wip-ping-timeouts
Chris Smith 5 years ago
parent
commit
1c2f55daaf

+ 49
- 0
docs/index.adoc View File

@@ -237,6 +237,12 @@ profile {
237 237
 behaviour {
238 238
     requestModesOnJoin = true
239 239
     alwaysEchoMessages = true
240
+    preferIPv6 = false
241
+    sendPings {
242
+        sendPeriod = Duration.ofSeconds(120)
243
+        responseGracePeriod = Duration.ofSeconds(30)
244
+        incomingLinesResetTimer = true
245
+    }
240 246
 }
241 247
 
242 248
 sasl {
@@ -318,6 +324,41 @@ advanced IRC features even if the server doesn't support them:
318 324
 
319 325
 The behaviour block is optional in its entirety.
320 326
 
327
+==== Ping timeouts
328
+
329
+The behaviour config has an optional `sendPings` configuration, which
330
+instructs KtIrc to automatically send ping requests to the server.
331
+This ensures that the server is still connected and operating properly,
332
+and will trigger a disconnect if that is not the case.
333
+
334
+The sendPings block looks like:
335
+
336
+[source,kotlin]
337
+----
338
+sendPings {
339
+    sendPeriod = Duration.ofSeconds(120) <1>
340
+    responseGracePeriod = Duration.ofSeconds(30) <2>
341
+    incomingLinesResetTimer = true <3>
342
+}
343
+----
344
+<1> The `sendPeriod` defines how often KtIrc should send pings. Most
345
+    applications will probably want to send pings somewhere between
346
+    every 30 seconds and every minute or two. If the `sendPings`
347
+    block is present, this field is required.
348
+<2> The `responseGracePeriod` defines how long KtIrc will wait for a
349
+    response from the server before it considers the server to be
350
+    malfunctioning. Setting this too low will result in disconnects
351
+    when the connection to the server is merely suffering from high
352
+    latency, rather than irreparably broken.  If the `sendPings`
353
+    block is present, this field is required.
354
+<3> The only optional field in the `sendPings` block, the
355
+    `incomingLinesResetTimer` setting determines whether KtIrc will
356
+    treat _any_ incoming line in the same way as a `PONG` response;
357
+    in effect it prevents KtIrc from disconnecting from a server
358
+    suffering from high latency as long as the server keeps sending
359
+    _something_. When disabled (or not specified), KtIrc will require
360
+    an explicit `PONG` reply.
361
+
321 362
 === SASL configuration
322 363
 
323 364
 SASL ("Simple Authentication and Security Layer") is a standard mechanism
@@ -1179,6 +1220,14 @@ If the user is no longer logged in to an account, `newAccount` will be
1179 1220
 Raised when the IRC server sends a PING message to the client. KtIrc will
1180 1221
 automatically reply with an appropriate PONG.
1181 1222
 
1223
+==== PongReceived
1224
+* Type: IrcEvent
1225
+* Properties:
1226
+** `nonce`: `ByteArray` - the unique data that was sent in the PING
1227
+
1228
+Raised when the IRC server sends a PONG message to the client. KtIrc can
1229
+automatically send pings and handle pongs, see <<Ping timeouts>>.
1230
+
1182 1231
 ==== ServerFeaturesUpdated
1183 1232
 * Type: IrcEvent
1184 1233
 * Properties:

+ 3
- 0
src/main/kotlin/com/dmdirc/ktirc/events/Events.kt View File

@@ -104,6 +104,9 @@ class ServerFeaturesUpdated(metadata: EventMetadata, val serverFeatures: ServerF
104 104
 /** Raised whenever a PING is received from the server. */
105 105
 class PingReceived(metadata: EventMetadata, val nonce: ByteArray) : IrcEvent(metadata)
106 106
 
107
+/** Raised whenever a PONG is received from the server. */
108
+class PongReceived(metadata: EventMetadata, val nonce: ByteArray) : IrcEvent(metadata)
109
+
107 110
 /** Raised when a user joins a channel. */
108 111
 class ChannelJoined(metadata: EventMetadata, override val user: User, channel: String)
109 112
     : TargetedEvent(metadata, channel), SourcedEvent, ChannelMembershipAdjustment {

+ 7
- 3
src/main/kotlin/com/dmdirc/ktirc/messages/processors/PingProcessor.kt View File

@@ -1,13 +1,17 @@
1 1
 package com.dmdirc.ktirc.messages.processors
2 2
 
3 3
 import com.dmdirc.ktirc.events.PingReceived
4
-import com.dmdirc.ktirc.messages.processors.MessageProcessor
4
+import com.dmdirc.ktirc.events.PongReceived
5 5
 import com.dmdirc.ktirc.model.IrcMessage
6 6
 
7 7
 internal class PingProcessor : MessageProcessor {
8 8
 
9
-    override val commands = arrayOf("PING")
9
+    override val commands = arrayOf("PING", "PONG")
10 10
 
11
-    override fun process(message: IrcMessage) = listOf(PingReceived(message.metadata, message.params[0]))
11
+    override fun process(message: IrcMessage) = if (message.command == "PING") {
12
+        listOf(PingReceived(message.metadata, message.params[0]))
13
+    } else {
14
+        listOf(PongReceived(message.metadata, message.params[0]))
15
+    }
12 16
 
13 17
 }

+ 42
- 0
src/test/kotlin/com/dmdirc/ktirc/messages/processors/PingProcessorTest.kt View File

@@ -0,0 +1,42 @@
1
+package com.dmdirc.ktirc.messages.processors
2
+
3
+import com.dmdirc.ktirc.TestConstants
4
+import com.dmdirc.ktirc.events.PingReceived
5
+import com.dmdirc.ktirc.events.PongReceived
6
+import com.dmdirc.ktirc.model.IrcMessage
7
+import com.dmdirc.ktirc.params
8
+import com.dmdirc.ktirc.util.currentTimeProvider
9
+import org.junit.jupiter.api.Assertions.assertEquals
10
+import org.junit.jupiter.api.BeforeEach
11
+import org.junit.jupiter.api.Test
12
+
13
+internal class PingProcessorTest {
14
+
15
+    @BeforeEach
16
+    fun setUp() {
17
+        currentTimeProvider = { TestConstants.time }
18
+    }
19
+
20
+    @Test
21
+    fun `raises ping event with nonce`() {
22
+        val events = PingProcessor().process(
23
+                IrcMessage(emptyMap(), null, "PING", params("12345")))
24
+        assertEquals(1, events.size)
25
+
26
+        val event = events[0] as PingReceived
27
+        assertEquals(TestConstants.time, event.metadata.time)
28
+        assertEquals("12345", String(event.nonce))
29
+    }
30
+
31
+    @Test
32
+    fun `raises pong event with nonce`() {
33
+        val events = PingProcessor().process(
34
+                IrcMessage(emptyMap(), null, "PONG", params("12345")))
35
+        assertEquals(1, events.size)
36
+
37
+        val event = events[0] as PongReceived
38
+        assertEquals(TestConstants.time, event.metadata.time)
39
+        assertEquals("12345", String(event.nonce))
40
+    }
41
+
42
+}

Loading…
Cancel
Save