krontab/src/commonMain/kotlin/dev/inmo/krontab/StringParser.kt

174 lines
6.9 KiB
Kotlin
Raw Normal View History

2020-11-21 08:58:19 +00:00
package dev.inmo.krontab
2019-10-05 05:09:22 +00:00
2021-04-22 05:58:19 +00:00
import com.soywiz.klock.TimezoneOffset
import com.soywiz.klock.minutes
2020-11-21 08:58:19 +00:00
import dev.inmo.krontab.internal.*
2021-04-09 18:28:08 +00:00
import dev.inmo.krontab.utils.Minutes
2019-10-05 05:09:22 +00:00
2020-08-22 15:42:47 +00:00
/**
* @see createSimpleScheduler
* @see buildSchedule
*/
typealias KrontabTemplate = String
2019-10-10 10:43:52 +00:00
/**
* Parse [incoming] string and adapt according to next format: "* * * * *" where order of things:
*
2022-04-29 15:57:10 +00:00
* * **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)
2019-10-10 10:43:52 +00:00
*
2021-04-22 05:58:19 +00:00
* And each one (except of offsets) have next format:
2019-10-10 10:43:52 +00:00
*
2020-07-24 08:18:18 +00:00
* `{number}[,{number},...]` or `*`
2019-10-10 10:43:52 +00:00
*
2020-06-03 14:41:54 +00:00
* and {number} here is one of
2019-10-10 10:43:52 +00:00
*
2020-06-03 14:41:54 +00:00
* * {int}-{int}
* * {int}/{int}
* * */{int}
* * {int}
2020-10-10 15:12:32 +00:00
* * F
* * L
2019-10-10 10:43:52 +00:00
*
2021-04-22 05:58:19 +00:00
* 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
*
2020-06-03 14:41:54 +00:00
* 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])
2021-04-22 05:58:19 +00:00
* * WeekDay (timezone) ranges can be found in [dayOfWeekRange]
2022-04-29 15:57:10 +00:00
* * Milliseconds ranges can be found in [millisecondsRange]
2020-06-03 14:41:54 +00:00
*
* Examples:
*
* * "0/5 * * * *" for every five seconds triggering
2020-10-10 15:12:32 +00:00
* * "0/5,L * * * *" for every five seconds triggering and on 59 second
2020-06-03 14:41:54 +00:00
* * "0/15 30 * * *" for every 15th seconds in a half of each hour
2022-04-29 15:57:10 +00:00
* * "0/15 30 * * * 500ms" for every 15th seconds in a half of each hour when milliseconds equal to 500
2022-06-15 06:40:03 +00:00
* * "1 2 3 F,4,L 5" for triggering in near first second of second minute of third hour of first, fifth and last days of may
* * "1 2 3 F,4,L 5 60o" 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
*
2021-04-09 18:28:08 +00:00
* @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
* [createKronSchedulerWithOffset] and returned [CronDateTimeSchedulerTz]
*
2020-11-21 08:58:19 +00:00
* @see dev.inmo.krontab.internal.createKronScheduler
2019-10-10 10:43:52 +00:00
*/
2021-04-09 18:28:08 +00:00
fun createSimpleScheduler(
incoming: KrontabTemplate
): KronScheduler {
2021-03-30 08:07:39 +00:00
var offsetParsed: Int? = null
2021-04-22 05:58:19 +00:00
var dayOfWeekParsed: Array<Byte>? = null
2021-03-30 08:07:39 +00:00
var yearParsed: Array<Int>? = null
2022-04-29 15:57:10 +00:00
var millisecondsParsed: Array<Short>? = null
val (secondsSource, minutesSource, hoursSource, dayOfMonthSource, monthSource) = incoming.split(" ").also {
2021-03-30 08:07:39 +00:00
listOfNotNull(
it.getOrNull(5),
2021-04-22 05:58:19 +00:00
it.getOrNull(6),
2022-04-29 15:57:10 +00:00
it.getOrNull(7),
it.getOrNull(8)
2021-03-30 08:07:39 +00:00
).forEach {
2021-04-10 09:38:20 +00:00
val offsetFromString = parseOffset(it)
2021-04-22 05:58:19 +00:00
val dayOfWeekFromString = parseWeekDay(it)
2022-04-29 15:57:10 +00:00
val millisecondsFromString = parseMilliseconds(it)
2021-04-10 09:38:20 +00:00
offsetParsed = offsetParsed ?: offsetFromString
2021-04-22 05:58:19 +00:00
dayOfWeekParsed = dayOfWeekParsed ?: dayOfWeekFromString
2022-04-29 15:57:10 +00:00
millisecondsParsed = millisecondsParsed ?: millisecondsFromString
2021-03-30 08:07:39 +00:00
when {
2022-04-29 15:57:10 +00:00
dayOfWeekFromString != null || offsetFromString != null || millisecondsFromString != null -> return@forEach
2021-04-24 12:33:37 +00:00
yearParsed == null -> {
2021-03-30 08:07:39 +00:00
yearParsed = parseYears(it)
}
}
}
}
2019-10-05 10:40:51 +00:00
val secondsParsed = parseSeconds(secondsSource)
val minutesParsed = parseMinutes(minutesSource)
val hoursParsed = parseHours(hoursSource)
val dayOfMonthParsed = parseDaysOfMonth(dayOfMonthSource)
val monthParsed = parseMonths(monthSource)
2021-04-09 18:28:08 +00:00
return offsetParsed ?.let { offset ->
createKronSchedulerWithOffset(
2022-04-29 15:57:10 +00:00
secondsParsed,
minutesParsed,
hoursParsed,
dayOfMonthParsed,
monthParsed,
yearParsed,
dayOfWeekParsed,
TimezoneOffset(offset.minutes),
millisecondsParsed ?: millisecondsArrayDefault
2021-04-09 18:28:08 +00:00
)
} ?: createKronScheduler(
2022-04-29 15:57:10 +00:00
secondsParsed,
minutesParsed,
hoursParsed,
dayOfMonthParsed,
monthParsed,
yearParsed,
dayOfWeekParsed,
millisecondsParsed ?: millisecondsArrayDefault
)
}
2021-04-09 18:28:08 +00:00
fun createSimpleScheduler(
incoming: KrontabTemplate,
defaultOffset: Minutes
): KronSchedulerTz {
val scheduler = createSimpleScheduler(incoming)
return if (scheduler is KronSchedulerTz) {
scheduler
} else {
CronDateTimeSchedulerTz(
(scheduler as CronDateTimeScheduler).cronDateTime,
2021-04-09 18:28:08 +00:00
TimezoneOffset(defaultOffset.minutes)
)
}
}
/**
2020-07-24 08:18:18 +00:00
* Shortcut for [createSimpleScheduler]
*/
2020-08-22 15:42:47 +00:00
fun buildSchedule(incoming: KrontabTemplate): KronScheduler = createSimpleScheduler(incoming)
2021-04-09 18:28:08 +00:00
/**
* Shortcut for [createSimpleScheduler]
*/
fun buildSchedule(incoming: KrontabTemplate, defaultOffset: Minutes): KronSchedulerTz = createSimpleScheduler(incoming, defaultOffset)
2020-08-22 15:42:47 +00:00
/**
* Shortcut for [buildSchedule]
*/
fun KrontabTemplate.toSchedule(): KronScheduler = buildSchedule(this)
2021-04-09 18:28:08 +00:00
/**
* Shortcut for [buildSchedule]
*/
fun KrontabTemplate.toSchedule(defaultOffset: Minutes): KronSchedulerTz = buildSchedule(this, defaultOffset)
/**
* Shortcut for [buildSchedule]
*/
2021-04-09 18:28:08 +00:00
fun KrontabTemplate.toKronScheduler(): KronScheduler = buildSchedule(this)
/**
* Shortcut for [buildSchedule]
*/
2021-04-24 12:33:37 +00:00
fun KrontabTemplate.toKronScheduler(defaultOffset: Minutes): KronSchedulerTz = buildSchedule(this, defaultOffset)