mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 11:18:24 +00:00
refactor(quartz): add TimeUtils.nowMillis, drop raw System calls in pagers
The relay-paging trackers measured elapsed wall-clock with System.currentTimeMillis() directly. Introduce a multiplatform millisecond clock (currentTimeMillis expect/actual across jvm/android/ios/macos/linux, mirroring the existing currentTimeSeconds) exposed as TimeUtils.nowMillis(), and route PerRelayLoadTracker + WindowLoadTracker through it. TimeUtils.now() is seconds, so it can't be used for the ms-scale silence / idle / linger timers — nowMillis() is the correct primitive. No behavior change (same underlying clock on JVM/Android). Note: the two trackers stay in jvmAndroid for now — @Synchronized has no commonMain equivalent. ConcurrentHashMap is kept deliberately: LargeCache is a sorted ConcurrentSkipListMap (Comparable, compareTo-identity keys) and the pager keys (ConvoKey not Comparable; ChatroomKey.compareTo is hashCode-based) don't satisfy that, so ConcurrentHashMap is the correct structure here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cd6537bfd5
commit
910037ad8e
@@ -23,3 +23,5 @@ package com.vitorpamplona.quartz.utils
|
||||
actual fun platform() = "Android"
|
||||
|
||||
actual fun currentTimeSeconds() = System.currentTimeMillis() / 1000
|
||||
|
||||
actual fun currentTimeMillis() = System.currentTimeMillis()
|
||||
|
||||
@@ -23,3 +23,5 @@ package com.vitorpamplona.quartz.utils
|
||||
expect fun platform(): String
|
||||
|
||||
expect fun currentTimeSeconds(): Long
|
||||
|
||||
expect fun currentTimeMillis(): Long
|
||||
|
||||
@@ -36,6 +36,8 @@ object TimeUtils {
|
||||
|
||||
fun now() = currentTimeSeconds()
|
||||
|
||||
fun nowMillis() = currentTimeMillis()
|
||||
|
||||
fun tenSecondsFromNow() = now() + TEN_SECONDS
|
||||
|
||||
fun tenSecondsAgo() = now() - TEN_SECONDS
|
||||
|
||||
@@ -31,3 +31,5 @@ actual fun currentTimeSeconds(): Long {
|
||||
// NSDate().timeIntervalSince1970 returns seconds since 1970-01-01 00:00:00 UTC
|
||||
return (NSDate().timeIntervalSince1970).toLong()
|
||||
}
|
||||
|
||||
actual fun currentTimeMillis(): Long = (NSDate().timeIntervalSince1970 * 1000).toLong()
|
||||
|
||||
+5
-4
@@ -22,6 +22,7 @@ package com.vitorpamplona.quartz.nip01Core.relay.client.paging
|
||||
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -82,14 +83,14 @@ class PerRelayLoadTracker(
|
||||
clearJob?.cancel() // a new page is starting — keep the spinner up, no flicker
|
||||
clearJob = null
|
||||
inFlight.add(relay)
|
||||
lastActivityMs = System.currentTimeMillis()
|
||||
lastActivityMs = TimeUtils.nowMillis()
|
||||
_loading.value = true
|
||||
ensureWatchdog()
|
||||
}
|
||||
|
||||
/** A sign of life from a relay (an event). Keeps the silence watchdog from firing. */
|
||||
fun onActivity() {
|
||||
lastActivityMs = System.currentTimeMillis()
|
||||
lastActivityMs = TimeUtils.nowMillis()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,7 +102,7 @@ class PerRelayLoadTracker(
|
||||
*/
|
||||
@Synchronized
|
||||
fun onSettled(relay: NormalizedRelayUrl) {
|
||||
lastActivityMs = System.currentTimeMillis()
|
||||
lastActivityMs = TimeUtils.nowMillis()
|
||||
if (inFlight.remove(relay) && inFlight.isEmpty()) scheduleClear()
|
||||
}
|
||||
|
||||
@@ -141,7 +142,7 @@ class PerRelayLoadTracker(
|
||||
delay(WATCHDOG_TICK_MS)
|
||||
val silenced =
|
||||
synchronized(this@PerRelayLoadTracker) {
|
||||
if (inFlight.isNotEmpty() && System.currentTimeMillis() - lastActivityMs > silenceMs) {
|
||||
if (inFlight.isNotEmpty() && TimeUtils.nowMillis() - lastActivityMs > silenceMs) {
|
||||
val pending = inFlight.toSet()
|
||||
inFlight.clear()
|
||||
_loading.value = false
|
||||
|
||||
+6
-5
@@ -25,6 +25,7 @@ import com.vitorpamplona.quartz.nip01Core.relay.client.reqs.SubscriptionListener
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.NormalizedRelayUrl
|
||||
import com.vitorpamplona.quartz.utils.Log
|
||||
import com.vitorpamplona.quartz.utils.TimeUtils
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
@@ -104,17 +105,17 @@ class WindowLoadTracker(
|
||||
expected = emptySet()
|
||||
heardFrom.clear()
|
||||
settled.clear()
|
||||
lastActivityMs = System.currentTimeMillis()
|
||||
lastActivityMs = TimeUtils.nowMillis()
|
||||
val wasLoading = _loading.value
|
||||
_loading.value = true
|
||||
Log.d(TAG) { "[$name] load start" + if (!wasLoading) "" else " (restart)" }
|
||||
watchdog?.cancel()
|
||||
watchdog =
|
||||
scope.launch {
|
||||
val deadline = System.currentTimeMillis() + absoluteCap.inWholeMilliseconds
|
||||
val deadline = TimeUtils.nowMillis() + absoluteCap.inWholeMilliseconds
|
||||
while (isActive) {
|
||||
delay(IDLE_CHECK_MS)
|
||||
if (!tick(gen, System.currentTimeMillis(), deadline)) break
|
||||
if (!tick(gen, TimeUtils.nowMillis(), deadline)) break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,7 +165,7 @@ class WindowLoadTracker(
|
||||
/** A non-terminal sign of life from [relay] (a stored or live event). Keeps the idle timer alive. */
|
||||
fun onRelayEvent(relay: NormalizedRelayUrl) {
|
||||
heardFrom.add(relay)
|
||||
lastActivityMs = System.currentTimeMillis()
|
||||
lastActivityMs = TimeUtils.nowMillis()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,7 +174,7 @@ class WindowLoadTracker(
|
||||
*/
|
||||
@Synchronized
|
||||
fun onRelaySettled(relay: NormalizedRelayUrl) {
|
||||
lastActivityMs = System.currentTimeMillis()
|
||||
lastActivityMs = TimeUtils.nowMillis()
|
||||
heardFrom.add(relay)
|
||||
settled.add(relay)
|
||||
if (expected.isNotEmpty() && settled.containsAll(expected)) finish("all relays")
|
||||
|
||||
@@ -23,3 +23,5 @@ package com.vitorpamplona.quartz.utils
|
||||
actual fun platform() = "JVM"
|
||||
|
||||
actual fun currentTimeSeconds() = System.currentTimeMillis() / 1000
|
||||
|
||||
actual fun currentTimeMillis() = System.currentTimeMillis()
|
||||
|
||||
@@ -38,3 +38,12 @@ actual fun currentTimeSeconds(): Long {
|
||||
return ts.tv_sec
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
actual fun currentTimeMillis(): Long {
|
||||
memScoped {
|
||||
val ts = alloc<timespec>()
|
||||
clock_gettime(CLOCK_REALTIME, ts.ptr)
|
||||
return ts.tv_sec * 1000 + ts.tv_nsec / 1_000_000
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,3 +26,5 @@ import platform.Foundation.timeIntervalSince1970
|
||||
actual fun platform() = "macOS"
|
||||
|
||||
actual fun currentTimeSeconds(): Long = (NSDate().timeIntervalSince1970).toLong()
|
||||
|
||||
actual fun currentTimeMillis(): Long = (NSDate().timeIntervalSince1970 * 1000).toLong()
|
||||
|
||||
Reference in New Issue
Block a user