2022-04-26 00:02:51 +08:00
|
|
|
package bot
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2022-05-06 17:47:43 +08:00
|
|
|
"sync"
|
2022-04-26 00:02:51 +08:00
|
|
|
"sync/atomic"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/go-telegram/bot/models"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
maxTimeoutAfterError = time.Second * 5
|
|
|
|
)
|
|
|
|
|
|
|
|
type getUpdatesParams struct {
|
2024-03-05 00:06:02 +08:00
|
|
|
Offset int64 `json:"offset,omitempty"`
|
|
|
|
Limit int `json:"limit,omitempty"`
|
|
|
|
Timeout int `json:"timeout,omitempty"`
|
|
|
|
AllowedUpdates AllowedUpdates `json:"allowed_updates,omitempty"`
|
2022-04-26 00:02:51 +08:00
|
|
|
}
|
|
|
|
|
2024-03-05 00:06:02 +08:00
|
|
|
type AllowedUpdates []string
|
|
|
|
|
2022-05-03 00:39:04 +08:00
|
|
|
// GetUpdates https://core.telegram.org/bots/api#getupdates
|
2022-05-06 17:47:43 +08:00
|
|
|
func (b *Bot) getUpdates(ctx context.Context, wg *sync.WaitGroup) {
|
|
|
|
defer wg.Done()
|
|
|
|
|
2022-04-26 00:02:51 +08:00
|
|
|
var timeoutAfterError time.Duration
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
|
|
|
if timeoutAfterError > 0 {
|
2023-04-13 16:39:58 +08:00
|
|
|
if b.isDebug {
|
|
|
|
b.debugHandler("wait after error, %v", timeoutAfterError)
|
|
|
|
}
|
2022-04-26 00:02:51 +08:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case <-time.After(timeoutAfterError):
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
params := &getUpdatesParams{
|
|
|
|
Timeout: int((b.pollTimeout - time.Second).Seconds()),
|
|
|
|
Offset: atomic.LoadInt64(&b.lastUpdateID) + 1,
|
|
|
|
}
|
|
|
|
|
2024-03-05 00:06:02 +08:00
|
|
|
if b.allowedUpdates != nil {
|
|
|
|
params.AllowedUpdates = b.allowedUpdates
|
|
|
|
}
|
|
|
|
|
2022-04-26 00:02:51 +08:00
|
|
|
var updates []*models.Update
|
|
|
|
|
2022-05-06 17:47:43 +08:00
|
|
|
errRequest := b.rawRequest(ctx, "getUpdates", params, &updates)
|
2022-04-26 00:02:51 +08:00
|
|
|
if errRequest != nil {
|
|
|
|
if errors.Is(errRequest, context.Canceled) {
|
|
|
|
return
|
|
|
|
}
|
2024-08-23 22:13:25 +08:00
|
|
|
b.error("error get updates, %w", errRequest)
|
2022-04-26 00:02:51 +08:00
|
|
|
timeoutAfterError = incErrTimeout(timeoutAfterError)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
timeoutAfterError = 0
|
|
|
|
|
|
|
|
for _, upd := range updates {
|
|
|
|
atomic.StoreInt64(&b.lastUpdateID, upd.ID)
|
|
|
|
select {
|
2024-04-02 22:23:32 +08:00
|
|
|
case <-ctx.Done():
|
|
|
|
b.error("some updates lost, ctx done")
|
|
|
|
return
|
2022-05-03 00:39:04 +08:00
|
|
|
case b.updates <- upd:
|
2022-04-26 00:02:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func incErrTimeout(timeout time.Duration) time.Duration {
|
|
|
|
if timeout == 0 {
|
|
|
|
return time.Millisecond * 100 // first timeout
|
|
|
|
}
|
|
|
|
timeout *= 2
|
|
|
|
if timeout > maxTimeoutAfterError {
|
|
|
|
return maxTimeoutAfterError
|
|
|
|
}
|
|
|
|
return timeout
|
|
|
|
}
|