mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 23:32:24 -06:00 
			
		
		
		
	* update go-sched to v1.2.4 which removes some now unused dependencies * whoops, remove test output
		
			
				
	
	
		
			143 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package sched
 | 
						|
 | 
						|
import (
 | 
						|
	"reflect"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"sync/atomic"
 | 
						|
	"time"
 | 
						|
	"unsafe"
 | 
						|
)
 | 
						|
 | 
						|
// Job encapsulates logic for a scheduled job to be run according
 | 
						|
// to a set Timing, executing the job with a set panic handler, and
 | 
						|
// holding onto a next execution time safely in a concurrent environment.
 | 
						|
type Job struct {
 | 
						|
	id     uint64
 | 
						|
	next   unsafe.Pointer // *time.Time
 | 
						|
	timing Timing
 | 
						|
	call   func(time.Time)
 | 
						|
	panic  func(interface{})
 | 
						|
}
 | 
						|
 | 
						|
// NewJob returns a new Job to run given function.
 | 
						|
func NewJob(fn func(now time.Time)) *Job {
 | 
						|
	if fn == nil {
 | 
						|
		// Ensure a function
 | 
						|
		panic("nil func")
 | 
						|
	}
 | 
						|
 | 
						|
	j := &Job{ // set defaults
 | 
						|
		timing: emptytiming, // i.e. fire immediately
 | 
						|
		call:   fn,
 | 
						|
		panic:  func(i interface{}) { panic(i) },
 | 
						|
	}
 | 
						|
 | 
						|
	return j
 | 
						|
}
 | 
						|
 | 
						|
// At sets this Job to execute at time, by passing (*sched.Once)(&at) to .With(). See .With() for details.
 | 
						|
func (job *Job) At(at time.Time) *Job {
 | 
						|
	return job.With((*Once)(&at))
 | 
						|
}
 | 
						|
 | 
						|
// Every sets this Job to execute every period, by passing sched.Period(period) to .With(). See .With() for details.
 | 
						|
func (job *Job) Every(period time.Duration) *Job {
 | 
						|
	return job.With(Periodic(period))
 | 
						|
}
 | 
						|
 | 
						|
// EveryAt sets this Job to execute every period starting at time, by passing &PeriodicAt{once: Once(at), period: Periodic(period)} to .With(). See .With() for details.
 | 
						|
func (job *Job) EveryAt(at time.Time, period time.Duration) *Job {
 | 
						|
	return job.With(&PeriodicAt{Once: Once(at), Period: Periodic(period)})
 | 
						|
}
 | 
						|
 | 
						|
// With sets this Job's timing to given implementation, or if already set will wrap existing using sched.TimingWrap{}.
 | 
						|
func (job *Job) With(t Timing) *Job {
 | 
						|
	if t == nil {
 | 
						|
		// Ensure a timing
 | 
						|
		panic("nil Timing")
 | 
						|
	}
 | 
						|
 | 
						|
	if job.id != 0 {
 | 
						|
		// Cannot update scheduled job
 | 
						|
		panic("job already scheduled")
 | 
						|
	}
 | 
						|
 | 
						|
	if job.timing == emptytiming {
 | 
						|
		// Set new timing
 | 
						|
		job.timing = t
 | 
						|
	} else {
 | 
						|
		// Wrap old timing
 | 
						|
		old := job.timing
 | 
						|
		job.timing = &TimingWrap{
 | 
						|
			Outer: t,
 | 
						|
			Inner: old,
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return job
 | 
						|
}
 | 
						|
 | 
						|
// OnPanic specifies how this job handles panics, default is an actual panic.
 | 
						|
func (job *Job) OnPanic(fn func(interface{})) *Job {
 | 
						|
	if fn == nil {
 | 
						|
		// Ensure a function
 | 
						|
		panic("nil func")
 | 
						|
	}
 | 
						|
 | 
						|
	if job.id != 0 {
 | 
						|
		// Cannot update scheduled job
 | 
						|
		panic("job already scheduled")
 | 
						|
	}
 | 
						|
 | 
						|
	job.panic = fn
 | 
						|
	return job
 | 
						|
}
 | 
						|
 | 
						|
// Next returns the next time this Job is expected to run.
 | 
						|
func (job *Job) Next() time.Time {
 | 
						|
	return loadTime(&job.next)
 | 
						|
}
 | 
						|
 | 
						|
// Run will execute this Job and pass through given now time.
 | 
						|
func (job *Job) Run(now time.Time) {
 | 
						|
	defer func() {
 | 
						|
		switch r := recover(); {
 | 
						|
		case r == nil:
 | 
						|
			// no panic
 | 
						|
		case job != nil &&
 | 
						|
			job.panic != nil:
 | 
						|
			job.panic(r)
 | 
						|
		default:
 | 
						|
			panic(r)
 | 
						|
		}
 | 
						|
	}()
 | 
						|
	job.call(now)
 | 
						|
}
 | 
						|
 | 
						|
// String provides a debuggable string representation of Job including ID, next time and Timing type.
 | 
						|
func (job *Job) String() string {
 | 
						|
	var buf strings.Builder
 | 
						|
	buf.WriteByte('{')
 | 
						|
	buf.WriteString("id=")
 | 
						|
	buf.WriteString(strconv.FormatUint(job.id, 10))
 | 
						|
	buf.WriteByte(' ')
 | 
						|
	buf.WriteString("next=")
 | 
						|
	buf.WriteString(loadTime(&job.next).Format(time.StampMicro))
 | 
						|
	buf.WriteByte(' ')
 | 
						|
	buf.WriteString("timing=")
 | 
						|
	buf.WriteString(reflect.TypeOf(job.timing).String())
 | 
						|
	buf.WriteByte('}')
 | 
						|
	return buf.String()
 | 
						|
}
 | 
						|
 | 
						|
func loadTime(p *unsafe.Pointer) time.Time {
 | 
						|
	if p := atomic.LoadPointer(p); p != nil {
 | 
						|
		return *(*time.Time)(p)
 | 
						|
	}
 | 
						|
	return zerotime
 | 
						|
}
 | 
						|
 | 
						|
func storeTime(p *unsafe.Pointer, t time.Time) {
 | 
						|
	atomic.StorePointer(p, unsafe.Pointer(&t))
 | 
						|
}
 |