diff --git a/internal/delivery/telegramsink/intake.go b/internal/delivery/telegramsink/intake.go index 8fbc21f..09e6035 100644 --- a/internal/delivery/telegramsink/intake.go +++ b/internal/delivery/telegramsink/intake.go @@ -14,6 +14,7 @@ package telegramsink import ( "context" "errors" + "fmt" "log" "net/http" "strings" @@ -58,6 +59,13 @@ func NewPoller(s *Sink, turn Turn, correct Correct) (*Poller, error) { if turn == nil { return nil, errors.New("telegramsink: intake needs a turn handler") } + // The push half accepts @channelusername as a destination. The intake half + // cannot: an inbound update names its chat by numeric id, so an @-name would + // match nothing and the poller would read the chat and answer none of it. + // Refusing here is the difference between a boot error and a dead reach. + if strings.HasPrefix(strings.TrimSpace(s.cfg.ChatID), "@") { + return nil, fmt.Errorf("telegramsink: intake needs the numeric chat id, not %s", s.cfg.ChatID) + } // The sink's transport already carries the relay. Only the timeout differs, // and it has to clear the long poll. hc := &http.Client{ @@ -101,15 +109,26 @@ func (p *Poller) Run(ctx context.Context) { // stopped mattering, and a reminder set from it would land at the wrong time. // Missing it is the safe direction. func (p *Poller) discardBacklog(ctx context.Context) { - updates, err := p.getUpdates(ctx, 0) - if err != nil { - // Not fatal. The offset stays 0, so the first real poll sees the backlog - // and the messages below get answered late. Say so rather than hide it. - log.Printf("telegram intake: could not skip the backlog, old messages may be answered: %v", err) - return + // getUpdates returns at most 100 per call, so one call is not the queue. The + // loop is bounded rather than "until empty": the timeout is 0, so an instance + // that keeps handing back a full batch would spin, and a thousand skipped + // messages is already a box that was down for a long time. + skipped := 0 + for range 10 { + updates, err := p.getUpdates(ctx, 0) + if err != nil { + // Not fatal. The offset stays where it was, so the first real poll sees + // what is left and answers it late. Say so rather than hide it. + log.Printf("telegram intake: could not skip the backlog, old messages may be answered: %v", err) + return + } + skipped += len(updates) + if len(updates) == 0 { + break + } } - if len(updates) > 0 { - log.Printf("telegram intake: skipped %d message(s) queued while the daemon was down", len(updates)) + if skipped > 0 { + log.Printf("telegram intake: skipped %d message(s) queued while the daemon was down", skipped) } }