Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial API #6

Merged
merged 3 commits into from
Aug 3, 2023
Merged
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
6 changes: 6 additions & 0 deletions .idea/artifacts/library_js.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
network-time
=

A Kotlin multiplatform implementation of an SNTP client.
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
buildscript {
repositories {
gradlePluginPortal()
google()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0")
classpath("com.android.tools.build:gradle:8.0.2")
}
}

Expand Down
39 changes: 39 additions & 0 deletions library/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
kotlin("multiplatform")
id("com.android.library")
}

group = "com.tidal.network-time"
Expand All @@ -8,4 +9,42 @@ kotlin {
targetHierarchy.default()

jvm()
androidTarget()
ios()
linuxX64()
macosX64()
macosArm64()
iosSimulatorArm64()
iosX64()
linuxArm64()
watchosSimulatorArm64()
watchosX64()
watchosArm32()
watchosArm64()
tvosSimulatorArm64()
tvosX64()
tvosArm64()
iosArm64()
androidNativeArm32()
androidNativeArm64()
androidNativeX86()
androidNativeX64()
mingwX64()
watchosDeviceArm64()

sourceSets {
val commonMain by getting {
dependencies {
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}
}
}
}

android {
compileSdk = 34
defaultConfig {
minSdk = 1
}
namespace = group.toString()
}
41 changes: 41 additions & 0 deletions library/src/commonMain/kotlin/com/tidal/networktime/NTPServer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.tidal.networktime

import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

sealed interface NTPServer {
val hostName: String
val responseTimeout: Duration
val dnsResolutionStrategy: DNSResolutionStrategy

sealed interface Unicast : NTPServer {
class Sequential(
override val hostName: String,
override val responseTimeout: Duration = 5.seconds,
override val dnsResolutionStrategy: DNSResolutionStrategy = DNSResolutionStrategy.ALL,
val outgoingRequestGap: Duration = OUTGOING_REQUEST_GAP_DEFAULT_SECONDS.seconds,
) : Unicast

class Concurrent(
override val hostName: String,
override val responseTimeout: Duration = 5.seconds,
override val dnsResolutionStrategy: DNSResolutionStrategy = DNSResolutionStrategy.ALL,
) : Unicast

companion object {
private const val OUTGOING_REQUEST_GAP_DEFAULT_SECONDS = 2
}
}

class Anycast(
override val hostName: String,
override val responseTimeout: Duration = 68.seconds,
override val dnsResolutionStrategy: DNSResolutionStrategy = DNSResolutionStrategy.ALL,
) : NTPServer

enum class DNSResolutionStrategy {
IP_V4,
IP_V6,
ALL,
}
}
54 changes: 54 additions & 0 deletions library/src/commonMain/kotlin/com/tidal/networktime/SNTPClient.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.tidal.networktime

import kotlinx.coroutines.CoroutineScope
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

/**
* Construct a new SNTP client that can be requested to periodically interact with the provided
* [ntpServers] to obtain information about their provided time.
*
* @param ntpServers Representation of supported NTP sources.
* @param coroutineScope The scope where synchronization will run on.
* @param ntpVersion The version number to write in packets.
* @param portSelectionStrategy The strategy for selecting a port to operate on.
* @param minimumSynchronizationInterval The minimum amount of time between performing time queries
* on all unicast sources. The actual value used may be larger than this on occasion based on
* changes to the difference between the time provided by [ntpServers] and [referenceClock] (if it
* ever changes), but will never be lower than this value.
* @param referenceClock A clock used to calculate timing differences with the information obtained
* from [ntpServers]. This clock will never be modified directly.
*/
class SNTPClient(
vararg val ntpServers: NTPServer,
val coroutineScope: CoroutineScope,
val ntpVersion: NTPVersion = NTPVersion.FOUR,
val portSelectionStrategy: PortSelectionStrategy = PortSelectionStrategy.RFC9109,
val minimumSynchronizationInterval: Duration = 64.seconds,
val referenceClock: () -> Long,
) {

val time: Long?
get() = TODO("Getting the time")

fun startSynchronization(): Unit = TODO("Start or return")

fun stopSynchronization(): Unit = TODO("Stop or return")

enum class NTPVersion(val descriptor: Short) {
ZERO(0),
ONE(1),
TWO(2),
THREE(3),
FOUR(4),
}

sealed class PortSelectionStrategy(val pinnedPortNumber: Int?) {
data object RFC5905 : PortSelectionStrategy(123)

/**
* Make a new selection of a random available port every time a socket is opened.
*/
data object RFC9109 : PortSelectionStrategy(null)
}
}