| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- // Package watch implements waiting/polling for new free game offers.
- package watch
- import (
- "context"
- "log"
- "time"
- "gogs.netdome.biz/paul/cheapo/internal/game"
- )
- // Notifier is called for every game that newly became free.
- type Notifier interface {
- Notify(games []game.Game)
- }
- // NotifierFunc adapts a function to Notifier.
- type NotifierFunc func(games []game.Game)
- func (f NotifierFunc) Notify(games []game.Game) { f(games) }
- // Watcher polls providers and reports games that were not seen before.
- type Watcher struct {
- Providers []game.Provider
- Interval time.Duration
- seen map[string]bool
- }
- // NewWatcher creates a watcher. Interval defaults to 15m.
- func NewWatcher(interval time.Duration, providers ...game.Provider) *Watcher {
- if interval <= 0 {
- interval = 15 * time.Minute
- }
- return &Watcher{Providers: providers, Interval: interval, seen: map[string]bool{}}
- }
- // Run polls all providers until ctx is done. On the first pass it reports all
- // current free games as "new" unless baselineOnly is true (useful to seed the
- // seen-set without notifying).
- func (w *Watcher) Run(ctx context.Context, baselineOnly bool, n Notifier) error {
- t := time.NewTicker(w.Interval)
- defer t.Stop()
- first := true
- for {
- var total int
- for _, p := range w.Providers {
- games, err := p.GetFreeGames(ctx)
- if err != nil {
- // One flaky provider shall not kill the watcher.
- log.Printf("watcher: %s: %v", p.Name(), err)
- continue
- }
- total += len(games)
- var fresh []game.Game
- for _, g := range games {
- if !w.seen[g.ID] {
- fresh = append(fresh, g)
- }
- w.seen[g.ID] = true
- }
- if len(fresh) > 0 && !(first && baselineOnly) {
- n.Notify(fresh)
- }
- }
- if first {
- log.Printf("watcher: baseline set with %d current free games across %d providers, polling every %s",
- total, len(w.Providers), w.Interval)
- first = false
- }
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-t.C:
- }
- }
- }
|