Report driver Reverb connection status

This commit is contained in:
admin
2026-07-02 14:58:12 +02:00
parent 705b8904a4
commit a3d39764e2
4 changed files with 62 additions and 3 deletions
@@ -18,6 +18,7 @@ import pl.firmatpp.kierowca.data.model.DriverDto
import pl.firmatpp.kierowca.data.model.OtpResponse import pl.firmatpp.kierowca.data.model.OtpResponse
import pl.firmatpp.kierowca.data.model.PhotoUploadResponse import pl.firmatpp.kierowca.data.model.PhotoUploadResponse
import pl.firmatpp.kierowca.data.model.PushTokenBody import pl.firmatpp.kierowca.data.model.PushTokenBody
import pl.firmatpp.kierowca.data.model.RealtimeStatusBody
import pl.firmatpp.kierowca.data.model.RequestOtpBody import pl.firmatpp.kierowca.data.model.RequestOtpBody
import pl.firmatpp.kierowca.data.model.RouteResponse import pl.firmatpp.kierowca.data.model.RouteResponse
import pl.firmatpp.kierowca.data.model.SyncStateResponse import pl.firmatpp.kierowca.data.model.SyncStateResponse
@@ -59,6 +60,10 @@ class DriverRepository(
api.storePushToken(authHeader(requireToken()), PushTokenBody(token)) api.storePushToken(authHeader(requireToken()), PushTokenBody(token))
} }
suspend fun storeRealtimeStatus(status: String, socketId: String? = null, error: String? = null) {
api.storeRealtimeStatus(authHeader(requireToken()), RealtimeStatusBody(status, socketId, error))
}
suspend fun deletePushToken() { suspend fun deletePushToken() {
val token = tokenStore.read() ?: return val token = tokenStore.read() ?: return
runCatching { api.deletePushToken(authHeader(token)) } runCatching { api.deletePushToken(authHeader(token)) }
@@ -9,6 +9,7 @@ import pl.firmatpp.kierowca.data.model.CompleteRouteResponse
import pl.firmatpp.kierowca.data.model.OtpResponse import pl.firmatpp.kierowca.data.model.OtpResponse
import pl.firmatpp.kierowca.data.model.PhotoUploadResponse import pl.firmatpp.kierowca.data.model.PhotoUploadResponse
import pl.firmatpp.kierowca.data.model.PushTokenBody import pl.firmatpp.kierowca.data.model.PushTokenBody
import pl.firmatpp.kierowca.data.model.RealtimeStatusBody
import pl.firmatpp.kierowca.data.model.RequestOtpBody import pl.firmatpp.kierowca.data.model.RequestOtpBody
import pl.firmatpp.kierowca.data.model.RouteResponse import pl.firmatpp.kierowca.data.model.RouteResponse
import pl.firmatpp.kierowca.data.model.SyncStateResponse import pl.firmatpp.kierowca.data.model.SyncStateResponse
@@ -72,6 +73,12 @@ interface MobileDriverApi {
@Body body: PushTokenBody, @Body body: PushTokenBody,
): Map<String, Boolean> ): Map<String, Boolean>
@PUT("mobile/driver/realtime-status")
suspend fun storeRealtimeStatus(
@Header("Authorization") authorization: String,
@Body body: RealtimeStatusBody,
): Map<String, Boolean>
@DELETE("mobile/driver/push-token") @DELETE("mobile/driver/push-token")
suspend fun deletePushToken( suspend fun deletePushToken(
@Header("Authorization") authorization: String, @Header("Authorization") authorization: String,
@@ -110,6 +110,12 @@ data class PushTokenBody(
val platform: String = "android", val platform: String = "android",
) )
data class RealtimeStatusBody(
val reverbStatus: String,
val socketId: String? = null,
val error: String? = null,
)
data class DriverRouteDto( data class DriverRouteDto(
val id: String, val id: String,
val startsAt: String, val startsAt: String,
@@ -4,6 +4,7 @@ import com.google.gson.Gson
import com.google.gson.JsonObject import com.google.gson.JsonObject
import com.google.gson.JsonParser import com.google.gson.JsonParser
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlinx.coroutines.Job
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
@@ -28,6 +29,8 @@ class DriverLiveSyncClient(
private val started = AtomicBoolean(false) private val started = AtomicBoolean(false)
private var webSocket: WebSocket? = null private var webSocket: WebSocket? = null
private var driverId: String? = null private var driverId: String? = null
private var socketId: String? = null
private var heartbeatJob: Job? = null
fun start(driverId: String) { fun start(driverId: String) {
if (BuildConfig.REVERB_APP_KEY.isBlank()) return if (BuildConfig.REVERB_APP_KEY.isBlank()) return
@@ -46,11 +49,15 @@ class DriverLiveSyncClient(
} }
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
stopHeartbeat()
reportRealtimeStatus("disconnected", reason.takeIf { it.isNotBlank() })
started.set(false) started.set(false)
scheduleReconnect() scheduleReconnect()
} }
override fun onFailure(webSocket: WebSocket, t: Throwable, response: okhttp3.Response?) { override fun onFailure(webSocket: WebSocket, t: Throwable, response: okhttp3.Response?) {
stopHeartbeat()
reportRealtimeStatus("error", t.message ?: response?.message)
started.set(false) started.set(false)
scheduleReconnect() scheduleReconnect()
} }
@@ -60,9 +67,12 @@ class DriverLiveSyncClient(
fun stop() { fun stop() {
started.set(false) started.set(false)
stopHeartbeat()
reportRealtimeStatus("disconnected", "client_stop")
webSocket?.close(1000, "logout") webSocket?.close(1000, "logout")
webSocket = null webSocket = null
driverId = null driverId = null
socketId = null
} }
fun close() { fun close() {
@@ -76,10 +86,18 @@ class DriverLiveSyncClient(
when (event) { when (event) {
"pusher:connection_established" -> { "pusher:connection_established" -> {
val socketId = root.dataObject()?.string("socket_id") ?: return socketId = root.dataObject()?.string("socket_id") ?: return
subscribe(socket, socketId) subscribe(socket, socketId ?: return)
}
"pusher_internal:subscription_succeeded" -> {
val channel = root.string("channel")
val id = driverId ?: return
if (channel == "private-driver-mobile.$id") {
reportRealtimeStatus("connected")
startHeartbeat()
onConnected() onConnected()
} }
}
"DriverMobileSyncHint" -> parseHint(root.dataObject())?.let(onHint) "DriverMobileSyncHint" -> parseHint(root.dataObject())?.let(onHint)
} }
} }
@@ -132,4 +150,27 @@ class DriverLiveSyncClient(
} }
} }
} }
private fun startHeartbeat() {
heartbeatJob?.cancel()
heartbeatJob = scope.launch {
while (started.get()) {
reportRealtimeStatus("connected")
delay(30_000)
}
}
}
private fun stopHeartbeat() {
heartbeatJob?.cancel()
heartbeatJob = null
}
private fun reportRealtimeStatus(status: String, error: String? = null) {
scope.launch {
runCatching {
repository.storeRealtimeStatus(status, socketId, error)
}
}
}
} }