Compare commits
74 Commits
Author | SHA1 | Date |
---|---|---|
InsanusMokrassar | f90d8d03d9 | |
InsanusMokrassar | 36671cb379 | |
InsanusMokrassar | 68be768763 | |
InsanusMokrassar | 9546eb5aec | |
InsanusMokrassar | 2efd7e6157 | |
InsanusMokrassar | 6845537afd | |
InsanusMokrassar | af28fce6f5 | |
InsanusMokrassar | 237b42c2d3 | |
InsanusMokrassar | 49f852f27e | |
renovate[bot] | 470dc92f54 | |
InsanusMokrassar | b5dcdc185f | |
InsanusMokrassar | 8df9f9c086 | |
InsanusMokrassar | 484f46223f | |
InsanusMokrassar | 1ce654fa06 | |
InsanusMokrassar | 6da04f54da | |
InsanusMokrassar | e1d716688a | |
InsanusMokrassar | e247de9e24 | |
InsanusMokrassar | a153bc7996 | |
InsanusMokrassar | 9753cda961 | |
InsanusMokrassar | e8ef6e6935 | |
InsanusMokrassar | b41bf0ea07 | |
InsanusMokrassar | 09d811e2c4 | |
InsanusMokrassar | 3faadefced | |
InsanusMokrassar | f3883a8678 | |
InsanusMokrassar | 5ff02a2a9d | |
InsanusMokrassar | f56215ee10 | |
InsanusMokrassar | e66acb34de | |
InsanusMokrassar | 78ac446311 | |
InsanusMokrassar | 697b4e81b8 | |
InsanusMokrassar | d1288de032 | |
InsanusMokrassar | eb867e7366 | |
InsanusMokrassar | 4aa10e00cf | |
InsanusMokrassar | 170d443517 | |
InsanusMokrassar | d1aab7ccd6 | |
InsanusMokrassar | 58d758f141 | |
InsanusMokrassar | 71bd3f0eb4 | |
InsanusMokrassar | bd2a852b16 | |
InsanusMokrassar | 8e844b5875 | |
InsanusMokrassar | e0f7dddf42 | |
InsanusMokrassar | d64acc9806 | |
InsanusMokrassar | 58375452c7 | |
InsanusMokrassar | cbfbdc1b33 | |
InsanusMokrassar | 715d414f51 | |
InsanusMokrassar | 2ecd8c4292 | |
InsanusMokrassar | 1be8d947f7 | |
InsanusMokrassar | f66c1c2477 | |
InsanusMokrassar | 69cf7afd4e | |
InsanusMokrassar | 92df91edd3 | |
InsanusMokrassar | f7a388f438 | |
InsanusMokrassar | 9a10c7eb87 | |
InsanusMokrassar | d67be582af | |
InsanusMokrassar | 171bb687ea | |
InsanusMokrassar | 7807d10121 | |
InsanusMokrassar | e5bbea84d9 | |
InsanusMokrassar | a01a18a6d1 | |
InsanusMokrassar | 132986d275 | |
InsanusMokrassar | 04118902e8 | |
InsanusMokrassar | 96857aa7bc | |
InsanusMokrassar | f8b677406f | |
InsanusMokrassar | 53f34f0a27 | |
InsanusMokrassar | 989780243a | |
InsanusMokrassar | 7b5417ccc5 | |
InsanusMokrassar | 2004a7dd05 | |
InsanusMokrassar | 7c4217bda6 | |
InsanusMokrassar | 3d6fee7257 | |
InsanusMokrassar | 6cec25eca0 | |
InsanusMokrassar | a0972eaff9 | |
InsanusMokrassar | cc75501b04 | |
InsanusMokrassar | 89e500ff33 | |
InsanusMokrassar | a61cd61602 | |
renovate[bot] | 5fdb2ea049 | |
InsanusMokrassar | 68ed562b19 | |
InsanusMokrassar | 87b5dfe1aa | |
InsanusMokrassar | 6a6bfe0552 |
|
@ -10,10 +10,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Fix android 32.0.0 dx
|
||||
continue-on-error: true
|
||||
run: cd /usr/local/lib/android/sdk/build-tools/32.0.0/ && cp d8 dx && cd lib && cp d8.jar dx.jar
|
||||
java-version: 17
|
||||
- name: Build
|
||||
run: ./gradlew dokkaHtml
|
||||
- name: Publish KDocs
|
||||
|
|
|
@ -7,7 +7,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
java-version: 17
|
||||
- name: Update version
|
||||
run: |
|
||||
branch="`echo "${{ github.ref }}" | grep -o "[^/]*$"`"
|
||||
|
|
110
CHANGELOG.md
110
CHANGELOG.md
|
@ -1,5 +1,115 @@
|
|||
# Changelog
|
||||
|
||||
## 2.3.0
|
||||
|
||||
* `doWhile` now will guarantee that it will not call `doOnce` more than once for time
|
||||
|
||||
## 2.2.9
|
||||
|
||||
* `Version`:
|
||||
* `Kotlin`: `1.9.23`
|
||||
* `Serialization`: `1.6.3`
|
||||
* `Klock`: `5.3.2`
|
||||
* Fixes in build-in schedulers
|
||||
|
||||
## 2.2.8
|
||||
|
||||
* `Version`:
|
||||
* `Coroutines`: `1.8.0`
|
||||
|
||||
## 2.2.7
|
||||
|
||||
* `Version`:
|
||||
* `Klock`: `5.3.1`
|
||||
* `AndroidXWork`: `2.9.0`
|
||||
|
||||
## 2.2.6
|
||||
|
||||
**Since this version klock depdendency replaced with `com.soywiz.korge:korlibs-time`**
|
||||
|
||||
* `Version`:
|
||||
* `Klock`: `5.3.0`
|
||||
|
||||
## 2.2.5
|
||||
|
||||
* `Versions`
|
||||
* `Kotlin`: `1.9.22`
|
||||
* `Serialization`: `1.6.2`
|
||||
|
||||
## 2.2.4
|
||||
|
||||
* `Versions`
|
||||
* `Kotlin`: `1.9.21`
|
||||
* `Serialization`: `1.6.1`
|
||||
|
||||
## 2.2.3
|
||||
|
||||
**THIS UPDATE CONTAINS UPGRADE OF USED JDK UP TO 17**
|
||||
|
||||
* Versions
|
||||
* `Kotlin`: `1.9.20`
|
||||
|
||||
## 2.2.2
|
||||
|
||||
* Versions
|
||||
* `Kotlin`: `1.9.20-RC`
|
||||
* `Android` (min/target): `34`
|
||||
|
||||
## 2.2.1
|
||||
|
||||
* Potential fix of [#65](https://github.com/InsanusMokrassar/krontab/issues/65)
|
||||
* Versions
|
||||
* `Kotlin`: `1.9.20-Beta`
|
||||
* `Klock`: `4.0.10`
|
||||
* `Serialization`: `1.6.0`
|
||||
|
||||
## 2.2.0
|
||||
|
||||
* Versions
|
||||
* `Kotlin`: `1.9.0`
|
||||
* `Coroutines`: `1.7.3`
|
||||
* `Klock`: `4.0.9`
|
||||
|
||||
## 2.1.2
|
||||
|
||||
* Versions
|
||||
* `Coroutines`: `1.7.2`
|
||||
* All callbacks for standard extensions like `doInfinity` now fully inline
|
||||
|
||||
## 2.1.1
|
||||
|
||||
* `asFlowWithoutDelays` and `asTzFlowWithoutDelays` will have nullable `since` parameters with default to `null`
|
||||
to avoid any inconsistency of `Flow` idiom.
|
||||
<details>
|
||||
<summary>About the reason of changes</summary>
|
||||
Cold flows should not contain some state by default. So, it was not right to save some `DateTime`/`DateTimeTz`
|
||||
by default. Now it will not use some external state unless developers will set it manually
|
||||
</details>
|
||||
|
||||
## 2.1.0
|
||||
|
||||
* Versions
|
||||
* `Kotlin`: `1.8.22`
|
||||
* `Klock`: `4.0.3`
|
||||
* New value class `KrontabConfig`. It is preferable way to create `KronScheduler` instead of
|
||||
`KrontabTemplate` since this update
|
||||
* You may configure krontab with builders using simple `KronScheduler` invoke extension
|
||||
* New useful extensions like `KronScheduler.daily`
|
||||
* `KrontabTemplateWrapper` is obsolete in favor to `KrontabConfig`
|
||||
|
||||
## 2.0.0
|
||||
|
||||
* Versions
|
||||
* `Kotlin`: `1.8.21`
|
||||
* `Klock`: `4.0.1`
|
||||
* Support of `mingwx64` platform
|
||||
|
||||
## 1.0.0
|
||||
|
||||
* Versions
|
||||
* `Kotlin`: `1.8.20`
|
||||
* `AndroidXWork`: `2.8.1`
|
||||
|
||||
## 0.10.0
|
||||
|
||||
* New extensions for `KronScheduler`:
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
![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)
|
||||
![Linux x64](https://img.shields.io/badge/Linux%20x64-white?style=for-the-badge&logo=linux&logoColor=black)
|
||||
|
||||
[![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)
|
||||
[![Tutorials](https://img.shields.io/badge/Tutorials-0288D1?style=for-the-badge&logo=mkdocs&logoColor=white)](https://docs.inmo.dev/krontab/index.html)
|
||||
|
||||
Library was created to give oppotunity to launch some things from time to time according to some schedule in
|
||||
runtime of applications.
|
||||
|
|
24
build.gradle
24
build.gradle
|
@ -8,14 +8,16 @@ buildscript {
|
|||
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$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:7.3.1'
|
||||
classpath "com.android.tools.build:gradle:$android_gradle_version"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
|
||||
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
|
||||
id "org.jetbrains.dokka" version "$dokka_version"
|
||||
}
|
||||
|
||||
|
@ -58,6 +60,8 @@ kotlin {
|
|||
publishAllLibraryVariants()
|
||||
}
|
||||
linuxX64()
|
||||
mingwX64()
|
||||
linuxArm64()
|
||||
|
||||
|
||||
sourceSets {
|
||||
|
@ -65,8 +69,9 @@ kotlin {
|
|||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlin_serialization_version"
|
||||
|
||||
api "com.soywiz.korlibs.klock:klock:$klockVersion"
|
||||
api "com.soywiz.korge:korlibs-time:$klockVersion"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +98,7 @@ kotlin {
|
|||
implementation kotlin('test-js')
|
||||
}
|
||||
}
|
||||
androidTest {
|
||||
androidUnitTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
}
|
||||
|
@ -104,8 +109,9 @@ kotlin {
|
|||
apply plugin: 'com.getkeepsafe.dexcount'
|
||||
|
||||
android {
|
||||
compileSdkVersion "$android_compileSdkVersion".toInteger()
|
||||
buildToolsVersion "$android_buildToolsVersion"
|
||||
compileSdk "$android_compileSdkVersion".toInteger()
|
||||
buildToolsVersion = "$android_buildToolsVersion"
|
||||
namespace "${group}.${project.name}"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion "$android_minSdkVersion".toInteger()
|
||||
|
@ -123,8 +129,8 @@ android {
|
|||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
@ -136,6 +142,6 @@ android {
|
|||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
|
|
@ -18,13 +18,13 @@ if (new File(projectDir, "secret.gradle").exists()) {
|
|||
githubRelease {
|
||||
token "${project.property('GITHUB_RELEASE_TOKEN')}"
|
||||
|
||||
owner "InsanusMokrassar"
|
||||
repo "${rootProject.name}"
|
||||
owner = "InsanusMokrassar"
|
||||
repo = "${rootProject.name}"
|
||||
|
||||
tagName "v${project.version}"
|
||||
releaseName "${project.version}"
|
||||
targetCommitish "${project.version}"
|
||||
tagName = "v${project.version}"
|
||||
releaseName = "${project.version}"
|
||||
targetCommitish = "${project.version}"
|
||||
|
||||
body getCurrentVersionChangelog("${project.version}")
|
||||
body = getCurrentVersionChangelog("${project.version}")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,30 +9,32 @@ android.useAndroidX=true
|
|||
android.enableJetifier=false
|
||||
|
||||
|
||||
kotlin_version=1.8.10
|
||||
kotlin_coroutines_version=1.6.4
|
||||
kotlin_version=1.9.23
|
||||
kotlin_coroutines_version=1.8.0
|
||||
kotlin_serialization_version=1.6.3
|
||||
|
||||
dokka_version=1.8.10
|
||||
dokka_version=1.9.20
|
||||
|
||||
klockVersion=3.4.0
|
||||
klockVersion=5.4.0
|
||||
|
||||
## Github reease
|
||||
|
||||
github_release_plugin_version=2.4.1
|
||||
github_release_plugin_version=2.5.2
|
||||
|
||||
## Android
|
||||
|
||||
android_gradle_version=8.1.4
|
||||
android_minSdkVersion=21
|
||||
android_compileSdkVersion=33
|
||||
android_buildToolsVersion=33.0.1
|
||||
dexcount_version=3.1.0
|
||||
android_compileSdkVersion=34
|
||||
android_buildToolsVersion=34.0.0
|
||||
dexcount_version=4.0.0
|
||||
junit_version=4.12
|
||||
test_ext_junit_version=1.1.3
|
||||
espresso_core=3.4.0
|
||||
|
||||
androidx_work_version=2.8.0
|
||||
androidx_work_version=2.9.0
|
||||
|
||||
## Common
|
||||
|
||||
version=0.10.0
|
||||
android_code_version=24
|
||||
version=2.3.0
|
||||
android_code_version=40
|
||||
|
|
|
@ -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.6.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
apply plugin: 'maven-publish'
|
||||
|
||||
task javadocsJar(type: Jar) {
|
||||
classifier = 'javadoc'
|
||||
archiveClassifier = 'javadoc'
|
||||
}
|
||||
|
||||
publishing {
|
||||
|
@ -50,18 +50,14 @@ publishing {
|
|||
|
||||
}
|
||||
}
|
||||
if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
|
||||
if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "Gitea"
|
||||
url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
|
||||
name = "InmoNexus"
|
||||
url = uri("https://nexus.inmo.dev/repository/maven-releases/")
|
||||
|
||||
credentials(HttpHeaderCredentials) {
|
||||
name = "Authorization"
|
||||
value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
|
||||
}
|
||||
|
||||
authentication {
|
||||
header(HttpHeaderAuthentication)
|
||||
credentials {
|
||||
username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
|
||||
password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,4 +92,27 @@ if (project.hasProperty("signing.gnupg.keyName")) {
|
|||
dependsOn(it)
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround to make android sign operations depend on signing tasks
|
||||
project.getTasks().withType(AbstractPublishToMaven.class).configureEach {
|
||||
def signingTasks = project.getTasks().withType(Sign.class)
|
||||
mustRunAfter(signingTasks)
|
||||
}
|
||||
// Workaround to make test tasks use sign
|
||||
project.getTasks().withType(Sign.class).configureEach { signTask ->
|
||||
def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name)
|
||||
def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign
|
||||
// These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets
|
||||
|
||||
// Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
|
||||
def debugTestTask = tasks.findByName("linkDebugTest$pubName")
|
||||
if (debugTestTask != null) {
|
||||
signTask.mustRunAfter(debugTestTask)
|
||||
}
|
||||
// Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
|
||||
def testTask = tasks.findByName("compileTestKotlin$pubName")
|
||||
if (testTask != null) {
|
||||
signTask.mustRunAfter(testTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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","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"}}}
|
||||
{"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":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
|
@ -2,7 +2,8 @@ package dev.inmo.krontab
|
|||
|
||||
import android.content.Context
|
||||
import androidx.work.*
|
||||
import com.soywiz.klock.DateTime
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.millisecondsLong
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
/**
|
|
@ -1,7 +1,8 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.DateTimeTz
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.DateTimeTz
|
||||
import korlibs.time.millisecondsLong
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
@ -14,7 +15,7 @@ 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.doOnce(noinline block: suspend (DateTime) -> T): T {
|
||||
suspend inline fun <T> KronScheduler.doOnce(block: (DateTime) -> T): T {
|
||||
val time = nextOrNow().also {
|
||||
delay((it - DateTime.now()).millisecondsLong)
|
||||
}
|
||||
|
@ -29,7 +30,7 @@ suspend inline fun <T> KronScheduler.doOnce(noinline block: suspend (DateTime) -
|
|||
* 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)
|
||||
suspend inline fun <T> KronScheduler.doOnceLocal(block: (DateTime) -> T): T = doOnce(block)
|
||||
|
||||
/**
|
||||
* Execute [block] once at the [KronScheduler.next] time and return result of [block] calculation.
|
||||
|
@ -53,7 +54,7 @@ suspend inline fun <T> KronScheduler.doOnceTz(noinline block: suspend (DateTimeT
|
|||
*/
|
||||
suspend inline fun <T> doOnce(
|
||||
scheduleConfig: String,
|
||||
noinline block: suspend (DateTime) -> T
|
||||
block: (DateTime) -> T
|
||||
) = buildSchedule(scheduleConfig).doOnce(block)
|
||||
|
||||
/**
|
||||
|
@ -69,24 +70,42 @@ suspend inline fun <T> doOnceTz(
|
|||
/**
|
||||
* Will execute [block] while it will return true as a result of its calculation
|
||||
*/
|
||||
suspend inline fun KronScheduler.doWhile(noinline block: suspend (DateTime) -> Boolean) {
|
||||
suspend inline fun KronScheduler.doWhile(block: (DateTime) -> Boolean) {
|
||||
var latest: DateTime? = null
|
||||
do {
|
||||
delay(1L)
|
||||
} while (doOnce(block))
|
||||
val result = doOnce {
|
||||
if (latest != it) {
|
||||
latest = it
|
||||
block(it)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
} while (result == null || result)
|
||||
}
|
||||
/**
|
||||
* 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)
|
||||
suspend inline fun KronScheduler.doWhileLocal(block: (DateTime) -> Boolean) = doWhile(block)
|
||||
|
||||
/**
|
||||
* Will execute [block] while it will return true as a result of its calculation
|
||||
*/
|
||||
suspend inline fun KronScheduler.doWhileTz(noinline block: suspend (DateTimeTz) -> Boolean) {
|
||||
var latest: DateTimeTz? = null
|
||||
do {
|
||||
delay(1L)
|
||||
} while (doOnceTz(block))
|
||||
val result = doOnceTz {
|
||||
if (latest != it) {
|
||||
latest = it
|
||||
block(it)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
} while (result == null || result)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,7 +115,7 @@ suspend inline fun KronScheduler.doWhileTz(noinline block: suspend (DateTimeTz)
|
|||
*/
|
||||
suspend inline fun doWhile(
|
||||
scheduleConfig: String,
|
||||
noinline block: suspend (DateTime) -> Boolean
|
||||
block: (DateTime) -> Boolean
|
||||
) = buildSchedule(scheduleConfig).doWhile(block)
|
||||
|
||||
/**
|
||||
|
@ -107,7 +126,7 @@ suspend inline fun doWhile(
|
|||
@Deprecated("Replaceable", ReplaceWith("doWhile", "dev.inmo.krontab.doWhile"))
|
||||
suspend inline fun doWhileLocal(
|
||||
scheduleConfig: String,
|
||||
noinline block: suspend (DateTime) -> Boolean
|
||||
block: (DateTime) -> Boolean
|
||||
) = doWhile(scheduleConfig, block)
|
||||
|
||||
/**
|
||||
|
@ -124,7 +143,7 @@ suspend inline fun doWhileTz(
|
|||
/**
|
||||
* Will execute [block] without any checking of result
|
||||
*/
|
||||
suspend inline fun KronScheduler.doInfinity(noinline block: suspend (DateTime) -> Unit) = doWhile {
|
||||
suspend inline fun KronScheduler.doInfinity(block: (DateTime) -> Unit) = doWhile {
|
||||
block(it)
|
||||
coroutineContext.isActive
|
||||
}
|
||||
|
@ -132,7 +151,7 @@ suspend inline fun KronScheduler.doInfinity(noinline block: suspend (DateTime) -
|
|||
* 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)
|
||||
suspend inline fun KronScheduler.doInfinityLocal(block: (DateTime) -> Unit) = doInfinity(block)
|
||||
|
||||
/**
|
||||
* Will execute [block] without any checking of result
|
||||
|
@ -149,7 +168,7 @@ suspend inline fun KronScheduler.doInfinityTz(noinline block: suspend (DateTimeT
|
|||
*/
|
||||
suspend inline fun doInfinity(
|
||||
scheduleConfig: String,
|
||||
noinline block: suspend (DateTime) -> Unit
|
||||
block: (DateTime) -> Unit
|
||||
) = buildSchedule(scheduleConfig).doInfinity(block)
|
||||
|
||||
/**
|
||||
|
@ -160,7 +179,7 @@ suspend inline fun doInfinity(
|
|||
@Deprecated("Replaceable", ReplaceWith("doInfinity", "dev.inmo.krontab.doInfinity"))
|
||||
suspend inline fun doInfinityLocal(
|
||||
scheduleConfig: String,
|
||||
noinline block: suspend (DateTime) -> Unit
|
||||
block: (DateTime) -> Unit
|
||||
) = doInfinity(scheduleConfig, block)
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import korlibs.time.DateTime
|
||||
|
||||
/**
|
||||
* This interface was created for abstraction of [next] operation. Currently, there is only
|
||||
|
@ -18,6 +18,8 @@ interface KronScheduler {
|
|||
* @see dev.inmo.krontab.internal.CronDateTimeScheduler.next
|
||||
*/
|
||||
suspend fun next(relatively: DateTime = DateTime.now()): DateTime?
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
suspend fun KronScheduler.nextOrRelative(relatively: DateTime = DateTime.now()): DateTime = next(relatively) ?: getAnyNext(relatively)
|
|
@ -1,7 +1,7 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.DateTimeTz
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.DateTimeTz
|
||||
|
||||
/**
|
||||
* This interface extending [KronScheduler] to use [DateTimeTz] with taking into account offset of incoming time for
|
|
@ -0,0 +1,165 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import dev.inmo.krontab.internal.CronDateTimeScheduler
|
||||
import dev.inmo.krontab.internal.CronDateTimeSchedulerTz
|
||||
import dev.inmo.krontab.internal.createKronScheduler
|
||||
import dev.inmo.krontab.internal.createKronSchedulerWithOffset
|
||||
import dev.inmo.krontab.internal.millisecondsArrayDefault
|
||||
import dev.inmo.krontab.internal.parseDaysOfMonth
|
||||
import dev.inmo.krontab.internal.parseHours
|
||||
import dev.inmo.krontab.internal.parseMilliseconds
|
||||
import dev.inmo.krontab.internal.parseMinutes
|
||||
import dev.inmo.krontab.internal.parseMonths
|
||||
import dev.inmo.krontab.internal.parseOffset
|
||||
import dev.inmo.krontab.internal.parseSeconds
|
||||
import dev.inmo.krontab.internal.parseWeekDay
|
||||
import dev.inmo.krontab.internal.parseYears
|
||||
import dev.inmo.krontab.utils.Minutes
|
||||
import korlibs.time.TimezoneOffset
|
||||
import korlibs.time.minutes
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlin.jvm.JvmInline
|
||||
|
||||
/**
|
||||
* This value class contains [KrontabTemplate]
|
||||
*
|
||||
* * **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:
|
||||
*
|
||||
* `{number}[,{number},...]` or `*`
|
||||
*
|
||||
* and {number} here is one of
|
||||
*
|
||||
* * {int}-{int}
|
||||
* * {int}/{int}
|
||||
* * */{int}
|
||||
* * {int}
|
||||
* * F
|
||||
* * L
|
||||
*
|
||||
* Week days must be marked with `w` at the end, and starts with 0 which means Sunday. For example, 0w == Sunday. With
|
||||
* weeks you can use syntax like with any number like seconds, for example: 0-2w means Sunday-Tuesday
|
||||
*
|
||||
* Additional info about ranges can be found in follow accordance:
|
||||
*
|
||||
* * Seconds ranges can be found in [secondsRange]
|
||||
* * Minutes ranges can be found in [minutesRange]
|
||||
* * Hours ranges can be found in [hoursRange]
|
||||
* * Days of month ranges can be found in [dayOfMonthRange]
|
||||
* * 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
|
||||
* * "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
|
||||
*
|
||||
* @see dev.inmo.krontab.internal.createKronScheduler
|
||||
*/
|
||||
@Serializable
|
||||
@JvmInline
|
||||
value class KrontabConfig(
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val template: KrontabTemplate
|
||||
) {
|
||||
/**
|
||||
* Creates __new__ [KronScheduler] based on a [template]
|
||||
*
|
||||
* @return In case when offset parameter is absent in [template] will be used [createSimpleScheduler] method and
|
||||
* returned [CronDateTimeScheduler]. In case when offset parameter there is in [template] [KrontabTemplate] will be used
|
||||
* [createKronSchedulerWithOffset] and returned [CronDateTimeSchedulerTz]
|
||||
*/
|
||||
fun scheduler(): KronScheduler {
|
||||
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) = template.split(" ").also {
|
||||
listOfNotNull(
|
||||
it.getOrNull(5),
|
||||
it.getOrNull(6),
|
||||
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 || millisecondsFromString != null -> return@forEach
|
||||
yearParsed == null -> {
|
||||
yearParsed = parseYears(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val secondsParsed = parseSeconds(secondsSource)
|
||||
val minutesParsed = parseMinutes(minutesSource)
|
||||
val hoursParsed = parseHours(hoursSource)
|
||||
val dayOfMonthParsed = parseDaysOfMonth(dayOfMonthSource)
|
||||
val monthParsed = parseMonths(monthSource)
|
||||
|
||||
return offsetParsed ?.let { offset ->
|
||||
createKronSchedulerWithOffset(
|
||||
secondsParsed,
|
||||
minutesParsed,
|
||||
hoursParsed,
|
||||
dayOfMonthParsed,
|
||||
monthParsed,
|
||||
yearParsed,
|
||||
dayOfWeekParsed,
|
||||
TimezoneOffset(offset.minutes),
|
||||
millisecondsParsed ?: millisecondsArrayDefault
|
||||
)
|
||||
} ?: createKronScheduler(
|
||||
secondsParsed,
|
||||
minutesParsed,
|
||||
hoursParsed,
|
||||
dayOfMonthParsed,
|
||||
monthParsed,
|
||||
yearParsed,
|
||||
dayOfWeekParsed,
|
||||
millisecondsParsed ?: millisecondsArrayDefault
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates base [KronScheduler] using [scheduler] function. In case when returned [KronScheduler] is [KronSchedulerTz],
|
||||
* it will be returned as is. Otherwise, will be created new [CronDateTimeSchedulerTz] with [defaultOffset] as
|
||||
* offset
|
||||
*/
|
||||
fun scheduler(defaultOffset: Minutes): KronSchedulerTz {
|
||||
val scheduler = scheduler()
|
||||
return if (scheduler is KronSchedulerTz) {
|
||||
scheduler
|
||||
} else {
|
||||
CronDateTimeSchedulerTz(
|
||||
(scheduler as CronDateTimeScheduler).cronDateTime,
|
||||
TimezoneOffset(defaultOffset.minutes)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,10 @@ package dev.inmo.krontab
|
|||
* [dev.inmo.krontab.internal.CronDateTimeScheduler] due to the fact that [toKronScheduler] will return it under the
|
||||
* hood
|
||||
*/
|
||||
@Deprecated(
|
||||
"It is useless wrapper for KrontabTemplate. Use KrontabConfig instead",
|
||||
ReplaceWith("KrontabConfig(template)", "dev.inmo.krontab.KrontabConfig")
|
||||
)
|
||||
data class KrontabTemplateWrapper(
|
||||
val template: KrontabTemplate
|
||||
) : KronScheduler by template.toKronScheduler()
|
||||
|
@ -15,4 +19,8 @@ data class KrontabTemplateWrapper(
|
|||
* @see [toKronScheduler]
|
||||
* @see [KrontabTemplateWrapper]
|
||||
*/
|
||||
@Deprecated(
|
||||
"Will be removed in near major update with KrontabTemplateWrapper",
|
||||
ReplaceWith("this.krontabConfig", "dev.inmo.krontab.krontabConfig")
|
||||
)
|
||||
fun KrontabTemplate.wrapAsKronScheduler() = KrontabTemplateWrapper(this)
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import korlibs.time.DateTime
|
||||
|
||||
class LambdaKronScheduler(
|
||||
private val onNext: suspend (DateTime) -> DateTime?
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import com.soywiz.klock.DateTimeTz
|
||||
import korlibs.time.DateTimeTz
|
||||
|
||||
class LambdaKronSchedulerTz(
|
||||
private val onNext: suspend (DateTimeTz) -> DateTimeTz?
|
|
@ -0,0 +1,133 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import korlibs.time.DateTime
|
||||
import dev.inmo.krontab.builder.buildSchedule
|
||||
import dev.inmo.krontab.internal.*
|
||||
|
||||
internal val anyCronDateTime by lazy {
|
||||
CronDateTime()
|
||||
}
|
||||
internal fun getAnyNext(relatively: DateTime) = anyCronDateTime.toNearDateTime(relatively)!!
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [korlibs.time.DateTime.now]
|
||||
*/
|
||||
val AnyTimeScheduler: KronScheduler by lazy {
|
||||
CronDateTimeScheduler(anyCronDateTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [korlibs.time.DateTime.now] + one millisecond
|
||||
*/
|
||||
val EveryMillisecondScheduler: KronScheduler by lazy {
|
||||
buildSchedule { milliseconds { 0 every 1 } }
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [korlibs.time.DateTime.now] + one second
|
||||
*/
|
||||
val EverySecondScheduler: KronScheduler by lazy {
|
||||
buildSchedule { seconds { 0 every 1 } }
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [korlibs.time.DateTime.now] + one minute
|
||||
*/
|
||||
val EveryMinuteScheduler: KronScheduler by lazy {
|
||||
buildSchedule {
|
||||
seconds { at(0) }
|
||||
minutes { 0 every 1 }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [korlibs.time.DateTime.now] + one hour
|
||||
*/
|
||||
val EveryHourScheduler: KronScheduler by lazy {
|
||||
buildSchedule {
|
||||
seconds { at(0) }
|
||||
minutes { at(0) }
|
||||
hours { 0 every 1 }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [korlibs.time.DateTime.now] + one day
|
||||
*/
|
||||
val EveryDayOfMonthScheduler: KronScheduler by lazy {
|
||||
buildSchedule {
|
||||
seconds { at(0) }
|
||||
minutes { at(0) }
|
||||
hours { at(0) }
|
||||
dayOfMonth { 0 every 1 }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [korlibs.time.DateTime.now] + one month
|
||||
*/
|
||||
val EveryMonthScheduler: KronScheduler by lazy {
|
||||
buildSchedule {
|
||||
seconds { at(0) }
|
||||
minutes { at(0) }
|
||||
hours { at(0) }
|
||||
dayOfMonth { at(0) }
|
||||
months { 0 every 1 }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [korlibs.time.DateTime.now] + one year
|
||||
*/
|
||||
val EveryYearScheduler: KronScheduler by lazy {
|
||||
buildSchedule {
|
||||
seconds { at(0) }
|
||||
minutes { at(0) }
|
||||
hours { at(0) }
|
||||
dayOfMonth { at(0) }
|
||||
months { at(0) }
|
||||
years { 0 every 1 }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for [EveryMillisecondScheduler]
|
||||
*/
|
||||
inline val KronScheduler.Companion.everyMillisecond
|
||||
get() = EveryMillisecondScheduler
|
||||
|
||||
/**
|
||||
* Shortcut for [EverySecondScheduler]
|
||||
*/
|
||||
inline val KronScheduler.Companion.everySecond
|
||||
get() = EverySecondScheduler
|
||||
|
||||
/**
|
||||
* Shortcut for [EveryMinuteScheduler]
|
||||
*/
|
||||
inline val KronScheduler.Companion.everyMinute
|
||||
get() = EveryMinuteScheduler
|
||||
|
||||
/**
|
||||
* Shortcut for [EveryHourScheduler]
|
||||
*/
|
||||
inline val KronScheduler.Companion.hourly
|
||||
get() = EveryHourScheduler
|
||||
|
||||
/**
|
||||
* Shortcut for [EveryDayOfMonthScheduler]
|
||||
*/
|
||||
inline val KronScheduler.Companion.daily
|
||||
get() = EveryDayOfMonthScheduler
|
||||
|
||||
/**
|
||||
* Shortcut for [EveryMonthScheduler]
|
||||
*/
|
||||
inline val KronScheduler.Companion.monthly
|
||||
get() = EveryMonthScheduler
|
||||
|
||||
/**
|
||||
* Shortcut for [EveryYearScheduler]
|
||||
*/
|
||||
inline val KronScheduler.Companion.annually
|
||||
get() = EveryYearScheduler
|
|
@ -1,7 +1,5 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import com.soywiz.klock.TimezoneOffset
|
||||
import com.soywiz.klock.minutes
|
||||
import dev.inmo.krontab.internal.*
|
||||
import dev.inmo.krontab.utils.Minutes
|
||||
|
||||
|
@ -11,6 +9,8 @@ import dev.inmo.krontab.utils.Minutes
|
|||
*/
|
||||
typealias KrontabTemplate = String
|
||||
|
||||
inline fun KrontabTemplate.krontabConfig() = KrontabConfig(this)
|
||||
|
||||
/**
|
||||
* Parse [incoming] string and adapt according to next format: "* * * * *" where order of things:
|
||||
*
|
||||
|
@ -70,80 +70,16 @@ typealias KrontabTemplate = String
|
|||
* [createKronSchedulerWithOffset] and returned [CronDateTimeSchedulerTz]
|
||||
*
|
||||
* @see dev.inmo.krontab.internal.createKronScheduler
|
||||
* @see KrontabConfig.scheduler
|
||||
*/
|
||||
fun createSimpleScheduler(
|
||||
incoming: KrontabTemplate
|
||||
): KronScheduler {
|
||||
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(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 || millisecondsFromString != null -> return@forEach
|
||||
yearParsed == null -> {
|
||||
yearParsed = parseYears(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val secondsParsed = parseSeconds(secondsSource)
|
||||
val minutesParsed = parseMinutes(minutesSource)
|
||||
val hoursParsed = parseHours(hoursSource)
|
||||
val dayOfMonthParsed = parseDaysOfMonth(dayOfMonthSource)
|
||||
val monthParsed = parseMonths(monthSource)
|
||||
|
||||
return offsetParsed ?.let { offset ->
|
||||
createKronSchedulerWithOffset(
|
||||
secondsParsed,
|
||||
minutesParsed,
|
||||
hoursParsed,
|
||||
dayOfMonthParsed,
|
||||
monthParsed,
|
||||
yearParsed,
|
||||
dayOfWeekParsed,
|
||||
TimezoneOffset(offset.minutes),
|
||||
millisecondsParsed ?: millisecondsArrayDefault
|
||||
)
|
||||
} ?: createKronScheduler(
|
||||
secondsParsed,
|
||||
minutesParsed,
|
||||
hoursParsed,
|
||||
dayOfMonthParsed,
|
||||
monthParsed,
|
||||
yearParsed,
|
||||
dayOfWeekParsed,
|
||||
millisecondsParsed ?: millisecondsArrayDefault
|
||||
)
|
||||
}
|
||||
): KronScheduler = KrontabConfig(incoming).scheduler()
|
||||
|
||||
fun createSimpleScheduler(
|
||||
incoming: KrontabTemplate,
|
||||
defaultOffset: Minutes
|
||||
): KronSchedulerTz {
|
||||
val scheduler = createSimpleScheduler(incoming)
|
||||
return if (scheduler is KronSchedulerTz) {
|
||||
scheduler
|
||||
} else {
|
||||
CronDateTimeSchedulerTz(
|
||||
(scheduler as CronDateTimeScheduler).cronDateTime,
|
||||
TimezoneOffset(defaultOffset.minutes)
|
||||
)
|
||||
}
|
||||
}
|
||||
): KronSchedulerTz = KrontabConfig(incoming).scheduler(defaultOffset)
|
||||
|
||||
/**
|
||||
* Shortcut for [createSimpleScheduler]
|
|
@ -1,7 +1,7 @@
|
|||
package dev.inmo.krontab.builder
|
||||
|
||||
import com.soywiz.klock.TimezoneOffset
|
||||
import com.soywiz.klock.minutes
|
||||
import korlibs.time.TimezoneOffset
|
||||
import korlibs.time.minutes
|
||||
import dev.inmo.krontab.KronScheduler
|
||||
import dev.inmo.krontab.KronSchedulerTz
|
||||
import dev.inmo.krontab.internal.*
|
||||
|
@ -14,7 +14,7 @@ import dev.inmo.krontab.utils.Minutes
|
|||
*
|
||||
* @see dev.inmo.krontab.createSimpleScheduler
|
||||
*/
|
||||
fun buildSchedule(settingsBlock: SchedulerBuilder.() -> Unit): KronScheduler {
|
||||
inline fun buildSchedule(settingsBlock: SchedulerBuilder.() -> Unit): KronScheduler {
|
||||
val builder = SchedulerBuilder()
|
||||
|
||||
builder.settingsBlock()
|
||||
|
@ -27,7 +27,7 @@ fun buildSchedule(settingsBlock: SchedulerBuilder.() -> Unit): KronScheduler {
|
|||
*
|
||||
* @see dev.inmo.krontab.createSimpleScheduler
|
||||
*/
|
||||
fun buildSchedule(
|
||||
inline fun buildSchedule(
|
||||
offset: Minutes,
|
||||
settingsBlock: SchedulerBuilder.() -> Unit
|
||||
): KronSchedulerTz {
|
||||
|
@ -38,6 +38,27 @@ fun buildSchedule(
|
|||
return builder.build() as KronSchedulerTz
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new [KronScheduler] with [settingsBlock]
|
||||
*
|
||||
* Since it is inline function, you may break execution of [settingsBlock]
|
||||
* at any time
|
||||
*/
|
||||
inline operator fun KronScheduler.Companion.invoke(
|
||||
offset: Minutes,
|
||||
settingsBlock: SchedulerBuilder.() -> Unit
|
||||
): KronSchedulerTz = buildSchedule(offset, settingsBlock)
|
||||
|
||||
/**
|
||||
* Creates new [KronScheduler] with [settingsBlock]
|
||||
*
|
||||
* Since it is inline function, you may break execution of [settingsBlock]
|
||||
* at any time
|
||||
*/
|
||||
inline operator fun KronScheduler.Companion.invoke(
|
||||
settingsBlock: SchedulerBuilder.() -> Unit
|
||||
): KronScheduler = buildSchedule(settingsBlock)
|
||||
|
||||
class SchedulerBuilder(
|
||||
private var seconds: Array<Byte>? = null,
|
||||
private var minutes: Array<Byte>? = null,
|
||||
|
@ -161,15 +182,24 @@ class SchedulerBuilder(
|
|||
*/
|
||||
fun build(): KronScheduler = offset ?.let {
|
||||
createKronSchedulerWithOffset(
|
||||
seconds,
|
||||
minutes,
|
||||
hours,
|
||||
dayOfMonth,
|
||||
month,
|
||||
year,
|
||||
dayOfWeek,
|
||||
TimezoneOffset(it.minutes),
|
||||
milliseconds ?: millisecondsArrayDefault
|
||||
seconds = seconds,
|
||||
minutes = minutes,
|
||||
hours = hours,
|
||||
dayOfMonth = dayOfMonth,
|
||||
month = month,
|
||||
years = year,
|
||||
weekDays = dayOfWeek,
|
||||
offset = TimezoneOffset(it.minutes),
|
||||
milliseconds = milliseconds ?: millisecondsArrayDefault
|
||||
)
|
||||
} ?: createKronScheduler(seconds, minutes, hours, dayOfMonth, month, year, dayOfWeek, milliseconds ?: millisecondsArrayDefault)
|
||||
} ?: createKronScheduler(
|
||||
seconds = seconds,
|
||||
minutes = minutes,
|
||||
hours = hours,
|
||||
dayOfMonth = dayOfMonth,
|
||||
month = month,
|
||||
years = year,
|
||||
weekDays = dayOfWeek,
|
||||
milliseconds = milliseconds ?: millisecondsArrayDefault
|
||||
)
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package dev.inmo.krontab.collection
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.DateTimeTz
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.DateTimeTz
|
||||
import dev.inmo.krontab.*
|
||||
import dev.inmo.krontab.internal.*
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package dev.inmo.krontab
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import dev.inmo.krontab.builder.buildSchedule
|
||||
import dev.inmo.krontab.internal.*
|
||||
|
||||
internal val anyCronDateTime by lazy {
|
||||
CronDateTime()
|
||||
}
|
||||
internal fun getAnyNext(relatively: DateTime) = anyCronDateTime.toNearDateTime(relatively)!!
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now]
|
||||
*/
|
||||
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
|
||||
*/
|
||||
val EverySecondScheduler: KronScheduler by lazy {
|
||||
buildSchedule { seconds { 0 every 1 } }
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now] + one minute
|
||||
*/
|
||||
val EveryMinuteScheduler: KronScheduler by lazy {
|
||||
buildSchedule { minutes { 0 every 1 } }
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now] + one hour
|
||||
*/
|
||||
val EveryHourScheduler: KronScheduler by lazy {
|
||||
buildSchedule { hours { 0 every 1 } }
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now] + one day
|
||||
*/
|
||||
val EveryDayOfMonthScheduler: KronScheduler by lazy {
|
||||
buildSchedule { dayOfMonth { 0 every 1 } }
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now] + one month
|
||||
*/
|
||||
val EveryMonthScheduler: KronScheduler by lazy {
|
||||
buildSchedule { months { 0 every 1 } }
|
||||
}
|
||||
|
||||
/**
|
||||
* [KronScheduler.next] will always return [com.soywiz.klock.DateTime.now] + one year
|
||||
*/
|
||||
val EveryYearScheduler: KronScheduler by lazy {
|
||||
buildSchedule { years { 0 every 1 } }
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package dev.inmo.krontab.internal
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.TimezoneOffset
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.TimezoneOffset
|
||||
import dev.inmo.krontab.KronScheduler
|
||||
|
||||
/**
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.internal
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import korlibs.time.DateTime
|
||||
import dev.inmo.krontab.KronScheduler
|
||||
|
||||
/**
|
|
@ -1,8 +1,8 @@
|
|||
package dev.inmo.krontab.internal
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.DateTimeTz
|
||||
import com.soywiz.klock.TimezoneOffset
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.DateTimeTz
|
||||
import korlibs.time.TimezoneOffset
|
||||
import dev.inmo.krontab.KronScheduler
|
||||
import dev.inmo.krontab.KronSchedulerTz
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.internal
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import korlibs.time.*
|
||||
import dev.inmo.krontab.utils.copy
|
||||
import kotlin.math.min
|
||||
|
||||
|
@ -108,13 +108,19 @@ internal fun NearDateTimeCalculatorDays(
|
|||
} else {
|
||||
dateTime
|
||||
})
|
||||
dateTime.copy(
|
||||
val newDateTime = dateTime.copy(
|
||||
dayOfMonth = min(dateTime.month.days(dateTime.year), newOne.toInt() + 1), // index1
|
||||
hour = 0,
|
||||
minute = 0,
|
||||
second = 0,
|
||||
milliseconds = 0
|
||||
)
|
||||
// If day of month has not been changed, use old dateTime due to no changes required
|
||||
if (newDateTime.dayOfMonth == dateTime.dayOfMonth) {
|
||||
dateTime
|
||||
} else {
|
||||
newDateTime
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package dev.inmo.krontab.utils
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.Month
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.Month
|
||||
import kotlin.math.min
|
||||
|
||||
fun DateTime.copy(
|
|
@ -1,10 +1,11 @@
|
|||
package dev.inmo.krontab.utils
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.DateTimeTz
|
||||
import com.soywiz.klock.milliseconds
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.DateTimeTz
|
||||
import korlibs.time.milliseconds
|
||||
import dev.inmo.krontab.KronScheduler
|
||||
import dev.inmo.krontab.next
|
||||
import korlibs.time.millisecondsLong
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
@ -18,10 +19,11 @@ import kotlinx.coroutines.isActive
|
|||
* Will emit all the [KronScheduler.next] as soon as possible. In case [KronScheduler.next] return null, flow will
|
||||
* be completed
|
||||
*
|
||||
* @param since Will be used as the first parameter for [KronScheduler.next] fun
|
||||
* @param since Will be used as the first parameter for [KronScheduler.next] fun. If passed null, `flow`
|
||||
* will always start since the moment of collecting start
|
||||
*/
|
||||
fun KronScheduler.asTzFlowWithoutDelays(since: DateTimeTz = DateTime.nowLocal()): Flow<DateTimeTz> = flow {
|
||||
var previous = since
|
||||
fun KronScheduler.asTzFlowWithoutDelays(since: DateTimeTz? = null): Flow<DateTimeTz> = flow {
|
||||
var previous = since ?: DateTime.nowLocal()
|
||||
while (currentCoroutineContext().isActive) {
|
||||
val next = next(previous) ?: break
|
||||
emit(next)
|
||||
|
@ -57,10 +59,11 @@ fun KronScheduler.asTzFlow(): Flow<DateTimeTz> = asTzFlowWithDelays()
|
|||
* Will emit all the [KronScheduler.next] as soon as possible. In case [KronScheduler.next] return null, flow will
|
||||
* be completed
|
||||
*
|
||||
* @param since Will be used as the first parameter for [KronScheduler.next] fun
|
||||
* @param since Will be used as the first parameter for [KronScheduler.next] fun. If passed null, `flow`
|
||||
* will always start since the moment of collecting start
|
||||
*/
|
||||
fun KronScheduler.asFlowWithoutDelays(since: DateTime = DateTime.now()): Flow<DateTime> = flow {
|
||||
var previous = since
|
||||
fun KronScheduler.asFlowWithoutDelays(since: DateTime? = null): Flow<DateTime> = flow {
|
||||
var previous = since ?: DateTime.now()
|
||||
while (currentCoroutineContext().isActive) {
|
||||
val next = next(previous) ?: break
|
||||
emit(next)
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.utils.flows
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import korlibs.time.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.utils.flows
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import korlibs.time.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.utils.flows
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import korlibs.time.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.utils.flows
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import korlibs.time.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
|
@ -0,0 +1,38 @@
|
|||
package dev.inmo.krontab.utils
|
||||
|
||||
import dev.inmo.krontab.*
|
||||
import korlibs.time.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class BuildersTest {
|
||||
@Test
|
||||
fun presetsWorksCorrectly() {
|
||||
val data = mapOf(
|
||||
EverySecondScheduler to { it: DateTime -> if (it.milliseconds > 0 ) it + 1.seconds - it.milliseconds.milliseconds else it },
|
||||
EveryMinuteScheduler to { it: DateTime -> if (it.seconds > 0 || it.milliseconds > 0 ) it + 1.minutes - it.seconds.seconds - it.milliseconds.milliseconds else it },
|
||||
EveryHourScheduler to { it: DateTime -> if (it.minutes > 0 || it.seconds > 0 || it.milliseconds > 0 ) it + 1.hours - it.minutes.minutes - it.seconds.seconds - it.milliseconds.milliseconds else it },
|
||||
EveryDayOfMonthScheduler to { it: DateTime -> if (it.hours > 0 || it.minutes > 0 || it.seconds > 0 || it.milliseconds > 0 ) it + 1.days - it.hours.hours - it.minutes.minutes - it.seconds.seconds - it.milliseconds.milliseconds else it },
|
||||
EveryMonthScheduler to { it: DateTime -> if (it.dayOfMonth > 1 || it.hours > 0 || it.minutes > 0 || it.seconds > 0 || it.milliseconds > 0 ) (it + 1.months).copy(dayOfMonth = 1, hour = 0, minute = 0, second = 0, milliseconds = 0) else it },
|
||||
)
|
||||
val samples = 10000
|
||||
|
||||
runTest {
|
||||
var now = DateTime.now()
|
||||
for (i in 0 until samples) {
|
||||
data.forEach { (scheduler, expectCalculator) ->
|
||||
val expectValue = expectCalculator(now)
|
||||
val newNow = scheduler.nextOrRelative(now)
|
||||
|
||||
assertEquals(expectValue, newNow, "For time ${now.toStringDefault()} calculated wrong value: ${newNow.toStringDefault()} is not equal to ${expectValue.toStringDefault()}")
|
||||
|
||||
now = newNow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package dev.inmo.krontab.utils
|
||||
|
||||
import com.soywiz.klock.DateTime
|
||||
import com.soywiz.klock.days
|
||||
import korlibs.time.DateTime
|
||||
import korlibs.time.days
|
||||
import dev.inmo.krontab.buildSchedule
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlin.test.*
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.utils
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import korlibs.time.*
|
||||
import dev.inmo.krontab.KronSchedulerTz
|
||||
import dev.inmo.krontab.buildSchedule
|
||||
import kotlinx.coroutines.*
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.utils
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import korlibs.time.*
|
||||
import dev.inmo.krontab.builder.buildSchedule
|
||||
import dev.inmo.krontab.next
|
||||
import kotlinx.coroutines.test.runTest
|
|
@ -1,6 +1,6 @@
|
|||
package dev.inmo.krontab.utils
|
||||
|
||||
import com.soywiz.klock.*
|
||||
import korlibs.time.*
|
||||
import dev.inmo.krontab.builder.buildSchedule
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlin.math.ceil
|
|
@ -1 +0,0 @@
|
|||
<manifest package="dev.inmo.krontab"/>
|
Loading…
Reference in New Issue