Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Kotlin Multiplatform library for network time synchronization. It extends the [`
- Android
- iOS
- Desktop JVM (MacOS, Linux, Windows)
- Web
## Usage
### `kotlin.time` Extension
The library [extends the main `Clock` interface](https://github.com/softartdev/Kronos-Multiplatform/blob/main/kronos/src/commonMain/kotlin/com/softartdev/kronos/ClockExt.kt) from the standard library. You can use the [`Clock.Network`](https://github.com/softartdev/Kronos-Multiplatform/blob/main/kronos/src/commonMain/kotlin/com/softartdev/kronos/NetworkClock.kt) class to retrieve the current network time, similar to using the built-in [`Clock.System`](https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/time/Clock.kt#L60) instance.
Expand Down
3 changes: 3 additions & 0 deletions kronos/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ version = libs.versions.kronos.get()
kotlin {
jvmToolchain(libs.versions.jdk.get().toInt())
jvm()
wasmJs()
androidTarget {
publishLibraryVariants("release", "debug")
}
Expand Down Expand Up @@ -53,6 +54,8 @@ kotlin {
implementation(libs.androidx.test)
}
}
val wasmJsMain by getting
val wasmJsTest by getting
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
Expand Down
13 changes: 13 additions & 0 deletions kronos/src/wasmJsMain/kotlin/com/softartdev/kronos/Network.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@file:OptIn(ExperimentalTime::class)

package com.softartdev.kronos

import kotlin.time.Clock
import kotlin.time.ExperimentalTime

actual val Clock.Companion.Network: NetworkClock
get() = WasmNetworkClock

fun NetworkClock.sync() = WasmNetworkClock.sync()
fun NetworkClock.blockingSync(): Boolean = WasmNetworkClock.blockingSync()
suspend fun NetworkClock.awaitSync(): Boolean = WasmNetworkClock.awaitSync()
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.softartdev.kronos

import kotlinx.browser.window
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.await
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlin.time.Clock

/**
* Fetches network time using the public WorldTime API and stores the offset
* from the local system clock. The [sync] functions update the offset
* asynchronously or in a blocking fashion. After synchronization the clock
* provides network based timestamps via [getCurrentNtpTimeMs].
*/
object WasmNetworkClock : NetworkClock {

private var offsetMs: Long? = null

fun sync() {
GlobalScope.launch { awaitSync() }
}

fun blockingSync(): Boolean = runBlocking { awaitSync() }

suspend fun awaitSync(): Boolean = try {
val response = window.fetch("https://worldtimeapi.org/api/ip").await()
val json = response.json().await() as dynamic
val dateStr = json.datetime as String
val networkTimeMs = js("Date.parse(dateStr)").unsafeCast<Double>().toLong()
val systemTimeMs = js("Date.now()").unsafeCast<Double>().toLong()
offsetMs = networkTimeMs - systemTimeMs
true
} catch (t: Throwable) {
console.error("Failed to sync time", t)
false
}

override fun getCurrentNtpTimeMs(): Long? {
val offset = offsetMs ?: return null
val systemTimeMs = js("Date.now()").unsafeCast<Double>().toLong()
return systemTimeMs + offset
}
}
3 changes: 3 additions & 0 deletions sampleApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ kotlin {
jvmToolchain(libs.versions.jdk.get().toInt())
jvm("desktop")
androidTarget()
wasmJs()
iosX64()
iosArm64()
iosSimulatorArm64()
Expand Down Expand Up @@ -62,6 +63,8 @@ kotlin {
implementation(compose.preview)
}
}
val wasmJsMain by getting
val wasmJsTest by getting
val iosX64Main by getting
val iosArm64Main by getting
val iosSimulatorArm64Main by getting
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@file:OptIn(ExperimentalTime::class)

package com.softartdev.kronos.sample

import kotlinx.browser.window
import kotlin.time.Clock
import kotlin.time.ExperimentalTime

internal actual fun openUrl(url: String?) {
url ?: return
window.open(url, "_blank")
}

internal actual fun clickSync() = Clock.Network.sync()

internal actual fun clickBlockingSync() {
Clock.Network.blockingSync()
}

internal actual suspend fun clickAwaitSync() {
Clock.Network.awaitSync()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.softartdev.kronos.sample

class WasmJsPlatform : Platform {
override val name: String = "Web"
}

actual fun getPlatform(): Platform = WasmJsPlatform()
Loading