Compare commits

...

61 Commits
0.7.0 ... 0.9.0

Author SHA1 Message Date
f6518d4d25 add kotlin-js-store folder in gitignore 2023-02-28 12:25:23 +06:00
97a8f39826 update dependencies 2023-02-28 12:24:30 +06:00
469861f7e3 start 0.9.0 2023-02-28 12:23:12 +06:00
69305506ce Update README.md 2023-02-19 16:35:31 +06:00
63ea3f0f1a Merge pull request #44 from InsanusMokrassar/0.8.5
0.8.5
2022-12-15 08:38:54 +06:00
13a8bacb52 fix changelog 2022-12-15 08:37:54 +06:00
9c80e29e71 update autobuild script 2022-12-14 23:00:44 +06:00
cfd2de8fe9 update dependencies 2022-12-14 22:45:34 +06:00
e3490d432e fix in timezoned crontab scheduler 2022-12-14 22:44:27 +06:00
1c95636b71 start 0.8.5 2022-12-14 22:30:34 +06:00
b31a6ab86a Merge pull request #43 from InsanusMokrassar/0.8.4
0.8.4
2022-12-08 09:32:25 +06:00
c35a679827 update kotlin 2022-12-05 15:27:41 +06:00
06f56026db start 0.8.4 2022-12-05 15:26:31 +06:00
54be57d709 Merge pull request #42 from InsanusMokrassar/0.8.3
0.8.3
2022-11-15 10:04:46 +06:00
fae297e4a6 Update CHANGELOG.md 2022-11-14 10:11:46 +06:00
bd81298ac9 Update gradle.properties 2022-11-11 10:25:26 +06:00
cfac5fcd1c Merge pull request #41 from InsanusMokrassar/0.8.2
0.8.2
2022-10-02 22:37:13 +06:00
93d38f8945 Update CHANGELOG.md 2022-10-02 22:26:24 +06:00
97dcd77a8a Update gradle.properties 2022-10-02 22:22:04 +06:00
afa2521b5d Update gradle-wrapper.properties 2022-10-02 22:21:23 +06:00
37b0ec9fb7 start 0.8.2 2022-10-02 11:40:48 +06:00
d36888173a Merge pull request #40 from InsanusMokrassar/0.8.1
0.8.1
2022-09-13 00:58:24 +06:00
30011cd309 Update CHANGELOG.md 2022-09-11 14:18:46 +06:00
fd37a5ddc3 Update gradle.properties 2022-09-11 14:17:48 +06:00
3874f6a42c start 0.8.1 2022-09-11 14:16:52 +06:00
8a98ebd5f9 Merge pull request #39 from InsanusMokrassar/0.8.0
0.8.0
2022-08-06 10:01:18 +06:00
8d0c55129f Update CHANGELOG.md 2022-08-06 09:54:31 +06:00
54b06bf9e6 start 0.8.0 2022-08-06 09:50:59 +06:00
da436ab432 Merge pull request #38 from InsanusMokrassar/0.7.5
0.7.5
2022-07-22 17:09:31 +06:00
154d211514 change kdocs link 2022-07-22 17:09:00 +06:00
0b843ada4f update yarn.lock 2022-07-22 17:03:20 +06:00
25f204a488 update dependencies 2022-07-22 17:00:41 +06:00
2e4ccb9253 start 0.7.5 2022-07-22 16:59:07 +06:00
411a52b85e Update github_release.gradle 2022-07-02 18:38:03 +06:00
5a5bde6f20 Merge pull request #37 from InsanusMokrassar/0.7.4
0.7.4
2022-07-02 12:20:28 +06:00
8f9b84ecc7 Update CHANGELOG.md 2022-07-02 12:20:04 +06:00
62c5a0f98d Update gradle.properties 2022-07-01 23:01:29 +06:00
dfd1a5a909 Update gradle.properties 2022-07-01 23:00:34 +06:00
04390f0726 Update README.md 2022-06-15 15:18:41 +06:00
d0f02e37ce Merge pull request #36 from InsanusMokrassar/0.7.3
0.7.3
2022-06-15 14:48:10 +06:00
681043db5a Update NearDateTimeCalculator.kt 2022-06-15 14:46:12 +06:00
f63ed1a873 rename check infinity loop test class and fun 2022-06-15 14:43:28 +06:00
9ea8194d7d fill changelog 2022-06-15 13:46:37 +06:00
0c37ccc902 fix of #33 2022-06-15 13:37:48 +06:00
2abef58335 fix of #35 2022-06-15 13:31:26 +06:00
8ac6cd3e62 fix of #34 and upfix for #27 2022-06-15 13:27:21 +06:00
58f30aef15 fix of #27 2022-06-15 12:40:03 +06:00
f163a64964 start 0.7.3 2022-06-14 00:14:15 +06:00
79ce455f5c Merge pull request #32 from InsanusMokrassar/0.7.2
0.7.2
2022-04-29 22:26:14 +06:00
fd54b035fe update yarn.lock 2022-04-29 22:18:13 +06:00
4fab7a28ff fix of #30 2022-04-29 22:14:42 +06:00
28d5665a14 fix of #31 and several refactorings 2022-04-29 21:57:10 +06:00
f98fd5ddb7 update dependencies 2022-04-29 20:44:51 +06:00
981327675a start 0.7.2 2022-04-29 20:43:33 +06:00
7649d20984 Merge pull request #28 from InsanusMokrassar/0.7.1
0.7.1
2022-02-27 22:08:03 +06:00
ab274636b9 workflows fix 2022-02-27 20:47:10 +06:00
7f2f8a4a26 revert android sdk version 2022-02-27 20:37:48 +06:00
f64171c0f0 update android compile sdk up to 33.0.0 2022-02-27 19:05:07 +06:00
8382108b01 start 0.7.1 2022-02-27 18:20:49 +06:00
32499d02fb Update kdocs.yml 2021-12-25 14:05:13 +06:00
2b06033c75 Merge pull request #25 from InsanusMokrassar/0.7.0
0.7.0
2021-12-25 00:25:16 +06:00
33 changed files with 542 additions and 129 deletions

View File

@@ -10,10 +10,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Fix android 31.0.0 dx
java-version: 11
- name: Fix android 32.0.0 dx
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
run: ./gradlew dokkaHtml
- name: Publish KDocs

View File

@@ -7,19 +7,21 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Fix android 32.0.0 dx
continue-on-error: true
run: cd /usr/local/lib/android/sdk/build-tools/32.0.0/ && mv d8 dx && cd lib && mv d8.jar dx.jar
java-version: 11
- name: Update version
run: |
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
sed -i -e "s/^version=\([0-9\.]*\)/version=\1-branch_$branch-build${{ github.run_number }}/" gradle.properties
- name: prebuild
run: ./gradlew clean build
- name: Publish to Gitea
continue-on-error: true
run: ./gradlew publishAllPublicationsToGiteaRepository
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
- name: Publish package
continue-on-error: true
run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository -x signJsPublication -x signJvmPublication -x signKotlinMultiplatformPublication -x signAndroidReleasePublication -x signAndroidDebugPublication -x signAndroidReleasePublication
run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository
env:
GITHUBPACKAGES_USER: ${{ github.actor }}
GITHUBPACKAGES_PASSWORD: ${{ secrets.GITHUB_TOKEN }}

2
.gitignore vendored
View File

@@ -9,4 +9,6 @@ settings.xml
build/
out/
kotlin-js-store/
local.properties

View File

@@ -1,5 +1,81 @@
# Changelog
## 0.9.0
* Versions
* `Kotlin`: `1.8.10`
* `AndroidXWork`: `2.8.0`
## 0.8.5
* Project is now available in owner `Gitea`: https://git.inmo.dev/InsanusMokrassar/-/packages/maven/dev.inmo-krontab
* `KronSchedulerTz#next` with incoming `DateTime` now will use adjusted local time instead of unadjusted one
* `CronDateTimeSchedulerTz#next` with incoming `DateTime` will convert that parameter to internal offset directly
## 0.8.4
* Versions
* `Kotlin`: `1.7.22`
## 0.8.3
* Versions
* `Kotlin`: `1.7.21`
* `Klock`: `3.4.0`
## 0.8.2
**THIS VERSION HAS CHANGED COMPILE ANDROID SDK FROM 32 -> 33**
* Versions
* `Kotlin`: `1.7.20`
* `Klock`: `3.2.0`
## 0.8.1
* Versions
* `Klock`: `3.1.0`
## 0.8.0
**THIS VERSION HAS CHANGED MIN ANDROID SDK FROM 19 -> 21**
* Versions
* `Kotlin`: `1.7.10`
* `Klock`: `3.0.0`
## 0.7.5
* Versions
* `Coroutines`: `1.6.4`
## 0.7.4
* Versions
* `Coroutines`: `1.6.3`
## 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**

View File

@@ -1,9 +1,16 @@
# krontab
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/krontab/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/krontab)
[![Build Status](https://github.com/InsanusMokrassar/krontab/actions/workflows/publishing_packages.yml/badge.svg)](https://github.com/InsanusMokrassar/krontab/actions/workflows/publishing_packages.yml)
[![KDocs](https://raw.githubusercontent.com/InsanusMokrassar/badges/master/kdocs.svg)](https://krontab.inmo.dev/index.html)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/dev.inmo/krontab/badge.svg)](https://maven-badges.herokuapp.com/maven-central/dev.inmo/krontab)
[![Telegram Chat](https://img.shields.io/badge/Telegram%20Chat-0288D1?style=for-the-badge&logo=telegram&logoColor=white)](https://inmodev_chat.t.me)
![JVM](https://img.shields.io/badge/JVM-red?style=for-the-badge&logo=openjdk&logoColor=white)
![Android](https://img.shields.io/badge/Android-green?style=for-the-badge&logo=android&logoColor=white)
![Js](https://img.shields.io/badge/JavaScript-323330?style=for-the-badge&logo=javascript&logoColor=F7DF1E)
[![KDocs](https://img.shields.io/badge/KDocs-323330?style=for-the-badge&logo=Kotlin&logoColor=7F52FF)](https://insanusmokrassar.github.io/krontab/)
[![Tutorials](https://img.shields.io/badge/Tutorials-0288D1?style=for-the-badge&logo=bookstack&logoColor=white)](https://bookstack.inmo.dev/books/krontab)
Library was created to give oppotunity to launch some things from time to time according to some schedule in
runtime of applications.

View File

@@ -10,7 +10,7 @@ buildscript {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.github.breadmoirai:github-release:$github_release_plugin_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'
}
}

View File

@@ -21,7 +21,7 @@ if (new File(projectDir, "secret.gradle").exists()) {
owner "InsanusMokrassar"
repo "${rootProject.name}"
tagName "${project.version}"
tagName "v${project.version}"
releaseName "${project.version}"
targetCommitish "${project.version}"

View File

@@ -8,30 +8,30 @@ android.useAndroidX=true
android.enableJetifier=false
kotlin_version=1.6.10
kotlin_coroutines_version=1.6.0
kotlin_version=1.8.10
kotlin_coroutines_version=1.6.4
dokka_version=1.6.0
dokka_version=1.7.20
klockVersion=2.4.10
klockVersion=3.4.0
## Github reease
github_release_plugin_version=2.2.12
github_release_plugin_version=2.4.1
## Android
android_minSdkVersion=19
android_compileSdkVersion=32
android_buildToolsVersion=32.0.0
dexcount_version=3.0.0
android_minSdkVersion=21
android_compileSdkVersion=33
android_buildToolsVersion=33.0.1
dexcount_version=3.1.0
junit_version=4.12
test_ext_junit_version=1.1.2
espresso_core=3.3.0
test_ext_junit_version=1.1.3
espresso_core=3.4.0
androidx_work_version=2.7.1
androidx_work_version=2.8.0
## Common
version=0.7.0
android_code_version=11
version=0.9.0
android_code_version=23

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip

View File

@@ -1 +1 @@
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/krontab/blob/master/LICENSE"}],"mavenConfig":{"name":"Krontab","description":"It is an analog of crontab util for Kotlin Coroutines","url":"https://github.com/InsanusMokrassar/krontab","vcsUrl":"https://github.com/InsanusMokrassar/krontab.git","includeGpgSigning":true,"developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/krontab"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}]}}
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/krontab/blob/master/LICENSE"}],"mavenConfig":{"name":"Krontab","description":"It is an analog of crontab util for Kotlin Coroutines","url":"https://github.com/InsanusMokrassar/krontab","vcsUrl":"https://github.com/InsanusMokrassar/krontab.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/krontab"},{"name":"Gitea","url":"https://git.inmo.dev/api/packages/InsanusMokrassar/maven","credsType":{"type":"dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository.CredentialsType.HttpHeaderCredentials","headerName":"Authorization","headerValueProperty":"GITEA_TOKEN"}},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}

View File

@@ -1,5 +1,4 @@
apply plugin: 'maven-publish'
apply plugin: 'signing'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
@@ -43,27 +42,58 @@ publishing {
maven {
name = "GithubPackages"
url = uri("https://maven.pkg.github.com/InsanusMokrassar/krontab")
credentials {
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
}
}
}
if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
maven {
name = "Gitea"
url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
credentials(HttpHeaderCredentials) {
name = "Authorization"
value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
maven {
name = "sonatype"
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
credentials {
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
}
}
}
}
}
}
signing {
useGpgCmd()
sign publishing.publications
if (project.hasProperty("signing.gnupg.keyName")) {
apply plugin: 'signing'
signing {
useGpgCmd()
sign publishing.publications
}
task signAll {
tasks.withType(Sign).forEach {
dependsOn(it)
}
}
}

View File

@@ -6,6 +6,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlin.coroutines.coroutineContext
/**
* 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
*/
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 {
delay((it - DateTime.now()).millisecondsLong)
}
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.
*
@@ -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.
*
* 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
* Will [buildSchedule] using [scheduleConfig] and call [doOnce] on it
* @see buildSchedule
*/
suspend inline fun <T> doOnce(
scheduleConfig: String,
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
*/
suspend inline fun <T> doOnceTz(
@@ -63,24 +65,20 @@ suspend inline fun <T> doOnceTz(
noinline block: suspend (DateTimeTz) -> T
) = 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
*/
suspend inline fun KronScheduler.doWhileLocal(noinline block: suspend (DateTime) -> Boolean) {
suspend inline fun KronScheduler.doWhile(noinline block: suspend (DateTime) -> Boolean) {
do {
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
@@ -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]
*
* @see buildSchedule
*/
@Deprecated("Replaceable", ReplaceWith("doWhile", "dev.inmo.krontab.doWhile"))
suspend inline fun doWhileLocal(
scheduleConfig: String,
noinline block: suspend (DateTime) -> Boolean
) = buildSchedule(scheduleConfig).doWhileLocal(block)
) = doWhile(scheduleConfig, block)
/**
* Will [buildSchedule] using [scheduleConfig] and call [doWhile] with [block]
@@ -116,24 +120,19 @@ suspend inline fun doWhileTz(
noinline block: suspend (DateTimeTz) -> Boolean
) = 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
*/
suspend inline fun KronScheduler.doInfinityLocal(noinline block: suspend (DateTime) -> Unit) = doWhileLocal {
suspend inline fun KronScheduler.doInfinity(noinline block: suspend (DateTime) -> Unit) = doWhile {
block(it)
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
@@ -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 {
block()
coroutineContext.isActive
}
suspend inline fun doInfinity(
scheduleConfig: String,
noinline block: suspend (DateTime) -> Unit
) = buildSchedule(scheduleConfig).doInfinity(block)
/**
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
*
* @see buildSchedule
*/
@Deprecated("Replaceable", ReplaceWith("doInfinity", "dev.inmo.krontab.doInfinity"))
suspend inline fun doInfinityLocal(
scheduleConfig: String,
noinline block: suspend (DateTime) -> Unit
) = buildSchedule(scheduleConfig).doInfinityLocal(block)
) = doInfinity(scheduleConfig, block)
/**
* Will [buildSchedule] using [scheduleConfig] and call [doInfinity] with [block]
@@ -170,13 +172,3 @@ suspend inline fun doInfinityTz(
scheduleConfig: String,
noinline block: suspend (DateTimeTz) -> Unit
) = 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)

View File

@@ -13,7 +13,7 @@ import com.soywiz.klock.DateTimeTz
interface KronSchedulerTz : KronScheduler {
suspend fun next(relatively: DateTimeTz): DateTimeTz?
override suspend fun next(relatively: DateTime): DateTime? = next(relatively.localUnadjusted) ?.local
override suspend fun next(relatively: DateTime): DateTime? = next(relatively.local) ?.local
}
suspend fun KronSchedulerTz.nextOrRelative(relatively: DateTimeTz): DateTimeTz = next(relatively) ?: getAnyNext(
@@ -31,4 +31,4 @@ suspend fun KronScheduler.next(relatively: DateTimeTz) = if (this is KronSchedul
this.next(relatively.local) ?.toOffsetUnadjusted(relatively.offset)
}
suspend fun KronScheduler.nextTimeZoned() = next(DateTime.now().local)
suspend fun KronScheduler.nextTimeZoned() = next(DateTime.now().local)

View File

@@ -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)

View File

@@ -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)

View File

@@ -16,6 +16,13 @@ val AnyTimeScheduler: KronScheduler by lazy {
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
*/

View File

@@ -14,14 +14,15 @@ typealias KrontabTemplate = String
/**
* Parse [incoming] string and adapt according to next format: "* * * * *" where order of things:
*
* * seconds
* * minutes
* * hours
* * dayOfMonth
* * month
* * (optional) year
* * (optional) (can be placed anywhere after month) (must be marked with `o` at the end, for example: 60o == +01:00) offset
* * (optional) (can be placed anywhere after month) dayOfWeek
* * **seconds**
* * **minutes**
* * **hours**
* * **dayOfMonth**
* * **month**
* * **year** (optional)
* * **offset** (optional) (can be placed anywhere after month) (must be marked with `o` at the end, for example: 60o == +01:00)
* * **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:
*
@@ -48,18 +49,21 @@ typealias KrontabTemplate = String
* * Months ranges can be found in [monthRange]
* * Years ranges can be found in [yearRange] (in fact - any [Int])
* * WeekDay (timezone) ranges can be found in [dayOfWeekRange]
* * Milliseconds ranges can be found in [millisecondsRange]
*
* Examples:
*
* * "0/5 * * * *" for every five seconds triggering
* * "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
* * "1 2 3 F,4,L 5" for triggering in near first second of second minute of third hour of fourth day of may
* * "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 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 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 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 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
* * "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" 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" 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 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" 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" 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
* 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 dayOfWeekParsed: Array<Byte>? = null
var yearParsed: Array<Int>? = null
var millisecondsParsed: Array<Short>? = null
val (secondsSource, minutesSource, hoursSource, dayOfMonthSource, monthSource) = incoming.split(" ").also {
listOfNotNull(
it.getOrNull(5),
it.getOrNull(6),
it.getOrNull(7)
it.getOrNull(7),
it.getOrNull(8)
).forEach {
val offsetFromString = parseOffset(it)
val dayOfWeekFromString = parseWeekDay(it)
val millisecondsFromString = parseMilliseconds(it)
offsetParsed = offsetParsed ?: offsetFromString
dayOfWeekParsed = dayOfWeekParsed ?: dayOfWeekFromString
millisecondsParsed = millisecondsParsed ?: millisecondsFromString
when {
dayOfWeekFromString != null || offsetFromString != null -> return@forEach
dayOfWeekFromString != null || offsetFromString != null || millisecondsFromString != null -> return@forEach
yearParsed == null -> {
yearParsed = parseYears(it)
}
@@ -100,10 +108,25 @@ fun createSimpleScheduler(
return offsetParsed ?.let { offset ->
createKronSchedulerWithOffset(
secondsParsed, minutesParsed, hoursParsed, dayOfMonthParsed, monthParsed, yearParsed, dayOfWeekParsed, TimezoneOffset(offset.minutes)
secondsParsed,
minutesParsed,
hoursParsed,
dayOfMonthParsed,
monthParsed,
yearParsed,
dayOfWeekParsed,
TimezoneOffset(offset.minutes),
millisecondsParsed ?: millisecondsArrayDefault
)
} ?: createKronScheduler(
secondsParsed, minutesParsed, hoursParsed, dayOfMonthParsed, monthParsed, yearParsed, dayOfWeekParsed
secondsParsed,
minutesParsed,
hoursParsed,
dayOfMonthParsed,
monthParsed,
yearParsed,
dayOfWeekParsed,
millisecondsParsed ?: millisecondsArrayDefault
)
}

View File

@@ -4,6 +4,7 @@ import com.soywiz.klock.TimezoneOffset
import com.soywiz.klock.minutes
import dev.inmo.krontab.KronScheduler
import dev.inmo.krontab.KronSchedulerTz
import dev.inmo.krontab.internal.*
import dev.inmo.krontab.internal.createKronScheduler
import dev.inmo.krontab.internal.createKronSchedulerWithOffset
import dev.inmo.krontab.utils.Minutes
@@ -45,7 +46,8 @@ class SchedulerBuilder(
private var month: Array<Byte>? = null,
private var year: Array<Int>? = 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(
initial: Array<I>?,
@@ -63,6 +65,17 @@ class SchedulerBuilder(
} ?: builderValue
}
/**
* Starts an milliseconds block
*/
fun milliseconds(block: MillisecondsBuilder.() -> Unit) {
milliseconds = callAndReturn(
milliseconds,
MillisecondsBuilder(),
block
) ?.toTypedArray()
}
/**
* Starts an seconds block
*/
@@ -147,6 +160,16 @@ class SchedulerBuilder(
* @see dev.inmo.krontab.internal.createKronScheduler
*/
fun build(): KronScheduler = offset ?.let {
createKronSchedulerWithOffset(seconds, minutes, hours, dayOfMonth, month, year, dayOfWeek, TimezoneOffset(it.minutes))
} ?: createKronScheduler(seconds, minutes, hours, dayOfMonth, month, year, dayOfWeek)
createKronSchedulerWithOffset(
seconds,
minutes,
hours,
dayOfMonth,
month,
year,
dayOfWeek,
TimezoneOffset(it.minutes),
milliseconds ?: millisecondsArrayDefault
)
} ?: createKronScheduler(seconds, minutes, hours, dayOfMonth, month, year, dayOfWeek, milliseconds ?: millisecondsArrayDefault)
}

View File

@@ -122,6 +122,7 @@ sealed class TimeBuilder<T : Number> (
internal fun build() = result ?.map(converter)
}
class MillisecondsBuilder : TimeBuilder<Short>(millisecondsRange, intToShortConverter)
class SecondsBuilder : TimeBuilder<Byte>(secondsRange, intToByteConverter)
class MinutesBuilder : TimeBuilder<Byte>(minutesRange, intToByteConverter)
class HoursBuilder : TimeBuilder<Byte>(hoursRange, intToByteConverter)

View File

@@ -8,7 +8,7 @@ import dev.inmo.krontab.KronScheduler
* @param daysOfWeek 0-6
* @param years any int
* @param months 0-11
* @param daysOfMonth 0-31
* @param daysOfMonth 0-30
* @param hours 0-23
* @param minutes 0-59
* @param seconds 0-59
@@ -20,7 +20,8 @@ internal data class CronDateTime(
val daysOfMonth: Array<Byte>? = null,
val hours: Array<Byte>? = null,
val minutes: Array<Byte>? = null,
val seconds: Array<Byte>? = null
val seconds: Array<Byte>? = null,
val milliseconds: Array<Short>? = millisecondsArrayDefault
) {
init {
check(daysOfWeek ?.all { it in dayOfWeekRange } ?: true)
@@ -30,12 +31,13 @@ internal data class CronDateTime(
check(hours?.all { it in hoursRange } ?: true)
check(minutes?.all { it in minutesRange } ?: true)
check(seconds?.all { it in secondsRange } ?: true)
check(milliseconds?.all { it in millisecondsRange } ?: true)
}
internal val calculators = listOf(
years ?.let { NearDateTimeCalculatorYears(it) },
daysOfWeek ?.let { NearDateTimeCalculatorWeekDays(it) },
NearDateTimeCalculatorMillis(arrayOf(0)),
milliseconds ?.let { NearDateTimeCalculatorMillis(it) },
seconds ?.let { NearDateTimeCalculatorSeconds(it) },
minutes ?.let { NearDateTimeCalculatorMinutes(it) },
hours ?.let { NearDateTimeCalculatorHours(it) },
@@ -65,9 +67,10 @@ internal fun createCronDateTime(
dayOfMonth: Array<Byte>? = null,
month: Array<Byte>? = null,
years: Array<Int>? = null,
weekDays: Array<Byte>? = null
weekDays: Array<Byte>? = null,
milliseconds: Array<Short>? = millisecondsArrayDefault
): 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,
month: Array<Byte>? = null,
years: Array<Int>? = null,
weekDays: Array<Byte>? = null
): KronScheduler = CronDateTimeScheduler(createCronDateTime(seconds, minutes, hours, dayOfMonth, month, years, weekDays))
weekDays: Array<Byte>? = null,
milliseconds: Array<Short>? = millisecondsArrayDefault
): KronScheduler = CronDateTimeScheduler(
createCronDateTime(
seconds,
minutes,
hours,
dayOfMonth,
month,
years,
weekDays,
milliseconds
)
)
/**
* @return [KronScheduler] (in fact [CronDateTimeScheduler]) based on incoming data
*/
@@ -93,8 +108,21 @@ internal fun createKronSchedulerWithOffset(
month: Array<Byte>? = null,
years: Array<Int>? = null,
weekDays: Array<Byte>? = null,
offset: TimezoneOffset
): KronScheduler = CronDateTimeSchedulerTz(createCronDateTime(seconds, minutes, hours, dayOfMonth, month, years, weekDays), offset)
offset: TimezoneOffset,
milliseconds: Array<Short>? = millisecondsArrayDefault
): KronScheduler = CronDateTimeSchedulerTz(
createCronDateTime(
seconds,
minutes,
hours,
dayOfMonth,
month,
years,
weekDays,
milliseconds
),
offset
)
internal fun List<CronDateTime>.merge() = CronDateTime(
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.minutes ?.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() },
)

View File

@@ -7,6 +7,7 @@ import dev.inmo.krontab.KronScheduler
* Cron-oriented realisation of [KronScheduler]
*
* @see dev.inmo.krontab.AnyTimeScheduler
* @see dev.inmo.krontab.EveryMillisecondScheduler
* @see dev.inmo.krontab.EverySecondScheduler
* @see dev.inmo.krontab.EveryMinuteScheduler
* @see dev.inmo.krontab.EveryHourScheduler

View File

@@ -1,5 +1,6 @@
package dev.inmo.krontab.internal
import com.soywiz.klock.DateTime
import com.soywiz.klock.DateTimeTz
import com.soywiz.klock.TimezoneOffset
import dev.inmo.krontab.KronScheduler
@@ -18,6 +19,10 @@ internal data class CronDateTimeSchedulerTz internal constructor(
val dateTimeWithActualOffset = relatively.toOffset(offset).local
return cronDateTime.toNearDateTime(dateTimeWithActualOffset) ?.toOffsetUnadjusted(offset) ?.toOffset(relatively.offset)
}
override suspend fun next(relatively: DateTime): DateTime? {
return next(relatively.toOffset(offset)) ?.utc
}
}
internal fun mergeCronDateTimeSchedulers(

View File

@@ -0,0 +1,4 @@
package dev.inmo.krontab.internal
internal const val millisecondsDefault: Short = 0
internal val millisecondsArrayDefault: Array<Short> = arrayOf(millisecondsDefault)

View File

@@ -101,13 +101,14 @@ internal fun NearDateTimeCalculatorDays(
times: Array<Byte>
) = CommonNearDateTimeCalculator(
times,
{ it.dayOfMonth.toByte() },
{ (it.dayOfMonth - 1).toByte() }, // index1, so, decrease
{ dateTime, newOne ->
(if (newOne < dateTime.dayOfMonth) {
val dateTime = (if (newOne < dateTime.dayOfMonth) {
dateTime.plus(1.months)
} else {
dateTime
}).copy(
})
dateTime.copy(
dayOfMonth = min(dateTime.month.days(dateTime.year), newOne.toInt() + 1), // index1
hour = 0,
minute = 0,
@@ -121,7 +122,7 @@ internal fun NearDateTimeCalculatorMonths(
times: Array<Byte>
) = CommonNearDateTimeCalculator(
times,
{ it.dayOfMonth.toByte() },
{ it.month0.toByte() },
{ dateTime, newOne ->
(if (newOne < dateTime.month0) {
dateTime.plus(1.years)

View File

@@ -3,6 +3,7 @@ package dev.inmo.krontab.internal
typealias Converter<T> = (Int) -> T
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 }
private fun <T> createSimpleScheduler(from: String, dataRange: IntRange, dataConverter: Converter<T>): List<T>? {
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 parseMinutes(from: String) = createSimpleScheduler(from, minutesRange, 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(
whereToPut: MutableList<CronDateTime>,

View File

@@ -7,3 +7,4 @@ internal val dayOfMonthRange = 0 .. 30
internal val hoursRange = 0 .. 23
internal val minutesRange = 0 .. 59
internal val secondsRange = minutesRange
internal val millisecondsRange = 0 .. 999

View File

@@ -6,6 +6,7 @@ import dev.inmo.krontab.*
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.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
@@ -25,11 +26,11 @@ fun KronScheduler.asTzFlow(): Flow<DateTimeTz> = channelFlow {
* This method is a map for [asTzFlow] and will works the same but return flow with [DateTime]s
*
* @see channelFlow
* @see KronScheduler.doInfinityLocal
* @see KronScheduler.doInfinity
*/
@FlowPreview
fun KronScheduler.asFlow(): Flow<DateTime> = channelFlow {
doInfinityLocal {
doInfinity {
send(it)
}
}

View File

@@ -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 }

View File

@@ -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 }

View File

@@ -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()

View File

@@ -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()

View File

@@ -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 CheckMonthsAndDaysCorrectWork {
@Test
fun checkMonthsAndDaysCorrectWork() {
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)
)
}
}
}
}

View File

@@ -6,8 +6,8 @@ import dev.inmo.krontab.buildSchedule
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.takeWhile
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.math.floor
import kotlin.test.*
@ExperimentalCoroutinesApi
@FlowPreview
@@ -29,6 +29,23 @@ class StringParseTest {
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
fun testThatFlowIsCorrectlyWorkEverySecondWithMuchOfEmittersBuiltOnString() {
@@ -74,6 +91,29 @@ class StringParseTest {
flow.takeWhile { ranges.isNotEmpty() }.collect {
ranges.remove(it.seconds)
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)
}