mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 08:52:25 -05:00 
			
		
		
		
	
		
			
	
	
		
			93 lines
		
	
	
	
		
			2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			93 lines
		
	
	
	
		
			2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | package sched | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"time" | ||
|  | ) | ||
|  | 
 | ||
|  | var ( | ||
|  | 	// zerotime is zero time.Time (unix epoch). | ||
|  | 	zerotime = time.Time{} | ||
|  | 
 | ||
|  | 	// emptytiming is a global timingempty to check against. | ||
|  | 	emptytiming = timingempty{} | ||
|  | ) | ||
|  | 
 | ||
|  | // Timing provides scheduling for a Job, determining the next time | ||
|  | // for given current time that execution is required. Please note that | ||
|  | // calls to .Next() may alter the results of the next call, and should | ||
|  | // only be called by the Scheduler. | ||
|  | type Timing interface { | ||
|  | 	Next(time.Time) time.Time | ||
|  | } | ||
|  | 
 | ||
|  | // timingempty is a 'zero' Timing implementation that always returns zero time. | ||
|  | type timingempty struct{} | ||
|  | 
 | ||
|  | func (timingempty) Next(time.Time) time.Time { | ||
|  | 	return zerotime | ||
|  | } | ||
|  | 
 | ||
|  | // Once implements Timing to provide a run-once Job execution. | ||
|  | type Once time.Time | ||
|  | 
 | ||
|  | func (o *Once) Next(time.Time) time.Time { | ||
|  | 	ret := *(*time.Time)(o) | ||
|  | 	*o = Once(zerotime) // reset | ||
|  | 	return ret | ||
|  | } | ||
|  | 
 | ||
|  | // Periodic implements Timing to provide a recurring Job execution. | ||
|  | type Periodic time.Duration | ||
|  | 
 | ||
|  | func (p Periodic) Next(now time.Time) time.Time { | ||
|  | 	return now.Add(time.Duration(p)) | ||
|  | } | ||
|  | 
 | ||
|  | // PeriodicAt implements Timing to provide a recurring Job execution starting at 'Once' time. | ||
|  | type PeriodicAt struct { | ||
|  | 	Once   Once | ||
|  | 	Period Periodic | ||
|  | } | ||
|  | 
 | ||
|  | func (p *PeriodicAt) Next(now time.Time) time.Time { | ||
|  | 	if next := p.Once.Next(now); !next.IsZero() { | ||
|  | 		return next | ||
|  | 	} | ||
|  | 	return p.Period.Next(now) | ||
|  | } | ||
|  | 
 | ||
|  | // TimingWrap allows combining two different Timing implementations. | ||
|  | type TimingWrap struct { | ||
|  | 	Outer Timing | ||
|  | 	Inner Timing | ||
|  | 
 | ||
|  | 	// determined next times | ||
|  | 	outerNext time.Time | ||
|  | 	innerNext time.Time | ||
|  | } | ||
|  | 
 | ||
|  | func (t *TimingWrap) Next(now time.Time) time.Time { | ||
|  | 	if t.outerNext.IsZero() { | ||
|  | 		// Regenerate outermost next run time | ||
|  | 		t.outerNext = t.Outer.Next(now) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if t.innerNext.IsZero() { | ||
|  | 		// Regenerate innermost next run time | ||
|  | 		t.innerNext = t.Inner.Next(now) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// If outer comes before inner, return outer | ||
|  | 	if t.outerNext != zerotime && | ||
|  | 		t.outerNext.Before(t.innerNext) { | ||
|  | 		next := t.outerNext | ||
|  | 		t.outerNext = zerotime | ||
|  | 		return next | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// Else, return inner | ||
|  | 	next := t.innerNext | ||
|  | 	t.innerNext = zerotime | ||
|  | 	return next | ||
|  | } |