Browse Source

DSL for ping timeout settings

wip-ping-timeouts
Chris Smith 5 years ago
parent
commit
85d453c2a9

+ 53
- 6
src/main/kotlin/com/dmdirc/ktirc/Dsl.kt View File

1
 package com.dmdirc.ktirc
1
 package com.dmdirc.ktirc
2
 
2
 
3
+import java.time.Duration
4
+
3
 /**
5
 /**
4
  * Dsl marker for [IrcClient] dsl.
6
  * Dsl marker for [IrcClient] dsl.
5
  */
7
  */
6
 @DslMarker
8
 @DslMarker
7
 annotation class IrcClientDsl
9
 annotation class IrcClientDsl
8
 
10
 
9
-internal data class IrcClientConfig(
10
-        val server: ServerConfig,
11
-        val profile: ProfileConfig,
12
-        val behaviour: ClientBehaviour,
13
-        val sasl: SaslConfig?)
14
-
15
 /**
11
 /**
16
  * Dsl for configuring an IRC Client.
12
  * Dsl for configuring an IRC Client.
17
  *
13
  *
206
     }
202
     }
207
 }
203
 }
208
 
204
 
205
+@IrcClientDsl
206
+class PingConfig {
207
+
208
+    /**
209
+     * The period of time we will wait between sending pings to the server.
210
+     *
211
+     * If [incomingLinesResetTimer] is enabled, then a ping will be sent this period of time after the last line
212
+     * is received from the server. Otherwise, it will be sent this period of time after the last PONG response.
213
+     */
214
+    var sendPeriod: Duration? = null
215
+
216
+    /**
217
+     * The period of time to wait for a reply.
218
+     *
219
+     * If the server does not respond to a PING in this period, we consider it stoned and disconnect.
220
+     */
221
+    var responseGracePeriod: Duration? = null
222
+
223
+    /**
224
+     * Whether to treat incoming lines from the server as an indication that it is still active.
225
+     *
226
+     * This reduces the amount of pings that KtIrc will send, but can result in KtIrc staying connected even if the
227
+     * server is severely lagged or ignores all lines sent to it (for example).
228
+     */
229
+    var incomingLinesResetTimer: Boolean = false
230
+
231
+}
232
+
209
 /**
233
 /**
210
  * Dsl for configuring the behaviour of an [IrcClient].
234
  * Dsl for configuring the behaviour of an [IrcClient].
211
  */
235
  */
212
 @IrcClientDsl
236
 @IrcClientDsl
213
 class BehaviourConfig : ClientBehaviour {
237
 class BehaviourConfig : ClientBehaviour {
238
+
214
     override var requestModesOnJoin = false
239
     override var requestModesOnJoin = false
215
     override var alwaysEchoMessages = false
240
     override var alwaysEchoMessages = false
216
     override var preferIPv6 = true
241
     override var preferIPv6 = true
242
+
243
+    override var pingTimeouts: PingTimeouts? = null
244
+        internal set(value) {
245
+            check(field == null) { "ping timeouts may only be specified once" }
246
+            field = value
247
+        }
248
+
249
+    /**
250
+     * Configures how frequently KtIrc will send pings, and how it will deal with non-responsive servers.
251
+     *
252
+     * If not specified, KtIrc will not send pings.
253
+     *
254
+     * See [PingConfig].
255
+     */
256
+    @IrcClientDsl
257
+    fun sendPings(block: PingConfig.() -> Unit) {
258
+        val config = PingConfig().apply(block)
259
+        requireNotNull(config.sendPeriod) { "send period must be specified" }
260
+        requireNotNull(config.responseGracePeriod) { "response grace period must be specified" }
261
+        pingTimeouts = IrcPingTimeouts(config.sendPeriod!!, config.responseGracePeriod!!, config.incomingLinesResetTimer)
262
+    }
263
+
217
 }
264
 }

+ 39
- 0
src/main/kotlin/com/dmdirc/ktirc/IrcClient.kt View File

7
 import com.dmdirc.ktirc.model.*
7
 import com.dmdirc.ktirc.model.*
8
 import com.dmdirc.ktirc.util.RemoveIn
8
 import com.dmdirc.ktirc.util.RemoveIn
9
 import kotlinx.coroutines.Deferred
9
 import kotlinx.coroutines.Deferred
10
+import java.time.Duration
10
 
11
 
11
 /**
12
 /**
12
  * Primary interface for interacting with KtIrc.
13
  * Primary interface for interacting with KtIrc.
186
 
187
 
187
 }
188
 }
188
 
189
 
190
+/**
191
+ * Defines the configuration for sending pings and dealing with ping timeouts.
192
+ */
193
+interface PingTimeouts {
194
+
195
+    /**
196
+     * The period of time we will wait between sending pings to the server.
197
+     *
198
+     * If [incomingLinesResetTimer] is enabled, then a ping will be sent this period of time after the last line
199
+     * is received from the server. Otherwise, it will be sent this period of time after the last PONG response.
200
+     */
201
+    val sendPeriod: Duration
202
+
203
+    /**
204
+     * The period of time to wait for a reply.
205
+     *
206
+     * If the server does not respond to a PING in this period, we consider it stoned and disconnect.
207
+     */
208
+    val responseGracePeriod: Duration
209
+
210
+    /**
211
+     * Whether to treat incoming lines from the server as an indication that it is still active.
212
+     *
213
+     * This reduces the amount of pings that KtIrc will send, but can result in KtIrc staying connected even if the
214
+     * server is severely lagged or ignores all lines sent to it (for example).
215
+     */
216
+    val incomingLinesResetTimer: Boolean
217
+
218
+}
219
+
189
 /**
220
 /**
190
  * Defines the behaviour of an [IrcClient].
221
  * Defines the behaviour of an [IrcClient].
191
  */
222
  */
210
      */
241
      */
211
     val preferIPv6: Boolean
242
     val preferIPv6: Boolean
212
 
243
 
244
+    /**
245
+     * The settings to use for sending pings to the server, and timing out connections that don't reply to those
246
+     * pings.
247
+     *
248
+     * If unset (i.e., `null`), no pings will be sent, and KtIrc will never time out servers.
249
+     */
250
+    val pingTimeouts: PingTimeouts?
251
+
213
 }
252
 }
214
 
253
 
215
 /**
254
 /**

+ 11
- 0
src/main/kotlin/com/dmdirc/ktirc/IrcClientImpl.kt View File

23
 import java.time.Duration
23
 import java.time.Duration
24
 import java.util.logging.Level
24
 import java.util.logging.Level
25
 
25
 
26
+internal data class IrcClientConfig(
27
+        val server: ServerConfig,
28
+        val profile: ProfileConfig,
29
+        val behaviour: ClientBehaviour,
30
+        val sasl: SaslConfig?)
31
+
32
+internal data class IrcPingTimeouts(
33
+        override val sendPeriod: Duration,
34
+        override val responseGracePeriod: Duration,
35
+        override val incomingLinesResetTimer: Boolean) : PingTimeouts
36
+
26
 /**
37
 /**
27
  * Concrete implementation of an [IrcClient].
38
  * Concrete implementation of an [IrcClient].
28
  */
39
  */

+ 87
- 0
src/test/kotlin/com/dmdirc/ktirc/DslTest.kt View File

3
 import org.junit.jupiter.api.Assertions.*
3
 import org.junit.jupiter.api.Assertions.*
4
 import org.junit.jupiter.api.Test
4
 import org.junit.jupiter.api.Test
5
 import org.junit.jupiter.api.assertThrows
5
 import org.junit.jupiter.api.assertThrows
6
+import java.time.Duration
6
 
7
 
7
 internal class IrcClientConfigBuilderTest {
8
 internal class IrcClientConfigBuilderTest {
8
 
9
 
212
         assertFalse(config.behaviour.requestModesOnJoin)
213
         assertFalse(config.behaviour.requestModesOnJoin)
213
     }
214
     }
214
 
215
 
216
+    @Test
217
+    fun `defaults to null ping timeouts if sendPings omitted`() {
218
+        val config = IrcClientConfigBuilder().apply {
219
+            profile { nickname = "acidBurn" }
220
+            server { host = "thegibson.com" }
221
+            behaviour {
222
+                requestModesOnJoin = true
223
+            }
224
+        }.build()
225
+
226
+        assertNull(config.behaviour.pingTimeouts)
227
+    }
228
+
229
+    @Test
230
+    fun `throws if sendPings specified without send period`() {
231
+        assertThrows<IllegalArgumentException> {
232
+            IrcClientConfigBuilder().apply {
233
+                profile { nickname = "acidBurn" }
234
+                server { host = "thegibson.com" }
235
+                behaviour {
236
+                    requestModesOnJoin = true
237
+                    sendPings {
238
+                        responseGracePeriod = Duration.ofSeconds(10)
239
+                    }
240
+                }
241
+            }.build()
242
+        }
243
+    }
244
+
245
+    @Test
246
+    fun `throws if sendPings specified without grace period`() {
247
+        assertThrows<IllegalArgumentException> {
248
+            IrcClientConfigBuilder().apply {
249
+                profile { nickname = "acidBurn" }
250
+                server { host = "thegibson.com" }
251
+                behaviour {
252
+                    requestModesOnJoin = true
253
+                    sendPings {
254
+                        sendPeriod = Duration.ofSeconds(10)
255
+                    }
256
+                }
257
+            }.build()
258
+        }
259
+    }
260
+
261
+    @Test
262
+    fun `throws if sendPings specified twice`() {
263
+        assertThrows<IllegalStateException> {
264
+            IrcClientConfigBuilder().apply {
265
+                profile { nickname = "acidBurn" }
266
+                server { host = "thegibson.com" }
267
+                behaviour {
268
+                    requestModesOnJoin = true
269
+                    sendPings {
270
+                        sendPeriod = Duration.ofSeconds(10)
271
+                        responseGracePeriod = Duration.ofSeconds(10)
272
+                    }
273
+                    sendPings {
274
+                        sendPeriod = Duration.ofSeconds(10)
275
+                        responseGracePeriod = Duration.ofSeconds(10)
276
+                    }
277
+                }
278
+            }.build()
279
+        }
280
+    }
281
+
282
+    @Test
283
+    fun `configures ping timeouts`() {
284
+        val config = IrcClientConfigBuilder().apply {
285
+            profile { nickname = "acidBurn" }
286
+            server { host = "thegibson.com" }
287
+            behaviour {
288
+                requestModesOnJoin = true
289
+                sendPings {
290
+                    sendPeriod = Duration.ofSeconds(50)
291
+                    responseGracePeriod = Duration.ofSeconds(100)
292
+                    incomingLinesResetTimer = true
293
+                }
294
+            }
295
+        }.build()
296
+
297
+        assertEquals(50, config.behaviour.pingTimeouts?.sendPeriod?.seconds)
298
+        assertEquals(100, config.behaviour.pingTimeouts?.responseGracePeriod?.seconds)
299
+        assertEquals(true, config.behaviour.pingTimeouts?.incomingLinesResetTimer)
300
+    }
301
+
215
     @Test
302
     @Test
216
     fun `applies sasl settings`() {
303
     fun `applies sasl settings`() {
217
         val config = IrcClientConfigBuilder().apply {
304
         val config = IrcClientConfigBuilder().apply {

Loading…
Cancel
Save