fix: don't reconnect when command was superseded

We only want to do the reconnect if the previous command was the
schedule reconnect, if the websocket connection got started another way
or was closed, we don't want to do the reconnect.
This commit is contained in:
Jannis Mattheis
2025-02-15 11:45:12 +01:00
parent a82d985027
commit 07b1da9de1
2 changed files with 24 additions and 10 deletions

View File

@@ -1,6 +1,7 @@
package com.github.gotify.service package com.github.gotify.service
import android.app.AlarmManager import android.app.AlarmManager
import android.app.AlarmManager.OnAlarmListener
import android.os.Build import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@@ -29,9 +30,10 @@ internal class WebSocketConnection(
private val ID = AtomicLong(0) private val ID = AtomicLong(0)
} }
private var alarmManagerCallback: OnAlarmListener? = null
private var handlerCallback: Runnable? = null
private val client: OkHttpClient private val client: OkHttpClient
private val reconnectHandler = Handler(Looper.getMainLooper()) private val reconnectHandler = Handler(Looper.getMainLooper())
private val reconnectCallback = Runnable { start() }
private var errorCount = 0 private var errorCount = 0
private var webSocket: WebSocket? = null private var webSocket: WebSocket? = null
@@ -106,6 +108,13 @@ internal class WebSocketConnection(
@Synchronized @Synchronized
fun close() { fun close() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
alarmManagerCallback?.run(alarmManager::cancel)
alarmManagerCallback = null
} else {
handlerCallback?.run(reconnectHandler::removeCallbacks)
handlerCallback = null
}
if (webSocket != null) { if (webSocket != null) {
webSocket?.close(1000, "") webSocket?.close(1000, "")
closed() closed()
@@ -119,8 +128,10 @@ internal class WebSocketConnection(
state = State.Disconnected state = State.Disconnected
} }
fun scheduleReconnectNow(seconds: Long) = scheduleReconnect(ID.get(), seconds)
@Synchronized @Synchronized
fun scheduleReconnect(seconds: Long) { fun scheduleReconnect(id: Long, seconds: Long) {
if (state == State.Connecting || state == State.Connected) { if (state == State.Connecting || state == State.Connected) {
return return
} }
@@ -130,17 +141,23 @@ internal class WebSocketConnection(
Logger.info("WebSocket: scheduling a restart in $seconds second(s) (via alarm manager)") Logger.info("WebSocket: scheduling a restart in $seconds second(s) (via alarm manager)")
val future = Calendar.getInstance() val future = Calendar.getInstance()
future.add(Calendar.SECOND, seconds.toInt()) future.add(Calendar.SECOND, seconds.toInt())
alarmManagerCallback?.run(alarmManager::cancel)
val cb = OnAlarmListener { syncExec(id) { start() } }
alarmManagerCallback = cb
alarmManager.setExact( alarmManager.setExact(
AlarmManager.RTC_WAKEUP, AlarmManager.RTC_WAKEUP,
future.timeInMillis, future.timeInMillis,
"reconnect-tag", "reconnect-tag",
{ start() }, cb,
null null
) )
} else { } else {
Logger.info("WebSocket: scheduling a restart in $seconds second(s)") Logger.info("WebSocket: scheduling a restart in $seconds second(s)")
reconnectHandler.removeCallbacks(reconnectCallback) handlerCallback?.run(reconnectHandler::removeCallbacks)
reconnectHandler.postDelayed(reconnectCallback, TimeUnit.SECONDS.toMillis(seconds)) val cb = Runnable { syncExec(id) { start() } }
handlerCallback = cb
reconnectHandler.postDelayed(cb, TimeUnit.SECONDS.toMillis(seconds))
} }
} }
@@ -190,7 +207,7 @@ internal class WebSocketConnection(
val minutes = (errorCount * 2 - 1).coerceAtMost(20) val minutes = (errorCount * 2 - 1).coerceAtMost(20)
onFailure.execute(response?.message ?: "unreachable", minutes) onFailure.execute(response?.message ?: "unreachable", minutes)
scheduleReconnect(TimeUnit.MINUTES.toSeconds(minutes.toLong())) scheduleReconnect(id, TimeUnit.MINUTES.toSeconds(minutes.toLong()))
} }
super.onFailure(webSocket, t, response) super.onFailure(webSocket, t, response)
} }

View File

@@ -172,10 +172,7 @@ internal class WebSocketService : Service() {
} }
private fun doReconnect() { private fun doReconnect() {
if (connection == null) { connection?.scheduleReconnectNow(15)
return
}
connection!!.scheduleReconnect(15)
} }
private fun onFailure(status: String, minutes: Int) { private fun onFailure(status: String, minutes: Int) {