@@ -3,11 +3,8 @@ package dev.schlaubi.mastermind.core
33import androidx.compose.runtime.getValue
44import androidx.compose.runtime.mutableStateOf
55import androidx.compose.runtime.setValue
6- import dev.schlaubi.gtakiller.common.Event
7- import dev.schlaubi.gtakiller.common.KillGtaEvent
8- import dev.schlaubi.gtakiller.common.Route
9- import dev.schlaubi.gtakiller.common.Status
10- import dev.schlaubi.gtakiller.common.Username
6+ import dev.kord.gateway.retry.LinearRetry
7+ import dev.schlaubi.gtakiller.common.*
118import dev.schlaubi.mastermind.core.settings.settings
129import io.github.oshai.kotlinlogging.KotlinLogging
1310import io.ktor.client.*
@@ -17,6 +14,7 @@ import io.ktor.client.plugins.contentnegotiation.*
1714import io.ktor.client.plugins.resources.*
1815import io.ktor.client.plugins.websocket.*
1916import io.ktor.http.*
17+ import io.ktor.serialization.*
2018import io.ktor.serialization.kotlinx.*
2119import io.ktor.serialization.kotlinx.json.*
2220import io.ktor.websocket.*
@@ -25,6 +23,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
2523import kotlinx.coroutines.flow.asSharedFlow
2624import kotlinx.serialization.json.Json
2725import kotlin.coroutines.CoroutineContext
26+ import kotlin.time.Duration.Companion.seconds
2827
2928var currentApi by mutableStateOf<APIClient ?>(null )
3029
@@ -40,6 +39,7 @@ class APIClient(val url: Url) : CoroutineScope {
4039 json()
4140 }
4241 install(WebSockets ) {
42+ pingInterval = 2 .seconds
4343 contentConverter = KotlinxWebsocketSerializationConverter (Json )
4444 }
4545 install(Resources )
@@ -52,38 +52,48 @@ class APIClient(val url: Url) : CoroutineScope {
5252 private var webSocketSession: DefaultClientWebSocketSession ? = null
5353 private val _events = MutableSharedFlow <Event >()
5454 val events = _events .asSharedFlow()
55+ private val retry = LinearRetry (2 .seconds, 20 .seconds, 10 )
5556
56- suspend fun connectToWebSocket () {
57+ suspend fun connectToWebSocket (isRetry : Boolean = false ) {
5758 webSocketSession?.close()
58- val session = client.webSocketSession {
59- url {
60- url.takeFrom(this @APIClient.url)
61- protocol = if (url.protocol.isSecure()) {
62- URLProtocol .WSS
63- } else {
64- URLProtocol .WS
59+ val session = try {
60+ client.webSocketSession {
61+ url {
62+ url.takeFrom(this @APIClient.url)
63+ protocol = if (url.protocol.isSecure()) {
64+ URLProtocol .WSS
65+ } else {
66+ URLProtocol .WS
67+ }
68+
69+ client.href(Route .Events (), this )
6570 }
6671
67- client.href( Route . Events (), this )
72+ headers.append( HttpHeaders . Username , settings.userName )
6873 }
69-
70- headers.append(HttpHeaders .Username , settings.userName)
74+ } catch (e: Exception ) {
75+ LOG .error(e) { " Could not connect to websocket" }
76+ if (isRetry) {
77+ retry.retry()
78+ LOG .warn { " Retrying ..." }
79+ connectToWebSocket(isRetry = true )
80+ }
81+ return
7182 }
83+ retry.reset()
7284
7385 webSocketSession = session
7486
7587 session.launch {
76- launch {
77- while (isActive) {
78- val event = session.receiveDeserialized<Event >()
88+ for (message in session.incoming) {
89+ val event = client.plugin(WebSockets ).contentConverter!! .deserialize<Event >(message)
7990 LOG .debug { " Received event: $event " }
8091 _events .emit(event)
8192 handleEvent(event)
8293 }
83- }
8494
85- val reason = session.closeReason.await()
86- LOG .info { " Lost connection to websocket: ${reason?.message} " }
95+ LOG .info { " Lost connection to websocket " }
96+ connectToWebSocket(isRetry = true )
8797 }
8898 }
8999
0 commit comments