package schedule import ( "context" "errors" "github.com/carlosframework/platform/internal/hostwrite" "github.com/carlosframework/platform/internal/registry" ) var errTimerHost = errors.New("schedule: selected timer host differs") type SelectedTimers struct { Store TimerStore Work hostwrite.Work Context context.Context Host string } func (s SelectedTimers) write(host string, fn func() error) error { if s.Store == nil || s.Work == nil || s.Context == nil { return hostwrite.ErrUnavailable } if host != s.Host { return errTimerHost } return s.Work.With(s.Context, hostwrite.Identity{}, fn) } func (s SelectedTimers) UpsertTimer(t registry.Timer) error { t.Registration = "" if handled, err := s.mutate(t, false); handled { return err } return s.write(t.Host, func() error { return s.Store.UpsertTimer(t) }) } func (s SelectedTimers) DeleteTimer(host, name string) error { if handled, err := s.mutate(registry.Timer{Host: host, Name: name}, true); handled { return err } return s.write(host, func() error { return s.Store.DeleteTimer(host, name) }) } func (s SelectedTimers) GetTimer(host, name string) (*registry.Timer, error) { if s.Store == nil { return nil, hostwrite.ErrUnavailable } if host != s.Host { return nil, errTimerHost } return s.Store.GetTimer(host, name) } func (s SelectedTimers) TimersFor(host string) ([]registry.Timer, error) { if s.Store == nil { return nil, hostwrite.ErrUnavailable } if host != s.Host { return nil, errTimerHost } return s.Store.TimersFor(host) } func (s SelectedTimers) CountTimers(host, kind string) (int, error) { if s.Store == nil { return 0, hostwrite.ErrUnavailable } if host != s.Host { return 0, errTimerHost } return s.Store.CountTimers(host, kind) } var _ TimerStore = SelectedTimers{} // ReplaceTimers imports a landing snapshot without changing registrations. // Its Work must have been selected as held-timers for the owning landing op. func (s SelectedTimers) ReplaceTimers(host string, rows []registry.Timer) error { replacement, ok := s.Store.(interface { ReplaceTimers(string, []registry.Timer) error }) if !ok { return hostwrite.ErrUnavailable } copyRows := append([]registry.Timer(nil), rows...) for _, row := range copyRows { if row.Host != host { return errTimerHost } } if _, ok := s.Work.(timerMutator); ok { seen := map[string]bool{} for _, row := range copyRows { if row.Registration == "" || seen[row.Name] { return registry.ErrClaimOwnership } seen[row.Name] = true } old, err := s.TimersFor(host) if err != nil { return err } keep := map[string]bool{} for _, row := range copyRows { keep[row.Name] = true if _, err := s.mutate(row, false); err != nil { return err } } for _, row := range old { if !keep[row.Name] { if err := s.DeleteTimer(host, row.Name); err != nil { return err } } } return nil } return s.write(host, func() error { return replacement.ReplaceTimers(host, copyRows) }) }