| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- // Package watch implements waiting/polling for new free game offers.
- package watch
- import (
- "context"
- "log"
- "time"
- "gogs.netdome.biz/paul/cheapo/internal/epic"
- )
- // Notifier is called for every game that newly became free.
- type Notifier interface {
- Notify(games []epic.Game)
- }
- // NotifierFunc adapts a function to Notifier.
- type NotifierFunc func(games []epic.Game)
- func (f NotifierFunc) Notify(games []epic.Game) { f(games) }
- // Watcher polls the client and reports games that were not seen before.
- type Watcher struct {
- Client *epic.Client
- Interval time.Duration
- seen map[string]bool
- }
- // NewWatcher creates a watcher. Interval defaults to 15m.
- func NewWatcher(c *epic.Client, interval time.Duration) *Watcher {
- if interval <= 0 {
- interval = 15 * time.Minute
- }
- return &Watcher{Client: c, Interval: interval, seen: map[string]bool{}}
- }
- // Run polls 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 {
- games, err := w.Client.GetFreeGames(ctx)
- if err != nil {
- return err
- }
- var fresh []epic.Game
- for _, g := range games {
- if !w.seen[g.ID] {
- fresh = append(fresh, g)
- }
- }
- for _, g := range games {
- 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, polling every %s", len(games), w.Interval)
- first = false
- }
- select {
- case <-ctx.Done():
- return ctx.Err()
- case <-t.C:
- }
- }
- }
|