From 4dc65bf09a46d53867cb3c22c47611b3e2301ad1 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 25 Sep 2021 19:28:49 +0600 Subject: [PATCH] delay in doWhile and flows with doWhile instead their own logic --- CHANGELOG.md | 3 + .../kotlin/dev/inmo/krontab/Executes.kt | 59 +++++++++++++++++-- .../dev/inmo/krontab/utils/SchedulerFlow.kt | 46 +++++++++------ 3 files changed, 87 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 925afe3..4ff747d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 0.6.5 +* Flows now use `doWhile` functions +* `doWhile` now use additional delay (for 1 ms) for cases when `block` executing too fast + ## 0.6.4 * Versions diff --git a/src/commonMain/kotlin/dev/inmo/krontab/Executes.kt b/src/commonMain/kotlin/dev/inmo/krontab/Executes.kt index f3077a9..e15eebf 100644 --- a/src/commonMain/kotlin/dev/inmo/krontab/Executes.kt +++ b/src/commonMain/kotlin/dev/inmo/krontab/Executes.kt @@ -1,8 +1,23 @@ package dev.inmo.krontab import com.soywiz.klock.DateTime +import com.soywiz.klock.DateTimeTz import kotlinx.coroutines.delay +/** + * Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation. + * + * WARNING!!! If you want to launch it in parallel, you must do this explicitly. + * + * WARNING!!! In case if [KronScheduler.next] of [this] instance will return null, [block] will be called immediately + */ +suspend inline fun KronSchedulerTz.doOnce(noinline block: suspend () -> T): T { + nextTimeZoned() ?.let { + delay((it - DateTimeTz.nowLocal()).millisecondsLong) + } + return block() +} + /** * Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation. * @@ -24,13 +39,31 @@ suspend inline fun KronScheduler.doOnce(noinline block: suspend () -> T): T suspend inline fun doOnce( scheduleConfig: String, noinline block: suspend () -> T -) = buildSchedule(scheduleConfig).doOnce(block) +) = with(buildSchedule(scheduleConfig)) { + when (this) { + is KronSchedulerTz -> doOnce(block) + else -> doOnce(block) + } +} /** * Will execute [block] while it will return true as a result of its calculation */ suspend inline fun KronScheduler.doWhile(noinline block: suspend () -> Boolean) { - do { val doNext = doOnce(block) } while (doNext) + do { + delay(1L) + val doNext = doOnce(block) + } while (doNext) +} + +/** + * Will execute [block] while it will return true as a result of its calculation + */ +suspend inline fun KronSchedulerTz.doWhile(noinline block: suspend () -> Boolean) { + do { + delay(1L) + val doNext = doOnce(block) + } while (doNext) } /** @@ -41,7 +74,12 @@ suspend inline fun KronScheduler.doWhile(noinline block: suspend () -> Boolean) suspend inline fun doWhile( scheduleConfig: String, noinline block: suspend () -> Boolean -) = buildSchedule(scheduleConfig).doWhile(block) +) = with(buildSchedule(scheduleConfig)) { + when (this) { + is KronSchedulerTz -> doWhile(block) + else -> doWhile(block) + } +} /** * Will execute [block] without any checking of result @@ -50,6 +88,14 @@ suspend inline fun KronScheduler.doInfinity(noinline block: suspend () -> Unit) block() true } + +/** + * Will execute [block] without any checking of result + */ +suspend inline fun KronSchedulerTz.doInfinity(noinline block: suspend () -> Unit) = doWhile { + block() + true +} /** * Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block] * @@ -58,4 +104,9 @@ suspend inline fun KronScheduler.doInfinity(noinline block: suspend () -> Unit) suspend inline fun doInfinity( scheduleConfig: String, noinline block: suspend () -> Unit -) = buildSchedule(scheduleConfig).doInfinity(block) +) = with(buildSchedule(scheduleConfig)) { + when (this) { + is KronSchedulerTz -> doInfinity(block) + else -> doInfinity(block) + } +} diff --git a/src/commonMain/kotlin/dev/inmo/krontab/utils/SchedulerFlow.kt b/src/commonMain/kotlin/dev/inmo/krontab/utils/SchedulerFlow.kt index 1382d86..b54e308 100644 --- a/src/commonMain/kotlin/dev/inmo/krontab/utils/SchedulerFlow.kt +++ b/src/commonMain/kotlin/dev/inmo/krontab/utils/SchedulerFlow.kt @@ -2,8 +2,7 @@ package dev.inmo.krontab.utils import com.soywiz.klock.DateTime import com.soywiz.klock.DateTimeTz -import dev.inmo.krontab.KronScheduler -import dev.inmo.krontab.next +import dev.inmo.krontab.* import kotlinx.coroutines.* import kotlinx.coroutines.flow.* @@ -12,30 +11,43 @@ import kotlinx.coroutines.flow.* * time zones * * @see channelFlow + * @see KronSchedulerTz.doWhile */ @FlowPreview -fun KronScheduler.asTzFlow(): Flow = channelFlow { - var previousTime = DateTime.nowLocal() - while (isActive) { - val now = DateTime.nowLocal() - val nextTime = next(now) ?: break - if (previousTime == nextTime) { - delay(1L) // skip 1ms - continue - } else { - previousTime = nextTime - } - val sleepDelay = (nextTime - DateTime.now().local).millisecondsLong - delay(sleepDelay) - send(nextTime) +fun KronSchedulerTz.asTzFlow(): Flow = channelFlow { + doWhile { + send(DateTime.nowLocal()) + isActive } } /** * This method is a map for [asTzFlow] and will works the same but return flow with [DateTime]s + * + * @see channelFlow + * @see KronScheduler.doWhile */ @FlowPreview -fun KronScheduler.asFlow(): Flow = asTzFlow().map { it.local } +fun KronScheduler.asFlow(): Flow = channelFlow { + doWhile { + send(DateTime.now()) + isActive + } +} + +/** + * This [Flow] will trigger emitting each near time which will be returned from [this] [KronScheduler] with attention to + * time zones + * + * @see channelFlow + * @see KronScheduler.asFlow + * @see KronSchedulerTz.asTzFlow + */ +@FlowPreview +fun KronScheduler.asTzFlow(): Flow = when (this) { + is KronSchedulerTz -> asTzFlow() + else -> asFlow().map { it.local } +} @Deprecated( "It is not recommended to use this class in future. This functionality will be removed soon",