mirror of
https://github.com/InsanusMokrassar/krontab.git
synced 2025-12-22 12:55:47 +00:00
Compare commits
35 Commits
0.6.5
...
9ea8194d7d
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ea8194d7d | |||
| 0c37ccc902 | |||
| 2abef58335 | |||
| 8ac6cd3e62 | |||
| 58f30aef15 | |||
| f163a64964 | |||
| 79ce455f5c | |||
| fd54b035fe | |||
| 4fab7a28ff | |||
| 28d5665a14 | |||
| f98fd5ddb7 | |||
| 981327675a | |||
| 7649d20984 | |||
| ab274636b9 | |||
| 7f2f8a4a26 | |||
| f64171c0f0 | |||
| 8382108b01 | |||
| 32499d02fb | |||
| 2b06033c75 | |||
| 84f1063e3f | |||
| 347cf64cb2 | |||
| eb73da67eb | |||
| 4aadf513aa | |||
| 8c011ea1fb | |||
| aa9c2b8ea0 | |||
| adf10301dc | |||
| 7799077e44 | |||
| 83339dc095 | |||
| 3040951f37 | |||
| 0bfe022476 | |||
| 06107f75f2 | |||
| 039fe1cb5f | |||
| ea7fab6130 | |||
| 2f3796733d | |||
| 89a6a305f8 |
6
.github/workflows/kdocs.yml
vendored
6
.github/workflows/kdocs.yml
vendored
@@ -10,10 +10,10 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 1.8
|
java-version: 11
|
||||||
- name: Fix android 31.0.0 dx
|
- name: Fix android 32.0.0 dx
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: cd /usr/local/lib/android/sdk/build-tools/31.0.0/ && mv d8 dx && cd lib && mv d8.jar dx.jar
|
run: cd /usr/local/lib/android/sdk/build-tools/32.0.0/ && cp d8 dx && cd lib && cp d8.jar dx.jar
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./gradlew dokkaHtml
|
run: ./gradlew dokkaHtml
|
||||||
- name: Publish KDocs
|
- name: Publish KDocs
|
||||||
|
|||||||
6
.github/workflows/publishing_packages.yml
vendored
6
.github/workflows/publishing_packages.yml
vendored
@@ -7,10 +7,10 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v1
|
||||||
with:
|
with:
|
||||||
java-version: 1.8
|
java-version: 11
|
||||||
- name: Fix android 31.0.0 dx
|
- name: Fix android 32.0.0 dx
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: cd /usr/local/lib/android/sdk/build-tools/31.0.0/ && mv d8 dx && cd lib && mv d8.jar dx.jar
|
run: cd /usr/local/lib/android/sdk/build-tools/32.0.0/ && cp d8 dx && cd lib && cp d8.jar dx.jar
|
||||||
- name: Update version
|
- name: Update version
|
||||||
run: |
|
run: |
|
||||||
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
|
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
|
||||||
|
|||||||
38
CHANGELOG.md
38
CHANGELOG.md
@@ -1,5 +1,43 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.7.3
|
||||||
|
|
||||||
|
* Versions
|
||||||
|
* `Kotlin`: `1.6.21`
|
||||||
|
* Several bug fixes ([#27](https://github.com/InsanusMokrassar/krontab/issues/27), [#34](https://github.com/InsanusMokrassar/krontab/issues/34))
|
||||||
|
* New factories for `KronScheduler` and `KronSchedulerTz` (fix of [#35](https://github.com/InsanusMokrassar/krontab/issues/35))
|
||||||
|
* Fill extensions for flow with time zones (fix of [#33](https://github.com/InsanusMokrassar/krontab/issues/33))
|
||||||
|
|
||||||
|
## 0.7.2
|
||||||
|
|
||||||
|
* Versions
|
||||||
|
* `Coroutines`: `1.6.1`
|
||||||
|
* `Klock`: `2.7.0`
|
||||||
|
* Deprecate `do*Local` due to their redundancy (use `do*` instead)
|
||||||
|
* Add support of milliseconds as optional parameter after month (fix of [#31](https://github.com/InsanusMokrassar/krontab/issues/31))
|
||||||
|
* Add support of filters for `Flow`s with `DateTime` (fix of [#30](https://github.com/InsanusMokrassar/krontab/issues/30))
|
||||||
|
|
||||||
|
## 0.7.1
|
||||||
|
|
||||||
|
* Versions
|
||||||
|
* `Klock`: `2.5.2`
|
||||||
|
|
||||||
|
## 0.7.0
|
||||||
|
|
||||||
|
**ALL DEPRECATIONS HAVE BEEN REMOVED**
|
||||||
|
|
||||||
|
* Versions
|
||||||
|
* `Kotlin`: `1.6.10`
|
||||||
|
* `Klock`: `2.4.10`
|
||||||
|
* `Coroutines`: `1.6.0`
|
||||||
|
* `Androidx Work`: `2.7.1`
|
||||||
|
|
||||||
|
## 0.6.6
|
||||||
|
|
||||||
|
* Versions
|
||||||
|
* `Klock`: `2.4.8`
|
||||||
|
* `Androidx Work`: `2.7.0`
|
||||||
|
|
||||||
## 0.6.5
|
## 0.6.5
|
||||||
|
|
||||||
* Flows now use `doWhile` functions
|
* Flows now use `doWhile` functions
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ buildscript {
|
|||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
|
classpath "com.github.breadmoirai:github-release:$github_release_plugin_version"
|
||||||
classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:$dexcount_version"
|
classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:$dexcount_version"
|
||||||
classpath 'com.android.tools.build:gradle:4.2.2'
|
classpath 'com.android.tools.build:gradle:7.0.4'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,6 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
languageVersion = JavaLanguageVersion.of(8)
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,30 +8,30 @@ android.useAndroidX=true
|
|||||||
android.enableJetifier=false
|
android.enableJetifier=false
|
||||||
|
|
||||||
|
|
||||||
kotlin_version=1.5.31
|
kotlin_version=1.6.21
|
||||||
kotlin_coroutines_version=1.5.2
|
kotlin_coroutines_version=1.6.1
|
||||||
|
|
||||||
dokka_version=1.5.30
|
dokka_version=1.6.21
|
||||||
|
|
||||||
klockVersion=2.4.2
|
klockVersion=2.7.0
|
||||||
|
|
||||||
## Github reease
|
## Github reease
|
||||||
|
|
||||||
github_release_plugin_version=2.2.12
|
github_release_plugin_version=2.3.7
|
||||||
|
|
||||||
## Android
|
## Android
|
||||||
|
|
||||||
android_minSdkVersion=19
|
android_minSdkVersion=19
|
||||||
android_compileSdkVersion=31
|
android_compileSdkVersion=32
|
||||||
android_buildToolsVersion=31.0.0
|
android_buildToolsVersion=32.0.0
|
||||||
dexcount_version=3.0.0
|
dexcount_version=3.0.1
|
||||||
junit_version=4.12
|
junit_version=4.12
|
||||||
test_ext_junit_version=1.1.2
|
test_ext_junit_version=1.1.2
|
||||||
espresso_core=3.3.0
|
espresso_core=3.3.0
|
||||||
|
|
||||||
androidx_work_version=2.6.0
|
androidx_work_version=2.7.1
|
||||||
|
|
||||||
## Common
|
## Common
|
||||||
|
|
||||||
version=0.6.5
|
version=0.7.3
|
||||||
android_code_version=9
|
android_code_version=14
|
||||||
|
|||||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||||
|
|||||||
1998
kotlin-js-store/yarn.lock
Normal file
1998
kotlin-js-store/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ import kotlinx.coroutines.delay
|
|||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import kotlin.coroutines.coroutineContext
|
import kotlin.coroutines.coroutineContext
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation.
|
* Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation.
|
||||||
*
|
*
|
||||||
@@ -13,13 +14,23 @@ import kotlin.coroutines.coroutineContext
|
|||||||
*
|
*
|
||||||
* WARNING!!! In case if [KronScheduler.next] of [this] instance will return null, [block] will be called immediately
|
* WARNING!!! In case if [KronScheduler.next] of [this] instance will return null, [block] will be called immediately
|
||||||
*/
|
*/
|
||||||
suspend inline fun <T> KronScheduler.doOnceLocal(noinline block: suspend (DateTime) -> T): T {
|
suspend inline fun <T> KronScheduler.doOnce(noinline block: suspend (DateTime) -> T): T {
|
||||||
val time = nextOrNow().also {
|
val time = nextOrNow().also {
|
||||||
delay((it - DateTime.now()).millisecondsLong)
|
delay((it - DateTime.now()).millisecondsLong)
|
||||||
}
|
}
|
||||||
return block(time)
|
return block(time)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
@Deprecated("Replaceable", ReplaceWith("doOnce", "dev.inmo.krontab.doOnce"))
|
||||||
|
suspend inline fun <T> KronScheduler.doOnceLocal(noinline block: suspend (DateTime) -> T): T = doOnce(block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation.
|
* Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation.
|
||||||
*
|
*
|
||||||
@@ -37,25 +48,16 @@ suspend inline fun <T> KronScheduler.doOnceTz(noinline block: suspend (DateTimeT
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation.
|
* Will [buildSchedule] using [scheduleConfig] and call [doOnce] on it
|
||||||
*
|
|
||||||
* 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 <T> KronScheduler.doOnce(noinline block: suspend () -> T): T = doOnceLocal { _ -> block() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doOnceLocal] on it
|
|
||||||
* @see buildSchedule
|
* @see buildSchedule
|
||||||
*/
|
*/
|
||||||
suspend inline fun <T> doOnce(
|
suspend inline fun <T> doOnce(
|
||||||
scheduleConfig: String,
|
scheduleConfig: String,
|
||||||
noinline block: suspend (DateTime) -> T
|
noinline block: suspend (DateTime) -> T
|
||||||
) = buildSchedule(scheduleConfig).doOnceLocal(block)
|
) = buildSchedule(scheduleConfig).doOnce(block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doOnceLocal] on it
|
* Will [buildSchedule] using [scheduleConfig] and call [doOnce] on it
|
||||||
* @see buildSchedule
|
* @see buildSchedule
|
||||||
*/
|
*/
|
||||||
suspend inline fun <T> doOnceTz(
|
suspend inline fun <T> doOnceTz(
|
||||||
@@ -63,24 +65,20 @@ suspend inline fun <T> doOnceTz(
|
|||||||
noinline block: suspend (DateTimeTz) -> T
|
noinline block: suspend (DateTimeTz) -> T
|
||||||
) = buildSchedule(scheduleConfig).doOnceTz(block)
|
) = buildSchedule(scheduleConfig).doOnceTz(block)
|
||||||
|
|
||||||
/**
|
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doOnceLocal] on it
|
|
||||||
* @see buildSchedule
|
|
||||||
*/
|
|
||||||
suspend inline fun <T> doOnce(
|
|
||||||
scheduleConfig: String,
|
|
||||||
noinline block: suspend () -> T
|
|
||||||
) = doOnce(scheduleConfig) { _ -> block() }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will execute [block] while it will return true as a result of its calculation
|
* Will execute [block] while it will return true as a result of its calculation
|
||||||
*/
|
*/
|
||||||
suspend inline fun KronScheduler.doWhileLocal(noinline block: suspend (DateTime) -> Boolean) {
|
suspend inline fun KronScheduler.doWhile(noinline block: suspend (DateTime) -> Boolean) {
|
||||||
do {
|
do {
|
||||||
delay(1L)
|
delay(1L)
|
||||||
} while (doOnceLocal(block))
|
} while (doOnce(block))
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Will execute [block] while it will return true as a result of its calculation
|
||||||
|
*/
|
||||||
|
@Deprecated("Replaceable", ReplaceWith("doWhile", "dev.inmo.krontab.doWhile"))
|
||||||
|
suspend inline fun KronScheduler.doWhileLocal(noinline block: suspend (DateTime) -> Boolean) = doWhile(block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will execute [block] while it will return true as a result of its calculation
|
* Will execute [block] while it will return true as a result of its calculation
|
||||||
@@ -92,19 +90,25 @@ suspend inline fun KronScheduler.doWhileTz(noinline block: suspend (DateTimeTz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will execute [block] while it will return true as a result of its calculation
|
* Will [buildSchedule] using [scheduleConfig] and call [doWhile] with [block]
|
||||||
|
*
|
||||||
|
* @see buildSchedule
|
||||||
*/
|
*/
|
||||||
suspend inline fun KronScheduler.doWhile(noinline block: suspend () -> Boolean) = doWhileLocal { block() }
|
suspend inline fun doWhile(
|
||||||
|
scheduleConfig: String,
|
||||||
|
noinline block: suspend (DateTime) -> Boolean
|
||||||
|
) = buildSchedule(scheduleConfig).doWhile(block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doWhile] with [block]
|
* Will [buildSchedule] using [scheduleConfig] and call [doWhile] with [block]
|
||||||
*
|
*
|
||||||
* @see buildSchedule
|
* @see buildSchedule
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("Replaceable", ReplaceWith("doWhile", "dev.inmo.krontab.doWhile"))
|
||||||
suspend inline fun doWhileLocal(
|
suspend inline fun doWhileLocal(
|
||||||
scheduleConfig: String,
|
scheduleConfig: String,
|
||||||
noinline block: suspend (DateTime) -> Boolean
|
noinline block: suspend (DateTime) -> Boolean
|
||||||
) = buildSchedule(scheduleConfig).doWhileLocal(block)
|
) = doWhile(scheduleConfig, block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doWhile] with [block]
|
* Will [buildSchedule] using [scheduleConfig] and call [doWhile] with [block]
|
||||||
@@ -116,24 +120,19 @@ suspend inline fun doWhileTz(
|
|||||||
noinline block: suspend (DateTimeTz) -> Boolean
|
noinline block: suspend (DateTimeTz) -> Boolean
|
||||||
) = buildSchedule(scheduleConfig).doWhileTz(block)
|
) = buildSchedule(scheduleConfig).doWhileTz(block)
|
||||||
|
|
||||||
/**
|
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doWhile] with [block]
|
|
||||||
*
|
|
||||||
* @see buildSchedule
|
|
||||||
*/
|
|
||||||
suspend inline fun doWhile(
|
|
||||||
scheduleConfig: String,
|
|
||||||
noinline block: suspend () -> Boolean
|
|
||||||
) = doWhileLocal(scheduleConfig) { block() }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will execute [block] without any checking of result
|
* Will execute [block] without any checking of result
|
||||||
*/
|
*/
|
||||||
suspend inline fun KronScheduler.doInfinityLocal(noinline block: suspend (DateTime) -> Unit) = doWhileLocal {
|
suspend inline fun KronScheduler.doInfinity(noinline block: suspend (DateTime) -> Unit) = doWhile {
|
||||||
block(it)
|
block(it)
|
||||||
coroutineContext.isActive
|
coroutineContext.isActive
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Will execute [block] without any checking of result
|
||||||
|
*/
|
||||||
|
@Deprecated("Replaceable", ReplaceWith("doInfinity", "dev.inmo.krontab.doInfinity"))
|
||||||
|
suspend inline fun KronScheduler.doInfinityLocal(noinline block: suspend (DateTime) -> Unit) = doInfinity(block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will execute [block] without any checking of result
|
* Will execute [block] without any checking of result
|
||||||
@@ -144,22 +143,25 @@ suspend inline fun KronScheduler.doInfinityTz(noinline block: suspend (DateTimeT
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will execute [block] without any checking of result
|
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
|
||||||
|
*
|
||||||
|
* @see buildSchedule
|
||||||
*/
|
*/
|
||||||
suspend inline fun KronScheduler.doInfinity(noinline block: suspend () -> Unit) = doWhile {
|
suspend inline fun doInfinity(
|
||||||
block()
|
scheduleConfig: String,
|
||||||
coroutineContext.isActive
|
noinline block: suspend (DateTime) -> Unit
|
||||||
}
|
) = buildSchedule(scheduleConfig).doInfinity(block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
|
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
|
||||||
*
|
*
|
||||||
* @see buildSchedule
|
* @see buildSchedule
|
||||||
*/
|
*/
|
||||||
|
@Deprecated("Replaceable", ReplaceWith("doInfinity", "dev.inmo.krontab.doInfinity"))
|
||||||
suspend inline fun doInfinityLocal(
|
suspend inline fun doInfinityLocal(
|
||||||
scheduleConfig: String,
|
scheduleConfig: String,
|
||||||
noinline block: suspend (DateTime) -> Unit
|
noinline block: suspend (DateTime) -> Unit
|
||||||
) = buildSchedule(scheduleConfig).doInfinityLocal(block)
|
) = doInfinity(scheduleConfig, block)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
|
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
|
||||||
@@ -170,13 +172,3 @@ suspend inline fun doInfinityTz(
|
|||||||
scheduleConfig: String,
|
scheduleConfig: String,
|
||||||
noinline block: suspend (DateTimeTz) -> Unit
|
noinline block: suspend (DateTimeTz) -> Unit
|
||||||
) = buildSchedule(scheduleConfig).doInfinityTz(block)
|
) = buildSchedule(scheduleConfig).doInfinityTz(block)
|
||||||
|
|
||||||
/**
|
|
||||||
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
|
|
||||||
*
|
|
||||||
* @see buildSchedule
|
|
||||||
*/
|
|
||||||
suspend inline fun doInfinity(
|
|
||||||
scheduleConfig: String,
|
|
||||||
noinline block: suspend () -> Unit
|
|
||||||
) = buildSchedule(scheduleConfig).doInfinity(block)
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package dev.inmo.krontab
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
|
||||||
|
class LambdaKronScheduler(
|
||||||
|
private val onNext: suspend (DateTime) -> DateTime?
|
||||||
|
) : KronScheduler {
|
||||||
|
override suspend fun next(relatively: DateTime): DateTime? = onNext(relatively)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KronScheduler(
|
||||||
|
onNext: suspend (DateTime) -> DateTime?
|
||||||
|
) = LambdaKronScheduler(onNext)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package dev.inmo.krontab
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTimeTz
|
||||||
|
|
||||||
|
class LambdaKronSchedulerTz(
|
||||||
|
private val onNext: suspend (DateTimeTz) -> DateTimeTz?
|
||||||
|
) : KronSchedulerTz {
|
||||||
|
override suspend fun next(relatively: DateTimeTz): DateTimeTz? = onNext(relatively)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KronSchedulerTz(
|
||||||
|
onNext: suspend (DateTimeTz) -> DateTimeTz?
|
||||||
|
) = LambdaKronSchedulerTz(onNext)
|
||||||
@@ -16,6 +16,13 @@ val AnyTimeScheduler: KronScheduler by lazy {
|
|||||||
CronDateTimeScheduler(anyCronDateTime)
|
CronDateTimeScheduler(anyCronDateTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now] + one millisecond
|
||||||
|
*/
|
||||||
|
val EveryMillisecondScheduler: KronScheduler by lazy {
|
||||||
|
buildSchedule { milliseconds { 0 every 1 } }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now] + one second
|
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now] + one second
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,14 +14,15 @@ typealias KrontabTemplate = String
|
|||||||
/**
|
/**
|
||||||
* Parse [incoming] string and adapt according to next format: "* * * * *" where order of things:
|
* Parse [incoming] string and adapt according to next format: "* * * * *" where order of things:
|
||||||
*
|
*
|
||||||
* * seconds
|
* * **seconds**
|
||||||
* * minutes
|
* * **minutes**
|
||||||
* * hours
|
* * **hours**
|
||||||
* * dayOfMonth
|
* * **dayOfMonth**
|
||||||
* * month
|
* * **month**
|
||||||
* * (optional) year
|
* * **year** (optional)
|
||||||
* * (optional) (can be placed anywhere after month) (must be marked with `o` at the end, for example: 60o == +01:00) offset
|
* * **offset** (optional) (can be placed anywhere after month) (must be marked with `o` at the end, for example: 60o == +01:00)
|
||||||
* * (optional) (can be placed anywhere after month) dayOfWeek
|
* * **dayOfWeek** (optional) (can be placed anywhere after month)
|
||||||
|
* * **milliseconds** (optional) (can be placed anywhere after month) (must be marked with `ms` at the end, for example: 500ms; 100-200ms)
|
||||||
*
|
*
|
||||||
* And each one (except of offsets) have next format:
|
* And each one (except of offsets) have next format:
|
||||||
*
|
*
|
||||||
@@ -48,18 +49,21 @@ typealias KrontabTemplate = String
|
|||||||
* * Months ranges can be found in [monthRange]
|
* * Months ranges can be found in [monthRange]
|
||||||
* * Years ranges can be found in [yearRange] (in fact - any [Int])
|
* * Years ranges can be found in [yearRange] (in fact - any [Int])
|
||||||
* * WeekDay (timezone) ranges can be found in [dayOfWeekRange]
|
* * WeekDay (timezone) ranges can be found in [dayOfWeekRange]
|
||||||
|
* * Milliseconds ranges can be found in [millisecondsRange]
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
*
|
*
|
||||||
* * "0/5 * * * *" for every five seconds triggering
|
* * "0/5 * * * *" for every five seconds triggering
|
||||||
* * "0/5,L * * * *" for every five seconds triggering and on 59 second
|
* * "0/5,L * * * *" for every five seconds triggering and on 59 second
|
||||||
* * "0/15 30 * * *" for every 15th seconds in a half of each hour
|
* * "0/15 30 * * *" for every 15th seconds in a half of each hour
|
||||||
* * "1 2 3 F,4,L 5" for triggering in near first second of second minute of third hour of fourth day of may
|
* * "0/15 30 * * * 500ms" for every 15th seconds in a half of each hour when milliseconds equal to 500
|
||||||
* * "1 2 3 F,4,L 5 60o" for triggering in near first second of second minute of third hour of fourth day of may with timezone UTC+01:00
|
* * "1 2 3 F,4,L 5" for triggering in near first second of second minute of third hour of first, fifth and last days of may
|
||||||
* * "1 2 3 F,4,L 5 60o 0-2w" for triggering in near first second of second minute of third hour of fourth day of may in case if it will be in Sunday-Tuesday week days with timezone UTC+01:00
|
* * "1 2 3 F,4,L 5 60o" for triggering in near first second of second minute of third hour of first, fifth and last days of may with timezone UTC+01:00
|
||||||
* * "1 2 3 F,4,L 5 2021" for triggering in near first second of second minute of third hour of fourth day of may of 2021st year
|
* * "1 2 3 F,4,L 5 60o 0-2w" for triggering in near first second of second minute of third hour of first, fifth and last days of may in case if it will be in Sunday-Tuesday week days with timezone UTC+01:00
|
||||||
* * "1 2 3 F,4,L 5 2021 60o" for triggering in near first second of second minute of third hour of fourth day of may of 2021st year with timezone UTC+01:00
|
* * "1 2 3 F,4,L 5 2021" for triggering in near first second of second minute of third hour of first, fifth and last days of may of 2021st year
|
||||||
* * "1 2 3 F,4,L 5 2021 60o 0-2w" for triggering in near first second of second minute of third hour of fourth day of may of 2021st year if it will be in Sunday-Tuesday week days with timezone UTC+01:00
|
* * "1 2 3 F,4,L 5 2021 60o" for triggering in near first second of second minute of third hour of first, fifth and last days of may of 2021st year with timezone UTC+01:00
|
||||||
|
* * "1 2 3 F,4,L 5 2021 60o 0-2w" for triggering in near first second of second minute of third hour of first, fifth and last days of may of 2021st year if it will be in Sunday-Tuesday week days with timezone UTC+01:00
|
||||||
|
* * "1 2 3 F,4,L 5 2021 60o 0-2w 500ms" for triggering in near first second of second minute of third hour of first, fifth and last days of may of 2021st year if it will be in Sunday-Tuesday week days with timezone UTC+01:00 when milliseconds will be equal to 500
|
||||||
*
|
*
|
||||||
* @return In case when offset parameter is absent in [incoming] will be used [createSimpleScheduler] method and
|
* @return In case when offset parameter is absent in [incoming] will be used [createSimpleScheduler] method and
|
||||||
* returned [CronDateTimeScheduler]. In case when offset parameter there is in [incoming] [KrontabTemplate] will be used
|
* returned [CronDateTimeScheduler]. In case when offset parameter there is in [incoming] [KrontabTemplate] will be used
|
||||||
@@ -73,18 +77,22 @@ fun createSimpleScheduler(
|
|||||||
var offsetParsed: Int? = null
|
var offsetParsed: Int? = null
|
||||||
var dayOfWeekParsed: Array<Byte>? = null
|
var dayOfWeekParsed: Array<Byte>? = null
|
||||||
var yearParsed: Array<Int>? = null
|
var yearParsed: Array<Int>? = null
|
||||||
|
var millisecondsParsed: Array<Short>? = null
|
||||||
val (secondsSource, minutesSource, hoursSource, dayOfMonthSource, monthSource) = incoming.split(" ").also {
|
val (secondsSource, minutesSource, hoursSource, dayOfMonthSource, monthSource) = incoming.split(" ").also {
|
||||||
listOfNotNull(
|
listOfNotNull(
|
||||||
it.getOrNull(5),
|
it.getOrNull(5),
|
||||||
it.getOrNull(6),
|
it.getOrNull(6),
|
||||||
it.getOrNull(7)
|
it.getOrNull(7),
|
||||||
|
it.getOrNull(8)
|
||||||
).forEach {
|
).forEach {
|
||||||
val offsetFromString = parseOffset(it)
|
val offsetFromString = parseOffset(it)
|
||||||
val dayOfWeekFromString = parseWeekDay(it)
|
val dayOfWeekFromString = parseWeekDay(it)
|
||||||
|
val millisecondsFromString = parseMilliseconds(it)
|
||||||
offsetParsed = offsetParsed ?: offsetFromString
|
offsetParsed = offsetParsed ?: offsetFromString
|
||||||
dayOfWeekParsed = dayOfWeekParsed ?: dayOfWeekFromString
|
dayOfWeekParsed = dayOfWeekParsed ?: dayOfWeekFromString
|
||||||
|
millisecondsParsed = millisecondsParsed ?: millisecondsFromString
|
||||||
when {
|
when {
|
||||||
dayOfWeekFromString != null || offsetFromString != null -> return@forEach
|
dayOfWeekFromString != null || offsetFromString != null || millisecondsFromString != null -> return@forEach
|
||||||
yearParsed == null -> {
|
yearParsed == null -> {
|
||||||
yearParsed = parseYears(it)
|
yearParsed = parseYears(it)
|
||||||
}
|
}
|
||||||
@@ -100,10 +108,25 @@ fun createSimpleScheduler(
|
|||||||
|
|
||||||
return offsetParsed ?.let { offset ->
|
return offsetParsed ?.let { offset ->
|
||||||
createKronSchedulerWithOffset(
|
createKronSchedulerWithOffset(
|
||||||
secondsParsed, minutesParsed, hoursParsed, dayOfMonthParsed, monthParsed, yearParsed, dayOfWeekParsed, TimezoneOffset(offset.minutes)
|
secondsParsed,
|
||||||
|
minutesParsed,
|
||||||
|
hoursParsed,
|
||||||
|
dayOfMonthParsed,
|
||||||
|
monthParsed,
|
||||||
|
yearParsed,
|
||||||
|
dayOfWeekParsed,
|
||||||
|
TimezoneOffset(offset.minutes),
|
||||||
|
millisecondsParsed ?: millisecondsArrayDefault
|
||||||
)
|
)
|
||||||
} ?: createKronScheduler(
|
} ?: createKronScheduler(
|
||||||
secondsParsed, minutesParsed, hoursParsed, dayOfMonthParsed, monthParsed, yearParsed, dayOfWeekParsed
|
secondsParsed,
|
||||||
|
minutesParsed,
|
||||||
|
hoursParsed,
|
||||||
|
dayOfMonthParsed,
|
||||||
|
monthParsed,
|
||||||
|
yearParsed,
|
||||||
|
dayOfWeekParsed,
|
||||||
|
millisecondsParsed ?: millisecondsArrayDefault
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.soywiz.klock.TimezoneOffset
|
|||||||
import com.soywiz.klock.minutes
|
import com.soywiz.klock.minutes
|
||||||
import dev.inmo.krontab.KronScheduler
|
import dev.inmo.krontab.KronScheduler
|
||||||
import dev.inmo.krontab.KronSchedulerTz
|
import dev.inmo.krontab.KronSchedulerTz
|
||||||
|
import dev.inmo.krontab.internal.*
|
||||||
import dev.inmo.krontab.internal.createKronScheduler
|
import dev.inmo.krontab.internal.createKronScheduler
|
||||||
import dev.inmo.krontab.internal.createKronSchedulerWithOffset
|
import dev.inmo.krontab.internal.createKronSchedulerWithOffset
|
||||||
import dev.inmo.krontab.utils.Minutes
|
import dev.inmo.krontab.utils.Minutes
|
||||||
@@ -45,7 +46,8 @@ class SchedulerBuilder(
|
|||||||
private var month: Array<Byte>? = null,
|
private var month: Array<Byte>? = null,
|
||||||
private var year: Array<Int>? = null,
|
private var year: Array<Int>? = null,
|
||||||
private var dayOfWeek: Array<Byte>? = null,
|
private var dayOfWeek: Array<Byte>? = null,
|
||||||
private val offset: Minutes? = null
|
private val offset: Minutes? = null,
|
||||||
|
private var milliseconds: Array<Short>? = null
|
||||||
) {
|
) {
|
||||||
private fun <I, T : TimeBuilder<I>> callAndReturn(
|
private fun <I, T : TimeBuilder<I>> callAndReturn(
|
||||||
initial: Array<I>?,
|
initial: Array<I>?,
|
||||||
@@ -63,6 +65,17 @@ class SchedulerBuilder(
|
|||||||
} ?: builderValue
|
} ?: builderValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts an milliseconds block
|
||||||
|
*/
|
||||||
|
fun milliseconds(block: MillisecondsBuilder.() -> Unit) {
|
||||||
|
milliseconds = callAndReturn(
|
||||||
|
milliseconds,
|
||||||
|
MillisecondsBuilder(),
|
||||||
|
block
|
||||||
|
) ?.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts an seconds block
|
* Starts an seconds block
|
||||||
*/
|
*/
|
||||||
@@ -147,6 +160,16 @@ class SchedulerBuilder(
|
|||||||
* @see dev.inmo.krontab.internal.createKronScheduler
|
* @see dev.inmo.krontab.internal.createKronScheduler
|
||||||
*/
|
*/
|
||||||
fun build(): KronScheduler = offset ?.let {
|
fun build(): KronScheduler = offset ?.let {
|
||||||
createKronSchedulerWithOffset(seconds, minutes, hours, dayOfMonth, month, year, dayOfWeek, TimezoneOffset(it.minutes))
|
createKronSchedulerWithOffset(
|
||||||
} ?: createKronScheduler(seconds, minutes, hours, dayOfMonth, month, year, dayOfWeek)
|
seconds,
|
||||||
|
minutes,
|
||||||
|
hours,
|
||||||
|
dayOfMonth,
|
||||||
|
month,
|
||||||
|
year,
|
||||||
|
dayOfWeek,
|
||||||
|
TimezoneOffset(it.minutes),
|
||||||
|
milliseconds ?: millisecondsArrayDefault
|
||||||
|
)
|
||||||
|
} ?: createKronScheduler(seconds, minutes, hours, dayOfMonth, month, year, dayOfWeek, milliseconds ?: millisecondsArrayDefault)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ sealed class TimeBuilder<T : Number> (
|
|||||||
internal fun build() = result ?.map(converter)
|
internal fun build() = result ?.map(converter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MillisecondsBuilder : TimeBuilder<Short>(millisecondsRange, intToShortConverter)
|
||||||
class SecondsBuilder : TimeBuilder<Byte>(secondsRange, intToByteConverter)
|
class SecondsBuilder : TimeBuilder<Byte>(secondsRange, intToByteConverter)
|
||||||
class MinutesBuilder : TimeBuilder<Byte>(minutesRange, intToByteConverter)
|
class MinutesBuilder : TimeBuilder<Byte>(minutesRange, intToByteConverter)
|
||||||
class HoursBuilder : TimeBuilder<Byte>(hoursRange, intToByteConverter)
|
class HoursBuilder : TimeBuilder<Byte>(hoursRange, intToByteConverter)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import dev.inmo.krontab.KronScheduler
|
|||||||
* @param daysOfWeek 0-6
|
* @param daysOfWeek 0-6
|
||||||
* @param years any int
|
* @param years any int
|
||||||
* @param months 0-11
|
* @param months 0-11
|
||||||
* @param daysOfMonth 0-31
|
* @param daysOfMonth 0-30
|
||||||
* @param hours 0-23
|
* @param hours 0-23
|
||||||
* @param minutes 0-59
|
* @param minutes 0-59
|
||||||
* @param seconds 0-59
|
* @param seconds 0-59
|
||||||
@@ -20,7 +20,8 @@ internal data class CronDateTime(
|
|||||||
val daysOfMonth: Array<Byte>? = null,
|
val daysOfMonth: Array<Byte>? = null,
|
||||||
val hours: Array<Byte>? = null,
|
val hours: Array<Byte>? = null,
|
||||||
val minutes: Array<Byte>? = null,
|
val minutes: Array<Byte>? = null,
|
||||||
val seconds: Array<Byte>? = null
|
val seconds: Array<Byte>? = null,
|
||||||
|
val milliseconds: Array<Short>? = millisecondsArrayDefault
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
check(daysOfWeek ?.all { it in dayOfWeekRange } ?: true)
|
check(daysOfWeek ?.all { it in dayOfWeekRange } ?: true)
|
||||||
@@ -30,12 +31,13 @@ internal data class CronDateTime(
|
|||||||
check(hours?.all { it in hoursRange } ?: true)
|
check(hours?.all { it in hoursRange } ?: true)
|
||||||
check(minutes?.all { it in minutesRange } ?: true)
|
check(minutes?.all { it in minutesRange } ?: true)
|
||||||
check(seconds?.all { it in secondsRange } ?: true)
|
check(seconds?.all { it in secondsRange } ?: true)
|
||||||
|
check(milliseconds?.all { it in millisecondsRange } ?: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val calculators = listOf(
|
internal val calculators = listOf(
|
||||||
years ?.let { NearDateTimeCalculatorYears(it) },
|
years ?.let { NearDateTimeCalculatorYears(it) },
|
||||||
daysOfWeek ?.let { NearDateTimeCalculatorWeekDays(it) },
|
daysOfWeek ?.let { NearDateTimeCalculatorWeekDays(it) },
|
||||||
NearDateTimeCalculatorMillis(arrayOf(0)),
|
milliseconds ?.let { NearDateTimeCalculatorMillis(it) },
|
||||||
seconds ?.let { NearDateTimeCalculatorSeconds(it) },
|
seconds ?.let { NearDateTimeCalculatorSeconds(it) },
|
||||||
minutes ?.let { NearDateTimeCalculatorMinutes(it) },
|
minutes ?.let { NearDateTimeCalculatorMinutes(it) },
|
||||||
hours ?.let { NearDateTimeCalculatorHours(it) },
|
hours ?.let { NearDateTimeCalculatorHours(it) },
|
||||||
@@ -65,9 +67,10 @@ internal fun createCronDateTime(
|
|||||||
dayOfMonth: Array<Byte>? = null,
|
dayOfMonth: Array<Byte>? = null,
|
||||||
month: Array<Byte>? = null,
|
month: Array<Byte>? = null,
|
||||||
years: Array<Int>? = null,
|
years: Array<Int>? = null,
|
||||||
weekDays: Array<Byte>? = null
|
weekDays: Array<Byte>? = null,
|
||||||
|
milliseconds: Array<Short>? = millisecondsArrayDefault
|
||||||
): CronDateTime {
|
): CronDateTime {
|
||||||
return CronDateTime(weekDays, years, month, dayOfMonth, hours, minutes, seconds)
|
return CronDateTime(weekDays, years, month, dayOfMonth, hours, minutes, seconds, milliseconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,8 +83,20 @@ internal fun createKronScheduler(
|
|||||||
dayOfMonth: Array<Byte>? = null,
|
dayOfMonth: Array<Byte>? = null,
|
||||||
month: Array<Byte>? = null,
|
month: Array<Byte>? = null,
|
||||||
years: Array<Int>? = null,
|
years: Array<Int>? = null,
|
||||||
weekDays: Array<Byte>? = null
|
weekDays: Array<Byte>? = null,
|
||||||
): KronScheduler = CronDateTimeScheduler(createCronDateTime(seconds, minutes, hours, dayOfMonth, month, years, weekDays))
|
milliseconds: Array<Short>? = millisecondsArrayDefault
|
||||||
|
): KronScheduler = CronDateTimeScheduler(
|
||||||
|
createCronDateTime(
|
||||||
|
seconds,
|
||||||
|
minutes,
|
||||||
|
hours,
|
||||||
|
dayOfMonth,
|
||||||
|
month,
|
||||||
|
years,
|
||||||
|
weekDays,
|
||||||
|
milliseconds
|
||||||
|
)
|
||||||
|
)
|
||||||
/**
|
/**
|
||||||
* @return [KronScheduler] (in fact [CronDateTimeScheduler]) based on incoming data
|
* @return [KronScheduler] (in fact [CronDateTimeScheduler]) based on incoming data
|
||||||
*/
|
*/
|
||||||
@@ -93,8 +108,21 @@ internal fun createKronSchedulerWithOffset(
|
|||||||
month: Array<Byte>? = null,
|
month: Array<Byte>? = null,
|
||||||
years: Array<Int>? = null,
|
years: Array<Int>? = null,
|
||||||
weekDays: Array<Byte>? = null,
|
weekDays: Array<Byte>? = null,
|
||||||
offset: TimezoneOffset
|
offset: TimezoneOffset,
|
||||||
): KronScheduler = CronDateTimeSchedulerTz(createCronDateTime(seconds, minutes, hours, dayOfMonth, month, years, weekDays), offset)
|
milliseconds: Array<Short>? = millisecondsArrayDefault
|
||||||
|
): KronScheduler = CronDateTimeSchedulerTz(
|
||||||
|
createCronDateTime(
|
||||||
|
seconds,
|
||||||
|
minutes,
|
||||||
|
hours,
|
||||||
|
dayOfMonth,
|
||||||
|
month,
|
||||||
|
years,
|
||||||
|
weekDays,
|
||||||
|
milliseconds
|
||||||
|
),
|
||||||
|
offset
|
||||||
|
)
|
||||||
|
|
||||||
internal fun List<CronDateTime>.merge() = CronDateTime(
|
internal fun List<CronDateTime>.merge() = CronDateTime(
|
||||||
flatMap { it.daysOfWeek ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
flatMap { it.daysOfWeek ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||||
@@ -104,4 +132,5 @@ internal fun List<CronDateTime>.merge() = CronDateTime(
|
|||||||
flatMap { it.hours ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
flatMap { it.hours ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||||
flatMap { it.minutes ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
flatMap { it.minutes ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||||
flatMap { it.seconds ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
flatMap { it.seconds ?.toList() ?: emptyList() }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||||
|
flatMap { it.milliseconds ?.toList() ?: listOf(0) }.distinct().toTypedArray().takeIf { it.isNotEmpty() },
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package dev.inmo.krontab.internal
|
|||||||
|
|
||||||
import com.soywiz.klock.DateTime
|
import com.soywiz.klock.DateTime
|
||||||
import dev.inmo.krontab.KronScheduler
|
import dev.inmo.krontab.KronScheduler
|
||||||
import dev.inmo.krontab.collection.plus
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cron-oriented realisation of [KronScheduler]
|
* Cron-oriented realisation of [KronScheduler]
|
||||||
*
|
*
|
||||||
* @see dev.inmo.krontab.AnyTimeScheduler
|
* @see dev.inmo.krontab.AnyTimeScheduler
|
||||||
|
* @see dev.inmo.krontab.EveryMillisecondScheduler
|
||||||
* @see dev.inmo.krontab.EverySecondScheduler
|
* @see dev.inmo.krontab.EverySecondScheduler
|
||||||
* @see dev.inmo.krontab.EveryMinuteScheduler
|
* @see dev.inmo.krontab.EveryMinuteScheduler
|
||||||
* @see dev.inmo.krontab.EveryHourScheduler
|
* @see dev.inmo.krontab.EveryHourScheduler
|
||||||
@@ -36,23 +36,3 @@ internal fun mergeCronDateTimeSchedulers(
|
|||||||
): CronDateTimeScheduler = CronDateTimeScheduler(
|
): CronDateTimeScheduler = CronDateTimeScheduler(
|
||||||
schedulers.map { it.cronDateTime }.merge()
|
schedulers.map { it.cronDateTime }.merge()
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
|
||||||
* @return New instance of [CronDateTimeScheduler] with all unique [CronDateTimeScheduler.cronDateTimes] of
|
|
||||||
* [kronSchedulers] included
|
|
||||||
*/
|
|
||||||
@Deprecated("Will be removed in next major release", ReplaceWith("merge", "dev.inmo.krontab"))
|
|
||||||
fun merge(kronSchedulers: List<KronScheduler>) = kronSchedulers.apply { dev.inmo.krontab.merge() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return Vararg shortcut for [dev.inmo.krontab.merge]
|
|
||||||
*/
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
@Deprecated("Will be removed in next major release", ReplaceWith("merge", "dev.inmo.krontab"))
|
|
||||||
inline fun merge(vararg kronDateTimeSchedulers: KronScheduler) = kronDateTimeSchedulers.apply { dev.inmo.krontab.merge() }
|
|
||||||
/**
|
|
||||||
* @return Vararg shortcut for [dev.inmo.krontab.merge]
|
|
||||||
*/
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
@Deprecated("Will be removed in next major release", ReplaceWith("merge", "dev.inmo.krontab"))
|
|
||||||
inline fun KronScheduler.plus(other: KronScheduler) = this + other
|
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package dev.inmo.krontab.internal
|
||||||
|
|
||||||
|
internal const val millisecondsDefault: Short = 0
|
||||||
|
internal val millisecondsArrayDefault: Array<Short> = arrayOf(millisecondsDefault)
|
||||||
@@ -101,13 +101,14 @@ internal fun NearDateTimeCalculatorDays(
|
|||||||
times: Array<Byte>
|
times: Array<Byte>
|
||||||
) = CommonNearDateTimeCalculator(
|
) = CommonNearDateTimeCalculator(
|
||||||
times,
|
times,
|
||||||
{ it.dayOfMonth.toByte() },
|
{ (it.dayOfMonth - 1).toByte() },
|
||||||
{ dateTime, newOne ->
|
{ dateTime, newOne ->
|
||||||
(if (newOne < dateTime.dayOfMonth) {
|
val dateTime = (if (newOne < dateTime.dayOfMonth) {
|
||||||
dateTime.plus(1.months)
|
dateTime.plus(1.months)
|
||||||
} else {
|
} else {
|
||||||
dateTime
|
dateTime
|
||||||
}).copy(
|
})
|
||||||
|
dateTime.copy(
|
||||||
dayOfMonth = min(dateTime.month.days(dateTime.year), newOne.toInt() + 1), // index1
|
dayOfMonth = min(dateTime.month.days(dateTime.year), newOne.toInt() + 1), // index1
|
||||||
hour = 0,
|
hour = 0,
|
||||||
minute = 0,
|
minute = 0,
|
||||||
@@ -121,7 +122,7 @@ internal fun NearDateTimeCalculatorMonths(
|
|||||||
times: Array<Byte>
|
times: Array<Byte>
|
||||||
) = CommonNearDateTimeCalculator(
|
) = CommonNearDateTimeCalculator(
|
||||||
times,
|
times,
|
||||||
{ it.dayOfMonth.toByte() },
|
{ it.month0.toByte() },
|
||||||
{ dateTime, newOne ->
|
{ dateTime, newOne ->
|
||||||
(if (newOne < dateTime.month0) {
|
(if (newOne < dateTime.month0) {
|
||||||
dateTime.plus(1.years)
|
dateTime.plus(1.years)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package dev.inmo.krontab.internal
|
|||||||
typealias Converter<T> = (Int) -> T
|
typealias Converter<T> = (Int) -> T
|
||||||
|
|
||||||
internal val intToByteConverter: Converter<Byte> = { it: Int -> it.toByte() }
|
internal val intToByteConverter: Converter<Byte> = { it: Int -> it.toByte() }
|
||||||
|
internal val intToShortConverter: Converter<Short> = { it: Int -> it.toShort() }
|
||||||
internal val intToIntConverter: Converter<Int> = { it: Int -> it }
|
internal val intToIntConverter: Converter<Int> = { it: Int -> it }
|
||||||
private fun <T> createSimpleScheduler(from: String, dataRange: IntRange, dataConverter: Converter<T>): List<T>? {
|
private fun <T> createSimpleScheduler(from: String, dataRange: IntRange, dataConverter: Converter<T>): List<T>? {
|
||||||
val things = from.split(",")
|
val things = from.split(",")
|
||||||
@@ -44,6 +45,7 @@ internal fun parseDaysOfMonth(from: String) = createSimpleScheduler(from, dayOfM
|
|||||||
internal fun parseHours(from: String) = createSimpleScheduler(from, hoursRange, intToByteConverter) ?.toTypedArray()
|
internal fun parseHours(from: String) = createSimpleScheduler(from, hoursRange, intToByteConverter) ?.toTypedArray()
|
||||||
internal fun parseMinutes(from: String) = createSimpleScheduler(from, minutesRange, intToByteConverter) ?.toTypedArray()
|
internal fun parseMinutes(from: String) = createSimpleScheduler(from, minutesRange, intToByteConverter) ?.toTypedArray()
|
||||||
internal fun parseSeconds(from: String) = createSimpleScheduler(from, secondsRange, intToByteConverter) ?.toTypedArray()
|
internal fun parseSeconds(from: String) = createSimpleScheduler(from, secondsRange, intToByteConverter) ?.toTypedArray()
|
||||||
|
internal fun parseMilliseconds(from: String?) = from ?.let { if (it.endsWith("ms")) createSimpleScheduler(from.removeSuffix("ms"), millisecondsRange, intToShortConverter) ?.toTypedArray() else null }
|
||||||
|
|
||||||
internal fun <T> Array<T>.fillWith(
|
internal fun <T> Array<T>.fillWith(
|
||||||
whereToPut: MutableList<CronDateTime>,
|
whereToPut: MutableList<CronDateTime>,
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ internal val dayOfMonthRange = 0 .. 30
|
|||||||
internal val hoursRange = 0 .. 23
|
internal val hoursRange = 0 .. 23
|
||||||
internal val minutesRange = 0 .. 59
|
internal val minutesRange = 0 .. 59
|
||||||
internal val secondsRange = minutesRange
|
internal val secondsRange = minutesRange
|
||||||
|
internal val millisecondsRange = 0 .. 999
|
||||||
|
|||||||
@@ -4,20 +4,21 @@ import com.soywiz.klock.DateTime
|
|||||||
import com.soywiz.klock.DateTimeTz
|
import com.soywiz.klock.DateTimeTz
|
||||||
import dev.inmo.krontab.*
|
import dev.inmo.krontab.*
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.channelFlow
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This [Flow] will trigger emitting each near time which will be returned from [this] [KronScheduler] with attention to
|
* This [Flow] will trigger emitting each near time which will be returned from [this] [KronScheduler] with attention to
|
||||||
* time zones
|
* time zones
|
||||||
*
|
*
|
||||||
* @see channelFlow
|
* @see channelFlow
|
||||||
* @see KronSchedulerTz.doWhile
|
* @see KronSchedulerTz.doInfinityTz
|
||||||
*/
|
*/
|
||||||
@FlowPreview
|
@FlowPreview
|
||||||
fun KronSchedulerTz.asTzFlow(): Flow<DateTimeTz> = channelFlow {
|
fun KronScheduler.asTzFlow(): Flow<DateTimeTz> = channelFlow {
|
||||||
doInfinity {
|
doInfinityTz {
|
||||||
send(DateTime.nowLocal())
|
send(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,45 +26,11 @@ fun KronSchedulerTz.asTzFlow(): Flow<DateTimeTz> = channelFlow {
|
|||||||
* This method is a map for [asTzFlow] and will works the same but return flow with [DateTime]s
|
* This method is a map for [asTzFlow] and will works the same but return flow with [DateTime]s
|
||||||
*
|
*
|
||||||
* @see channelFlow
|
* @see channelFlow
|
||||||
* @see KronScheduler.doWhile
|
* @see KronScheduler.doInfinity
|
||||||
*/
|
*/
|
||||||
@FlowPreview
|
@FlowPreview
|
||||||
fun KronScheduler.asFlow(): Flow<DateTime> = channelFlow {
|
fun KronScheduler.asFlow(): Flow<DateTime> = channelFlow {
|
||||||
doInfinity {
|
doInfinity {
|
||||||
send(DateTime.now())
|
send(it)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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<DateTimeTz> = 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",
|
|
||||||
ReplaceWith("asFlow", "dev.inmo.krontab.utils.asFlow")
|
|
||||||
)
|
|
||||||
@FlowPreview
|
|
||||||
class SchedulerFlow(
|
|
||||||
private val scheduler: KronScheduler
|
|
||||||
) : AbstractFlow<DateTime>() {
|
|
||||||
@FlowPreview
|
|
||||||
override suspend fun collectSafely(collector: FlowCollector<DateTime>) {
|
|
||||||
while (true) {
|
|
||||||
val now = DateTime.now()
|
|
||||||
val nextTime = scheduler.next(now) ?: break
|
|
||||||
val sleepDelay = (nextTime - now).millisecondsLong
|
|
||||||
delay(sleepDelay)
|
|
||||||
collector.emit(nextTime)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package dev.inmo.krontab.utils.flows
|
||||||
|
|
||||||
|
import com.soywiz.klock.*
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterSeconds(vararg seconds: Int) = filter { it.seconds in seconds }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterMinutes(vararg minutes: Int) = filter { it.minutes in minutes }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterHours(vararg hours: Int) = filter { it.hours in hours }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterDaysOfMonths(vararg daysOfMonths: Int) = filter { it.dayOfMonth in daysOfMonths }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterMonths(vararg months: Month) = filter { it.month in months }
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterMonths0(vararg months: Int) = filter { it.month0 in months }
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterMonths1(vararg months: Int) = filter { it.month1 in months }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterYears(year: Year) = filter { it.year == year }
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterYears(vararg years: Int) = filter { it.yearInt in years }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterWeekDays(vararg weekDays: DayOfWeek) = filter { it.dayOfWeek in weekDays }
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.filterWeekDays(vararg weekDays: Int) = filter { it.dayOfWeekInt in weekDays }
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package dev.inmo.krontab.utils.flows
|
||||||
|
|
||||||
|
import com.soywiz.klock.*
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.filter
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterSeconds(vararg seconds: Int) = filter { it.seconds in seconds }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterMinutes(vararg minutes: Int) = filter { it.minutes in minutes }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterHours(vararg hours: Int) = filter { it.hours in hours }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterDaysOfMonths(vararg daysOfMonths: Int) = filter { it.dayOfMonth in daysOfMonths }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterMonths(vararg months: Month) = filter { it.month in months }
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterMonths0(vararg months: Int) = filter { it.month0 in months }
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterMonths1(vararg months: Int) = filter { it.month1 in months }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterYears(year: Year) = filter { it.year == year }
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterYears(vararg years: Int) = filter { it.yearInt in years }
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterWeekDays(vararg weekDays: DayOfWeek) = filter { it.dayOfWeek in weekDays }
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.filterWeekDays(vararg weekDays: Int) = filter { it.dayOfWeekInt in weekDays }
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.inmo.krontab.utils.flows
|
||||||
|
|
||||||
|
import com.soywiz.klock.*
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.onlyStartsOfMinutes() = filterSeconds(0)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.onlyStartsOfHours() = filterMinutes(0).onlyStartsOfMinutes()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.onlyStartsOfDays() = filterHours(0).onlyStartsOfHours()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.onlyStartsOfMondays() = filterWeekDays(DayOfWeek.Monday).onlyStartsOfDays()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.onlyStartsOfSundays() = filterWeekDays(DayOfWeek.Sunday).onlyStartsOfDays()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.onlyStartsOfMonths() = filterDaysOfMonths(1).onlyStartsOfDays()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTime>.onlyStartsOfYears() = filterMonths(Month.January).onlyStartsOfMonths()
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package dev.inmo.krontab.utils.flows
|
||||||
|
|
||||||
|
import com.soywiz.klock.*
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.onlyStartsOfMinutes() = filterSeconds(0)
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.onlyStartsOfHours() = filterMinutes(0).onlyStartsOfMinutes()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.onlyStartsOfDays() = filterHours(0).onlyStartsOfHours()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.onlyStartsOfMondays() = filterWeekDays(DayOfWeek.Monday).onlyStartsOfDays()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.onlyStartsOfSundays() = filterWeekDays(DayOfWeek.Sunday).onlyStartsOfDays()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.onlyStartsOfMonths() = filterDaysOfMonths(1).onlyStartsOfDays()
|
||||||
|
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
inline fun Flow<DateTimeTz>.onlyStartsOfYears() = filterMonths(Month.January).onlyStartsOfMonths()
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package dev.inmo.krontab.utils
|
||||||
|
|
||||||
|
import com.soywiz.klock.DateTime
|
||||||
|
import com.soywiz.klock.days
|
||||||
|
import dev.inmo.krontab.buildSchedule
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
class InfinityLoopCheckTest {
|
||||||
|
@Test
|
||||||
|
fun absenceOfInfinityLoopCheckTest() {
|
||||||
|
val now = DateTime.now().startOfYear.startOfDay
|
||||||
|
for (i in 0 until now.year.days) {
|
||||||
|
val scheduleDateTime = (now + i.days)
|
||||||
|
runTest {
|
||||||
|
assertEquals(
|
||||||
|
scheduleDateTime,
|
||||||
|
buildSchedule("0 0 0 ${scheduleDateTime.dayOfMonth - 1} ${scheduleDateTime.month0}").next(now)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ import dev.inmo.krontab.buildSchedule
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.takeWhile
|
import kotlinx.coroutines.flow.takeWhile
|
||||||
import kotlin.test.Test
|
import kotlin.math.floor
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.*
|
||||||
|
|
||||||
@ExperimentalCoroutinesApi
|
@ExperimentalCoroutinesApi
|
||||||
@FlowPreview
|
@FlowPreview
|
||||||
@@ -29,6 +29,23 @@ class StringParseTest {
|
|||||||
assertEquals(mustBeCollected, collected)
|
assertEquals(mustBeCollected, collected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Test
|
||||||
|
fun testThatFlowIsCorrectlyWorkEverySecondWhenMillisIsHalfOfSecondBuiltOnString() {
|
||||||
|
val kronScheduler = buildSchedule("*/1 * * * * 500ms")
|
||||||
|
|
||||||
|
val flow = kronScheduler.asFlow()
|
||||||
|
|
||||||
|
runTest {
|
||||||
|
val mustBeCollected = 10
|
||||||
|
var collected = 0
|
||||||
|
flow.takeWhile {
|
||||||
|
collected < mustBeCollected
|
||||||
|
}.collect {
|
||||||
|
collected++
|
||||||
|
}
|
||||||
|
assertEquals(mustBeCollected, collected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testThatFlowIsCorrectlyWorkEverySecondWithMuchOfEmittersBuiltOnString() {
|
fun testThatFlowIsCorrectlyWorkEverySecondWithMuchOfEmittersBuiltOnString() {
|
||||||
@@ -74,6 +91,29 @@ class StringParseTest {
|
|||||||
flow.takeWhile { ranges.isNotEmpty() }.collect {
|
flow.takeWhile { ranges.isNotEmpty() }.collect {
|
||||||
ranges.remove(it.seconds)
|
ranges.remove(it.seconds)
|
||||||
collected++
|
collected++
|
||||||
|
assertTrue(collected <= expectedCollects)
|
||||||
|
}
|
||||||
|
assertEquals(expectedCollects, collected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
fun testNextIsCorrectlyWorkEverySeveralMillisecondsRangeBuiltOnString() {
|
||||||
|
val rangesEnds = listOf(0, 200, 500, 750)
|
||||||
|
val kronScheduler = buildSchedule("* * * * * ${rangesEnds.joinToString(",") { "$it" }}ms")
|
||||||
|
|
||||||
|
runTest {
|
||||||
|
val ranges = rangesEnds.toMutableList()
|
||||||
|
val expectedCollects = ranges.size
|
||||||
|
var collected = 0
|
||||||
|
|
||||||
|
var currentTime = DateTime.now()
|
||||||
|
while (ranges.isNotEmpty()) {
|
||||||
|
val nextTrigger = kronScheduler.next(currentTime) ?: error("Strangely unable to get next time")
|
||||||
|
|
||||||
|
ranges.remove(nextTrigger.milliseconds)
|
||||||
|
collected++
|
||||||
|
|
||||||
|
currentTime = nextTrigger + 1.milliseconds
|
||||||
}
|
}
|
||||||
assertEquals(expectedCollects, collected)
|
assertEquals(expectedCollects, collected)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user