diff --git a/android/nativebrik/src/main/java/com/nativebrik/sdk/data/experiment.kt b/android/nativebrik/src/main/java/com/nativebrik/sdk/data/experiment.kt index 5c94f66..7fb07f0 100644 --- a/android/nativebrik/src/main/java/com/nativebrik/sdk/data/experiment.kt +++ b/android/nativebrik/src/main/java/com/nativebrik/sdk/data/experiment.kt @@ -18,7 +18,7 @@ internal class ExperimentRepositoryImpl(private val config: Config): ExperimentR ): Result { return withContext(Dispatchers.IO) { val url = config.endpoint.cdn + "/projects/" + config.projectId + "/experiments/id/" + id - val response: String = getRequest(url).getOrElse { + val response: String = getRequest(url, syncDateTime = true).getOrElse { return@withContext Result.failure(it) } val json = Json.decodeFromString(response) @@ -30,7 +30,7 @@ internal class ExperimentRepositoryImpl(private val config: Config): ExperimentR override suspend fun fetchTriggerExperimentConfigs(name: String): Result { return withContext(Dispatchers.IO) { val url = config.endpoint.cdn + "/projects/" + config.projectId + "/experiments/trigger/" + name - val response: String = getRequest(url).getOrElse { + val response: String = getRequest(url, syncDateTime = true).getOrElse { return@withContext Result.failure(it) } val json = Json.decodeFromString(response) diff --git a/android/nativebrik/src/main/java/com/nativebrik/sdk/data/network.kt b/android/nativebrik/src/main/java/com/nativebrik/sdk/data/network.kt index 2f4a8ed..40b0bf0 100644 --- a/android/nativebrik/src/main/java/com/nativebrik/sdk/data/network.kt +++ b/android/nativebrik/src/main/java/com/nativebrik/sdk/data/network.kt @@ -1,5 +1,6 @@ package com.nativebrik.sdk.data +import com.nativebrik.sdk.data.user.syncDateFromHttpResponse import java.io.BufferedReader import java.io.IOException import java.io.InputStreamReader @@ -9,9 +10,10 @@ import java.net.URL internal const val CONNECT_TIMEOUT = 10 * 1000 internal const val READ_TIMEOUT = 5 * 1000 -internal fun getRequest(endpoint: String): Result { +internal fun getRequest(endpoint: String, syncDateTime: Boolean = false): Result { var connection: HttpURLConnection? = null try { + val t0 = System.currentTimeMillis() val url = URL(endpoint) connection = url.openConnection() as HttpURLConnection connection.connectTimeout = CONNECT_TIMEOUT @@ -23,6 +25,10 @@ internal fun getRequest(endpoint: String): Result { connection.connect() val responseCode = connection.responseCode + if (syncDateTime) { + syncDateFromHttpResponse(t0, connection) + } + if (responseCode == HttpURLConnection.HTTP_OK) { val sb = StringBuilder() var line: String? diff --git a/android/nativebrik/src/main/java/com/nativebrik/sdk/data/user/user.kt b/android/nativebrik/src/main/java/com/nativebrik/sdk/data/user/user.kt index a3801bb..f3c271e 100644 --- a/android/nativebrik/src/main/java/com/nativebrik/sdk/data/user/user.kt +++ b/android/nativebrik/src/main/java/com/nativebrik/sdk/data/user/user.kt @@ -5,10 +5,15 @@ import android.content.SharedPreferences import android.os.Build import com.nativebrik.sdk.VERSION import com.nativebrik.sdk.schema.BuiltinUserProperty +import java.net.HttpURLConnection +import java.text.SimpleDateFormat +import java.time.Instant +import java.time.ZoneId import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit import java.util.Locale +import java.util.TimeZone import java.util.UUID import kotlin.random.Random @@ -22,8 +27,32 @@ internal fun getNativebrikUserSharedPreferences(context: Context): SharedPrefere internal const val USER_SEED_MAX = 100000000 internal const val USER_SEED_KEY = "NATIVEBRIK_USER_SEED" +internal var DATETIME_OFFSET: Long = 0 internal fun getCurrentDate(): ZonedDateTime { - return ZonedDateTime.now() + val currentMillis = ZonedDateTime.now().toInstant().toEpochMilli() + return ZonedDateTime.ofInstant( + Instant.ofEpochMilli(currentMillis + DATETIME_OFFSET), + ZoneId.systemDefault() + ) +} + +internal fun syncDateFromHttpResponse(t0: Long, connection: HttpURLConnection) { + val t1 = System.currentTimeMillis() + + val serverDateStr = connection.headerFields["Date"]?.firstOrNull() ?: return + + val serverTime = try { + val formatter = SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) + formatter.timeZone = TimeZone.getTimeZone("GMT") + formatter.parse(serverDateStr)?.time ?: return + } catch (e: Exception) { + return + } + + val networkDelay = (t1 - t0) / 2 + val estimatedServerTime = serverTime + networkDelay + + DATETIME_OFFSET = estimatedServerTime - t1 } internal fun getToday(): ZonedDateTime {