From a1f0b2841e741777aaf7761d35d8469807379ade Mon Sep 17 00:00:00 2001 From: Luc de Cafmeyer Date: Wed, 2 Apr 2025 13:08:36 +0200 Subject: [PATCH 1/3] replace user-id with user-agent --- core/build.gradle.kts | 13 +++++++++++++ .../kotlin/com/powersync/sync/SyncStream.kt | 17 +++++++++++------ .../kotlin/com/powersync/sync/SyncStream.ios.kt | 10 ++++++++++ .../kotlin/com/powersync/sync/SyncStream.jvm.kt | 7 +++++++ gradle/libs.versions.toml | 2 ++ 5 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 core/src/iosMain/kotlin/com/powersync/sync/SyncStream.ios.kt create mode 100644 core/src/jvmMain/kotlin/com/powersync/sync/SyncStream.jvm.kt diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 96f77274..2bb4d52f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest import org.jetbrains.kotlin.gradle.tasks.KotlinTest import org.jetbrains.kotlin.konan.target.Family +import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING plugins { @@ -21,6 +22,7 @@ plugins { id("com.powersync.plugins.sonatype") alias(libs.plugins.mokkery) alias(libs.plugins.kotlin.atomicfu) + alias(libs.plugins.buildKonfig) } val binariesFolder = project.layout.buildDirectory.dir("binaries/desktop") @@ -320,6 +322,17 @@ androidComponents.onVariants { } } +buildkonfig { + packageName = "com.powersync.core" + defaultConfigs { + buildConfigField(STRING, "LIBRARY_VERSION", version.toString()) + + // TODO: Swift SDK relies on this too. + // Find out how to add a build flag to toggle between "powersync-kotlin" and "powersync-swift". + buildConfigField(STRING, "LIBRARY_NAME", "powersync-kotlin") + } +} + tasks.named(kotlin.jvm().compilations["main"].processResourcesTaskName) { from(downloadPowersyncDesktopBinaries) } diff --git a/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt b/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt index 23b3e5ed..54d1ea7b 100644 --- a/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt +++ b/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt @@ -22,10 +22,6 @@ import io.ktor.client.request.headers import io.ktor.client.request.preparePost import io.ktor.client.request.setBody import io.ktor.client.statement.bodyAsText -import io.ktor.http.ContentType -import io.ktor.http.HttpHeaders -import io.ktor.http.HttpStatusCode -import io.ktor.http.contentType import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.readUTF8Line import kotlinx.coroutines.CancellationException @@ -35,6 +31,9 @@ import kotlinx.coroutines.flow.flow import kotlinx.datetime.Clock import kotlinx.serialization.encodeToString import kotlinx.serialization.json.JsonObject +import com.powersync.core.BuildKonfig.LIBRARY_NAME +import com.powersync.core.BuildKonfig.LIBRARY_VERSION +import io.ktor.http.* internal class SyncStream( private val bucketStorage: BucketStorage, @@ -172,7 +171,7 @@ internal class SyncStream( contentType(ContentType.Application.Json) headers { append(HttpHeaders.Authorization, "Token ${credentials.token}") - append("User-Id", credentials.userId ?: "") + append("User-Agent", powerSyncUserAgent()) } } if (response.status.value == 401) { @@ -186,6 +185,10 @@ internal class SyncStream( return body.data.writeCheckpoint } + private fun powerSyncUserAgent(): String { + "$LIBRARY_NAME/$LIBRARY_VERSION ${getOS()}" + } + private fun streamingSyncRequest(req: StreamingSyncRequest): Flow = flow { val credentials = connector.getCredentialsCached() @@ -200,7 +203,7 @@ internal class SyncStream( contentType(ContentType.Application.Json) headers { append(HttpHeaders.Authorization, "Token ${credentials.token}") - append("User-Id", credentials.userId ?: "") + append("User-Agent", powerSyncUserAgent()) } timeout { socketTimeoutMillis = Long.MAX_VALUE } setBody(bodyJson) @@ -449,6 +452,8 @@ internal class SyncStream( } } +internal expect fun getOS(): String + internal data class SyncStreamState( var targetCheckpoint: Checkpoint?, var validatedCheckpoint: Checkpoint?, diff --git a/core/src/iosMain/kotlin/com/powersync/sync/SyncStream.ios.kt b/core/src/iosMain/kotlin/com/powersync/sync/SyncStream.ios.kt new file mode 100644 index 00000000..d0e691ff --- /dev/null +++ b/core/src/iosMain/kotlin/com/powersync/sync/SyncStream.ios.kt @@ -0,0 +1,10 @@ +package com.powersync.sync + +import platform.UIKit.UIDevice + +internal actual fun getOS(): String { + val current = UIDevice.currentDevice + val version = current.systemVersion + + return "ios $version" +} \ No newline at end of file diff --git a/core/src/jvmMain/kotlin/com/powersync/sync/SyncStream.jvm.kt b/core/src/jvmMain/kotlin/com/powersync/sync/SyncStream.jvm.kt new file mode 100644 index 00000000..e8dee744 --- /dev/null +++ b/core/src/jvmMain/kotlin/com/powersync/sync/SyncStream.jvm.kt @@ -0,0 +1,7 @@ +package com.powersync.sync + +internal actual fun getOS(): String { + val os = System.getProperty("os.name") + val version = System.getProperty("os.version") + return "jvm $os/$version" +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 224c0422..13d19789 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,6 +40,7 @@ mokkery = "2.7.1" kotlinter = "5.0.1" keeper = "0.16.1" atomicfu = "0.27.0" +buildKonfig = "0.17.0" # Sample - Android androidx-core = "1.15.0" @@ -128,6 +129,7 @@ kotlinter = { id = "org.jmailen.kotlinter", version.ref = "kotlinter" } keeper = { id = "com.slack.keeper", version.ref = "keeper" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-atomicfu = { id = "org.jetbrains.kotlinx.atomicfu", version.ref = "atomicfu" } +buildKonfig = { id = "com.codingfeline.buildkonfig", version.ref = "buildKonfig" } [bundles] sqldelight = [ From cc1c6ba4aa3ed9d9a844db34f502fbde9071f574 Mon Sep 17 00:00:00 2001 From: Luc de Cafmeyer Date: Wed, 2 Apr 2025 13:12:59 +0200 Subject: [PATCH 2/3] fix: add return keyword --- core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt b/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt index 54d1ea7b..5082bac0 100644 --- a/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt +++ b/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt @@ -186,7 +186,7 @@ internal class SyncStream( } private fun powerSyncUserAgent(): String { - "$LIBRARY_NAME/$LIBRARY_VERSION ${getOS()}" + return "$LIBRARY_NAME/$LIBRARY_VERSION ${getOS()}" } private fun streamingSyncRequest(req: StreamingSyncRequest): Flow = From aff394c58c62dc55cb47a0d64c06f44cb9866113 Mon Sep 17 00:00:00 2001 From: Luc de Cafmeyer Date: Thu, 3 Apr 2025 15:41:15 +0200 Subject: [PATCH 3/3] add missing actual fun and configure linter to ignore BuildKonfig --- core/build.gradle.kts | 15 ++++++++-- .../com/powersync/sync/SyncStream.android.kt | 9 ++++++ .../kotlin/com/powersync/sync/SyncStream.kt | 29 +++++++++++++++---- .../com/powersync/sync/SyncStream.ios.kt | 2 +- gradle/libs.versions.toml | 2 +- 5 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 core/src/androidMain/kotlin/com/powersync/sync/SyncStream.android.kt diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 2bb4d52f..80282cb6 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,3 +1,4 @@ +import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING import com.powersync.plugins.sonatype.setupGithubRepository import de.undercouch.gradle.tasks.download.Download import org.gradle.api.tasks.testing.logging.TestExceptionFormat @@ -9,7 +10,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.TestExecutable import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest import org.jetbrains.kotlin.gradle.tasks.KotlinTest import org.jetbrains.kotlin.konan.target.Family -import com.codingfeline.buildkonfig.compiler.FieldSpec.Type.STRING plugins { @@ -317,8 +317,8 @@ android { } androidComponents.onVariants { - tasks.named("preBuild") { - dependsOn(moveJDBCJNIFiles) + tasks.named("preBuild") { + dependsOn(moveJDBCJNIFiles) } } @@ -362,4 +362,13 @@ tasks.withType { showStackTraces = true } } + +tasks.formatKotlinCommonMain { + exclude { it.file.name == "BuildKonfig.kt" } +} + +tasks.lintKotlinCommonMain { + exclude { it.file.name == "BuildKonfig.kt" } +} + setupGithubRepository() diff --git a/core/src/androidMain/kotlin/com/powersync/sync/SyncStream.android.kt b/core/src/androidMain/kotlin/com/powersync/sync/SyncStream.android.kt new file mode 100644 index 00000000..a9c4c67a --- /dev/null +++ b/core/src/androidMain/kotlin/com/powersync/sync/SyncStream.android.kt @@ -0,0 +1,9 @@ +package com.powersync.sync + +import android.os.Build + +internal actual fun getOS(): String { + val base = Build.VERSION.BASE_OS + val version = Build.VERSION.SDK_INT + return "android $base/$version" +} diff --git a/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt b/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt index 5082bac0..4f8155ad 100644 --- a/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt +++ b/core/src/commonMain/kotlin/com/powersync/sync/SyncStream.kt @@ -8,6 +8,8 @@ import com.powersync.bucket.BucketStorage import com.powersync.bucket.Checkpoint import com.powersync.bucket.WriteCheckpointResponse import com.powersync.connectors.PowerSyncBackendConnector +import com.powersync.core.BuildKonfig.LIBRARY_NAME +import com.powersync.core.BuildKonfig.LIBRARY_VERSION import com.powersync.db.crud.CrudEntry import com.powersync.utils.JsonUtil import io.ktor.client.HttpClient @@ -22,6 +24,10 @@ import io.ktor.client.request.headers import io.ktor.client.request.preparePost import io.ktor.client.request.setBody import io.ktor.client.statement.bodyAsText +import io.ktor.http.ContentType +import io.ktor.http.HttpHeaders +import io.ktor.http.HttpStatusCode +import io.ktor.http.contentType import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.readUTF8Line import kotlinx.coroutines.CancellationException @@ -31,9 +37,22 @@ import kotlinx.coroutines.flow.flow import kotlinx.datetime.Clock import kotlinx.serialization.encodeToString import kotlinx.serialization.json.JsonObject -import com.powersync.core.BuildKonfig.LIBRARY_NAME -import com.powersync.core.BuildKonfig.LIBRARY_VERSION -import io.ktor.http.* +import kotlin.collections.MutableSet +import kotlin.collections.buildList +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.filter +import kotlin.collections.forEach +import kotlin.collections.isNotEmpty +import kotlin.collections.joinToString +import kotlin.collections.listOf +import kotlin.collections.map +import kotlin.collections.mutableMapOf +import kotlin.collections.mutableSetOf +import kotlin.collections.set +import kotlin.collections.toList +import kotlin.collections.toMutableList +import kotlin.collections.toMutableSet internal class SyncStream( private val bucketStorage: BucketStorage, @@ -185,9 +204,7 @@ internal class SyncStream( return body.data.writeCheckpoint } - private fun powerSyncUserAgent(): String { - return "$LIBRARY_NAME/$LIBRARY_VERSION ${getOS()}" - } + private fun powerSyncUserAgent(): String = "$LIBRARY_NAME/$LIBRARY_VERSION ${getOS()}" private fun streamingSyncRequest(req: StreamingSyncRequest): Flow = flow { diff --git a/core/src/iosMain/kotlin/com/powersync/sync/SyncStream.ios.kt b/core/src/iosMain/kotlin/com/powersync/sync/SyncStream.ios.kt index d0e691ff..66b9de39 100644 --- a/core/src/iosMain/kotlin/com/powersync/sync/SyncStream.ios.kt +++ b/core/src/iosMain/kotlin/com/powersync/sync/SyncStream.ios.kt @@ -7,4 +7,4 @@ internal actual fun getOS(): String { val version = current.systemVersion return "ios $version" -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 13d19789..a20ac503 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ compose-preview = "1.7.8" androidxSqlite = "2.4.0" # plugins -android-gradle-plugin = "8.9.0" +android-gradle-plugin = "8.9.1" kmmBridge = "0.5.7" skie = "0.10.1" maven-publish = "0.27.0"