summaryrefslogtreecommitdiff
path: root/vendor/github.com/robfig/cron/v3/spec.go
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2022-03-07 11:08:26 +0100
committerLibravatar GitHub <noreply@github.com>2022-03-07 11:08:26 +0100
commit07727753b96d209406783e5e539725bcdafebdc7 (patch)
treeb32f11cbc304d633ed0acd8f84b4c11e909bb5f3 /vendor/github.com/robfig/cron/v3/spec.go
parent[documentation] Creates Docker documentation and docker-compose.yaml (#416) (diff)
downloadgotosocial-07727753b96d209406783e5e539725bcdafebdc7.tar.xz
[feature] Clean up/uncache remote media (#407)
* Add whereNotEmptyAndNotNull * Add GetRemoteOlderThanDays * Add GetRemoteOlderThanDays * Add PruneRemote to Manager interface * Start implementing PruneRemote * add new attachment + status to tests * fix up and test GetRemoteOlderThan * fix bad import * PruneRemote: return number pruned * add Cached column to mediaattachment * update + test pruneRemote * update mediaTest * use Cached column * upstep bun to latest version * embed structs in mediaAttachment * migrate mediaAttachment to new format * don't default cached to true * select only remote media * update db dependencies * step bun back to last working version * update pruneRemote to use Cached field * fix storage path of test attachments * add recache logic to manager * fix trimmed aspect ratio * test prune and recache * return errwithcode * tidy up different paths for emoji vs attachment * fix incorrect thumbnail type being stored * expose TransportController to media processor * implement tee-ing recached content * add thoughts of dog to test fedi attachments * test get remote files * add comment on PruneRemote * add postData cleanup to recache * test thumbnail fetching * add incredible diagram * go mod tidy * buffer pipes for recache streaming * test for client stops reading after 1kb * add media-remote-cache-days to config * add cron package * wrap logrus so it's available to cron * start and stop cron jobs gracefully
Diffstat (limited to 'vendor/github.com/robfig/cron/v3/spec.go')
-rw-r--r--vendor/github.com/robfig/cron/v3/spec.go188
1 files changed, 188 insertions, 0 deletions
diff --git a/vendor/github.com/robfig/cron/v3/spec.go b/vendor/github.com/robfig/cron/v3/spec.go
new file mode 100644
index 000000000..fa1e241e5
--- /dev/null
+++ b/vendor/github.com/robfig/cron/v3/spec.go
@@ -0,0 +1,188 @@
+package cron
+
+import "time"
+
+// SpecSchedule specifies a duty cycle (to the second granularity), based on a
+// traditional crontab specification. It is computed initially and stored as bit sets.
+type SpecSchedule struct {
+ Second, Minute, Hour, Dom, Month, Dow uint64
+
+ // Override location for this schedule.
+ Location *time.Location
+}
+
+// bounds provides a range of acceptable values (plus a map of name to value).
+type bounds struct {
+ min, max uint
+ names map[string]uint
+}
+
+// The bounds for each field.
+var (
+ seconds = bounds{0, 59, nil}
+ minutes = bounds{0, 59, nil}
+ hours = bounds{0, 23, nil}
+ dom = bounds{1, 31, nil}
+ months = bounds{1, 12, map[string]uint{
+ "jan": 1,
+ "feb": 2,
+ "mar": 3,
+ "apr": 4,
+ "may": 5,
+ "jun": 6,
+ "jul": 7,
+ "aug": 8,
+ "sep": 9,
+ "oct": 10,
+ "nov": 11,
+ "dec": 12,
+ }}
+ dow = bounds{0, 6, map[string]uint{
+ "sun": 0,
+ "mon": 1,
+ "tue": 2,
+ "wed": 3,
+ "thu": 4,
+ "fri": 5,
+ "sat": 6,
+ }}
+)
+
+const (
+ // Set the top bit if a star was included in the expression.
+ starBit = 1 << 63
+)
+
+// Next returns the next time this schedule is activated, greater than the given
+// time. If no time can be found to satisfy the schedule, return the zero time.
+func (s *SpecSchedule) Next(t time.Time) time.Time {
+ // General approach
+ //
+ // For Month, Day, Hour, Minute, Second:
+ // Check if the time value matches. If yes, continue to the next field.
+ // If the field doesn't match the schedule, then increment the field until it matches.
+ // While incrementing the field, a wrap-around brings it back to the beginning
+ // of the field list (since it is necessary to re-verify previous field
+ // values)
+
+ // Convert the given time into the schedule's timezone, if one is specified.
+ // Save the original timezone so we can convert back after we find a time.
+ // Note that schedules without a time zone specified (time.Local) are treated
+ // as local to the time provided.
+ origLocation := t.Location()
+ loc := s.Location
+ if loc == time.Local {
+ loc = t.Location()
+ }
+ if s.Location != time.Local {
+ t = t.In(s.Location)
+ }
+
+ // Start at the earliest possible time (the upcoming second).
+ t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond)
+
+ // This flag indicates whether a field has been incremented.
+ added := false
+
+ // If no time is found within five years, return zero.
+ yearLimit := t.Year() + 5
+
+WRAP:
+ if t.Year() > yearLimit {
+ return time.Time{}
+ }
+
+ // Find the first applicable month.
+ // If it's this month, then do nothing.
+ for 1<<uint(t.Month())&s.Month == 0 {
+ // If we have to add a month, reset the other parts to 0.
+ if !added {
+ added = true
+ // Otherwise, set the date at the beginning (since the current time is irrelevant).
+ t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, loc)
+ }
+ t = t.AddDate(0, 1, 0)
+
+ // Wrapped around.
+ if t.Month() == time.January {
+ goto WRAP
+ }
+ }
+
+ // Now get a day in that month.
+ //
+ // NOTE: This causes issues for daylight savings regimes where midnight does
+ // not exist. For example: Sao Paulo has DST that transforms midnight on
+ // 11/3 into 1am. Handle that by noticing when the Hour ends up != 0.
+ for !dayMatches(s, t) {
+ if !added {
+ added = true
+ t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, loc)
+ }
+ t = t.AddDate(0, 0, 1)
+ // Notice if the hour is no longer midnight due to DST.
+ // Add an hour if it's 23, subtract an hour if it's 1.
+ if t.Hour() != 0 {
+ if t.Hour() > 12 {
+ t = t.Add(time.Duration(24-t.Hour()) * time.Hour)
+ } else {
+ t = t.Add(time.Duration(-t.Hour()) * time.Hour)
+ }
+ }
+
+ if t.Day() == 1 {
+ goto WRAP
+ }
+ }
+
+ for 1<<uint(t.Hour())&s.Hour == 0 {
+ if !added {
+ added = true
+ t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, loc)
+ }
+ t = t.Add(1 * time.Hour)
+
+ if t.Hour() == 0 {
+ goto WRAP
+ }
+ }
+
+ for 1<<uint(t.Minute())&s.Minute == 0 {
+ if !added {
+ added = true
+ t = t.Truncate(time.Minute)
+ }
+ t = t.Add(1 * time.Minute)
+
+ if t.Minute() == 0 {
+ goto WRAP
+ }
+ }
+
+ for 1<<uint(t.Second())&s.Second == 0 {
+ if !added {
+ added = true
+ t = t.Truncate(time.Second)
+ }
+ t = t.Add(1 * time.Second)
+
+ if t.Second() == 0 {
+ goto WRAP
+ }
+ }
+
+ return t.In(origLocation)
+}
+
+// dayMatches returns true if the schedule's day-of-week and day-of-month
+// restrictions are satisfied by the given time.
+func dayMatches(s *SpecSchedule, t time.Time) bool {
+ var (
+ domMatch bool = 1<<uint(t.Day())&s.Dom > 0
+ dowMatch bool = 1<<uint(t.Weekday())&s.Dow > 0
+ )
+ if s.Dom&starBit > 0 || s.Dow&starBit > 0 {
+ return domMatch && dowMatch
+ }
+ return domMatch || dowMatch
+}