package core import ( "context" "errors" "fmt" maxbot "github.com/max-messenger/max-bot-api-client-go/v2" "github.com/max-messenger/max-bot-api-client-go/v2/model" "github.com/rs/zerolog/log" "time" ) const defaultInterval = 200 * time.Millisecond type LongPollerOption interface { apply(opts *longPollerOptions) } type Webhook struct{} type LongPoller struct { api *maxbot.Api pollInterval time.Duration } type TestPoller struct{} type longPollerOptions struct { pollInterval time.Duration } func (w *Webhook) Start(_ context.Context) (<-chan model.Update, error) { return nil, fmt.Errorf("unimplemented") } func NewLongPoller(api *maxbot.Api, options ...LongPollerOption) *LongPoller { lp := &LongPoller{ api: api, } opts := newLongPollerOptions() for _, opt := range options { opt.apply(opts) } lp.pollInterval = opts.pollInterval return lp } func (lp *LongPoller) Start(ctx context.Context) (<-chan model.Update, error) { var updates []model.Update var marker int64 var err error ch := make(chan model.Update) go func() { defer close(ch) // todo: backoff on errors for { select { case <-ctx.Done(): return case <-time.Tick(lp.pollInterval): start := time.Now() updates, marker, err = lp.api.Subscriptions.GetUpdates(ctx, marker) latency := time.Since(start) if err != nil && !errors.Is(err, context.Canceled) { log.Error().Err(err).Send() } log.Ctx(ctx).Debug(). Int("received", len(updates)). Dur("latency", latency). Msg("received updates") for _, update := range updates { select { case <-ctx.Done(): return case ch <- update: } } } } }() return ch, nil } func (tp *TestPoller) Start(_ context.Context) (<-chan model.Update, error) { return nil, fmt.Errorf("unimplemented") } func newLongPollerOptions() *longPollerOptions { return &longPollerOptions{ pollInterval: defaultInterval, } }