package providers // Both Telegram auth and notifications need to receive messages received by Telegram bot in the loop, // and below is the implementation of such loop which dispatched received events to both receivers, // so that they could work at the same time. import ( "context" "encoding/json" "fmt" "time" log "github.com/go-pkgz/lgr" ntf "github.com/go-pkgz/notify" ) type tgRequester interface { Request(ctx context.Context, method string, b []byte, data interface{}) error } // TGUpdatesReceiver used to dispatch telegram updates to multiple receivers type TGUpdatesReceiver interface { fmt.Stringer ProcessUpdate(ctx context.Context, textUpdate string) error } // DispatchTelegramUpdates dispatches telegram updates to provided list of receivers // Blocks caller func DispatchTelegramUpdates(ctx context.Context, requester tgRequester, receivers []TGUpdatesReceiver, period time.Duration) { // Identifier of the first update to be requested. // Should be equal to LastSeenUpdateID + 1 // See https://core.telegram.org/bots/api#getupdates var updateOffset int processUpdatedTicker := time.NewTicker(period) for { select { case <-ctx.Done(): processUpdatedTicker.Stop() return case <-processUpdatedTicker.C: url := `getUpdates?allowed_updates=["message"]` if updateOffset != 0 { url += fmt.Sprintf("&offset=%d", updateOffset) } var update ntf.TelegramUpdate err := requester.Request(ctx, url, nil, &update) if err != nil { log.Printf("[WARN] failed to fetch updates: %v", err) continue } for _, u := range update.Result { if u.UpdateID >= updateOffset { updateOffset = u.UpdateID + 1 } } if raw, err := json.Marshal(update); err == nil { for _, r := range receivers { e := r.ProcessUpdate(ctx, string(raw)) if e != nil { log.Printf("[ERROR] failure from destination %s on processing telegram update %v", r, e) } } } } } }