Compare commits

...
Author SHA1 Message Date
admin f4f5cec2be chore: release android driver 1.0.55 (108) 2026-07-12 22:04:46 +02:00
admin 5a630f8401 Użyj origin realtime z bootstrapu 2026-07-12 21:59:46 +02:00
admin 54a3c58a22 chore: release android driver 1.0.54 (107) 2026-07-12 21:57:39 +02:00
admin 1c6a044c37 Dodaj Origin dla WebSocket Reverb 2026-07-12 21:55:01 +02:00
4 changed files with 51 additions and 8 deletions
+2 -2
View File
@@ -34,8 +34,8 @@ android {
applicationId = "pl.firmatpp.kierowca"
minSdk = 26
targetSdk = 35
versionCode = 106
versionName = "1.0.53"
versionCode = 108
versionName = "1.0.55"
setProperty("archivesBaseName", "pl.firmatpp.kierowca")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -117,6 +117,7 @@ data class RealtimeConfigDto(
val reverbEnabled: Boolean = false,
val reverbAppKey: String? = null,
val reverbWsBaseUrl: String? = null,
val reverbOrigin: String? = null,
)
data class RoutesBucketDto(
@@ -3,6 +3,7 @@ package pl.firmatpp.kierowca.sync
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import java.net.URI
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -42,16 +43,33 @@ class DriverRepositoryLiveSyncGateway(
}
interface LiveWebSocketFactory {
fun newWebSocket(url: String, listener: WebSocketListener): WebSocket
fun newWebSocket(url: String, origin: String?, listener: WebSocketListener): WebSocket
}
class OkHttpLiveWebSocketFactory(
private val client: OkHttpClient,
) : LiveWebSocketFactory {
override fun newWebSocket(url: String, listener: WebSocketListener): WebSocket =
client.newWebSocket(Request.Builder().url(url).build(), listener)
override fun newWebSocket(url: String, origin: String?, listener: WebSocketListener): WebSocket =
client.newWebSocket(
Request.Builder()
.url(url)
.header("Origin", origin?.takeIf { it.isNotBlank() } ?: websocketOrigin(url))
.build(),
listener,
)
}
internal fun websocketOrigin(url: String): String =
URI(
url
.replaceFirst("wss://", "https://")
.replaceFirst("ws://", "http://")
).let { uri ->
val defaultPort = (uri.scheme == "https" && uri.port == 443) || (uri.scheme == "http" && uri.port == 80)
val port = if (uri.port > 0 && !defaultPort) ":${uri.port}" else ""
"${uri.scheme}://${uri.host}$port"
}
enum class LiveSyncConnectionState {
Stopped,
WaitingForNetwork,
@@ -230,7 +248,7 @@ class DriverLiveSyncClient(
}
private fun connectNow(resetAttempt: Boolean = false) {
val wsUrl = synchronized(lock) {
val (wsUrl, origin) = synchronized(lock) {
val config = realtimeConfig ?: return
val id = driverId ?: return
if (!desiredActive || !foregroundActive || !networkAvailable || !isConfigUsable(config)) return
@@ -244,11 +262,15 @@ class DriverLiveSyncClient(
val appKey = config.reverbAppKey.orEmpty()
val wsBaseUrl = config.reverbWsBaseUrl.orEmpty()
wsBaseUrl.trimEnd('/') + "/" + appKey + "?protocol=7&client=android&version=1.0&flash=false"
Pair(
wsBaseUrl.trimEnd('/') + "/" + appKey + "?protocol=7&client=android&version=1.0&flash=false",
config.reverbOrigin,
)
}
val socket = webSocketFactory.newWebSocket(
wsUrl,
origin,
object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
handleMessage(webSocket, text)
@@ -23,8 +23,26 @@ class DriverLiveSyncClientTest {
reverbEnabled = true,
reverbAppKey = "app-key",
reverbWsBaseUrl = "wss://example.test/app",
reverbOrigin = "https://bootstrap-origin.test",
)
@Test
fun derivesBrowserCompatibleOriginFromWebSocketUrl() {
assertEquals("https://api-intranet.firmatpp.pl", websocketOrigin("wss://api-intranet.firmatpp.pl/ws/app/app-key"))
assertEquals("https://example.test:8443", websocketOrigin("wss://example.test:8443/app/app-key"))
assertEquals("http://localhost:8080", websocketOrigin("ws://localhost:8080/app/app-key"))
}
@Test
fun passesBootstrapOriginToWebSocketFactory() = runTest {
val factory = FakeWebSocketFactory()
val client = liveClient(factory = factory, scope = backgroundScope)
client.start("driver-1", config)
assertEquals("https://bootstrap-origin.test", factory.origins.single())
}
@Test
fun reconnectsWithBackoffAfterSocketFailure() = runTest {
val factory = FakeWebSocketFactory()
@@ -204,10 +222,12 @@ class DriverLiveSyncClientTest {
private class FakeWebSocketFactory : LiveWebSocketFactory {
val sockets = mutableListOf<FakeWebSocket>()
val origins = mutableListOf<String?>()
override fun newWebSocket(url: String, listener: WebSocketListener): WebSocket {
override fun newWebSocket(url: String, origin: String?, listener: WebSocketListener): WebSocket {
val socket = FakeWebSocket(listener)
sockets += socket
origins += origin
return socket
}
}