diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 9711178b..0c50ba58 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,13 +1,7 @@
# These are supported funding model platforms
-github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
-patreon: "mymmrac" # Replace with a single Patreon username
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-otechie: # Replace with a single Otechie username
-lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
-custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
+patreon: "mymmrac"
+custom: [
+ "https://tronscan.org/#/address/TW6sjDnGbTSpztXrASfD2Pt4JnBqmphRah",
+ "https://etherscan.io/address/0x45f57E685Ec43053f6803491e7347B95C9573b8A",
+]
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index fd377f24..72ffe162 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -21,5 +21,5 @@ updates:
schedule:
interval: "weekly"
labels:
- - ":gear: Github Actions"
+ - ":gear: GitHub Actions"
- ":shamrock: Dependencies"
diff --git a/.golangci.yml b/.golangci.yml
index 056179b9..56ebae32 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -8,6 +8,7 @@ linters:
enable-all: true
disable:
# Disabled because not relevant for this project
+ - cyclop # Checks function and package cyclomatic complexity
- containedctx # containedctx is a linter that detects struct contained context.Context field
- depguard # Go linter that checks if package imports are in a list of acceptable packages
- dupword # checks for duplicate words in the source code
@@ -29,7 +30,7 @@ linters:
- wsl # Whitespace Linter - Forces you to use empty lines!
# Disabled because deprecated
- - exportloopref # An analyzer that finds exporting pointers for loop variables
+ - tenv # Tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17
# To see a list of enabled/disabled by current configuration linters:
# golangci-lint linters
@@ -37,34 +38,14 @@ linters:
# Settings of specific linters
linters-settings:
govet: # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not
- # align with the format string
- asmdecl: true # report mismatches between assembly files and Go declarations
- assign: true # check for useless assignments
- atomic: true # check for common mistakes using the sync/atomic package
- bools: true # check for common mistakes involving boolean operators
- buildtag: true # check that +build tags are well-formed and correctly located
- cgocall: true # detect some violations of the cgo pointer passing rules
- composites: true # check for unkeyed composite literals
- copylocks: true # check for locks erroneously passed by value
- errorsas: true # report passing non-pointer or non-error values to errors.As
- framepointer: true # report assembly that clobbers the frame pointer before saving it
- httpresponse: true # check for mistakes using HTTP responses
- ifaceassert: true # detect impossible interface-to-interface type assertions
- loopclosure: true # check references to loop variables from within nested functions
- lostcancel: true # check cancel func returned by context.WithCancel is called
- nilfunc: true # check for useless comparisons between functions and nil
- printf: true # check consistency of Printf format strings and arguments
- shift: true # check for shifts that equal or exceed the width of the integer
- sigchanyzer: true # check for unbuffered channel of os.Signal
- stdmethods: true # check signature of methods of well-known interfaces
- stringintconv: true # check for string(int) conversions
- structtag: true # check that struct field tags conform to reflect.StructTag.Get
- testinggoroutine: true # report calls to (*testing.T).Fatal from goroutines started by a test.
- tests: true # check for common mistaken usages of tests and examples
- unmarshal: true # report passing non-pointer or non-interface values to unmarshal
- unreachable: true # check for unreachable code
- unsafeptr: true # check for invalid conversions of uintptr to unsafe.Pointer
- unusedresult: true # check for unused results of calls to some functions
+ # Enable all analyzers.
+ # Default: false
+ enable-all: true
+ # Disable analyzers by name.
+ # Run `go tool vet help` to see all analyzers.
+ # Default: []
+ disable:
+ - fieldalignment # check for struct field alignments
gocyclo: # Computes and checks the cyclomatic complexity of functions
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 15
@@ -104,9 +85,6 @@ linters-settings:
# Make an issue if func has more lines of code than this setting, and it has naked returns; default is 30
# decided to use 3 to exclude long functions with named returns which can be a potential source of many errors / bugs
max-func-lines: 3
- staticcheck: # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
- # Include tests in the analysis.
- tests: true
funlen: # Tool for detection of long functions
lines: 120
statements: 40
@@ -137,9 +115,7 @@ linters-settings:
disabled: true
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cognitive-complexity
- name: cognitive-complexity
- severity: warning
- disabled: false
- arguments: [ 20 ]
+ disabled: true # Duplicate: gocognit
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#comment-spacings
- name: comment-spacings
severity: warning
@@ -148,9 +124,7 @@ linters-settings:
- nolint
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#cyclomatic
- name: cyclomatic
- severity: warning
- disabled: false
- arguments: [ 15 ]
+ disabled: true # Duplicate: gocyclo
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#file-header
- name: file-header
disabled: true
@@ -177,10 +151,6 @@ linters-settings:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-receiver
- name: unused-receiver
disabled: true
- cyclop:
- # The maximal code complexity to report.
- # Default: 10
- max-complexity: 15
issues:
# Excluding configuration per-path, per-linter, per-text and per-source
@@ -197,6 +167,16 @@ issues:
- maintidx
- revive
+ # Exclude linters for types file
+ - path: "types.go"
+ linters:
+ - funlen
+
+ # Exclude linters for methods file
+ - path: "methods.go"
+ linters:
+ - lll
+
# Which dirs to exclude: issues from them won't be reported.
# Can use regexp here: `generated.*`, regexp is applied on full path,
# including the path prefix if one is set.
diff --git a/README.md b/README.md
index 30d1b770..963abfac 100644
--- a/README.md
+++ b/README.md
@@ -22,13 +22,13 @@
-Telego is Telegram Bot API library for Golang with full [API][TelegramBotAPI] implementation (one-to-one)
+Telego is a Telegram Bot API library for Golang with full [API][TelegramBotAPI] implementation (one-to-one)
The goal of this library was to create API with the same types and methods as actual Telegram Bot API.
Every type and method have been represented in [`types.go`](types.go) and [`methods.go`](methods.go) files with mostly
all documentation from Telegram.
-:warning: Telego is still in v0.x.x version, so do expect breaking changes! :warning:
+:warning: This is a Telego release candidate, so do expect breaking changes! :warning:
For more detailed documentation, see docs at [telego.pixelbox.dev](https://telego.pixelbox.dev).
@@ -62,7 +62,7 @@ How to get the library:
go get github.com/mymmrac/telego
```
-Make sure you get the latest version to have all new features & fixes.
+Make sure you get the latest version to have all new features and fixes.
More examples can be seen here:
@@ -138,6 +138,7 @@ specify [token](https://core.telegram.org/bots/api#authorizing-your-bot).
package main
import (
+ "context"
"fmt"
"os"
@@ -159,7 +160,7 @@ func main() {
}
// Call method getMe (https://core.telegram.org/bots/api#getme)
- botUser, err := bot.GetMe()
+ botUser, err := bot.GetMe(context.Background())
if err != nil {
fmt.Println("Error:", err)
}
@@ -173,10 +174,10 @@ func main() {
[▲ Go Up ▲](#telego--go-telegram-bot-api)
-In order to receive updates, you can use one of two methods:
+To receive updates, you can use one of two methods:
- using long polling (`bot.UpdatesViaLongPolling`)
-- using webhook (`bot.UpdatesViaWebhook`)
+- using webhook (`bot.UpdatesViaWebhook`, recommended way)
Let's start from long polling (easier for local testing):
@@ -184,6 +185,7 @@ Let's start from long polling (easier for local testing):
package main
import (
+ "context"
"fmt"
"os"
@@ -203,10 +205,7 @@ func main() {
// Get updates channel
// (more on configuration in examples/updates_long_polling/main.go)
- updates, _ := bot.UpdatesViaLongPolling(nil)
-
- // Stop reviving updates from update channel
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(context.Background(), nil)
// Loop through all updates when they came
for update := range updates {
@@ -221,13 +220,16 @@ Webhook example (recommended way):
package main
import (
+ "context"
"fmt"
+ "net/http"
"os"
"github.com/mymmrac/telego"
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information,
@@ -239,26 +241,24 @@ func main() {
}
// Set up a webhook on Telegram side
- _ = bot.SetWebhook(&telego.SetWebhookParams{
+ _ = bot.SetWebhook(ctx, &telego.SetWebhookParams{
URL: "https://example.com/bot" + bot.Token(),
})
// Receive information about webhook
- info, _ := bot.GetWebhookInfo()
+ info, _ := bot.GetWebhookInfo(ctx)
fmt.Printf("Webhook Info: %+v\n", info)
+ // Create http serve mux
+ mux := http.NewServeMux()
+
// Get an update channel from webhook.
// (more on configuration in examples/updates_webhook/main.go)
- updates, _ := bot.UpdatesViaWebhook("/bot" + bot.Token())
+ updates, _ := bot.UpdatesViaWebhook(ctx, telego.WebhookHTTPServeMux(mux, "/bot", bot.Token()))
// Start server for receiving requests from the Telegram
go func() {
- _ = bot.StartWebhook("localhost:443")
- }()
-
- // Stop reviving updates from update channel and shutdown webhook server
- defer func() {
- _ = bot.StopWebhook()
+ _ = http.ListenAndServe(":443", mux)
}()
// Loop through all updates when they came
@@ -270,7 +270,7 @@ func main() {
For running multiple bots from a single server, see [this](examples/multi_bot_webhook/main.go) example.
-> Tip: For testing webhooks, you can use [Ngrok](https://ngrok.com) to make a tunnel to your localhost,
+> Tip: For testing webhooks locally, you can use [Ngrok](https://ngrok.com) to make a tunnel to your localhost,
> and get a random domain available from the Internet.
> It's as simple as `ngrok http 8080`.
> Or follow [Telego + Ngrok example](examples/ngrok/main.go) using [ngrok/ngrok-go](https://github.com/ngrok/ngrok-go)
@@ -294,6 +294,7 @@ name: `` + `Params`. If method doesn't have required parameters `nil
package main
import (
+ "context"
"fmt"
"os"
@@ -302,6 +303,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information,
@@ -313,11 +315,10 @@ func main() {
}
// Call method getMe
- botUser, _ := bot.GetMe()
+ botUser, _ := bot.GetMe(ctx)
fmt.Printf("Bot User: %+v\n", botUser)
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
for update := range updates {
if update.Message != nil {
@@ -327,7 +328,7 @@ func main() {
// Call method sendMessage.
// Send a message to sender with the same text (echo bot).
// (https://core.telegram.org/bots/api#sendmessage)
- sentMessage, _ := bot.SendMessage(
+ sentMessage, _ := bot.SendMessage(ctx,
tu.Message(
tu.ID(chatID),
update.Message.Text,
@@ -420,12 +421,12 @@ func main() {
"Hello World",
).WithReplyMarkup(keyboard).WithProtectContent() // Multiple `with` method
- bot.SendMessage(msg)
+ bot.SendMessage(ctx, msg)
}
```
Those methods allow you to modify values without directly accessing them, also as you saw `with` methods can be staked
-one to another in order to update multiple values.
+one to another to update multiple values.
### :sun_behind_large_cloud: Bot handlers
@@ -453,6 +454,7 @@ or define your own.
package main
import (
+ "context"
"fmt"
"os"
@@ -462,6 +464,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information,
@@ -473,47 +476,46 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Register new handler with match on command `/start`
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// Send message
- _, _ = bot.SendMessage(tu.Message(
+ _, _ = ctx.Bot().SendMessage(ctx, tu.Message(
tu.ID(update.Message.Chat.ID),
fmt.Sprintf("Hello %s!", update.Message.From.FirstName),
))
+ return nil
}, th.CommandEqual("start"))
// Register new handler with match on any command
// Handlers will match only once and in order of registration,
// so this handler will be called on any command except `/start` command
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// Send message
- _, _ = bot.SendMessage(tu.Message(
+ _, _ = ctx.Bot().SendMessage(ctx, tu.Message(
tu.ID(update.Message.Chat.ID),
"Unknown command, use /start",
))
+ return nil
}, th.AnyCommand())
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
```
-Also, just handling updates is useful, but handling specific updates like messages or callback queries in most of the
-cases are more straightforward and provides cleaner code.
+Just handling updates is useful, but handling specific updates like messages or callback queries in most of the
+cases is more straightforward and provides cleaner code.
So Telego provides specific handles for all fields of `telego.Update`. See the list of all available handler types in
-[`telegohandler/update_handlers`](telegohandler/update_handlers.go), or define your own.
+[`telegohandler/handlers`](telegohandler/handlers.go), or define your own.
```go
package main
@@ -531,9 +533,9 @@ func main() {
// (full example in examples/handler_specific/main.go)
// Register new handler with match on command `/start`
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
// Send a message with inline keyboard
- _, _ = bot.SendMessage(tu.Message(
+ _, _ = ctx.Bot().SendMessage(ctx, tu.Message(
tu.ID(message.Chat.ID),
fmt.Sprintf("Hello %s!", message.From.FirstName),
).WithReplyMarkup(tu.InlineKeyboard(
@@ -541,23 +543,26 @@ func main() {
tu.InlineKeyboardButton("Go!").WithCallbackData("go"),
)),
))
+ return nil
}, th.CommandEqual("start"))
// Register new handler with match on the call back query
// with data equal to `go` and non-nil message
- bh.HandleCallbackQuery(func(bot *telego.Bot, query telego.CallbackQuery) {
+ bh.HandleCallbackQuery(func(ctx *th.Context, query telego.CallbackQuery) error {
// Send message
- _, _ = bot.SendMessage(tu.Message(tu.ID(query.Message.Chat.ID), "GO GO GO"))
+ _, _ = ctx.Bot().SendMessage(ctx, tu.Message(tu.ID(query.Message.Chat.ID), "GO GO GO"))
// Answer callback query
- _ = bot.AnswerCallbackQuery(tu.CallbackQuery(query.ID).WithText("Done"))
+ _ = ctx.Bot().AnswerCallbackQuery(ctx, tu.CallbackQuery(query.ID).WithText("Done"))
+
+ return nil
}, th.AnyCallbackQueryWithMessage(), th.CallbackDataEqual("go"))
// ... start bot handler
}
```
-One more important part of handlers are groups and middlewares.
+One more important part of handlers is groups and middlewares.
Telego allows creating groups with and without predicates and attaching middleware to groups.
```go
@@ -574,9 +579,9 @@ func main() {
// Init ...
// Add global middleware, it will be applied in order of addition
- bh.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ bh.Use(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Global middleware") // Will be called first
- next(bot, update)
+ return ctx.Next(update)
})
// Create any groups with or without predicates
@@ -585,20 +590,22 @@ func main() {
task := bh.Group(th.TextContains("task"))
// Add middleware to groups
- task.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ task.Use(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Group-based middleware") // Will be called second
if len(update.Message.Text) < 10 {
- next(bot, update)
+ return ctx.Next(update)
}
+
+ return nil
})
// Handle updates on a group
- task.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ task.HandleMessage(func(ctx *th.Context, message telego.Message) error {
fmt.Println("Task...") // Will be called third
+ return nil
})
}
-
```
### :gear: Build configuration
@@ -615,6 +622,9 @@ Telego supports multiple build configurations via Go's build tags
> Note: Use `sonic` only on supported platforms as it has its own limitations, more
> [here](https://github.com/bytedance/sonic?tab=readme-ov-file#requirement).
+If you wish to set JSON encoding/decoding methods to something custom, there are global methods `SetJSONMarshal` and
+`SetJSONUnmarshal` that can be used.
+
## :art: Contribution
Contribution guidelines listed [here](docs/CONTRIBUTING.md).
diff --git a/Taskfile.yml b/Taskfile.yml
index b280df14..96805e42 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -83,6 +83,12 @@ tasks:
cmds:
- go test -bench=. -benchtime=10s -benchmem
+ vulnerability:
+ desc: "Check for vulnerabilities"
+ deps: [ install:govulncheck ]
+ cmds:
+ - govulncheck -show verbose ./...
+
build:lib:
desc: "Build library"
cmds:
@@ -101,6 +107,14 @@ tasks:
- go list -f "{{"{{if not (or .Main .Indirect)}}{{.Path}}{{end}}"}}" -m all | xargs go get
- go mod tidy
+ update:dependencies:examples:
+ desc: "Update dependencies for examples"
+ dir: ./examples
+ cmds:
+ - go mod tidy
+ - go list -f "{{"{{if not (or .Main .Indirect)}}{{.Path}}{{end}}"}}" -m all | xargs go get
+ - go mod tidy
+
generate:
desc: "Generate (used for mock generation)"
deps: [ install:mock ]
@@ -130,6 +144,7 @@ tasks:
deps:
- install:lint
- install:mock
+ - install:govulncheck
install:lint:
desc: "Install golangci-lint"
@@ -144,3 +159,10 @@ tasks:
- go install go.uber.org/mock/mockgen@latest
status:
- command -v mockgen
+
+ install:govulncheck:
+ desc: "Install govulncheck"
+ cmds:
+ - go install golang.org/x/vuln/cmd/govulncheck@latest
+ status:
+ - command -v govulncheck
diff --git a/bot.go b/bot.go
index 4d4d0a57..c05e8990 100644
--- a/bot.go
+++ b/bot.go
@@ -1,11 +1,14 @@
package telego
import (
+ "context"
"errors"
"fmt"
"reflect"
"regexp"
"strings"
+ "sync"
+ "sync/atomic"
"github.com/valyala/fasthttp"
@@ -25,10 +28,10 @@ const (
botPathPrefix = "/bot"
)
-// ErrEmptyToken Bot token is empty
+// ErrEmptyToken bot token is empty
var ErrEmptyToken = errors.New("telego: empty token")
-// ErrInvalidToken Bot token is invalid according to token regexp
+// ErrInvalidToken bot token is invalid according to token regexp
var ErrInvalidToken = errors.New("telego: invalid token format")
// validateToken validates if token matches format
@@ -46,17 +49,41 @@ type Bot struct {
constructor ta.RequestConstructor
useTestServerPath bool
- healthCheckRequested bool
reportWarningAsErrors bool
- longPollingContext *longPollingContext
- webhookContext *webhookContext
+ running atomic.Int32
+
+ myOnce sync.Once
+ myID int64
+ myUsername string
}
-// BotOption represents an option that can be applied to Bot
+// Bot actions
+const (
+ runningNone = 0
+ runningLongPolling = 1
+ runningWebhook = 2
+)
+
+// run checks if bot is already running some action
+func (b *Bot) run(actionToRun int32) error {
+ if b.running.CompareAndSwap(runningNone, actionToRun) {
+ return nil
+ }
+ switch b.running.Load() {
+ case runningLongPolling:
+ return errors.New("telego: long polling already running")
+ case runningWebhook:
+ return errors.New("telego: webhook already running")
+ default:
+ return errors.New("telego: unknown running state")
+ }
+}
+
+// BotOption represents an option that can be applied to [Bot]
type BotOption func(bot *Bot) error
-// NewBot creates new bots with given options.
+// NewBot creates new bots with given options (order is important).
// If no options are specified, default values are used.
// Note: Default logger (that logs only errors if not configured) will hide your bot token, but it still may log
// sensitive information, it's only safe to use default logger in testing environment.
@@ -78,13 +105,7 @@ func NewBot(token string, options ...BotOption) (*Bot, error) {
for _, option := range options {
if err := option(b); err != nil {
- return nil, fmt.Errorf("telego: options: %w", err)
- }
- }
-
- if b.healthCheckRequested {
- if _, err := b.GetMe(); err != nil {
- return nil, fmt.Errorf("telego: health check: %w", err)
+ return nil, fmt.Errorf("telego: bot options: %w", err)
}
}
@@ -101,7 +122,30 @@ func (b *Bot) Logger() Logger {
return b.log
}
-// FileDownloadURL returns URL used to download file by its file path retrieved from GetFile method
+// updateMe updates bot ID and username
+func (b *Bot) updateMe() {
+ me, err := b.GetMe(context.Background())
+ if err != nil {
+ b.log.Errorf("Error on get me: %s", err)
+ } else {
+ b.myID = me.ID
+ b.myUsername = me.Username
+ }
+}
+
+// ID returns bot ID by calling [Bot.GetMe] method once, if error occurs ID will be 0
+func (b *Bot) ID() int64 {
+ b.myOnce.Do(b.updateMe)
+ return b.myID
+}
+
+// Username returns bot username by calling [Bot.GetMe] method once, if error occurs username will be empty
+func (b *Bot) Username() string {
+ b.myOnce.Do(b.updateMe)
+ return b.myUsername
+}
+
+// FileDownloadURL returns URL that can be used to download a file by its file path retrieved from [Bot.GetFile] method
func (b *Bot) FileDownloadURL(filepath string) string {
if b.useTestServerPath {
return b.apiURL + "/file/bot" + b.token + "/test/" + filepath
@@ -110,8 +154,8 @@ func (b *Bot) FileDownloadURL(filepath string) string {
}
// performRequest executes and parses response of method
-func (b *Bot) performRequest(methodName string, parameters any, vs ...any) error {
- resp, err := b.constructAndCallRequest(methodName, parameters)
+func (b *Bot) performRequest(ctx context.Context, methodName string, parameters any, vs ...any) error {
+ resp, err := b.constructAndCallRequest(ctx, methodName, parameters)
if err != nil {
b.log.Errorf("Execution error %s: %s", methodName, err)
return fmt.Errorf("internal execution: %w", err)
@@ -144,7 +188,7 @@ func (b *Bot) performRequest(methodName string, parameters any, vs ...any) error
}
// constructAndCallRequest creates and executes request with parsing of parameters
-func (b *Bot) constructAndCallRequest(methodName string, parameters any) (*ta.Response, error) {
+func (b *Bot) constructAndCallRequest(ctx context.Context, methodName string, parameters any) (*ta.Response, error) {
filesParams, hasFiles := filesParameters(parameters)
var data *ta.RequestData
@@ -182,7 +226,7 @@ func (b *Bot) constructAndCallRequest(methodName string, parameters any) (*ta.Re
debugData := strings.TrimSuffix(debug.String(), "\n")
b.log.Debugf("API call to: %q, with data: %s", url, debugData)
- resp, err := b.api.Call(url, data)
+ resp, err := b.api.Call(ctx, url, data)
if err != nil {
return nil, fmt.Errorf("request call: %w", err)
}
@@ -269,19 +313,21 @@ func parseField(field reflect.Value) (string, error) {
return value, nil
}
-func isNil(i any) bool {
- if i == nil {
+// isNil checks if the value, or it's underlying interface is nil
+func isNil(v any) bool {
+ if v == nil {
return true
}
- switch reflect.TypeOf(i).Kind() {
- case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
- return reflect.ValueOf(i).IsNil()
+ switch reflect.TypeOf(v).Kind() {
+ case reflect.Interface, reflect.Ptr, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func:
+ return reflect.ValueOf(v).IsNil()
default:
return false
}
}
+// logRequestWithFiles logs request with files
func logRequestWithFiles(debug *strings.Builder, parameters map[string]string, files map[string]ta.NamedReader) {
debugFiles := make([]string, 0, len(files))
for k, v := range files {
@@ -297,7 +343,6 @@ func logRequestWithFiles(debug *strings.Builder, parameters map[string]string, f
}
//nolint:errcheck
debugJSON, _ := json.Marshal(parameters)
-
_, _ = debug.WriteString(fmt.Sprintf("parameters: %s, files: {%s}", debugJSON, strings.Join(debugFiles, ", ")))
}
@@ -305,15 +350,3 @@ func logRequestWithFiles(debug *strings.Builder, parameters map[string]string, f
func ToPtr[T any](value T) *T {
return &value
}
-
-// safeSend safely send to chan and return true if chan was closed
-func safeSend[T any](ch chan<- T, value T) (closed bool) {
- defer func() {
- if recover() != nil {
- closed = true
- }
- }()
-
- ch <- value
- return false
-}
diff --git a/bot_options.go b/bot_options.go
index a280974e..04f2e9d0 100644
--- a/bot_options.go
+++ b/bot_options.go
@@ -1,6 +1,7 @@
package telego
import (
+ "context"
"errors"
"net/http"
"os"
@@ -120,9 +121,16 @@ func WithTestServerPath() BotOption {
}
// WithHealthCheck enables health check using [Bot.GetMe] method on start
-func WithHealthCheck() BotOption {
+func WithHealthCheck(ctx context.Context) BotOption {
return func(bot *Bot) error {
- bot.healthCheckRequested = true
+ me, err := bot.GetMe(ctx)
+ if err != nil {
+ return err
+ }
+
+ bot.myOnce.Do(func() {})
+ bot.myID = me.ID
+ bot.myUsername = me.Username
return nil
}
}
diff --git a/bot_options_test.go b/bot_options_test.go
index 49c4aaff..740fd1da 100644
--- a/bot_options_test.go
+++ b/bot_options_test.go
@@ -1,6 +1,8 @@
package telego
import (
+ "bytes"
+ "context"
"net/http"
"strings"
"testing"
@@ -8,13 +10,16 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/valyala/fasthttp"
+ "go.uber.org/mock/gomock"
+ "github.com/mymmrac/telego/internal/json"
ta "github.com/mymmrac/telego/telegoapi"
+ mockapi "github.com/mymmrac/telego/telegoapi/mock"
)
type testCallerType struct{}
-func (c testCallerType) Call(_ string, _ *ta.RequestData) (*ta.Response, error) {
+func (c testCallerType) Call(_ context.Context, _ string, _ *ta.RequestData) (*ta.Response, error) {
panic("implement me")
}
@@ -177,12 +182,38 @@ func TestWithTestServerPath(t *testing.T) {
}
func TestWithHealthCheck(t *testing.T) {
- bot := &Bot{}
-
- err := WithHealthCheck()(bot)
+ ctrl := gomock.NewController(t)
+
+ caller := mockapi.NewMockCaller(ctrl)
+ constructor := mockapi.NewMockRequestConstructor(ctrl)
+
+ expectedResp := &ta.Response{
+ Ok: true,
+ Result: json.RawMessage(`{}`),
+ }
+
+ expectedData := &ta.RequestData{
+ ContentType: ta.ContentTypeJSON,
+ Buffer: bytes.NewBuffer([]byte{}),
+ }
+
+ constructor.EXPECT().
+ JSONRequest(nil).
+ Return(expectedData, nil).
+ Times(1)
+
+ caller.EXPECT().
+ Call(testCtx, defaultBotAPIServer+botPathPrefix+token+"/getMe", expectedData).
+ Return(expectedResp, nil).
+ Times(1)
+
+ bot, err := NewBot(token,
+ WithAPICaller(caller),
+ WithRequestConstructor(constructor),
+ WithHealthCheck(testCtx),
+ )
require.NoError(t, err)
-
- assert.True(t, bot.healthCheckRequested)
+ require.NotNil(t, bot)
}
func TestWithWarnings(t *testing.T) {
diff --git a/bot_test.go b/bot_test.go
index 9d477684..5b9546dd 100644
--- a/bot_test.go
+++ b/bot_test.go
@@ -100,7 +100,8 @@ func TestNewBot(t *testing.T) {
t.Run("success", func(t *testing.T) {
expectedResp := &ta.Response{
- Ok: true,
+ Ok: true,
+ Result: json.RawMessage(`{}`),
}
constructor.EXPECT().
@@ -109,11 +110,15 @@ func TestNewBot(t *testing.T) {
Times(1)
caller.EXPECT().
- Call(defaultBotAPIServer+botPathPrefix+token+"/getMe", expectedData).
+ Call(testCtx, defaultBotAPIServer+botPathPrefix+token+"/getMe", expectedData).
Return(expectedResp, nil).
Times(1)
- bot, err := NewBot(token, WithHealthCheck(), WithAPICaller(caller), WithRequestConstructor(constructor))
+ bot, err := NewBot(token,
+ WithAPICaller(caller),
+ WithRequestConstructor(constructor),
+ WithHealthCheck(testCtx),
+ )
require.NoError(t, err)
assert.NotNil(t, bot)
@@ -131,11 +136,15 @@ func TestNewBot(t *testing.T) {
Times(1)
caller.EXPECT().
- Call(defaultBotAPIServer+botPathPrefix+token+"/getMe", expectedData).
+ Call(testCtx, defaultBotAPIServer+botPathPrefix+token+"/getMe", expectedData).
Return(expectedResp, nil).
Times(1)
- bot, err := NewBot(token, WithHealthCheck(), WithAPICaller(caller), WithRequestConstructor(constructor))
+ bot, err := NewBot(token,
+ WithAPICaller(caller),
+ WithRequestConstructor(constructor),
+ WithHealthCheck(testCtx),
+ )
require.Error(t, err)
assert.Nil(t, bot)
@@ -420,11 +429,11 @@ func TestBot_constructAndCallRequest(t *testing.T) {
Times(1)
m.MockAPICaller.EXPECT().
- Call(url, expectedData).
+ Call(testCtx, url, expectedData).
Return(expectedResp, nil).
Times(1)
- resp, err := m.Bot.constructAndCallRequest(methodName, params)
+ resp, err := m.Bot.constructAndCallRequest(testCtx, methodName, params)
require.NoError(t, err)
assert.Equal(t, expectedResp, resp)
})
@@ -435,7 +444,7 @@ func TestBot_constructAndCallRequest(t *testing.T) {
Return(nil, errTest).
Times(1)
- resp, err := m.Bot.constructAndCallRequest(methodName, params)
+ resp, err := m.Bot.constructAndCallRequest(testCtx, methodName, params)
require.ErrorIs(t, err, errTest)
assert.Nil(t, resp)
})
@@ -460,11 +469,11 @@ func TestBot_constructAndCallRequest(t *testing.T) {
Times(1)
m.MockAPICaller.EXPECT().
- Call(url, expectedDataFile).
+ Call(testCtx, url, expectedDataFile).
Return(expectedResp, nil).
Times(1)
- resp, err := m.Bot.constructAndCallRequest(methodName, paramsFile)
+ resp, err := m.Bot.constructAndCallRequest(testCtx, methodName, paramsFile)
require.NoError(t, err)
assert.Equal(t, expectedResp, resp)
})
@@ -480,7 +489,7 @@ func TestBot_constructAndCallRequest(t *testing.T) {
Return(nil, errTest).
Times(1)
- resp, err := m.Bot.constructAndCallRequest(methodName, paramsFile)
+ resp, err := m.Bot.constructAndCallRequest(testCtx, methodName, paramsFile)
require.Error(t, err)
assert.Nil(t, resp)
})
@@ -488,7 +497,7 @@ func TestBot_constructAndCallRequest(t *testing.T) {
t.Run("error_multipart_params", func(t *testing.T) {
notStruct := notStructParamsWithFile("test")
- resp, err := m.Bot.constructAndCallRequest(methodName, ¬Struct)
+ resp, err := m.Bot.constructAndCallRequest(testCtx, methodName, ¬Struct)
require.Error(t, err)
assert.Nil(t, resp)
})
@@ -500,11 +509,11 @@ func TestBot_constructAndCallRequest(t *testing.T) {
Times(1)
m.MockAPICaller.EXPECT().
- Call(url, expectedData).
+ Call(testCtx, url, expectedData).
Return(nil, errTest).
Times(1)
- resp, err := m.Bot.constructAndCallRequest(methodName, params)
+ resp, err := m.Bot.constructAndCallRequest(testCtx, methodName, params)
require.Error(t, err)
assert.Nil(t, resp)
})
@@ -529,14 +538,14 @@ func TestBot_performRequest(t *testing.T) {
Times(1)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(&ta.Response{
Ok: true,
Result: bytes.NewBufferString("1").Bytes(),
Error: nil,
}, nil)
- err := m.Bot.performRequest(methodName, params, &result)
+ err := m.Bot.performRequest(testCtx, methodName, params, &result)
require.NoError(t, err)
assert.Equal(t, 1, result)
})
@@ -551,14 +560,14 @@ func TestBot_performRequest(t *testing.T) {
Times(1)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(&ta.Response{
Ok: true,
Result: bytes.NewBufferString("true").Bytes(),
Error: nil,
}, nil)
- err := m.Bot.performRequest(methodName, params, &result1, &result2)
+ err := m.Bot.performRequest(testCtx, methodName, params, &result1, &result2)
require.NoError(t, err)
assert.Equal(t, 0, result1)
assert.True(t, result2)
@@ -573,14 +582,14 @@ func TestBot_performRequest(t *testing.T) {
Times(1)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(&ta.Response{
Ok: false,
Result: nil,
Error: &ta.Error{},
}, nil)
- err := m.Bot.performRequest(methodName, params, &result)
+ err := m.Bot.performRequest(testCtx, methodName, params, &result)
require.Error(t, err)
})
@@ -592,7 +601,7 @@ func TestBot_performRequest(t *testing.T) {
Return(nil, errTest).
Times(1)
- err := m.Bot.performRequest(methodName, params, &result)
+ err := m.Bot.performRequest(testCtx, methodName, params, &result)
require.Error(t, err)
})
@@ -603,7 +612,7 @@ func TestBot_performRequest(t *testing.T) {
Times(1)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(&ta.Response{
Ok: true,
Result: bytes.NewBufferString("1").Bytes(),
@@ -611,7 +620,7 @@ func TestBot_performRequest(t *testing.T) {
}, nil)
var stringResult string
- err := m.Bot.performRequest(methodName, params, &stringResult)
+ err := m.Bot.performRequest(testCtx, methodName, params, &stringResult)
require.Error(t, err)
assert.Equal(t, "", stringResult)
})
@@ -625,14 +634,14 @@ func TestBot_performRequest(t *testing.T) {
Times(1)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(&ta.Response{
Ok: true,
Result: bytes.NewBufferString("1").Bytes(),
Error: &ta.Error{ErrorCode: 1},
}, nil)
- err := m.Bot.performRequest(methodName, params, &result)
+ err := m.Bot.performRequest(testCtx, methodName, params, &result)
assert.Equal(t, &ta.Error{ErrorCode: 1}, err)
assert.Equal(t, 1, result)
})
diff --git a/common_test.go b/common_test.go
index dbf5bd24..2ec46e99 100644
--- a/common_test.go
+++ b/common_test.go
@@ -1,8 +1,6 @@
package telego
import (
- "fmt"
- "sync"
"testing"
"github.com/stretchr/testify/require"
@@ -22,21 +20,8 @@ var (
expectedMessage = &Message{
MessageID: 1,
}
-
- testPortStart = 3100
- testPortLock = sync.Mutex{}
)
-func testAddress(t *testing.T) string {
- t.Helper()
-
- testPortLock.Lock()
- defer testPortLock.Unlock()
-
- testPortStart++
- return fmt.Sprintf("127.0.0.1:%d", testPortStart)
-}
-
func telegoResponse(t *testing.T, v any) *ta.Response {
t.Helper()
diff --git a/doc.go b/doc.go
index 244e9b1e..71fa08de 100644
--- a/doc.go
+++ b/doc.go
@@ -1,5 +1,5 @@
/*
-Package telego provides one-to-one Telegram Bot API method & types.
+Package telego provides one-to-one Telegram Bot API method and types.
Telego features all methods and types described in official Telegram documentation (https://core.telegram.org/bots/api).
It achieves this by generating methods and types from docs (generation is in internal/generator package).
@@ -12,12 +12,12 @@ immediately know how to implement that in Go using Telego.
All types named and contain the same information as documented by Telegram, for methods it's exactly the same.
However, some minor differences may be present (like use of interfaces or combined types).
Also, all generated codes have the same description as in Telegram docs, so there is actually no need to go to docs (but
-still, be careful as it is not a full copy of docs due to text only limitation).
+still, be careful as it is not a full copy of docs due to text-only limitation).
Telego was also created to simplify work with a Telegram API, so some additional methods for more convenient usage
located in long_polling.go and webhook.go and telegoutil package.
-When you are working with things like chat ID which can be an integer or string Telego provides combined types:
+When you are working with things like chat ID which can be an integer or string, Telego provides combined types:
type ChatID struct {
ID int64
@@ -34,18 +34,18 @@ or input files that can be URL, file ID or actual file data:
you will specify only one of the fields and Telego will figure out what to do with that.
-For more flexibility, file data for InputFile are provided via simple interface:
+For more flexibility, file data for [InputFile] are provided via simple interface:
type NamedReader interface {
io.Reader
Name() string
}
-os.File already implements this interface, so you can use it directly.
+[os.File] already implements this interface, so you can use it directly.
# Example
-Most of the examples can be seen in examples folder.
+Most of the examples can be seen in the examples folder.
Simple echo bot:
@@ -60,6 +60,7 @@ Simple echo bot:
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Create Bot with debug on
@@ -70,10 +71,7 @@ Simple echo bot:
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
-
- // Stop reviving updates from updates channel
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Loop through all updates when they came
for update := range updates {
@@ -83,7 +81,7 @@ Simple echo bot:
chatID := tu.ID(update.Message.Chat.ID)
// Copy sent message back to user
- _, _ = bot.CopyMessage(&telego.CopyMessageParams{
+ _, _ = bot.CopyMessage(ctx, &telego.CopyMessageParams{
ChatID: chatID,
FromChatID: chatID,
MessageID: update.Message.MessageID,
diff --git a/examples/basic/main.go b/examples/basic/main.go
index 0b4ce5b9..9eac5d53 100644
--- a/examples/basic/main.go
+++ b/examples/basic/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -21,7 +22,7 @@ func main() {
}
// Call method getMe (https://core.telegram.org/bots/api#getme)
- botUser, err := bot.GetMe()
+ botUser, err := bot.GetMe(context.Background())
if err != nil {
fmt.Println("Error:", err)
}
diff --git a/examples/configuration/main.go b/examples/configuration/main.go
index 8bec748a..aa10bd41 100644
--- a/examples/configuration/main.go
+++ b/examples/configuration/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"net/http"
"os"
@@ -28,7 +29,7 @@ func main() {
telego.WithHTTPClient(&http.Client{}),
// Enables basic health check that will call getMe method before returning bot instance (default: false)
- telego.WithHealthCheck(),
+ telego.WithHealthCheck(context.Background()),
// Make all warnings an errors for all requests (default: false)
// Note: Things like `deleteWebhook` may return a result as true, but also error description with warning
@@ -61,6 +62,6 @@ func main() {
}
// Call method getMe
- botUser, _ := bot.GetMe()
+ botUser, _ := bot.GetMe(context.Background())
fmt.Printf("Bot user: %+v\n", botUser)
}
diff --git a/examples/conversation_bot/main.go b/examples/conversation_bot/main.go
index fd205c38..742537a7 100644
--- a/examples/conversation_bot/main.go
+++ b/examples/conversation_bot/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"net/mail"
"os"
@@ -32,6 +33,7 @@ type User struct {
}
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Create Bot with debug on
@@ -43,7 +45,7 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler
bh, _ := th.NewBotHandler(bot, updates)
@@ -55,7 +57,7 @@ func main() {
lock := sync.RWMutex{}
// Handle any message
- bh.HandleMessage(func(bot *telego.Bot, msg telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, msg telego.Message) error {
userID := msg.From.ID
lock.RLock()
@@ -117,13 +119,13 @@ func main() {
users[userID] = user
lock.Unlock()
- _, _ = bot.SendMessage(tu.Message(msg.Chat.ChatID(), text))
+ _, _ = bot.SendMessage(ctx, tu.Message(msg.Chat.ChatID(), text))
+ return nil
})
// Stop handling updates on exit
- defer bh.Stop()
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
diff --git a/examples/download_file/main.go b/examples/download_file/main.go
index 4d8f3b0d..db40f6b8 100644
--- a/examples/download_file/main.go
+++ b/examples/download_file/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -25,11 +27,11 @@ func main() {
)
// Send a test document
- msg, _ := bot.SendDocument(document)
+ msg, _ := bot.SendDocument(ctx, document)
// Get file info
// Note: File ID used to get info is only valid for temporary time
- file, _ := bot.GetFile(&telego.GetFileParams{
+ file, _ := bot.GetFile(ctx, &telego.GetFileParams{
FileID: msg.Document.FileID,
})
diff --git a/examples/echo_bot/main.go b/examples/echo_bot/main.go
index 247193b8..58b66095 100644
--- a/examples/echo_bot/main.go
+++ b/examples/echo_bot/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Create Bot with debug on
@@ -20,10 +22,7 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
-
- // Stop reviving updates from update channel
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Loop through all updates when they came
for update := range updates {
@@ -33,7 +32,7 @@ func main() {
chatID := tu.ID(update.Message.Chat.ID)
// Copy sent messages back to the user
- _, _ = bot.CopyMessage(
+ _, _ = bot.CopyMessage(ctx,
tu.CopyMessage(
chatID,
chatID,
diff --git a/examples/echo_bot_with_handlers/main.go b/examples/echo_bot_with_handlers/main.go
index d0c5dba9..184a056c 100644
--- a/examples/echo_bot_with_handlers/main.go
+++ b/examples/echo_bot_with_handlers/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -10,6 +11,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Create Bot with debug on
@@ -21,7 +23,7 @@ func main() {
}
// Get bot user
- botUser, err := bot.GetMe()
+ botUser, err := bot.GetMe(ctx)
if err != nil {
fmt.Println(err)
os.Exit(1)
@@ -30,26 +32,25 @@ func main() {
fmt.Printf("Bot user: %+v\n", botUser)
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler
bh, _ := th.NewBotHandler(bot, updates)
// Handle any message
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
// Get chat ID from the message
chatID := tu.ID(message.Chat.ID)
// Copy sent messages back to the user
- _, _ = bot.CopyMessage(
- tu.CopyMessage(chatID, chatID, message.MessageID),
- )
+ _, _ = bot.CopyMessage(ctx, tu.CopyMessage(chatID, chatID, message.MessageID))
+
+ return nil
})
// Stop handling updates on exit
- defer bh.Stop()
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
diff --git a/examples/edit_message/main.go b/examples/edit_message/main.go
index 432a4569..69fc3220 100644
--- a/examples/edit_message/main.go
+++ b/examples/edit_message/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -19,7 +21,7 @@ func main() {
}
// Edit message text
- _, _ = bot.EditMessageText(&telego.EditMessageTextParams{
+ _, _ = bot.EditMessageText(ctx, &telego.EditMessageTextParams{
ChatID: tu.ID(1234567),
MessageID: 1234, // Message ID can be retried when it's sent or with update
Text: "New text
",
@@ -27,7 +29,7 @@ func main() {
})
// Edit message caption & reply markup (inline keyboard)
- _, _ = bot.EditMessageCaption(&telego.EditMessageCaptionParams{
+ _, _ = bot.EditMessageCaption(ctx, &telego.EditMessageCaptionParams{
ChatID: tu.ID(1234567),
MessageID: 1234, // Message ID can be retried when it's sent or with update
Caption: "New caption",
@@ -39,7 +41,7 @@ func main() {
})
// Edit message photo
- _, _ = bot.EditMessageMedia(&telego.EditMessageMediaParams{
+ _, _ = bot.EditMessageMedia(ctx, &telego.EditMessageMediaParams{
ChatID: tu.ID(1234567),
MessageID: 1234, // Message ID can be retried when it's sent or with update
Media: tu.MediaPhoto(tu.File(mustOpen("photo.png"))),
diff --git a/examples/go.mod b/examples/go.mod
index 3576ba6e..7b340cc7 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -1,19 +1,18 @@
module github.com/mymmrac/telego/examples
-go 1.22.6
+go 1.23.4
require (
- github.com/fasthttp/router v1.5.4
- github.com/mymmrac/telego v0.32.0
- github.com/valyala/fasthttp v1.58.0
- golang.ngrok.com/ngrok v1.11.0
+ github.com/mymmrac/telego v0.32.1-0.20250203211309-2f8d8f9e7e05
+ github.com/valyala/fasthttp v1.59.0
+ golang.ngrok.com/ngrok v1.13.0
)
require (
github.com/andybalholm/brotli v1.1.1 // indirect
- github.com/bytedance/sonic v1.12.7 // indirect
+ github.com/bytedance/sonic v1.12.8 // indirect
github.com/bytedance/sonic/loader v0.2.2 // indirect
- github.com/cloudwego/base64x v0.1.4 // indirect
+ github.com/cloudwego/base64x v0.1.5 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/grbit/go-json v0.11.0 // indirect
github.com/inconshreveable/log15 v3.0.0-testing.5+incompatible // indirect
@@ -21,22 +20,19 @@ require (
github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
- github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/rogpeppe/go-internal v1.12.0 // indirect
- github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
go.uber.org/multierr v1.11.0 // indirect
- golang.ngrok.com/muxado/v2 v2.0.0 // indirect
+ golang.ngrok.com/muxado/v2 v2.0.1 // indirect
golang.org/x/arch v0.6.0 // indirect
- golang.org/x/net v0.31.0 // indirect
+ golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.8.0 // indirect
- golang.org/x/sys v0.27.0 // indirect
- golang.org/x/term v0.26.0 // indirect
- google.golang.org/protobuf v1.34.2 // indirect
+ golang.org/x/sys v0.30.0 // indirect
+ golang.org/x/term v0.29.0 // indirect
+ google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/examples/go.sum b/examples/go.sum
index 11c2caac..32baffff 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -1,19 +1,16 @@
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
-github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
-github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I=
+github.com/bytedance/sonic v1.12.8 h1:4xYRVRlXIgvSZ4e8iVTlMF5szgpXd4AfvuWgA8I8lgs=
+github.com/bytedance/sonic v1.12.8/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
-github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
-github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
+github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
+github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fasthttp/router v1.5.4 h1:oxdThbBwQgsDIYZ3wR1IavsNl6ZS9WdjKukeMikOnC8=
-github.com/fasthttp/router v1.5.4/go.mod h1:3/hysWq6cky7dTfzaaEPZGdptwjwx0qzTgFCKEWRjgc=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
@@ -34,23 +31,15 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mymmrac/telego v0.32.0 h1:4X8C1l3k+opkk86r95+eQE8DxiS2LYlR61L/G7yreDY=
-github.com/mymmrac/telego v0.32.0/go.mod h1:qS6NaRhJgcuEEBEMVCV79S2xCAuHq9O+ixwfLuRW31M=
+github.com/mymmrac/telego v0.32.1-0.20250203211309-2f8d8f9e7e05 h1:Y/mssuzk/lzo5iu9gKmh9asO+4TOIDySsfdR2LimJwM=
+github.com/mymmrac/telego v0.32.1-0.20250203211309-2f8d8f9e7e05/go.mod h1:vxWyqSoZbh8OKS6jE3u4yoS71N3jWUqxDv9wr1DSr3Q=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
-github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -64,8 +53,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE=
-github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw=
+github.com/valyala/fasthttp v1.59.0 h1:Qu0qYHfXvPk1mSLNqcFtEk6DpxgA26hy6bmydotDpRI=
+github.com/valyala/fasthttp v1.59.0/go.mod h1:GTxNb9Bc6r2a9D0TWNSPwDz78UxnTGBViY3xZNEqyYU=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
@@ -74,32 +63,31 @@ go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-golang.ngrok.com/muxado/v2 v2.0.0 h1:bu9eIDhRdYNtIXNnqat/HyMeHYOAbUH55ebD7gTvW6c=
-golang.ngrok.com/muxado/v2 v2.0.0/go.mod h1:wzxJYX4xiAtmwumzL+QsukVwFRXmPNv86vB8RPpOxyM=
-golang.ngrok.com/ngrok v1.11.0 h1:lvbBcoOvH+Ek15wgrjvxpCB+PBM7vinU6jQPsrCdOLw=
-golang.ngrok.com/ngrok v1.11.0/go.mod h1:1/gLOyOJm7ygHJlcEbtldFLQwQnQ42z+rucpLE2YsvA=
+golang.ngrok.com/muxado/v2 v2.0.1 h1:jM9i6Pom6GGmnPrHKNR6OJRrUoHFkSZlJ3/S0zqdVpY=
+golang.ngrok.com/muxado/v2 v2.0.1/go.mod h1:wzxJYX4xiAtmwumzL+QsukVwFRXmPNv86vB8RPpOxyM=
+golang.ngrok.com/ngrok v1.13.0 h1:6SeOS+DAeIaHlkDmNH5waFHv0xjlavOV3wml0Z59/8k=
+golang.ngrok.com/ngrok v1.13.0/go.mod h1:BKOMdoZXfD4w6o3EtE7Cu9TVbaUWBqptrZRWnVcAuI4=
golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
-golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
-golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
-golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
-golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
+golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
+golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
-golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
-golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
+golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
+google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/examples/graceful_shutdown_long_polling/main.go b/examples/graceful_shutdown_long_polling/main.go
index 522193ce..0d756f33 100644
--- a/examples/graceful_shutdown_long_polling/main.go
+++ b/examples/graceful_shutdown_long_polling/main.go
@@ -22,39 +22,46 @@ func main() {
}
// Initialize signal handling
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, os.Interrupt)
-
- // Initialize done chan
- done := make(chan struct{}, 1)
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+ defer cancel()
// Get updates
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler with stop timeout
bh, _ := th.NewBotHandler(bot, updates)
// Handle updates
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Processing update:", update.UpdateID)
time.Sleep(time.Second * 15) // Simulate long process time
fmt.Println("Done update:", update.UpdateID)
+ return nil
})
+ // Initialize done chan
+ done := make(chan struct{}, 1)
+
// Handle stop signal (Ctrl+C)
go func() {
// Wait for stop signal
- <-sigs
-
+ <-ctx.Done()
fmt.Println("Stopping...")
- ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
- defer cancel()
-
- bot.StopLongPolling()
+ stopCtx, stopCancel := context.WithTimeout(context.Background(), time.Second*20)
+ defer stopCancel()
+
+ for len(updates) > 0 {
+ select {
+ case <-stopCtx.Done():
+ break
+ case <-time.After(time.Microsecond * 100):
+ // Continue
+ }
+ }
fmt.Println("Long polling done")
- bh.StopWithContext(ctx)
+ _ = bh.StopWithContext(stopCtx)
fmt.Println("Bot handler done")
// Notify that stop is done
@@ -62,7 +69,7 @@ func main() {
}()
// Start handling in goroutine
- go bh.Start()
+ go func() { _ = bh.Start() }()
fmt.Println("Handling updates...")
// Wait for the stop process to be completed
diff --git a/examples/graceful_shutdown_no_helpers/main.go b/examples/graceful_shutdown_no_helpers/main.go
index 551cc593..6573af6f 100644
--- a/examples/graceful_shutdown_no_helpers/main.go
+++ b/examples/graceful_shutdown_no_helpers/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
"os/signal"
@@ -20,8 +21,8 @@ func main() {
}
// Initialize signal handling
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, os.Interrupt)
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+ defer cancel()
// Initialize done chan
done := make(chan struct{}, 1)
@@ -32,22 +33,22 @@ func main() {
// Handle stop signal (Ctrl+C)
go func() {
// Wait for stop signal
- <-sigs
-
+ <-ctx.Done()
fmt.Println("Stopping...")
- bot.StopLongPolling()
- fmt.Println("Long polling done")
-
- <-updatesProcessed
- fmt.Println("Updates processed")
+ select {
+ case <-updatesProcessed:
+ fmt.Println("Updates processed")
+ case <-time.After(time.Second * 20):
+ // Timeout
+ }
// Notify that stop is done
done <- struct{}{}
}()
// Get updates
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Handle updates
go func() {
diff --git a/examples/graceful_shutdown_webhook/main.go b/examples/graceful_shutdown_webhook/main.go
index ca02d096..5ef5d402 100644
--- a/examples/graceful_shutdown_webhook/main.go
+++ b/examples/graceful_shutdown_webhook/main.go
@@ -9,6 +9,7 @@ import (
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
+ "github.com/valyala/fasthttp"
)
func main() {
@@ -22,39 +23,52 @@ func main() {
}
// Initialize signal handling
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, os.Interrupt)
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+ defer cancel()
// Initialize done chan
done := make(chan struct{}, 1)
+ // Create HTTP server
+ srv := &fasthttp.Server{}
+
// Get updates
- updates, _ := bot.UpdatesViaWebhook("/bot" + bot.Token())
+ updates, _ := bot.UpdatesViaWebhook(ctx, telego.WebhookFastHTTP(srv, "/bot", bot.Token()))
- // Create bot handler with stop timeout
+ // Create bot handler
bh, _ := th.NewBotHandler(bot, updates)
// Handle updates
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Processing update:", update.UpdateID)
time.Sleep(time.Second * 5) // Simulate long process time
fmt.Println("Done update:", update.UpdateID)
+ return nil
})
// Handle stop signal (Ctrl+C)
go func() {
// Wait for stop signal
- <-sigs
-
+ <-ctx.Done()
fmt.Println("Stopping...")
- ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
- defer cancel()
+ stopCtx, stopCancel := context.WithTimeout(context.Background(), time.Second*20)
+ defer stopCancel()
+
+ _ = srv.ShutdownWithContext(stopCtx)
+ fmt.Println("Server done")
- _ = bot.StopWebhookWithContext(ctx)
+ for len(updates) > 0 {
+ select {
+ case <-stopCtx.Done():
+ break
+ case <-time.After(time.Microsecond * 100):
+ // Continue
+ }
+ }
fmt.Println("Webhook done")
- bh.StopWithContext(ctx)
+ _ = bh.StopWithContext(stopCtx)
fmt.Println("Bot handler done")
// Notify that stop is done
@@ -62,13 +76,11 @@ func main() {
}()
// Start handling in goroutine
- go bh.Start()
+ go func() { _ = bh.Start() }()
fmt.Println("Handling updates...")
// Start server for receiving requests from the Telegram
- go func() {
- _ = bot.StartWebhook("localhost:443")
- }()
+ go func() { _ = srv.ListenAndServe(":443") }()
// Wait for the stop process to be completed
<-done
diff --git a/examples/handler/main.go b/examples/handler/main.go
index f29dd458..afe86e06 100644
--- a/examples/handler/main.go
+++ b/examples/handler/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -10,6 +11,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -20,37 +22,36 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
- // Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
-
// Register new handler with match on command `/start`
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// Send message
- _, _ = bot.SendMessage(tu.Messagef(
+ _, _ = bot.SendMessage(ctx, tu.Messagef(
tu.ID(update.Message.Chat.ID),
"Hello %s!", update.Message.From.FirstName,
))
+ return nil
}, th.CommandEqual("start"))
// Register new handler with match on any command
// Handlers will match only once and in order of registration, so this handler will be called on any command except
// `/start` command
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// Send message
- _, _ = bot.SendMessage(tu.Message(
+ _, _ = bot.SendMessage(ctx, tu.Message(
tu.ID(update.Message.Chat.ID),
"Unknown command, use /start",
))
+ return nil
}, th.AnyCommand())
+ // Stop handling updates
+ defer func() { _ = bh.Stop() }()
+
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
diff --git a/examples/handler_custom/main.go b/examples/handler_custom/main.go
index f36dca8a..50b885e0 100644
--- a/examples/handler_custom/main.go
+++ b/examples/handler_custom/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -19,40 +21,40 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Register a handler with union predicate and not predicate
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Update with message text `Hmm?` or any other, but without message.")
+ return nil
}, th.Or(
th.Not(th.AnyMessage()), // Matches to any not message update
th.TextEqual("Hmm?"), // Matches to message update with a text `Hmm?`
))
// Register handler with message predicate and custom predicate
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Update with the message which text is longer than 7 chars.")
+ return nil
},
th.AnyMessage(), // Matches to any message update
- func(update telego.Update) bool { // Matches to message update with text longer then 7
+ func(ctx context.Context, update telego.Update) bool { // Matches to message update with text longer then 7
return len(update.Message.Text) > 7
},
)
// Register handler with commands and specific args
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Update with command `start` without args or `help` with any args")
+ return nil
}, th.TextContains("one"), th.TextPrefix("two"), th.TextSuffix("three"))
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
diff --git a/examples/handler_groups_and_middleware/main.go b/examples/handler_groups_and_middleware/main.go
index 98cd8de7..d953d69c 100644
--- a/examples/handler_groups_and_middleware/main.go
+++ b/examples/handler_groups_and_middleware/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -19,27 +21,24 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Add global middleware, it will be applied in order of addition
bh.Use(th.PanicRecovery()) // Will be called first
bh.Use(
- func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ func(ctx *th.Context, update telego.Update) error {
fmt.Println("Global middleware") // Will be called second
- next(bot, update)
+ return ctx.Next(update)
},
- func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ func(ctx *th.Context, update telego.Update) error {
fmt.Println("Global middleware 2") // Will be called third
- next(bot, update)
+ return ctx.Next(update)
},
)
@@ -48,19 +47,22 @@ func main() {
task := bh.Group(th.TextContains("task"))
// Add middleware to groups
- task.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ task.Use(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Group-based middleware") // Will be called fourth
if len(update.Message.Text) < 10 {
- next(bot, update)
+ return ctx.Next(update)
}
+
+ return nil
})
// Handle updates on a group
- task.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ task.HandleMessage(func(ctx *th.Context, message telego.Message) error {
fmt.Println("Task...") // Will be called fifth
+ return err
})
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
diff --git a/examples/handler_ordering/main.go b/examples/handler_ordering/main.go
index e1a05a55..735e58d1 100644
--- a/examples/handler_ordering/main.go
+++ b/examples/handler_ordering/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -18,20 +20,18 @@ func main() {
os.Exit(1)
}
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Should not be here, because the order of handlers does meter.
//
- // bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ // bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
// fmt.Println("Message:", message.Text)
+ // return nil
// })
//
// When you are defining handlers only the first matched handler will process update, that means that in this
@@ -42,15 +42,17 @@ func main() {
// and only then more generic handlers (like any message).
// Will match any message with command `/start`
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
fmt.Println("Start")
+ return nil
}, th.CommandEqual("start"))
// Will match to any message
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
fmt.Println("Message:", message.Text)
+ return nil
})
// Start handling
- bh.Start()
+ _ = bh.Start()
}
diff --git a/examples/handler_specific/main.go b/examples/handler_specific/main.go
index 8df1fe6c..768bb520 100644
--- a/examples/handler_specific/main.go
+++ b/examples/handler_specific/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -10,6 +11,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -20,37 +22,37 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Register new handler with match on command `/start`
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
// Send a message with inline keyboard
- _, _ = bot.SendMessage(tu.Messagef(
+ _, _ = bot.SendMessage(ctx, tu.Messagef(
tu.ID(message.Chat.ID),
"Hello %s!", message.From.FirstName,
).WithReplyMarkup(tu.InlineKeyboard(
tu.InlineKeyboardRow(tu.InlineKeyboardButton("Go!").WithCallbackData("go"))),
))
+ return nil
}, th.CommandEqual("start"))
// Register new handler with match on a call back query with data equal to `go` and non-nil message
- bh.HandleCallbackQuery(func(bot *telego.Bot, query telego.CallbackQuery) {
+ bh.HandleCallbackQuery(func(ctx *th.Context, query telego.CallbackQuery) error {
// Send message
- _, _ = bot.SendMessage(tu.Message(tu.ID(query.Message.GetChat().ID), "GO"))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(query.Message.GetChat().ID), "GO"))
// Answer callback query
- _ = bot.AnswerCallbackQuery(tu.CallbackQuery(query.ID).WithText("Done"))
+ _ = bot.AnswerCallbackQuery(ctx, tu.CallbackQuery(query.ID).WithText("Done"))
+
+ return nil
}, th.AnyCallbackQueryWithMessage(), th.CallbackDataEqual("go"))
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
diff --git a/examples/handler_with_context/main.go b/examples/handler_with_context/main.go
index 113e2238..307dea08 100644
--- a/examples/handler_with_context/main.go
+++ b/examples/handler_with_context/main.go
@@ -10,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -20,44 +21,37 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Define a context key
type userID bool
var userIDKey userID
// Apply middleware that will retrieve user ID from update
- bh.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
- // Get initial context
- ctx := update.Context()
-
+ bh.Use(func(ctx *th.Context, update telego.Update) error {
if update.Message != nil && update.Message.From != nil {
// Set user ID in context
- ctx = context.WithValue(ctx, userIDKey, update.Message.From.ID)
+ ctx = ctx.WithValue(userIDKey, update.Message.From.ID)
}
// Update context
update = update.WithContext(ctx)
- next(bot, update)
+ return ctx.Next(update)
})
// Handle messages
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
- ctx := update.Context()
-
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// Retrieve user ID from context
fmt.Println("User ID:", ctx.Value(userIDKey))
+ return nil
}, th.AnyMessage())
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
diff --git a/examples/inline_keyboard/main.go b/examples/inline_keyboard/main.go
index f2706596..9c23d2e0 100644
--- a/examples/inline_keyboard/main.go
+++ b/examples/inline_keyboard/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -38,10 +40,9 @@ func main() {
).WithReplyMarkup(inlineKeyboard)
// Sending message
- _, _ = bot.SendMessage(message)
+ _, _ = bot.SendMessage(ctx, message)
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Receiving callback data
for update := range updates {
diff --git a/examples/inline_query_bot/main.go b/examples/inline_query_bot/main.go
index d3d40820..b5130925 100644
--- a/examples/inline_query_bot/main.go
+++ b/examples/inline_query_bot/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -18,8 +20,7 @@ func main() {
os.Exit(1)
}
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
for update := range updates {
// Receive inline query
@@ -28,7 +29,7 @@ func main() {
name := iq.From.FirstName
// Answer inline query request
- _ = bot.AnswerInlineQuery(tu.InlineQuery(
+ _ = bot.AnswerInlineQuery(ctx, tu.InlineQuery(
iq.ID,
tu.ResultArticle(
diff --git a/examples/keyboard/main.go b/examples/keyboard/main.go
index af80856f..d88fab84 100644
--- a/examples/keyboard/main.go
+++ b/examples/keyboard/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -42,5 +43,5 @@ func main() {
).WithReplyMarkup(keyboard)
// Sending message
- _, _ = bot.SendMessage(message)
+ _, _ = bot.SendMessage(context.Background(), message)
}
diff --git a/examples/menu_bot/build_local.go b/examples/menu_bot/build_local.go
index 14b30078..73cd8212 100644
--- a/examples/menu_bot/build_local.go
+++ b/examples/menu_bot/build_local.go
@@ -5,30 +5,19 @@ package main
import (
"context"
"log"
+ "net"
- "github.com/fasthttp/router"
- "github.com/mymmrac/telego"
- "github.com/valyala/fasthttp"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
)
-func Webhook(ctx context.Context, bot *telego.Bot, secret string) (telego.WebhookServer, string) {
- tun, err := ngrok.Listen(ctx, config.HTTPEndpoint(config.WithForwardsTo(":8080")))
+func WebhookListener(ctx context.Context) (net.Listener, string) {
+ tun, err := ngrok.Listen(ctx,
+ config.HTTPEndpoint(config.WithForwardsTo(":8080")),
+ ngrok.WithAuthtokenFromEnv(),
+ )
if err != nil {
log.Fatalf("Ngrok listen: %s", err)
}
-
- srv := &fasthttp.Server{}
- return telego.FuncWebhookServer{
- Server: telego.FastHTTPWebhookServer{
- Logger: bot.Logger(),
- Server: srv,
- Router: router.New(),
- SecretToken: secret,
- },
- StartFunc: func(_ string) error {
- return srv.Serve(tun)
- },
- }, tun.URL()
+ return tun, tun.URL()
}
diff --git a/examples/menu_bot/build_release.go b/examples/menu_bot/build_release.go
index 8e5ddcf1..af5cc4a8 100644
--- a/examples/menu_bot/build_release.go
+++ b/examples/menu_bot/build_release.go
@@ -4,17 +4,14 @@ package main
import (
"context"
-
- "github.com/fasthttp/router"
- "github.com/mymmrac/telego"
- "github.com/valyala/fasthttp"
+ "log"
+ "net"
)
-func Webhook(_ context.Context, bot *telego.Bot, secret string) (telego.WebhookServer, string) {
- return telego.FastHTTPWebhookServer{
- Logger: bot.Logger(),
- Server: &fasthttp.Server{},
- Router: router.New(),
- SecretToken: secret,
- }, "https://example.org"
+func WebhookListener(_ context.Context) (net.Listener, string) {
+ ln, err := net.Listen("tcp", ":443")
+ if err != nil {
+ log.Fatalf("Listen: %s", err)
+ }
+ return ln, "https://example.org"
}
diff --git a/examples/menu_bot/handler.go b/examples/menu_bot/handler.go
index fea89a6a..155ee5a8 100644
--- a/examples/menu_bot/handler.go
+++ b/examples/menu_bot/handler.go
@@ -1,6 +1,7 @@
package main
import (
+ "fmt"
"log"
"github.com/mymmrac/telego"
@@ -8,9 +9,16 @@ import (
tu "github.com/mymmrac/telego/telegoutil"
)
-func RegisterHandlers(bh *th.BotHandler) {
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
- _, err := bot.SendMessage(tu.Message(tu.ID(message.Chat.ID), "Menu").
+func registerHandlers(bh *th.BotHandler) {
+ bh.Use(func(ctx *th.Context, update telego.Update) error {
+ if err := ctx.Next(update); err != nil {
+ log.Printf("Handler error: %s", err)
+ }
+ return nil
+ })
+
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
+ _, err := ctx.Bot().SendMessage(ctx, tu.Message(tu.ID(message.Chat.ID), "Menu").
WithReplyMarkup(tu.Keyboard(
tu.KeyboardRow(
tu.KeyboardButton("Sub menu 1"),
@@ -21,37 +29,41 @@ func RegisterHandlers(bh *th.BotHandler) {
),
).WithResizeKeyboard()))
if err != nil {
- log.Printf("Error on start: %s", err)
+ return fmt.Errorf("start: %w", err)
}
+ return nil
}, th.Or(th.CommandEqual("start"), th.TextEqual("Back")))
subMenu := bh.Group(th.TextPrefix("Sub menu"))
- subMenu.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ subMenu.Use(func(ctx *th.Context, update telego.Update) error {
log.Println("Sub menu group")
- next(bot, update)
+ return ctx.Next(update)
})
- subMenu.HandleMessage(func(bot *telego.Bot, message telego.Message) {
- _, err := bot.SendMessage(tu.Message(tu.ID(message.Chat.ID), "Sub menu 1 content").
+ subMenu.HandleMessage(func(ctx *th.Context, message telego.Message) error {
+ _, err := ctx.Bot().SendMessage(ctx, tu.Message(tu.ID(message.Chat.ID), "Sub menu 1 content").
WithReplyMarkup(tu.Keyboard(tu.KeyboardRow(tu.KeyboardButton("Back"))).WithResizeKeyboard()))
if err != nil {
- log.Printf("Error on sub menu 1: %s", err)
+ return fmt.Errorf("sub menu 1: %w", err)
}
+ return nil
}, th.TextSuffix("1"))
- subMenu.HandleMessage(func(bot *telego.Bot, message telego.Message) {
- _, err := bot.SendMessage(tu.Message(tu.ID(message.Chat.ID), "Sub menu 2 content").
+ subMenu.HandleMessage(func(ctx *th.Context, message telego.Message) error {
+ _, err := ctx.Bot().SendMessage(ctx, tu.Message(tu.ID(message.Chat.ID), "Sub menu 2 content").
WithReplyMarkup(tu.Keyboard(tu.KeyboardRow(tu.KeyboardButton("Back"))).WithResizeKeyboard()))
if err != nil {
- log.Printf("Error on sub menu 2: %s", err)
+ return fmt.Errorf("sub menu 2: %w", err)
}
+ return nil
}, th.TextSuffix("2"))
- subMenu.HandleMessage(func(bot *telego.Bot, message telego.Message) {
- _, err := bot.SendMessage(tu.Message(tu.ID(message.Chat.ID), "Sub menu 3 content").
+ subMenu.HandleMessage(func(ctx *th.Context, message telego.Message) error {
+ _, err := ctx.Bot().SendMessage(ctx, tu.Message(tu.ID(message.Chat.ID), "Sub menu 3 content").
WithReplyMarkup(tu.Keyboard(tu.KeyboardRow(tu.KeyboardButton("Back"))).WithResizeKeyboard()))
if err != nil {
- log.Printf("Error on sub menu 3: %s", err)
+ return fmt.Errorf("sub menu 3: %w", err)
}
+ return nil
}, th.TextSuffix("3"))
}
diff --git a/examples/menu_bot/main.go b/examples/menu_bot/main.go
index 956a3b3c..3287ee02 100644
--- a/examples/menu_bot/main.go
+++ b/examples/menu_bot/main.go
@@ -12,6 +12,7 @@ import (
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
tu "github.com/mymmrac/telego/telegoutil"
+ "github.com/valyala/fasthttp"
)
func main() {
@@ -23,63 +24,85 @@ func main() {
log.Fatalf("Create bot: %s", err)
}
- ctx, cancel := context.WithCancel(context.Background())
+ // Initialize signal handling
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
- // Note: Creating a secret token like this is not secure,
- // but at least better than having a plain bot token as is in requests
+ // Generate secret
secretBytes := sha256.Sum256([]byte(botToken))
secret := hex.EncodeToString(secretBytes[:])
- srv, url := Webhook(ctx, bot, secret)
+ // Create webhook server and listener
+ srv := &fasthttp.Server{}
+ listener, url := WebhookListener(ctx)
- updates, err := bot.UpdatesViaWebhook(
- "/bot",
- telego.WithWebhookServer(srv),
- telego.WithWebhookSet(tu.Webhook(url+"/bot").WithSecretToken(secret)),
+ // Get updates via webhook
+ updates, err := bot.UpdatesViaWebhook(ctx,
+ telego.WebhookFastHTTP(srv, "/bot", secret),
+ telego.WithWebhookSet(ctx, tu.Webhook(url+"/bot").WithSecretToken(secret)),
)
if err != nil {
log.Fatalf("Updates via webhoo: %s", err)
}
+ // Create bot handler
bh, err := th.NewBotHandler(bot, updates)
if err != nil {
- log.Fatalf("Bot handler: %s", err)
+ log.Fatalf("Create bot handler: %s", err)
}
- RegisterHandlers(bh)
+ // Register bot handlers
+ registerHandlers(bh)
+ // Initialize done chan
done := make(chan struct{}, 1)
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, os.Interrupt)
go func() {
- <-sigs
+ // Wait for stop signal
+ <-ctx.Done()
log.Println("Stopping...")
stopCtx, stopCancel := context.WithTimeout(context.Background(), time.Second*10)
defer stopCancel()
- err = bot.StopWebhookWithContext(stopCtx)
- if err != nil {
- log.Println("Failed to stop webhook properly:", err)
+ if err = srv.ShutdownWithContext(stopCtx); err != nil {
+ log.Printf("Failed to shutdown webhook server: %s", err)
+ }
+
+ for len(updates) > 0 {
+ select {
+ case <-stopCtx.Done():
+ break
+ case <-time.After(time.Microsecond * 100):
+ log.Printf("Update handler timeout")
+ }
}
- bh.StopWithContext(stopCtx)
+ if err = bh.StopWithContext(stopCtx); err != nil {
+ log.Printf("Failed to stop bot handler: %s", err)
+ }
+ // Notify that stop is done
done <- struct{}{}
}()
- go bh.Start()
+ // Start handling in goroutine
+ go func() {
+ if startErr := bh.Start(); startErr != nil {
+ log.Fatalf("Failed to start bot handler: %s", startErr)
+ }
+ }()
log.Println("Handling updates...")
+ // Start server for receiving requests from the Telegram
go func() {
- err = bot.StartWebhook(":443")
+ err = srv.Serve(listener)
if err != nil {
- log.Fatalf("Failed to start webhook: %s", err)
+ log.Fatalf("Failed to start webhook server: %s", err)
}
}()
+ // Wait for the stop process to be completed
<-done
log.Println("Done")
}
diff --git a/examples/message_entity/main.go b/examples/message_entity/main.go
index 6a4fdd3f..feecc7ca 100644
--- a/examples/message_entity/main.go
+++ b/examples/message_entity/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -20,7 +21,7 @@ func main() {
}
// Send a message with provided message entities
- _, _ = bot.SendMessage(tu.MessageWithEntities(tu.ID(1234567),
+ _, _ = bot.SendMessage(context.Background(), tu.MessageWithEntities(tu.ID(1234567),
tu.Entity("Hi").Bold(), tu.Entity(" "), tu.Entity("There").Italic().Spoiler(), tu.Entity("\n"),
tu.Entity("The Link").TextLink("https://example.com").Italic(), tu.Entity("\n"),
tu.Entity("User: "), tu.Entity("???").TextMentionWithID(1234567),
diff --git a/examples/methods/main.go b/examples/methods/main.go
index ab7926b9..a4f20d71 100644
--- a/examples/methods/main.go
+++ b/examples/methods/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Create Bot
@@ -20,11 +22,10 @@ func main() {
}
// Call method getMe
- botUser, _ := bot.GetMe()
+ botUser, _ := bot.GetMe(ctx)
fmt.Printf("Bot User: %+v\n", botUser)
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
for update := range updates {
if update.Message != nil {
@@ -33,7 +34,7 @@ func main() {
// Call method sendMessage (https://core.telegram.org/bots/api#sendmessage).
// Send a message to sender with the same text (echo bot).
- sentMessage, _ := bot.SendMessage(
+ sentMessage, _ := bot.SendMessage(ctx,
tu.Message(
tu.ID(chatID),
update.Message.Text,
diff --git a/examples/middleware_with_predicates/main.go b/examples/middleware_with_predicates/main.go
deleted file mode 100644
index 9a07c27d..00000000
--- a/examples/middleware_with_predicates/main.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
-
- "github.com/mymmrac/telego"
- th "github.com/mymmrac/telego/telegohandler"
-)
-
-// ==== DEPRECATED ====
-// See example handler_groups_and_middleware/main.go for a proper way of middleware implementation.
-// ====================
-
-func main() {
- botToken := os.Getenv("TOKEN")
-
- // Note: Please keep in mind that default logger may expose sensitive information, use in development only
- bot, err := telego.NewBot(botToken, telego.WithDefaultDebugLogger())
- if err != nil {
- fmt.Println(err)
- os.Exit(1)
- }
-
- // Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
-
- // Create bot handler and specify from where to get updates
- bh, _ := th.NewBotHandler(bot, updates)
-
- // Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
-
- // Define auth predicate
- auth := func(update telego.Update) bool {
- var userID int64
-
- // Get user ID from the message
- if update.Message != nil && update.Message.From != nil {
- userID = update.Message.From.ID
- }
-
- // Get user ID from the callback query
- if update.CallbackQuery != nil {
- userID = update.CallbackQuery.From.ID
- }
-
- // Reject if no user
- if userID == 0 {
- return false
- }
-
- // Accept
- if userID == 1234 {
- return true
- }
-
- return false
- }
-
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
- // DO AUTHORIZED STUFF...
- }, auth) // Check for authorization
-
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
- // DO NOT AUTHORIZED STUFF...
- }, th.Not(auth)) // Process unauthorized update
-
- // Start handling updates
- bh.Start()
-}
diff --git a/examples/multi_bot_webhook/main.go b/examples/multi_bot_webhook/main.go
index 899fb007..9d05df1a 100644
--- a/examples/multi_bot_webhook/main.go
+++ b/examples/multi_bot_webhook/main.go
@@ -1,16 +1,16 @@
package main
import (
+ "context"
"fmt"
+ "net/http"
"os"
- "github.com/fasthttp/router"
- "github.com/valyala/fasthttp"
-
"github.com/mymmrac/telego"
)
func main() {
+ ctx := context.Background()
botToken1 := os.Getenv("TOKEN_1")
botToken2 := os.Getenv("TOKEN_2")
@@ -20,48 +20,25 @@ func main() {
bot2, _ := telego.NewBot(botToken2, telego.WithDefaultDebugLogger())
// Set up a webhook on Telegram side for each bot with different URLs
- _ = bot1.SetWebhook(&telego.SetWebhookParams{
- URL: "https://example.com/bot" + bot1.Token(),
+ _ = bot1.SetWebhook(ctx, &telego.SetWebhookParams{
+ URL: "https://example.com/bot1",
+ SecretToken: bot1.Token(),
})
- _ = bot2.SetWebhook(&telego.SetWebhookParams{
- URL: "https://example.com/bot" + bot2.Token(),
+ _ = bot2.SetWebhook(ctx, &telego.SetWebhookParams{
+ URL: "https://example.com/bot2",
+ SecretToken: bot2.Token(),
})
- // Create a common webhook server for all bots.
- // MultiBotWebhookServer will ensure that Start and Stop will be called only once.
- srv := &telego.MultiBotWebhookServer{
- Server: telego.FastHTTPWebhookServer{
- Server: &fasthttp.Server{},
- Router: router.New(),
- },
- }
+ // Create a common webhook serve mux (or another custom server) for all bots
+ mux := &http.ServeMux{}
// Get updates chan from webhook with respect to webhook URL
- // Note: Each bot should use the same webhook server
- updates1, _ := bot1.UpdatesViaWebhook(
- "/bot"+bot1.Token(),
- telego.WithWebhookServer(srv),
- )
- updates2, _ := bot2.UpdatesViaWebhook(
- "/bot"+bot2.Token(),
- telego.WithWebhookServer(srv),
- )
+ // Note: Each bot should use the same webhook serve mux (or another custom server)
+ updates1, _ := bot1.UpdatesViaWebhook(ctx, telego.WebhookHTTPServeMux(mux, "POST /bot1", bot1.Token()))
+ updates2, _ := bot2.UpdatesViaWebhook(ctx, telego.WebhookHTTPServeMux(mux, "POST /bot2", bot2.Token()))
// Start server for receiving requests from the Telegram
- // Note: You still need to start both bot webhook servers
- go func() {
- _ = bot1.StartWebhook("localhost:443")
- }()
- go func() {
- _ = bot2.StartWebhook("localhost:443")
- }()
-
- // Stop reviving updates from updates chan and shutdown webhook server
- // Note: You still need to stop both bot webhook servers
- defer func() {
- _ = bot1.StopWebhook()
- _ = bot2.StopWebhook()
- }()
+ go func() { _ = http.ListenAndServe(":443", mux) }()
// Loop through all updates when they came
go func() {
diff --git a/examples/ngrok/main.go b/examples/ngrok/main.go
index 6fd7e69c..ea18897a 100644
--- a/examples/ngrok/main.go
+++ b/examples/ngrok/main.go
@@ -7,7 +7,6 @@ import (
"os/signal"
"time"
- "github.com/fasthttp/router"
"github.com/valyala/fasthttp"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
@@ -26,8 +25,8 @@ func main() {
}
// Initialize signal handling
- sigs := make(chan os.Signal, 1)
- signal.Notify(sigs, os.Interrupt)
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
+ defer cancel()
// Initialize done chan
done := make(chan struct{}, 1)
@@ -48,49 +47,44 @@ func main() {
srv := &fasthttp.Server{}
// Get an update channel from webhook using Ngrok
- updates, _ := bot.UpdatesViaWebhook("/bot"+bot.Token(),
- // Set func server with fast http server inside that will be used to handle webhooks
- telego.WithWebhookServer(telego.FuncWebhookServer{
- Server: telego.FastHTTPWebhookServer{
- Logger: bot.Logger(),
- Server: srv,
- Router: router.New(),
- },
- // Override default start func to use Ngrok tunnel
- // Note: When server is stopped, the Ngrok tunnel always returns an error, so it should be handled by user
- StartFunc: func(_ string) error {
- return srv.Serve(tun)
- },
- }),
-
+ updates, _ := bot.UpdatesViaWebhook(ctx,
+ // Use FastHTTP webhook server
+ telego.WebhookFastHTTP(srv, "/bot", bot.Token()),
// Calls SetWebhook before starting webhook and provide dynamic Ngrok tunnel URL
- telego.WithWebhookSet(&telego.SetWebhookParams{
- URL: tun.URL() + "/bot" + bot.Token(),
+ telego.WithWebhookSet(ctx, &telego.SetWebhookParams{
+ URL: tun.URL() + "/bot",
+ SecretToken: bot.Token(),
}),
)
// Handle stop signal (Ctrl+C)
go func() {
// Wait for stop signal
- <-sigs
-
+ <-ctx.Done()
fmt.Println("Stopping...")
- ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
- defer cancel()
+ stopCtx, stopCancel := context.WithTimeout(context.Background(), time.Second*20)
+ defer stopCancel()
+
+ _ = srv.ShutdownWithContext(stopCtx)
+ fmt.Println("Server done")
- // Stop reviving updates from update channel and shutdown webhook server
- _ = bot.StopWebhookWithContext(ctx)
+ for len(updates) > 0 {
+ select {
+ case <-stopCtx.Done():
+ break
+ case <-time.After(time.Microsecond * 100):
+ // Continue
+ }
+ }
fmt.Println("Webhook done")
// Notify that stop is done
done <- struct{}{}
}()
- // Start server for receiving requests from the Telegram
- go func() {
- _ = bot.StartWebhook("")
- }()
+ // Start server for receiving requests from the Telegram using the Ngrok tunnel
+ go func() { _ = srv.Serve(tun) }()
// Loop through all updates when they came
go func() {
diff --git a/examples/retry_caller/main.go b/examples/retry_caller/main.go
index b1dd3876..f54ce889 100644
--- a/examples/retry_caller/main.go
+++ b/examples/retry_caller/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
"time"
@@ -41,7 +42,7 @@ func main() {
// Call method getMe (https://core.telegram.org/bots/api#getme).
// In case if this call will fail, retry caller will retry calling Telegram until request is
// successful (no network errors) or max attempts reached.
- botUser, err := bot.GetMe()
+ botUser, err := bot.GetMe(context.Background())
if err != nil {
fmt.Println("Error:", err)
}
diff --git a/examples/sending_files/main.go b/examples/sending_files/main.go
index 0bc2ac40..d2962c38 100644
--- a/examples/sending_files/main.go
+++ b/examples/sending_files/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -9,6 +10,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -34,7 +36,7 @@ func main() {
).WithCaption("My cool file from disk")
// Sending document
- msg, err := bot.SendDocument(document)
+ msg, err := bot.SendDocument(ctx, document)
if err != nil {
fmt.Println(err)
return
@@ -53,7 +55,7 @@ func main() {
).WithCaption("My cool photo")
// Sending photo
- _, _ = bot.SendPhoto(photo)
+ _, _ = bot.SendPhoto(ctx, photo)
// =========================================== //
@@ -70,7 +72,7 @@ func main() {
)
// Sending a media group
- _, _ = bot.SendMediaGroup(mediaGroup)
+ _, _ = bot.SendMediaGroup(ctx, mediaGroup)
}
// Helper function to open file or panic
diff --git a/examples/test_server/main.go b/examples/test_server/main.go
index 098ecd77..b10981f2 100644
--- a/examples/test_server/main.go
+++ b/examples/test_server/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
@@ -31,7 +32,7 @@ func main() {
// Call method getMe (https://core.telegram.org/bots/api#getme).
// Note: Bot will call the test server: https://api.telegram.org/bot/test/getMe
- botUser, err := bot.GetMe()
+ botUser, err := bot.GetMe(context.Background())
if err != nil {
fmt.Println("Error:", err)
}
diff --git a/examples/update_processor/main.go b/examples/update_processor/main.go
index 31b4b3a2..c3816113 100644
--- a/examples/update_processor/main.go
+++ b/examples/update_processor/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
"sync/atomic"
@@ -10,6 +11,9 @@ import (
)
func main() {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
botToken := os.Getenv("TOKEN")
// Create Bot
@@ -20,10 +24,7 @@ func main() {
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
-
- // Stop reviving updates from update channel
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
fmt.Println("Listening for updates...")
@@ -38,7 +39,7 @@ func main() {
// Stop bot when processed 3 updates
if currentCount >= 3 {
- bot.StopLongPolling()
+ cancel()
}
return update
diff --git a/examples/updates_long_polling/main.go b/examples/updates_long_polling/main.go
index ec4da1b6..46218eda 100644
--- a/examples/updates_long_polling/main.go
+++ b/examples/updates_long_polling/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"os"
"time"
@@ -20,6 +21,9 @@ func main() {
// Get updates channel, all options are optional
updates, _ := bot.UpdatesViaLongPolling(
+ // When the context is closed, the update channel will be closed and long polling will be stopped
+ context.Background(),
+
// Set Telegram parameter to get updates, can be nil
// Note: If nil then timeout will be set to default 8s
&telego.GetUpdatesParams{
@@ -39,9 +43,6 @@ func main() {
telego.WithLongPollingBuffer(100),
)
- // Stop reviving updates from update channel
- defer bot.StopLongPolling()
-
// Loop through all updates when they came
for update := range updates {
fmt.Printf("Update: %+v\n", update)
diff --git a/examples/updates_webhook/main.go b/examples/updates_webhook/main.go
index e17a3cad..40441cf2 100644
--- a/examples/updates_webhook/main.go
+++ b/examples/updates_webhook/main.go
@@ -1,16 +1,16 @@
package main
import (
+ "context"
"fmt"
"os"
- "github.com/fasthttp/router"
- "github.com/valyala/fasthttp"
-
"github.com/mymmrac/telego"
+ "github.com/valyala/fasthttp"
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -22,45 +22,44 @@ func main() {
// Set up a webhook on Telegram side
// Note: If you are keeping this call, you shouldn't use telego.WithWebhookSet option below
- _ = bot.SetWebhook(&telego.SetWebhookParams{
- URL: "https://example.com/bot" + bot.Token(),
+ _ = bot.SetWebhook(ctx, &telego.SetWebhookParams{
+ URL: "https://example.com/bot",
+ SecretToken: bot.Token(),
})
// Receive information about webhook
- info, _ := bot.GetWebhookInfo()
+ info, _ := bot.GetWebhookInfo(ctx)
fmt.Printf("Webhook Info: %+v\n", info)
+ // Create HTTP server
+ srv := &fasthttp.Server{}
+
// Get an update channel from webhook, also all options are optional.
// Note: For one bot, only one webhook allowed.
- updates, _ := bot.UpdatesViaWebhook("/bot"+bot.Token(),
+ updates, _ := bot.UpdatesViaWebhook(ctx,
+ // Use fasthttp webhook server, any other custom server can be used,
+ // you need to provide a way to register handler
+ telego.WebhookFastHTTP(srv, "/bot", bot.Token()),
+
+ // Telego provides a simple way to use http.Server as a webhook server
+ // telego.WebhookHTTPServer(srv, "/bot", bot.Token()),
+
+ // Telego provides a simple way to use http.ServeMux as a webhook server
+ // telego.WebhookHTTPServeMux(mux, "POST /bot", bot.Token()),
+
// Set chan buffer (default 128)
telego.WithWebhookBuffer(128),
- // Set fast http server that will be used to handle webhooks (default telego.FastHTTPWebhookServer)
- // Note: If SecretToken is non-empty, it will be verified on each request
- telego.WithWebhookServer(telego.FastHTTPWebhookServer{
- Logger: bot.Logger(),
- Server: &fasthttp.Server{},
- Router: router.New(),
- SecretToken: "token",
- }),
-
// Calls SetWebhook before starting webhook
// Note: If you are using this option, you shouldn't call bot.SetWebhook above
- telego.WithWebhookSet(&telego.SetWebhookParams{
- URL: "https://example.com/bot" + bot.Token(),
+ telego.WithWebhookSet(ctx, &telego.SetWebhookParams{
+ URL: "https://example.com/bot",
+ SecretToken: bot.Token(),
}),
)
// Start server for receiving requests from the Telegram
- go func() {
- _ = bot.StartWebhook("localhost:443")
- }()
-
- // Stop reviving updates from update channel and shutdown webhook server
- defer func() {
- _ = bot.StopWebhook()
- }()
+ go func() { _ = srv.ListenAndServe(":433") }()
// Loop through all updates when they came
for update := range updates {
diff --git a/examples/utility_methods/main.go b/examples/utility_methods/main.go
index 922a8c9d..65620785 100644
--- a/examples/utility_methods/main.go
+++ b/examples/utility_methods/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "context"
"fmt"
"io"
"os"
@@ -10,6 +11,7 @@ import (
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -23,10 +25,10 @@ func main() {
chatID := tu.ID(123)
// Create a message with only required parameters
- _, _ = bot.SendMessage(tu.Message(chatID, "Hello"))
+ _, _ = bot.SendMessage(ctx, tu.Message(chatID, "Hello"))
// Create telego.ChatID username and send a message
- _, _ = bot.SendMessage(tu.Message(tu.Username("@user"), "World"))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.Username("@user"), "World"))
// Create a message and change optional parameters
msg := tu.Message(chatID, "Hello World").
@@ -35,26 +37,26 @@ func main() {
}).
WithDisableNotification().
WithProtectContent()
- _, _ = bot.SendMessage(msg)
+ _, _ = bot.SendMessage(ctx, msg)
var file *os.File // Used, just for example (not valid in real use)
// Create document using *os.File as telego.InputFile
- _, _ = bot.SendDocument(tu.Document(chatID, tu.File(file)))
+ _, _ = bot.SendDocument(ctx, tu.Document(chatID, tu.File(file)))
var reader io.Reader // Used, just for example (not valid in real use)
// Create a document using io.Reader by "naming" it and send as a document
- _, _ = bot.SendDocument(tu.Document(chatID, tu.File(tu.NameReader(reader, "my_file"))))
+ _, _ = bot.SendDocument(ctx, tu.Document(chatID, tu.File(tu.NameReader(reader, "my_file"))))
// Create document using URL to file as telego.InputFile
- _, _ = bot.SendDocument(tu.Document(chatID, tu.FileFromURL("https://example.com/test.txt")))
+ _, _ = bot.SendDocument(ctx, tu.Document(chatID, tu.FileFromURL("https://example.com/test.txt")))
// Create contact from phone and first name
- _, _ = bot.SendContact(tu.Contact(chatID, "+123454321", "John"))
+ _, _ = bot.SendContact(ctx, tu.Contact(chatID, "+123454321", "John"))
// Small example of parsing commands
- updates, _ := bot.GetUpdates(nil)
+ updates, _ := bot.GetUpdates(ctx, nil)
for _, u := range updates {
if u.Message != nil {
text := u.Message.Text
diff --git a/go.mod b/go.mod
index 5dafc7a9..30e8bbb8 100644
--- a/go.mod
+++ b/go.mod
@@ -1,13 +1,11 @@
module github.com/mymmrac/telego
-go 1.22.3
+go 1.23.4
require (
- github.com/bytedance/sonic v1.12.7
- github.com/fasthttp/router v1.5.4
- github.com/joho/godotenv v1.5.1
+ github.com/bytedance/sonic v1.12.9
github.com/stretchr/testify v1.10.0
- github.com/valyala/fasthttp v1.58.0
+ github.com/valyala/fasthttp v1.59.0
github.com/valyala/fastjson v1.6.4
go.uber.org/mock v0.5.0
)
@@ -19,17 +17,13 @@ require github.com/grbit/go-json v0.11.0
require (
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/bytedance/sonic/loader v0.2.2 // indirect
- github.com/cloudwego/base64x v0.1.4 // indirect
+ github.com/cloudwego/base64x v0.1.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/klauspost/compress v1.17.11 // indirect
- github.com/klauspost/cpuid/v2 v2.2.6 // indirect
- github.com/kr/pretty v0.3.1 // indirect
+ github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
- golang.org/x/arch v0.6.0 // indirect
- golang.org/x/sys v0.27.0 // indirect
- gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 07503f74..6e44c3b4 100644
--- a/go.sum
+++ b/go.sum
@@ -1,43 +1,25 @@
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
-github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
-github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I=
+github.com/bytedance/sonic v1.12.9 h1:Od1BvK55NnewtGaJsTDeAOSnLVO2BTSLOe0+ooKokmQ=
+github.com/bytedance/sonic v1.12.9/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
-github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
-github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
+github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
+github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fasthttp/router v1.5.4 h1:oxdThbBwQgsDIYZ3wR1IavsNl6ZS9WdjKukeMikOnC8=
-github.com/fasthttp/router v1.5.4/go.mod h1:3/hysWq6cky7dTfzaaEPZGdptwjwx0qzTgFCKEWRjgc=
github.com/grbit/go-json v0.11.0 h1:bAbyMdYrYl/OjYsSqLH99N2DyQ291mHy726Mx+sYrnc=
github.com/grbit/go-json v0.11.0/go.mod h1:IYpHsdybQ386+6g3VE6AXQ3uTGa5mquBme5/ZWmtzek=
-github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
-github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
+github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
-github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
-github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
-github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -51,22 +33,18 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.58.0 h1:GGB2dWxSbEprU9j0iMJHgdKYJVDyjrOwF9RE59PbRuE=
-github.com/valyala/fasthttp v1.58.0/go.mod h1:SYXvHHaFp7QZHGKSHmoMipInhrI5StHrhDTYVEjK/Kw=
+github.com/valyala/fasthttp v1.59.0 h1:Qu0qYHfXvPk1mSLNqcFtEk6DpxgA26hy6bmydotDpRI=
+github.com/valyala/fasthttp v1.59.0/go.mod h1:GTxNb9Bc6r2a9D0TWNSPwDz78UxnTGBViY3xZNEqyYU=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
-golang.org/x/arch v0.6.0 h1:S0JTfE48HbRj80+4tbvZDYsJ3tGv6BUU3XxyZ7CirAc=
-golang.org/x/arch v0.6.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
-golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/generator/methods.go b/internal/generator/methods.go
index e1a9af21..4f53c4e5 100644
--- a/internal/generator/methods.go
+++ b/internal/generator/methods.go
@@ -292,7 +292,11 @@ import (
returnsNotFoundCount++
}
- data.WriteString(fmt.Sprintf("\nfunc (b *Bot) %s(%s) %s {\n", m.nameTitle, parametersArg, returnType))
+ if parametersArg != "" {
+ parametersArg = ", " + parametersArg
+ }
+
+ data.WriteString(fmt.Sprintf("\nfunc (b *Bot) %s(ctx context.Context%s) %s {\n", m.nameTitle, parametersArg, returnType))
returnVar := returnTypeToVar(m.returnType)
switch m.nameTitle {
@@ -315,21 +319,21 @@ import (
}
if len(m.parameters) > 0 {
- data.WriteString(fmt.Sprintf("\terr := b.performRequest(\"%s\", params, &%s%s)\n", m.name, returnVar, successValue))
+ data.WriteString(fmt.Sprintf("\terr := b.performRequest(ctx, \"%s\", params, &%s%s)\n", m.name, returnVar, successValue))
} else {
- data.WriteString(fmt.Sprintf("\terr := b.performRequest(\"%s\", nil, &%s%s)\n", m.name, returnVar, successValue))
+ data.WriteString(fmt.Sprintf("\terr := b.performRequest(ctx, \"%s\", nil, &%s%s)\n", m.name, returnVar, successValue))
}
- data.WriteString(fmt.Sprintf("\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"telego: %s(): %%w\", err)\n\t}\n\n", m.name))
+ data.WriteString(fmt.Sprintf("\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"telego: %s: %%w\", err)\n\t}\n", m.name))
data.WriteString(fmt.Sprintf("\treturn %s, nil\n}\n\n", returnVar))
} else {
if len(m.parameters) > 0 {
- data.WriteString(fmt.Sprintf("\terr := b.performRequest(\"%s\", params)\n", m.name))
+ data.WriteString(fmt.Sprintf("\terr := b.performRequest(ctx, \"%s\", params)\n", m.name))
} else {
- data.WriteString(fmt.Sprintf("\terr := b.performRequest(\"%s\", nil)\n", m.name))
+ data.WriteString(fmt.Sprintf("\terr := b.performRequest(ctx, \"%s\", nil)\n", m.name))
}
- data.WriteString(fmt.Sprintf("\tif err != nil {\n\t\treturn fmt.Errorf(\"telego: %s(): %%w\", err)\n\t}\n\n", m.name))
+ data.WriteString(fmt.Sprintf("\tif err != nil {\n\t\treturn fmt.Errorf(\"telego: %s: %%w\", err)\n\t}\n", m.name))
data.WriteString("\treturn nil\n}\n\n")
}
}
diff --git a/internal/generator/setters.go b/internal/generator/setters.go
index 7140d3d7..f05b6d35 100644
--- a/internal/generator/setters.go
+++ b/internal/generator/setters.go
@@ -142,7 +142,7 @@ func writeSetters(file *os.File, setters tgSetters, receiverDefault bool, noPoin
if setter.fieldType != "bool" {
value := firstToLower(setter.fieldName)
if convertToPtr {
- value = "ToPtr(" + value + ")"
+ value = "&" + value
}
data.WriteString(fmt.Sprintf("\t%s.%s = %s\n", r, setter.fieldName, value))
diff --git a/internal/integration/forward_messages_test.go b/internal/integration/forward_messages_test.go
new file mode 100644
index 00000000..45e2fcd1
--- /dev/null
+++ b/internal/integration/forward_messages_test.go
@@ -0,0 +1,111 @@
+//go:build integration && interactive
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "slices"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/mymmrac/telego"
+ th "github.com/mymmrac/telego/telegohandler"
+)
+
+func TestForwardMessages(t *testing.T) {
+ ctx := context.Background()
+
+ updates, err := bot.UpdatesViaLongPolling(ctx, &telego.GetUpdatesParams{
+ AllowedUpdates: []string{
+ telego.MessageUpdates,
+ },
+ })
+ require.NoError(t, err)
+
+ bh, err := th.NewBotHandler(bot, updates)
+ require.NoError(t, err)
+
+ lock := sync.Mutex{}
+ groupedMessages := map[string]chan int{}
+
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
+ if message.MediaGroupID == "" {
+ _, err = ctx.Bot().ForwardMessage(ctx, &telego.ForwardMessageParams{
+ ChatID: message.Chat.ChatID(),
+ MessageThreadID: message.MessageThreadID,
+ FromChatID: message.Chat.ChatID(),
+ MessageID: message.MessageID,
+ })
+ if err != nil {
+ return err
+ }
+ } else {
+ lock.Lock()
+ defer lock.Unlock()
+
+ var ok bool
+ var ch chan int
+
+ if ch, ok = groupedMessages[message.MediaGroupID]; ok {
+ ch <- message.MessageID
+ return nil
+ }
+
+ ch = make(chan int, 1)
+ groupedMessages[message.MediaGroupID] = ch
+
+ go func() {
+ messageIDs := make([]int, 0, 10)
+ // Add the initial message
+ messageIDs = append(messageIDs, message.MessageID)
+
+ loop:
+ for {
+ // Limit the number of messages to 10 (Telegram limit)
+ if len(messageIDs) == 10 {
+ break
+ }
+
+ select {
+ case messageID := <-ch:
+ messageIDs = append(messageIDs, messageID)
+ // Wait for 1 second for other messages in a group
+ case <-time.After(time.Second):
+ break loop
+ }
+ }
+
+ lock.Lock()
+ delete(groupedMessages, message.MediaGroupID)
+ lock.Unlock()
+
+ close(ch)
+ // Drain message IDs if any left
+ for messageID := range ch {
+ messageIDs = append(messageIDs, messageID)
+ }
+
+ // Sort message IDs to preserve the order
+ slices.Sort(messageIDs)
+
+ _, err = ctx.Bot().ForwardMessages(ctx.WithoutCancel(), &telego.ForwardMessagesParams{
+ ChatID: message.Chat.ChatID(),
+ MessageThreadID: message.MessageThreadID,
+ FromChatID: message.Chat.ChatID(),
+ MessageIDs: messageIDs,
+ })
+ if err != nil {
+ fmt.Println(err)
+ }
+ }()
+ }
+ return nil
+ })
+
+ err = bh.Start()
+ require.NoError(t, err)
+}
diff --git a/internal/integration/inline_query_test.go b/internal/integration/inline_query_test.go
new file mode 100644
index 00000000..1c1b2039
--- /dev/null
+++ b/internal/integration/inline_query_test.go
@@ -0,0 +1,56 @@
+//go:build integration && interactive
+
+package main
+
+import (
+ "context"
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/mymmrac/telego"
+ th "github.com/mymmrac/telego/telegohandler"
+ tu "github.com/mymmrac/telego/telegoutil"
+)
+
+func TestInlineQuery(t *testing.T) {
+ ctx := context.Background()
+
+ updates, err := bot.UpdatesViaLongPolling(ctx, &telego.GetUpdatesParams{
+ AllowedUpdates: []string{
+ telego.InlineQueryUpdates,
+ telego.ChosenInlineResultUpdates,
+ },
+ })
+ require.NoError(t, err)
+
+ bh, err := th.NewBotHandler(bot, updates)
+ require.NoError(t, err)
+
+ bh.HandleInlineQuery(func(ctx *th.Context, query telego.InlineQuery) error {
+ t.Log(query.Query)
+
+ err = ctx.Bot().AnswerInlineQuery(ctx, &telego.AnswerInlineQueryParams{
+ InlineQueryID: query.ID,
+ Results: []telego.InlineQueryResult{
+ tu.ResultArticle("1", "Echo", tu.TextMessage("["+query.Query+"]")).WithDescription(query.Query),
+ },
+ CacheTime: 1,
+ IsPersonal: true,
+ })
+ if err != nil {
+ return fmt.Errorf("answer inline query: %w", err)
+ }
+
+ return nil
+ })
+
+ bh.HandleChosenInlineResult(func(ctx *th.Context, result telego.ChosenInlineResult) error {
+ t.Log(result.Query, result.ResultID)
+ return nil
+ })
+
+ err = bh.Start()
+ require.NoError(t, err)
+}
diff --git a/internal/integration/main_test.go b/internal/integration/main_test.go
index b19efd84..c3fd1d9d 100644
--- a/internal/integration/main_test.go
+++ b/internal/integration/main_test.go
@@ -7,11 +7,10 @@ import (
"os"
"path/filepath"
"strconv"
+ "strings"
"testing"
"time"
- _ "github.com/joho/godotenv/autoload"
-
"github.com/mymmrac/telego"
)
@@ -30,7 +29,22 @@ var (
)
func TestMain(m *testing.M) {
- var err error
+ envData, err := os.ReadFile(".env")
+ expect(err == nil, "Read env:", err)
+
+ for _, e := range strings.Split(string(envData), "\n") {
+ e = strings.TrimSpace(e)
+ if e == "" {
+ continue
+ }
+
+ key, value, ok := strings.Cut(e, "=")
+ expect(ok, "Parse env:", e)
+
+ err = os.Setenv(key, value)
+ expect(err == nil, "Set env:", err)
+ }
+
bot, err = telego.NewBot(env("TOKEN"), telego.WithDiscardLogger())
expect(err == nil, "Create bot:", err)
diff --git a/internal/integration/middleware_test.go b/internal/integration/middleware_test.go
index 5b4c2daf..56bba577 100644
--- a/internal/integration/middleware_test.go
+++ b/internal/integration/middleware_test.go
@@ -13,7 +13,9 @@ import (
)
func TestMiddleware(t *testing.T) {
- updates, err := bot.UpdatesViaLongPolling(nil)
+ ctx := context.Background()
+
+ updates, err := bot.UpdatesViaLongPolling(ctx, nil)
require.NoError(t, err)
bh, err := th.NewBotHandler(bot, updates)
@@ -22,21 +24,23 @@ func TestMiddleware(t *testing.T) {
messages := bh.Group(th.AnyMessageWithFrom())
const userIDKey = "user-id"
- messages.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ messages.Use(func(ctx *th.Context, update telego.Update) error {
t.Log("User ID middleware")
- ctx := context.WithValue(update.Context(), userIDKey, update.Message.From.ID)
- next(bot, update.WithContext(ctx))
+ ctx.WithValue(userIDKey, update.Message.From.ID)
+ return ctx.Next(update)
})
messages.Handle(
- func(bot *telego.Bot, update telego.Update) {
- userID := update.Context().Value(userIDKey).(int64)
+ func(ctx *th.Context, update telego.Update) error {
+ userID := ctx.Value(userIDKey).(int64)
t.Log("User ID:", userID)
+ return nil
},
- func(update telego.Update) bool {
- return update.Context().Value(userIDKey) != nil
+ func(ctx context.Context, update telego.Update) bool {
+ return ctx.Value(userIDKey) != nil
},
)
- bh.Start()
+ err = bh.Start()
+ require.NoError(t, err)
}
diff --git a/internal/integration/send_test.go b/internal/integration/send_test.go
index de21ac45..5fdc1a7a 100644
--- a/internal/integration/send_test.go
+++ b/internal/integration/send_test.go
@@ -3,6 +3,7 @@
package main
import (
+ "context"
"testing"
"github.com/stretchr/testify/assert"
@@ -13,8 +14,10 @@ import (
)
func TestSendMessage(t *testing.T) {
+ ctx := context.Background()
+
t.Run("simple", func(t *testing.T) {
- msg, err := bot.SendMessage(&telego.SendMessageParams{
+ msg, err := bot.SendMessage(ctx, &telego.SendMessageParams{
ChatID: tu.ID(chatID),
Text: "SendMessage " + timeNow,
})
@@ -27,7 +30,7 @@ func TestSendMessage(t *testing.T) {
keyboard := tu.InlineKeyboard(
tu.InlineKeyboardRow(tu.InlineKeyboardButton("Test").WithCallbackData("OK")),
)
- msg, err := bot.SendMessage(
+ msg, err := bot.SendMessage(ctx,
tu.MessageWithEntities(tu.ID(chatID),
tu.Entity("SendMessage").Bold(), tu.Entity(" "), tu.Entity(timeNow).Code(),
).WithReplyMarkup(keyboard),
@@ -38,7 +41,7 @@ func TestSendMessage(t *testing.T) {
})
t.Run("new_line", func(t *testing.T) {
- msg, err := bot.SendMessage(&telego.SendMessageParams{
+ msg, err := bot.SendMessage(ctx, &telego.SendMessageParams{
ChatID: tu.ID(chatID),
Text: "Send\nMessage",
})
@@ -53,7 +56,7 @@ func TestSendMessage(t *testing.T) {
tu.Entity("\n"),
tu.Entity(" Pre\nPre").Pre(""),
)
- msg, err := bot.SendMessage(tu.Message(tu.ID(chatID), text).WithEntities(entities...))
+ msg, err := bot.SendMessage(ctx, tu.Message(tu.ID(chatID), text).WithEntities(entities...))
require.NoError(t, err)
assert.Equal(t, msg.Text, text)
@@ -71,7 +74,7 @@ func TestSendMessage(t *testing.T) {
tu.Entity("世界").Bold(),
)
- msg, err := bot.SendMessage(tu.Message(tu.ID(chatID), "_😅_* test *_🌗_* Україна* _\U0001FAE5 _*世界*").
+ msg, err := bot.SendMessage(ctx, tu.Message(tu.ID(chatID), "_😅_* test *_🌗_* Україна* _\U0001FAE5 _*世界*").
WithParseMode(telego.ModeMarkdownV2))
require.NoError(t, err)
@@ -84,7 +87,7 @@ func TestSendMessage(t *testing.T) {
})
t.Run("entities_check", func(t *testing.T) {
- msg, err := bot.SendMessage(tu.MessageWithEntities(tu.ID(chatID),
+ msg, err := bot.SendMessage(ctx, tu.MessageWithEntities(tu.ID(chatID),
tu.Entity("Lo").Strikethrough(), tu.Entity("rem").Underline(), tu.Entity(" ipsum "),
tu.Entity("dolor").Strikethrough().Underline(), tu.Entity(" sit amet, consectetur adipiscing elit."),
tu.Entity("\n"),
@@ -107,8 +110,10 @@ func TestSendMessage(t *testing.T) {
}
func TestSendPhoto(t *testing.T) {
+ ctx := context.Background()
+
t.Run("regular", func(t *testing.T) {
- msg, err := bot.SendPhoto(&telego.SendPhotoParams{
+ msg, err := bot.SendPhoto(ctx, &telego.SendPhotoParams{
ChatID: tu.ID(chatID),
Photo: tu.File(open(img1Jpg)),
Caption: "SendPhoto " + timeNow,
@@ -119,7 +124,7 @@ func TestSendPhoto(t *testing.T) {
})
t.Run("new_line", func(t *testing.T) {
- msg, err := bot.SendPhoto(&telego.SendPhotoParams{
+ msg, err := bot.SendPhoto(ctx, &telego.SendPhotoParams{
ChatID: tu.ID(chatID),
Photo: tu.File(open(img1Jpg)),
Caption: "Send\nPhoto \" >",
@@ -130,7 +135,7 @@ func TestSendPhoto(t *testing.T) {
})
t.Run("keyboard_and_markdown", func(t *testing.T) {
- msg, err := bot.SendPhoto(&telego.SendPhotoParams{
+ msg, err := bot.SendPhoto(ctx, &telego.SendPhotoParams{
ChatID: tu.ID(chatID),
Photo: tu.File(open(img1Jpg)),
ParseMode: telego.ModeMarkdownV2,
@@ -146,8 +151,10 @@ func TestSendPhoto(t *testing.T) {
}
func TestSendAudio(t *testing.T) {
+ ctx := context.Background()
+
t.Run("audio_file", func(t *testing.T) {
- msg, err := bot.SendAudio(&telego.SendAudioParams{
+ msg, err := bot.SendAudio(ctx, &telego.SendAudioParams{
ChatID: tu.ID(chatID),
Audio: tu.File(open(kittenMp3)),
Caption: "SendAudio " + timeNow,
@@ -159,7 +166,7 @@ func TestSendAudio(t *testing.T) {
})
t.Run("url", func(t *testing.T) {
- msg, err := bot.SendAudio(&telego.SendAudioParams{
+ msg, err := bot.SendAudio(ctx, &telego.SendAudioParams{
ChatID: tu.ID(chatID),
Audio: tu.FileFromURL(exampleMp3),
Caption: "SendAudio " + timeNow,
@@ -172,8 +179,10 @@ func TestSendAudio(t *testing.T) {
}
func TestSendPoll(t *testing.T) {
+ ctx := context.Background()
+
t.Run("anonymous", func(t *testing.T) {
- msg, err := bot.SendPoll(&telego.SendPollParams{
+ msg, err := bot.SendPoll(ctx, &telego.SendPollParams{
ChatID: tu.ID(chatID),
Question: "Test",
Options: []telego.InputPollOption{tu.PollOption("Option 1"), tu.PollOption("Option 2")},
@@ -185,7 +194,7 @@ func TestSendPoll(t *testing.T) {
})
t.Run("not_anonymous", func(t *testing.T) {
- msg, err := bot.SendPoll(&telego.SendPollParams{
+ msg, err := bot.SendPoll(ctx, &telego.SendPollParams{
ChatID: tu.ID(chatID),
Question: "Test",
Options: []telego.InputPollOption{tu.PollOption("Option 1"), tu.PollOption("Option 2")},
@@ -197,7 +206,7 @@ func TestSendPoll(t *testing.T) {
})
t.Run("correct_option_id", func(t *testing.T) {
- msg, err := bot.SendPoll(&telego.SendPollParams{
+ msg, err := bot.SendPoll(ctx, &telego.SendPollParams{
ChatID: tu.ID(chatID),
Question: "Test",
Options: []telego.InputPollOption{tu.PollOption("Option 1"), tu.PollOption("Option 2")},
diff --git a/internal/test/main.go b/internal/test/main.go
index 88bcbb3b..5c212c7d 100644
--- a/internal/test/main.go
+++ b/internal/test/main.go
@@ -1,13 +1,13 @@
package main
import (
+ "context"
"fmt"
+ "io"
+ "net/http"
"os"
"time"
- "github.com/fasthttp/router"
- "github.com/valyala/fasthttp"
-
"github.com/mymmrac/telego"
th "github.com/mymmrac/telego/telegohandler"
tu "github.com/mymmrac/telego/telegoutil"
@@ -21,9 +21,10 @@ var (
userUsername = tu.Username("@mymmrac")
)
-const testCase = 34
+const testCase = 35
func main() {
+ ctx := context.Background()
testToken := os.Getenv("TOKEN")
bot, err := telego.NewBot(testToken,
@@ -33,7 +34,7 @@ func main() {
return
}
- _, err = bot.GetMe()
+ _, err = bot.GetMe(ctx)
if err != nil {
fmt.Println(err)
return
@@ -66,26 +67,24 @@ func main() {
},
}
- msg, err := bot.SendMessage(message)
+ msg, err := bot.SendMessage(ctx, message)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(msg)
case 2:
- updChan, err := bot.UpdatesViaLongPolling(nil)
+ updChan, err := bot.UpdatesViaLongPolling(ctx, nil)
if err != nil {
fmt.Println(err)
return
}
- defer bot.StopLongPolling()
for upd := range updChan {
fmt.Println(upd)
- fmt.Println(bot.IsRunningLongPolling())
if upd.Message != nil {
- _, err := bot.CopyMessage(&telego.CopyMessageParams{
+ _, err := bot.CopyMessage(ctx, &telego.CopyMessageParams{
ChatID: telego.ChatID{ID: upd.Message.Chat.ID},
FromChatID: telego.ChatID{ID: upd.Message.Chat.ID},
MessageID: upd.Message.MessageID,
@@ -97,7 +96,7 @@ func main() {
}
case 3:
p := &telego.ExportChatInviteLinkParams{ChatID: groupID}
- link, err := bot.ExportChatInviteLink(p)
+ link, err := bot.ExportChatInviteLink(ctx, p)
if err != nil {
fmt.Println(err)
return
@@ -129,7 +128,7 @@ func main() {
},
},
}
- msgs, err := bot.SendMediaGroup(p)
+ msgs, err := bot.SendMediaGroup(ctx, p)
if err != nil {
fmt.Println(err)
return
@@ -138,7 +137,7 @@ func main() {
fmt.Println(m)
}
case 5:
- err = bot.SetMyCommands(&telego.SetMyCommandsParams{
+ err = bot.SetMyCommands(ctx, &telego.SetMyCommandsParams{
Commands: []telego.BotCommand{
{
Command: "test",
@@ -152,7 +151,7 @@ func main() {
return
}
case 6:
- commands, err := bot.GetMyCommands(nil)
+ commands, err := bot.GetMyCommands(ctx, nil)
if err != nil {
fmt.Println(err)
return
@@ -165,7 +164,7 @@ func main() {
updParams := &telego.GetUpdatesParams{
AllowedUpdates: []string{"chat_member"},
}
- upd, err := bot.GetUpdates(updParams)
+ upd, err := bot.GetUpdates(ctx, updParams)
if err != nil {
fmt.Println(err)
return
@@ -175,7 +174,7 @@ func main() {
}
case 8:
p := &telego.GetChatAdministratorsParams{ChatID: telego.ChatID{ID: -1001516926498}}
- admins, err := bot.GetChatAdministrators(p)
+ admins, err := bot.GetChatAdministrators(ctx, p)
if err != nil {
fmt.Println(err)
return
@@ -204,7 +203,7 @@ func main() {
},
}},
}
- msg, err := bot.SendDocument(dp)
+ msg, err := bot.SendDocument(ctx, dp)
if err != nil {
fmt.Println(err)
return
@@ -216,7 +215,7 @@ func main() {
Document: telego.InputFile{File: mustOpen("doc.txt")},
Caption: "Hello world",
}
- msg, err := bot.SendDocument(dp)
+ msg, err := bot.SendDocument(ctx, dp)
if err != nil {
fmt.Println(err)
return
@@ -229,7 +228,7 @@ func main() {
Caption: "https://test.ua/test_url",
}
- msg, err := bot.SendPhoto(photo)
+ msg, err := bot.SendPhoto(ctx, photo)
if err != nil {
fmt.Println(err)
return
@@ -240,7 +239,7 @@ func main() {
ChatID: channelUsername,
Text: "Test msg",
}
- _, err = bot.SendMessage(msg)
+ _, err = bot.SendMessage(ctx, msg)
if err != nil {
fmt.Println(err)
return
@@ -269,162 +268,176 @@ func main() {
},
}
- _, err = bot.SendMessage(msg)
+ _, err = bot.SendMessage(ctx, msg)
if err != nil {
fmt.Println(err)
return
}
case 14:
- _, err := bot.SendMessage(tu.Message(groupUsername, "Test 1"))
+ _, err := bot.SendMessage(ctx, tu.Message(groupUsername, "Test 1"))
if err != nil {
fmt.Println(err)
return
}
- _, err = bot.SendMessage(tu.Message(userUsername, "Test 2"))
+ _, err = bot.SendMessage(ctx, tu.Message(userUsername, "Test 2"))
if err != nil {
fmt.Println(err)
return
}
case 15:
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
bh, _ := th.NewBotHandler(bot, updates)
defer bh.Stop()
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println(update.Message.Text)
- }, func(update telego.Update) bool {
+ return nil
+ }, func(ctx context.Context, update telego.Update) bool {
return update.Message != nil
})
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("====")
fmt.Println(update.Message.Text)
fmt.Println("====")
- }, func(update telego.Update) bool {
+ return nil
+ }, func(ctx context.Context, update telego.Update) bool {
return update.Message != nil && update.Message.Text == "OK"
})
- bh.Start()
+ err = bh.Start()
+ assert(err == nil, err)
case 16:
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
bh, _ := th.NewBotHandler(bot, updates)
count := 0
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("ZERO")
- _, _ = bot.SendMessage(tu.Message(tu.ID(update.Message.Chat.ID), fmt.Sprintf("Count is zero")))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(update.Message.Chat.ID), fmt.Sprintf("Count is zero")))
count = 1
- }, func(update telego.Update) bool {
+ return nil
+ }, func(ctx context.Context, update telego.Update) bool {
return update.Message != nil && count == 0
})
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("ONE")
- _, _ = bot.SendMessage(tu.Message(tu.ID(update.Message.Chat.ID), fmt.Sprintf("Count is one")))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(update.Message.Chat.ID), fmt.Sprintf("Count is one")))
count = 2
- }, func(update telego.Update) bool {
+ return nil
+ }, func(ctx context.Context, update telego.Update) bool {
return update.Message != nil && count == 1
})
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
fmt.Println("BIG")
- _, _ = bot.SendMessage(tu.Message(tu.ID(update.Message.Chat.ID), fmt.Sprintf("Count is big: %d", count)))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(update.Message.Chat.ID), fmt.Sprintf("Count is big: %d", count)))
count++
- }, func(update telego.Update) bool {
+ return nil
+ }, func(ctx context.Context, update telego.Update) bool {
return update.Message != nil && count > 1
})
- bh.Start()
defer bh.Stop()
+ err = bh.Start()
+ assert(err == nil, err)
case 17:
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
bh, _ := th.NewBotHandler(bot, updates)
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
msg := update.Message
matches := th.CommandRegexp.FindStringSubmatch(msg.Text)
- _, _ = bot.SendMessage(tu.Message(tu.ID(msg.Chat.ID), fmt.Sprintf("%+v", matches)))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(msg.Chat.ID), fmt.Sprintf("%+v", matches)))
+ return nil
}, th.AnyCommand())
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
msg := update.Message
- _, _ = bot.SendMessage(tu.Message(tu.ID(msg.Chat.ID), fmt.Sprintf("Whaaat? %s", msg.Text)))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(msg.Chat.ID), fmt.Sprintf("Whaaat? %s", msg.Text)))
+ return nil
}, th.AnyMessage(), th.Not(th.AnyCommand()))
- bh.Start()
defer bh.Stop()
+ err = bh.Start()
+ assert(err == nil, err)
case 18:
- updates, err := bot.UpdatesViaLongPolling(nil)
+ updates, err := bot.UpdatesViaLongPolling(ctx, nil)
assert(err == nil, err)
- defer bot.StopLongPolling()
-
bh, err := th.NewBotHandler(bot, updates)
assert(err == nil, err)
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
msg := update.Message
- _, _ = bot.SendMessage(tu.Message(tu.ID(msg.Chat.ID), "Running test"))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(msg.Chat.ID), "Running test"))
+ return nil
}, th.CommandEqualArgv("run", "test"))
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
msg := update.Message
- _, _ = bot.SendMessage(tu.Message(tu.ID(msg.Chat.ID), "Running update"))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(msg.Chat.ID), "Running update"))
+ return nil
}, th.CommandEqualArgv("run", "update"))
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
msg := update.Message
m := tu.Message(tu.ID(msg.Chat.ID), "Run usage:\n```/run test```\n```/run update```")
m.ParseMode = telego.ModeMarkdownV2
- _, _ = bot.SendMessage(m)
+ _, _ = bot.SendMessage(ctx, m)
+ return nil
}, th.Or(
th.CommandEqualArgc("run", 0),
th.CommandEqualArgv("help", "run"),
))
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
msg := update.Message
m := tu.Message(tu.ID(msg.Chat.ID), "Unknown subcommand\nRun usage:\n```/run test```\n```/run update```")
m.ParseMode = telego.ModeMarkdownV2
- _, _ = bot.SendMessage(m)
+ _, _ = bot.SendMessage(ctx, m)
+ return nil
}, th.CommandEqual("run"))
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
msg := update.Message
- _, _ = bot.SendMessage(tu.Message(tu.ID(msg.Chat.ID), "Help: /run"))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(msg.Chat.ID), "Help: /run"))
+ return nil
}, th.CommandEqual("help"))
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
msg := update.Message
- _, _ = bot.SendMessage(tu.Message(tu.ID(msg.Chat.ID), "Unknown command, use: /run"))
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(msg.Chat.ID), "Unknown command, use: /run"))
+ return nil
}, th.AnyCommand())
- bh.Start()
defer bh.Stop()
+ err = bh.Start()
+ assert(err == nil, err)
case 19:
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
bh, _ := th.NewBotHandler(bot, updates)
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
- _, _ = bot.SendMessage(tu.Message(tu.ID(message.Chat.ID), "Hmm?"))
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(message.Chat.ID), "Hmm?"))
+ return nil
}, th.TextEqual("Hmm"))
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
- _, _ = bot.SendMessage(tu.Message(tu.ID(message.Chat.ID), "Hello"))
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
+ _, _ = bot.SendMessage(ctx, tu.Message(tu.ID(message.Chat.ID), "Hello"))
+ return nil
})
- bh.Start()
defer bh.Stop()
+ err = bh.Start()
+ assert(err == nil, err)
case 20:
img := tu.File(mustOpen("img1.jpg"))
img2 := tu.File(mustOpen("img2.jpg"))
@@ -435,30 +448,30 @@ func main() {
note := tu.File(mustOpen("note.mp4"))
gif := tu.File(mustOpen("cat.mp4"))
- _, err = bot.SendMessage(tu.Message(myID, "Test"))
+ _, err = bot.SendMessage(ctx, tu.Message(myID, "Test"))
assert(err == nil, err)
- _, err = bot.SendPhoto(tu.Photo(myID, img))
+ _, err = bot.SendPhoto(ctx, tu.Photo(myID, img))
assert(err == nil, err)
- _, err = bot.SendAudio(tu.Audio(myID, audio))
+ _, err = bot.SendAudio(ctx, tu.Audio(myID, audio))
assert(err == nil, err)
- _, err = bot.SendDocument(tu.Document(myID, doc))
+ _, err = bot.SendDocument(ctx, tu.Document(myID, doc))
assert(err == nil, err)
time.Sleep(time.Second * 3)
- _, err = bot.SendVideo(tu.Video(myID, video))
+ _, err = bot.SendVideo(ctx, tu.Video(myID, video))
assert(err == nil, err)
- _, err = bot.SendAnimation(tu.Animation(myID, gif))
+ _, err = bot.SendAnimation(ctx, tu.Animation(myID, gif))
assert(err == nil, err)
- _, err = bot.SendVoice(tu.Voice(myID, voice))
+ _, err = bot.SendVoice(ctx, tu.Voice(myID, voice))
assert(err == nil, err)
- _, err = bot.SendVideoNote(tu.VideoNote(myID, note))
+ _, err = bot.SendVideoNote(ctx, tu.VideoNote(myID, note))
assert(err == nil, err)
time.Sleep(time.Second * 3)
@@ -466,36 +479,35 @@ func main() {
img = tu.File(mustOpen("img1.jpg"))
img2 = tu.File(mustOpen("img2.jpg"))
- _, err = bot.SendMediaGroup(tu.MediaGroup(myID, tu.MediaPhoto(img), tu.MediaPhoto(img2)))
+ _, err = bot.SendMediaGroup(ctx, tu.MediaGroup(myID, tu.MediaPhoto(img), tu.MediaPhoto(img2)))
assert(err == nil, err)
- _, err = bot.SendLocation(tu.Location(myID, 42, 24))
+ _, err = bot.SendLocation(ctx, tu.Location(myID, 42, 24))
assert(err == nil, err)
- _, err = bot.SendVenue(tu.Venue(myID, 42, 24, "The Thing", "Things str."))
+ _, err = bot.SendVenue(ctx, tu.Venue(myID, 42, 24, "The Thing", "Things str."))
assert(err == nil, err)
- _, err = bot.SendContact(tu.Contact(myID, "+424242", "The 42"))
+ _, err = bot.SendContact(ctx, tu.Contact(myID, "+424242", "The 42"))
assert(err == nil, err)
time.Sleep(time.Second * 3)
- _, err = bot.SendPoll(tu.Poll(myID, "42?", tu.PollOption("42"), tu.PollOption("24")))
+ _, err = bot.SendPoll(ctx, tu.Poll(myID, "42?", tu.PollOption("42"), tu.PollOption("24")))
assert(err == nil, err)
- _, err = bot.SendDice(tu.Dice(myID, telego.EmojiBasketball))
+ _, err = bot.SendDice(ctx, tu.Dice(myID, telego.EmojiBasketball))
assert(err == nil, err)
- err = bot.SendChatAction(tu.ChatAction(myID, telego.ChatActionTyping))
+ err = bot.SendChatAction(ctx, tu.ChatAction(myID, telego.ChatActionTyping))
assert(err == nil, err)
case 21:
- updates, _ := bot.UpdatesViaLongPolling(nil, telego.WithLongPollingUpdateInterval(time.Second))
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil, telego.WithLongPollingUpdateInterval(time.Second))
bh, _ := th.NewBotHandler(bot, updates)
- bh.HandleInlineQuery(func(bot *telego.Bot, query telego.InlineQuery) {
- err = bot.AnswerInlineQuery(&telego.AnswerInlineQueryParams{
+ bh.HandleInlineQuery(func(ctx *th.Context, query telego.InlineQuery) error {
+ err = bot.AnswerInlineQuery(ctx, &telego.AnswerInlineQueryParams{
InlineQueryID: query.ID,
Results: []telego.InlineQueryResult{
&telego.InlineQueryResultArticle{
@@ -510,31 +522,33 @@ func main() {
},
})
assert(err == nil, err)
+ return nil
})
- bh.HandleCallbackQuery(func(bot *telego.Bot, query telego.CallbackQuery) {
- _, err = bot.EditMessageText(&telego.EditMessageTextParams{
+ bh.HandleCallbackQuery(func(ctx *th.Context, query telego.CallbackQuery) error {
+ _, err = bot.EditMessageText(ctx, &telego.EditMessageTextParams{
Text: "GG?",
InlineMessageID: query.InlineMessageID,
})
assert(err == nil, err)
- err = bot.AnswerCallbackQuery(&telego.AnswerCallbackQueryParams{
+ err = bot.AnswerCallbackQuery(ctx, &telego.AnswerCallbackQueryParams{
CallbackQueryID: query.ID,
Text: "OK",
})
assert(err == nil, err)
+ return nil
})
defer bh.Stop()
- bh.Start()
+ err = bh.Start()
+ assert(err == nil, err)
case 22:
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
bh, _ := th.NewBotHandler(bot, updates)
- auth := func(update telego.Update) bool {
+ auth := func(ctx context.Context, update telego.Update) bool {
var userID int64
if update.Message != nil && update.Message.From != nil {
@@ -556,128 +570,87 @@ func main() {
return false
}
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// DO AUTHORIZED STUFF...
+ return nil
}, auth)
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// DO NOT AUTHORIZED STUFF...
+ return nil
}, th.Not(auth))
defer bh.Stop()
- bh.Start()
+ err = bh.Start()
+ assert(err == nil, err)
case 23:
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
bh, _ := th.NewBotHandler(bot, updates)
ok := false
- middleware := func(update telego.Update) bool {
+ middleware := func(ctx context.Context, update telego.Update) bool {
return ok
}
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
ok = true
fmt.Println("SET OK")
+ return nil
}, th.CommandEqual("ok"))
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
fmt.Println("OK")
+ return nil
}, middleware)
defer bh.Stop()
- bh.Start()
- case 24:
- updates, err := bot.UpdatesViaLongPolling(nil)
+ err = bh.Start()
assert(err == nil, err)
+ case 24:
+ mux := http.NewServeMux()
- fmt.Println(bot.IsRunningLongPolling())
- time.Sleep(time.Second * 10)
-
- fmt.Println(bot.IsRunningLongPolling())
- bot.StopLongPolling()
- fmt.Println(bot.IsRunningLongPolling())
-
- for upd := range updates {
- fmt.Println(upd)
+ updates, err := bot.UpdatesViaWebhook(ctx, telego.WebhookHTTPServeMux(mux, "POST /"))
+ if err != nil {
+ panic(err)
}
- case 25:
- fmt.Println(bot.IsRunningWebhook())
-
- err = bot.StopWebhook()
- assert(err == nil, err)
-
- _, err = bot.UpdatesViaWebhook("/")
- assert(err == nil, err)
-
- fmt.Println(bot.IsRunningWebhook())
-
- go func() {
- err = bot.StartWebhook(":8080")
- assert(err == nil, err)
- }()
-
- fmt.Println(bot.IsRunningWebhook())
-
- err = bot.StopWebhook()
- assert(err == nil, err)
-
- err = bot.StopWebhook()
- assert(err == nil, err)
-
- fmt.Println(bot.IsRunningWebhook())
-
- fmt.Println("====")
- _, err = bot.UpdatesViaWebhook("/")
- assert(err == nil, err)
-
- fmt.Println(bot.IsRunningWebhook())
-
- go func() {
- err = bot.StartWebhook(":8080")
- assert(err == nil, err)
- }()
-
- fmt.Println(bot.IsRunningWebhook())
+ updates, err = bot.UpdatesViaWebhook(ctx, func(handler telego.WebhookHandler) error {
+ mux.HandleFunc("POST /", func(writer http.ResponseWriter, request *http.Request) {
+ data, err := io.ReadAll(request.Body)
+ if err != nil {
+ panic(err)
+ }
- err = bot.StopWebhook()
- assert(err == nil, err)
+ err = handler(request.Context(), data)
+ if err != nil {
+ panic(err)
+ }
- fmt.Println(bot.IsRunningWebhook())
- case 26:
- r := router.New()
- r.GET("/", func(ctx *fasthttp.RequestCtx) {
- ctx.SetStatusCode(fasthttp.StatusAccepted)
+ writer.WriteHeader(http.StatusOK)
+ })
+ return nil
})
+ if err != nil {
+ panic(err)
+ }
- _, err = bot.UpdatesViaWebhook("/", telego.WithWebhookServer(telego.FastHTTPWebhookServer{
- Logger: bot.Logger(),
- Server: &fasthttp.Server{},
- Router: r,
- }))
- assert(err == nil, err)
-
- go func() {
- err = bot.StartWebhook(":8080")
- assert(err == nil, err)
- }()
+ err = http.ListenAndServe(":8080", mux)
+ if err != nil {
+ panic(err)
+ }
- defer func() {
- _ = bot.StopWebhook()
- }()
- select {}
+ <-updates
case 27:
note := tu.File(mustOpen("note.mp4"))
- _, err = bot.SendVideoNote(tu.VideoNote(myID, note))
+ _, err = bot.SendVideoNote(ctx, tu.VideoNote(myID, note))
assert(err == nil, err)
case 28:
- err = bot.DeleteWebhook(nil)
+ err = bot.DeleteWebhook(ctx, nil)
fmt.Println(err)
case 29:
- _, err = bot.SendMessage(
+ _, err = bot.SendMessage(ctx,
tu.Message(myID, "Hmm").
WithReplyMarkup(
tu.InlineKeyboard(
@@ -690,48 +663,50 @@ func main() {
)
assert(err == nil, err)
case 30:
- _, err = bot.SendMessage(tu.Message(myID, "Reply?").
+ _, err = bot.SendMessage(ctx, tu.Message(myID, "Reply?").
WithReplyMarkup(tu.ForceReply().WithInputFieldPlaceholder("GG")))
assert(err == nil, err)
case 31:
- updates, _ := bot.UpdatesViaLongPolling(nil)
- defer bot.StopLongPolling()
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
bh, _ := th.NewBotHandler(bot, updates)
bh.Use(th.PanicRecovery())
bh.Use(
- func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ func(ctx *th.Context, update telego.Update) error {
fmt.Println("M 2")
- next(bot, update)
+ return ctx.Next(update)
},
- func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ func(ctx *th.Context, update telego.Update) error {
fmt.Println("M 3")
- next(bot, update)
+ return ctx.Next(update)
},
)
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
fmt.Println("REGULAR USER")
+ return nil
})
- adminUserMsg := bh.Group(th.AnyMessage(), func(update telego.Update) bool {
+ adminUserMsg := bh.Group(th.AnyMessage(), func(ctx context.Context, update telego.Update) bool {
ok := update.Message.From.ID == myID.ID
fmt.Println("OK", ok)
return ok
})
- adminUserMsg.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ adminUserMsg.HandleMessage(func(ctx *th.Context, message telego.Message) error {
fmt.Println("ADMIN USER")
+ return nil
})
- adminUserMsg.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ adminUserMsg.Use(func(ctx *th.Context, update telego.Update) error {
fmt.Println("M 4")
- next(bot, update)
+ return ctx.Next(update)
})
defer bh.Stop()
- bh.Start()
+ err = bh.Start()
+ assert(err == nil, err)
case 32:
- err = bot.CreateNewStickerSet(&telego.CreateNewStickerSetParams{
+ err = bot.CreateNewStickerSet(ctx, &telego.CreateNewStickerSetParams{
UserID: myID.ID,
Name: "the_test_by_ThenWhyBot",
Title: "The Test",
@@ -747,7 +722,7 @@ func main() {
})
assert(err == nil, err)
case 33:
- err = bot.AddStickerToSet(&telego.AddStickerToSetParams{
+ err = bot.AddStickerToSet(ctx, &telego.AddStickerToSetParams{
UserID: myID.ID,
Name: "the_test_by_ThenWhyBot",
Sticker: telego.InputSticker{
@@ -760,15 +735,53 @@ func main() {
})
assert(err == nil, err)
case 34:
- err = bot.SetMyDescription(&telego.SetMyDescriptionParams{
+ err = bot.SetMyDescription(ctx, &telego.SetMyDescriptionParams{
Description: "",
})
assert(err == nil, err)
- err = bot.SetMyShortDescription(&telego.SetMyShortDescriptionParams{
+ err = bot.SetMyShortDescription(ctx, &telego.SetMyShortDescriptionParams{
ShortDescription: "",
})
assert(err == nil, err)
+ case 35:
+ updates := make(chan telego.Update, 1)
+
+ bh, _ := th.NewBotHandler(nil, updates)
+
+ test := bh.Group()
+ test.Use(func(ctx *th.Context, update telego.Update) error {
+ fmt.Println("middleware")
+ // _ = ctx.Next(update)
+ return ctx.Next(update)
+ })
+ test.Handle(func(ctx *th.Context, update telego.Update) error {
+ panic("not here")
+ }, th.None())
+
+ test2 := test.Group()
+ test2.Use(func(ctx *th.Context, update telego.Update) error {
+ fmt.Println("middleware 2")
+ return ctx.Next(update)
+ })
+
+ test.Handle(func(ctx *th.Context, update telego.Update) error {
+ fmt.Println("handler 3")
+ return ctx.Next(update)
+ })
+
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
+ fmt.Println("handler")
+ return nil
+ })
+
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
+ fmt.Println("handler 2")
+ return nil
+ })
+
+ updates <- telego.Update{}
+ _ = bh.Start()
}
}
diff --git a/json.go b/json.go
index f64bf028..76712971 100644
--- a/json.go
+++ b/json.go
@@ -5,11 +5,12 @@ import "github.com/mymmrac/telego/internal/json"
// SetJSONMarshal set JSON marshal func used in Telego
//
// Warning: Panics if passed func is nil
+//
+// Warning: This method is not concurrently-safe, do not call if bot is already running
func SetJSONMarshal(marshal func(v any) ([]byte, error)) {
if marshal == nil {
panic("Telego: nil marshal func not allowed")
}
-
json.Marshal = marshal
}
@@ -18,10 +19,11 @@ func SetJSONMarshal(marshal func(v any) ([]byte, error)) {
// the correct type, not all libraries support this
//
// Warning: Panics if passed func is nil
+//
+// Warning: This method is not concurrently-safe, do not call if bot is already running
func SetJSONUnmarshal(unmarshal func(data []byte, v any) error) {
if unmarshal == nil {
panic("Telego: nil unmarshal func not allowed")
}
-
json.Unmarshal = unmarshal
}
diff --git a/json_test.go b/json_test.go
index f8ae2927..eb3a1cb0 100644
--- a/json_test.go
+++ b/json_test.go
@@ -1,3 +1,5 @@
+//go:build !race
+
package telego
import (
diff --git a/logger.go b/logger.go
index 313e09e9..efc8bf27 100644
--- a/logger.go
+++ b/logger.go
@@ -15,18 +15,24 @@ type Logger interface {
Errorf(format string, args ...any)
}
+// logMode represents logging mode
type logMode string
+// Logging modes
const (
debugMode logMode = "DEBUG"
errorMode logMode = "ERROR"
+)
+// ANSI escape codes
+const (
ansiReset = "\u001B[0m"
ansiRed = "\u001B[31m"
ansiYellow = "\u001B[33m"
ansiBlue = "\u001B[34m"
)
+// logger used to debug or error information
type logger struct {
Out io.Writer
DebugMode bool
@@ -36,6 +42,7 @@ type logger struct {
mutex sync.Mutex
}
+// newDefaultLogger creates new default logger
func newDefaultLogger(token string) *logger {
return &logger{
Out: os.Stderr,
@@ -45,6 +52,7 @@ func newDefaultLogger(token string) *logger {
}
}
+// prefix returns log prefix
func (l *logger) prefix(mode logMode) string {
timeNow := ansiBlue + time.Now().Format(time.UnixDate) + ansiReset
switch mode {
@@ -56,6 +64,7 @@ func (l *logger) prefix(mode logMode) string {
return "LOGGING "
}
+// log logs text
func (l *logger) log(mode logMode, text string) {
l.mutex.Lock()
defer l.mutex.Unlock()
@@ -71,12 +80,14 @@ func (l *logger) log(mode logMode, text string) {
}
}
+// Debugf logs debug information
func (l *logger) Debugf(format string, args ...any) {
if l.DebugMode {
l.log(debugMode, fmt.Sprintf(format+"\n", args...))
}
}
+// Errorf logs error information
func (l *logger) Errorf(format string, args ...any) {
if l.PrintErrors {
l.log(errorMode, fmt.Sprintf(format+"\n", args...))
@@ -86,6 +97,7 @@ func (l *logger) Errorf(format string, args ...any) {
// DefaultLoggerTokenReplacement used to replace bot token in logs when using default logger
const DefaultLoggerTokenReplacement = "BOT_TOKEN"
+// defaultReplacer returns replacer for default logger
func defaultReplacer(token string) *strings.Replacer {
return strings.NewReplacer(token, DefaultLoggerTokenReplacement)
}
diff --git a/long_polling.go b/long_polling.go
index 11d3f6aa..bbe7efd6 100644
--- a/long_polling.go
+++ b/long_polling.go
@@ -4,7 +4,7 @@ import (
"context"
"errors"
"fmt"
- "sync"
+ "slices"
"time"
)
@@ -17,48 +17,41 @@ const (
defaultLongPollingUpdateTimeoutInSeconds = 8 // 8s
)
-// longPollingContext represents configuration of getting updates via long polling
-type longPollingContext struct {
- running bool
- runningLock sync.RWMutex
- stop chan struct{}
- ctx context.Context
-
+// longPolling represents configuration of getting updates via long polling
+type longPolling struct {
updateChanBuffer uint
updateInterval time.Duration
retryTimeout time.Duration
}
-// LongPollingOption represents an option that can be applied to longPollingContext
-type LongPollingOption func(ctx *longPollingContext) error
+// LongPollingOption represents an option that can be applied to long polling
+type LongPollingOption func(lp *longPolling) error
// WithLongPollingUpdateInterval sets an update interval for long polling. Ensure that between two calls of
// [Bot.GetUpdates] method will be at least specified time, but it could be longer.
// Default is 0s.
-// Note: Telegram has built in a timeout mechanism, to properly use it, set GetUpdatesParams.Timeout to desired timeout
-// and update interval to 0 (default, recommended way).
+// Note: Telegram has built in a timeout mechanism, to properly use it, set [GetUpdatesParams.Timeout] to desired
+// timeout and update interval to 0 (default, recommended way).
func WithLongPollingUpdateInterval(updateInterval time.Duration) LongPollingOption {
- return func(ctx *longPollingContext) error {
+ return func(lp *longPolling) error {
if updateInterval < 0 {
return fmt.Errorf("update interval is negative: %s", updateInterval)
}
-
- ctx.updateInterval = updateInterval
+ lp.updateInterval = updateInterval
return nil
}
}
// WithLongPollingRetryTimeout sets updates retry timeout for long polling.
// Ensure that between two calls of [Bot.GetUpdates] method will be at least specified time if an error occurred,
-// but it could be longer.
+// but it could be longer. If zero is passed, reties will be disabled and on error update chan will be closed.
// Default is 8s.
func WithLongPollingRetryTimeout(retryTimeout time.Duration) LongPollingOption {
- return func(ctx *longPollingContext) error {
+ return func(lp *longPolling) error {
if retryTimeout < 0 {
return fmt.Errorf("retry timeout is negative: %s", retryTimeout)
}
-
- ctx.retryTimeout = retryTimeout
+ lp.retryTimeout = retryTimeout
return nil
}
}
@@ -66,83 +59,78 @@ func WithLongPollingRetryTimeout(retryTimeout time.Duration) LongPollingOption {
// WithLongPollingBuffer sets buffering for update chan.
// Default is 100.
func WithLongPollingBuffer(chanBuffer uint) LongPollingOption {
- return func(ctx *longPollingContext) error {
- ctx.updateChanBuffer = chanBuffer
- return nil
- }
-}
-
-// WithLongPollingContext sets context used in long polling, this context will be added to each update
-//
-// Warning: Canceling the context doesn't stop long polling, it only closes update chan,
-// be sure to stop long polling by calling [Bot.StopLongPolling] method
-func WithLongPollingContext(ctx context.Context) LongPollingOption {
- return func(lCtx *longPollingContext) error {
- if ctx == nil {
- return errors.New("context is nil")
- }
-
- lCtx.ctx = ctx //nolint:fatcontext
+ return func(lp *longPolling) error {
+ lp.updateChanBuffer = chanBuffer
return nil
}
}
// UpdatesViaLongPolling receive updates in chan using the [Bot.GetUpdates] method.
-// Calling if already running (before [Bot.StopLongPolling] method) will return an error.
-// Note: After you done with getting updates, you should call [Bot.StopLongPolling] method which will close update chan.
+// Calling if already running long polling or webhook will return an error.
//
// Warning: If nil is passed as get update parameters, then the default timeout of 8s will be applied,
// but if a non-nil parameter is passed, you should remember to explicitly specify timeout
-func (b *Bot) UpdatesViaLongPolling(params *GetUpdatesParams, options ...LongPollingOption) (<-chan Update, error) {
- if b.longPollingContext != nil {
- return nil, errors.New("telego: long polling context already exists")
+//
+// Note: After you done with getting updates, you should close context this will close the update chan
+// Note: Value of params is reused to call [Bot.GetUpdates] method many times, because of this we copy params value
+func (b *Bot) UpdatesViaLongPolling(
+ ctx context.Context, params *GetUpdatesParams, options ...LongPollingOption,
+) (<-chan Update, error) {
+ if err := b.run(runningLongPolling); err != nil {
+ return nil, err
}
- ctx, err := b.createLongPollingContext(options)
+ lp, err := b.createLongPolling(options)
if err != nil {
+ b.running.Store(runningNone)
return nil, err
}
- ctx.runningLock.Lock()
- defer ctx.runningLock.Unlock()
-
- b.longPollingContext = ctx
- ctx.stop = make(chan struct{})
- ctx.running = true
-
- updatesChan := make(chan Update, ctx.updateChanBuffer)
+ updatesChan := make(chan Update, lp.updateChanBuffer)
if params == nil {
params = &GetUpdatesParams{
Timeout: defaultLongPollingUpdateTimeoutInSeconds,
}
+ } else {
+ params = &GetUpdatesParams{
+ Offset: params.Offset,
+ Limit: params.Limit,
+ Timeout: params.Timeout,
+ AllowedUpdates: slices.Clone(params.AllowedUpdates),
+ }
}
- go b.doLongPolling(ctx, params, updatesChan)
+ go b.doLongPolling(ctx, lp, params, updatesChan)
return updatesChan, nil
}
-func (b *Bot) doLongPolling(ctx *longPollingContext, params *GetUpdatesParams, updatesChan chan<- Update) {
- defer close(updatesChan)
+// doLongPolling receive updates in chan using the [Bot.GetUpdates] method
+func (b *Bot) doLongPolling(ctx context.Context, lp *longPolling, params *GetUpdatesParams, updatesChan chan<- Update) {
+ defer func() {
+ b.running.Store(runningNone)
+ close(updatesChan)
+ }()
for {
select {
- case <-ctx.stop:
- return
- case <-ctx.ctx.Done():
+ case <-ctx.Done():
return
default:
// Continue getting updates
}
var updates []Update
- updates, err := b.GetUpdates(params)
+ updates, err := b.GetUpdates(ctx, params)
if err != nil {
b.log.Errorf("Getting updates: %s", err)
- b.log.Errorf("Retrying to get updates in %s", ctx.retryTimeout.String())
+ if lp.retryTimeout == 0 || errors.Is(err, context.Canceled) {
+ return
+ }
- time.Sleep(ctx.retryTimeout)
+ b.log.Errorf("Retrying getting updates in %s...", lp.retryTimeout.String())
+ time.Sleep(lp.retryTimeout)
continue
}
@@ -151,69 +139,33 @@ func (b *Bot) doLongPolling(ctx *longPollingContext, params *GetUpdatesParams, u
params.Offset = update.UpdateID + 1
select {
- case <-ctx.stop:
+ case <-ctx.Done():
return
- case <-ctx.ctx.Done():
- return
- default:
- if safeSend(updatesChan, update.WithContext(ctx.ctx)) {
- b.log.Debugf("Long polling update chan closed")
- return
- }
+ case updatesChan <- update.WithContext(ctx):
+ // Continue
}
}
}
- time.Sleep(ctx.updateInterval)
+ if lp.updateInterval > 0 {
+ time.Sleep(lp.updateInterval)
+ }
}
}
-func (b *Bot) createLongPollingContext(options []LongPollingOption) (*longPollingContext, error) {
- ctx := &longPollingContext{
+// createLongPolling create new long polling configuration
+func (b *Bot) createLongPolling(options []LongPollingOption) (*longPolling, error) {
+ lp := &longPolling{
updateChanBuffer: defaultLongPollingUpdateChanBuffer,
updateInterval: defaultLongPollingUpdateInterval,
retryTimeout: defaultLongPollingRetryTimeout,
- ctx: context.Background(),
}
for _, option := range options {
- if err := option(ctx); err != nil {
- return nil, fmt.Errorf("telego: options: %w", err)
+ if err := option(lp); err != nil {
+ return nil, fmt.Errorf("telego: long polling options: %w", err)
}
}
- return ctx, nil
-}
-
-// IsRunningLongPolling tells if [Bot.UpdatesViaLongPolling] method is running
-func (b *Bot) IsRunningLongPolling() bool {
- ctx := b.longPollingContext
- if ctx == nil {
- return false
- }
-
- ctx.runningLock.RLock()
- defer ctx.runningLock.RUnlock()
-
- return ctx.running
-}
-
-// StopLongPolling stop reviving updates from [Bot.UpdatesViaLongPolling] method, stopping is non-blocking, it closes
-// update chan, so it's caller's responsibility to process all unhandled updates after calling stop.
-// Stop will only ensure that no more updates will come in update chan.
-// Calling [Bot.StopLongPolling] method multiple times will do nothing.
-func (b *Bot) StopLongPolling() {
- ctx := b.longPollingContext
- if ctx == nil {
- return
- }
-
- ctx.runningLock.Lock()
- defer ctx.runningLock.Unlock()
-
- if ctx.running {
- close(ctx.stop)
- ctx.running = false
- b.longPollingContext = nil
- }
+ return lp, nil
}
diff --git a/long_polling_test.go b/long_polling_test.go
index e72fef2d..d1ce8e4b 100644
--- a/long_polling_test.go
+++ b/long_polling_test.go
@@ -1,7 +1,6 @@
package telego
import (
- "context"
"testing"
"time"
@@ -10,6 +9,8 @@ import (
"go.uber.org/mock/gomock"
)
+const timeout = time.Second
+
func TestBot_UpdatesViaLongPolling(t *testing.T) {
ctrl := gomock.NewController(t)
@@ -26,15 +27,20 @@ func TestBot_UpdatesViaLongPolling(t *testing.T) {
}
resp := telegoResponse(t, expectedUpdates)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil).MinTimes(1)
assert.NotPanics(t, func() {
- _, err := m.Bot.UpdatesViaLongPolling(nil)
+ updates, err := m.Bot.UpdatesViaLongPolling(testCtx, nil)
require.NoError(t, err)
+
time.Sleep(time.Millisecond * 10)
- m.Bot.StopLongPolling()
- time.Sleep(time.Millisecond * 500)
+ select {
+ case <-time.After(timeout):
+ t.Fatal("Timeout")
+ case update := <-updates:
+ assert.NotZero(t, update.UpdateID)
+ }
})
})
@@ -46,10 +52,9 @@ func TestBot_UpdatesViaLongPolling(t *testing.T) {
Return(nil, errTest).MinTimes(1)
assert.NotPanics(t, func() {
- _, err := m.Bot.UpdatesViaLongPolling(nil)
+ _, err := m.Bot.UpdatesViaLongPolling(testCtx, nil)
require.NoError(t, err)
time.Sleep(time.Millisecond * 10)
- m.Bot.StopLongPolling()
})
})
@@ -61,13 +66,11 @@ func TestBot_UpdatesViaLongPolling(t *testing.T) {
Return(nil, errTest).AnyTimes()
assert.NotPanics(t, func() {
- _, err := m.Bot.UpdatesViaLongPolling(nil)
+ _, err := m.Bot.UpdatesViaLongPolling(testCtx, nil)
require.NoError(t, err)
- _, err = m.Bot.UpdatesViaLongPolling(nil)
+ _, err = m.Bot.UpdatesViaLongPolling(testCtx, nil)
require.Error(t, err)
-
- m.Bot.StopLongPolling()
})
})
@@ -75,100 +78,14 @@ func TestBot_UpdatesViaLongPolling(t *testing.T) {
m := newMockedBot(ctrl)
assert.NotPanics(t, func() {
- _, err := m.Bot.UpdatesViaLongPolling(nil, WithLongPollingUpdateInterval(-time.Second))
+ _, err := m.Bot.UpdatesViaLongPolling(testCtx, nil, WithLongPollingUpdateInterval(-time.Second))
require.Error(t, err)
})
})
-
- t.Run("success_with_context", func(t *testing.T) {
- m := newMockedBot(ctrl)
-
- m.MockRequestConstructor.EXPECT().
- JSONRequest(gomock.Any()).
- Return(data, nil).MinTimes(1)
-
- expectedUpdates := []Update{
- {UpdateID: 1},
- {UpdateID: 2},
- }
- resp := telegoResponse(t, expectedUpdates)
- m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
- Return(resp, nil).MinTimes(1)
-
- assert.NotPanics(t, func() {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- updates, err := m.Bot.UpdatesViaLongPolling(nil, WithLongPollingContext(ctx))
- require.NoError(t, err)
-
- time.Sleep(time.Millisecond * 10)
-
- cancel()
- <-updates
-
- assert.True(t, m.Bot.IsRunningLongPolling())
- m.Bot.StopLongPolling()
- assert.False(t, m.Bot.IsRunningLongPolling())
- })
- })
-}
-
-func TestBot_IsRunningLongPolling(t *testing.T) {
- ctrl := gomock.NewController(t)
- m := newMockedBot(ctrl)
-
- t.Run("stopped", func(t *testing.T) {
- assert.False(t, m.Bot.IsRunningLongPolling())
- })
-
- t.Run("running", func(t *testing.T) {
- m.MockRequestConstructor.EXPECT().
- JSONRequest(gomock.Any()).
- Return(data, nil).AnyTimes()
-
- resp := telegoResponse(t, []Update{})
- m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
- Return(resp, nil).AnyTimes()
-
- _, err := m.Bot.UpdatesViaLongPolling(nil)
- require.NoError(t, err)
-
- assert.True(t, m.Bot.IsRunningLongPolling())
-
- m.Bot.StopLongPolling()
- assert.False(t, m.Bot.IsRunningLongPolling())
- })
-}
-
-func TestBot_StopLongPolling(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- bot := &Bot{}
-
- bot.longPollingContext = &longPollingContext{
- running: true,
- stop: make(chan struct{}),
- }
- assert.NotPanics(t, func() {
- bot.StopLongPolling()
- })
-
- assert.Nil(t, bot.longPollingContext)
- })
-
- t.Run("success_no_context", func(t *testing.T) {
- bot := &Bot{}
-
- assert.NotPanics(t, func() {
- bot.StopLongPolling()
- })
- })
}
func TestWithLongPollingUpdateInterval(t *testing.T) {
- ctx := &longPollingContext{}
+ ctx := &longPolling{}
interval := time.Second
t.Run("success", func(t *testing.T) {
@@ -184,8 +101,7 @@ func TestWithLongPollingUpdateInterval(t *testing.T) {
}
func TestWithLongPollingRetryTimeout(t *testing.T) {
- ctx := &longPollingContext{}
- timeout := time.Second
+ ctx := &longPolling{}
t.Run("success", func(t *testing.T) {
err := WithLongPollingRetryTimeout(timeout)(ctx)
@@ -200,27 +116,10 @@ func TestWithLongPollingRetryTimeout(t *testing.T) {
}
func TestWithLongPollingBuffer(t *testing.T) {
- ctx := &longPollingContext{}
+ ctx := &longPolling{}
buffer := uint(1)
err := WithLongPollingBuffer(buffer)(ctx)
require.NoError(t, err)
assert.EqualValues(t, buffer, ctx.updateChanBuffer)
}
-
-func TestWithLongPollingContext(t *testing.T) {
- lCtx := &longPollingContext{}
-
- t.Run("success", func(t *testing.T) {
- ctx := context.Background()
- err := WithLongPollingContext(ctx)(lCtx)
- require.NoError(t, err)
- assert.EqualValues(t, ctx, lCtx.ctx)
- })
-
- t.Run("error", func(t *testing.T) {
- //nolint:staticcheck
- err := WithLongPollingContext(nil)(lCtx)
- require.Error(t, err)
- })
-}
diff --git a/methods.go b/methods.go
index 7389252d..ed0806e9 100644
--- a/methods.go
+++ b/methods.go
@@ -1,6 +1,7 @@
package telego
import (
+ "context"
"fmt"
ta "github.com/mymmrac/telego/telegoapi"
@@ -36,34 +37,40 @@ type GetUpdatesParams struct {
// Update types you want your bot to receive
const (
- MessageUpdates = "message"
- EditedMessageUpdates = "edited_message"
- ChannelPostUpdates = "channel_post"
- EditedChannelPostUpdates = "edited_channel_post"
- MessageReaction = "message_reaction"
- MessageReactionCount = "message_reaction_count"
- InlineQueryUpdates = "inline_query"
- ChosenInlineResultUpdates = "chosen_inline_result"
- CallbackQueryUpdates = "callback_query"
- ShippingQueryUpdates = "shipping_query"
- PreCheckoutQueryUpdates = "pre_checkout_query"
- PollUpdates = "poll"
- PollAnswerUpdates = "poll_answer"
- MyChatMemberUpdates = "my_chat_member"
- ChatMemberUpdates = "chat_member"
- ChatJoinRequestUpdates = "chat_join_request"
+ MessageUpdates = "message"
+ EditedMessageUpdates = "edited_message"
+ ChannelPostUpdates = "channel_post"
+ EditedChannelPostUpdates = "edited_channel_post"
+ BusinessConnectionUpdates = "business_connection"
+ BusinessMessageUpdates = "business_message"
+ EditedBusinessMessageUpdates = "edited_business_message"
+ DeletedBusinessMessagesUpdates = "deleted_business_messages"
+ MessageReactionUpdates = "message_reaction"
+ MessageReactionCountUpdates = "message_reaction_count"
+ InlineQueryUpdates = "inline_query"
+ ChosenInlineResultUpdates = "chosen_inline_result"
+ CallbackQueryUpdates = "callback_query"
+ ShippingQueryUpdates = "shipping_query"
+ PreCheckoutQueryUpdates = "pre_checkout_query"
+ PurchasedPaidMediaUpdates = "purchased_paid_media"
+ PollUpdates = "poll"
+ PollAnswerUpdates = "poll_answer"
+ MyChatMemberUpdates = "my_chat_member"
+ ChatMemberUpdates = "chat_member"
+ ChatJoinRequestUpdates = "chat_join_request"
+ ChatBoostUpdates = "chat_boost"
+ RemovedChatBoostUpdates = "removed_chat_boost"
)
// GetUpdates - Use this method to receive incoming updates using long polling (wiki
// (https://en.wikipedia.org/wiki/Push_technology#Long_polling)). Returns an Array of Update
// (https://core.telegram.org/bots/api#update) objects.
-func (b *Bot) GetUpdates(params *GetUpdatesParams) ([]Update, error) {
+func (b *Bot) GetUpdates(ctx context.Context, params *GetUpdatesParams) ([]Update, error) {
var updates []Update
- err := b.performRequest("getUpdates", params, &updates)
+ err := b.performRequest(ctx, "getUpdates", params, &updates)
if err != nil {
- return nil, fmt.Errorf("telego: getUpdates(): %w", err)
+ return nil, fmt.Errorf("telego: getUpdates: %w", err)
}
-
return updates, nil
}
@@ -123,12 +130,11 @@ func (p *SetWebhookParams) fileParameters() map[string]ta.NamedReader {
// If you'd like to make sure that the webhook was set by you, you can specify secret data in the parameter
// secret_token. If specified, the request will contain a header “X-Telegram-Bot-Api-Secret-Token” with the
// secret token as content.
-func (b *Bot) SetWebhook(params *SetWebhookParams) error {
- err := b.performRequest("setWebhook", params)
+func (b *Bot) SetWebhook(ctx context.Context, params *SetWebhookParams) error {
+ err := b.performRequest(ctx, "setWebhook", params)
if err != nil {
- return fmt.Errorf("telego: setWebhook(): %w", err)
+ return fmt.Errorf("telego: setWebhook: %w", err)
}
-
return nil
}
@@ -140,37 +146,34 @@ type DeleteWebhookParams struct {
// DeleteWebhook - Use this method to remove webhook integration if you decide to switch back to getUpdates
// (https://core.telegram.org/bots/api#getupdates). Returns True on success.
-func (b *Bot) DeleteWebhook(params *DeleteWebhookParams) error {
- err := b.performRequest("deleteWebhook", params)
+func (b *Bot) DeleteWebhook(ctx context.Context, params *DeleteWebhookParams) error {
+ err := b.performRequest(ctx, "deleteWebhook", params)
if err != nil {
- return fmt.Errorf("telego: deleteWebhook(): %w", err)
+ return fmt.Errorf("telego: deleteWebhook: %w", err)
}
-
return nil
}
// GetWebhookInfo - Use this method to get current webhook status. Requires no parameters. On success,
// returns a WebhookInfo (https://core.telegram.org/bots/api#webhookinfo) object. If the bot is using getUpdates
// (https://core.telegram.org/bots/api#getupdates), will return an object with the URL field empty.
-func (b *Bot) GetWebhookInfo() (*WebhookInfo, error) {
+func (b *Bot) GetWebhookInfo(ctx context.Context) (*WebhookInfo, error) {
var webhookInfo *WebhookInfo
- err := b.performRequest("getWebhookInfo", nil, &webhookInfo)
+ err := b.performRequest(ctx, "getWebhookInfo", nil, &webhookInfo)
if err != nil {
- return nil, fmt.Errorf("telego: getWebhookInfo(): %w", err)
+ return nil, fmt.Errorf("telego: getWebhookInfo: %w", err)
}
-
return webhookInfo, nil
}
// GetMe - A simple method for testing your bot's authentication token. Requires no parameters. Returns basic
// information about the bot in form of a User (https://core.telegram.org/bots/api#user) object.
-func (b *Bot) GetMe() (*User, error) {
+func (b *Bot) GetMe(ctx context.Context) (*User, error) {
var user *User
- err := b.performRequest("getMe", nil, &user)
+ err := b.performRequest(ctx, "getMe", nil, &user)
if err != nil {
- return nil, fmt.Errorf("telego: getMe(): %w", err)
+ return nil, fmt.Errorf("telego: getMe: %w", err)
}
-
return user, nil
}
@@ -178,12 +181,11 @@ func (b *Bot) GetMe() (*User, error) {
// must log out the bot before running it locally, otherwise there is no guarantee that the bot will receive
// updates. After a successful call, you can immediately log in on a local server, but will not be able to log
// in back to the cloud Bot API server for 10 minutes. Returns True on success. Requires no parameters.
-func (b *Bot) LogOut() error {
- err := b.performRequest("logOut", nil)
+func (b *Bot) LogOut(ctx context.Context) error {
+ err := b.performRequest(ctx, "logOut", nil)
if err != nil {
- return fmt.Errorf("telego: logOut(): %w", err)
+ return fmt.Errorf("telego: logOut: %w", err)
}
-
return nil
}
@@ -191,12 +193,11 @@ func (b *Bot) LogOut() error {
// need to delete the webhook before calling this method to ensure that the bot isn't launched again after
// server restart. The method will return error 429 in the first 10 minutes after the bot is launched. Returns
// True on success. Requires no parameters.
-func (b *Bot) Close() error {
- err := b.performRequest("close", nil)
+func (b *Bot) Close(ctx context.Context) error {
+ err := b.performRequest(ctx, "close", nil)
if err != nil {
- return fmt.Errorf("telego: close(): %w", err)
+ return fmt.Errorf("telego: close: %w", err)
}
-
return nil
}
@@ -263,13 +264,12 @@ const (
// SendMessage - Use this method to send text messages. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendMessage(params *SendMessageParams) (*Message, error) {
+func (b *Bot) SendMessage(ctx context.Context, params *SendMessageParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendMessage", params, &message)
+ err := b.performRequest(ctx, "sendMessage", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendMessage(): %w", err)
+ return nil, fmt.Errorf("telego: sendMessage: %w", err)
}
-
return message, nil
}
@@ -301,13 +301,12 @@ type ForwardMessageParams struct {
// ForwardMessage - Use this method to forward messages of any kind. Service messages and messages with
// protected content can't be forwarded. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) ForwardMessage(params *ForwardMessageParams) (*Message, error) {
+func (b *Bot) ForwardMessage(ctx context.Context, params *ForwardMessageParams) (*Message, error) {
var message *Message
- err := b.performRequest("forwardMessage", params, &message)
+ err := b.performRequest(ctx, "forwardMessage", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: forwardMessage(): %w", err)
+ return nil, fmt.Errorf("telego: forwardMessage: %w", err)
}
-
return message, nil
}
@@ -341,13 +340,12 @@ type ForwardMessagesParams struct {
// messages can't be found or forwarded, they are skipped. Service messages and messages with protected content
// can't be forwarded. Album grouping is kept for forwarded messages. On success, an array of MessageID
// (https://core.telegram.org/bots/api#messageid) of the sent messages is returned.
-func (b *Bot) ForwardMessages(params *ForwardMessagesParams) ([]MessageID, error) {
+func (b *Bot) ForwardMessages(ctx context.Context, params *ForwardMessagesParams) ([]MessageID, error) {
var messageIDs []MessageID
- err := b.performRequest("forwardMessages", params, &messageIDs)
+ err := b.performRequest(ctx, "forwardMessages", params, &messageIDs)
if err != nil {
- return nil, fmt.Errorf("telego: forwardMessages(): %w", err)
+ return nil, fmt.Errorf("telego: forwardMessages: %w", err)
}
-
return messageIDs, nil
}
@@ -413,13 +411,12 @@ type CopyMessageParams struct {
// (https://core.telegram.org/bots/api#forwardmessage), but the copied message doesn't have a link to the
// original message. Returns the MessageID (https://core.telegram.org/bots/api#messageid) of the sent message on
// success.
-func (b *Bot) CopyMessage(params *CopyMessageParams) (*MessageID, error) {
+func (b *Bot) CopyMessage(ctx context.Context, params *CopyMessageParams) (*MessageID, error) {
var messageID *MessageID
- err := b.performRequest("copyMessage", params, &messageID)
+ err := b.performRequest(ctx, "copyMessage", params, &messageID)
if err != nil {
- return nil, fmt.Errorf("telego: copyMessage(): %w", err)
+ return nil, fmt.Errorf("telego: copyMessage: %w", err)
}
-
return messageID, nil
}
@@ -459,13 +456,12 @@ type CopyMessagesParams struct {
// method forwardMessages (https://core.telegram.org/bots/api#forwardmessages), but the copied messages don't
// have a link to the original message. Album grouping is kept for copied messages. On success, an array of
// MessageID (https://core.telegram.org/bots/api#messageid) of the sent messages is returned.
-func (b *Bot) CopyMessages(params *CopyMessagesParams) ([]MessageID, error) {
+func (b *Bot) CopyMessages(ctx context.Context, params *CopyMessagesParams) ([]MessageID, error) {
var messageIDs []MessageID
- err := b.performRequest("copyMessages", params, &messageIDs)
+ err := b.performRequest(ctx, "copyMessages", params, &messageIDs)
if err != nil {
- return nil, fmt.Errorf("telego: copyMessages(): %w", err)
+ return nil, fmt.Errorf("telego: copyMessages: %w", err)
}
-
return messageIDs, nil
}
@@ -542,13 +538,12 @@ func (p *SendPhotoParams) fileParameters() map[string]ta.NamedReader {
// SendPhoto - Use this method to send photos. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendPhoto(params *SendPhotoParams) (*Message, error) {
+func (b *Bot) SendPhoto(ctx context.Context, params *SendPhotoParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendPhoto", params, &message)
+ err := b.performRequest(ctx, "sendPhoto", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendPhoto(): %w", err)
+ return nil, fmt.Errorf("telego: sendPhoto: %w", err)
}
-
return message, nil
}
@@ -642,13 +637,12 @@ func (p *SendAudioParams) fileParameters() map[string]ta.NamedReader {
// (https://core.telegram.org/bots/api#message) is returned. Bots can currently send audio files of up to 50 MB
// in size, this limit may be changed in the future.
// For sending voice messages, use the sendVoice (https://core.telegram.org/bots/api#sendvoice) method instead.
-func (b *Bot) SendAudio(params *SendAudioParams) (*Message, error) {
+func (b *Bot) SendAudio(ctx context.Context, params *SendAudioParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendAudio", params, &message)
+ err := b.performRequest(ctx, "sendAudio", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendAudio(): %w", err)
+ return nil, fmt.Errorf("telego: sendAudio: %w", err)
}
-
return message, nil
}
@@ -736,13 +730,12 @@ func (p *SendDocumentParams) fileParameters() map[string]ta.NamedReader {
// SendDocument - Use this method to send general files. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned. Bots can currently send files of any type of up to
// 50 MB in size, this limit may be changed in the future.
-func (b *Bot) SendDocument(params *SendDocumentParams) (*Message, error) {
+func (b *Bot) SendDocument(ctx context.Context, params *SendDocumentParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendDocument", params, &message)
+ err := b.performRequest(ctx, "sendDocument", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendDocument(): %w", err)
+ return nil, fmt.Errorf("telego: sendDocument: %w", err)
}
-
return message, nil
}
@@ -845,13 +838,12 @@ func (p *SendVideoParams) fileParameters() map[string]ta.NamedReader {
// be sent as Document (https://core.telegram.org/bots/api#document)). On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned. Bots can currently send video files of up to 50 MB
// in size, this limit may be changed in the future.
-func (b *Bot) SendVideo(params *SendVideoParams) (*Message, error) {
+func (b *Bot) SendVideo(ctx context.Context, params *SendVideoParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendVideo", params, &message)
+ err := b.performRequest(ctx, "sendVideo", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendVideo(): %w", err)
+ return nil, fmt.Errorf("telego: sendVideo: %w", err)
}
-
return message, nil
}
@@ -950,13 +942,12 @@ func (p *SendAnimationParams) fileParameters() map[string]ta.NamedReader {
// SendAnimation - Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). On
// success, the sent Message (https://core.telegram.org/bots/api#message) is returned. Bots can currently send
// animation files of up to 50 MB in size, this limit may be changed in the future.
-func (b *Bot) SendAnimation(params *SendAnimationParams) (*Message, error) {
+func (b *Bot) SendAnimation(ctx context.Context, params *SendAnimationParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendAnimation", params, &message)
+ err := b.performRequest(ctx, "sendAnimation", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendAnimation(): %w", err)
+ return nil, fmt.Errorf("telego: sendAnimation: %w", err)
}
-
return message, nil
}
@@ -1032,13 +1023,12 @@ func (p *SendVoiceParams) fileParameters() map[string]ta.NamedReader {
// Document (https://core.telegram.org/bots/api#document)). On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned. Bots can currently send voice messages of up to 50
// MB in size, this limit may be changed in the future.
-func (b *Bot) SendVoice(params *SendVoiceParams) (*Message, error) {
+func (b *Bot) SendVoice(ctx context.Context, params *SendVoiceParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendVoice", params, &message)
+ err := b.performRequest(ctx, "sendVoice", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendVoice(): %w", err)
+ return nil, fmt.Errorf("telego: sendVoice: %w", err)
}
-
return message, nil
}
@@ -1115,13 +1105,12 @@ func (p *SendVideoNoteParams) fileParameters() map[string]ta.NamedReader {
// SendVideoNote - As of v.4.0 (https://telegram.org/blog/video-messages-and-telescope), Telegram clients
// support rounded square MPEG4 videos of up to 1 minute long. Use this method to send video messages. On
// success, the sent Message (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendVideoNote(params *SendVideoNoteParams) (*Message, error) {
+func (b *Bot) SendVideoNote(ctx context.Context, params *SendVideoNoteParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendVideoNote", params, &message)
+ err := b.performRequest(ctx, "sendVideoNote", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendVideoNote(): %w", err)
+ return nil, fmt.Errorf("telego: sendVideoNote: %w", err)
}
-
return message, nil
}
@@ -1184,13 +1173,12 @@ type SendPaidMediaParams struct {
// SendPaidMedia - Use this method to send paid media. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendPaidMedia(params *SendPaidMediaParams) (*Message, error) {
+func (b *Bot) SendPaidMedia(ctx context.Context, params *SendPaidMediaParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendPaidMedia", params, &message)
+ err := b.performRequest(ctx, "sendPaidMedia", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendPaidMedia(): %w", err)
+ return nil, fmt.Errorf("telego: sendPaidMedia: %w", err)
}
-
return message, nil
}
@@ -1249,13 +1237,12 @@ func (p *SendMediaGroupParams) fileParameters() map[string]ta.NamedReader {
// SendMediaGroup - Use this method to send a group of photos, videos, documents or audios as an album.
// Documents and audio files can be only grouped in an album with messages of the same type. On success, an
// array of Messages (https://core.telegram.org/bots/api#message) that were sent is returned.
-func (b *Bot) SendMediaGroup(params *SendMediaGroupParams) ([]Message, error) {
+func (b *Bot) SendMediaGroup(ctx context.Context, params *SendMediaGroupParams) ([]Message, error) {
var messages []Message
- err := b.performRequest("sendMediaGroup", params, &messages)
+ err := b.performRequest(ctx, "sendMediaGroup", params, &messages)
if err != nil {
- return nil, fmt.Errorf("telego: sendMediaGroup(): %w", err)
+ return nil, fmt.Errorf("telego: sendMediaGroup: %w", err)
}
-
return messages, nil
}
@@ -1323,13 +1310,12 @@ type SendLocationParams struct {
// SendLocation - Use this method to send point on the map. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendLocation(params *SendLocationParams) (*Message, error) {
+func (b *Bot) SendLocation(ctx context.Context, params *SendLocationParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendLocation", params, &message)
+ err := b.performRequest(ctx, "sendLocation", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendLocation(): %w", err)
+ return nil, fmt.Errorf("telego: sendLocation: %w", err)
}
-
return message, nil
}
@@ -1401,13 +1387,12 @@ type SendVenueParams struct {
// SendVenue - Use this method to send information about a venue. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendVenue(params *SendVenueParams) (*Message, error) {
+func (b *Bot) SendVenue(ctx context.Context, params *SendVenueParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendVenue", params, &message)
+ err := b.performRequest(ctx, "sendVenue", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendVenue(): %w", err)
+ return nil, fmt.Errorf("telego: sendVenue: %w", err)
}
-
return message, nil
}
@@ -1466,13 +1451,12 @@ type SendContactParams struct {
// SendContact - Use this method to send phone contacts. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendContact(params *SendContactParams) (*Message, error) {
+func (b *Bot) SendContact(ctx context.Context, params *SendContactParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendContact", params, &message)
+ err := b.performRequest(ctx, "sendContact", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendContact(): %w", err)
+ return nil, fmt.Errorf("telego: sendContact: %w", err)
}
-
return message, nil
}
@@ -1571,13 +1555,12 @@ type SendPollParams struct {
// SendPoll - Use this method to send a native poll. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendPoll(params *SendPollParams) (*Message, error) {
+func (b *Bot) SendPoll(ctx context.Context, params *SendPollParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendPoll", params, &message)
+ err := b.performRequest(ctx, "sendPoll", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendPoll(): %w", err)
+ return nil, fmt.Errorf("telego: sendPoll: %w", err)
}
-
return message, nil
}
@@ -1629,13 +1612,12 @@ type SendDiceParams struct {
// SendDice - Use this method to send an animated emoji that will display a random value. On success, the
// sent Message (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendDice(params *SendDiceParams) (*Message, error) {
+func (b *Bot) SendDice(ctx context.Context, params *SendDiceParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendDice", params, &message)
+ err := b.performRequest(ctx, "sendDice", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendDice(): %w", err)
+ return nil, fmt.Errorf("telego: sendDice: %w", err)
}
-
return message, nil
}
@@ -1688,12 +1670,11 @@ const (
// see a “sending photo” status for the bot.
// We only recommend using this method when a response from the bot will take a noticeable amount of time to
// arrive.
-func (b *Bot) SendChatAction(params *SendChatActionParams) error {
- err := b.performRequest("sendChatAction", params)
+func (b *Bot) SendChatAction(ctx context.Context, params *SendChatActionParams) error {
+ err := b.performRequest(ctx, "sendChatAction", params)
if err != nil {
- return fmt.Errorf("telego: sendChatAction(): %w", err)
+ return fmt.Errorf("telego: sendChatAction: %w", err)
}
-
return nil
}
@@ -1720,12 +1701,11 @@ type SetMessageReactionParams struct {
// SetMessageReaction - Use this method to change the chosen reactions on a message. Service messages can't
// be reacted to. Automatically forwarded messages from a channel to its discussion group have the same
// available reactions as messages in the channel. Bots can't use paid reactions. Returns True on success.
-func (b *Bot) SetMessageReaction(params *SetMessageReactionParams) error {
- err := b.performRequest("setMessageReaction", params)
+func (b *Bot) SetMessageReaction(ctx context.Context, params *SetMessageReactionParams) error {
+ err := b.performRequest(ctx, "setMessageReaction", params)
if err != nil {
- return fmt.Errorf("telego: setMessageReaction(): %w", err)
+ return fmt.Errorf("telego: setMessageReaction: %w", err)
}
-
return nil
}
@@ -1745,13 +1725,12 @@ type GetUserProfilePhotosParams struct {
// GetUserProfilePhotos - Use this method to get a list of profile pictures for a user. Returns a
// UserProfilePhotos (https://core.telegram.org/bots/api#userprofilephotos) object.
-func (b *Bot) GetUserProfilePhotos(params *GetUserProfilePhotosParams) (*UserProfilePhotos, error) {
+func (b *Bot) GetUserProfilePhotos(ctx context.Context, params *GetUserProfilePhotosParams) (*UserProfilePhotos, error) {
var userProfilePhotos *UserProfilePhotos
- err := b.performRequest("getUserProfilePhotos", params, &userProfilePhotos)
+ err := b.performRequest(ctx, "getUserProfilePhotos", params, &userProfilePhotos)
if err != nil {
- return nil, fmt.Errorf("telego: getUserProfilePhotos(): %w", err)
+ return nil, fmt.Errorf("telego: getUserProfilePhotos: %w", err)
}
-
return userProfilePhotos, nil
}
@@ -1771,12 +1750,11 @@ type SetUserEmojiStatusParams struct {
// SetUserEmojiStatus - Changes the emoji status for a given user that previously allowed the bot to manage
// their emoji status via the Mini App method requestEmojiStatusAccess
// (https://core.telegram.org/bots/webapps#initializing-mini-apps). Returns True on success.
-func (b *Bot) SetUserEmojiStatus(params *SetUserEmojiStatusParams) error {
- err := b.performRequest("setUserEmojiStatus", params)
+func (b *Bot) SetUserEmojiStatus(ctx context.Context, params *SetUserEmojiStatusParams) error {
+ err := b.performRequest(ctx, "setUserEmojiStatus", params)
if err != nil {
- return fmt.Errorf("telego: setUserEmojiStatus(): %w", err)
+ return fmt.Errorf("telego: setUserEmojiStatus: %w", err)
}
-
return nil
}
@@ -1792,13 +1770,12 @@ type GetFileParams struct {
// https://api.telegram.org/file/bot/, where is taken from the response. It is
// guaranteed that the link will be valid for at least 1 hour. When the link expires, a new one can be requested
// by calling getFile (https://core.telegram.org/bots/api#getfile) again.
-func (b *Bot) GetFile(params *GetFileParams) (*File, error) {
+func (b *Bot) GetFile(ctx context.Context, params *GetFileParams) (*File, error) {
var file *File
- err := b.performRequest("getFile", params, &file)
+ err := b.performRequest(ctx, "getFile", params, &file)
if err != nil {
- return nil, fmt.Errorf("telego: getFile(): %w", err)
+ return nil, fmt.Errorf("telego: getFile: %w", err)
}
-
return file, nil
}
@@ -1827,12 +1804,11 @@ type BanChatMemberParams struct {
// etc., unless unbanned (https://core.telegram.org/bots/api#unbanchatmember) first. The bot must be an
// administrator in the chat for this to work and must have the appropriate administrator rights. Returns True
// on success.
-func (b *Bot) BanChatMember(params *BanChatMemberParams) error {
- err := b.performRequest("banChatMember", params)
+func (b *Bot) BanChatMember(ctx context.Context, params *BanChatMemberParams) error {
+ err := b.performRequest(ctx, "banChatMember", params)
if err != nil {
- return fmt.Errorf("telego: banChatMember(): %w", err)
+ return fmt.Errorf("telego: banChatMember: %w", err)
}
-
return nil
}
@@ -1854,12 +1830,11 @@ type UnbanChatMemberParams struct {
// be an administrator for this to work. By default, this method guarantees that after the call the user is not
// a member of the chat, but will be able to join it. So if the user is a member of the chat they will also be
// removed from the chat. If you don't want this, use the parameter only_if_banned. Returns True on success.
-func (b *Bot) UnbanChatMember(params *UnbanChatMemberParams) error {
- err := b.performRequest("unbanChatMember", params)
+func (b *Bot) UnbanChatMember(ctx context.Context, params *UnbanChatMemberParams) error {
+ err := b.performRequest(ctx, "unbanChatMember", params)
if err != nil {
- return fmt.Errorf("telego: unbanChatMember(): %w", err)
+ return fmt.Errorf("telego: unbanChatMember: %w", err)
}
-
return nil
}
@@ -1890,12 +1865,11 @@ type RestrictChatMemberParams struct {
// RestrictChatMember - Use this method to restrict a user in a supergroup. The bot must be an administrator
// in the supergroup for this to work and must have the appropriate administrator rights. Pass True for all
// permissions to lift restrictions from a user. Returns True on success.
-func (b *Bot) RestrictChatMember(params *RestrictChatMemberParams) error {
- err := b.performRequest("restrictChatMember", params)
+func (b *Bot) RestrictChatMember(ctx context.Context, params *RestrictChatMemberParams) error {
+ err := b.performRequest(ctx, "restrictChatMember", params)
if err != nil {
- return fmt.Errorf("telego: restrictChatMember(): %w", err)
+ return fmt.Errorf("telego: restrictChatMember: %w", err)
}
-
return nil
}
@@ -1966,12 +1940,11 @@ type PromoteChatMemberParams struct {
// PromoteChatMember - Use this method to promote or demote a user in a supergroup or a channel. The bot must
// be an administrator in the chat for this to work and must have the appropriate administrator rights. Pass
// False for all boolean parameters to demote a user. Returns True on success.
-func (b *Bot) PromoteChatMember(params *PromoteChatMemberParams) error {
- err := b.performRequest("promoteChatMember", params)
+func (b *Bot) PromoteChatMember(ctx context.Context, params *PromoteChatMemberParams) error {
+ err := b.performRequest(ctx, "promoteChatMember", params)
if err != nil {
- return fmt.Errorf("telego: promoteChatMember(): %w", err)
+ return fmt.Errorf("telego: promoteChatMember: %w", err)
}
-
return nil
}
@@ -1990,12 +1963,11 @@ type SetChatAdministratorCustomTitleParams struct {
// SetChatAdministratorCustomTitle - Use this method to set a custom title for an administrator in a
// supergroup promoted by the bot. Returns True on success.
-func (b *Bot) SetChatAdministratorCustomTitle(params *SetChatAdministratorCustomTitleParams) error {
- err := b.performRequest("setChatAdministratorCustomTitle", params)
+func (b *Bot) SetChatAdministratorCustomTitle(ctx context.Context, params *SetChatAdministratorCustomTitleParams) error {
+ err := b.performRequest(ctx, "setChatAdministratorCustomTitle", params)
if err != nil {
- return fmt.Errorf("telego: setChatAdministratorCustomTitle(): %w", err)
+ return fmt.Errorf("telego: setChatAdministratorCustomTitle: %w", err)
}
-
return nil
}
@@ -2013,12 +1985,11 @@ type BanChatSenderChatParams struct {
// unbanned (https://core.telegram.org/bots/api#unbanchatsenderchat), the owner of the banned chat won't be able
// to send messages on behalf of any of their channels. The bot must be an administrator in the supergroup or
// channel for this to work and must have the appropriate administrator rights. Returns True on success.
-func (b *Bot) BanChatSenderChat(params *BanChatSenderChatParams) error {
- err := b.performRequest("banChatSenderChat", params)
+func (b *Bot) BanChatSenderChat(ctx context.Context, params *BanChatSenderChatParams) error {
+ err := b.performRequest(ctx, "banChatSenderChat", params)
if err != nil {
- return fmt.Errorf("telego: banChatSenderChat(): %w", err)
+ return fmt.Errorf("telego: banChatSenderChat: %w", err)
}
-
return nil
}
@@ -2035,12 +2006,11 @@ type UnbanChatSenderChatParams struct {
// UnbanChatSenderChat - Use this method to unban a previously banned channel chat in a supergroup or
// channel. The bot must be an administrator for this to work and must have the appropriate administrator
// rights. Returns True on success.
-func (b *Bot) UnbanChatSenderChat(params *UnbanChatSenderChatParams) error {
- err := b.performRequest("unbanChatSenderChat", params)
+func (b *Bot) UnbanChatSenderChat(ctx context.Context, params *UnbanChatSenderChatParams) error {
+ err := b.performRequest(ctx, "unbanChatSenderChat", params)
if err != nil {
- return fmt.Errorf("telego: unbanChatSenderChat(): %w", err)
+ return fmt.Errorf("telego: unbanChatSenderChat: %w", err)
}
-
return nil
}
@@ -2063,12 +2033,11 @@ type SetChatPermissionsParams struct {
// SetChatPermissions - Use this method to set default chat permissions for all members. The bot must be an
// administrator in the group or a supergroup for this to work and must have the can_restrict_members
// administrator rights. Returns True on success.
-func (b *Bot) SetChatPermissions(params *SetChatPermissionsParams) error {
- err := b.performRequest("setChatPermissions", params)
+func (b *Bot) SetChatPermissions(ctx context.Context, params *SetChatPermissionsParams) error {
+ err := b.performRequest(ctx, "setChatPermissions", params)
if err != nil {
- return fmt.Errorf("telego: setChatPermissions(): %w", err)
+ return fmt.Errorf("telego: setChatPermissions: %w", err)
}
-
return nil
}
@@ -2082,13 +2051,12 @@ type ExportChatInviteLinkParams struct {
// ExportChatInviteLink - Use this method to generate a new primary invite link for a chat; any previously
// generated primary link is revoked. The bot must be an administrator in the chat for this to work and must
// have the appropriate administrator rights. Returns the new invite link as String on success.
-func (b *Bot) ExportChatInviteLink(params *ExportChatInviteLinkParams) (*string, error) {
+func (b *Bot) ExportChatInviteLink(ctx context.Context, params *ExportChatInviteLinkParams) (*string, error) {
var inviteLink *string
- err := b.performRequest("exportChatInviteLink", params, &inviteLink)
+ err := b.performRequest(ctx, "exportChatInviteLink", params, &inviteLink)
if err != nil {
- return nil, fmt.Errorf("telego: exportChatInviteLink(): %w", err)
+ return nil, fmt.Errorf("telego: exportChatInviteLink: %w", err)
}
-
return inviteLink, nil
}
@@ -2117,13 +2085,12 @@ type CreateChatInviteLinkParams struct {
// administrator in the chat for this to work and must have the appropriate administrator rights. The link can
// be revoked using the method revokeChatInviteLink (https://core.telegram.org/bots/api#revokechatinvitelink).
// Returns the new invite link as ChatInviteLink (https://core.telegram.org/bots/api#chatinvitelink) object.
-func (b *Bot) CreateChatInviteLink(params *CreateChatInviteLinkParams) (*ChatInviteLink, error) {
+func (b *Bot) CreateChatInviteLink(ctx context.Context, params *CreateChatInviteLinkParams) (*ChatInviteLink, error) {
var chatInviteLink *ChatInviteLink
- err := b.performRequest("createChatInviteLink", params, &chatInviteLink)
+ err := b.performRequest(ctx, "createChatInviteLink", params, &chatInviteLink)
if err != nil {
- return nil, fmt.Errorf("telego: createChatInviteLink(): %w", err)
+ return nil, fmt.Errorf("telego: createChatInviteLink: %w", err)
}
-
return chatInviteLink, nil
}
@@ -2154,13 +2121,12 @@ type EditChatInviteLinkParams struct {
// EditChatInviteLink - Use this method to edit a non-primary invite link created by the bot. The bot must be
// an administrator in the chat for this to work and must have the appropriate administrator rights. Returns the
// edited invite link as a ChatInviteLink (https://core.telegram.org/bots/api#chatinvitelink) object.
-func (b *Bot) EditChatInviteLink(params *EditChatInviteLinkParams) (*ChatInviteLink, error) {
+func (b *Bot) EditChatInviteLink(ctx context.Context, params *EditChatInviteLinkParams) (*ChatInviteLink, error) {
var chatInviteLink *ChatInviteLink
- err := b.performRequest("editChatInviteLink", params, &chatInviteLink)
+ err := b.performRequest(ctx, "editChatInviteLink", params, &chatInviteLink)
if err != nil {
- return nil, fmt.Errorf("telego: editChatInviteLink(): %w", err)
+ return nil, fmt.Errorf("telego: editChatInviteLink: %w", err)
}
-
return chatInviteLink, nil
}
@@ -2188,15 +2154,12 @@ type CreateChatSubscriptionInviteLinkParams struct {
// editChatSubscriptionInviteLink (https://core.telegram.org/bots/api#editchatsubscriptioninvitelink) or revoked
// using the method revokeChatInviteLink (https://core.telegram.org/bots/api#revokechatinvitelink). Returns the
// new invite link as a ChatInviteLink (https://core.telegram.org/bots/api#chatinvitelink) object.
-func (b *Bot) CreateChatSubscriptionInviteLink(
- params *CreateChatSubscriptionInviteLinkParams,
-) (*ChatInviteLink, error) {
+func (b *Bot) CreateChatSubscriptionInviteLink(ctx context.Context, params *CreateChatSubscriptionInviteLinkParams) (*ChatInviteLink, error) {
var chatInviteLink *ChatInviteLink
- err := b.performRequest("createChatSubscriptionInviteLink", params, &chatInviteLink)
+ err := b.performRequest(ctx, "createChatSubscriptionInviteLink", params, &chatInviteLink)
if err != nil {
- return nil, fmt.Errorf("telego: createChatSubscriptionInviteLink(): %w", err)
+ return nil, fmt.Errorf("telego: createChatSubscriptionInviteLink: %w", err)
}
-
return chatInviteLink, nil
}
@@ -2216,13 +2179,12 @@ type EditChatSubscriptionInviteLinkParams struct {
// EditChatSubscriptionInviteLink - Use this method to edit a subscription invite link created by the bot.
// The bot must have the can_invite_users administrator rights. Returns the edited invite link as a
// ChatInviteLink (https://core.telegram.org/bots/api#chatinvitelink) object.
-func (b *Bot) EditChatSubscriptionInviteLink(params *EditChatSubscriptionInviteLinkParams) (*ChatInviteLink, error) {
+func (b *Bot) EditChatSubscriptionInviteLink(ctx context.Context, params *EditChatSubscriptionInviteLinkParams) (*ChatInviteLink, error) {
var chatInviteLink *ChatInviteLink
- err := b.performRequest("editChatSubscriptionInviteLink", params, &chatInviteLink)
+ err := b.performRequest(ctx, "editChatSubscriptionInviteLink", params, &chatInviteLink)
if err != nil {
- return nil, fmt.Errorf("telego: editChatSubscriptionInviteLink(): %w", err)
+ return nil, fmt.Errorf("telego: editChatSubscriptionInviteLink: %w", err)
}
-
return chatInviteLink, nil
}
@@ -2240,13 +2202,12 @@ type RevokeChatInviteLinkParams struct {
// revoked, a new link is automatically generated. The bot must be an administrator in the chat for this to work
// and must have the appropriate administrator rights. Returns the revoked invite link as ChatInviteLink
// (https://core.telegram.org/bots/api#chatinvitelink) object.
-func (b *Bot) RevokeChatInviteLink(params *RevokeChatInviteLinkParams) (*ChatInviteLink, error) {
+func (b *Bot) RevokeChatInviteLink(ctx context.Context, params *RevokeChatInviteLinkParams) (*ChatInviteLink, error) {
var chatInviteLink *ChatInviteLink
- err := b.performRequest("revokeChatInviteLink", params, &chatInviteLink)
+ err := b.performRequest(ctx, "revokeChatInviteLink", params, &chatInviteLink)
if err != nil {
- return nil, fmt.Errorf("telego: revokeChatInviteLink(): %w", err)
+ return nil, fmt.Errorf("telego: revokeChatInviteLink: %w", err)
}
-
return chatInviteLink, nil
}
@@ -2262,12 +2223,11 @@ type ApproveChatJoinRequestParams struct {
// ApproveChatJoinRequest - Use this method to approve a chat join request. The bot must be an administrator
// in the chat for this to work and must have the can_invite_users administrator right. Returns True on success.
-func (b *Bot) ApproveChatJoinRequest(params *ApproveChatJoinRequestParams) error {
- err := b.performRequest("approveChatJoinRequest", params)
+func (b *Bot) ApproveChatJoinRequest(ctx context.Context, params *ApproveChatJoinRequestParams) error {
+ err := b.performRequest(ctx, "approveChatJoinRequest", params)
if err != nil {
- return fmt.Errorf("telego: approveChatJoinRequest(): %w", err)
+ return fmt.Errorf("telego: approveChatJoinRequest: %w", err)
}
-
return nil
}
@@ -2283,12 +2243,11 @@ type DeclineChatJoinRequestParams struct {
// DeclineChatJoinRequest - Use this method to decline a chat join request. The bot must be an administrator
// in the chat for this to work and must have the can_invite_users administrator right. Returns True on success.
-func (b *Bot) DeclineChatJoinRequest(params *DeclineChatJoinRequestParams) error {
- err := b.performRequest("declineChatJoinRequest", params)
+func (b *Bot) DeclineChatJoinRequest(ctx context.Context, params *DeclineChatJoinRequestParams) error {
+ err := b.performRequest(ctx, "declineChatJoinRequest", params)
if err != nil {
- return fmt.Errorf("telego: declineChatJoinRequest(): %w", err)
+ return fmt.Errorf("telego: declineChatJoinRequest: %w", err)
}
-
return nil
}
@@ -2311,12 +2270,11 @@ func (p *SetChatPhotoParams) fileParameters() map[string]ta.NamedReader {
// SetChatPhoto - Use this method to set a new profile photo for the chat. Photos can't be changed for
// private chats. The bot must be an administrator in the chat for this to work and must have the appropriate
// administrator rights. Returns True on success.
-func (b *Bot) SetChatPhoto(params *SetChatPhotoParams) error {
- err := b.performRequest("setChatPhoto", params)
+func (b *Bot) SetChatPhoto(ctx context.Context, params *SetChatPhotoParams) error {
+ err := b.performRequest(ctx, "setChatPhoto", params)
if err != nil {
- return fmt.Errorf("telego: setChatPhoto(): %w", err)
+ return fmt.Errorf("telego: setChatPhoto: %w", err)
}
-
return nil
}
@@ -2330,12 +2288,11 @@ type DeleteChatPhotoParams struct {
// DeleteChatPhoto - Use this method to delete a chat photo. Photos can't be changed for private chats. The
// bot must be an administrator in the chat for this to work and must have the appropriate administrator rights.
// Returns True on success.
-func (b *Bot) DeleteChatPhoto(params *DeleteChatPhotoParams) error {
- err := b.performRequest("deleteChatPhoto", params)
+func (b *Bot) DeleteChatPhoto(ctx context.Context, params *DeleteChatPhotoParams) error {
+ err := b.performRequest(ctx, "deleteChatPhoto", params)
if err != nil {
- return fmt.Errorf("telego: deleteChatPhoto(): %w", err)
+ return fmt.Errorf("telego: deleteChatPhoto: %w", err)
}
-
return nil
}
@@ -2352,12 +2309,11 @@ type SetChatTitleParams struct {
// SetChatTitle - Use this method to change the title of a chat. Titles can't be changed for private chats.
// The bot must be an administrator in the chat for this to work and must have the appropriate administrator
// rights. Returns True on success.
-func (b *Bot) SetChatTitle(params *SetChatTitleParams) error {
- err := b.performRequest("setChatTitle", params)
+func (b *Bot) SetChatTitle(ctx context.Context, params *SetChatTitleParams) error {
+ err := b.performRequest(ctx, "setChatTitle", params)
if err != nil {
- return fmt.Errorf("telego: setChatTitle(): %w", err)
+ return fmt.Errorf("telego: setChatTitle: %w", err)
}
-
return nil
}
@@ -2374,12 +2330,11 @@ type SetChatDescriptionParams struct {
// SetChatDescription - Use this method to change the description of a group, a supergroup or a channel. The
// bot must be an administrator in the chat for this to work and must have the appropriate administrator rights.
// Returns True on success.
-func (b *Bot) SetChatDescription(params *SetChatDescriptionParams) error {
- err := b.performRequest("setChatDescription", params)
+func (b *Bot) SetChatDescription(ctx context.Context, params *SetChatDescriptionParams) error {
+ err := b.performRequest(ctx, "setChatDescription", params)
if err != nil {
- return fmt.Errorf("telego: setChatDescription(): %w", err)
+ return fmt.Errorf("telego: setChatDescription: %w", err)
}
-
return nil
}
@@ -2405,12 +2360,11 @@ type PinChatMessageParams struct {
// not a private chat, the bot must be an administrator in the chat for this to work and must have the
// 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a
// channel. Returns True on success.
-func (b *Bot) PinChatMessage(params *PinChatMessageParams) error {
- err := b.performRequest("pinChatMessage", params)
+func (b *Bot) PinChatMessage(ctx context.Context, params *PinChatMessageParams) error {
+ err := b.performRequest(ctx, "pinChatMessage", params)
if err != nil {
- return fmt.Errorf("telego: pinChatMessage(): %w", err)
+ return fmt.Errorf("telego: pinChatMessage: %w", err)
}
-
return nil
}
@@ -2433,12 +2387,11 @@ type UnpinChatMessageParams struct {
// chat is not a private chat, the bot must be an administrator in the chat for this to work and must have the
// 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a
// channel. Returns True on success.
-func (b *Bot) UnpinChatMessage(params *UnpinChatMessageParams) error {
- err := b.performRequest("unpinChatMessage", params)
+func (b *Bot) UnpinChatMessage(ctx context.Context, params *UnpinChatMessageParams) error {
+ err := b.performRequest(ctx, "unpinChatMessage", params)
if err != nil {
- return fmt.Errorf("telego: unpinChatMessage(): %w", err)
+ return fmt.Errorf("telego: unpinChatMessage: %w", err)
}
-
return nil
}
@@ -2453,12 +2406,11 @@ type UnpinAllChatMessagesParams struct {
// a private chat, the bot must be an administrator in the chat for this to work and must have the
// 'can_pin_messages' administrator right in a supergroup or 'can_edit_messages' administrator right in a
// channel. Returns True on success.
-func (b *Bot) UnpinAllChatMessages(params *UnpinAllChatMessagesParams) error {
- err := b.performRequest("unpinAllChatMessages", params)
+func (b *Bot) UnpinAllChatMessages(ctx context.Context, params *UnpinAllChatMessagesParams) error {
+ err := b.performRequest(ctx, "unpinAllChatMessages", params)
if err != nil {
- return fmt.Errorf("telego: unpinAllChatMessages(): %w", err)
+ return fmt.Errorf("telego: unpinAllChatMessages: %w", err)
}
-
return nil
}
@@ -2470,12 +2422,11 @@ type LeaveChatParams struct {
}
// LeaveChat - Use this method for your bot to leave a group, supergroup or channel. Returns True on success.
-func (b *Bot) LeaveChat(params *LeaveChatParams) error {
- err := b.performRequest("leaveChat", params)
+func (b *Bot) LeaveChat(ctx context.Context, params *LeaveChatParams) error {
+ err := b.performRequest(ctx, "leaveChat", params)
if err != nil {
- return fmt.Errorf("telego: leaveChat(): %w", err)
+ return fmt.Errorf("telego: leaveChat: %w", err)
}
-
return nil
}
@@ -2488,13 +2439,12 @@ type GetChatParams struct {
// GetChat - Use this method to get up-to-date information about the chat. Returns a ChatFullInfo
// (https://core.telegram.org/bots/api#chatfullinfo) object on success.
-func (b *Bot) GetChat(params *GetChatParams) (*ChatFullInfo, error) {
+func (b *Bot) GetChat(ctx context.Context, params *GetChatParams) (*ChatFullInfo, error) {
var chatFullInfo *ChatFullInfo
- err := b.performRequest("getChat", params, &chatFullInfo)
+ err := b.performRequest(ctx, "getChat", params, &chatFullInfo)
if err != nil {
- return nil, fmt.Errorf("telego: getChat(): %w", err)
+ return nil, fmt.Errorf("telego: getChat: %w", err)
}
-
return chatFullInfo, nil
}
@@ -2507,13 +2457,12 @@ type GetChatAdministratorsParams struct {
// GetChatAdministrators - Use this method to get a list of administrators in a chat, which aren't bots.
// Returns an Array of ChatMember (https://core.telegram.org/bots/api#chatmember) objects.
-func (b *Bot) GetChatAdministrators(params *GetChatAdministratorsParams) ([]ChatMember, error) {
+func (b *Bot) GetChatAdministrators(ctx context.Context, params *GetChatAdministratorsParams) ([]ChatMember, error) {
var chatMembersData []chatMemberData
- err := b.performRequest("getChatAdministrators", params, &chatMembersData)
+ err := b.performRequest(ctx, "getChatAdministrators", params, &chatMembersData)
if err != nil {
- return nil, fmt.Errorf("telego: getChatAdministrators(): %w", err)
+ return nil, fmt.Errorf("telego: getChatAdministrators: %w", err)
}
-
chatMembers := make([]ChatMember, len(chatMembersData))
for i, d := range chatMembersData {
chatMembers[i] = d.Data
@@ -2529,13 +2478,12 @@ type GetChatMemberCountParams struct {
}
// GetChatMemberCount - Use this method to get the number of members in a chat. Returns Int on success.
-func (b *Bot) GetChatMemberCount(params *GetChatMemberCountParams) (*int, error) {
+func (b *Bot) GetChatMemberCount(ctx context.Context, params *GetChatMemberCountParams) (*int, error) {
var chatMemberCount *int
- err := b.performRequest("getChatMemberCount", params, &chatMemberCount)
+ err := b.performRequest(ctx, "getChatMemberCount", params, &chatMemberCount)
if err != nil {
- return nil, fmt.Errorf("telego: getChatMemberCount(): %w", err)
+ return nil, fmt.Errorf("telego: getChatMemberCount: %w", err)
}
-
return chatMemberCount, nil
}
@@ -2552,13 +2500,12 @@ type GetChatMemberParams struct {
// GetChatMember - Use this method to get information about a member of a chat. The method is only guaranteed
// to work for other users if the bot is an administrator in the chat. Returns a ChatMember
// (https://core.telegram.org/bots/api#chatmember) object on success.
-func (b *Bot) GetChatMember(params *GetChatMemberParams) (ChatMember, error) {
+func (b *Bot) GetChatMember(ctx context.Context, params *GetChatMemberParams) (ChatMember, error) {
var memberData chatMemberData
- err := b.performRequest("getChatMember", params, &memberData)
+ err := b.performRequest(ctx, "getChatMember", params, &memberData)
if err != nil {
- return nil, fmt.Errorf("telego: getChatMember(): %w", err)
+ return nil, fmt.Errorf("telego: getChatMember: %w", err)
}
-
return memberData.Data, nil
}
@@ -2576,12 +2523,11 @@ type SetChatStickerSetParams struct {
// administrator in the chat for this to work and must have the appropriate administrator rights. Use the field
// can_set_sticker_set optionally returned in getChat (https://core.telegram.org/bots/api#getchat) requests to
// check if the bot can use this method. Returns True on success.
-func (b *Bot) SetChatStickerSet(params *SetChatStickerSetParams) error {
- err := b.performRequest("setChatStickerSet", params)
+func (b *Bot) SetChatStickerSet(ctx context.Context, params *SetChatStickerSetParams) error {
+ err := b.performRequest(ctx, "setChatStickerSet", params)
if err != nil {
- return fmt.Errorf("telego: setChatStickerSet(): %w", err)
+ return fmt.Errorf("telego: setChatStickerSet: %w", err)
}
-
return nil
}
@@ -2596,25 +2542,23 @@ type DeleteChatStickerSetParams struct {
// administrator in the chat for this to work and must have the appropriate administrator rights. Use the field
// can_set_sticker_set optionally returned in getChat (https://core.telegram.org/bots/api#getchat) requests to
// check if the bot can use this method. Returns True on success.
-func (b *Bot) DeleteChatStickerSet(params *DeleteChatStickerSetParams) error {
- err := b.performRequest("deleteChatStickerSet", params)
+func (b *Bot) DeleteChatStickerSet(ctx context.Context, params *DeleteChatStickerSetParams) error {
+ err := b.performRequest(ctx, "deleteChatStickerSet", params)
if err != nil {
- return fmt.Errorf("telego: deleteChatStickerSet(): %w", err)
+ return fmt.Errorf("telego: deleteChatStickerSet: %w", err)
}
-
return nil
}
// GetForumTopicIconStickers - Use this method to get custom emoji stickers, which can be used as a forum
// topic icon by any user. Requires no parameters. Returns an Array of Sticker
// (https://core.telegram.org/bots/api#sticker) objects.
-func (b *Bot) GetForumTopicIconStickers() ([]Sticker, error) {
+func (b *Bot) GetForumTopicIconStickers(ctx context.Context) ([]Sticker, error) {
var stickers []Sticker
- err := b.performRequest("getForumTopicIconStickers", nil, &stickers)
+ err := b.performRequest(ctx, "getForumTopicIconStickers", nil, &stickers)
if err != nil {
- return nil, fmt.Errorf("telego: getForumTopicIconStickers(): %w", err)
+ return nil, fmt.Errorf("telego: getForumTopicIconStickers: %w", err)
}
-
return stickers, nil
}
@@ -2641,13 +2585,12 @@ type CreateForumTopicParams struct {
// CreateForumTopic - Use this method to create a topic in a forum supergroup chat. The bot must be an
// administrator in the chat for this to work and must have the can_manage_topics administrator rights. Returns
// information about the created topic as a ForumTopic (https://core.telegram.org/bots/api#forumtopic) object.
-func (b *Bot) CreateForumTopic(params *CreateForumTopicParams) (*ForumTopic, error) {
+func (b *Bot) CreateForumTopic(ctx context.Context, params *CreateForumTopicParams) (*ForumTopic, error) {
var forumTopic *ForumTopic
- err := b.performRequest("createForumTopic", params, &forumTopic)
+ err := b.performRequest(ctx, "createForumTopic", params, &forumTopic)
if err != nil {
- return nil, fmt.Errorf("telego: createForumTopic(): %w", err)
+ return nil, fmt.Errorf("telego: createForumTopic: %w", err)
}
-
return forumTopic, nil
}
@@ -2674,12 +2617,11 @@ type EditForumTopicParams struct {
// EditForumTopic - Use this method to edit name and icon of a topic in a forum supergroup chat. The bot must
// be an administrator in the chat for this to work and must have the can_manage_topics administrator rights,
// unless it is the creator of the topic. Returns True on success.
-func (b *Bot) EditForumTopic(params *EditForumTopicParams) error {
- err := b.performRequest("editForumTopic", params)
+func (b *Bot) EditForumTopic(ctx context.Context, params *EditForumTopicParams) error {
+ err := b.performRequest(ctx, "editForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: editForumTopic(): %w", err)
+ return fmt.Errorf("telego: editForumTopic: %w", err)
}
-
return nil
}
@@ -2696,12 +2638,11 @@ type CloseForumTopicParams struct {
// CloseForumTopic - Use this method to close an open topic in a forum supergroup chat. The bot must be an
// administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless
// it is the creator of the topic. Returns True on success.
-func (b *Bot) CloseForumTopic(params *CloseForumTopicParams) error {
- err := b.performRequest("closeForumTopic", params)
+func (b *Bot) CloseForumTopic(ctx context.Context, params *CloseForumTopicParams) error {
+ err := b.performRequest(ctx, "closeForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: closeForumTopic(): %w", err)
+ return fmt.Errorf("telego: closeForumTopic: %w", err)
}
-
return nil
}
@@ -2718,12 +2659,11 @@ type ReopenForumTopicParams struct {
// ReopenForumTopic - Use this method to reopen a closed topic in a forum supergroup chat. The bot must be an
// administrator in the chat for this to work and must have the can_manage_topics administrator rights, unless
// it is the creator of the topic. Returns True on success.
-func (b *Bot) ReopenForumTopic(params *ReopenForumTopicParams) error {
- err := b.performRequest("reopenForumTopic", params)
+func (b *Bot) ReopenForumTopic(ctx context.Context, params *ReopenForumTopicParams) error {
+ err := b.performRequest(ctx, "reopenForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: reopenForumTopic(): %w", err)
+ return fmt.Errorf("telego: reopenForumTopic: %w", err)
}
-
return nil
}
@@ -2740,12 +2680,11 @@ type DeleteForumTopicParams struct {
// DeleteForumTopic - Use this method to delete a forum topic along with all its messages in a forum
// supergroup chat. The bot must be an administrator in the chat for this to work and must have the
// can_delete_messages administrator rights. Returns True on success.
-func (b *Bot) DeleteForumTopic(params *DeleteForumTopicParams) error {
- err := b.performRequest("deleteForumTopic", params)
+func (b *Bot) DeleteForumTopic(ctx context.Context, params *DeleteForumTopicParams) error {
+ err := b.performRequest(ctx, "deleteForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: deleteForumTopic(): %w", err)
+ return fmt.Errorf("telego: deleteForumTopic: %w", err)
}
-
return nil
}
@@ -2762,12 +2701,11 @@ type UnpinAllForumTopicMessagesParams struct {
// UnpinAllForumTopicMessages - Use this method to clear the list of pinned messages in a forum topic. The
// bot must be an administrator in the chat for this to work and must have the can_pin_messages administrator
// right in the supergroup. Returns True on success.
-func (b *Bot) UnpinAllForumTopicMessages(params *UnpinAllForumTopicMessagesParams) error {
- err := b.performRequest("unpinAllForumTopicMessages", params)
+func (b *Bot) UnpinAllForumTopicMessages(ctx context.Context, params *UnpinAllForumTopicMessagesParams) error {
+ err := b.performRequest(ctx, "unpinAllForumTopicMessages", params)
if err != nil {
- return fmt.Errorf("telego: unpinAllForumTopicMessages(): %w", err)
+ return fmt.Errorf("telego: unpinAllForumTopicMessages: %w", err)
}
-
return nil
}
@@ -2784,12 +2722,11 @@ type EditGeneralForumTopicParams struct {
// EditGeneralForumTopic - Use this method to edit the name of the 'General' topic in a forum supergroup
// chat. The bot must be an administrator in the chat for this to work and must have the can_manage_topics
// administrator rights. Returns True on success.
-func (b *Bot) EditGeneralForumTopic(params *EditGeneralForumTopicParams) error {
- err := b.performRequest("editGeneralForumTopic", params)
+func (b *Bot) EditGeneralForumTopic(ctx context.Context, params *EditGeneralForumTopicParams) error {
+ err := b.performRequest(ctx, "editGeneralForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: editGeneralForumTopic(): %w", err)
+ return fmt.Errorf("telego: editGeneralForumTopic: %w", err)
}
-
return nil
}
@@ -2803,12 +2740,11 @@ type CloseGeneralForumTopicParams struct {
// CloseGeneralForumTopic - Use this method to close an open 'General' topic in a forum supergroup chat. The
// bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator
// rights. Returns True on success.
-func (b *Bot) CloseGeneralForumTopic(params *CloseGeneralForumTopicParams) error {
- err := b.performRequest("closeGeneralForumTopic", params)
+func (b *Bot) CloseGeneralForumTopic(ctx context.Context, params *CloseGeneralForumTopicParams) error {
+ err := b.performRequest(ctx, "closeGeneralForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: closeGeneralForumTopic(): %w", err)
+ return fmt.Errorf("telego: closeGeneralForumTopic: %w", err)
}
-
return nil
}
@@ -2822,12 +2758,11 @@ type ReopenGeneralForumTopicParams struct {
// ReopenGeneralForumTopic - Use this method to reopen a closed 'General' topic in a forum supergroup chat.
// The bot must be an administrator in the chat for this to work and must have the can_manage_topics
// administrator rights. The topic will be automatically unhidden if it was hidden. Returns True on success.
-func (b *Bot) ReopenGeneralForumTopic(params *ReopenGeneralForumTopicParams) error {
- err := b.performRequest("reopenGeneralForumTopic", params)
+func (b *Bot) ReopenGeneralForumTopic(ctx context.Context, params *ReopenGeneralForumTopicParams) error {
+ err := b.performRequest(ctx, "reopenGeneralForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: reopenGeneralForumTopic(): %w", err)
+ return fmt.Errorf("telego: reopenGeneralForumTopic: %w", err)
}
-
return nil
}
@@ -2841,12 +2776,11 @@ type HideGeneralForumTopicParams struct {
// HideGeneralForumTopic - Use this method to hide the 'General' topic in a forum supergroup chat. The bot
// must be an administrator in the chat for this to work and must have the can_manage_topics administrator
// rights. The topic will be automatically closed if it was open. Returns True on success.
-func (b *Bot) HideGeneralForumTopic(params *HideGeneralForumTopicParams) error {
- err := b.performRequest("hideGeneralForumTopic", params)
+func (b *Bot) HideGeneralForumTopic(ctx context.Context, params *HideGeneralForumTopicParams) error {
+ err := b.performRequest(ctx, "hideGeneralForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: hideGeneralForumTopic(): %w", err)
+ return fmt.Errorf("telego: hideGeneralForumTopic: %w", err)
}
-
return nil
}
@@ -2860,12 +2794,11 @@ type UnhideGeneralForumTopicParams struct {
// UnhideGeneralForumTopic - Use this method to unhide the 'General' topic in a forum supergroup chat. The
// bot must be an administrator in the chat for this to work and must have the can_manage_topics administrator
// rights. Returns True on success.
-func (b *Bot) UnhideGeneralForumTopic(params *UnhideGeneralForumTopicParams) error {
- err := b.performRequest("unhideGeneralForumTopic", params)
+func (b *Bot) UnhideGeneralForumTopic(ctx context.Context, params *UnhideGeneralForumTopicParams) error {
+ err := b.performRequest(ctx, "unhideGeneralForumTopic", params)
if err != nil {
- return fmt.Errorf("telego: unhideGeneralForumTopic(): %w", err)
+ return fmt.Errorf("telego: unhideGeneralForumTopic: %w", err)
}
-
return nil
}
@@ -2880,12 +2813,11 @@ type UnpinAllGeneralForumTopicMessagesParams struct {
// UnpinAllGeneralForumTopicMessages - Use this method to clear the list of pinned messages in a General
// forum topic. The bot must be an administrator in the chat for this to work and must have the can_pin_messages
// administrator right in the supergroup. Returns True on success.
-func (b *Bot) UnpinAllGeneralForumTopicMessages(params *UnpinAllGeneralForumTopicMessagesParams) error {
- err := b.performRequest("unpinAllGeneralForumTopicMessages", params)
+func (b *Bot) UnpinAllGeneralForumTopicMessages(ctx context.Context, params *UnpinAllGeneralForumTopicMessagesParams) error {
+ err := b.performRequest(ctx, "unpinAllGeneralForumTopicMessages", params)
if err != nil {
- return fmt.Errorf("telego: unpinAllGeneralForumTopicMessages(): %w", err)
+ return fmt.Errorf("telego: unpinAllGeneralForumTopicMessages: %w", err)
}
-
return nil
}
@@ -2920,12 +2852,11 @@ type AnswerCallbackQueryParams struct {
// Alternatively, the user can be redirected to the specified Game URL. For this option to work, you must first
// create a game for your bot via @BotFather (https://t.me/botfather) and accept the terms. Otherwise, you may
// use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
-func (b *Bot) AnswerCallbackQuery(params *AnswerCallbackQueryParams) error {
- err := b.performRequest("answerCallbackQuery", params)
+func (b *Bot) AnswerCallbackQuery(ctx context.Context, params *AnswerCallbackQueryParams) error {
+ err := b.performRequest(ctx, "answerCallbackQuery", params)
if err != nil {
- return fmt.Errorf("telego: answerCallbackQuery(): %w", err)
+ return fmt.Errorf("telego: answerCallbackQuery: %w", err)
}
-
return nil
}
@@ -2941,13 +2872,12 @@ type GetUserChatBoostsParams struct {
// GetUserChatBoosts - Use this method to get the list of boosts added to a chat by a user. Requires
// administrator rights in the chat. Returns a UserChatBoosts
// (https://core.telegram.org/bots/api#userchatboosts) object.
-func (b *Bot) GetUserChatBoosts(params *GetUserChatBoostsParams) (*UserChatBoosts, error) {
+func (b *Bot) GetUserChatBoosts(ctx context.Context, params *GetUserChatBoostsParams) (*UserChatBoosts, error) {
var userChatBoosts *UserChatBoosts
- err := b.performRequest("getUserChatBoosts", params, &userChatBoosts)
+ err := b.performRequest(ctx, "getUserChatBoosts", params, &userChatBoosts)
if err != nil {
- return nil, fmt.Errorf("telego: getUserChatBoosts(): %w", err)
+ return nil, fmt.Errorf("telego: getUserChatBoosts: %w", err)
}
-
return userChatBoosts, nil
}
@@ -2960,13 +2890,12 @@ type GetBusinessConnectionParams struct {
// GetBusinessConnection - Use this method to get information about the connection of the bot with a business
// account. Returns a BusinessConnection (https://core.telegram.org/bots/api#businessconnection) object on
// success.
-func (b *Bot) GetBusinessConnection(params *GetBusinessConnectionParams) (*BusinessConnection, error) {
+func (b *Bot) GetBusinessConnection(ctx context.Context, params *GetBusinessConnectionParams) (*BusinessConnection, error) {
var businessConnection *BusinessConnection
- err := b.performRequest("getBusinessConnection", params, &businessConnection)
+ err := b.performRequest(ctx, "getBusinessConnection", params, &businessConnection)
if err != nil {
- return nil, fmt.Errorf("telego: getBusinessConnection(): %w", err)
+ return nil, fmt.Errorf("telego: getBusinessConnection: %w", err)
}
-
return businessConnection, nil
}
@@ -2988,12 +2917,11 @@ type SetMyCommandsParams struct {
// SetMyCommands - Use this method to change the list of the bot's commands. See this manual
// (https://core.telegram.org/bots/features#commands) for more details about bot commands. Returns True on
// success.
-func (b *Bot) SetMyCommands(params *SetMyCommandsParams) error {
- err := b.performRequest("setMyCommands", params)
+func (b *Bot) SetMyCommands(ctx context.Context, params *SetMyCommandsParams) error {
+ err := b.performRequest(ctx, "setMyCommands", params)
if err != nil {
- return fmt.Errorf("telego: setMyCommands(): %w", err)
+ return fmt.Errorf("telego: setMyCommands: %w", err)
}
-
return nil
}
@@ -3012,12 +2940,11 @@ type DeleteMyCommandsParams struct {
// language. After deletion, higher level commands
// (https://core.telegram.org/bots/api#determining-list-of-commands) will be shown to affected users. Returns
// True on success.
-func (b *Bot) DeleteMyCommands(params *DeleteMyCommandsParams) error {
- err := b.performRequest("deleteMyCommands", params)
+func (b *Bot) DeleteMyCommands(ctx context.Context, params *DeleteMyCommandsParams) error {
+ err := b.performRequest(ctx, "deleteMyCommands", params)
if err != nil {
- return fmt.Errorf("telego: deleteMyCommands(): %w", err)
+ return fmt.Errorf("telego: deleteMyCommands: %w", err)
}
-
return nil
}
@@ -3034,13 +2961,12 @@ type GetMyCommandsParams struct {
// GetMyCommands - Use this method to get the current list of the bot's commands for the given scope and user
// language. Returns an Array of BotCommand (https://core.telegram.org/bots/api#botcommand) objects. If commands
// aren't set, an empty list is returned.
-func (b *Bot) GetMyCommands(params *GetMyCommandsParams) ([]BotCommand, error) {
+func (b *Bot) GetMyCommands(ctx context.Context, params *GetMyCommandsParams) ([]BotCommand, error) {
var botCommands []BotCommand
- err := b.performRequest("getMyCommands", params, &botCommands)
+ err := b.performRequest(ctx, "getMyCommands", params, &botCommands)
if err != nil {
- return nil, fmt.Errorf("telego: getMyCommands(): %w", err)
+ return nil, fmt.Errorf("telego: getMyCommands: %w", err)
}
-
return botCommands, nil
}
@@ -3056,12 +2982,11 @@ type SetMyNameParams struct {
}
// SetMyName - Use this method to change the bot's name. Returns True on success.
-func (b *Bot) SetMyName(params *SetMyNameParams) error {
- err := b.performRequest("setMyName", params)
+func (b *Bot) SetMyName(ctx context.Context, params *SetMyNameParams) error {
+ err := b.performRequest(ctx, "setMyName", params)
if err != nil {
- return fmt.Errorf("telego: setMyName(): %w", err)
+ return fmt.Errorf("telego: setMyName: %w", err)
}
-
return nil
}
@@ -3073,13 +2998,12 @@ type GetMyNameParams struct {
// GetMyName - Use this method to get the current bot name for the given user language. Returns BotName
// (https://core.telegram.org/bots/api#botname) on success.
-func (b *Bot) GetMyName(params *GetMyNameParams) (*BotName, error) {
+func (b *Bot) GetMyName(ctx context.Context, params *GetMyNameParams) (*BotName, error) {
var botName *BotName
- err := b.performRequest("getMyName", params, &botName)
+ err := b.performRequest(ctx, "getMyName", params, &botName)
if err != nil {
- return nil, fmt.Errorf("telego: getMyName(): %w", err)
+ return nil, fmt.Errorf("telego: getMyName: %w", err)
}
-
return botName, nil
}
@@ -3096,12 +3020,11 @@ type SetMyDescriptionParams struct {
// SetMyDescription - Use this method to change the bot's description, which is shown in the chat with the
// bot if the chat is empty. Returns True on success.
-func (b *Bot) SetMyDescription(params *SetMyDescriptionParams) error {
- err := b.performRequest("setMyDescription", params)
+func (b *Bot) SetMyDescription(ctx context.Context, params *SetMyDescriptionParams) error {
+ err := b.performRequest(ctx, "setMyDescription", params)
if err != nil {
- return fmt.Errorf("telego: setMyDescription(): %w", err)
+ return fmt.Errorf("telego: setMyDescription: %w", err)
}
-
return nil
}
@@ -3113,13 +3036,12 @@ type GetMyDescriptionParams struct {
// GetMyDescription - Use this method to get the current bot description for the given user language. Returns
// BotDescription (https://core.telegram.org/bots/api#botdescription) on success.
-func (b *Bot) GetMyDescription(params *GetMyDescriptionParams) (*BotDescription, error) {
+func (b *Bot) GetMyDescription(ctx context.Context, params *GetMyDescriptionParams) (*BotDescription, error) {
var botDescription *BotDescription
- err := b.performRequest("getMyDescription", params, &botDescription)
+ err := b.performRequest(ctx, "getMyDescription", params, &botDescription)
if err != nil {
- return nil, fmt.Errorf("telego: getMyDescription(): %w", err)
+ return nil, fmt.Errorf("telego: getMyDescription: %w", err)
}
-
return botDescription, nil
}
@@ -3136,12 +3058,11 @@ type SetMyShortDescriptionParams struct {
// SetMyShortDescription - Use this method to change the bot's short description, which is shown on the bot's
// profile page and is sent together with the link when users share the bot. Returns True on success.
-func (b *Bot) SetMyShortDescription(params *SetMyShortDescriptionParams) error {
- err := b.performRequest("setMyShortDescription", params)
+func (b *Bot) SetMyShortDescription(ctx context.Context, params *SetMyShortDescriptionParams) error {
+ err := b.performRequest(ctx, "setMyShortDescription", params)
if err != nil {
- return fmt.Errorf("telego: setMyShortDescription(): %w", err)
+ return fmt.Errorf("telego: setMyShortDescription: %w", err)
}
-
return nil
}
@@ -3153,13 +3074,12 @@ type GetMyShortDescriptionParams struct {
// GetMyShortDescription - Use this method to get the current bot short description for the given user
// language. Returns BotShortDescription (https://core.telegram.org/bots/api#botshortdescription) on success.
-func (b *Bot) GetMyShortDescription(params *GetMyShortDescriptionParams) (*BotShortDescription, error) {
+func (b *Bot) GetMyShortDescription(ctx context.Context, params *GetMyShortDescriptionParams) (*BotShortDescription, error) {
var botShortDescription *BotShortDescription
- err := b.performRequest("getMyShortDescription", params, &botShortDescription)
+ err := b.performRequest(ctx, "getMyShortDescription", params, &botShortDescription)
if err != nil {
- return nil, fmt.Errorf("telego: getMyShortDescription(): %w", err)
+ return nil, fmt.Errorf("telego: getMyShortDescription: %w", err)
}
-
return botShortDescription, nil
}
@@ -3176,12 +3096,11 @@ type SetChatMenuButtonParams struct {
// SetChatMenuButton - Use this method to change the bot's menu button in a private chat, or the default menu
// button. Returns True on success.
-func (b *Bot) SetChatMenuButton(params *SetChatMenuButtonParams) error {
- err := b.performRequest("setChatMenuButton", params)
+func (b *Bot) SetChatMenuButton(ctx context.Context, params *SetChatMenuButtonParams) error {
+ err := b.performRequest(ctx, "setChatMenuButton", params)
if err != nil {
- return fmt.Errorf("telego: setChatMenuButton(): %w", err)
+ return fmt.Errorf("telego: setChatMenuButton: %w", err)
}
-
return nil
}
@@ -3194,13 +3113,12 @@ type GetChatMenuButtonParams struct {
// GetChatMenuButton - Use this method to get the current value of the bot's menu button in a private chat,
// or the default menu button. Returns MenuButton (https://core.telegram.org/bots/api#menubutton) on success.
-func (b *Bot) GetChatMenuButton(params *GetChatMenuButtonParams) (MenuButton, error) {
+func (b *Bot) GetChatMenuButton(ctx context.Context, params *GetChatMenuButtonParams) (MenuButton, error) {
var menuButton menuButtonData
- err := b.performRequest("getChatMenuButton", params, &menuButton)
+ err := b.performRequest(ctx, "getChatMenuButton", params, &menuButton)
if err != nil {
- return nil, fmt.Errorf("telego: getChatMenuButton(): %w", err)
+ return nil, fmt.Errorf("telego: getChatMenuButton: %w", err)
}
-
return menuButton.Data, nil
}
@@ -3218,12 +3136,11 @@ type SetMyDefaultAdministratorRightsParams struct {
// SetMyDefaultAdministratorRights - Use this method to change the default administrator rights requested by
// the bot when it's added as an administrator to groups or channels. These rights will be suggested to users,
// but they are free to modify the list before adding the bot. Returns True on success.
-func (b *Bot) SetMyDefaultAdministratorRights(params *SetMyDefaultAdministratorRightsParams) error {
- err := b.performRequest("setMyDefaultAdministratorRights", params)
+func (b *Bot) SetMyDefaultAdministratorRights(ctx context.Context, params *SetMyDefaultAdministratorRightsParams) error {
+ err := b.performRequest(ctx, "setMyDefaultAdministratorRights", params)
if err != nil {
- return fmt.Errorf("telego: setMyDefaultAdministratorRights(): %w", err)
+ return fmt.Errorf("telego: setMyDefaultAdministratorRights: %w", err)
}
-
return nil
}
@@ -3236,15 +3153,12 @@ type GetMyDefaultAdministratorRightsParams struct {
// GetMyDefaultAdministratorRights - Use this method to get the current default administrator rights of the
// bot. Returns ChatAdministratorRights (https://core.telegram.org/bots/api#chatadministratorrights) on success.
-func (b *Bot) GetMyDefaultAdministratorRights(
- params *GetMyDefaultAdministratorRightsParams,
-) (*ChatAdministratorRights, error) {
+func (b *Bot) GetMyDefaultAdministratorRights(ctx context.Context, params *GetMyDefaultAdministratorRightsParams) (*ChatAdministratorRights, error) {
var chatAdministratorRights *ChatAdministratorRights
- err := b.performRequest("getMyDefaultAdministratorRights", params, &chatAdministratorRights)
+ err := b.performRequest(ctx, "getMyDefaultAdministratorRights", params, &chatAdministratorRights)
if err != nil {
- return nil, fmt.Errorf("telego: getMyDefaultAdministratorRights(): %w", err)
+ return nil, fmt.Errorf("telego: getMyDefaultAdministratorRights: %w", err)
}
-
return chatAdministratorRights, nil
}
@@ -3289,14 +3203,13 @@ type EditMessageTextParams struct {
// (https://core.telegram.org/bots/api#message) is returned, otherwise True is returned. Note that business
// messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48
// hours from the time they were sent.
-func (b *Bot) EditMessageText(params *EditMessageTextParams) (*Message, error) {
+func (b *Bot) EditMessageText(ctx context.Context, params *EditMessageTextParams) (*Message, error) {
var message *Message
var success *bool
- err := b.performRequest("editMessageText", params, &message, &success)
+ err := b.performRequest(ctx, "editMessageText", params, &message, &success)
if err != nil {
- return nil, fmt.Errorf("telego: editMessageText(): %w", err)
+ return nil, fmt.Errorf("telego: editMessageText: %w", err)
}
-
return message, nil
}
@@ -3341,14 +3254,13 @@ type EditMessageCaptionParams struct {
// not an inline message, the edited Message (https://core.telegram.org/bots/api#message) is returned, otherwise
// True is returned. Note that business messages that were not sent by the bot and do not contain an inline
// keyboard can only be edited within 48 hours from the time they were sent.
-func (b *Bot) EditMessageCaption(params *EditMessageCaptionParams) (*Message, error) {
+func (b *Bot) EditMessageCaption(ctx context.Context, params *EditMessageCaptionParams) (*Message, error) {
var message *Message
var success *bool
- err := b.performRequest("editMessageCaption", params, &message, &success)
+ err := b.performRequest(ctx, "editMessageCaption", params, &message, &success)
if err != nil {
- return nil, fmt.Errorf("telego: editMessageCaption(): %w", err)
+ return nil, fmt.Errorf("telego: editMessageCaption: %w", err)
}
-
return message, nil
}
@@ -3398,14 +3310,13 @@ func (p *EditMessageMediaParams) fileParameters() map[string]ta.NamedReader {
// (https://core.telegram.org/bots/api#message) is returned, otherwise True is returned. Note that business
// messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48
// hours from the time they were sent.
-func (b *Bot) EditMessageMedia(params *EditMessageMediaParams) (*Message, error) {
+func (b *Bot) EditMessageMedia(ctx context.Context, params *EditMessageMediaParams) (*Message, error) {
var message *Message
var success *bool
- err := b.performRequest("editMessageMedia", params, &message, &success)
+ err := b.performRequest(ctx, "editMessageMedia", params, &message, &success)
if err != nil {
- return nil, fmt.Errorf("telego: editMessageMedia(): %w", err)
+ return nil, fmt.Errorf("telego: editMessageMedia: %w", err)
}
-
return message, nil
}
@@ -3459,14 +3370,13 @@ type EditMessageLiveLocationParams struct {
// (https://core.telegram.org/bots/api#stopmessagelivelocation). On success, if the edited message is not an
// inline message, the edited Message (https://core.telegram.org/bots/api#message) is returned, otherwise True
// is returned.
-func (b *Bot) EditMessageLiveLocation(params *EditMessageLiveLocationParams) (*Message, error) {
+func (b *Bot) EditMessageLiveLocation(ctx context.Context, params *EditMessageLiveLocationParams) (*Message, error) {
var message *Message
var success *bool
- err := b.performRequest("editMessageLiveLocation", params, &message, &success)
+ err := b.performRequest(ctx, "editMessageLiveLocation", params, &message, &success)
if err != nil {
- return nil, fmt.Errorf("telego: editMessageLiveLocation(): %w", err)
+ return nil, fmt.Errorf("telego: editMessageLiveLocation: %w", err)
}
-
return message, nil
}
@@ -3496,14 +3406,13 @@ type StopMessageLiveLocationParams struct {
// StopMessageLiveLocation - Use this method to stop updating a live location message before live_period
// expires. On success, if the message is not an inline message, the edited Message
// (https://core.telegram.org/bots/api#message) is returned, otherwise True is returned.
-func (b *Bot) StopMessageLiveLocation(params *StopMessageLiveLocationParams) (*Message, error) {
+func (b *Bot) StopMessageLiveLocation(ctx context.Context, params *StopMessageLiveLocationParams) (*Message, error) {
var message *Message
var success *bool
- err := b.performRequest("stopMessageLiveLocation", params, &message, &success)
+ err := b.performRequest(ctx, "stopMessageLiveLocation", params, &message, &success)
if err != nil {
- return nil, fmt.Errorf("telego: stopMessageLiveLocation(): %w", err)
+ return nil, fmt.Errorf("telego: stopMessageLiveLocation: %w", err)
}
-
return message, nil
}
@@ -3533,14 +3442,13 @@ type EditMessageReplyMarkupParams struct {
// edited message is not an inline message, the edited Message (https://core.telegram.org/bots/api#message) is
// returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not
// contain an inline keyboard can only be edited within 48 hours from the time they were sent.
-func (b *Bot) EditMessageReplyMarkup(params *EditMessageReplyMarkupParams) (*Message, error) {
+func (b *Bot) EditMessageReplyMarkup(ctx context.Context, params *EditMessageReplyMarkupParams) (*Message, error) {
var message *Message
var success *bool
- err := b.performRequest("editMessageReplyMarkup", params, &message, &success)
+ err := b.performRequest(ctx, "editMessageReplyMarkup", params, &message, &success)
if err != nil {
- return nil, fmt.Errorf("telego: editMessageReplyMarkup(): %w", err)
+ return nil, fmt.Errorf("telego: editMessageReplyMarkup: %w", err)
}
-
return message, nil
}
@@ -3564,13 +3472,12 @@ type StopPollParams struct {
// StopPoll - Use this method to stop a poll which was sent by the bot. On success, the stopped Poll
// (https://core.telegram.org/bots/api#poll) is returned.
-func (b *Bot) StopPoll(params *StopPollParams) (*Poll, error) {
+func (b *Bot) StopPoll(ctx context.Context, params *StopPollParams) (*Poll, error) {
var poll *Poll
- err := b.performRequest("stopPoll", params, &poll)
+ err := b.performRequest(ctx, "stopPoll", params, &poll)
if err != nil {
- return nil, fmt.Errorf("telego: stopPoll(): %w", err)
+ return nil, fmt.Errorf("telego: stopPoll: %w", err)
}
-
return poll, nil
}
@@ -3596,12 +3503,11 @@ type DeleteMessageParams struct {
// - If the bot has can_delete_messages permission in a supergroup or a channel, it can delete any message
// there.
// Returns True on success.
-func (b *Bot) DeleteMessage(params *DeleteMessageParams) error {
- err := b.performRequest("deleteMessage", params)
+func (b *Bot) DeleteMessage(ctx context.Context, params *DeleteMessageParams) error {
+ err := b.performRequest(ctx, "deleteMessage", params)
if err != nil {
- return fmt.Errorf("telego: deleteMessage(): %w", err)
+ return fmt.Errorf("telego: deleteMessage: %w", err)
}
-
return nil
}
@@ -3618,12 +3524,11 @@ type DeleteMessagesParams struct {
// DeleteMessages - Use this method to delete multiple messages simultaneously. If some of the specified
// messages can't be found, they are skipped. Returns True on success.
-func (b *Bot) DeleteMessages(params *DeleteMessagesParams) error {
- err := b.performRequest("deleteMessages", params)
+func (b *Bot) DeleteMessages(ctx context.Context, params *DeleteMessagesParams) error {
+ err := b.performRequest(ctx, "deleteMessages", params)
if err != nil {
- return fmt.Errorf("telego: deleteMessages(): %w", err)
+ return fmt.Errorf("telego: deleteMessages: %w", err)
}
-
return nil
}
@@ -3686,13 +3591,12 @@ func (p *SendStickerParams) fileParameters() map[string]ta.NamedReader {
// SendSticker - Use this method to send static .WEBP, animated (https://telegram.org/blog/animated-stickers)
// .TGS, or video (https://telegram.org/blog/video-stickers-better-reactions) .WEBM stickers. On success, the
// sent Message (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendSticker(params *SendStickerParams) (*Message, error) {
+func (b *Bot) SendSticker(ctx context.Context, params *SendStickerParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendSticker", params, &message)
+ err := b.performRequest(ctx, "sendSticker", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendSticker(): %w", err)
+ return nil, fmt.Errorf("telego: sendSticker: %w", err)
}
-
return message, nil
}
@@ -3704,13 +3608,12 @@ type GetStickerSetParams struct {
// GetStickerSet - Use this method to get a sticker set. On success, a StickerSet
// (https://core.telegram.org/bots/api#stickerset) object is returned.
-func (b *Bot) GetStickerSet(params *GetStickerSetParams) (*StickerSet, error) {
+func (b *Bot) GetStickerSet(ctx context.Context, params *GetStickerSetParams) (*StickerSet, error) {
var stickerSet *StickerSet
- err := b.performRequest("getStickerSet", params, &stickerSet)
+ err := b.performRequest(ctx, "getStickerSet", params, &stickerSet)
if err != nil {
- return nil, fmt.Errorf("telego: getStickerSet(): %w", err)
+ return nil, fmt.Errorf("telego: getStickerSet: %w", err)
}
-
return stickerSet, nil
}
@@ -3723,13 +3626,12 @@ type GetCustomEmojiStickersParams struct {
// GetCustomEmojiStickers - Use this method to get information about custom emoji stickers by their
// identifiers. Returns an Array of Sticker (https://core.telegram.org/bots/api#sticker) objects.
-func (b *Bot) GetCustomEmojiStickers(params *GetCustomEmojiStickersParams) ([]Sticker, error) {
+func (b *Bot) GetCustomEmojiStickers(ctx context.Context, params *GetCustomEmojiStickersParams) ([]Sticker, error) {
var stickers []Sticker
- err := b.performRequest("getCustomEmojiStickers", params, &stickers)
+ err := b.performRequest(ctx, "getCustomEmojiStickers", params, &stickers)
if err != nil {
- return nil, fmt.Errorf("telego: getCustomEmojiStickers(): %w", err)
+ return nil, fmt.Errorf("telego: getCustomEmojiStickers: %w", err)
}
-
return stickers, nil
}
@@ -3765,13 +3667,12 @@ func (p *UploadStickerFileParams) fileParameters() map[string]ta.NamedReader {
// (https://core.telegram.org/bots/api#addstickertoset), or replaceStickerInSet
// (https://core.telegram.org/bots/api#replacestickerinset) methods (the file can be used multiple times).
// Returns the uploaded File (https://core.telegram.org/bots/api#file) on success.
-func (b *Bot) UploadStickerFile(params *UploadStickerFileParams) (*File, error) {
+func (b *Bot) UploadStickerFile(ctx context.Context, params *UploadStickerFileParams) (*File, error) {
var file *File
- err := b.performRequest("uploadStickerFile", params, &file)
+ err := b.performRequest(ctx, "uploadStickerFile", params, &file)
if err != nil {
- return nil, fmt.Errorf("telego: uploadStickerFile(): %w", err)
+ return nil, fmt.Errorf("telego: uploadStickerFile: %w", err)
}
-
return file, nil
}
@@ -3820,12 +3721,11 @@ func (p *CreateNewStickerSetParams) fileParameters() map[string]ta.NamedReader {
// CreateNewStickerSet - Use this method to create a new sticker set owned by a user. The bot will be able to
// edit the sticker set thus created. Returns True on success.
-func (b *Bot) CreateNewStickerSet(params *CreateNewStickerSetParams) error {
- err := b.performRequest("createNewStickerSet", params)
+func (b *Bot) CreateNewStickerSet(ctx context.Context, params *CreateNewStickerSetParams) error {
+ err := b.performRequest(ctx, "createNewStickerSet", params)
if err != nil {
- return fmt.Errorf("telego: createNewStickerSet(): %w", err)
+ return fmt.Errorf("telego: createNewStickerSet: %w", err)
}
-
return nil
}
@@ -3856,12 +3756,11 @@ func (p *AddStickerToSetParams) fileParameters() map[string]ta.NamedReader {
// AddStickerToSet - Use this method to add a new sticker to a set created by the bot. Emoji sticker sets can
// have up to 200 stickers. Other sticker sets can have up to 120 stickers. Returns True on success.
-func (b *Bot) AddStickerToSet(params *AddStickerToSetParams) error {
- err := b.performRequest("addStickerToSet", params)
+func (b *Bot) AddStickerToSet(ctx context.Context, params *AddStickerToSetParams) error {
+ err := b.performRequest(ctx, "addStickerToSet", params)
if err != nil {
- return fmt.Errorf("telego: addStickerToSet(): %w", err)
+ return fmt.Errorf("telego: addStickerToSet: %w", err)
}
-
return nil
}
@@ -3876,12 +3775,11 @@ type SetStickerPositionInSetParams struct {
// SetStickerPositionInSet - Use this method to move a sticker in a set created by the bot to a specific
// position. Returns True on success.
-func (b *Bot) SetStickerPositionInSet(params *SetStickerPositionInSetParams) error {
- err := b.performRequest("setStickerPositionInSet", params)
+func (b *Bot) SetStickerPositionInSet(ctx context.Context, params *SetStickerPositionInSetParams) error {
+ err := b.performRequest(ctx, "setStickerPositionInSet", params)
if err != nil {
- return fmt.Errorf("telego: setStickerPositionInSet(): %w", err)
+ return fmt.Errorf("telego: setStickerPositionInSet: %w", err)
}
-
return nil
}
@@ -3893,12 +3791,11 @@ type DeleteStickerFromSetParams struct {
// DeleteStickerFromSet - Use this method to delete a sticker from a set created by the bot. Returns True on
// success.
-func (b *Bot) DeleteStickerFromSet(params *DeleteStickerFromSetParams) error {
- err := b.performRequest("deleteStickerFromSet", params)
+func (b *Bot) DeleteStickerFromSet(ctx context.Context, params *DeleteStickerFromSetParams) error {
+ err := b.performRequest(ctx, "deleteStickerFromSet", params)
if err != nil {
- return fmt.Errorf("telego: deleteStickerFromSet(): %w", err)
+ return fmt.Errorf("telego: deleteStickerFromSet: %w", err)
}
-
return nil
}
@@ -3935,12 +3832,11 @@ func (p *ReplaceStickerInSetParams) fileParameters() map[string]ta.NamedReader {
// (https://core.telegram.org/bots/api#deletestickerfromset), then addStickerToSet
// (https://core.telegram.org/bots/api#addstickertoset), then setStickerPositionInSet
// (https://core.telegram.org/bots/api#setstickerpositioninset). Returns True on success.
-func (b *Bot) ReplaceStickerInSet(params *ReplaceStickerInSetParams) error {
- err := b.performRequest("replaceStickerInSet", params)
+func (b *Bot) ReplaceStickerInSet(ctx context.Context, params *ReplaceStickerInSetParams) error {
+ err := b.performRequest(ctx, "replaceStickerInSet", params)
if err != nil {
- return fmt.Errorf("telego: replaceStickerInSet(): %w", err)
+ return fmt.Errorf("telego: replaceStickerInSet: %w", err)
}
-
return nil
}
@@ -3955,12 +3851,11 @@ type SetStickerEmojiListParams struct {
// SetStickerEmojiList - Use this method to change the list of emoji assigned to a regular or custom emoji
// sticker. The sticker must belong to a sticker set created by the bot. Returns True on success.
-func (b *Bot) SetStickerEmojiList(params *SetStickerEmojiListParams) error {
- err := b.performRequest("setStickerEmojiList", params)
+func (b *Bot) SetStickerEmojiList(ctx context.Context, params *SetStickerEmojiListParams) error {
+ err := b.performRequest(ctx, "setStickerEmojiList", params)
if err != nil {
- return fmt.Errorf("telego: setStickerEmojiList(): %w", err)
+ return fmt.Errorf("telego: setStickerEmojiList: %w", err)
}
-
return nil
}
@@ -3976,12 +3871,11 @@ type SetStickerKeywordsParams struct {
// SetStickerKeywords - Use this method to change search keywords assigned to a regular or custom emoji
// sticker. The sticker must belong to a sticker set created by the bot. Returns True on success.
-func (b *Bot) SetStickerKeywords(params *SetStickerKeywordsParams) error {
- err := b.performRequest("setStickerKeywords", params)
+func (b *Bot) SetStickerKeywords(ctx context.Context, params *SetStickerKeywordsParams) error {
+ err := b.performRequest(ctx, "setStickerKeywords", params)
if err != nil {
- return fmt.Errorf("telego: setStickerKeywords(): %w", err)
+ return fmt.Errorf("telego: setStickerKeywords: %w", err)
}
-
return nil
}
@@ -3998,12 +3892,11 @@ type SetStickerMaskPositionParams struct {
// SetStickerMaskPosition - Use this method to change the mask position
// (https://core.telegram.org/bots/api#maskposition) of a mask sticker. The sticker must belong to a sticker set
// that was created by the bot. Returns True on success.
-func (b *Bot) SetStickerMaskPosition(params *SetStickerMaskPositionParams) error {
- err := b.performRequest("setStickerMaskPosition", params)
+func (b *Bot) SetStickerMaskPosition(ctx context.Context, params *SetStickerMaskPositionParams) error {
+ err := b.performRequest(ctx, "setStickerMaskPosition", params)
if err != nil {
- return fmt.Errorf("telego: setStickerMaskPosition(): %w", err)
+ return fmt.Errorf("telego: setStickerMaskPosition: %w", err)
}
-
return nil
}
@@ -4017,12 +3910,11 @@ type SetStickerSetTitleParams struct {
}
// SetStickerSetTitle - Use this method to set the title of a created sticker set. Returns True on success.
-func (b *Bot) SetStickerSetTitle(params *SetStickerSetTitleParams) error {
- err := b.performRequest("setStickerSetTitle", params)
+func (b *Bot) SetStickerSetTitle(ctx context.Context, params *SetStickerSetTitleParams) error {
+ err := b.performRequest(ctx, "setStickerSetTitle", params)
if err != nil {
- return fmt.Errorf("telego: setStickerSetTitle(): %w", err)
+ return fmt.Errorf("telego: setStickerSetTitle: %w", err)
}
-
return nil
}
@@ -4065,12 +3957,11 @@ func (p *SetStickerSetThumbnailParams) fileParameters() map[string]ta.NamedReade
// SetStickerSetThumbnail - Use this method to set the thumbnail of a regular or mask sticker set. The format
// of the thumbnail file must match the format of the stickers in the set. Returns True on success.
-func (b *Bot) SetStickerSetThumbnail(params *SetStickerSetThumbnailParams) error {
- err := b.performRequest("setStickerSetThumbnail", params)
+func (b *Bot) SetStickerSetThumbnail(ctx context.Context, params *SetStickerSetThumbnailParams) error {
+ err := b.performRequest(ctx, "setStickerSetThumbnail", params)
if err != nil {
- return fmt.Errorf("telego: setStickerSetThumbnail(): %w", err)
+ return fmt.Errorf("telego: setStickerSetThumbnail: %w", err)
}
-
return nil
}
@@ -4087,12 +3978,11 @@ type SetCustomEmojiStickerSetThumbnailParams struct {
// SetCustomEmojiStickerSetThumbnail - Use this method to set the thumbnail of a custom emoji sticker set.
// Returns True on success.
-func (b *Bot) SetCustomEmojiStickerSetThumbnail(params *SetCustomEmojiStickerSetThumbnailParams) error {
- err := b.performRequest("setCustomEmojiStickerSetThumbnail", params)
+func (b *Bot) SetCustomEmojiStickerSetThumbnail(ctx context.Context, params *SetCustomEmojiStickerSetThumbnailParams) error {
+ err := b.performRequest(ctx, "setCustomEmojiStickerSetThumbnail", params)
if err != nil {
- return fmt.Errorf("telego: setCustomEmojiStickerSetThumbnail(): %w", err)
+ return fmt.Errorf("telego: setCustomEmojiStickerSetThumbnail: %w", err)
}
-
return nil
}
@@ -4104,24 +3994,22 @@ type DeleteStickerSetParams struct {
// DeleteStickerSet - Use this method to delete a sticker set that was created by the bot. Returns True on
// success.
-func (b *Bot) DeleteStickerSet(params *DeleteStickerSetParams) error {
- err := b.performRequest("deleteStickerSet", params)
+func (b *Bot) DeleteStickerSet(ctx context.Context, params *DeleteStickerSetParams) error {
+ err := b.performRequest(ctx, "deleteStickerSet", params)
if err != nil {
- return fmt.Errorf("telego: deleteStickerSet(): %w", err)
+ return fmt.Errorf("telego: deleteStickerSet: %w", err)
}
-
return nil
}
// GetAvailableGifts - Returns the list of gifts that can be sent by the bot to users. Requires no
// parameters. Returns a Gifts (https://core.telegram.org/bots/api#gifts) object.
-func (b *Bot) GetAvailableGifts() (*Gifts, error) {
+func (b *Bot) GetAvailableGifts(ctx context.Context) (*Gifts, error) {
var gifts *Gifts
- err := b.performRequest("getAvailableGifts", nil, &gifts)
+ err := b.performRequest(ctx, "getAvailableGifts", nil, &gifts)
if err != nil {
- return nil, fmt.Errorf("telego: getAvailableGifts(): %w", err)
+ return nil, fmt.Errorf("telego: getAvailableGifts: %w", err)
}
-
return gifts, nil
}
@@ -4153,12 +4041,11 @@ type SendGiftParams struct {
// SendGift - Sends a gift to the given user. The gift can't be converted to Telegram Stars by the user.
// Returns True on success.
-func (b *Bot) SendGift(params *SendGiftParams) error {
- err := b.performRequest("sendGift", params)
+func (b *Bot) SendGift(ctx context.Context, params *SendGiftParams) error {
+ err := b.performRequest(ctx, "sendGift", params)
if err != nil {
- return fmt.Errorf("telego: sendGift(): %w", err)
+ return fmt.Errorf("telego: sendGift: %w", err)
}
-
return nil
}
@@ -4175,12 +4062,11 @@ type VerifyUserParams struct {
// VerifyUser - Verifies a user on behalf of the organization
// (https://telegram.org/verify#third-party-verification) which is represented by the bot. Returns True on
// success.
-func (b *Bot) VerifyUser(params *VerifyUserParams) error {
- err := b.performRequest("verifyUser", params)
+func (b *Bot) VerifyUser(ctx context.Context, params *VerifyUserParams) error {
+ err := b.performRequest(ctx, "verifyUser", params)
if err != nil {
- return fmt.Errorf("telego: verifyUser(): %w", err)
+ return fmt.Errorf("telego: verifyUser: %w", err)
}
-
return nil
}
@@ -4198,12 +4084,11 @@ type VerifyChatParams struct {
// VerifyChat - Verifies a chat on behalf of the organization
// (https://telegram.org/verify#third-party-verification) which is represented by the bot. Returns True on
// success.
-func (b *Bot) VerifyChat(params *VerifyChatParams) error {
- err := b.performRequest("verifyChat", params)
+func (b *Bot) VerifyChat(ctx context.Context, params *VerifyChatParams) error {
+ err := b.performRequest(ctx, "verifyChat", params)
if err != nil {
- return fmt.Errorf("telego: verifyChat(): %w", err)
+ return fmt.Errorf("telego: verifyChat: %w", err)
}
-
return nil
}
@@ -4216,12 +4101,11 @@ type RemoveUserVerificationParams struct {
// RemoveUserVerification - Removes verification from a user who is currently verified on behalf of the
// organization (https://telegram.org/verify#third-party-verification) represented by the bot. Returns True on
// success.
-func (b *Bot) RemoveUserVerification(params *RemoveUserVerificationParams) error {
- err := b.performRequest("removeUserVerification", params)
+func (b *Bot) RemoveUserVerification(ctx context.Context, params *RemoveUserVerificationParams) error {
+ err := b.performRequest(ctx, "removeUserVerification", params)
if err != nil {
- return fmt.Errorf("telego: removeUserVerification(): %w", err)
+ return fmt.Errorf("telego: removeUserVerification: %w", err)
}
-
return nil
}
@@ -4235,12 +4119,11 @@ type RemoveChatVerificationParams struct {
// RemoveChatVerification - Removes verification from a chat that is currently verified on behalf of the
// organization (https://telegram.org/verify#third-party-verification) represented by the bot. Returns True on
// success.
-func (b *Bot) RemoveChatVerification(params *RemoveChatVerificationParams) error {
- err := b.performRequest("removeChatVerification", params)
+func (b *Bot) RemoveChatVerification(ctx context.Context, params *RemoveChatVerificationParams) error {
+ err := b.performRequest(ctx, "removeChatVerification", params)
if err != nil {
- return fmt.Errorf("telego: removeChatVerification(): %w", err)
+ return fmt.Errorf("telego: removeChatVerification: %w", err)
}
-
return nil
}
@@ -4271,12 +4154,11 @@ type AnswerInlineQueryParams struct {
// AnswerInlineQuery - Use this method to send answers to an inline query. On success, True is returned.
// No more than 50 results per query are allowed.
-func (b *Bot) AnswerInlineQuery(params *AnswerInlineQueryParams) error {
- err := b.performRequest("answerInlineQuery", params)
+func (b *Bot) AnswerInlineQuery(ctx context.Context, params *AnswerInlineQueryParams) error {
+ err := b.performRequest(ctx, "answerInlineQuery", params)
if err != nil {
- return fmt.Errorf("telego: answerInlineQuery(): %w", err)
+ return fmt.Errorf("telego: answerInlineQuery: %w", err)
}
-
return nil
}
@@ -4293,13 +4175,12 @@ type AnswerWebAppQueryParams struct {
// (https://core.telegram.org/bots/webapps) and send a corresponding message on behalf of the user to the chat
// from which the query originated. On success, a SentWebAppMessage
// (https://core.telegram.org/bots/api#sentwebappmessage) object is returned.
-func (b *Bot) AnswerWebAppQuery(params *AnswerWebAppQueryParams) (*SentWebAppMessage, error) {
+func (b *Bot) AnswerWebAppQuery(ctx context.Context, params *AnswerWebAppQueryParams) (*SentWebAppMessage, error) {
var sentWebAppMessage *SentWebAppMessage
- err := b.performRequest("answerWebAppQuery", params, &sentWebAppMessage)
+ err := b.performRequest(ctx, "answerWebAppQuery", params, &sentWebAppMessage)
if err != nil {
- return nil, fmt.Errorf("telego: answerWebAppQuery(): %w", err)
+ return nil, fmt.Errorf("telego: answerWebAppQuery: %w", err)
}
-
return sentWebAppMessage, nil
}
@@ -4326,13 +4207,12 @@ type SavePreparedInlineMessageParams struct {
// SavePreparedInlineMessage - Stores a message that can be sent by a user of a Mini App. Returns a
// PreparedInlineMessage (https://core.telegram.org/bots/api#preparedinlinemessage) object.
-func (b *Bot) SavePreparedInlineMessage(params *SavePreparedInlineMessageParams) (*PreparedInlineMessage, error) {
+func (b *Bot) SavePreparedInlineMessage(ctx context.Context, params *SavePreparedInlineMessageParams) (*PreparedInlineMessage, error) {
var preparedInlineMessage *PreparedInlineMessage
- err := b.performRequest("savePreparedInlineMessage", params, &preparedInlineMessage)
+ err := b.performRequest(ctx, "savePreparedInlineMessage", params, &preparedInlineMessage)
if err != nil {
- return nil, fmt.Errorf("telego: savePreparedInlineMessage(): %w", err)
+ return nil, fmt.Errorf("telego: savePreparedInlineMessage: %w", err)
}
-
return preparedInlineMessage, nil
}
@@ -4461,13 +4341,12 @@ type SendInvoiceParams struct {
// SendInvoice - Use this method to send invoices. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendInvoice(params *SendInvoiceParams) (*Message, error) {
+func (b *Bot) SendInvoice(ctx context.Context, params *SendInvoiceParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendInvoice", params, &message)
+ err := b.performRequest(ctx, "sendInvoice", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendInvoice(): %w", err)
+ return nil, fmt.Errorf("telego: sendInvoice: %w", err)
}
-
return message, nil
}
@@ -4569,13 +4448,12 @@ type CreateInvoiceLinkParams struct {
// CreateInvoiceLink - Use this method to create a link for an invoice. Returns the created invoice link as
// String on success.
-func (b *Bot) CreateInvoiceLink(params *CreateInvoiceLinkParams) (*string, error) {
+func (b *Bot) CreateInvoiceLink(ctx context.Context, params *CreateInvoiceLinkParams) (*string, error) {
var invoiceLink *string
- err := b.performRequest("createInvoiceLink", params, &invoiceLink)
+ err := b.performRequest(ctx, "createInvoiceLink", params, &invoiceLink)
if err != nil {
- return nil, fmt.Errorf("telego: createInvoiceLink(): %w", err)
+ return nil, fmt.Errorf("telego: createInvoiceLink: %w", err)
}
-
return invoiceLink, nil
}
@@ -4601,12 +4479,11 @@ type AnswerShippingQueryParams struct {
// AnswerShippingQuery - If you sent an invoice requesting a shipping address and the parameter is_flexible
// was specified, the Bot API will send an Update (https://core.telegram.org/bots/api#update) with a
// shipping_query field to the bot. Use this method to reply to shipping queries. On success, True is returned.
-func (b *Bot) AnswerShippingQuery(params *AnswerShippingQueryParams) error {
- err := b.performRequest("answerShippingQuery", params)
+func (b *Bot) AnswerShippingQuery(ctx context.Context, params *AnswerShippingQueryParams) error {
+ err := b.performRequest(ctx, "answerShippingQuery", params)
if err != nil {
- return fmt.Errorf("telego: answerShippingQuery(): %w", err)
+ return fmt.Errorf("telego: answerShippingQuery: %w", err)
}
-
return nil
}
@@ -4630,12 +4507,11 @@ type AnswerPreCheckoutQueryParams struct {
// the final confirmation in the form of an Update (https://core.telegram.org/bots/api#update) with the field
// pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True is returned.
// Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
-func (b *Bot) AnswerPreCheckoutQuery(params *AnswerPreCheckoutQueryParams) error {
- err := b.performRequest("answerPreCheckoutQuery", params)
+func (b *Bot) AnswerPreCheckoutQuery(ctx context.Context, params *AnswerPreCheckoutQueryParams) error {
+ err := b.performRequest(ctx, "answerPreCheckoutQuery", params)
if err != nil {
- return fmt.Errorf("telego: answerPreCheckoutQuery(): %w", err)
+ return fmt.Errorf("telego: answerPreCheckoutQuery: %w", err)
}
-
return nil
}
@@ -4651,13 +4527,12 @@ type GetStarTransactionsParams struct {
// GetStarTransactions - Returns the bot's Telegram Star transactions in chronological order. On success,
// returns a StarTransactions (https://core.telegram.org/bots/api#startransactions) object.
-func (b *Bot) GetStarTransactions(params *GetStarTransactionsParams) (*StarTransactions, error) {
+func (b *Bot) GetStarTransactions(ctx context.Context, params *GetStarTransactionsParams) (*StarTransactions, error) {
var starTransactions *StarTransactions
- err := b.performRequest("getStarTransactions", params, &starTransactions)
+ err := b.performRequest(ctx, "getStarTransactions", params, &starTransactions)
if err != nil {
- return nil, fmt.Errorf("telego: getStarTransactions(): %w", err)
+ return nil, fmt.Errorf("telego: getStarTransactions: %w", err)
}
-
return starTransactions, nil
}
@@ -4672,12 +4547,11 @@ type RefundStarPaymentParams struct {
// RefundStarPayment - Refunds a successful payment in Telegram Stars (https://t.me/BotNews/90). Returns True
// on success.
-func (b *Bot) RefundStarPayment(params *RefundStarPaymentParams) error {
- err := b.performRequest("refundStarPayment", params)
+func (b *Bot) RefundStarPayment(ctx context.Context, params *RefundStarPaymentParams) error {
+ err := b.performRequest(ctx, "refundStarPayment", params)
if err != nil {
- return fmt.Errorf("telego: refundStarPayment(): %w", err)
+ return fmt.Errorf("telego: refundStarPayment: %w", err)
}
-
return nil
}
@@ -4697,12 +4571,11 @@ type EditUserStarSubscriptionParams struct {
// EditUserStarSubscription - Allows the bot to cancel or re-enable extension of a subscription paid in
// Telegram Stars. Returns True on success.
-func (b *Bot) EditUserStarSubscription(params *EditUserStarSubscriptionParams) error {
- err := b.performRequest("editUserStarSubscription", params)
+func (b *Bot) EditUserStarSubscription(ctx context.Context, params *EditUserStarSubscriptionParams) error {
+ err := b.performRequest(ctx, "editUserStarSubscription", params)
if err != nil {
- return fmt.Errorf("telego: editUserStarSubscription(): %w", err)
+ return fmt.Errorf("telego: editUserStarSubscription: %w", err)
}
-
return nil
}
@@ -4722,12 +4595,11 @@ type SetPassportDataErrorsParams struct {
// reason. For example, if a birthday date seems invalid, a submitted document is blurry, a scan shows evidence
// of tampering, etc. Supply some details in the error message to make sure the user knows how to correct the
// issues.
-func (b *Bot) SetPassportDataErrors(params *SetPassportDataErrorsParams) error {
- err := b.performRequest("setPassportDataErrors", params)
+func (b *Bot) SetPassportDataErrors(ctx context.Context, params *SetPassportDataErrorsParams) error {
+ err := b.performRequest(ctx, "setPassportDataErrors", params)
if err != nil {
- return fmt.Errorf("telego: setPassportDataErrors(): %w", err)
+ return fmt.Errorf("telego: setPassportDataErrors: %w", err)
}
-
return nil
}
@@ -4776,13 +4648,12 @@ type SendGameParams struct {
// SendGame - Use this method to send a game. On success, the sent Message
// (https://core.telegram.org/bots/api#message) is returned.
-func (b *Bot) SendGame(params *SendGameParams) (*Message, error) {
+func (b *Bot) SendGame(ctx context.Context, params *SendGameParams) (*Message, error) {
var message *Message
- err := b.performRequest("sendGame", params, &message)
+ err := b.performRequest(ctx, "sendGame", params, &message)
if err != nil {
- return nil, fmt.Errorf("telego: sendGame(): %w", err)
+ return nil, fmt.Errorf("telego: sendGame: %w", err)
}
-
return message, nil
}
@@ -4817,14 +4688,13 @@ type SetGameScoreParams struct {
// the message is not an inline message, the Message (https://core.telegram.org/bots/api#message) is returned,
// otherwise True is returned. Returns an error, if the new score is not greater than the user's current score
// in the chat and force is False.
-func (b *Bot) SetGameScore(params *SetGameScoreParams) (*Message, error) {
+func (b *Bot) SetGameScore(ctx context.Context, params *SetGameScoreParams) (*Message, error) {
var message *Message
var success *bool
- err := b.performRequest("setGameScore", params, &message, &success)
+ err := b.performRequest(ctx, "setGameScore", params, &message, &success)
if err != nil {
- return nil, fmt.Errorf("telego: setGameScore(): %w", err)
+ return nil, fmt.Errorf("telego: setGameScore: %w", err)
}
-
return message, nil
}
@@ -4850,12 +4720,11 @@ type GetGameHighScoresParams struct {
// This method will currently return scores for the target user, plus two of their closest neighbors on each
// side. Will also return the top three users if the user and their neighbors are not among them. Please note
// that this behavior is subject to change.
-func (b *Bot) GetGameHighScores(params *GetGameHighScoresParams) ([]GameHighScore, error) {
+func (b *Bot) GetGameHighScores(ctx context.Context, params *GetGameHighScoresParams) ([]GameHighScore, error) {
var gameHighScores []GameHighScore
- err := b.performRequest("getGameHighScores", params, &gameHighScores)
+ err := b.performRequest(ctx, "getGameHighScores", params, &gameHighScores)
if err != nil {
- return nil, fmt.Errorf("telego: getGameHighScores(): %w", err)
+ return nil, fmt.Errorf("telego: getGameHighScores: %w", err)
}
-
return gameHighScores, nil
}
diff --git a/methods_setters.go b/methods_setters.go
index 0ebc22ab..785bc43e 100644
--- a/methods_setters.go
+++ b/methods_setters.go
@@ -1442,7 +1442,7 @@ func (p *SendPollParams) WithOptions(options ...InputPollOption) *SendPollParams
// WithIsAnonymous adds is anonymous parameter
func (p *SendPollParams) WithIsAnonymous(isAnonymous bool) *SendPollParams {
- p.IsAnonymous = ToPtr(isAnonymous)
+ p.IsAnonymous = &isAnonymous
return p
}
@@ -1460,7 +1460,7 @@ func (p *SendPollParams) WithAllowsMultipleAnswers() *SendPollParams {
// WithCorrectOptionID adds correct option ID parameter
func (p *SendPollParams) WithCorrectOptionID(correctOptionID int) *SendPollParams {
- p.CorrectOptionID = ToPtr(correctOptionID)
+ p.CorrectOptionID = &correctOptionID
return p
}
@@ -1713,91 +1713,91 @@ func (p *PromoteChatMemberParams) WithChatID(chatID ChatID) *PromoteChatMemberPa
// WithIsAnonymous adds is anonymous parameter
func (p *PromoteChatMemberParams) WithIsAnonymous(isAnonymous bool) *PromoteChatMemberParams {
- p.IsAnonymous = ToPtr(isAnonymous)
+ p.IsAnonymous = &isAnonymous
return p
}
// WithCanManageChat adds can manage chat parameter
func (p *PromoteChatMemberParams) WithCanManageChat(canManageChat bool) *PromoteChatMemberParams {
- p.CanManageChat = ToPtr(canManageChat)
+ p.CanManageChat = &canManageChat
return p
}
// WithCanDeleteMessages adds can delete messages parameter
func (p *PromoteChatMemberParams) WithCanDeleteMessages(canDeleteMessages bool) *PromoteChatMemberParams {
- p.CanDeleteMessages = ToPtr(canDeleteMessages)
+ p.CanDeleteMessages = &canDeleteMessages
return p
}
// WithCanManageVideoChats adds can manage video chats parameter
func (p *PromoteChatMemberParams) WithCanManageVideoChats(canManageVideoChats bool) *PromoteChatMemberParams {
- p.CanManageVideoChats = ToPtr(canManageVideoChats)
+ p.CanManageVideoChats = &canManageVideoChats
return p
}
// WithCanRestrictMembers adds can restrict members parameter
func (p *PromoteChatMemberParams) WithCanRestrictMembers(canRestrictMembers bool) *PromoteChatMemberParams {
- p.CanRestrictMembers = ToPtr(canRestrictMembers)
+ p.CanRestrictMembers = &canRestrictMembers
return p
}
// WithCanPromoteMembers adds can promote members parameter
func (p *PromoteChatMemberParams) WithCanPromoteMembers(canPromoteMembers bool) *PromoteChatMemberParams {
- p.CanPromoteMembers = ToPtr(canPromoteMembers)
+ p.CanPromoteMembers = &canPromoteMembers
return p
}
// WithCanChangeInfo adds can change info parameter
func (p *PromoteChatMemberParams) WithCanChangeInfo(canChangeInfo bool) *PromoteChatMemberParams {
- p.CanChangeInfo = ToPtr(canChangeInfo)
+ p.CanChangeInfo = &canChangeInfo
return p
}
// WithCanInviteUsers adds can invite users parameter
func (p *PromoteChatMemberParams) WithCanInviteUsers(canInviteUsers bool) *PromoteChatMemberParams {
- p.CanInviteUsers = ToPtr(canInviteUsers)
+ p.CanInviteUsers = &canInviteUsers
return p
}
// WithCanPostStories adds can post stories parameter
func (p *PromoteChatMemberParams) WithCanPostStories(canPostStories bool) *PromoteChatMemberParams {
- p.CanPostStories = ToPtr(canPostStories)
+ p.CanPostStories = &canPostStories
return p
}
// WithCanEditStories adds can edit stories parameter
func (p *PromoteChatMemberParams) WithCanEditStories(canEditStories bool) *PromoteChatMemberParams {
- p.CanEditStories = ToPtr(canEditStories)
+ p.CanEditStories = &canEditStories
return p
}
// WithCanDeleteStories adds can delete stories parameter
func (p *PromoteChatMemberParams) WithCanDeleteStories(canDeleteStories bool) *PromoteChatMemberParams {
- p.CanDeleteStories = ToPtr(canDeleteStories)
+ p.CanDeleteStories = &canDeleteStories
return p
}
// WithCanPostMessages adds can post messages parameter
func (p *PromoteChatMemberParams) WithCanPostMessages(canPostMessages bool) *PromoteChatMemberParams {
- p.CanPostMessages = ToPtr(canPostMessages)
+ p.CanPostMessages = &canPostMessages
return p
}
// WithCanEditMessages adds can edit messages parameter
func (p *PromoteChatMemberParams) WithCanEditMessages(canEditMessages bool) *PromoteChatMemberParams {
- p.CanEditMessages = ToPtr(canEditMessages)
+ p.CanEditMessages = &canEditMessages
return p
}
// WithCanPinMessages adds can pin messages parameter
func (p *PromoteChatMemberParams) WithCanPinMessages(canPinMessages bool) *PromoteChatMemberParams {
- p.CanPinMessages = ToPtr(canPinMessages)
+ p.CanPinMessages = &canPinMessages
return p
}
// WithCanManageTopics adds can manage topics parameter
func (p *PromoteChatMemberParams) WithCanManageTopics(canManageTopics bool) *PromoteChatMemberParams {
- p.CanManageTopics = ToPtr(canManageTopics)
+ p.CanManageTopics = &canManageTopics
return p
}
@@ -2147,7 +2147,7 @@ func (p *EditForumTopicParams) WithName(name string) *EditForumTopicParams {
// WithIconCustomEmojiID adds icon custom emoji ID parameter
func (p *EditForumTopicParams) WithIconCustomEmojiID(iconCustomEmojiID string) *EditForumTopicParams {
- p.IconCustomEmojiID = ToPtr(iconCustomEmojiID)
+ p.IconCustomEmojiID = &iconCustomEmojiID
return p
}
diff --git a/methods_test.go b/methods_test.go
index 64676597..843bbc39 100644
--- a/methods_test.go
+++ b/methods_test.go
@@ -1,6 +1,7 @@
package telego
import (
+ "context"
"testing"
"github.com/stretchr/testify/assert"
@@ -10,6 +11,8 @@ import (
ta "github.com/mymmrac/telego/telegoapi"
)
+var testCtx = context.Background()
+
func TestBot_GetUpdates(t *testing.T) {
ctrl := gomock.NewController(t)
m := newMockedBot(ctrl)
@@ -25,10 +28,10 @@ func TestBot_GetUpdates(t *testing.T) {
}
resp := telegoResponse(t, expectedUpdates)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- updates, err := m.Bot.GetUpdates(nil)
+ updates, err := m.Bot.GetUpdates(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedUpdates, updates)
})
@@ -38,7 +41,7 @@ func TestBot_GetUpdates(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- updates, err := m.Bot.GetUpdates(nil)
+ updates, err := m.Bot.GetUpdates(testCtx, nil)
require.Error(t, err)
assert.Nil(t, updates)
})
@@ -54,10 +57,10 @@ func TestBot_SetWebhook(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetWebhook(nil)
+ err := m.Bot.SetWebhook(testCtx, nil)
require.NoError(t, err)
})
@@ -66,7 +69,7 @@ func TestBot_SetWebhook(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetWebhook(nil)
+ err := m.Bot.SetWebhook(testCtx, nil)
require.Error(t, err)
})
}
@@ -81,10 +84,10 @@ func TestBot_DeleteWebhook(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteWebhook(nil)
+ err := m.Bot.DeleteWebhook(testCtx, nil)
require.NoError(t, err)
})
@@ -93,7 +96,7 @@ func TestBot_DeleteWebhook(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteWebhook(nil)
+ err := m.Bot.DeleteWebhook(testCtx, nil)
require.Error(t, err)
})
}
@@ -112,10 +115,10 @@ func TestBot_GetWebhookInfo(t *testing.T) {
}
resp := telegoResponse(t, expectedWebhookInfo)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- webhookInfo, err := m.Bot.GetWebhookInfo()
+ webhookInfo, err := m.Bot.GetWebhookInfo(testCtx)
require.NoError(t, err)
assert.Equal(t, expectedWebhookInfo, webhookInfo)
})
@@ -125,7 +128,7 @@ func TestBot_GetWebhookInfo(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- webhookInfo, err := m.Bot.GetWebhookInfo()
+ webhookInfo, err := m.Bot.GetWebhookInfo(testCtx)
require.Error(t, err)
assert.Nil(t, webhookInfo)
})
@@ -145,10 +148,10 @@ func TestBot_GetMe(t *testing.T) {
}
resp := telegoResponse(t, expectedUser)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- user, err := m.Bot.GetMe()
+ user, err := m.Bot.GetMe(testCtx)
require.NoError(t, err)
assert.Equal(t, expectedUser, user)
})
@@ -158,7 +161,7 @@ func TestBot_GetMe(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- user, err := m.Bot.GetMe()
+ user, err := m.Bot.GetMe(testCtx)
require.Error(t, err)
assert.Nil(t, user)
})
@@ -174,10 +177,10 @@ func TestBot_LogOut(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.LogOut()
+ err := m.Bot.LogOut(testCtx)
require.NoError(t, err)
})
@@ -186,7 +189,7 @@ func TestBot_LogOut(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.LogOut()
+ err := m.Bot.LogOut(testCtx)
require.Error(t, err)
})
}
@@ -201,10 +204,10 @@ func TestBot_Close(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.Close()
+ err := m.Bot.Close(testCtx)
require.NoError(t, err)
})
@@ -213,7 +216,7 @@ func TestBot_Close(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.Close()
+ err := m.Bot.Close(testCtx)
require.Error(t, err)
})
}
@@ -229,10 +232,10 @@ func TestBot_SendMessage(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendMessage(nil)
+ message, err := m.Bot.SendMessage(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -242,7 +245,7 @@ func TestBot_SendMessage(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendMessage(nil)
+ message, err := m.Bot.SendMessage(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -259,10 +262,10 @@ func TestBot_ForwardMessage(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.ForwardMessage(nil)
+ message, err := m.Bot.ForwardMessage(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -272,7 +275,7 @@ func TestBot_ForwardMessage(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.ForwardMessage(nil)
+ message, err := m.Bot.ForwardMessage(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -293,10 +296,10 @@ func TestBot_ForwardMessages(t *testing.T) {
}
resp := telegoResponse(t, expectedMessageIDs)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- messageIDs, err := m.Bot.ForwardMessages(nil)
+ messageIDs, err := m.Bot.ForwardMessages(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessageIDs, messageIDs)
})
@@ -306,7 +309,7 @@ func TestBot_ForwardMessages(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- messageIDs, err := m.Bot.ForwardMessages(nil)
+ messageIDs, err := m.Bot.ForwardMessages(testCtx, nil)
require.Error(t, err)
assert.Nil(t, messageIDs)
})
@@ -326,10 +329,10 @@ func TestBot_CopyMessage(t *testing.T) {
}
resp := telegoResponse(t, expectedMessageID)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- messageID, err := m.Bot.CopyMessage(nil)
+ messageID, err := m.Bot.CopyMessage(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessageID, messageID)
})
@@ -339,7 +342,7 @@ func TestBot_CopyMessage(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- messageID, err := m.Bot.CopyMessage(nil)
+ messageID, err := m.Bot.CopyMessage(testCtx, nil)
require.Error(t, err)
assert.Nil(t, messageID)
})
@@ -360,10 +363,10 @@ func TestBot_CopyMessages(t *testing.T) {
}
resp := telegoResponse(t, expectedMessageIDs)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- messageIDs, err := m.Bot.CopyMessages(nil)
+ messageIDs, err := m.Bot.CopyMessages(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessageIDs, messageIDs)
})
@@ -373,7 +376,7 @@ func TestBot_CopyMessages(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- messageIDs, err := m.Bot.CopyMessages(nil)
+ messageIDs, err := m.Bot.CopyMessages(testCtx, nil)
require.Error(t, err)
assert.Nil(t, messageIDs)
})
@@ -390,10 +393,10 @@ func TestBot_SendPhoto(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendPhoto(nil)
+ message, err := m.Bot.SendPhoto(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -403,7 +406,7 @@ func TestBot_SendPhoto(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendPhoto(nil)
+ message, err := m.Bot.SendPhoto(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -420,10 +423,10 @@ func TestBot_SendAudio(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendAudio(nil)
+ message, err := m.Bot.SendAudio(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -433,7 +436,7 @@ func TestBot_SendAudio(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendAudio(nil)
+ message, err := m.Bot.SendAudio(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -450,10 +453,10 @@ func TestBot_SendDocument(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendDocument(nil)
+ message, err := m.Bot.SendDocument(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -463,7 +466,7 @@ func TestBot_SendDocument(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendDocument(nil)
+ message, err := m.Bot.SendDocument(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -480,10 +483,10 @@ func TestBot_SendVideo(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendVideo(nil)
+ message, err := m.Bot.SendVideo(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -493,7 +496,7 @@ func TestBot_SendVideo(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendVideo(nil)
+ message, err := m.Bot.SendVideo(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -510,10 +513,10 @@ func TestBot_SendAnimation(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendAnimation(nil)
+ message, err := m.Bot.SendAnimation(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -523,7 +526,7 @@ func TestBot_SendAnimation(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendAnimation(nil)
+ message, err := m.Bot.SendAnimation(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -540,10 +543,10 @@ func TestBot_SendVoice(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendVoice(nil)
+ message, err := m.Bot.SendVoice(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -553,7 +556,7 @@ func TestBot_SendVoice(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendVoice(nil)
+ message, err := m.Bot.SendVoice(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -570,10 +573,10 @@ func TestBot_SendVideoNote(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendVideoNote(nil)
+ message, err := m.Bot.SendVideoNote(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -583,7 +586,7 @@ func TestBot_SendVideoNote(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendVideoNote(nil)
+ message, err := m.Bot.SendVideoNote(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -600,10 +603,10 @@ func TestBot_SendPaidMedia(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendPaidMedia(nil)
+ message, err := m.Bot.SendPaidMedia(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -613,7 +616,7 @@ func TestBot_SendPaidMedia(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendPaidMedia(nil)
+ message, err := m.Bot.SendPaidMedia(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -634,10 +637,10 @@ func TestBot_SendMediaGroup(t *testing.T) {
}
resp := telegoResponse(t, expectedMessages)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- messages, err := m.Bot.SendMediaGroup(nil)
+ messages, err := m.Bot.SendMediaGroup(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessages, messages)
})
@@ -647,7 +650,7 @@ func TestBot_SendMediaGroup(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- messages, err := m.Bot.SendMediaGroup(nil)
+ messages, err := m.Bot.SendMediaGroup(testCtx, nil)
require.Error(t, err)
assert.Nil(t, messages)
})
@@ -664,10 +667,10 @@ func TestBot_SendLocation(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendLocation(nil)
+ message, err := m.Bot.SendLocation(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -677,7 +680,7 @@ func TestBot_SendLocation(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendLocation(nil)
+ message, err := m.Bot.SendLocation(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -694,10 +697,10 @@ func TestBot_SendVenue(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendVenue(nil)
+ message, err := m.Bot.SendVenue(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -707,7 +710,7 @@ func TestBot_SendVenue(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendVenue(nil)
+ message, err := m.Bot.SendVenue(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -724,10 +727,10 @@ func TestBot_SendContact(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendContact(nil)
+ message, err := m.Bot.SendContact(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -737,7 +740,7 @@ func TestBot_SendContact(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendContact(nil)
+ message, err := m.Bot.SendContact(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -754,10 +757,10 @@ func TestBot_SendPoll(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendPoll(nil)
+ message, err := m.Bot.SendPoll(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -767,7 +770,7 @@ func TestBot_SendPoll(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendPoll(nil)
+ message, err := m.Bot.SendPoll(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -784,10 +787,10 @@ func TestBot_SendDice(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendDice(nil)
+ message, err := m.Bot.SendDice(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -797,7 +800,7 @@ func TestBot_SendDice(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendDice(nil)
+ message, err := m.Bot.SendDice(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -813,10 +816,10 @@ func TestBot_SendChatAction(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SendChatAction(nil)
+ err := m.Bot.SendChatAction(testCtx, nil)
require.NoError(t, err)
})
@@ -825,7 +828,7 @@ func TestBot_SendChatAction(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SendChatAction(nil)
+ err := m.Bot.SendChatAction(testCtx, nil)
require.Error(t, err)
})
}
@@ -840,10 +843,10 @@ func TestBot_SetMessageReaction(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetMessageReaction(nil)
+ err := m.Bot.SetMessageReaction(testCtx, nil)
require.NoError(t, err)
})
@@ -852,7 +855,7 @@ func TestBot_SetMessageReaction(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetMessageReaction(nil)
+ err := m.Bot.SetMessageReaction(testCtx, nil)
require.Error(t, err)
})
}
@@ -871,10 +874,10 @@ func TestBot_GetUserProfilePhotos(t *testing.T) {
}
resp := telegoResponse(t, expectedUserProfilePhotos)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- userProfilePhotos, err := m.Bot.GetUserProfilePhotos(nil)
+ userProfilePhotos, err := m.Bot.GetUserProfilePhotos(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedUserProfilePhotos, userProfilePhotos)
})
@@ -884,7 +887,7 @@ func TestBot_GetUserProfilePhotos(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- userProfilePhotos, err := m.Bot.GetUserProfilePhotos(nil)
+ userProfilePhotos, err := m.Bot.GetUserProfilePhotos(testCtx, nil)
require.Error(t, err)
assert.Nil(t, userProfilePhotos)
})
@@ -900,10 +903,10 @@ func TestBot_SetUserEmojiStatus(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetUserEmojiStatus(nil)
+ err := m.Bot.SetUserEmojiStatus(testCtx, nil)
require.NoError(t, err)
})
@@ -912,7 +915,7 @@ func TestBot_SetUserEmojiStatus(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetUserEmojiStatus(nil)
+ err := m.Bot.SetUserEmojiStatus(testCtx, nil)
require.Error(t, err)
})
}
@@ -931,10 +934,10 @@ func TestBot_GetFile(t *testing.T) {
}
resp := telegoResponse(t, expectedFile)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- file, err := m.Bot.GetFile(nil)
+ file, err := m.Bot.GetFile(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedFile, file)
})
@@ -944,7 +947,7 @@ func TestBot_GetFile(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- file, err := m.Bot.GetFile(nil)
+ file, err := m.Bot.GetFile(testCtx, nil)
require.Error(t, err)
assert.Nil(t, file)
})
@@ -960,10 +963,10 @@ func TestBot_BanChatMember(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.BanChatMember(nil)
+ err := m.Bot.BanChatMember(testCtx, nil)
require.NoError(t, err)
})
@@ -972,7 +975,7 @@ func TestBot_BanChatMember(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.BanChatMember(nil)
+ err := m.Bot.BanChatMember(testCtx, nil)
require.Error(t, err)
})
}
@@ -987,10 +990,10 @@ func TestBot_UnbanChatMember(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.UnbanChatMember(nil)
+ err := m.Bot.UnbanChatMember(testCtx, nil)
require.NoError(t, err)
})
@@ -999,7 +1002,7 @@ func TestBot_UnbanChatMember(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.UnbanChatMember(nil)
+ err := m.Bot.UnbanChatMember(testCtx, nil)
require.Error(t, err)
})
}
@@ -1014,10 +1017,10 @@ func TestBot_RestrictChatMember(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.RestrictChatMember(nil)
+ err := m.Bot.RestrictChatMember(testCtx, nil)
require.NoError(t, err)
})
@@ -1026,7 +1029,7 @@ func TestBot_RestrictChatMember(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.RestrictChatMember(nil)
+ err := m.Bot.RestrictChatMember(testCtx, nil)
require.Error(t, err)
})
}
@@ -1041,10 +1044,10 @@ func TestBot_PromoteChatMember(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.PromoteChatMember(nil)
+ err := m.Bot.PromoteChatMember(testCtx, nil)
require.NoError(t, err)
})
@@ -1053,7 +1056,7 @@ func TestBot_PromoteChatMember(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.PromoteChatMember(nil)
+ err := m.Bot.PromoteChatMember(testCtx, nil)
require.Error(t, err)
})
}
@@ -1068,10 +1071,10 @@ func TestBot_SetChatAdministratorCustomTitle(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetChatAdministratorCustomTitle(nil)
+ err := m.Bot.SetChatAdministratorCustomTitle(testCtx, nil)
require.NoError(t, err)
})
@@ -1080,7 +1083,7 @@ func TestBot_SetChatAdministratorCustomTitle(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetChatAdministratorCustomTitle(nil)
+ err := m.Bot.SetChatAdministratorCustomTitle(testCtx, nil)
require.Error(t, err)
})
}
@@ -1095,10 +1098,10 @@ func TestBot_BanChatSenderChat(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.BanChatSenderChat(nil)
+ err := m.Bot.BanChatSenderChat(testCtx, nil)
require.NoError(t, err)
})
@@ -1107,7 +1110,7 @@ func TestBot_BanChatSenderChat(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.BanChatSenderChat(nil)
+ err := m.Bot.BanChatSenderChat(testCtx, nil)
require.Error(t, err)
})
}
@@ -1122,10 +1125,10 @@ func TestBot_UnbanChatSenderChat(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.UnbanChatSenderChat(nil)
+ err := m.Bot.UnbanChatSenderChat(testCtx, nil)
require.NoError(t, err)
})
@@ -1134,7 +1137,7 @@ func TestBot_UnbanChatSenderChat(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.UnbanChatSenderChat(nil)
+ err := m.Bot.UnbanChatSenderChat(testCtx, nil)
require.Error(t, err)
})
}
@@ -1149,10 +1152,10 @@ func TestBot_SetChatPermissions(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetChatPermissions(nil)
+ err := m.Bot.SetChatPermissions(testCtx, nil)
require.NoError(t, err)
})
@@ -1161,7 +1164,7 @@ func TestBot_SetChatPermissions(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetChatPermissions(nil)
+ err := m.Bot.SetChatPermissions(testCtx, nil)
require.Error(t, err)
})
}
@@ -1178,10 +1181,10 @@ func TestBot_ExportChatInviteLink(t *testing.T) {
expectedInviteLink := "InviteLink"
resp := telegoResponse(t, expectedInviteLink)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- inviteLink, err := m.Bot.ExportChatInviteLink(nil)
+ inviteLink, err := m.Bot.ExportChatInviteLink(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, &expectedInviteLink, inviteLink)
})
@@ -1191,7 +1194,7 @@ func TestBot_ExportChatInviteLink(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- inviteLink, err := m.Bot.ExportChatInviteLink(nil)
+ inviteLink, err := m.Bot.ExportChatInviteLink(testCtx, nil)
require.Error(t, err)
assert.Nil(t, inviteLink)
})
@@ -1211,10 +1214,10 @@ func TestBot_CreateChatInviteLink(t *testing.T) {
}
resp := telegoResponse(t, expectedChatInviteLink)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatInviteLink, err := m.Bot.CreateChatInviteLink(nil)
+ chatInviteLink, err := m.Bot.CreateChatInviteLink(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatInviteLink, chatInviteLink)
})
@@ -1224,7 +1227,7 @@ func TestBot_CreateChatInviteLink(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatInviteLink, err := m.Bot.CreateChatInviteLink(nil)
+ chatInviteLink, err := m.Bot.CreateChatInviteLink(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatInviteLink)
})
@@ -1244,10 +1247,10 @@ func TestBot_EditChatInviteLink(t *testing.T) {
}
resp := telegoResponse(t, expectedChatInviteLink)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatInviteLink, err := m.Bot.EditChatInviteLink(nil)
+ chatInviteLink, err := m.Bot.EditChatInviteLink(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatInviteLink, chatInviteLink)
})
@@ -1257,7 +1260,7 @@ func TestBot_EditChatInviteLink(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatInviteLink, err := m.Bot.EditChatInviteLink(nil)
+ chatInviteLink, err := m.Bot.EditChatInviteLink(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatInviteLink)
})
@@ -1277,10 +1280,10 @@ func TestBot_CreateChatSubscriptionInviteLink(t *testing.T) {
}
resp := telegoResponse(t, expectedChatInviteLink)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatInviteLink, err := m.Bot.CreateChatSubscriptionInviteLink(nil)
+ chatInviteLink, err := m.Bot.CreateChatSubscriptionInviteLink(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatInviteLink, chatInviteLink)
})
@@ -1290,7 +1293,7 @@ func TestBot_CreateChatSubscriptionInviteLink(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatInviteLink, err := m.Bot.CreateChatSubscriptionInviteLink(nil)
+ chatInviteLink, err := m.Bot.CreateChatSubscriptionInviteLink(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatInviteLink)
})
@@ -1310,10 +1313,10 @@ func TestBot_EditChatSubscriptionInviteLink(t *testing.T) {
}
resp := telegoResponse(t, expectedChatInviteLink)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatInviteLink, err := m.Bot.EditChatSubscriptionInviteLink(nil)
+ chatInviteLink, err := m.Bot.EditChatSubscriptionInviteLink(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatInviteLink, chatInviteLink)
})
@@ -1323,7 +1326,7 @@ func TestBot_EditChatSubscriptionInviteLink(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatInviteLink, err := m.Bot.EditChatSubscriptionInviteLink(nil)
+ chatInviteLink, err := m.Bot.EditChatSubscriptionInviteLink(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatInviteLink)
})
@@ -1343,10 +1346,10 @@ func TestBot_RevokeChatInviteLink(t *testing.T) {
}
resp := telegoResponse(t, expectedChatInviteLink)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatInviteLink, err := m.Bot.RevokeChatInviteLink(nil)
+ chatInviteLink, err := m.Bot.RevokeChatInviteLink(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatInviteLink, chatInviteLink)
})
@@ -1356,7 +1359,7 @@ func TestBot_RevokeChatInviteLink(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatInviteLink, err := m.Bot.RevokeChatInviteLink(nil)
+ chatInviteLink, err := m.Bot.RevokeChatInviteLink(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatInviteLink)
})
@@ -1372,10 +1375,10 @@ func TestBot_ApproveChatJoinRequest(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.ApproveChatJoinRequest(nil)
+ err := m.Bot.ApproveChatJoinRequest(testCtx, nil)
require.NoError(t, err)
})
@@ -1384,7 +1387,7 @@ func TestBot_ApproveChatJoinRequest(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.ApproveChatJoinRequest(nil)
+ err := m.Bot.ApproveChatJoinRequest(testCtx, nil)
require.Error(t, err)
})
}
@@ -1399,10 +1402,10 @@ func TestBot_DeclineChatJoinRequest(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeclineChatJoinRequest(nil)
+ err := m.Bot.DeclineChatJoinRequest(testCtx, nil)
require.NoError(t, err)
})
@@ -1411,7 +1414,7 @@ func TestBot_DeclineChatJoinRequest(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeclineChatJoinRequest(nil)
+ err := m.Bot.DeclineChatJoinRequest(testCtx, nil)
require.Error(t, err)
})
}
@@ -1426,10 +1429,10 @@ func TestBot_SetChatPhoto(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetChatPhoto(nil)
+ err := m.Bot.SetChatPhoto(testCtx, nil)
require.NoError(t, err)
})
@@ -1438,7 +1441,7 @@ func TestBot_SetChatPhoto(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetChatPhoto(nil)
+ err := m.Bot.SetChatPhoto(testCtx, nil)
require.Error(t, err)
})
}
@@ -1453,10 +1456,10 @@ func TestBot_DeleteChatPhoto(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteChatPhoto(nil)
+ err := m.Bot.DeleteChatPhoto(testCtx, nil)
require.NoError(t, err)
})
@@ -1465,7 +1468,7 @@ func TestBot_DeleteChatPhoto(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteChatPhoto(nil)
+ err := m.Bot.DeleteChatPhoto(testCtx, nil)
require.Error(t, err)
})
}
@@ -1480,10 +1483,10 @@ func TestBot_SetChatTitle(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetChatTitle(nil)
+ err := m.Bot.SetChatTitle(testCtx, nil)
require.NoError(t, err)
})
@@ -1492,7 +1495,7 @@ func TestBot_SetChatTitle(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetChatTitle(nil)
+ err := m.Bot.SetChatTitle(testCtx, nil)
require.Error(t, err)
})
}
@@ -1507,10 +1510,10 @@ func TestBot_SetChatDescription(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetChatDescription(nil)
+ err := m.Bot.SetChatDescription(testCtx, nil)
require.NoError(t, err)
})
@@ -1519,7 +1522,7 @@ func TestBot_SetChatDescription(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetChatDescription(nil)
+ err := m.Bot.SetChatDescription(testCtx, nil)
require.Error(t, err)
})
}
@@ -1534,10 +1537,10 @@ func TestBot_PinChatMessage(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.PinChatMessage(nil)
+ err := m.Bot.PinChatMessage(testCtx, nil)
require.NoError(t, err)
})
@@ -1546,7 +1549,7 @@ func TestBot_PinChatMessage(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.PinChatMessage(nil)
+ err := m.Bot.PinChatMessage(testCtx, nil)
require.Error(t, err)
})
}
@@ -1561,10 +1564,10 @@ func TestBot_UnpinChatMessage(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.UnpinChatMessage(nil)
+ err := m.Bot.UnpinChatMessage(testCtx, nil)
require.NoError(t, err)
})
@@ -1573,7 +1576,7 @@ func TestBot_UnpinChatMessage(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.UnpinChatMessage(nil)
+ err := m.Bot.UnpinChatMessage(testCtx, nil)
require.Error(t, err)
})
}
@@ -1588,10 +1591,10 @@ func TestBot_UnpinAllChatMessages(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.UnpinAllChatMessages(nil)
+ err := m.Bot.UnpinAllChatMessages(testCtx, nil)
require.NoError(t, err)
})
@@ -1600,7 +1603,7 @@ func TestBot_UnpinAllChatMessages(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.UnpinAllChatMessages(nil)
+ err := m.Bot.UnpinAllChatMessages(testCtx, nil)
require.Error(t, err)
})
}
@@ -1615,10 +1618,10 @@ func TestBot_LeaveChat(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.LeaveChat(nil)
+ err := m.Bot.LeaveChat(testCtx, nil)
require.NoError(t, err)
})
@@ -1627,7 +1630,7 @@ func TestBot_LeaveChat(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.LeaveChat(nil)
+ err := m.Bot.LeaveChat(testCtx, nil)
require.Error(t, err)
})
}
@@ -1646,10 +1649,10 @@ func TestBot_GetChat(t *testing.T) {
}
resp := telegoResponse(t, expectedChatFullInfo)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatFullInfo, err := m.Bot.GetChat(nil)
+ chatFullInfo, err := m.Bot.GetChat(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatFullInfo, chatFullInfo)
})
@@ -1659,7 +1662,7 @@ func TestBot_GetChat(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatFullInfo, err := m.Bot.GetChat(nil)
+ chatFullInfo, err := m.Bot.GetChat(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatFullInfo)
})
@@ -1680,10 +1683,10 @@ func TestBot_GetChatAdministrators(t *testing.T) {
}
resp := telegoResponse(t, expectedChatMembers)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatMembers, err := m.Bot.GetChatAdministrators(nil)
+ chatMembers, err := m.Bot.GetChatAdministrators(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatMembers, chatMembers)
})
@@ -1693,7 +1696,7 @@ func TestBot_GetChatAdministrators(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatMembers, err := m.Bot.GetChatAdministrators(nil)
+ chatMembers, err := m.Bot.GetChatAdministrators(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatMembers)
})
@@ -1711,10 +1714,10 @@ func TestBot_GetChatMemberCount(t *testing.T) {
expectedChatMemberCount := 1
resp := telegoResponse(t, expectedChatMemberCount)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatMemberCount, err := m.Bot.GetChatMemberCount(nil)
+ chatMemberCount, err := m.Bot.GetChatMemberCount(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, &expectedChatMemberCount, chatMemberCount)
})
@@ -1724,7 +1727,7 @@ func TestBot_GetChatMemberCount(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- nt, err := m.Bot.GetChatMemberCount(nil)
+ nt, err := m.Bot.GetChatMemberCount(testCtx, nil)
require.Error(t, err)
assert.Nil(t, nt)
})
@@ -1744,10 +1747,10 @@ func TestBot_GetChatMember(t *testing.T) {
}
resp := telegoResponse(t, expectedChatMember)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatMember, err := m.Bot.GetChatMember(nil)
+ chatMember, err := m.Bot.GetChatMember(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatMember, chatMember)
})
@@ -1757,7 +1760,7 @@ func TestBot_GetChatMember(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatMember, err := m.Bot.GetChatMember(nil)
+ chatMember, err := m.Bot.GetChatMember(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatMember)
})
@@ -1773,10 +1776,10 @@ func TestBot_SetChatStickerSet(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetChatStickerSet(nil)
+ err := m.Bot.SetChatStickerSet(testCtx, nil)
require.NoError(t, err)
})
@@ -1785,7 +1788,7 @@ func TestBot_SetChatStickerSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetChatStickerSet(nil)
+ err := m.Bot.SetChatStickerSet(testCtx, nil)
require.Error(t, err)
})
}
@@ -1800,10 +1803,10 @@ func TestBot_DeleteChatStickerSet(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteChatStickerSet(nil)
+ err := m.Bot.DeleteChatStickerSet(testCtx, nil)
require.NoError(t, err)
})
@@ -1812,7 +1815,7 @@ func TestBot_DeleteChatStickerSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteChatStickerSet(nil)
+ err := m.Bot.DeleteChatStickerSet(testCtx, nil)
require.Error(t, err)
})
}
@@ -1831,10 +1834,10 @@ func TestBot_GetForumTopicIconStickers(t *testing.T) {
}
resp := telegoResponse(t, expectedStickers)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- stickers, err := m.Bot.GetForumTopicIconStickers()
+ stickers, err := m.Bot.GetForumTopicIconStickers(testCtx)
require.NoError(t, err)
assert.Equal(t, expectedStickers, stickers)
})
@@ -1844,7 +1847,7 @@ func TestBot_GetForumTopicIconStickers(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- stickers, err := m.Bot.GetForumTopicIconStickers()
+ stickers, err := m.Bot.GetForumTopicIconStickers(testCtx)
require.Error(t, err)
assert.Nil(t, stickers)
})
@@ -1864,10 +1867,10 @@ func TestBot_CreateForumTopic(t *testing.T) {
}
resp := telegoResponse(t, expectedForumTopic)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- forumTopic, err := m.Bot.CreateForumTopic(nil)
+ forumTopic, err := m.Bot.CreateForumTopic(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedForumTopic, forumTopic)
})
@@ -1877,7 +1880,7 @@ func TestBot_CreateForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- forumTopic, err := m.Bot.CreateForumTopic(nil)
+ forumTopic, err := m.Bot.CreateForumTopic(testCtx, nil)
require.Error(t, err)
assert.Nil(t, forumTopic)
})
@@ -1893,10 +1896,10 @@ func TestBot_EditForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.EditForumTopic(nil)
+ err := m.Bot.EditForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -1905,7 +1908,7 @@ func TestBot_EditForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.EditForumTopic(nil)
+ err := m.Bot.EditForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -1920,10 +1923,10 @@ func TestBot_CloseForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.CloseForumTopic(nil)
+ err := m.Bot.CloseForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -1932,7 +1935,7 @@ func TestBot_CloseForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.CloseForumTopic(nil)
+ err := m.Bot.CloseForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -1947,10 +1950,10 @@ func TestBot_ReopenForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.ReopenForumTopic(nil)
+ err := m.Bot.ReopenForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -1959,7 +1962,7 @@ func TestBot_ReopenForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.ReopenForumTopic(nil)
+ err := m.Bot.ReopenForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -1974,10 +1977,10 @@ func TestBot_DeleteForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteForumTopic(nil)
+ err := m.Bot.DeleteForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -1986,7 +1989,7 @@ func TestBot_DeleteForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteForumTopic(nil)
+ err := m.Bot.DeleteForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -2001,10 +2004,10 @@ func TestBot_UnpinAllForumTopicMessages(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.UnpinAllForumTopicMessages(nil)
+ err := m.Bot.UnpinAllForumTopicMessages(testCtx, nil)
require.NoError(t, err)
})
@@ -2013,7 +2016,7 @@ func TestBot_UnpinAllForumTopicMessages(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.UnpinAllForumTopicMessages(nil)
+ err := m.Bot.UnpinAllForumTopicMessages(testCtx, nil)
require.Error(t, err)
})
}
@@ -2028,10 +2031,10 @@ func TestBot_EditGeneralForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.EditGeneralForumTopic(nil)
+ err := m.Bot.EditGeneralForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -2040,7 +2043,7 @@ func TestBot_EditGeneralForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.EditGeneralForumTopic(nil)
+ err := m.Bot.EditGeneralForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -2055,10 +2058,10 @@ func TestBot_CloseGeneralForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.CloseGeneralForumTopic(nil)
+ err := m.Bot.CloseGeneralForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -2067,7 +2070,7 @@ func TestBot_CloseGeneralForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.CloseGeneralForumTopic(nil)
+ err := m.Bot.CloseGeneralForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -2082,10 +2085,10 @@ func TestBot_ReopenGeneralForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.ReopenGeneralForumTopic(nil)
+ err := m.Bot.ReopenGeneralForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -2094,7 +2097,7 @@ func TestBot_ReopenGeneralForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.ReopenGeneralForumTopic(nil)
+ err := m.Bot.ReopenGeneralForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -2109,10 +2112,10 @@ func TestBot_HideGeneralForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.HideGeneralForumTopic(nil)
+ err := m.Bot.HideGeneralForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -2121,7 +2124,7 @@ func TestBot_HideGeneralForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.HideGeneralForumTopic(nil)
+ err := m.Bot.HideGeneralForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -2136,10 +2139,10 @@ func TestBot_UnhideGeneralForumTopic(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.UnhideGeneralForumTopic(nil)
+ err := m.Bot.UnhideGeneralForumTopic(testCtx, nil)
require.NoError(t, err)
})
@@ -2148,7 +2151,7 @@ func TestBot_UnhideGeneralForumTopic(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.UnhideGeneralForumTopic(nil)
+ err := m.Bot.UnhideGeneralForumTopic(testCtx, nil)
require.Error(t, err)
})
}
@@ -2163,10 +2166,10 @@ func TestBot_UnpinAllGeneralForumTopicMessages(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.UnpinAllGeneralForumTopicMessages(nil)
+ err := m.Bot.UnpinAllGeneralForumTopicMessages(testCtx, nil)
require.NoError(t, err)
})
@@ -2175,7 +2178,7 @@ func TestBot_UnpinAllGeneralForumTopicMessages(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.UnpinAllGeneralForumTopicMessages(nil)
+ err := m.Bot.UnpinAllGeneralForumTopicMessages(testCtx, nil)
require.Error(t, err)
})
}
@@ -2190,10 +2193,10 @@ func TestBot_AnswerCallbackQuery(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.AnswerCallbackQuery(nil)
+ err := m.Bot.AnswerCallbackQuery(testCtx, nil)
require.NoError(t, err)
})
@@ -2202,7 +2205,7 @@ func TestBot_AnswerCallbackQuery(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.AnswerCallbackQuery(nil)
+ err := m.Bot.AnswerCallbackQuery(testCtx, nil)
require.Error(t, err)
})
}
@@ -2219,10 +2222,10 @@ func TestBot_GetUserChatBoosts(t *testing.T) {
expectedUserChatBoosts := &UserChatBoosts{}
resp := telegoResponse(t, expectedUserChatBoosts)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- userChatBoosts, err := m.Bot.GetUserChatBoosts(nil)
+ userChatBoosts, err := m.Bot.GetUserChatBoosts(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedUserChatBoosts, userChatBoosts)
})
@@ -2232,7 +2235,7 @@ func TestBot_GetUserChatBoosts(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- userChatBoosts, err := m.Bot.GetUserChatBoosts(nil)
+ userChatBoosts, err := m.Bot.GetUserChatBoosts(testCtx, nil)
require.Error(t, err)
assert.Nil(t, userChatBoosts)
})
@@ -2250,10 +2253,10 @@ func TestBot_GetBusinessConnection(t *testing.T) {
expectedBusinessConnection := &BusinessConnection{}
resp := telegoResponse(t, expectedBusinessConnection)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- businessConnection, err := m.Bot.GetBusinessConnection(nil)
+ businessConnection, err := m.Bot.GetBusinessConnection(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedBusinessConnection, businessConnection)
})
@@ -2263,7 +2266,7 @@ func TestBot_GetBusinessConnection(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- businessConnection, err := m.Bot.GetBusinessConnection(nil)
+ businessConnection, err := m.Bot.GetBusinessConnection(testCtx, nil)
require.Error(t, err)
assert.Nil(t, businessConnection)
})
@@ -2279,10 +2282,10 @@ func TestBot_SetMyCommands(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetMyCommands(nil)
+ err := m.Bot.SetMyCommands(testCtx, nil)
require.NoError(t, err)
})
@@ -2291,7 +2294,7 @@ func TestBot_SetMyCommands(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetMyCommands(nil)
+ err := m.Bot.SetMyCommands(testCtx, nil)
require.Error(t, err)
})
}
@@ -2306,10 +2309,10 @@ func TestBot_DeleteMyCommands(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteMyCommands(nil)
+ err := m.Bot.DeleteMyCommands(testCtx, nil)
require.NoError(t, err)
})
@@ -2318,7 +2321,7 @@ func TestBot_DeleteMyCommands(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteMyCommands(nil)
+ err := m.Bot.DeleteMyCommands(testCtx, nil)
require.Error(t, err)
})
}
@@ -2338,10 +2341,10 @@ func TestBot_GetMyCommands(t *testing.T) {
}
resp := telegoResponse(t, expectedBotCommands)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- botCommands, err := m.Bot.GetMyCommands(nil)
+ botCommands, err := m.Bot.GetMyCommands(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedBotCommands, botCommands)
})
@@ -2351,7 +2354,7 @@ func TestBot_GetMyCommands(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- botCommands, err := m.Bot.GetMyCommands(nil)
+ botCommands, err := m.Bot.GetMyCommands(testCtx, nil)
require.Error(t, err)
assert.Nil(t, botCommands)
})
@@ -2367,10 +2370,10 @@ func TestBot_SetMyName(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetMyName(nil)
+ err := m.Bot.SetMyName(testCtx, nil)
require.NoError(t, err)
})
@@ -2379,7 +2382,7 @@ func TestBot_SetMyName(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetMyName(nil)
+ err := m.Bot.SetMyName(testCtx, nil)
require.Error(t, err)
})
}
@@ -2398,10 +2401,10 @@ func TestBot_GetMyName(t *testing.T) {
}
resp := telegoResponse(t, expectedBotName)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- botName, err := m.Bot.GetMyName(nil)
+ botName, err := m.Bot.GetMyName(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedBotName, botName)
})
@@ -2411,7 +2414,7 @@ func TestBot_GetMyName(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- botName, err := m.Bot.GetMyName(nil)
+ botName, err := m.Bot.GetMyName(testCtx, nil)
require.Error(t, err)
assert.Nil(t, botName)
})
@@ -2427,10 +2430,10 @@ func TestBot_SetMyDescription(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetMyDescription(nil)
+ err := m.Bot.SetMyDescription(testCtx, nil)
require.NoError(t, err)
})
@@ -2439,7 +2442,7 @@ func TestBot_SetMyDescription(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetMyDescription(nil)
+ err := m.Bot.SetMyDescription(testCtx, nil)
require.Error(t, err)
})
}
@@ -2458,10 +2461,10 @@ func TestBot_GetMyDescription(t *testing.T) {
}
resp := telegoResponse(t, expectedBotDescription)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- botDescription, err := m.Bot.GetMyDescription(nil)
+ botDescription, err := m.Bot.GetMyDescription(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedBotDescription, botDescription)
})
@@ -2471,7 +2474,7 @@ func TestBot_GetMyDescription(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- botDescription, err := m.Bot.GetMyDescription(nil)
+ botDescription, err := m.Bot.GetMyDescription(testCtx, nil)
require.Error(t, err)
assert.Nil(t, botDescription)
})
@@ -2487,10 +2490,10 @@ func TestBot_SetMyShortDescription(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetMyShortDescription(nil)
+ err := m.Bot.SetMyShortDescription(testCtx, nil)
require.NoError(t, err)
})
@@ -2499,7 +2502,7 @@ func TestBot_SetMyShortDescription(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetMyShortDescription(nil)
+ err := m.Bot.SetMyShortDescription(testCtx, nil)
require.Error(t, err)
})
}
@@ -2518,10 +2521,10 @@ func TestBot_GetMyShortDescription(t *testing.T) {
}
resp := telegoResponse(t, expectedBotShortDescription)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- botShortDescription, err := m.Bot.GetMyShortDescription(nil)
+ botShortDescription, err := m.Bot.GetMyShortDescription(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedBotShortDescription, botShortDescription)
})
@@ -2531,7 +2534,7 @@ func TestBot_GetMyShortDescription(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- botShortDescription, err := m.Bot.GetMyShortDescription(nil)
+ botShortDescription, err := m.Bot.GetMyShortDescription(testCtx, nil)
require.Error(t, err)
assert.Nil(t, botShortDescription)
})
@@ -2547,10 +2550,10 @@ func TestBot_SetChatMenuButton(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetChatMenuButton(nil)
+ err := m.Bot.SetChatMenuButton(testCtx, nil)
require.NoError(t, err)
})
@@ -2559,7 +2562,7 @@ func TestBot_SetChatMenuButton(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetChatMenuButton(nil)
+ err := m.Bot.SetChatMenuButton(testCtx, nil)
require.Error(t, err)
})
}
@@ -2578,10 +2581,10 @@ func TestBot_GetChatMenuButton(t *testing.T) {
}
resp := telegoResponse(t, expectedMenuButton)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- menuButton, err := m.Bot.GetChatMenuButton(nil)
+ menuButton, err := m.Bot.GetChatMenuButton(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMenuButton, menuButton)
})
@@ -2591,7 +2594,7 @@ func TestBot_GetChatMenuButton(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- menuButton, err := m.Bot.GetChatMenuButton(nil)
+ menuButton, err := m.Bot.GetChatMenuButton(testCtx, nil)
require.Error(t, err)
assert.Nil(t, menuButton)
})
@@ -2607,10 +2610,10 @@ func TestBot_SetMyDefaultAdministratorRights(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetMyDefaultAdministratorRights(nil)
+ err := m.Bot.SetMyDefaultAdministratorRights(testCtx, nil)
require.NoError(t, err)
})
@@ -2619,7 +2622,7 @@ func TestBot_SetMyDefaultAdministratorRights(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetMyDefaultAdministratorRights(nil)
+ err := m.Bot.SetMyDefaultAdministratorRights(testCtx, nil)
require.Error(t, err)
})
}
@@ -2638,10 +2641,10 @@ func TestBot_GetMyDefaultAdministratorRights(t *testing.T) {
}
resp := telegoResponse(t, expectedChatAdministratorRights)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- chatAdministratorRights, err := m.Bot.GetMyDefaultAdministratorRights(nil)
+ chatAdministratorRights, err := m.Bot.GetMyDefaultAdministratorRights(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedChatAdministratorRights, chatAdministratorRights)
})
@@ -2651,7 +2654,7 @@ func TestBot_GetMyDefaultAdministratorRights(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- chatAdministratorRights, err := m.Bot.GetMyDefaultAdministratorRights(nil)
+ chatAdministratorRights, err := m.Bot.GetMyDefaultAdministratorRights(testCtx, nil)
require.Error(t, err)
assert.Nil(t, chatAdministratorRights)
})
@@ -2668,10 +2671,10 @@ func TestBot_EditMessageText(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.EditMessageText(nil)
+ message, err := m.Bot.EditMessageText(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -2681,7 +2684,7 @@ func TestBot_EditMessageText(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.EditMessageText(nil)
+ message, err := m.Bot.EditMessageText(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -2698,10 +2701,10 @@ func TestBot_EditMessageCaption(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.EditMessageCaption(nil)
+ message, err := m.Bot.EditMessageCaption(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -2711,7 +2714,7 @@ func TestBot_EditMessageCaption(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.EditMessageCaption(nil)
+ message, err := m.Bot.EditMessageCaption(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -2728,10 +2731,10 @@ func TestBot_EditMessageMedia(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.EditMessageMedia(nil)
+ message, err := m.Bot.EditMessageMedia(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -2741,7 +2744,7 @@ func TestBot_EditMessageMedia(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.EditMessageMedia(nil)
+ message, err := m.Bot.EditMessageMedia(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -2758,10 +2761,10 @@ func TestBot_EditMessageLiveLocation(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.EditMessageLiveLocation(nil)
+ message, err := m.Bot.EditMessageLiveLocation(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -2771,7 +2774,7 @@ func TestBot_EditMessageLiveLocation(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.EditMessageLiveLocation(nil)
+ message, err := m.Bot.EditMessageLiveLocation(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -2788,10 +2791,10 @@ func TestBot_StopMessageLiveLocation(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.StopMessageLiveLocation(nil)
+ message, err := m.Bot.StopMessageLiveLocation(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -2801,7 +2804,7 @@ func TestBot_StopMessageLiveLocation(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.StopMessageLiveLocation(nil)
+ message, err := m.Bot.StopMessageLiveLocation(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -2818,10 +2821,10 @@ func TestBot_EditMessageReplyMarkup(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.EditMessageReplyMarkup(nil)
+ message, err := m.Bot.EditMessageReplyMarkup(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -2831,7 +2834,7 @@ func TestBot_EditMessageReplyMarkup(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.EditMessageReplyMarkup(nil)
+ message, err := m.Bot.EditMessageReplyMarkup(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -2851,10 +2854,10 @@ func TestBot_StopPoll(t *testing.T) {
}
resp := telegoResponse(t, expectedPoll)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- poll, err := m.Bot.StopPoll(nil)
+ poll, err := m.Bot.StopPoll(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedPoll, poll)
})
@@ -2864,7 +2867,7 @@ func TestBot_StopPoll(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- poll, err := m.Bot.StopPoll(nil)
+ poll, err := m.Bot.StopPoll(testCtx, nil)
require.Error(t, err)
assert.Nil(t, poll)
})
@@ -2880,10 +2883,10 @@ func TestBot_DeleteMessage(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteMessage(nil)
+ err := m.Bot.DeleteMessage(testCtx, nil)
require.NoError(t, err)
})
@@ -2892,7 +2895,7 @@ func TestBot_DeleteMessage(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteMessage(nil)
+ err := m.Bot.DeleteMessage(testCtx, nil)
require.Error(t, err)
})
}
@@ -2907,10 +2910,10 @@ func TestBot_DeleteMessages(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteMessages(nil)
+ err := m.Bot.DeleteMessages(testCtx, nil)
require.NoError(t, err)
})
@@ -2919,7 +2922,7 @@ func TestBot_DeleteMessages(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteMessages(nil)
+ err := m.Bot.DeleteMessages(testCtx, nil)
require.Error(t, err)
})
}
@@ -2935,10 +2938,10 @@ func TestBot_SendSticker(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendSticker(nil)
+ message, err := m.Bot.SendSticker(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -2948,7 +2951,7 @@ func TestBot_SendSticker(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendSticker(nil)
+ message, err := m.Bot.SendSticker(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -2968,10 +2971,10 @@ func TestBot_GetStickerSet(t *testing.T) {
}
resp := telegoResponse(t, expectedStickerSet)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- stickerSet, err := m.Bot.GetStickerSet(nil)
+ stickerSet, err := m.Bot.GetStickerSet(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedStickerSet, stickerSet)
})
@@ -2981,7 +2984,7 @@ func TestBot_GetStickerSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- stickerSet, err := m.Bot.GetStickerSet(nil)
+ stickerSet, err := m.Bot.GetStickerSet(testCtx, nil)
require.Error(t, err)
assert.Nil(t, stickerSet)
})
@@ -3001,10 +3004,10 @@ func TestBot_GetCustomEmojiStickers(t *testing.T) {
}
resp := telegoResponse(t, expectedStickers)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- stickers, err := m.Bot.GetCustomEmojiStickers(nil)
+ stickers, err := m.Bot.GetCustomEmojiStickers(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedStickers, stickers)
})
@@ -3014,7 +3017,7 @@ func TestBot_GetCustomEmojiStickers(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- stickers, err := m.Bot.GetCustomEmojiStickers(nil)
+ stickers, err := m.Bot.GetCustomEmojiStickers(testCtx, nil)
require.Error(t, err)
assert.Nil(t, stickers)
})
@@ -3034,10 +3037,10 @@ func TestBot_UploadStickerFile(t *testing.T) {
}
resp := telegoResponse(t, expectedFile)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- file, err := m.Bot.UploadStickerFile(nil)
+ file, err := m.Bot.UploadStickerFile(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedFile, file)
})
@@ -3047,7 +3050,7 @@ func TestBot_UploadStickerFile(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- file, err := m.Bot.UploadStickerFile(nil)
+ file, err := m.Bot.UploadStickerFile(testCtx, nil)
require.Error(t, err)
assert.Nil(t, file)
})
@@ -3063,10 +3066,10 @@ func TestBot_CreateNewStickerSet(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.CreateNewStickerSet(nil)
+ err := m.Bot.CreateNewStickerSet(testCtx, nil)
require.NoError(t, err)
})
@@ -3075,7 +3078,7 @@ func TestBot_CreateNewStickerSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.CreateNewStickerSet(nil)
+ err := m.Bot.CreateNewStickerSet(testCtx, nil)
require.Error(t, err)
})
}
@@ -3090,10 +3093,10 @@ func TestBot_AddStickerToSet(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.AddStickerToSet(nil)
+ err := m.Bot.AddStickerToSet(testCtx, nil)
require.NoError(t, err)
})
@@ -3102,7 +3105,7 @@ func TestBot_AddStickerToSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.AddStickerToSet(nil)
+ err := m.Bot.AddStickerToSet(testCtx, nil)
require.Error(t, err)
})
}
@@ -3117,10 +3120,10 @@ func TestBot_SetStickerPositionInSet(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetStickerPositionInSet(nil)
+ err := m.Bot.SetStickerPositionInSet(testCtx, nil)
require.NoError(t, err)
})
@@ -3129,7 +3132,7 @@ func TestBot_SetStickerPositionInSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetStickerPositionInSet(nil)
+ err := m.Bot.SetStickerPositionInSet(testCtx, nil)
require.Error(t, err)
})
}
@@ -3144,10 +3147,10 @@ func TestBot_DeleteStickerFromSet(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteStickerFromSet(nil)
+ err := m.Bot.DeleteStickerFromSet(testCtx, nil)
require.NoError(t, err)
})
@@ -3156,7 +3159,7 @@ func TestBot_DeleteStickerFromSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteStickerFromSet(nil)
+ err := m.Bot.DeleteStickerFromSet(testCtx, nil)
require.Error(t, err)
})
}
@@ -3171,10 +3174,10 @@ func TestBot_ReplaceStickerInSet(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.ReplaceStickerInSet(nil)
+ err := m.Bot.ReplaceStickerInSet(testCtx, nil)
require.NoError(t, err)
})
@@ -3183,7 +3186,7 @@ func TestBot_ReplaceStickerInSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.ReplaceStickerInSet(nil)
+ err := m.Bot.ReplaceStickerInSet(testCtx, nil)
require.Error(t, err)
})
}
@@ -3198,10 +3201,10 @@ func TestBot_SetStickerEmojiList(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetStickerEmojiList(nil)
+ err := m.Bot.SetStickerEmojiList(testCtx, nil)
require.NoError(t, err)
})
@@ -3210,7 +3213,7 @@ func TestBot_SetStickerEmojiList(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetStickerEmojiList(nil)
+ err := m.Bot.SetStickerEmojiList(testCtx, nil)
require.Error(t, err)
})
}
@@ -3225,10 +3228,10 @@ func TestBot_SetStickerKeywords(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetStickerKeywords(nil)
+ err := m.Bot.SetStickerKeywords(testCtx, nil)
require.NoError(t, err)
})
@@ -3237,7 +3240,7 @@ func TestBot_SetStickerKeywords(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetStickerKeywords(nil)
+ err := m.Bot.SetStickerKeywords(testCtx, nil)
require.Error(t, err)
})
}
@@ -3252,10 +3255,10 @@ func TestBot_SetStickerMaskPosition(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetStickerMaskPosition(nil)
+ err := m.Bot.SetStickerMaskPosition(testCtx, nil)
require.NoError(t, err)
})
@@ -3264,7 +3267,7 @@ func TestBot_SetStickerMaskPosition(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetStickerMaskPosition(nil)
+ err := m.Bot.SetStickerMaskPosition(testCtx, nil)
require.Error(t, err)
})
}
@@ -3279,10 +3282,10 @@ func TestBot_SetStickerSetTitle(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetStickerSetTitle(nil)
+ err := m.Bot.SetStickerSetTitle(testCtx, nil)
require.NoError(t, err)
})
@@ -3291,7 +3294,7 @@ func TestBot_SetStickerSetTitle(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetStickerSetTitle(nil)
+ err := m.Bot.SetStickerSetTitle(testCtx, nil)
require.Error(t, err)
})
}
@@ -3306,10 +3309,10 @@ func TestBot_SetStickerSetThumbnail(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetStickerSetThumbnail(nil)
+ err := m.Bot.SetStickerSetThumbnail(testCtx, nil)
require.NoError(t, err)
})
@@ -3318,7 +3321,7 @@ func TestBot_SetStickerSetThumbnail(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetStickerSetThumbnail(nil)
+ err := m.Bot.SetStickerSetThumbnail(testCtx, nil)
require.Error(t, err)
})
}
@@ -3333,10 +3336,10 @@ func TestBot_SetCustomEmojiStickerSetThumbnail(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetCustomEmojiStickerSetThumbnail(nil)
+ err := m.Bot.SetCustomEmojiStickerSetThumbnail(testCtx, nil)
require.NoError(t, err)
})
@@ -3345,7 +3348,7 @@ func TestBot_SetCustomEmojiStickerSetThumbnail(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetCustomEmojiStickerSetThumbnail(nil)
+ err := m.Bot.SetCustomEmojiStickerSetThumbnail(testCtx, nil)
require.Error(t, err)
})
}
@@ -3360,10 +3363,10 @@ func TestBot_DeleteStickerSet(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.DeleteStickerSet(nil)
+ err := m.Bot.DeleteStickerSet(testCtx, nil)
require.NoError(t, err)
})
@@ -3372,7 +3375,7 @@ func TestBot_DeleteStickerSet(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.DeleteStickerSet(nil)
+ err := m.Bot.DeleteStickerSet(testCtx, nil)
require.Error(t, err)
})
}
@@ -3391,10 +3394,10 @@ func TestBot_GetAvailableGifts(t *testing.T) {
}
resp := telegoResponse(t, expectedGifts)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- gifts, err := m.Bot.GetAvailableGifts()
+ gifts, err := m.Bot.GetAvailableGifts(testCtx)
require.NoError(t, err)
assert.Equal(t, expectedGifts, gifts)
})
@@ -3404,7 +3407,7 @@ func TestBot_GetAvailableGifts(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- gifts, err := m.Bot.GetAvailableGifts()
+ gifts, err := m.Bot.GetAvailableGifts(testCtx)
require.Error(t, err)
assert.Nil(t, gifts)
})
@@ -3420,10 +3423,10 @@ func TestBot_SendGift(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SendGift(nil)
+ err := m.Bot.SendGift(testCtx, nil)
require.NoError(t, err)
})
@@ -3432,7 +3435,7 @@ func TestBot_SendGift(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SendGift(nil)
+ err := m.Bot.SendGift(testCtx, nil)
require.Error(t, err)
})
}
@@ -3447,10 +3450,10 @@ func TestBot_VerifyUser(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.VerifyUser(nil)
+ err := m.Bot.VerifyUser(testCtx, nil)
require.NoError(t, err)
})
@@ -3459,7 +3462,7 @@ func TestBot_VerifyUser(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.VerifyUser(nil)
+ err := m.Bot.VerifyUser(testCtx, nil)
require.Error(t, err)
})
}
@@ -3474,10 +3477,10 @@ func TestBot_VerifyChat(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.VerifyChat(nil)
+ err := m.Bot.VerifyChat(testCtx, nil)
require.NoError(t, err)
})
@@ -3486,7 +3489,7 @@ func TestBot_VerifyChat(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.VerifyChat(nil)
+ err := m.Bot.VerifyChat(testCtx, nil)
require.Error(t, err)
})
}
@@ -3501,10 +3504,10 @@ func TestBot_RemoveUserVerification(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.RemoveUserVerification(nil)
+ err := m.Bot.RemoveUserVerification(testCtx, nil)
require.NoError(t, err)
})
@@ -3513,7 +3516,7 @@ func TestBot_RemoveUserVerification(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.RemoveUserVerification(nil)
+ err := m.Bot.RemoveUserVerification(testCtx, nil)
require.Error(t, err)
})
}
@@ -3528,10 +3531,10 @@ func TestBot_RemoveChatVerification(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.RemoveChatVerification(nil)
+ err := m.Bot.RemoveChatVerification(testCtx, nil)
require.NoError(t, err)
})
@@ -3540,7 +3543,7 @@ func TestBot_RemoveChatVerification(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.RemoveChatVerification(nil)
+ err := m.Bot.RemoveChatVerification(testCtx, nil)
require.Error(t, err)
})
}
@@ -3555,10 +3558,10 @@ func TestBot_AnswerInlineQuery(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.AnswerInlineQuery(nil)
+ err := m.Bot.AnswerInlineQuery(testCtx, nil)
require.NoError(t, err)
})
@@ -3567,7 +3570,7 @@ func TestBot_AnswerInlineQuery(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.AnswerInlineQuery(nil)
+ err := m.Bot.AnswerInlineQuery(testCtx, nil)
require.Error(t, err)
})
}
@@ -3586,10 +3589,10 @@ func TestBot_AnswerWebAppQuery(t *testing.T) {
}
resp := telegoResponse(t, expectedSentWebAppMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- sentWebAppMessage, err := m.Bot.AnswerWebAppQuery(nil)
+ sentWebAppMessage, err := m.Bot.AnswerWebAppQuery(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedSentWebAppMessage, sentWebAppMessage)
})
@@ -3599,7 +3602,7 @@ func TestBot_AnswerWebAppQuery(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- sentWebAppMessage, err := m.Bot.AnswerWebAppQuery(nil)
+ sentWebAppMessage, err := m.Bot.AnswerWebAppQuery(testCtx, nil)
require.Error(t, err)
assert.Nil(t, sentWebAppMessage)
})
@@ -3619,10 +3622,10 @@ func TestBot_SavePreparedInlineMessage(t *testing.T) {
}
resp := telegoResponse(t, expectedPreparedInlineMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- preparedInlineMessage, err := m.Bot.SavePreparedInlineMessage(nil)
+ preparedInlineMessage, err := m.Bot.SavePreparedInlineMessage(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedPreparedInlineMessage, preparedInlineMessage)
})
@@ -3632,7 +3635,7 @@ func TestBot_SavePreparedInlineMessage(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- preparedInlineMessage, err := m.Bot.SavePreparedInlineMessage(nil)
+ preparedInlineMessage, err := m.Bot.SavePreparedInlineMessage(testCtx, nil)
require.Error(t, err)
assert.Nil(t, preparedInlineMessage)
})
@@ -3649,10 +3652,10 @@ func TestBot_SendInvoice(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendInvoice(nil)
+ message, err := m.Bot.SendInvoice(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -3662,7 +3665,7 @@ func TestBot_SendInvoice(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendInvoice(nil)
+ message, err := m.Bot.SendInvoice(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -3680,10 +3683,10 @@ func TestBot_CreateInvoiceLink(t *testing.T) {
expectedInvoiceLink := "InvoiceLink"
resp := telegoResponse(t, expectedInvoiceLink)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- invoiceLink, err := m.Bot.CreateInvoiceLink(nil)
+ invoiceLink, err := m.Bot.CreateInvoiceLink(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, &expectedInvoiceLink, invoiceLink)
})
@@ -3693,7 +3696,7 @@ func TestBot_CreateInvoiceLink(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- invoiceLink, err := m.Bot.CreateInvoiceLink(nil)
+ invoiceLink, err := m.Bot.CreateInvoiceLink(testCtx, nil)
require.Error(t, err)
assert.Nil(t, invoiceLink)
})
@@ -3709,10 +3712,10 @@ func TestBot_AnswerShippingQuery(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.AnswerShippingQuery(nil)
+ err := m.Bot.AnswerShippingQuery(testCtx, nil)
require.NoError(t, err)
})
@@ -3721,7 +3724,7 @@ func TestBot_AnswerShippingQuery(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.AnswerShippingQuery(nil)
+ err := m.Bot.AnswerShippingQuery(testCtx, nil)
require.Error(t, err)
})
}
@@ -3736,10 +3739,10 @@ func TestBot_AnswerPreCheckoutQuery(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.AnswerPreCheckoutQuery(nil)
+ err := m.Bot.AnswerPreCheckoutQuery(testCtx, nil)
require.NoError(t, err)
})
@@ -3748,7 +3751,7 @@ func TestBot_AnswerPreCheckoutQuery(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.AnswerPreCheckoutQuery(nil)
+ err := m.Bot.AnswerPreCheckoutQuery(testCtx, nil)
require.Error(t, err)
})
}
@@ -3769,10 +3772,10 @@ func TestBot_GetStarTransactions(t *testing.T) {
}
resp := telegoResponse(t, expectedStarTransactions)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- starTransactions, err := m.Bot.GetStarTransactions(nil)
+ starTransactions, err := m.Bot.GetStarTransactions(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedStarTransactions, starTransactions)
})
@@ -3782,7 +3785,7 @@ func TestBot_GetStarTransactions(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- starTransactions, err := m.Bot.GetStarTransactions(nil)
+ starTransactions, err := m.Bot.GetStarTransactions(testCtx, nil)
require.Error(t, err)
assert.Nil(t, starTransactions)
})
@@ -3798,10 +3801,10 @@ func TestBot_RefundStarPayment(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.RefundStarPayment(nil)
+ err := m.Bot.RefundStarPayment(testCtx, nil)
require.NoError(t, err)
})
@@ -3810,7 +3813,7 @@ func TestBot_RefundStarPayment(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.RefundStarPayment(nil)
+ err := m.Bot.RefundStarPayment(testCtx, nil)
require.Error(t, err)
})
}
@@ -3825,10 +3828,10 @@ func TestBot_EditUserStarSubscription(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.EditUserStarSubscription(nil)
+ err := m.Bot.EditUserStarSubscription(testCtx, nil)
require.NoError(t, err)
})
@@ -3837,7 +3840,7 @@ func TestBot_EditUserStarSubscription(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.EditUserStarSubscription(nil)
+ err := m.Bot.EditUserStarSubscription(testCtx, nil)
require.Error(t, err)
})
}
@@ -3852,10 +3855,10 @@ func TestBot_SetPassportDataErrors(t *testing.T) {
Return(data, nil)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(emptyResp, nil)
- err := m.Bot.SetPassportDataErrors(nil)
+ err := m.Bot.SetPassportDataErrors(testCtx, nil)
require.NoError(t, err)
})
@@ -3864,7 +3867,7 @@ func TestBot_SetPassportDataErrors(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- err := m.Bot.SetPassportDataErrors(nil)
+ err := m.Bot.SetPassportDataErrors(testCtx, nil)
require.Error(t, err)
})
}
@@ -3880,10 +3883,10 @@ func TestBot_SendGame(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SendGame(nil)
+ message, err := m.Bot.SendGame(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -3893,7 +3896,7 @@ func TestBot_SendGame(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SendGame(nil)
+ message, err := m.Bot.SendGame(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -3910,10 +3913,10 @@ func TestBot_SetGameScore(t *testing.T) {
resp := telegoResponse(t, expectedMessage)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- message, err := m.Bot.SetGameScore(nil)
+ message, err := m.Bot.SetGameScore(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedMessage, message)
})
@@ -3923,7 +3926,7 @@ func TestBot_SetGameScore(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- message, err := m.Bot.SetGameScore(nil)
+ message, err := m.Bot.SetGameScore(testCtx, nil)
require.Error(t, err)
assert.Nil(t, message)
})
@@ -3944,10 +3947,10 @@ func TestBot_GetGameHighScores(t *testing.T) {
}
resp := telegoResponse(t, expectedGameHighScores)
m.MockAPICaller.EXPECT().
- Call(gomock.Any(), gomock.Any()).
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
Return(resp, nil)
- gameHighScores, err := m.Bot.GetGameHighScores(nil)
+ gameHighScores, err := m.Bot.GetGameHighScores(testCtx, nil)
require.NoError(t, err)
assert.Equal(t, expectedGameHighScores, gameHighScores)
})
@@ -3957,7 +3960,7 @@ func TestBot_GetGameHighScores(t *testing.T) {
JSONRequest(gomock.Any()).
Return(nil, errTest)
- gameHighScores, err := m.Bot.GetGameHighScores(nil)
+ gameHighScores, err := m.Bot.GetGameHighScores(testCtx, nil)
require.Error(t, err)
assert.Nil(t, gameHighScores)
})
@@ -4156,10 +4159,12 @@ func TestSetStickerSetThumbnailParams_fileParameters(t *testing.T) {
func TestMethodsConstants(t *testing.T) {
tests := [][]string{
{
- MessageUpdates, EditedMessageUpdates, ChannelPostUpdates, EditedChannelPostUpdates, MessageReaction,
- MessageReactionCount, InlineQueryUpdates, ChosenInlineResultUpdates, CallbackQueryUpdates,
- ShippingQueryUpdates, PreCheckoutQueryUpdates, PollUpdates, PollAnswerUpdates, MyChatMemberUpdates,
- ChatMemberUpdates, ChatJoinRequestUpdates,
+ MessageUpdates, EditedMessageUpdates, ChannelPostUpdates, EditedChannelPostUpdates,
+ BusinessConnectionUpdates, BusinessMessageUpdates, EditedBusinessMessageUpdates,
+ DeletedBusinessMessagesUpdates, MessageReactionUpdates, MessageReactionCountUpdates, InlineQueryUpdates,
+ ChosenInlineResultUpdates, CallbackQueryUpdates, ShippingQueryUpdates, PreCheckoutQueryUpdates,
+ PurchasedPaidMediaUpdates, PollUpdates, PollAnswerUpdates, MyChatMemberUpdates,
+ ChatMemberUpdates, ChatJoinRequestUpdates, ChatBoostUpdates, RemovedChatBoostUpdates,
},
{
ModeHTML, ModeMarkdown, ModeMarkdownV2,
diff --git a/telegoapi/api.go b/telegoapi/api.go
index e8453219..ef63b242 100644
--- a/telegoapi/api.go
+++ b/telegoapi/api.go
@@ -2,6 +2,7 @@ package telegoapi
import (
"bytes"
+ "context"
"fmt"
"io"
@@ -67,16 +68,16 @@ type RequestData struct {
// Caller represents way to call API with request
type Caller interface {
- Call(url string, data *RequestData) (*Response, error)
+ Call(ctx context.Context, url string, data *RequestData) (*Response, error)
}
// NamedReader represents a way to send files (or other data).
-// Implemented by os.File.
+// Implemented by [os.File].
// Note: Name method may be called multiple times and should return unique names for all files sent in one request.
//
// Warning: Since, for sending data (files) reader data will be copied, using the same reader multiple times as is
// will not work.
-// For os.File you can use file.Seek(0, io.SeekStart) to prepare for a new request.
+// For [os.File] you can use os.File.Seek(0, io.SeekStart) to prepare for a new request.
type NamedReader interface {
io.Reader
Name() string
diff --git a/telegoapi/caller.go b/telegoapi/caller.go
index c10e029e..4d263d00 100644
--- a/telegoapi/caller.go
+++ b/telegoapi/caller.go
@@ -3,6 +3,7 @@
package telegoapi
import (
+ "context"
"errors"
"fmt"
"io"
@@ -15,18 +16,25 @@ import (
"github.com/mymmrac/telego/internal/json"
)
-// FastHTTPCaller fasthttp implementation of Caller
+// FastHTTPCaller fasthttp implementation of [Caller]
type FastHTTPCaller struct {
Client *fasthttp.Client
}
-// DefaultFastHTTPCaller is a default fast http caller
+// DefaultFastHTTPCaller is a default fasthttp caller
var DefaultFastHTTPCaller = &FastHTTPCaller{
Client: &fasthttp.Client{},
}
// Call is a fasthttp implementation
-func (a FastHTTPCaller) Call(url string, data *RequestData) (*Response, error) {
+func (a FastHTTPCaller) Call(ctx context.Context, url string, data *RequestData) (*Response, error) {
+ select {
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ default:
+ // Continue
+ }
+
req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)
@@ -38,7 +46,13 @@ func (a FastHTTPCaller) Call(url string, data *RequestData) (*Response, error) {
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)
- err := a.Client.Do(req, resp)
+ var err error
+ deadline, ok := ctx.Deadline()
+ if ok {
+ err = a.Client.DoDeadline(req, resp, deadline)
+ } else {
+ err = a.Client.Do(req, resp)
+ }
if err != nil {
return nil, fmt.Errorf("fasthttp do request: %w", err)
}
@@ -56,7 +70,7 @@ func (a FastHTTPCaller) Call(url string, data *RequestData) (*Response, error) {
return apiResp, nil
}
-// HTTPCaller http implementation of Caller
+// HTTPCaller http implementation of [Caller]
type HTTPCaller struct {
Client *http.Client
}
@@ -67,8 +81,8 @@ var DefaultHTTPCaller = &HTTPCaller{
}
// Call is a http implementation
-func (h HTTPCaller) Call(url string, data *RequestData) (*Response, error) {
- req, err := http.NewRequest(http.MethodPost, url, data.Buffer)
+func (h HTTPCaller) Call(ctx context.Context, url string, data *RequestData) (*Response, error) {
+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, data.Buffer)
if err != nil {
return nil, fmt.Errorf("http create request: %w", err)
}
@@ -98,7 +112,7 @@ func (h HTTPCaller) Call(url string, data *RequestData) (*Response, error) {
return apiResp, nil
}
-// RetryCaller decorator over Caller that provides reties with exponential backoff
+// RetryCaller decorator over [Caller] that provides retries with exponential backoff
// Delay = (ExponentBase ^ AttemptNumber) * StartDelay or MaxDelay
type RetryCaller struct {
Caller Caller
@@ -112,9 +126,9 @@ type RetryCaller struct {
var ErrMaxRetryAttempts = errors.New("max retry attempts reached")
// Call makes calls using provided caller with retries
-func (r *RetryCaller) Call(url string, data *RequestData) (resp *Response, err error) {
+func (r *RetryCaller) Call(ctx context.Context, url string, data *RequestData) (resp *Response, err error) {
for i := 0; i < r.MaxAttempts; i++ {
- resp, err = r.Caller.Call(url, data)
+ resp, err = r.Caller.Call(ctx, url, data)
if err == nil {
return resp, nil
}
diff --git a/telegoapi/caller_test.go b/telegoapi/caller_test.go
index 700bf69a..745c81d9 100644
--- a/telegoapi/caller_test.go
+++ b/telegoapi/caller_test.go
@@ -2,6 +2,7 @@ package telegoapi
import (
"bytes"
+ "context"
"errors"
"net"
"net/http"
@@ -56,26 +57,28 @@ func TestFastHTTPCaller_Call(t *testing.T) {
Buffer: bytes.NewBufferString("test"),
}
+ ctx := context.Background()
+
t.Run("success", func(t *testing.T) {
- resp, err := caller.Call("http://localhost", data)
+ resp, err := caller.Call(ctx, "http://localhost", data)
require.NoError(t, err)
assert.True(t, resp.Ok)
})
t.Run("error_fasthttp_do_request", func(t *testing.T) {
- resp, err := caller.Call("abc", data)
+ resp, err := caller.Call(ctx, "abc", data)
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("error_500", func(t *testing.T) {
- resp, err := caller.Call("http://localhost/500", data)
+ resp, err := caller.Call(ctx, "http://localhost/500", data)
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("error_json", func(t *testing.T) {
- resp, err := caller.Call("http://localhost/json_err", data)
+ resp, err := caller.Call(ctx, "http://localhost/json_err", data)
require.Error(t, err)
assert.Nil(t, resp)
})
@@ -120,32 +123,34 @@ func TestHTTPCaller_Call(t *testing.T) {
Buffer: bytes.NewBufferString("test"),
}
+ ctx := context.Background()
+
t.Run("success", func(t *testing.T) {
- resp, err := caller.Call(srv.URL, data)
+ resp, err := caller.Call(ctx, srv.URL, data)
require.NoError(t, err)
assert.True(t, resp.Ok)
})
t.Run("error_http_create_request", func(t *testing.T) {
- resp, err := caller.Call("\x00", data)
+ resp, err := caller.Call(ctx, "\x00", data)
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("error_http_do_request", func(t *testing.T) {
- resp, err := caller.Call("abc", data)
+ resp, err := caller.Call(ctx, "abc", data)
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("error_500", func(t *testing.T) {
- resp, err := caller.Call(srv.URL+err500Path, data)
+ resp, err := caller.Call(ctx, srv.URL+err500Path, data)
require.Error(t, err)
assert.Nil(t, resp)
})
t.Run("error_json", func(t *testing.T) {
- resp, err := caller.Call(srv.URL+errJSONPath, data)
+ resp, err := caller.Call(ctx, srv.URL+errJSONPath, data)
require.Error(t, err)
assert.Nil(t, resp)
})
@@ -180,7 +185,7 @@ type testRetryCaller struct {
okAfter int
}
-func (t *testRetryCaller) Call(_ string, _ *RequestData) (*Response, error) {
+func (t *testRetryCaller) Call(_ context.Context, _ string, _ *RequestData) (*Response, error) {
t.attempts++
if t.okAfter != 0 && t.attempts > t.okAfter {
return t.resp, nil
@@ -189,6 +194,7 @@ func (t *testRetryCaller) Call(_ string, _ *RequestData) (*Response, error) {
}
func TestRetryCaller_Call(t *testing.T) {
+ ctx := context.Background()
expectedResp := &Response{Ok: true}
t.Run("success", func(t *testing.T) {
@@ -199,7 +205,7 @@ func TestRetryCaller_Call(t *testing.T) {
},
MaxAttempts: 1,
}
- resp, err := retryCaller.Call("", nil)
+ resp, err := retryCaller.Call(ctx, "", nil)
require.NoError(t, err)
assert.Equal(t, expectedResp, resp)
})
@@ -213,7 +219,7 @@ func TestRetryCaller_Call(t *testing.T) {
},
MaxAttempts: 3,
}
- resp, err := retryCaller.Call("", nil)
+ resp, err := retryCaller.Call(ctx, "", nil)
require.NoError(t, err)
assert.Equal(t, expectedResp, resp)
})
@@ -226,7 +232,7 @@ func TestRetryCaller_Call(t *testing.T) {
},
MaxAttempts: 2,
}
- resp, err := retryCaller.Call("", nil)
+ resp, err := retryCaller.Call(ctx, "", nil)
require.Error(t, err)
assert.Nil(t, resp)
})
@@ -242,7 +248,7 @@ func TestRetryCaller_Call(t *testing.T) {
StartDelay: 10,
MaxDelay: 1,
}
- resp, err := retryCaller.Call("", nil)
+ resp, err := retryCaller.Call(ctx, "", nil)
require.Error(t, err)
assert.Nil(t, resp)
})
diff --git a/telegoapi/doc.go b/telegoapi/doc.go
index dd580646..9750f109 100644
--- a/telegoapi/doc.go
+++ b/telegoapi/doc.go
@@ -1,20 +1,22 @@
/*
-Package telegoapi provides API for calling Telegram for Telego.
+Package telegoapi provides an API for calling Telegram for Telego.
This API package describes the main part of communication with Telegram Bot API.
-The response represents the API response from Telegram with respectful result and error values.
+The [Response] represents the API response from Telegram with respectful result and error values.
-Caller interface represents the general logic of sending requests to API and receiving responses from it. Currently,
-Telego provides valyala/fasthttp and net/http implementation, but your own can be defined and specified
-via telego.BotOption's.
+[Caller] interface represents the general logic of sending requests to API and receiving responses from it.
+Currently, Telego provides valyala/fasthttp and net/http implementation, but your own can be defined and specified
+via bot options.
-RequestConstructor interface represents a general way of constructing RequestData used in Caller. Currently, Telego
-provides an only default implementation that uses goccy/go-json instead of encoding/json and std mime/multipart
-package.
+[RequestConstructor] interface represents a general way of constructing [RequestData] used in [Caller].
+Currently, Telego provides only default implementation that uses goccy/go-json instead of encoding/json and std
+mime/multipart package.
-NamedReader interface represents a general way of sending files that are provided to RequestConstructor. As io.Reader
-can be provided, any valid reader and name method should return a unique name for every file in one request, otherwise
-not all files will be sent properly.
+[NamedReader] interface represents a general way of sending files that are provided to [RequestConstructor].
+As [io.Reader] can be provided, any valid reader and name method should return a unique name for every file in one
+request otherwise not all files will be sent properly.
+Note: Keep in mind that Telego doesn't reset reader, if you want to reuse the same reader, you must reset it
+manually before sending a new request.
*/
package telegoapi
diff --git a/telegoapi/mock/caller.go b/telegoapi/mock/caller.go
index fc907132..8575d65d 100644
--- a/telegoapi/mock/caller.go
+++ b/telegoapi/mock/caller.go
@@ -10,6 +10,7 @@
package mock
import (
+ context "context"
reflect "reflect"
telegoapi "github.com/mymmrac/telego/telegoapi"
@@ -41,18 +42,18 @@ func (m *MockCaller) EXPECT() *MockCallerMockRecorder {
}
// Call mocks base method.
-func (m *MockCaller) Call(url string, data *telegoapi.RequestData) (*telegoapi.Response, error) {
+func (m *MockCaller) Call(ctx context.Context, url string, data *telegoapi.RequestData) (*telegoapi.Response, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Call", url, data)
+ ret := m.ctrl.Call(m, "Call", ctx, url, data)
ret0, _ := ret[0].(*telegoapi.Response)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Call indicates an expected call of Call.
-func (mr *MockCallerMockRecorder) Call(url, data any) *MockCallerCallCall {
+func (mr *MockCallerMockRecorder) Call(ctx, url, data any) *MockCallerCallCall {
mr.mock.ctrl.T.Helper()
- call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockCaller)(nil).Call), url, data)
+ call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockCaller)(nil).Call), ctx, url, data)
return &MockCallerCallCall{Call: call}
}
@@ -68,13 +69,13 @@ func (c *MockCallerCallCall) Return(arg0 *telegoapi.Response, arg1 error) *MockC
}
// Do rewrite *gomock.Call.Do
-func (c *MockCallerCallCall) Do(f func(string, *telegoapi.RequestData) (*telegoapi.Response, error)) *MockCallerCallCall {
+func (c *MockCallerCallCall) Do(f func(context.Context, string, *telegoapi.RequestData) (*telegoapi.Response, error)) *MockCallerCallCall {
c.Call = c.Call.Do(f)
return c
}
// DoAndReturn rewrite *gomock.Call.DoAndReturn
-func (c *MockCallerCallCall) DoAndReturn(f func(string, *telegoapi.RequestData) (*telegoapi.Response, error)) *MockCallerCallCall {
+func (c *MockCallerCallCall) DoAndReturn(f func(context.Context, string, *telegoapi.RequestData) (*telegoapi.Response, error)) *MockCallerCallCall {
c.Call = c.Call.DoAndReturn(f)
return c
}
diff --git a/telegoapi/request_constructor.go b/telegoapi/request_constructor.go
index 0a324ecb..8f674267 100644
--- a/telegoapi/request_constructor.go
+++ b/telegoapi/request_constructor.go
@@ -12,7 +12,7 @@ import (
"github.com/mymmrac/telego/internal/json"
)
-// DefaultConstructor default implementation of RequestConstructor
+// DefaultConstructor default implementation of [RequestConstructor]
type DefaultConstructor struct{}
// JSONRequest is default implementation
@@ -67,14 +67,15 @@ func (d DefaultConstructor) MultipartRequest(parameters map[string]string, files
return data, nil
}
-func isNil(i any) bool {
- if i == nil {
+// isNil checks if the value, or it's underlying interface is nil
+func isNil(v any) bool {
+ if v == nil {
return true
}
- switch reflect.TypeOf(i).Kind() {
- case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
- return reflect.ValueOf(i).IsNil()
+ switch reflect.TypeOf(v).Kind() {
+ case reflect.Interface, reflect.Ptr, reflect.Slice, reflect.Map, reflect.Chan, reflect.Func:
+ return reflect.ValueOf(v).IsNil()
default:
return false
}
diff --git a/telegohandler/bot_handler.go b/telegohandler/bot_handler.go
index 77df4911..d1936f61 100644
--- a/telegohandler/bot_handler.go
+++ b/telegohandler/bot_handler.go
@@ -2,6 +2,7 @@ package telegohandler
import (
"context"
+ "errors"
"fmt"
"sync"
@@ -9,19 +10,11 @@ import (
)
// Handler handles update that came from bot
-type Handler func(bot *telego.Bot, update telego.Update)
+type Handler func(ctx *Context, update telego.Update) error
// Predicate allows filtering updates for handlers
// Note: Predicate can't change the update, because it uses a copy, not original value
-type Predicate func(update telego.Update) bool
-
-// Middleware applies any function on bot and update before calling other middlewares, predicates and handler
-// Note: Calling next multiple times does nothing after first call, calling next in goroutine is allowed,
-// but user should expect that context will be closed sooner than handler ends
-//
-// Warning: Not calling next at all is allowed, but if context doesn't close, update will be stuck forever, however
-// if context closes since not all middlewares were executed, the handler group will be skipped
-type Middleware func(bot *telego.Bot, update telego.Update, next Handler)
+type Predicate func(ctx context.Context, update telego.Update) bool
// BotHandler represents a bot handler that can handle updated matching by predicates
type BotHandler struct {
@@ -29,65 +22,75 @@ type BotHandler struct {
updates <-chan telego.Update
baseGroup *HandlerGroup
- running bool
- runningLock sync.RWMutex
- stop chan struct{}
- handledUpdates *sync.WaitGroup
+ running bool
+ lock sync.RWMutex
+ stop chan struct{}
+ handlers sync.WaitGroup
}
// BotHandlerOption represents an option that can be applied to bot handler
type BotHandlerOption func(bh *BotHandler) error
// NewBotHandler creates new bot handler
+// Note: Currently no options available, they may be added in future
func NewBotHandler(bot *telego.Bot, updates <-chan telego.Update, options ...BotHandlerOption) (*BotHandler, error) {
bh := &BotHandler{
- bot: bot,
- updates: updates,
- baseGroup: &HandlerGroup{},
- handledUpdates: &sync.WaitGroup{},
+ bot: bot,
+ updates: updates,
+ baseGroup: &HandlerGroup{},
}
for _, option := range options {
if err := option(bh); err != nil {
- return nil, fmt.Errorf("telego: options: %w", err)
+ return nil, fmt.Errorf("telego: bot handler options: %w", err)
}
}
return bh, nil
}
-// Start starts handling of updates, blocks execution
-// Note: Calling [BotHandler.Start] method multiple times after the first one does nothing.
-func (h *BotHandler) Start() {
- h.runningLock.RLock()
+// Start starts handling of updates, blocks execution, caller is responsible for handling all unhandled updates in the
+// update channel after bot handler stop (start will return an error in this case)
+// Note: Calling if already running will return an error
+func (h *BotHandler) Start() error {
+ h.lock.Lock()
+
if h.running {
- h.runningLock.RUnlock()
- return
+ h.lock.Unlock()
+ return errors.New("telego: bot handler already running")
}
- h.runningLock.RUnlock()
- h.runningLock.Lock()
- h.stop = make(chan struct{})
h.running = true
+ h.stop = make(chan struct{})
+
// Prevents calling Wait before single Add call
- h.handledUpdates.Add(1)
- defer h.handledUpdates.Done()
- h.runningLock.Unlock()
+ h.handlers.Add(1)
+ defer h.handlers.Done()
+
+ h.lock.Unlock()
+
+ depth := h.baseGroup.depth(1)
for {
select {
case <-h.stop:
- return
+ if unhandled := len(h.updates); unhandled > 0 {
+ return fmt.Errorf("telego: bot handler stopped, %d update(s) left unhandled", unhandled)
+ }
+ return nil
case update, ok := <-h.updates:
if !ok {
- go h.Stop()
- return
+ return nil
}
// Process update
- h.handledUpdates.Add(1)
+ h.handlers.Add(1)
go func() {
- ctx, cancel := context.WithCancel(update.Context())
+ defer h.handlers.Done()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
go func() {
select {
case <-ctx.Done():
@@ -97,10 +100,19 @@ func (h *BotHandler) Start() {
}
}()
- h.baseGroup.processUpdate(h.bot, update.WithContext(ctx))
- cancel()
-
- h.handledUpdates.Done()
+ bCtx := &Context{
+ ctx: ctx,
+ ctxBase: &ctxBase{
+ bot: h.bot,
+ updateID: update.UpdateID,
+ group: h.baseGroup,
+ stack: append(make([]int, 0, depth), -1),
+ },
+ }
+
+ if err := bCtx.Next(update); err != nil {
+ h.bot.Logger().Errorf("Error processing update %d, err: %s", update.UpdateID, err)
+ }
}()
}
}
@@ -108,84 +120,85 @@ func (h *BotHandler) Start() {
// IsRunning tells if Start is running
func (h *BotHandler) IsRunning() bool {
- h.runningLock.RLock()
- defer h.runningLock.RUnlock()
-
+ h.lock.RLock()
+ defer h.lock.RUnlock()
return h.running
}
-// StopWithContext stops handling of updates, blocks until all updates have been processes or when context is canceled.
-// Note: Calling [BotHandler.StopWithContext] method multiple times or before [BotHandler.Start] does nothing.
-func (h *BotHandler) StopWithContext(ctx context.Context) {
- h.runningLock.Lock()
- defer h.runningLock.Unlock()
+// StopWithContext stops handling of updates, blocks until all updates have been processes (only if update was received
+// from the update channel) or when context is canceled, if not all updates were received from the update channel
+// [BotHandler.Start] will return an error, if context is canceled context error will be returned
+// Note: Calling [BotHandler.StopWithContext] method multiple times or before [BotHandler.Start] does nothing
+func (h *BotHandler) StopWithContext(ctx context.Context) error {
+ h.lock.Lock()
+ defer h.lock.Unlock()
+
if !h.running {
- return
+ return nil
}
close(h.stop)
+ h.running = false
select {
case <-ctx.Done():
- h.running = false
- return
+ return ctx.Err()
default:
// Continue
}
wait := make(chan struct{})
go func() {
- h.handledUpdates.Wait()
+ h.handlers.Wait()
close(wait)
}()
select {
case <-ctx.Done():
// Wait for context to be done
+ return ctx.Err()
case <-wait:
- // Wait for handler to complete
+ // Wait for handlers to complete
+ return nil
}
-
- h.running = false
}
// Stop stops handling of updates, will block until all updates have been processes.
// It's recommended to use [BotHandler.StopWithContext] if you want to force stop after some timeout.
-func (h *BotHandler) Stop() {
- h.StopWithContext(context.Background())
+func (h *BotHandler) Stop() error {
+ return h.StopWithContext(context.Background())
}
-// Handle registers new handler in the base group, update will be processed only by first-matched handler,
-// order of registration determines the order of matching handlers.
-// Important to notice, update's context will be automatically canceled once the handler will finish processing or
+// Handle registers new handler in the base group, update will be processed only by first-matched route,
+// order of registration determines the order of matching routes.
+// Important to notice handler's context will be automatically canceled once the handler will finish processing or
// the bot handler stopped.
// Note: All handlers will process updates in parallel, there is no guaranty on order of processed updates, also keep
-// in mind that middlewares and predicates are checked sequentially.
+// in mind that middlewares and predicates are run sequentially.
//
// Warning: Panics if nil handler or predicates passed
func (h *BotHandler) Handle(handler Handler, predicates ...Predicate) {
h.baseGroup.Handle(handler, predicates...)
}
-// Group creates a new group of handlers and middlewares from the base group
-// Note: Updates first checked by group and only after that by handler
+// Group creates a new group of handlers and middlewares from the base group, update will be processed only by
+// first-matched route, order of registration determines the order of matching routes
//
// Warning: Panics if nil predicates passed
func (h *BotHandler) Group(predicates ...Predicate) *HandlerGroup {
return h.baseGroup.Group(predicates...)
}
-// Use applies middleware to the base group
-// Note: The chain will be stopped if middleware doesn't call the next func,
-// if there is no context timeout then update will be stuck,
-// if there is time out then the group will be skipped since not all middlewares were called
+// Use applies middleware to the base group, update will be processed only by first-matched route,
+// order of registration determines the order of matching routes.
+// Note: The chain will be stopped if middleware doesn't call the [Context.Next]
//
// Warning: Panics if nil middlewares passed
-func (h *BotHandler) Use(middlewares ...Middleware) {
+func (h *BotHandler) Use(middlewares ...Handler) {
h.baseGroup.Use(middlewares...)
}
-// BaseGroup returns a base group that is used by default in [BotHandler] methods
+// BaseGroup returns a base group used by default in [BotHandler] methods
func (h *BotHandler) BaseGroup() *HandlerGroup {
return h.baseGroup
}
diff --git a/telegohandler/bot_handler_options.go b/telegohandler/bot_handler_options.go
index 4fb78ecc..d48648d7 100644
--- a/telegohandler/bot_handler_options.go
+++ b/telegohandler/bot_handler_options.go
@@ -1,3 +1,3 @@
package telegohandler
-// No options yet
+// No bot handler options yet
diff --git a/telegohandler/bot_handler_test.go b/telegohandler/bot_handler_test.go
index 9fed86d6..68c394be 100644
--- a/telegohandler/bot_handler_test.go
+++ b/telegohandler/bot_handler_test.go
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"sync"
+ "sync/atomic"
"testing"
"time"
@@ -85,16 +86,18 @@ func TestBotHandler_Start(t *testing.T) {
h1 := 0
h2 := 0
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(_ *Context, _ telego.Update) error {
defer wg.Done()
h1++
- }, func(update telego.Update) bool {
+ return nil
+ }, func(ctx context.Context, update telego.Update) bool {
return update.UpdateID == 1
})
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(_ *Context, _ telego.Update) error {
defer wg.Done()
h2++
+ return nil
})
timeoutSignal := time.After(timeout * 10)
@@ -103,13 +106,19 @@ func TestBotHandler_Start(t *testing.T) {
assert.NotPanics(t, func() {
wg.Add(2)
- go bh.Start()
+ go func() {
+ errStart := bh.Start()
+ assert.NoError(t, errStart)
+ }()
- // Check if multiple Start calls do nothing
time.Sleep(smallTimeout)
- bh.Start()
+ err = bh.Start()
+ assert.Error(t, err)
- defer bh.Stop()
+ defer func() {
+ err = bh.Stop()
+ assert.NoError(t, err)
+ }()
updates <- telego.Update{}
updates <- telego.Update{UpdateID: 1}
@@ -129,14 +138,14 @@ func TestBotHandler_Start(t *testing.T) {
})
}
-//revive:disable:cognitive-complexity
-//nolint:gocognit
+//nolint:gocognit,gocyclo
func TestBotHandler_Stop(t *testing.T) {
t.Run("basic", func(t *testing.T) {
bh := newTestBotHandler(t)
bh.stop = make(chan struct{})
assert.NotPanics(t, func() {
- bh.Stop()
+ err := bh.Stop()
+ assert.NoError(t, err)
})
})
@@ -149,25 +158,31 @@ func TestBotHandler_Stop(t *testing.T) {
bh, err := NewBotHandler(bot, updates)
require.NoError(t, err)
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(_ *Context, _ telego.Update) error {
time.Sleep(hugeTimeout)
t.Fatal("timeout didn't work")
+ return nil
})
timeoutSignal := time.After(timeout)
done := make(chan struct{})
assert.NotPanics(t, func() {
- go bh.Start()
+ go func() {
+ errStart := bh.Start()
+ assert.NoError(t, errStart)
+ }()
for !bh.IsRunning() {
// Wait for handler to start
}
updates <- telego.Update{}
+ time.Sleep(smallTimeout)
ctx, cancel := context.WithTimeout(context.Background(), smallTimeout)
go func() {
- bh.StopWithContext(ctx)
+ errStop := bh.StopWithContext(ctx)
+ assert.ErrorIs(t, errStop, context.DeadlineExceeded)
done <- struct{}{}
cancel()
}()
@@ -184,27 +199,48 @@ func TestBotHandler_Stop(t *testing.T) {
bot, err := telego.NewBot(token)
require.NoError(t, err)
- updates := make(chan telego.Update)
+ updates := make(chan telego.Update, 2)
bh, err := NewBotHandler(bot, updates)
require.NoError(t, err)
- bh.Handle(func(bot *telego.Bot, update telego.Update) {})
+ called1 := atomic.Int32{}
+ bh.Handle(
+ func(_ *Context, _ telego.Update) error {
+ called1.Add(1)
+ return nil
+ },
+ func(_ context.Context, update telego.Update) bool { return update.UpdateID == 0 },
+ )
+
+ called2 := atomic.Int32{}
+ bh.Handle(
+ func(_ *Context, _ telego.Update) error {
+ called2.Add(1)
+ return errTest
+ },
+ )
timeoutSignal := time.After(timeout)
done := make(chan struct{})
assert.NotPanics(t, func() {
- go bh.Start()
+ go func() {
+ errStart := bh.Start()
+ assert.NoError(t, errStart)
+ }()
for !bh.IsRunning() {
// Wait for handler to start
}
updates <- telego.Update{}
+ updates <- telego.Update{UpdateID: 1}
+ time.Sleep(smallTimeout)
ctx, cancel := context.WithTimeout(context.Background(), hugeTimeout)
go func() {
- bh.StopWithContext(ctx)
+ errStop := bh.StopWithContext(ctx)
+ assert.NoError(t, errStop)
done <- struct{}{}
cancel()
}()
@@ -214,7 +250,48 @@ func TestBotHandler_Stop(t *testing.T) {
t.Fatal("Timeout")
case <-done:
}
+
+ assert.Equal(t, int32(1), called1.Load())
+ assert.Equal(t, int32(1), called2.Load())
+ })
+ })
+
+ t.Run("with_unhandled_updates_error", func(t *testing.T) {
+ bot, err := telego.NewBot(token)
+ require.NoError(t, err)
+
+ updates := make(chan telego.Update, 1000)
+ for range cap(updates) - 1 {
+ updates <- telego.Update{}
+ }
+
+ bh, err := NewBotHandler(bot, updates)
+ require.NoError(t, err)
+
+ done := make(chan struct{})
+ assert.NotPanics(t, func() {
+ go func() {
+ startErr := bh.Start()
+ if len(updates) == 0 {
+ assert.NoError(t, startErr)
+ } else {
+ assert.Error(t, startErr)
+ }
+ done <- struct{}{}
+ }()
+ for !bh.IsRunning() {
+ // Wait for handler to start
+ }
+
+ err = bh.StopWithContext(context.Background())
+ assert.NoError(t, err)
})
+
+ select {
+ case <-done:
+ case <-time.After(timeout):
+ t.Fatal("Timeout")
+ }
})
t.Run("with_canceled", func(t *testing.T) {
@@ -226,16 +303,20 @@ func TestBotHandler_Stop(t *testing.T) {
bh, err := NewBotHandler(bot, updates)
require.NoError(t, err)
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(_ *Context, _ telego.Update) error {
time.Sleep(hugeTimeout)
t.Fatal("timeout didn't work")
+ return nil
})
timeoutSignal := time.After(timeout)
done := make(chan struct{})
assert.NotPanics(t, func() {
- go bh.Start()
+ go func() {
+ errStart := bh.Start()
+ assert.NoError(t, errStart)
+ }()
for !bh.IsRunning() {
// Wait for handler to start
}
@@ -245,7 +326,8 @@ func TestBotHandler_Stop(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
go func() {
- bh.StopWithContext(ctx)
+ errStop := bh.StopWithContext(ctx)
+ assert.ErrorIs(t, errStop, context.Canceled)
done <- struct{}{}
}()
@@ -266,17 +348,22 @@ func TestBotHandler_Stop(t *testing.T) {
bh, err := NewBotHandler(bot, updates)
require.NoError(t, err)
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(_ *Context, _ telego.Update) error {
t.Fatal("handled after stop")
+ return nil
})
assert.NotPanics(t, func() {
- go bh.Start()
+ go func() {
+ errStart := bh.Start()
+ assert.NoError(t, errStart)
+ }()
for !bh.IsRunning() {
// Wait for handler to start
}
- bh.Stop()
+ err = bh.Stop()
+ assert.NoError(t, err)
updates <- telego.Update{}
})
@@ -291,62 +378,63 @@ func TestBotHandler_Stop(t *testing.T) {
bh, err := NewBotHandler(bot, updates)
require.NoError(t, err)
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(_ *Context, _ telego.Update) error {
t.Fatal("handled after stop")
+ return nil
})
assert.NotPanics(t, func() {
- go bh.Start()
+ go func() {
+ errStart := bh.Start()
+ assert.NoError(t, errStart)
+ }()
for !bh.IsRunning() {
// Wait for handler to start
}
-
close(updates)
})
time.Sleep(smallTimeout)
- assert.False(t, bh.IsRunning())
+ assert.True(t, bh.IsRunning())
})
}
func TestBotHandler_Handle(t *testing.T) {
bh := newTestBotHandler(t)
- handler := Handler(func(bot *telego.Bot, update telego.Update) {})
- predicate := Predicate(func(update telego.Update) bool { return false })
+ handler := Handler(func(_ *Context, _ telego.Update) error { return nil })
+ predicate := Predicate(func(_ context.Context, _ telego.Update) bool { return false })
bh.Handle(handler, predicate)
- require.Len(t, bh.baseGroup.handlers, 1)
- assert.NotNil(t, bh.baseGroup.handlers[0].handler)
- assert.NotNil(t, bh.baseGroup.handlers[0].predicates)
-
- bh.baseGroup.handlers = make([]conditionalHandler, 0)
+ require.Len(t, bh.baseGroup.routes, 1)
+ assert.NotNil(t, bh.baseGroup.routes[0].handler)
+ assert.NotEmpty(t, bh.baseGroup.routes[0].predicates)
}
func TestBotHandler_Group(t *testing.T) {
bh := newTestBotHandler(t)
- predicate := Predicate(func(update telego.Update) bool { return false })
+ predicate := Predicate(func(_ context.Context, _ telego.Update) bool { return false })
newGr := bh.Group(predicate)
- require.Len(t, bh.baseGroup.groups, 1)
- assert.Equal(t, newGr, bh.baseGroup.groups[0])
- assert.NotEmpty(t, bh.baseGroup.groups[0].predicates)
+ require.Len(t, bh.baseGroup.routes, 1)
+ assert.Equal(t, newGr, bh.baseGroup.routes[0].group)
+ assert.NotEmpty(t, bh.baseGroup.routes[0].predicates)
}
func TestBotHandler_Use(t *testing.T) {
bh := newTestBotHandler(t)
- middleware := Middleware(func(bot *telego.Bot, update telego.Update, next Handler) {
- next(bot, update)
+ middleware := Handler(func(ctx *Context, update telego.Update) error {
+ return ctx.Next(update)
})
bh.Use(middleware)
- require.Len(t, bh.baseGroup.middlewares, 1)
- assert.NotNil(t, bh.baseGroup.middlewares[0])
+ require.Len(t, bh.baseGroup.routes, 1)
+ assert.NotNil(t, bh.baseGroup.routes[0].handler)
}
func TestBotHandler_IsRunning(t *testing.T) {
@@ -357,11 +445,15 @@ func TestBotHandler_IsRunning(t *testing.T) {
})
t.Run("running", func(t *testing.T) {
- go bh.Start()
+ go func() {
+ err := bh.Start()
+ assert.NoError(t, err)
+ }()
time.Sleep(smallTimeout)
assert.True(t, bh.IsRunning())
- bh.Stop()
+ err := bh.Stop()
+ require.NoError(t, err)
assert.False(t, bh.IsRunning())
})
}
diff --git a/telegohandler/context.go b/telegohandler/context.go
new file mode 100644
index 00000000..81350b0a
--- /dev/null
+++ b/telegohandler/context.go
@@ -0,0 +1,138 @@
+package telegohandler
+
+import (
+ "context"
+ "time"
+
+ "github.com/mymmrac/telego"
+)
+
+// Context is a wrapper around [context.Context] with bot handler specific methods
+type Context struct {
+ ctx context.Context
+ *ctxBase
+}
+
+// ctxBase is a base struct for [Context] that is used to copy context without a need to copy all fields
+type ctxBase struct {
+ bot *telego.Bot
+ updateID int
+
+ group *HandlerGroup
+ stack []int
+}
+
+// Deadline implements [context.Context.Deadline]
+func (c *Context) Deadline() (deadline time.Time, ok bool) {
+ return c.ctx.Deadline()
+}
+
+// Done implements [context.Context.Done]
+func (c *Context) Done() <-chan struct{} {
+ return c.ctx.Done()
+}
+
+// Err implements [context.Context.Err]
+func (c *Context) Err() error {
+ return c.ctx.Err()
+}
+
+// Value implements [context.Context.Value]
+func (c *Context) Value(key any) any {
+ return c.ctx.Value(key)
+}
+
+// Context returns underling [context.Context]
+func (c *Context) Context() context.Context {
+ return c.ctx
+}
+
+// WithContext creates new [Context] with its underling [context.Context] changed to the one provided by user
+//
+// Warning: Panics if nil context passed
+func (c *Context) WithContext(ctx context.Context) *Context {
+ if ctx == nil {
+ panic("Telego: nil context not allowed")
+ }
+
+ return &Context{
+ ctx: ctx,
+ ctxBase: c.ctxBase,
+ }
+}
+
+// WithValue creates new [Context] with set value
+func (c *Context) WithValue(key any, value any) *Context {
+ return &Context{
+ ctx: context.WithValue(c.ctx, key, value),
+ ctxBase: c.ctxBase,
+ }
+}
+
+// WithTimeout creates new [Context] with timeout
+func (c *Context) WithTimeout(timeout time.Duration) (*Context, context.CancelFunc) {
+ ctx, cancel := context.WithTimeout(c.ctx, timeout)
+ return &Context{
+ ctx: ctx,
+ ctxBase: c.ctxBase,
+ }, cancel
+}
+
+// WithCancel creates new [Context] with cancel
+func (c *Context) WithCancel() (*Context, context.CancelFunc) {
+ ctx, cancel := context.WithCancel(c.ctx)
+ return &Context{
+ ctx: ctx,
+ ctxBase: c.ctxBase,
+ }, cancel
+}
+
+// WithoutCancel creates new [Context] without cancel
+func (c *Context) WithoutCancel() *Context {
+ return &Context{
+ ctx: context.WithoutCancel(c.ctx),
+ ctxBase: c.ctxBase,
+ }
+}
+
+// Bot returns [telego.Bot]
+func (c *Context) Bot() *telego.Bot {
+ return c.bot
+}
+
+// UpdateID returns update ID
+func (c *Context) UpdateID() int {
+ return c.updateID
+}
+
+// Next executes the next handler in the stack that matches the current update
+func (c *Context) Next(update telego.Update) error {
+ // Go though all middlewares, subgroups and handlers
+ for i := c.stack[len(c.stack)-1] + 1; i < len(c.group.routes); i++ {
+ r := c.group.routes[i]
+ if r.match(c.ctx, update) {
+ // Update last checked route
+ c.stack[len(c.stack)-1] = i
+
+ // Go into handler or middleware
+ if r.handler != nil {
+ return r.handler(c, update)
+ }
+
+ // Go into subgroup
+ c.group = r.group
+ c.stack = append(c.stack, -1)
+ return c.Next(update)
+ }
+ }
+
+ // Go back to parent if nothing matches in the current group
+ if c.group.parent != nil {
+ c.group = c.group.parent
+ c.stack = c.stack[:len(c.stack)-1]
+ return c.Next(update)
+ }
+
+ // Nothing matches in any group
+ return nil
+}
diff --git a/telegohandler/context_test.go b/telegohandler/context_test.go
new file mode 100644
index 00000000..8e7ac9a4
--- /dev/null
+++ b/telegohandler/context_test.go
@@ -0,0 +1,178 @@
+package telegohandler
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/mymmrac/telego"
+)
+
+func TestContext_Deadline(t *testing.T) {
+ ctx := &Context{
+ ctx: context.Background(),
+ }
+ _, ok := ctx.Deadline()
+ assert.False(t, ok)
+}
+
+func TestContext_Done(t *testing.T) {
+ ctx, cancel := context.WithCancel(context.Background())
+ bCtx := &Context{
+ ctx: ctx,
+ }
+ cancel()
+
+ select {
+ case <-bCtx.Done():
+ case <-time.After(timeout):
+ t.Fatal("Timeout")
+ }
+}
+
+func TestContext_Err(t *testing.T) {
+ ctx := &Context{
+ ctx: context.Background(),
+ }
+ assert.NoError(t, ctx.Err())
+}
+
+func TestContext_Value(t *testing.T) {
+ ctx := &Context{
+ ctx: context.WithValue(context.Background(), "key", "value"), //nolint:staticcheck
+ }
+ assert.Equal(t, "value", ctx.Value("key"))
+}
+
+func TestContext_Context(t *testing.T) {
+ ctx := context.Background()
+ bCtx := &Context{
+ ctx: ctx,
+ }
+
+ assert.Equal(t, ctx, bCtx.Context())
+}
+
+func TestContext_WithContext(t *testing.T) {
+ bCtx := &Context{}
+ ctx := context.Background()
+
+ t.Run("success", func(t *testing.T) {
+ newCtx := bCtx.WithContext(ctx)
+ assert.Equal(t, ctx, newCtx.ctx)
+ })
+
+ t.Run("nil", func(t *testing.T) {
+ assert.Panics(t, func() {
+ bCtx.WithContext(nil) //nolint:staticcheck
+ })
+ })
+
+ t.Run("recursion", func(t *testing.T) {
+ bCtx.ctx = ctx
+ bCtx = bCtx.WithValue("key", "value")
+ assert.Equal(t, "value", bCtx.Value("key"))
+ newCtx := bCtx.WithContext(context.WithoutCancel(bCtx)) //nolint:contextcheck
+ assert.Equal(t, "value", newCtx.Value("key"))
+ })
+}
+
+func TestContext_WithValue(t *testing.T) {
+ ctx := &Context{
+ ctx: context.Background(),
+ }
+ newCtx := ctx.WithValue("key", "value")
+ assert.Equal(t, "value", newCtx.Value("key"))
+}
+
+func TestContext_WithTimeout(t *testing.T) {
+ ctx := &Context{
+ ctx: context.Background(),
+ }
+ ctx, cancel := ctx.WithTimeout(time.Minute)
+ assert.NotNil(t, cancel)
+ _, ok := ctx.Deadline()
+ assert.True(t, ok)
+}
+
+func TestContext_WithCancel(t *testing.T) {
+ ctx := &Context{
+ ctx: context.Background(),
+ }
+ ctx, cancel := ctx.WithCancel()
+ assert.NotNil(t, cancel)
+ cancel()
+ assert.ErrorIs(t, ctx.Err(), context.Canceled)
+}
+
+func TestContext_WithoutCancel(t *testing.T) {
+ ctx, cancel := context.WithTimeout(context.Background(), time.Hour)
+ defer cancel()
+
+ bCtx := &Context{
+ ctx: ctx,
+ }
+
+ bCtx = bCtx.WithoutCancel()
+ assert.NotNil(t, cancel)
+ _, ok := bCtx.Deadline()
+ assert.False(t, ok)
+}
+
+func TestContext_Bot(t *testing.T) {
+ ctx := &Context{
+ ctxBase: &ctxBase{
+ bot: &telego.Bot{},
+ },
+ }
+ assert.NotNil(t, ctx.Bot())
+}
+
+func TestContext_UpdateID(t *testing.T) {
+ ctx := &Context{
+ ctxBase: &ctxBase{
+ updateID: 1,
+ },
+ }
+ assert.Equal(t, 1, ctx.UpdateID())
+}
+
+func TestContext_Next(t *testing.T) {
+ run := false
+
+ gr := &HandlerGroup{}
+
+ gr.Use(func(ctx *Context, update telego.Update) error {
+ update.UpdateID = 1
+ ctx = ctx.WithContext(context.WithValue(ctx, "key", "value")) //nolint:staticcheck
+ return ctx.Next(update)
+ })
+
+ gr1 := gr.Group()
+ gr1.Handle(func(ctx *Context, update telego.Update) error {
+ t.Fatalf("Should not be called")
+ return nil
+ }, None())
+
+ gr2 := gr.Group()
+ gr2.Handle(func(ctx *Context, update telego.Update) error {
+ assert.Equal(t, 1, update.UpdateID)
+ assert.Equal(t, "value", ctx.Value("key"))
+ run = true
+ return nil
+ })
+
+ ctx := &Context{
+ ctxBase: &ctxBase{
+ group: gr,
+ stack: []int{-1},
+ },
+ }
+
+ err := ctx.Next(telego.Update{})
+ require.NoError(t, err)
+ assert.True(t, run)
+}
diff --git a/telegohandler/doc.go b/telegohandler/doc.go
index d8e61fba..a7db9eca 100644
--- a/telegohandler/doc.go
+++ b/telegohandler/doc.go
@@ -1,17 +1,19 @@
/*
-Package telegohandler provides handlers & predicates for Telego.
+Package telegohandler provides handlers and predicates for Telego.
Bot handlers provide an easy way to make net/http like handlers, but with predicates instead of paths.
-In addition to just predicates it, also provides groups and middlewares.
+In addition to just handlers and predicates, it also provides groups and middlewares.
-You can create BotHandler, register new handlers and start processing updates from the update channel which you provide.
-All handlers process updates concurrently, but keep in mind that predicates are checked sequentially. This gives an
-ability to process one update only with the first matched handler.
+You can create [BotHandler] register new handlers and start processing updates from the update channel.
+All handlers process updates concurrently, but keep in mind that predicates are checked sequentially.
+This gives an ability to process one update only with the first matched handler.
# Example
-This example shows how you can create BotHandler and register new handlers. Note, that order of registration directly
-impacts order of checking matched handlers, and only the first matched handler will process the update.
+This example shows how you can create [BotHandler] and register new handlers.
+Note that order of registration directly impacts the order of checking matched handlers, and only the first matched
+handler will process the update, however, middlewares can run even if no handler matched since we are searching for any
+handler in any group to process the update.
package main
@@ -25,6 +27,7 @@ impacts order of checking matched handlers, and only the first matched handler w
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -35,42 +38,42 @@ impacts order of checking matched handlers, and only the first matched handler w
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Register new handler with match on command `/start`
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// Send message
- _, _ = bot.SendMessage(tu.Messagef(
+ _, _ = ctx.Bot().SendMessage(ctx, tu.Messagef(
tu.ID(update.Message.Chat.ID),
"Hello %s!", update.Message.From.FirstName,
))
+ return nil
}, th.CommandEqual("start"))
// Register new handler with match on any command
// Handlers will match only once and in order of registration, so this handler will be called on any command
// except `/start` command
- bh.Handle(func(bot *telego.Bot, update telego.Update) {
+ bh.Handle(func(ctx *th.Context, update telego.Update) error {
// Send message
- _, _ = bot.SendMessage(tu.Message(
+ _, _ = ctx.Bot().SendMessage(tu.Message(
tu.ID(update.Message.Chat.ID),
"Unknown command, use /start",
))
+ return nil
}, th.AnyCommand())
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
-One more example of handler usage. It shows how to use specific handlers to process individual fields of telego.Update.
+One more example of handler usage.
+It shows how to use specific handlers to process individual fields of [telego.Update].
package main
@@ -84,6 +87,7 @@ One more example of handler usage. It shows how to use specific handlers to proc
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -94,39 +98,39 @@ One more example of handler usage. It shows how to use specific handlers to proc
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Register new handler with match on command `/start`
- bh.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ bh.HandleMessage(func(ctx *th.Context, message telego.Message) error {
// Send a message with inline keyboard
- _, _ = bot.SendMessage(tu.Messagef(
+ _, _ = ctx.Bot().SendMessage(tu.Messagef(
tu.ID(message.Chat.ID),
"Hello %s!", message.From.FirstName,
).WithReplyMarkup(tu.InlineKeyboard(
tu.InlineKeyboardRow(tu.InlineKeyboardButton("Go!").WithCallbackData("go"))),
))
+ return nil
}, th.CommandEqual("start"))
// Register new handler with match on a call back query with data equal to `go` and non-nil message
- bh.HandleCallbackQuery(func(bot *telego.Bot, query telego.CallbackQuery) {
+ bh.HandleCallbackQuery(func(ctx *th.Context, query telego.CallbackQuery) error {
// Send message
_, _ = bot.SendMessage(tu.Message(tu.ID(query.Message.Chat.ID), "GO GO GO"))
// Answer callback query
_ = bot.AnswerCallbackQuery(tu.CallbackQuery(query.ID).WithText("Done"))
+
+ return nil
}, th.AnyCallbackQueryWithMessage(), th.CallbackDataEqual("go"))
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
In this example, usage of groups and middleware will be shown.
@@ -142,6 +146,7 @@ In this example, usage of groups and middleware will be shown.
)
func main() {
+ ctx := context.Background()
botToken := os.Getenv("TOKEN")
// Note: Please keep in mind that default logger may expose sensitive information, use in development only
@@ -152,49 +157,48 @@ In this example, usage of groups and middleware will be shown.
}
// Get updates channel
- updates, _ := bot.UpdatesViaLongPolling(nil)
+ updates, _ := bot.UpdatesViaLongPolling(ctx, nil)
// Create bot handler and specify from where to get updates
bh, _ := th.NewBotHandler(bot, updates)
// Stop handling updates
- defer bh.Stop()
-
- // Stop getting updates
- defer bot.StopLongPolling()
+ defer func() { _ = bh.Stop() }()
// Add global middleware, it will be applied in order of addition
bh.Use(
- func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ func(ctx *th.Context, update telego.Update) error {
fmt.Println("Global middleware") // Will be called first
- next(bot, update)
+ return ctx.Next(update)
},
- func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ func(ctx *th.Context, update telego.Update) error {
fmt.Println("Global middleware 2") // Will be called second
- next(bot, update)
+ return ctx.Next(update)
},
)
// Create any groups with or without predicates
- // Note: Updates first checked by groups and only then by handlers (group -> ... -> group -> handler)
task := bh.Group(th.TextContains("task"))
// Add middleware to groups
- task.Use(func(bot *telego.Bot, update telego.Update, next th.Handler) {
+ task.Use(func(ctx *th.Context, update telego.Update) error {
fmt.Println("Group based middleware") // Will be called third
if len(update.Message.Text) < 10 {
- next(bot, update)
+ return ctx.Next(update)
}
+
+ return nil
})
// Handle updates on a group
- task.HandleMessage(func(bot *telego.Bot, message telego.Message) {
+ task.HandleMessage(func(ctx *th.Context, message telego.Message) error {
fmt.Println("Task...") // Will be called fourth
+ return nil
})
// Start handling updates
- bh.Start()
+ _ = bh.Start()
}
*/
package telegohandler
diff --git a/telegohandler/handler_group.go b/telegohandler/handler_group.go
index 37e64dde..469f990b 100644
--- a/telegohandler/handler_group.go
+++ b/telegohandler/handler_group.go
@@ -1,114 +1,59 @@
package telegohandler
import (
- "sync"
+ "context"
+ "slices"
"github.com/mymmrac/telego"
)
-// conditionalHandler represents handler with respectful predicates
-type conditionalHandler struct {
- handler Handler
+// route represents handler, middleware or group with respectful predicates
+type route struct {
predicates []Predicate
-}
-// match matches the current update and handler
-func (h conditionalHandler) match(update telego.Update) bool {
- update = update.Clone()
- for _, p := range h.predicates {
- if !p(update) {
- return false
- }
- }
- return true
+ group *HandlerGroup
+ handler Handler
}
-// HandlerGroup represents a group of handlers, middlewares and child groups
-type HandlerGroup struct {
- lock sync.RWMutex
- predicates []Predicate
- middlewares []Middleware
- groups []*HandlerGroup
- handlers []conditionalHandler
-}
+// match matches the current update by predicates
+func (r route) match(ctx context.Context, update telego.Update) bool {
+ if len(r.predicates) == 0 {
+ return true
+ }
-// match matches the current update and group
-func (h *HandlerGroup) match(update telego.Update) bool {
update = update.Clone()
- for _, p := range h.predicates {
- if !p(update) {
+ for _, p := range r.predicates {
+ if !p(ctx, update) {
return false
}
}
+
return true
}
-// processUpdate checks all group predicates, runs middlewares, checks handler predicates,
-// tries to process update in first matched handler
-func (h *HandlerGroup) processUpdate(bot *telego.Bot, update telego.Update) {
- h.lock.RLock()
- _ = h.processUpdateWithMiddlewares(bot, update, h.middlewares)
- h.lock.RUnlock()
+// HandlerGroup represents a group of middlewares and routes (handlers and subgroups)
+type HandlerGroup struct {
+ parent *HandlerGroup
+ routes []route
}
-func (h *HandlerGroup) processUpdateWithMiddlewares(
- bot *telego.Bot, update telego.Update, middlewares []Middleware,
-) bool {
- ctx := update.Context()
- select {
- case <-ctx.Done():
- return false
- default:
- // Continue
- }
-
- // Check group predicates once
- if len(middlewares) == len(h.middlewares) && !h.match(update) {
- return false
- }
-
- // Process all middlewares
- if len(middlewares) != 0 {
- once := sync.Once{}
- done := make(chan bool, 1)
- middlewares[0](bot, update, func(bot *telego.Bot, update telego.Update) {
- once.Do(func() {
- done <- h.processUpdateWithMiddlewares(bot, update, middlewares[1:])
- })
- })
-
- select {
- case <-ctx.Done():
- return false
- case matched := <-done:
- return matched
- }
- }
-
- // Process all groups
- for _, group := range h.groups {
- if group.processUpdateWithMiddlewares(bot, update, group.middlewares) {
- return true
- }
- }
-
- // Process all handlers
- for _, handler := range h.handlers {
- if handler.match(update) {
- handler.handler(bot, update)
- return true
+// depth returns the depth of the group's routes
+func (h *HandlerGroup) depth(depth int) int {
+ localDepth := depth
+ for _, r := range h.routes {
+ if r.group != nil {
+ depth = max(depth, r.group.depth(localDepth+1))
}
}
-
- return false
+ return depth
}
-// Handle registers new handler in the group, update will be processed only by first-matched handler,
-// order of registration determines the order of matching handlers.
-// Important to notice, update's context will be automatically canceled once the handler will finish processing or
+// Handle registers new handler in the group, update will be processed only by first-matched route,
+// order of registration determines the order of matching routes.
+// Important to notice handler's context will be automatically canceled once the handler will finish processing or
// the bot handler stopped.
// Note: All handlers will process updates in parallel, there is no guaranty on order of processed updates, also keep
-// in mind that middlewares and predicates are checked sequentially.
+// in mind that middlewares and predicates are run sequentially.
//
// Warning: Panics if nil handler or predicates passed
func (h *HandlerGroup) Handle(handler Handler, predicates ...Predicate) {
@@ -122,16 +67,14 @@ func (h *HandlerGroup) Handle(handler Handler, predicates ...Predicate) {
}
}
- h.lock.Lock()
- h.handlers = append(h.handlers, conditionalHandler{
- handler: handler,
+ h.routes = append(h.routes, route{
predicates: predicates,
+ handler: handler,
})
- h.lock.Unlock()
}
-// Group creates a new group of handlers and middlewares from the parent group
-// Note: Updates first checked by group and only after that by handler
+// Group creates a new group of handlers and middlewares from the parent group, update will be processed only by
+// first-matched route, order of registration determines the order of matching routes
//
// Warning: Panics if nil predicates passed
func (h *HandlerGroup) Group(predicates ...Predicate) *HandlerGroup {
@@ -142,30 +85,33 @@ func (h *HandlerGroup) Group(predicates ...Predicate) *HandlerGroup {
}
group := &HandlerGroup{
- predicates: predicates,
+ parent: h,
}
- h.lock.Lock()
- h.groups = append(h.groups, group)
- h.lock.Unlock()
+ h.routes = append(h.routes, route{
+ predicates: predicates,
+ group: group,
+ })
return group
}
-// Use applies middleware to the group
-// Note: The chain will be stopped if middleware doesn't call the next func,
-// if there is no context timeout then update will be stuck,
-// if there is time out then the group will be skipped since not all middlewares were called
+// Use applies middleware to the group, update will be processed only by first-matched route,
+// order of registration determines the order of matching routes.
+// Note: The chain will be stopped if middleware doesn't call the [Context.Next]
//
// Warning: Panics if nil middlewares passed
-func (h *HandlerGroup) Use(middlewares ...Middleware) {
+func (h *HandlerGroup) Use(middlewares ...Handler) {
for _, m := range middlewares {
if m == nil {
panic("Telego: nil middlewares not allowed")
}
}
- h.lock.Lock()
- h.middlewares = append(h.middlewares, middlewares...)
- h.lock.Unlock()
+ h.routes = slices.Grow(h.routes, len(middlewares))
+ for _, middleware := range middlewares {
+ h.routes = append(h.routes, route{
+ handler: middleware,
+ })
+ }
}
diff --git a/telegohandler/handler_group_test.go b/telegohandler/handler_group_test.go
index 00329e54..172da7ce 100644
--- a/telegohandler/handler_group_test.go
+++ b/telegohandler/handler_group_test.go
@@ -2,7 +2,6 @@ package telegohandler
import (
"context"
- "sync"
"testing"
"github.com/stretchr/testify/assert"
@@ -20,7 +19,7 @@ func TestHandlerGroup_Handle(t *testing.T) {
})
})
- handler := Handler(func(bot *telego.Bot, update telego.Update) {})
+ handler := Handler(func(_ *Context, _ telego.Update) error { return nil })
t.Run("panic_nil_predicate", func(t *testing.T) {
assert.Panics(t, func() {
@@ -31,23 +30,23 @@ func TestHandlerGroup_Handle(t *testing.T) {
t.Run("without_predicates", func(t *testing.T) {
gr.Handle(handler)
- require.Len(t, gr.handlers, 1)
- assert.NotNil(t, gr.handlers[0].handler)
- assert.Nil(t, gr.handlers[0].predicates)
+ require.Len(t, gr.routes, 1)
+ assert.NotNil(t, gr.routes[0].handler)
+ assert.Nil(t, gr.routes[0].predicates)
- gr.handlers = make([]conditionalHandler, 0)
+ gr.routes = nil
})
- predicate := Predicate(func(update telego.Update) bool { return false })
+ predicate := Predicate(func(_ context.Context, _ telego.Update) bool { return false })
t.Run("with_predicates", func(t *testing.T) {
gr.Handle(handler, predicate)
- require.Len(t, gr.handlers, 1)
- assert.NotNil(t, gr.handlers[0].handler)
- assert.NotNil(t, gr.handlers[0].predicates)
+ require.Len(t, gr.routes, 1)
+ assert.NotNil(t, gr.routes[0].handler)
+ assert.NotNil(t, gr.routes[0].predicates)
- gr.handlers = make([]conditionalHandler, 0)
+ gr.routes = nil
})
}
@@ -63,22 +62,22 @@ func TestHandlerGroup_Group(t *testing.T) {
t.Run("without_predicates", func(t *testing.T) {
newGr := gr.Group()
- require.Len(t, gr.groups, 1)
- assert.Equal(t, newGr, gr.groups[0])
+ require.Len(t, gr.routes, 1)
+ assert.Equal(t, newGr, gr.routes[0].group)
- gr.groups = nil
+ gr.routes = nil
})
- predicate := Predicate(func(update telego.Update) bool { return false })
+ predicate := Predicate(func(_ context.Context, _ telego.Update) bool { return false })
t.Run("with_predicates", func(t *testing.T) {
newGr := gr.Group(predicate)
- require.Len(t, gr.groups, 1)
- assert.Equal(t, newGr, gr.groups[0])
- assert.NotEmpty(t, gr.groups[0].predicates)
+ require.Len(t, gr.routes, 1)
+ assert.Equal(t, newGr, gr.routes[0].group)
+ assert.NotEmpty(t, gr.routes[0].predicates)
- gr.groups = nil
+ gr.routes = nil
})
}
@@ -91,226 +90,50 @@ func TestHandlerGroup_Use(t *testing.T) {
})
})
- middleware := Middleware(func(bot *telego.Bot, update telego.Update, next Handler) {
- next(bot, update)
+ middleware := Handler(func(ctx *Context, update telego.Update) error {
+ return ctx.Next(update)
})
t.Run("success", func(t *testing.T) {
gr.Use(middleware)
- require.Len(t, gr.middlewares, 1)
- assert.NotNil(t, gr.middlewares[0])
+ require.Len(t, gr.routes, 1)
+ assert.NotNil(t, gr.routes[0].handler)
})
}
-func TestHandlerGroup_processUpdate(t *testing.T) {
- var order []int
- lock := sync.Mutex{}
- updOrder := func(i int) {
- lock.Lock()
- order = append(order, i)
- lock.Unlock()
- }
+func TestHandlerGroup_depth(t *testing.T) {
+ t.Run("1", func(t *testing.T) {
+ gr := &HandlerGroup{}
+ assert.Equal(t, 1, gr.depth(1))
+ })
- gr := &HandlerGroup{
- predicates: []Predicate{
- func(update telego.Update) bool {
- t.Log("Predicate")
- updOrder(1)
- return true
- },
- },
- middlewares: []Middleware{
- func(bot *telego.Bot, update telego.Update, next Handler) {
- t.Log("Before next")
- updOrder(9)
- next(bot, update)
- next(bot, update)
- t.Log("After next")
- updOrder(10)
- },
- func(bot *telego.Bot, update telego.Update, next Handler) {
- t.Log("Before nested next")
- updOrder(11)
- next(bot, update)
- t.Log("After nested next")
- updOrder(12)
- },
- func(bot *telego.Bot, update telego.Update, next Handler) {
- t.Log("Before nested next go")
- updOrder(20)
- go next(bot, update)
- t.Log("After nested next go")
- updOrder(21)
- },
- },
- groups: []*HandlerGroup{
- {
- handlers: []conditionalHandler{
- {
- predicates: []Predicate{
- func(update telego.Update) bool {
- t.Log("Predicate handler nested in a group")
- updOrder(14)
- return false
- },
- },
- },
- },
- },
- {
- middlewares: []Middleware{
- func(bot *telego.Bot, update telego.Update, next Handler) {
- t.Log("Before nested in a group next")
- updOrder(15)
- ctx, cancel := context.WithCancel(update.Context())
- cancel()
- next(bot, update.WithContext(ctx))
- updOrder(19)
- },
- },
- groups: []*HandlerGroup{
- {
- middlewares: []Middleware{
- func(bot *telego.Bot, update telego.Update, next Handler) {
- assert.Fail(t, "shouldn't be called")
- },
- },
- },
- },
+ t.Run("2", func(t *testing.T) {
+ gr := &HandlerGroup{
+ routes: []route{
+ {},
+ {group: &HandlerGroup{}},
},
- {
- middlewares: []Middleware{
- func(bot *telego.Bot, update telego.Update, next Handler) {
- t.Log("Before nested in a group next")
- updOrder(18)
- ctx, cancel := context.WithTimeout(update.Context(), smallTimeout)
- next(bot, update.WithContext(ctx))
- cancel()
- t.Log("After nested in a group next")
- updOrder(17)
- },
- func(bot *telego.Bot, update telego.Update, next Handler) {
- t.Log("Before nested in a group next")
- updOrder(16)
- },
- },
- },
- {
- predicates: []Predicate{
- func(update telego.Update) bool {
- t.Log("Predicate nested in a group")
- updOrder(13)
- return false
- },
- },
- },
- {
- predicates: []Predicate{
- func(update telego.Update) bool {
- t.Log("Predicate nested in a group")
- updOrder(2)
- return true
- },
- },
- middlewares: []Middleware{
- func(bot *telego.Bot, update telego.Update, next Handler) {
- t.Log("Before nested in a group next")
- updOrder(5)
- next(bot, update)
- t.Log("After nested in a group next")
- updOrder(6)
- },
- },
- handlers: []conditionalHandler{
- {
- handler: func(bot *telego.Bot, update telego.Update) {
- t.Log("Handler in a group")
- updOrder(3)
- },
- predicates: []Predicate{
- func(update telego.Update) bool {
- t.Log("Predicate handler nested in a group")
- updOrder(4)
- return true
- },
- },
- },
- },
- },
- },
- handlers: []conditionalHandler{
- {
- handler: func(bot *telego.Bot, update telego.Update) {
- t.Log("Handler")
- updOrder(7)
- },
- predicates: []Predicate{
- func(update telego.Update) bool {
- t.Log("Predicate handler")
- updOrder(8)
- return true
+ }
+ assert.Equal(t, 2, gr.depth(1))
+ })
+
+ t.Run("3", func(t *testing.T) {
+ gr := &HandlerGroup{
+ routes: []route{
+ {},
+ {group: &HandlerGroup{}},
+ {},
+ {group: &HandlerGroup{
+ routes: []route{
+ {},
+ {group: &HandlerGroup{}},
},
- },
+ }},
+ {group: &HandlerGroup{}},
+ {},
},
- },
- }
-
- gr.processUpdate(nil, telego.Update{})
-
- lock.Lock()
- t.Log("Order:", order)
- ok := false
- for i, value := range order {
- if value == 21 {
- order = append(order[:i], order[i+1:]...)
- ok = true
- break
}
- }
- assert.True(t, ok)
- assert.Equal(t, []int{1, 9, 11, 20, 14, 15, 19, 18, 16, 17, 13, 2, 5, 4, 3, 6, 12, 10}, order)
- lock.Unlock()
-}
-
-func TestHandlerGroup_parallel(t *testing.T) {
- gr := &HandlerGroup{}
-
- wait := sync.WaitGroup{}
- wait.Add(1)
-
- h := func(bot *telego.Bot, update telego.Update) {}
- p := func(update telego.Update) bool { return false }
- m := func(bot *telego.Bot, update telego.Update, next Handler) { next(bot, update) }
-
- wg := sync.WaitGroup{}
-
- n := 64
- for i := 0; i < n; i++ {
- wg.Add(1)
- go func() {
- wait.Wait()
- gr.Handle(h, p)
- wg.Done()
- }()
- wg.Add(1)
- go func() {
- wait.Wait()
- gr.Group(p)
- wg.Done()
- }()
- wg.Add(1)
- go func() {
- wait.Wait()
- gr.Use(m)
- wg.Done()
- }()
- }
-
- wait.Done()
- wg.Wait()
-
- assert.Len(t, gr.handlers, n)
- assert.Len(t, gr.groups, n)
- assert.Len(t, gr.middlewares, n)
+ assert.Equal(t, 3, gr.depth(1))
+ })
}
diff --git a/telegohandler/handlers.go b/telegohandler/handlers.go
index 95c9f1f7..d2143de0 100644
--- a/telegohandler/handlers.go
+++ b/telegohandler/handlers.go
@@ -1,515 +1,428 @@
package telegohandler
import (
- "context"
-
"github.com/mymmrac/telego"
)
// MessageHandler handles message that came from bot
-type MessageHandler func(bot *telego.Bot, message telego.Message)
-
-// MessageHandlerCtx handles message that came from bot with context
-type MessageHandlerCtx func(ctx context.Context, bot *telego.Bot, message telego.Message)
+type MessageHandler func(ctx *Context, message telego.Message) error
-// HandleMessage same as Handle, but assumes that the update contains a message
+// HandleMessage same as [BotHandler.Handle], but assumes that the update contains a message
func (h *HandlerGroup) HandleMessage(handler MessageHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil message handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.Message)
- }, append([]Predicate{AnyMessage()}, predicates...)...)
-}
-
-// HandleMessageCtx same as Handle, but assumes that the update contains a message
-func (h *HandlerGroup) HandleMessageCtx(handler MessageHandlerCtx, predicates ...Predicate) {
- if handler == nil {
- panic("Telego: nil message handlers not allowed")
- }
-
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.Message)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.Message)
}, append([]Predicate{AnyMessage()}, predicates...)...)
}
-// HandleMessage same as Handle, but assumes that the update contains a message
+// HandleMessage same as [BotHandler.Handle], but assumes that the update contains a message
func (h *BotHandler) HandleMessage(handler MessageHandler, predicates ...Predicate) {
h.baseGroup.HandleMessage(handler, predicates...)
}
-// HandleMessageCtx same as Handle, but assumes that the update contains a message
-func (h *BotHandler) HandleMessageCtx(handler MessageHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleMessageCtx(handler, predicates...)
-}
-
-// HandleEditedMessage same as Handle, but assumes that the update contains an edited message
+// HandleEditedMessage same as [BotHandler.Handle], but assumes that the update contains an edited message
func (h *HandlerGroup) HandleEditedMessage(handler MessageHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil edited message handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.EditedMessage)
- }, append([]Predicate{AnyEditedMessage()}, predicates...)...)
-}
-
-// HandleEditedMessageCtx same as Handle, but assumes that the update contains an edited message
-func (h *HandlerGroup) HandleEditedMessageCtx(handler MessageHandlerCtx, predicates ...Predicate) {
- if handler == nil {
- panic("Telego: nil edited message handlers not allowed")
- }
-
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.EditedMessage)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.EditedMessage)
}, append([]Predicate{AnyEditedMessage()}, predicates...)...)
}
-// HandleEditedMessage same as Handle, but assumes that the update contains an edited message
+// HandleEditedMessage same as [BotHandler.Handle], but assumes that the update contains an edited message
func (h *BotHandler) HandleEditedMessage(handler MessageHandler, predicates ...Predicate) {
h.baseGroup.HandleEditedMessage(handler, predicates...)
}
-// HandleEditedMessageCtx same as Handle, but assumes that the update contains an edited message
-func (h *BotHandler) HandleEditedMessageCtx(handler MessageHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleEditedMessageCtx(handler, predicates...)
-}
-
-// HandleChannelPost same as Handle, but assumes that the update contains a channel post
+// HandleChannelPost same as [BotHandler.Handle], but assumes that the update contains a channel post
func (h *HandlerGroup) HandleChannelPost(handler MessageHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil channel post handlers not allowed")
+ panic("Telego: nil channel post-handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.ChannelPost)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.ChannelPost)
}, append([]Predicate{AnyChannelPost()}, predicates...)...)
}
-// HandleChannelPostCtx same as Handle, but assumes that the update contains a channel post
-func (h *HandlerGroup) HandleChannelPostCtx(handler MessageHandlerCtx, predicates ...Predicate) {
+// HandleChannelPost same as [BotHandler.Handle], but assumes that the update contains a channel post
+func (h *BotHandler) HandleChannelPost(handler MessageHandler, predicates ...Predicate) {
+ h.baseGroup.HandleChannelPost(handler, predicates...)
+}
+
+// HandleEditedChannelPost same as [BotHandler.Handle], but assumes that the update contains an edited channel post
+func (h *HandlerGroup) HandleEditedChannelPost(handler MessageHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil channel post handlers not allowed")
+ panic("Telego: nil edited channel post-handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.ChannelPost)
- }, append([]Predicate{AnyChannelPost()}, predicates...)...)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.EditedChannelPost)
+ }, append([]Predicate{AnyEditedChannelPost()}, predicates...)...)
}
-// HandleChannelPost same as Handle, but assumes that the update contains a channel post
-func (h *BotHandler) HandleChannelPost(handler MessageHandler, predicates ...Predicate) {
- h.baseGroup.HandleChannelPost(handler, predicates...)
+// HandleEditedChannelPost same as [BotHandler.Handle], but assumes that the update contains an edited channel post
+func (h *BotHandler) HandleEditedChannelPost(handler MessageHandler, predicates ...Predicate) {
+ h.baseGroup.HandleEditedChannelPost(handler, predicates...)
}
-// HandleChannelPostCtx same as Handle, but assumes that the update contains a channel post
-func (h *BotHandler) HandleChannelPostCtx(handler MessageHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleChannelPostCtx(handler, predicates...)
-}
+// BusinessConnectionHandler handles business connection that came from bot
+type BusinessConnectionHandler func(ctx *Context, connection telego.BusinessConnection) error
-// HandleEditedChannelPost same as Handle, but assumes that the update contains an edited channel post
-func (h *HandlerGroup) HandleEditedChannelPost(handler MessageHandler, predicates ...Predicate) {
+// HandleBusinessConnection same as [BotHandler.Handle], but assumes that the update contains a business connection
+func (h *HandlerGroup) HandleBusinessConnection(handler BusinessConnectionHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil edited channel post handlers not allowed")
+ panic("Telego: nil business connection handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.EditedChannelPost)
- }, append([]Predicate{AnyEditedChannelPost()}, predicates...)...)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.BusinessConnection)
+ }, append([]Predicate{AnyBusinessConnection()}, predicates...)...)
+}
+
+// HandleBusinessConnection same as [BotHandler.Handle], but assumes that the update contains a business connection
+func (h *BotHandler) HandleBusinessConnection(handler BusinessConnectionHandler, predicates ...Predicate) {
+ h.baseGroup.HandleBusinessConnection(handler, predicates...)
}
-// HandleEditedChannelPostCtx same as Handle, but assumes that the update contains an edited channel post
-func (h *HandlerGroup) HandleEditedChannelPostCtx(handler MessageHandlerCtx, predicates ...Predicate) {
+// HandleBusinessMessage same as [BotHandler.Handle], but assumes that the update contains a business message
+func (h *HandlerGroup) HandleBusinessMessage(handler MessageHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil edited channel post handlers not allowed")
+ panic("Telego: nil business message handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.EditedChannelPost)
- }, append([]Predicate{AnyEditedChannelPost()}, predicates...)...)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.BusinessMessage)
+ }, append([]Predicate{AnyBusinessMessage()}, predicates...)...)
}
-// HandleEditedChannelPost same as Handle, but assumes that the update contains an edited channel post
-func (h *BotHandler) HandleEditedChannelPost(handler MessageHandler, predicates ...Predicate) {
- h.baseGroup.HandleEditedChannelPost(handler, predicates...)
+// HandleBusinessMessage same as [BotHandler.Handle], but assumes that the update contains a business message
+func (h *BotHandler) HandleBusinessMessage(handler MessageHandler, predicates ...Predicate) {
+ h.baseGroup.HandleBusinessMessage(handler, predicates...)
}
-// HandleEditedChannelPostCtx same as Handle, but assumes that the update contains an edited channel post
-func (h *BotHandler) HandleEditedChannelPostCtx(handler MessageHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleEditedChannelPostCtx(handler, predicates...)
+// HandleEditedBusinessMessage same as [BotHandler.Handle], but assumes that the update contains an edited
+// business message
+func (h *HandlerGroup) HandleEditedBusinessMessage(handler MessageHandler, predicates ...Predicate) {
+ if handler == nil {
+ panic("Telego: nil edited business message handlers not allowed")
+ }
+
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.EditedBusinessMessage)
+ }, append([]Predicate{AnyEditedBusinessMessage()}, predicates...)...)
}
-// InlineQueryHandler handles inline queries that came from bot
-type InlineQueryHandler func(bot *telego.Bot, query telego.InlineQuery)
+// HandleEditedBusinessMessage same as [BotHandler.Handle], but assumes that the update contains an edited
+// business message
+func (h *BotHandler) HandleEditedBusinessMessage(handler MessageHandler, predicates ...Predicate) {
+ h.baseGroup.HandleEditedBusinessMessage(handler, predicates...)
+}
-// InlineQueryHandlerCtx handles inline queries that came from bot with context
-type InlineQueryHandlerCtx func(ctx context.Context, bot *telego.Bot, query telego.InlineQuery)
+// DeletedBusinessMessagesHandler handles deleted business messages that came from bot
+type DeletedBusinessMessagesHandler func(ctx *Context, deletedMessage telego.BusinessMessagesDeleted) error
-// HandleInlineQuery same as Handle, but assumes that the update contains an inline query
-func (h *HandlerGroup) HandleInlineQuery(handler InlineQueryHandler, predicates ...Predicate) {
+// HandleDeletedBusinessMessages same as [BotHandler.Handle], but assumes that the update contains a deleted
+// business messages
+func (h *HandlerGroup) HandleDeletedBusinessMessages(handler DeletedBusinessMessagesHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil inline query handlers not allowed")
+ panic("Telego: nil deleted business messages handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.InlineQuery)
- }, append([]Predicate{AnyInlineQuery()}, predicates...)...)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.DeletedBusinessMessages)
+ }, append([]Predicate{AnyDeletedBusinessMessages()}, predicates...)...)
}
-// HandleInlineQueryCtx same as Handle, but assumes that the update contains an inline query
-func (h *HandlerGroup) HandleInlineQueryCtx(handler InlineQueryHandlerCtx, predicates ...Predicate) {
+// HandleDeletedBusinessMessages same as [BotHandler.Handle], but assumes that the update contains a deleted
+// business messages
+func (h *BotHandler) HandleDeletedBusinessMessages(handler DeletedBusinessMessagesHandler, predicates ...Predicate) {
+ h.baseGroup.HandleDeletedBusinessMessages(handler, predicates...)
+}
+
+// MessageReactionHandler handles message reaction that came from bot
+type MessageReactionHandler func(ctx *Context, reaction telego.MessageReactionUpdated) error
+
+// HandleMessageReaction same as [BotHandler.Handle], but assumes that the update contains a message reaction
+func (h *HandlerGroup) HandleMessageReaction(handler MessageReactionHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil inline query handlers not allowed")
+ panic("Telego: nil message reaction handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.InlineQuery)
- }, append([]Predicate{AnyInlineQuery()}, predicates...)...)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.MessageReaction)
+ }, append([]Predicate{AnyMessageReaction()}, predicates...)...)
}
-// HandleInlineQuery same as Handle, but assumes that the update contains an inline query
-func (h *BotHandler) HandleInlineQuery(handler InlineQueryHandler, predicates ...Predicate) {
- h.baseGroup.HandleInlineQuery(handler, predicates...)
+// HandleMessageReaction same as [BotHandler.Handle], but assumes that the update contains a message reaction
+func (h *BotHandler) HandleMessageReaction(handler MessageReactionHandler, predicates ...Predicate) {
+ h.baseGroup.HandleMessageReaction(handler, predicates...)
}
-// HandleInlineQueryCtx same as Handle, but assumes that the update contains an inline query
-func (h *BotHandler) HandleInlineQueryCtx(handler InlineQueryHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleInlineQueryCtx(handler, predicates...)
+// MessageReactionCountHandler handles message reaction that came from bot
+type MessageReactionCountHandler func(ctx *Context, reaction telego.MessageReactionCountUpdated) error
+
+// HandleMessageReactionCount same as [BotHandler.Handle], but assumes that the update contains a message reaction count
+func (h *HandlerGroup) HandleMessageReactionCount(handler MessageReactionCountHandler, predicates ...Predicate) {
+ if handler == nil {
+ panic("Telego: nil message reaction count handlers not allowed")
+ }
+
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.MessageReactionCount)
+ }, append([]Predicate{AnyMessageReactionCount()}, predicates...)...)
}
-// ChosenInlineResultHandler handles chosen inline result that came from bot
-type ChosenInlineResultHandler func(bot *telego.Bot, result telego.ChosenInlineResult)
+// HandleMessageReactionCount same as [BotHandler.Handle], but assumes that the update contains a message reaction count
+func (h *BotHandler) HandleMessageReactionCount(handler MessageReactionCountHandler, predicates ...Predicate) {
+ h.baseGroup.HandleMessageReactionCount(handler, predicates...)
+}
-// ChosenInlineResultHandlerCtx handles chosen inline result that came from bot with context
-type ChosenInlineResultHandlerCtx func(ctx context.Context, bot *telego.Bot, result telego.ChosenInlineResult)
+// InlineQueryHandler handles inline queries that came from bot
+type InlineQueryHandler func(ctx *Context, query telego.InlineQuery) error
-// HandleChosenInlineResult same as Handle, but assumes that the update contains a chosen inline result
-func (h *HandlerGroup) HandleChosenInlineResult(handler ChosenInlineResultHandler, predicates ...Predicate) {
+// HandleInlineQuery same as [BotHandler.Handle], but assumes that the update contains an inline query
+func (h *HandlerGroup) HandleInlineQuery(handler InlineQueryHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil chosen inline query handlers not allowed")
+ panic("Telego: nil inline query handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.ChosenInlineResult)
- }, append([]Predicate{AnyChosenInlineResult()}, predicates...)...)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.InlineQuery)
+ }, append([]Predicate{AnyInlineQuery()}, predicates...)...)
+}
+
+// HandleInlineQuery same as [BotHandler.Handle], but assumes that the update contains an inline query
+func (h *BotHandler) HandleInlineQuery(handler InlineQueryHandler, predicates ...Predicate) {
+ h.baseGroup.HandleInlineQuery(handler, predicates...)
}
-// HandleChosenInlineResultCtx same as Handle, but assumes that the update contains a chosen inline result
-func (h *HandlerGroup) HandleChosenInlineResultCtx(handler ChosenInlineResultHandlerCtx, predicates ...Predicate) {
+// ChosenInlineResultHandler handles chosen an inline result that came from bot
+type ChosenInlineResultHandler func(ctx *Context, result telego.ChosenInlineResult) error
+
+// HandleChosenInlineResult same as [BotHandler.Handle], but assumes that the update contains a chosen inline result
+func (h *HandlerGroup) HandleChosenInlineResult(handler ChosenInlineResultHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil chosen inline query handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.ChosenInlineResult)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.ChosenInlineResult)
}, append([]Predicate{AnyChosenInlineResult()}, predicates...)...)
}
-// HandleChosenInlineResult same as Handle, but assumes that the update contains a chosen inline result
+// HandleChosenInlineResult same as [BotHandler.Handle], but assumes that the update contains a chosen inline result
func (h *BotHandler) HandleChosenInlineResult(handler ChosenInlineResultHandler, predicates ...Predicate) {
h.baseGroup.HandleChosenInlineResult(handler, predicates...)
}
-// HandleChosenInlineResultCtx same as Handle, but assumes that the update contains a chosen inline result
-func (h *BotHandler) HandleChosenInlineResultCtx(handler ChosenInlineResultHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleChosenInlineResultCtx(handler, predicates...)
-}
-
// CallbackQueryHandler handles callback queries that came from bot
-type CallbackQueryHandler func(bot *telego.Bot, query telego.CallbackQuery)
-
-// CallbackQueryHandlerCtx handles callback queries that came from bot with context
-type CallbackQueryHandlerCtx func(ctx context.Context, bot *telego.Bot, query telego.CallbackQuery)
+type CallbackQueryHandler func(ctx *Context, query telego.CallbackQuery) error
-// HandleCallbackQuery same as Handle, but assumes that the update contains a callback query
+// HandleCallbackQuery same as [BotHandler.Handle], but assumes that the update contains a callback query
func (h *HandlerGroup) HandleCallbackQuery(handler CallbackQueryHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil callback query handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.CallbackQuery)
- }, append([]Predicate{AnyCallbackQuery()}, predicates...)...)
-}
-
-// HandleCallbackQueryCtx same as Handle, but assumes that the update contains a callback query
-func (h *HandlerGroup) HandleCallbackQueryCtx(handler CallbackQueryHandlerCtx, predicates ...Predicate) {
- if handler == nil {
- panic("Telego: nil callback query handlers not allowed")
- }
-
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.CallbackQuery)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.CallbackQuery)
}, append([]Predicate{AnyCallbackQuery()}, predicates...)...)
}
-// HandleCallbackQuery same as Handle, but assumes that the update contains a callback query
+// HandleCallbackQuery same as [BotHandler.Handle], but assumes that the update contains a callback query
func (h *BotHandler) HandleCallbackQuery(handler CallbackQueryHandler, predicates ...Predicate) {
h.baseGroup.HandleCallbackQuery(handler, predicates...)
}
-// HandleCallbackQueryCtx same as Handle, but assumes that the update contains a callback query
-func (h *BotHandler) HandleCallbackQueryCtx(handler CallbackQueryHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleCallbackQueryCtx(handler, predicates...)
-}
-
// ShippingQueryHandler handles shipping query that came from bot
-type ShippingQueryHandler func(bot *telego.Bot, query telego.ShippingQuery)
-
-// ShippingQueryHandlerCtx handles shipping query that came from bot with context
-type ShippingQueryHandlerCtx func(ctx context.Context, bot *telego.Bot, query telego.ShippingQuery)
+type ShippingQueryHandler func(ctx *Context, query telego.ShippingQuery) error
-// HandleShippingQuery same as Handle, but assumes that the update contains a shipping query
+// HandleShippingQuery same as [BotHandler.Handle], but assumes that the update contains a shipping query
func (h *HandlerGroup) HandleShippingQuery(handler ShippingQueryHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil shipping query handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.ShippingQuery)
- }, append([]Predicate{AnyShippingQuery()}, predicates...)...)
-}
-
-// HandleShippingQueryCtx same as Handle, but assumes that the update contains a shipping query
-func (h *HandlerGroup) HandleShippingQueryCtx(handler ShippingQueryHandlerCtx, predicates ...Predicate) {
- if handler == nil {
- panic("Telego: nil shipping query handlers not allowed")
- }
-
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.ShippingQuery)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.ShippingQuery)
}, append([]Predicate{AnyShippingQuery()}, predicates...)...)
}
-// HandleShippingQuery same as Handle, but assumes that the update contains a shipping query
+// HandleShippingQuery same as [BotHandler.Handle], but assumes that the update contains a shipping query
func (h *BotHandler) HandleShippingQuery(handler ShippingQueryHandler, predicates ...Predicate) {
h.baseGroup.HandleShippingQuery(handler, predicates...)
}
-// HandleShippingQueryCtx same as Handle, but assumes that the update contains a shipping query
-func (h *BotHandler) HandleShippingQueryCtx(handler ShippingQueryHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleShippingQueryCtx(handler, predicates...)
-}
-
-// PreCheckoutQueryHandler handles pre checkout query that came from bot
-type PreCheckoutQueryHandler func(bot *telego.Bot, query telego.PreCheckoutQuery)
-
-// PreCheckoutQueryHandlerCtx handles pre checkout query that came from bot with context
-type PreCheckoutQueryHandlerCtx func(ctx context.Context, bot *telego.Bot, query telego.PreCheckoutQuery)
+// PreCheckoutQueryHandler handles pre-checkout query that came from bot
+type PreCheckoutQueryHandler func(ctx *Context, query telego.PreCheckoutQuery) error
-// HandlePreCheckoutQuery same as Handle, but assumes that the update contains a pre checkout query
+// HandlePreCheckoutQuery same as [BotHandler.Handle], but assumes that the update contains a pre-checkout query
func (h *HandlerGroup) HandlePreCheckoutQuery(handler PreCheckoutQueryHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil pre checkout query handlers not allowed")
- }
-
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.PreCheckoutQuery)
- }, append([]Predicate{AnyPreCheckoutQuery()}, predicates...)...)
-}
-
-// HandlePreCheckoutQueryCtx same as Handle, but assumes that the update contains a pre checkout query
-func (h *HandlerGroup) HandlePreCheckoutQueryCtx(handler PreCheckoutQueryHandlerCtx, predicates ...Predicate) {
- if handler == nil {
- panic("Telego: nil pre checkout query handlers not allowed")
+ panic("Telego: nil pre-checkout query handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.PreCheckoutQuery)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.PreCheckoutQuery)
}, append([]Predicate{AnyPreCheckoutQuery()}, predicates...)...)
}
-// HandlePreCheckoutQuery same as Handle, but assumes that the update contains a pre checkout query
+// HandlePreCheckoutQuery same as [BotHandler.Handle], but assumes that the update contains a pre-checkout query
func (h *BotHandler) HandlePreCheckoutQuery(handler PreCheckoutQueryHandler, predicates ...Predicate) {
h.baseGroup.HandlePreCheckoutQuery(handler, predicates...)
}
-// HandlePreCheckoutQueryCtx same as Handle, but assumes that the update contains a pre checkout query
-func (h *BotHandler) HandlePreCheckoutQueryCtx(handler PreCheckoutQueryHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandlePreCheckoutQueryCtx(handler, predicates...)
-}
-
-// PollHandler handles poll that came from bot
-type PollHandler func(bot *telego.Bot, poll telego.Poll)
-
-// PollHandlerCtx handles poll that came from bot with context
-type PollHandlerCtx func(ctx context.Context, bot *telego.Bot, poll telego.Poll)
+// PurchasedPaidMediaHandler handles purchased paid media that came from bot
+type PurchasedPaidMediaHandler func(ctx *Context, purchase telego.PaidMediaPurchased) error
-// HandlePoll same as Handle, but assumes that the update contains a poll
-func (h *HandlerGroup) HandlePoll(handler PollHandler, predicates ...Predicate) {
+// HandlePurchasedPaidMedia same as [BotHandler.Handle], but assumes that the update contains a purchased paid media
+func (h *HandlerGroup) HandlePurchasedPaidMedia(handler PurchasedPaidMediaHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil poll handlers not allowed")
+ panic("Telego: nil purchased paid media handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.Poll)
- }, append([]Predicate{AnyPoll()}, predicates...)...)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.PurchasedPaidMedia)
+ }, append([]Predicate{AnyPurchasedPaidMedia()}, predicates...)...)
+}
+
+// HandlePurchasedPaidMedia same as [BotHandler.Handle], but assumes that the update contains a pre-checkout query
+func (h *BotHandler) HandlePurchasedPaidMedia(handler PurchasedPaidMediaHandler, predicates ...Predicate) {
+ h.baseGroup.HandlePurchasedPaidMedia(handler, predicates...)
}
-// HandlePollCtx same as Handle, but assumes that the update contains a poll
-func (h *HandlerGroup) HandlePollCtx(handler PollHandlerCtx, predicates ...Predicate) {
+// PollHandler handles poll that came from bot
+type PollHandler func(ctx *Context, poll telego.Poll) error
+
+// HandlePoll same as [BotHandler.Handle], but assumes that the update contains a poll
+func (h *HandlerGroup) HandlePoll(handler PollHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil poll handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.Poll)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.Poll)
}, append([]Predicate{AnyPoll()}, predicates...)...)
}
-// HandlePoll same as Handle, but assumes that the update contains a poll
+// HandlePoll same as [BotHandler.Handle], but assumes that the update contains a poll
func (h *BotHandler) HandlePoll(handler PollHandler, predicates ...Predicate) {
h.baseGroup.HandlePoll(handler, predicates...)
}
-// HandlePollCtx same as Handle, but assumes that the update contains a poll
-func (h *BotHandler) HandlePollCtx(handler PollHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandlePollCtx(handler, predicates...)
-}
-
// PollAnswerHandler handles poll answer that came from bot
-type PollAnswerHandler func(bot *telego.Bot, answer telego.PollAnswer)
+type PollAnswerHandler func(ctx *Context, answer telego.PollAnswer) error
-// PollAnswerHandlerCtx handles poll answer that came from bot with context
-type PollAnswerHandlerCtx func(ctx context.Context, bot *telego.Bot, answer telego.PollAnswer)
-
-// HandlePollAnswer same as Handle, but assumes that the update contains a poll answer
+// HandlePollAnswer same as [BotHandler.Handle], but assumes that the update contains a poll answer
func (h *HandlerGroup) HandlePollAnswer(handler PollAnswerHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil poll answer handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.PollAnswer)
- }, append([]Predicate{AnyPollAnswer()}, predicates...)...)
-}
-
-// HandlePollAnswerCtx same as Handle, but assumes that the update contains a poll answer
-func (h *HandlerGroup) HandlePollAnswerCtx(handler PollAnswerHandlerCtx, predicates ...Predicate) {
- if handler == nil {
- panic("Telego: nil poll answer handlers not allowed")
- }
-
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.PollAnswer)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.PollAnswer)
}, append([]Predicate{AnyPollAnswer()}, predicates...)...)
}
-// HandlePollAnswer same as Handle, but assumes that the update contains a poll answer
+// HandlePollAnswer same as [BotHandler.Handle], but assumes that the update contains a poll answer
func (h *BotHandler) HandlePollAnswer(handler PollAnswerHandler, predicates ...Predicate) {
h.baseGroup.HandlePollAnswer(handler, predicates...)
}
-// HandlePollAnswerCtx same as Handle, but assumes that the update contains a poll answer
-func (h *BotHandler) HandlePollAnswerCtx(handler PollAnswerHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandlePollAnswerCtx(handler, predicates...)
-}
-
// ChatMemberUpdatedHandler handles chat member that came from bot
-type ChatMemberUpdatedHandler func(bot *telego.Bot, chatMember telego.ChatMemberUpdated)
+type ChatMemberUpdatedHandler func(ctx *Context, chatMember telego.ChatMemberUpdated) error
-// ChatMemberUpdatedHandlerCtx handles chat member that came from bot with context
-type ChatMemberUpdatedHandlerCtx func(ctx context.Context, bot *telego.Bot, chatMember telego.ChatMemberUpdated)
-
-// HandleMyChatMemberUpdated same as Handle, but assumes that the update contains my chat member
+// HandleMyChatMemberUpdated same as [BotHandler.Handle], but assumes that the update contains my chat member
func (h *HandlerGroup) HandleMyChatMemberUpdated(handler ChatMemberUpdatedHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil my chat member update handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.MyChatMember)
- }, append([]Predicate{AnyMyChatMember()}, predicates...)...)
-}
-
-// HandleMyChatMemberUpdatedCtx same as Handle, but assumes that the update contains my chat member
-func (h *HandlerGroup) HandleMyChatMemberUpdatedCtx(handler ChatMemberUpdatedHandlerCtx, predicates ...Predicate) {
- if handler == nil {
- panic("Telego: nil my chat member update handlers not allowed")
- }
-
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.MyChatMember)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.MyChatMember)
}, append([]Predicate{AnyMyChatMember()}, predicates...)...)
}
-// HandleMyChatMemberUpdated same as Handle, but assumes that the update contains my chat member
+// HandleMyChatMemberUpdated same as [BotHandler.Handle], but assumes that the update contains my chat member
func (h *BotHandler) HandleMyChatMemberUpdated(handler ChatMemberUpdatedHandler, predicates ...Predicate) {
h.baseGroup.HandleMyChatMemberUpdated(handler, predicates...)
}
-// HandleMyChatMemberUpdatedCtx same as Handle, but assumes that the update contains my chat member
-func (h *BotHandler) HandleMyChatMemberUpdatedCtx(handler ChatMemberUpdatedHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleMyChatMemberUpdatedCtx(handler, predicates...)
-}
-
-// HandleChatMemberUpdated same as Handle, but assumes that the update contains chat member
+// HandleChatMemberUpdated same as [BotHandler.Handle], but assumes that the update contains chat member
func (h *HandlerGroup) HandleChatMemberUpdated(handler ChatMemberUpdatedHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil chat member update handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.ChatMember)
- }, append([]Predicate{AnyChatMember()}, predicates...)...)
-}
-
-// HandleChatMemberUpdatedCtx same as Handle, but assumes that the update contains chat member
-func (h *HandlerGroup) HandleChatMemberUpdatedCtx(handler ChatMemberUpdatedHandlerCtx, predicates ...Predicate) {
- if handler == nil {
- panic("Telego: nil chat member update handlers not allowed")
- }
-
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.ChatMember)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.ChatMember)
}, append([]Predicate{AnyChatMember()}, predicates...)...)
}
-// HandleChatMemberUpdated same as Handle, but assumes that the update contains chat member
+// HandleChatMemberUpdated same as [BotHandler.Handle], but assumes that the update contains chat member
func (h *BotHandler) HandleChatMemberUpdated(handler ChatMemberUpdatedHandler, predicates ...Predicate) {
h.baseGroup.HandleChatMemberUpdated(handler, predicates...)
}
-// HandleChatMemberUpdatedCtx same as Handle, but assumes that the update contains chat member
-func (h *BotHandler) HandleChatMemberUpdatedCtx(handler ChatMemberUpdatedHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleChatMemberUpdatedCtx(handler, predicates...)
-}
-
// ChatJoinRequestHandler handles chat join request that came from bot
-type ChatJoinRequestHandler func(bot *telego.Bot, request telego.ChatJoinRequest)
-
-// ChatJoinRequestHandlerCtx handles chat join request that came from bot with context
-type ChatJoinRequestHandlerCtx func(ctx context.Context, bot *telego.Bot, request telego.ChatJoinRequest)
+type ChatJoinRequestHandler func(ctx *Context, request telego.ChatJoinRequest) error
-// HandleChatJoinRequest same as Handle, but assumes that the update contains chat join request
+// HandleChatJoinRequest same as [BotHandler.Handle], but assumes that the update contains chat join request
func (h *HandlerGroup) HandleChatJoinRequest(handler ChatJoinRequestHandler, predicates ...Predicate) {
if handler == nil {
panic("Telego: nil chat join request handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(bot, *update.ChatJoinRequest)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.ChatJoinRequest)
}, append([]Predicate{AnyChatJoinRequest()}, predicates...)...)
}
-// HandleChatJoinRequestCtx same as Handle, but assumes that the update contains chat join request
-func (h *HandlerGroup) HandleChatJoinRequestCtx(handler ChatJoinRequestHandlerCtx, predicates ...Predicate) {
+// HandleChatJoinRequest same as [BotHandler.Handle], but assumes that the update contains chat join request
+func (h *BotHandler) HandleChatJoinRequest(handler ChatJoinRequestHandler, predicates ...Predicate) {
+ h.baseGroup.HandleChatJoinRequest(handler, predicates...)
+}
+
+// ChatBoostHandler handles chat boost that came from bot
+type ChatBoostHandler func(ctx *Context, boost telego.ChatBoostUpdated) error
+
+// HandleChatBoost same as [BotHandler.Handle], but assumes that the update contains chat boost
+func (h *HandlerGroup) HandleChatBoost(handler ChatBoostHandler, predicates ...Predicate) {
if handler == nil {
- panic("Telego: nil chat join request handlers not allowed")
+ panic("Telego: nil chat boost handlers not allowed")
}
- h.Handle(func(bot *telego.Bot, update telego.Update) {
- handler(update.Context(), bot, *update.ChatJoinRequest)
- }, append([]Predicate{AnyChatJoinRequest()}, predicates...)...)
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.ChatBoost)
+ }, append([]Predicate{AnyChatBoost()}, predicates...)...)
}
-// HandleChatJoinRequest same as Handle, but assumes that the update contains chat join request
-func (h *BotHandler) HandleChatJoinRequest(handler ChatJoinRequestHandler, predicates ...Predicate) {
- h.baseGroup.HandleChatJoinRequest(handler, predicates...)
+// HandleChatBoost same as [BotHandler.Handle], but assumes that the update contains chat boost
+func (h *BotHandler) HandleChatBoost(handler ChatBoostHandler, predicates ...Predicate) {
+ h.baseGroup.HandleChatBoost(handler, predicates...)
+}
+
+// RemovedChatBoostHandler handles removed chat boost that came from bot
+type RemovedChatBoostHandler func(ctx *Context, removedBoost telego.ChatBoostRemoved) error
+
+// HandleRemovedChatBoost same as [BotHandler.Handle], but assumes that the update contains removed chat boost
+func (h *HandlerGroup) HandleRemovedChatBoost(handler RemovedChatBoostHandler, predicates ...Predicate) {
+ if handler == nil {
+ panic("Telego: nil removed chat boost handlers not allowed")
+ }
+
+ h.Handle(func(ctx *Context, update telego.Update) error {
+ return handler(ctx, *update.RemovedChatBoost)
+ }, append([]Predicate{AnyRemovedChatBoost()}, predicates...)...)
}
-// HandleChatJoinRequestCtx same as Handle, but assumes that the update contains chat join request
-func (h *BotHandler) HandleChatJoinRequestCtx(handler ChatJoinRequestHandlerCtx, predicates ...Predicate) {
- h.baseGroup.HandleChatJoinRequestCtx(handler, predicates...)
+// HandleRemovedChatBoost same as [BotHandler.Handle], but assumes that the update contains removed chat boost
+func (h *BotHandler) HandleRemovedChatBoost(handler RemovedChatBoostHandler, predicates ...Predicate) {
+ h.baseGroup.HandleRemovedChatBoost(handler, predicates...)
}
diff --git a/telegohandler/handlers_test.go b/telegohandler/handlers_test.go
index bde918bc..18ff5cbe 100644
--- a/telegohandler/handlers_test.go
+++ b/telegohandler/handlers_test.go
@@ -1,11 +1,11 @@
package telegohandler
import (
- "context"
"sync"
"testing"
"time"
+ "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mymmrac/telego"
@@ -19,7 +19,10 @@ func testHandler(t *testing.T, bh *BotHandler, wg *sync.WaitGroup) {
timeoutSignal := time.After(timeout)
done := make(chan struct{})
- go bh.Start()
+ go func() {
+ errStart := bh.Start()
+ assert.NoError(t, errStart)
+ }()
go func() {
wg.Wait()
@@ -31,16 +34,17 @@ func testHandler(t *testing.T, bh *BotHandler, wg *sync.WaitGroup) {
t.Fatal("Timeout")
case <-done:
}
- bh.Stop()
+ err := bh.Stop()
+ assert.NoError(t, err)
}
func testHandlerSetup(t *testing.T, bh *BotHandler) {
t.Helper()
- require.Len(t, bh.baseGroup.handlers, 1)
- require.NotNil(t, bh.baseGroup.handlers[0].handler)
- require.NotNil(t, bh.baseGroup.handlers[0].predicates)
- require.Len(t, bh.baseGroup.handlers[0].predicates, 1)
+ require.Len(t, bh.baseGroup.routes, 1)
+ require.NotNil(t, bh.baseGroup.routes[0].handler)
+ require.NotNil(t, bh.baseGroup.routes[0].predicates)
+ require.Len(t, bh.baseGroup.routes[0].predicates, 1)
}
func TestBotHandler_HandleMessage(t *testing.T) {
@@ -49,7 +53,7 @@ func TestBotHandler_HandleMessage(t *testing.T) {
require.Panics(t, func() { bh.HandleMessage(nil) })
wg := &sync.WaitGroup{}
- handler := MessageHandler(func(_ *telego.Bot, _ telego.Message) { wg.Done() })
+ handler := MessageHandler(func(_ *Context, _ telego.Message) error { wg.Done(); return nil })
bh.HandleMessage(handler)
testHandlerSetup(t, bh)
@@ -61,31 +65,13 @@ func TestBotHandler_HandleMessage(t *testing.T) {
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleMessageCtx(t *testing.T) {
- bh := newTestBotHandler(t)
-
- require.Panics(t, func() { bh.HandleMessageCtx(nil) })
-
- wg := &sync.WaitGroup{}
- handler := MessageHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.Message) { wg.Done() })
-
- bh.HandleMessageCtx(handler)
- testHandlerSetup(t, bh)
-
- updates := make(chan telego.Update, 1)
- updates <- telego.Update{Message: &telego.Message{}}
-
- bh.updates = updates
- testHandler(t, bh, wg)
-}
-
func TestBotHandler_HandleEditedMessage(t *testing.T) {
bh := newTestBotHandler(t)
require.Panics(t, func() { bh.HandleEditedMessage(nil) })
wg := &sync.WaitGroup{}
- handler := MessageHandler(func(_ *telego.Bot, _ telego.Message) { wg.Done() })
+ handler := MessageHandler(func(_ *Context, _ telego.Message) error { wg.Done(); return nil })
bh.HandleEditedMessage(handler)
testHandlerSetup(t, bh)
@@ -97,31 +83,13 @@ func TestBotHandler_HandleEditedMessage(t *testing.T) {
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleEditedMessageCtx(t *testing.T) {
- bh := newTestBotHandler(t)
-
- require.Panics(t, func() { bh.HandleEditedMessageCtx(nil) })
-
- wg := &sync.WaitGroup{}
- handler := MessageHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.Message) { wg.Done() })
-
- bh.HandleEditedMessageCtx(handler)
- testHandlerSetup(t, bh)
-
- updates := make(chan telego.Update, 1)
- updates <- telego.Update{EditedMessage: &telego.Message{}}
-
- bh.updates = updates
- testHandler(t, bh, wg)
-}
-
func TestBotHandler_HandleChannelPost(t *testing.T) {
bh := newTestBotHandler(t)
require.Panics(t, func() { bh.HandleChannelPost(nil) })
wg := &sync.WaitGroup{}
- handler := MessageHandler(func(_ *telego.Bot, _ telego.Message) { wg.Done() })
+ handler := MessageHandler(func(_ *Context, _ telego.Message) error { wg.Done(); return nil })
bh.HandleChannelPost(handler)
testHandlerSetup(t, bh)
@@ -133,197 +101,204 @@ func TestBotHandler_HandleChannelPost(t *testing.T) {
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleChannelPostCtx(t *testing.T) {
+func TestBotHandler_HandleEditedChannelPost(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleChannelPostCtx(nil) })
+ require.Panics(t, func() { bh.HandleEditedChannelPost(nil) })
wg := &sync.WaitGroup{}
- handler := MessageHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.Message) { wg.Done() })
+ handler := MessageHandler(func(_ *Context, _ telego.Message) error { wg.Done(); return nil })
- bh.HandleChannelPostCtx(handler)
+ bh.HandleEditedChannelPost(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{ChannelPost: &telego.Message{}}
+ updates <- telego.Update{EditedChannelPost: &telego.Message{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleEditedChannelPost(t *testing.T) {
+func TestBotHandler_HandleBusinessConnection(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleEditedChannelPost(nil) })
+ require.Panics(t, func() { bh.HandleBusinessConnection(nil) })
wg := &sync.WaitGroup{}
- handler := MessageHandler(func(_ *telego.Bot, _ telego.Message) { wg.Done() })
+ handler := BusinessConnectionHandler(func(_ *Context, _ telego.BusinessConnection) error { wg.Done(); return nil })
- bh.HandleEditedChannelPost(handler)
+ bh.HandleBusinessConnection(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{EditedChannelPost: &telego.Message{}}
+ updates <- telego.Update{BusinessConnection: &telego.BusinessConnection{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleEditedChannelPostCtx(t *testing.T) {
+func TestBotHandler_HandleBusinessMessage(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleEditedChannelPostCtx(nil) })
+ require.Panics(t, func() { bh.HandleBusinessMessage(nil) })
wg := &sync.WaitGroup{}
- handler := MessageHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.Message) { wg.Done() })
+ handler := MessageHandler(func(_ *Context, _ telego.Message) error { wg.Done(); return nil })
- bh.HandleEditedChannelPostCtx(handler)
+ bh.HandleBusinessMessage(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{EditedChannelPost: &telego.Message{}}
+ updates <- telego.Update{BusinessMessage: &telego.Message{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleInlineQuery(t *testing.T) {
+func TestBotHandler_HandleEditedBusinessMessage(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleInlineQuery(nil) })
+ require.Panics(t, func() { bh.HandleEditedBusinessMessage(nil) })
wg := &sync.WaitGroup{}
- handler := InlineQueryHandler(func(_ *telego.Bot, _ telego.InlineQuery) { wg.Done() })
+ handler := MessageHandler(func(_ *Context, _ telego.Message) error { wg.Done(); return nil })
- bh.HandleInlineQuery(handler)
+ bh.HandleEditedBusinessMessage(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{InlineQuery: &telego.InlineQuery{}}
+ updates <- telego.Update{EditedBusinessMessage: &telego.Message{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleInlineQueryCtx(t *testing.T) {
+func TestBotHandler_HandleDeletedBusinessMessages(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleInlineQueryCtx(nil) })
+ require.Panics(t, func() { bh.HandleDeletedBusinessMessages(nil) })
wg := &sync.WaitGroup{}
- handler := InlineQueryHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.InlineQuery) { wg.Done() })
+ handler := DeletedBusinessMessagesHandler(func(_ *Context, _ telego.BusinessMessagesDeleted) error {
+ wg.Done()
+ return nil
+ })
- bh.HandleInlineQueryCtx(handler)
+ bh.HandleDeletedBusinessMessages(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{InlineQuery: &telego.InlineQuery{}}
+ updates <- telego.Update{DeletedBusinessMessages: &telego.BusinessMessagesDeleted{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleChosenInlineResult(t *testing.T) {
+func TestBotHandler_HandleMessageReaction(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleChosenInlineResult(nil) })
+ require.Panics(t, func() { bh.HandleMessageReaction(nil) })
wg := &sync.WaitGroup{}
- handler := ChosenInlineResultHandler(func(_ *telego.Bot, _ telego.ChosenInlineResult) { wg.Done() })
+ handler := MessageReactionHandler(func(_ *Context, _ telego.MessageReactionUpdated) error { wg.Done(); return nil })
- bh.HandleChosenInlineResult(handler)
+ bh.HandleMessageReaction(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{ChosenInlineResult: &telego.ChosenInlineResult{}}
+ updates <- telego.Update{MessageReaction: &telego.MessageReactionUpdated{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleChosenInlineResultCtx(t *testing.T) {
+func TestBotHandler_HandleMessageReactionCount(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleChosenInlineResultCtx(nil) })
+ require.Panics(t, func() { bh.HandleMessageReactionCount(nil) })
wg := &sync.WaitGroup{}
- handler := ChosenInlineResultHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.ChosenInlineResult) {
+ handler := MessageReactionCountHandler(func(_ *Context, _ telego.MessageReactionCountUpdated) error {
wg.Done()
+ return nil
})
- bh.HandleChosenInlineResultCtx(handler)
+ bh.HandleMessageReactionCount(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{ChosenInlineResult: &telego.ChosenInlineResult{}}
+ updates <- telego.Update{MessageReactionCount: &telego.MessageReactionCountUpdated{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleCallbackQuery(t *testing.T) {
+func TestBotHandler_HandleInlineQuery(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleCallbackQuery(nil) })
+ require.Panics(t, func() { bh.HandleInlineQuery(nil) })
wg := &sync.WaitGroup{}
- handler := CallbackQueryHandler(func(_ *telego.Bot, _ telego.CallbackQuery) { wg.Done() })
+ handler := InlineQueryHandler(func(_ *Context, _ telego.InlineQuery) error { wg.Done(); return nil })
- bh.HandleCallbackQuery(handler)
+ bh.HandleInlineQuery(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{CallbackQuery: &telego.CallbackQuery{}}
+ updates <- telego.Update{InlineQuery: &telego.InlineQuery{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleCallbackQueryCtx(t *testing.T) {
+func TestBotHandler_HandleChosenInlineResult(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleCallbackQueryCtx(nil) })
+ require.Panics(t, func() { bh.HandleChosenInlineResult(nil) })
wg := &sync.WaitGroup{}
- handler := CallbackQueryHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.CallbackQuery) { wg.Done() })
+ handler := ChosenInlineResultHandler(func(_ *Context, _ telego.ChosenInlineResult) error {
+ wg.Done()
+ return nil
+ })
- bh.HandleCallbackQueryCtx(handler)
+ bh.HandleChosenInlineResult(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{CallbackQuery: &telego.CallbackQuery{}}
+ updates <- telego.Update{ChosenInlineResult: &telego.ChosenInlineResult{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleShippingQuery(t *testing.T) {
+func TestBotHandler_HandleCallbackQuery(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleShippingQuery(nil) })
+ require.Panics(t, func() { bh.HandleCallbackQuery(nil) })
wg := &sync.WaitGroup{}
- handler := ShippingQueryHandler(func(_ *telego.Bot, _ telego.ShippingQuery) { wg.Done() })
+ handler := CallbackQueryHandler(func(_ *Context, _ telego.CallbackQuery) error { wg.Done(); return nil })
- bh.HandleShippingQuery(handler)
+ bh.HandleCallbackQuery(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{ShippingQuery: &telego.ShippingQuery{}}
+ updates <- telego.Update{CallbackQuery: &telego.CallbackQuery{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleShippingQueryCtx(t *testing.T) {
+func TestBotHandler_HandleShippingQuery(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleShippingQueryCtx(nil) })
+ require.Panics(t, func() { bh.HandleShippingQuery(nil) })
wg := &sync.WaitGroup{}
- handler := ShippingQueryHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.ShippingQuery) { wg.Done() })
+ handler := ShippingQueryHandler(func(_ *Context, _ telego.ShippingQuery) error { wg.Done(); return nil })
- bh.HandleShippingQueryCtx(handler)
+ bh.HandleShippingQuery(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
@@ -339,7 +314,10 @@ func TestBotHandler_HandlePreCheckoutQuery(t *testing.T) {
require.Panics(t, func() { bh.HandlePreCheckoutQuery(nil) })
wg := &sync.WaitGroup{}
- handler := PreCheckoutQueryHandler(func(_ *telego.Bot, _ telego.PreCheckoutQuery) { wg.Done() })
+ handler := PreCheckoutQueryHandler(func(_ *Context, _ telego.PreCheckoutQuery) error {
+ wg.Done()
+ return nil
+ })
bh.HandlePreCheckoutQuery(handler)
testHandlerSetup(t, bh)
@@ -351,21 +329,22 @@ func TestBotHandler_HandlePreCheckoutQuery(t *testing.T) {
testHandler(t, bh, wg)
}
-func TestBotHandler_HandlePreCheckoutQueryCtx(t *testing.T) {
+func TestBotHandler_HandlePurchasedPaidMedia(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandlePreCheckoutQueryCtx(nil) })
+ require.Panics(t, func() { bh.HandlePurchasedPaidMedia(nil) })
wg := &sync.WaitGroup{}
- handler := PreCheckoutQueryHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.PreCheckoutQuery) {
+ handler := PurchasedPaidMediaHandler(func(_ *Context, _ telego.PaidMediaPurchased) error {
wg.Done()
+ return nil
})
- bh.HandlePreCheckoutQueryCtx(handler)
+ bh.HandlePurchasedPaidMedia(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{PreCheckoutQuery: &telego.PreCheckoutQuery{}}
+ updates <- telego.Update{PurchasedPaidMedia: &telego.PaidMediaPurchased{}}
bh.updates = updates
testHandler(t, bh, wg)
@@ -377,7 +356,7 @@ func TestBotHandler_HandlePoll(t *testing.T) {
require.Panics(t, func() { bh.HandlePoll(nil) })
wg := &sync.WaitGroup{}
- handler := PollHandler(func(_ *telego.Bot, _ telego.Poll) { wg.Done() })
+ handler := PollHandler(func(_ *Context, _ telego.Poll) error { wg.Done(); return nil })
bh.HandlePoll(handler)
testHandlerSetup(t, bh)
@@ -389,31 +368,13 @@ func TestBotHandler_HandlePoll(t *testing.T) {
testHandler(t, bh, wg)
}
-func TestBotHandler_HandlePollCtx(t *testing.T) {
- bh := newTestBotHandler(t)
-
- require.Panics(t, func() { bh.HandlePollCtx(nil) })
-
- wg := &sync.WaitGroup{}
- handler := PollHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.Poll) { wg.Done() })
-
- bh.HandlePollCtx(handler)
- testHandlerSetup(t, bh)
-
- updates := make(chan telego.Update, 1)
- updates <- telego.Update{Poll: &telego.Poll{}}
-
- bh.updates = updates
- testHandler(t, bh, wg)
-}
-
func TestBotHandler_HandlePollAnswer(t *testing.T) {
bh := newTestBotHandler(t)
require.Panics(t, func() { bh.HandlePollAnswer(nil) })
wg := &sync.WaitGroup{}
- handler := PollAnswerHandler(func(_ *telego.Bot, _ telego.PollAnswer) { wg.Done() })
+ handler := PollAnswerHandler(func(_ *Context, _ telego.PollAnswer) error { wg.Done(); return nil })
bh.HandlePollAnswer(handler)
testHandlerSetup(t, bh)
@@ -425,56 +386,18 @@ func TestBotHandler_HandlePollAnswer(t *testing.T) {
testHandler(t, bh, wg)
}
-func TestBotHandler_HandlePollAnswerCtx(t *testing.T) {
- bh := newTestBotHandler(t)
-
- require.Panics(t, func() { bh.HandlePollAnswerCtx(nil) })
-
- wg := &sync.WaitGroup{}
- handler := PollAnswerHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.PollAnswer) { wg.Done() })
-
- bh.HandlePollAnswerCtx(handler)
- testHandlerSetup(t, bh)
-
- updates := make(chan telego.Update, 1)
- updates <- telego.Update{PollAnswer: &telego.PollAnswer{}}
-
- bh.updates = updates
- testHandler(t, bh, wg)
-}
-
func TestBotHandler_HandleMyChatMemberUpdated(t *testing.T) {
bh := newTestBotHandler(t)
require.Panics(t, func() { bh.HandleMyChatMemberUpdated(nil) })
wg := &sync.WaitGroup{}
- handler := ChatMemberUpdatedHandler(func(_ *telego.Bot, _ telego.ChatMemberUpdated) { wg.Done() })
-
- bh.HandleMyChatMemberUpdated(handler)
- testHandlerSetup(t, bh)
-
- updates := make(chan telego.Update, 1)
- updates <- telego.Update{MyChatMember: &telego.ChatMemberUpdated{
- OldChatMember: &telego.ChatMemberMember{Status: telego.MemberStatusMember},
- NewChatMember: &telego.ChatMemberMember{Status: telego.MemberStatusMember},
- }}
-
- bh.updates = updates
- testHandler(t, bh, wg)
-}
-
-func TestBotHandler_HandleMyChatMemberUpdatedCtx(t *testing.T) {
- bh := newTestBotHandler(t)
-
- require.Panics(t, func() { bh.HandleMyChatMemberUpdatedCtx(nil) })
-
- wg := &sync.WaitGroup{}
- handler := ChatMemberUpdatedHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.ChatMemberUpdated) {
+ handler := ChatMemberUpdatedHandler(func(_ *Context, _ telego.ChatMemberUpdated) error {
wg.Done()
+ return nil
})
- bh.HandleMyChatMemberUpdatedCtx(handler)
+ bh.HandleMyChatMemberUpdated(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
@@ -493,7 +416,10 @@ func TestBotHandler_HandleChatMemberUpdated(t *testing.T) {
require.Panics(t, func() { bh.HandleChatMemberUpdated(nil) })
wg := &sync.WaitGroup{}
- handler := ChatMemberUpdatedHandler(func(_ *telego.Bot, _ telego.ChatMemberUpdated) { wg.Done() })
+ handler := ChatMemberUpdatedHandler(func(_ *Context, _ telego.ChatMemberUpdated) error {
+ wg.Done()
+ return nil
+ })
bh.HandleChatMemberUpdated(handler)
testHandlerSetup(t, bh)
@@ -508,60 +434,65 @@ func TestBotHandler_HandleChatMemberUpdated(t *testing.T) {
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleChatMemberUpdatedCtx(t *testing.T) {
+func TestBotHandler_HandleChatJoinRequest(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleChatMemberUpdatedCtx(nil) })
+ require.Panics(t, func() { bh.HandleChatJoinRequest(nil) })
wg := &sync.WaitGroup{}
- handler := ChatMemberUpdatedHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.ChatMemberUpdated) {
- wg.Done()
- })
+ handler := ChatJoinRequestHandler(func(_ *Context, _ telego.ChatJoinRequest) error { wg.Done(); return nil })
- bh.HandleChatMemberUpdatedCtx(handler)
+ bh.HandleChatJoinRequest(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{ChatMember: &telego.ChatMemberUpdated{
- OldChatMember: &telego.ChatMemberMember{Status: telego.MemberStatusMember},
- NewChatMember: &telego.ChatMemberMember{Status: telego.MemberStatusMember},
- }}
+ updates <- telego.Update{ChatJoinRequest: &telego.ChatJoinRequest{}}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleChatJoinRequest(t *testing.T) {
+func TestBotHandler_HandleChatBoost(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleChatJoinRequest(nil) })
+ require.Panics(t, func() { bh.HandleChatBoost(nil) })
wg := &sync.WaitGroup{}
- handler := ChatJoinRequestHandler(func(_ *telego.Bot, _ telego.ChatJoinRequest) { wg.Done() })
+ handler := ChatBoostHandler(func(_ *Context, _ telego.ChatBoostUpdated) error { wg.Done(); return nil })
- bh.HandleChatJoinRequest(handler)
+ bh.HandleChatBoost(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{ChatJoinRequest: &telego.ChatJoinRequest{}}
+ updates <- telego.Update{ChatBoost: &telego.ChatBoostUpdated{
+ Boost: telego.ChatBoost{
+ Source: &telego.ChatBoostSourcePremium{
+ Source: telego.BoostSourcePremium,
+ },
+ },
+ }}
bh.updates = updates
testHandler(t, bh, wg)
}
-func TestBotHandler_HandleChatJoinRequestCtx(t *testing.T) {
+func TestBotHandler_HandleRemovedChatBoost(t *testing.T) {
bh := newTestBotHandler(t)
- require.Panics(t, func() { bh.HandleChatJoinRequestCtx(nil) })
+ require.Panics(t, func() { bh.HandleRemovedChatBoost(nil) })
wg := &sync.WaitGroup{}
- handler := ChatJoinRequestHandlerCtx(func(_ context.Context, _ *telego.Bot, _ telego.ChatJoinRequest) { wg.Done() })
+ handler := RemovedChatBoostHandler(func(_ *Context, _ telego.ChatBoostRemoved) error { wg.Done(); return nil })
- bh.HandleChatJoinRequestCtx(handler)
+ bh.HandleRemovedChatBoost(handler)
testHandlerSetup(t, bh)
updates := make(chan telego.Update, 1)
- updates <- telego.Update{ChatJoinRequest: &telego.ChatJoinRequest{}}
+ updates <- telego.Update{RemovedChatBoost: &telego.ChatBoostRemoved{
+ Source: &telego.ChatBoostSourcePremium{
+ Source: telego.BoostSourcePremium,
+ },
+ }}
bh.updates = updates
testHandler(t, bh, wg)
diff --git a/telegohandler/middleware.go b/telegohandler/middleware.go
index 365f5e3a..c4f44dbe 100644
--- a/telegohandler/middleware.go
+++ b/telegohandler/middleware.go
@@ -1,7 +1,6 @@
package telegohandler
import (
- "context"
"time"
"github.com/mymmrac/telego"
@@ -9,27 +8,29 @@ import (
// PanicRecovery returns a middleware that will recover handler from panic
// Note: It's not recommend to ignore panics, use [PanicRecoveryHandler] instead to handle them
-func PanicRecovery() Middleware {
+func PanicRecovery() Handler {
return PanicRecoveryHandler(nil)
}
-// PanicRecoveryHandler returns a middleware that will recover handler from panic and call panic handler
-func PanicRecoveryHandler(panicHandler func(recovered any)) Middleware {
- return func(bot *telego.Bot, update telego.Update, next Handler) {
+// PanicRecoveryHandler returns a middleware that will recover handler from panic and call panic handler.
+// Error returned from panic handler will be returned as handler error, if panic handler is nil, panic will be ignored
+// (not recommended, try to always handle panics).
+func PanicRecoveryHandler(panicHandler func(recovered any) error) Handler {
+ return func(ctx *Context, update telego.Update) (err error) {
defer func() {
if recovered := recover(); recovered != nil && panicHandler != nil {
- panicHandler(recovered)
+ err = panicHandler(recovered)
}
}()
- next(bot, update)
+ return ctx.Next(update)
}
}
// Timeout returns a middleware that will add timeout to context
-func Timeout(timeout time.Duration) Middleware {
- return func(bot *telego.Bot, update telego.Update, next Handler) {
- ctx, cancel := context.WithTimeout(update.Context(), timeout)
- next(bot, update.WithContext(ctx))
- cancel()
+func Timeout(timeout time.Duration) Handler {
+ return func(ctx *Context, update telego.Update) error {
+ ctx, cancel := ctx.WithTimeout(timeout)
+ defer cancel()
+ return ctx.Next(update)
}
}
diff --git a/telegohandler/middleware_test.go b/telegohandler/middleware_test.go
index 49bdb336..aed6d43e 100644
--- a/telegohandler/middleware_test.go
+++ b/telegohandler/middleware_test.go
@@ -1,6 +1,7 @@
package telegohandler
import (
+ "context"
"testing"
"time"
@@ -11,34 +12,56 @@ import (
)
func TestPanicRecovery(t *testing.T) {
- bot, err := telego.NewBot(token, telego.WithDiscardLogger())
- require.NoError(t, err)
-
t.Run("no_panic", func(t *testing.T) {
assert.NotPanics(t, func() {
- PanicRecovery()(bot, telego.Update{}, func(bot *telego.Bot, update telego.Update) {})
+ err := PanicRecovery()(nil, telego.Update{})
+ assert.NoError(t, err)
})
})
- t.Run("panic_recovered", func(t *testing.T) {
- const panicValue = "test panic"
+ t.Run("panic_recovered_no_error", func(t *testing.T) {
assert.NotPanics(t, func() {
- PanicRecoveryHandler(func(recovered any) {
- assert.Equal(t, panicValue, recovered)
- })(bot, telego.Update{}, func(bot *telego.Bot, update telego.Update) {
- panic(panicValue)
- })
+ err := PanicRecoveryHandler(func(recovered any) error {
+ assert.NotNil(t, recovered)
+ return nil
+ })(nil, telego.Update{})
+ assert.NoError(t, err)
+ })
+ })
+
+ t.Run("panic_recovered_error", func(t *testing.T) {
+ assert.NotPanics(t, func() {
+ err := PanicRecoveryHandler(func(recovered any) error {
+ assert.NotNil(t, recovered)
+ return errTest
+ })(nil, telego.Update{})
+ assert.ErrorIs(t, err, errTest)
})
})
}
func TestTimeout(t *testing.T) {
- bot, err := telego.NewBot(token, telego.WithDiscardLogger())
- require.NoError(t, err)
+ run := false
+ ctx := &Context{
+ ctx: context.Background(),
+ ctxBase: &ctxBase{
+ group: &HandlerGroup{
+ routes: []route{
+ {
+ handler: func(ctx *Context, update telego.Update) error {
+ _, hasDeadline := ctx.Deadline()
+ assert.True(t, hasDeadline)
+ run = true
+ return nil
+ },
+ },
+ },
+ },
+ stack: []int{-1},
+ },
+ }
- hasDeadline := false
- Timeout(time.Minute)(bot, telego.Update{}, func(bot *telego.Bot, update telego.Update) {
- _, hasDeadline = update.Context().Deadline()
- })
- assert.True(t, hasDeadline)
+ err := Timeout(time.Minute)(ctx, telego.Update{})
+ require.NoError(t, err)
+ assert.True(t, run)
}
diff --git a/telegohandler/predicates.go b/telegohandler/predicates.go
index 0df47080..b56feee0 100644
--- a/telegohandler/predicates.go
+++ b/telegohandler/predicates.go
@@ -1,6 +1,7 @@
package telegohandler
import (
+ "context"
"regexp"
"strings"
@@ -9,23 +10,23 @@ import (
// Any is always true
func Any() Predicate {
- return func(_ telego.Update) bool {
+ return func(_ context.Context, _ telego.Update) bool {
return true
}
}
// None is always false
func None() Predicate {
- return func(_ telego.Update) bool {
+ return func(_ context.Context, _ telego.Update) bool {
return false
}
}
// And is true if all the predicates are true
func And(predicates ...Predicate) Predicate {
- return func(update telego.Update) bool {
+ return func(ctx context.Context, update telego.Update) bool {
for _, p := range predicates {
- if !p(update) {
+ if !p(ctx, update) {
return false
}
}
@@ -35,9 +36,9 @@ func And(predicates ...Predicate) Predicate {
// Or is true if at least one of the predicates is true
func Or(predicates ...Predicate) Predicate {
- return func(update telego.Update) bool {
+ return func(ctx context.Context, update telego.Update) bool {
for _, p := range predicates {
- if p(update) {
+ if p(ctx, update) {
return true
}
}
@@ -45,17 +46,10 @@ func Or(predicates ...Predicate) Predicate {
}
}
-// Union is true if at least one of the predicates is true
-//
-// Deprecated: Use [Or] predicate instead
-func Union(predicates ...Predicate) Predicate {
- return Or(predicates...)
-}
-
// Not is true if predicate is false
func Not(predicate Predicate) Predicate {
- return func(update telego.Update) bool {
- return !predicate(update)
+ return func(ctx context.Context, update telego.Update) bool {
+ return !predicate(ctx, update)
}
}
@@ -65,7 +59,7 @@ func anyMassage(message *telego.Message) bool {
// AnyMessage is true if the message isn't nil
func AnyMessage() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassage(update.Message)
}
}
@@ -76,7 +70,7 @@ func anyMassageWithText(message *telego.Message) bool {
// AnyMessageWithText is true if the message isn't nil and its text is not empty
func AnyMessageWithText() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithText(update.Message)
}
}
@@ -87,7 +81,7 @@ func anyMassageWithFrom(message *telego.Message) bool {
// AnyMessageWithFrom is true if the message isn't nil and its from (sender) is not nil
func AnyMessageWithFrom() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithFrom(update.Message)
}
}
@@ -98,7 +92,7 @@ func baseTextEqual(message *telego.Message, text string) bool {
// TextEqual is true if the message isn't nil, and its text is equal to the specified text
func TextEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextEqual(update.Message, text)
}
}
@@ -110,7 +104,7 @@ func baseTextEqualFold(message *telego.Message, text string) bool {
// TextEqualFold is true if the message isn't nil, and its text equal fold (more general form of case-insensitivity
// equal) to the specified text
func TextEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextEqualFold(update.Message, text)
}
}
@@ -121,7 +115,7 @@ func baseTextContains(message *telego.Message, text string) bool {
// TextContains is true if the message isn't nil, and its text contains specified text
func TextContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextContains(update.Message, text)
}
}
@@ -132,7 +126,7 @@ func baseTextPrefix(message *telego.Message, prefix string) bool {
// TextPrefix is true if the message isn't nil, and its text has specified prefix
func TextPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextPrefix(update.Message, prefix)
}
}
@@ -143,7 +137,7 @@ func baseTextSuffix(message *telego.Message, suffix string) bool {
// TextSuffix is true if the message isn't nil, and its text has specified suffix
func TextSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextSuffix(update.Message, suffix)
}
}
@@ -154,13 +148,13 @@ func baseTextMatches(message *telego.Message, pattern *regexp.Regexp) bool {
// TextMatches is true if the message isn't nil, and its text matches specified regexp
func TextMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextMatches(update.Message, pattern)
}
}
// CommandRegexp matches to command and has match groups on command, bot username and arguments
-var CommandRegexp = regexp.MustCompile(`(?s)^/(\w+)(@\w+)?(?:\s+(.+?)\s*)?$`)
+var CommandRegexp = regexp.MustCompile(`(?s)^/(\w+)(?:@(\w+))?(?:\s+(.+?)\s*)?$`)
// Command match group indexes in the [CommandRegexp]
const (
@@ -174,14 +168,35 @@ const CommandMatchGroupsLen = 4
// AnyCommand is true if the message isn't nil, and it matches to command regexp
func AnyCommand() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.Message != nil && CommandRegexp.MatchString(update.Message.Text)
}
}
+// AnyCommandToMe is true if the message isn't nil, and it matches to command regexp, and the message either in
+// private chat, or it contains bot's username or reply to bot's message
+// Note: It's better to use Group Privacy Mode (https://core.telegram.org/bots/features#privacy-mode) instead
+func AnyCommandToMe(botUsername string) Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ if update.Message == nil {
+ return false
+ }
+
+ matches := CommandRegexp.FindStringSubmatch(update.Message.Text)
+ if len(matches) != CommandMatchGroupsLen {
+ return false
+ }
+
+ return update.Message.Chat.Type == telego.ChatTypePrivate ||
+ strings.EqualFold(matches[CommandMatchBotUsernameGroup], botUsername) ||
+ (update.Message.ReplyToMessage != nil && update.Message.ReplyToMessage.From != nil &&
+ strings.EqualFold(update.Message.ReplyToMessage.From.Username, botUsername))
+ }
+}
+
// CommandEqual is true if the message isn't nil, and it contains specified command
func CommandEqual(command string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
if update.Message == nil {
return false
}
@@ -197,7 +212,7 @@ func CommandEqual(command string) Predicate {
// CommandEqualArgc is true if the message isn't nil, and it contains specified command with a number of args
func CommandEqualArgc(command string, argc int) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
if update.Message == nil {
return false
}
@@ -215,7 +230,7 @@ func CommandEqualArgc(command string, argc int) Predicate {
// CommandEqualArgv is true if the message isn't nil, and it contains specified command and args
func CommandEqualArgv(command string, argv ...string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
if update.Message == nil {
return false
}
@@ -233,35 +248,35 @@ func CommandEqualArgv(command string, argv ...string) Predicate {
// SuccessPayment is true if the message isn't nil, and contains success payment
func SuccessPayment() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.Message != nil && update.Message.SuccessfulPayment != nil
}
}
// AnyEditedMessage is true if the edited message isn't nil
func AnyEditedMessage() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassage(update.EditedMessage)
}
}
// AnyEditedMessageWithText is true if the edited message isn't nil and its text is not empty
func AnyEditedMessageWithText() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithText(update.EditedMessage)
}
}
// AnyEditedMessageWithFrom is true if the edited message isn't nil and its from (sender) is not nil
func AnyEditedMessageWithFrom() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithFrom(update.EditedMessage)
}
}
// EditedTextEqual is true if the edited message isn't nil, and its text equals to the specified text
func EditedTextEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextEqual(update.EditedMessage, text)
}
}
@@ -269,56 +284,56 @@ func EditedTextEqual(text string) Predicate {
// EditedTextEqualFold is true if the edited message isn't nil, and its text equal fold (more general form of
// case-insensitivity equal) to the specified text
func EditedTextEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextEqualFold(update.EditedMessage, text)
}
}
// EditedTextContains is true if the edited message isn't nil, and its text contains specified text
func EditedTextContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextContains(update.EditedMessage, text)
}
}
// EditedTextPrefix is true if the edited message isn't nil, and its text has specified prefix
func EditedTextPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextPrefix(update.EditedMessage, prefix)
}
}
// EditedTextSuffix is true if the edited message isn't nil, and its text has specified suffix
func EditedTextSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextSuffix(update.EditedMessage, suffix)
}
}
// EditedTextMatches is true if the edited message isn't nil, and its text matches specified regexp
func EditedTextMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextMatches(update.EditedMessage, pattern)
}
}
// AnyChannelPost is true if channel post isn't nil
func AnyChannelPost() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassage(update.ChannelPost)
}
}
// AnyChannelPostWithText is true if channel post isn't nil and its text is not empty
func AnyChannelPostWithText() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithText(update.ChannelPost)
}
}
// PostTextEqual is true if channel post isn't nil, and its text equals to the specified text
func PostTextEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextEqual(update.ChannelPost, text)
}
}
@@ -326,56 +341,56 @@ func PostTextEqual(text string) Predicate {
// PostTextEqualFold is true if channel post isn't nil, and its text equal fold (more general form of case-insensitivity
// equal) to the specified text
func PostTextEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextEqualFold(update.ChannelPost, text)
}
}
// PostTextContains is true if channel post isn't nil, and its text contains specified text
func PostTextContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextContains(update.ChannelPost, text)
}
}
// PostTextPrefix is true if channel post isn't nil, and its text has specified prefix
func PostTextPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextPrefix(update.ChannelPost, prefix)
}
}
// PostTextSuffix is true if channel post isn't nil, and its text has specified suffix
func PostTextSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextSuffix(update.ChannelPost, suffix)
}
}
// PostTextMatches is true if channel post isn't nil, and its text matches specified regexp
func PostTextMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextMatches(update.ChannelPost, pattern)
}
}
// AnyEditedChannelPost is true if the edited channel post isn't nil
func AnyEditedChannelPost() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassage(update.EditedChannelPost)
}
}
// AnyEditedChannelPostWithText is true if edited channel post isn't nil and its text is not empty
func AnyEditedChannelPostWithText() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithText(update.EditedChannelPost)
}
}
// EditedPostTextEqual is true if edited channel post isn't nil, and its text equals to the specified text
func EditedPostTextEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextEqual(update.EditedChannelPost, text)
}
}
@@ -383,49 +398,91 @@ func EditedPostTextEqual(text string) Predicate {
// EditedPostTextEqualFold is true if edited channel post isn't nil, and its text equal fold (more general form of
// case-insensitivity equal) to the specified text
func EditedPostTextEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextEqualFold(update.EditedChannelPost, text)
}
}
// EditedPostTextContains is true if edited channel post isn't nil, and its text contains specified text
func EditedPostTextContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextContains(update.EditedChannelPost, text)
}
}
// EditedPostTextPrefix is true if edited channel post isn't nil, and its text has specified prefix
func EditedPostTextPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextPrefix(update.EditedChannelPost, prefix)
}
}
// EditedPostTextSuffix is true if edited channel post isn't nil, and its text has specified suffix
func EditedPostTextSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextSuffix(update.EditedChannelPost, suffix)
}
}
// EditedPostTextMatches is true if edited channel post isn't nil, and its text matches specified regexp
func EditedPostTextMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseTextMatches(update.EditedChannelPost, pattern)
}
}
+// AnyBusinessConnection is true if business connection isn't nil
+func AnyBusinessConnection() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return update.BusinessConnection != nil
+ }
+}
+
+// AnyBusinessMessage is true if the business message isn't nil
+func AnyBusinessMessage() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return anyMassage(update.BusinessMessage)
+ }
+}
+
+// AnyEditedBusinessMessage is true if edited business message isn't nil
+func AnyEditedBusinessMessage() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return anyMassage(update.EditedBusinessMessage)
+ }
+}
+
+// AnyDeletedBusinessMessages is true if deleted business messages isn't nil
+func AnyDeletedBusinessMessages() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return update.DeletedBusinessMessages != nil
+ }
+}
+
+// AnyMessageReaction is true if message reaction isn't nil
+func AnyMessageReaction() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return update.MessageReaction != nil
+ }
+}
+
+// AnyMessageReactionCount is true if message reaction count isn't nil
+func AnyMessageReactionCount() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return update.MessageReactionCount != nil
+ }
+}
+
// AnyInlineQuery is true if inline query isn't nil
func AnyInlineQuery() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.InlineQuery != nil
}
}
// InlineQueryEqual is true if inline query isn't nil, and its query equal to specified text
func InlineQueryEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.InlineQuery != nil && update.InlineQuery.Query == text
}
}
@@ -433,63 +490,63 @@ func InlineQueryEqual(text string) Predicate {
// InlineQueryEqualFold is true if inline query isn't nil, and its query equal fold (more general form of
// case-insensitivity equal) to the specified text
func InlineQueryEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.InlineQuery != nil && strings.EqualFold(update.InlineQuery.Query, text)
}
}
// InlineQueryContains is true if inline query isn't nil, and its query contains specified text
func InlineQueryContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.InlineQuery != nil && strings.Contains(update.InlineQuery.Query, text)
}
}
// InlineQueryPrefix is true if inline query isn't nil, and its query has specified prefix
func InlineQueryPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.InlineQuery != nil && strings.HasPrefix(update.InlineQuery.Query, prefix)
}
}
// InlineQuerySuffix is true if inline query isn't nil, and its query has specified suffix
func InlineQuerySuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.InlineQuery != nil && strings.HasSuffix(update.InlineQuery.Query, suffix)
}
}
// InlineQueryMatches is true if inline query isn't nil, and its query matches specified regexp
func InlineQueryMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.InlineQuery != nil && pattern.MatchString(update.InlineQuery.Query)
}
}
// AnyChosenInlineResult is true if the chosen inline result isn't nil
func AnyChosenInlineResult() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.ChosenInlineResult != nil
}
}
// AnyCallbackQuery is true if the callback query isn't nil
func AnyCallbackQuery() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.CallbackQuery != nil
}
}
// AnyCallbackQueryWithMessage is true if callback query and its message isn't nil
func AnyCallbackQueryWithMessage() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.CallbackQuery != nil && update.CallbackQuery.Message != nil
}
}
// CallbackDataEqual is true if callback query isn't nil, and its data equal to specified text
func CallbackDataEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.CallbackQuery != nil && update.CallbackQuery.Data == text
}
}
@@ -497,95 +554,116 @@ func CallbackDataEqual(text string) Predicate {
// CallbackDataEqualFold is true if the callback query isn't nil, and its data equal fold (more general form of
// case-insensitivity equal) to the specified text
func CallbackDataEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.CallbackQuery != nil && strings.EqualFold(update.CallbackQuery.Data, text)
}
}
// CallbackDataContains is true if the callback query isn't nil, and its data contains specified text
func CallbackDataContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.CallbackQuery != nil && strings.Contains(update.CallbackQuery.Data, text)
}
}
// CallbackDataPrefix is true if the callback query isn't nil, and its data has specified prefix
func CallbackDataPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.CallbackQuery != nil && strings.HasPrefix(update.CallbackQuery.Data, prefix)
}
}
// CallbackDataSuffix is true if the callback query isn't nil, and its data has specified suffix
func CallbackDataSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.CallbackQuery != nil && strings.HasSuffix(update.CallbackQuery.Data, suffix)
}
}
// CallbackDataMatches is true if the callback query isn't nil, and its data matches specified regexp
func CallbackDataMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.CallbackQuery != nil && pattern.MatchString(update.CallbackQuery.Data)
}
}
// AnyShippingQuery is true if shipping query isn't nil
func AnyShippingQuery() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.ShippingQuery != nil
}
}
// AnyPreCheckoutQuery is true if the pre checkout query isn't nil
func AnyPreCheckoutQuery() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.PreCheckoutQuery != nil
}
}
+// AnyPurchasedPaidMedia is true if the purchased paid media isn't nil
+func AnyPurchasedPaidMedia() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return update.PurchasedPaidMedia != nil
+ }
+}
+
// AnyPoll is true if the poll isn't nil
func AnyPoll() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.Poll != nil
}
}
// AnyPollAnswer is true if the poll answer isn't nil
func AnyPollAnswer() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.PollAnswer != nil
}
}
// AnyMyChatMember is true if my chat member isn't nil
func AnyMyChatMember() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.MyChatMember != nil
}
}
// AnyChatMember is true if chat member isn't nil
func AnyChatMember() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.ChatMember != nil
}
}
// AnyChatJoinRequest is true if chat join request isn't nil
func AnyChatJoinRequest() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.ChatJoinRequest != nil
}
}
+// AnyChatBoost is true if chat boost isn't nil
+func AnyChatBoost() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return update.ChatBoost != nil
+ }
+}
+
+// AnyRemovedChatBoost is true if removed chat boost isn't nil
+func AnyRemovedChatBoost() Predicate {
+ return func(_ context.Context, update telego.Update) bool {
+ return update.RemovedChatBoost != nil
+ }
+}
+
func anyMassageWithCaption(message *telego.Message) bool {
return message != nil && message.Caption != ""
}
// AnyMessageWithCaption is true if the message isn't nil and its caption is not empty
func AnyMessageWithCaption() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithCaption(update.Message)
}
}
@@ -596,7 +674,7 @@ func baseCaptionEqual(message *telego.Message, text string) bool {
// CaptionEqual is true if the message isn't nil, and its caption is equal to the specified text
func CaptionEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionEqual(update.Message, text)
}
}
@@ -608,7 +686,7 @@ func baseCaptionEqualFold(message *telego.Message, text string) bool {
// CaptionEqualFold is true if the message isn't nil, and its caption equal fold (more general form of
// case-insensitivity equal) to the specified text
func CaptionEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionEqualFold(update.Message, text)
}
}
@@ -619,7 +697,7 @@ func baseCaptionContains(message *telego.Message, text string) bool {
// CaptionContains is true if the message isn't nil, and its caption contains specified text
func CaptionContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionContains(update.Message, text)
}
}
@@ -630,7 +708,7 @@ func baseCaptionPrefix(message *telego.Message, prefix string) bool {
// CaptionPrefix is true if the message isn't nil, and its caption has specified prefix
func CaptionPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionPrefix(update.Message, prefix)
}
}
@@ -641,7 +719,7 @@ func baseCaptionSuffix(message *telego.Message, suffix string) bool {
// CaptionSuffix is true if the message isn't nil, and its caption has specified suffix
func CaptionSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionSuffix(update.Message, suffix)
}
}
@@ -652,21 +730,21 @@ func baseCaptionMatches(message *telego.Message, pattern *regexp.Regexp) bool {
// CaptionMatches is true if the message isn't nil, and its caption matches specified regexp
func CaptionMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionMatches(update.Message, pattern)
}
}
// AnyCaptionCommand is true if the message isn't nil, and its caption matches to command regexp
func AnyCaptionCommand() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return update.Message != nil && CommandRegexp.MatchString(update.Message.Caption)
}
}
// CaptionCommandEqual is true if the message isn't nil, and its caption contains specified command
func CaptionCommandEqual(command string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
if update.Message == nil {
return false
}
@@ -683,7 +761,7 @@ func CaptionCommandEqual(command string) Predicate {
// CaptionCommandEqualArgc is true if the message isn't nil, and its caption contains specified
// command with a number of args
func CaptionCommandEqualArgc(command string, argc int) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
if update.Message == nil {
return false
}
@@ -701,7 +779,7 @@ func CaptionCommandEqualArgc(command string, argc int) Predicate {
// CaptionCommandEqualArgv is true if the message isn't nil, and its caption contains specified command and args
func CaptionCommandEqualArgv(command string, argv ...string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
if update.Message == nil {
return false
}
@@ -719,14 +797,14 @@ func CaptionCommandEqualArgv(command string, argv ...string) Predicate {
// AnyEditedMessageWithCaption is true if the edited message isn't nil and its caption is not empty
func AnyEditedMessageWithCaption() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithCaption(update.EditedMessage)
}
}
// EditedCaptionEqual is true if the edited message isn't nil, and its caption equals to the specified text
func EditedCaptionEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionEqual(update.EditedMessage, text)
}
}
@@ -734,49 +812,49 @@ func EditedCaptionEqual(text string) Predicate {
// EditedCaptionEqualFold is true if the edited message isn't nil, and its caption equal fold (more general form of
// case-insensitivity equal) to the specified text
func EditedCaptionEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionEqualFold(update.EditedMessage, text)
}
}
// EditedCaptionContains is true if the edited message isn't nil, and its caption contains specified text
func EditedCaptionContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionContains(update.EditedMessage, text)
}
}
// EditedCaptionPrefix is true if the edited message isn't nil, and its caption has specified prefix
func EditedCaptionPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionPrefix(update.EditedMessage, prefix)
}
}
// EditedCaptionSuffix is true if the edited message isn't nil, and its caption has specified suffix
func EditedCaptionSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionSuffix(update.EditedMessage, suffix)
}
}
// EditedCaptionMatches is true if the edited message isn't nil, and its caption matches specified regexp
func EditedCaptionMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionMatches(update.EditedMessage, pattern)
}
}
// AnyChannelPostWithCaption is true if channel post isn't nil and its caption is not empty
func AnyChannelPostWithCaption() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithCaption(update.ChannelPost)
}
}
// PostCaptionEqual is true if channel post isn't nil, and its caption equals to the specified text
func PostCaptionEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionEqual(update.ChannelPost, text)
}
}
@@ -784,49 +862,49 @@ func PostCaptionEqual(text string) Predicate {
// PostCaptionEqualFold is true if channel post isn't nil, and its caption equal fold (more general form of
// case-insensitivity equal) to the specified text
func PostCaptionEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionEqualFold(update.ChannelPost, text)
}
}
// PostCaptionContains is true if channel post isn't nil, and its caption contains specified text
func PostCaptionContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionContains(update.ChannelPost, text)
}
}
// PostCaptionPrefix is true if channel post isn't nil, and its caption has specified prefix
func PostCaptionPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionPrefix(update.ChannelPost, prefix)
}
}
// PostCaptionSuffix is true if channel post isn't nil, and its caption has specified suffix
func PostCaptionSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionSuffix(update.ChannelPost, suffix)
}
}
// PostCaptionMatches is true if channel post isn't nil, and its caption matches specified regexp
func PostCaptionMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionMatches(update.ChannelPost, pattern)
}
}
// AnyEditedChannelPostWithCaption is true if edited channel post isn't nil and its caption is not empty
func AnyEditedChannelPostWithCaption() Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return anyMassageWithCaption(update.EditedChannelPost)
}
}
// EditedPostCaptionEqual is true if edited channel post isn't nil, and its caption equals to the specified text
func EditedPostCaptionEqual(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionEqual(update.EditedChannelPost, text)
}
}
@@ -834,35 +912,35 @@ func EditedPostCaptionEqual(text string) Predicate {
// EditedPostCaptionEqualFold is true if edited channel post isn't nil, and its caption equal fold (more general form of
// case-insensitivity equal) to the specified text
func EditedPostCaptionEqualFold(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionEqualFold(update.EditedChannelPost, text)
}
}
// EditedPostCaptionContains is true if edited channel post isn't nil, and its caption contains specified text
func EditedPostCaptionContains(text string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionContains(update.EditedChannelPost, text)
}
}
// EditedPostCaptionPrefix is true if edited channel post isn't nil, and its caption has specified prefix
func EditedPostCaptionPrefix(prefix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionPrefix(update.EditedChannelPost, prefix)
}
}
// EditedPostCaptionSuffix is true if edited channel post isn't nil, and its caption has specified suffix
func EditedPostCaptionSuffix(suffix string) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionSuffix(update.EditedChannelPost, suffix)
}
}
// EditedPostCaptionMatches is true if edited channel post isn't nil, and its caption matches specified regexp
func EditedPostCaptionMatches(pattern *regexp.Regexp) Predicate {
- return func(update telego.Update) bool {
+ return func(_ context.Context, update telego.Update) bool {
return baseCaptionMatches(update.EditedChannelPost, pattern)
}
}
diff --git a/telegohandler/predicates_test.go b/telegohandler/predicates_test.go
index c549ff5b..8301ff71 100644
--- a/telegohandler/predicates_test.go
+++ b/telegohandler/predicates_test.go
@@ -1,6 +1,7 @@
package telegohandler
import (
+ "context"
"regexp"
"testing"
@@ -17,7 +18,9 @@ const (
testTextSuffix = `text`
testCommand1 = `/test abc 123`
testCommand2 = `/hmm bcd`
+ testCommand3 = "/test@test_bot abc 123"
testCommandName = `test`
+ testBotUsername = "test_bot"
)
func TestPredicates(t *testing.T) {
@@ -42,8 +45,8 @@ func TestPredicates(t *testing.T) {
{
name: "and_matches",
predicate: And(
- func(update telego.Update) bool { return true },
- func(update telego.Update) bool { return true },
+ func(_ context.Context, _ telego.Update) bool { return true },
+ func(_ context.Context, _ telego.Update) bool { return true },
),
update: telego.Update{},
matches: true,
@@ -51,8 +54,8 @@ func TestPredicates(t *testing.T) {
{
name: "and_not_matches",
predicate: And(
- func(update telego.Update) bool { return true },
- func(update telego.Update) bool { return false },
+ func(_ context.Context, _ telego.Update) bool { return true },
+ func(_ context.Context, _ telego.Update) bool { return false },
),
update: telego.Update{},
matches: false,
@@ -60,8 +63,8 @@ func TestPredicates(t *testing.T) {
{
name: "or_matches",
predicate: Or(
- func(update telego.Update) bool { return true },
- func(update telego.Update) bool { return false },
+ func(_ context.Context, _ telego.Update) bool { return true },
+ func(_ context.Context, _ telego.Update) bool { return false },
),
update: telego.Update{},
matches: true,
@@ -69,39 +72,21 @@ func TestPredicates(t *testing.T) {
{
name: "or_not_matches",
predicate: Or(
- func(update telego.Update) bool { return false },
- func(update telego.Update) bool { return false },
- ),
- update: telego.Update{},
- matches: false,
- },
- {
- name: "union_matches",
- predicate: Union(
- func(update telego.Update) bool { return true },
- func(update telego.Update) bool { return false },
- ),
- update: telego.Update{},
- matches: true,
- },
- {
- name: "union_not_matches",
- predicate: Union(
- func(update telego.Update) bool { return false },
- func(update telego.Update) bool { return false },
+ func(_ context.Context, _ telego.Update) bool { return false },
+ func(_ context.Context, _ telego.Update) bool { return false },
),
update: telego.Update{},
matches: false,
},
{
name: "not_matches",
- predicate: Not(func(update telego.Update) bool { return false }),
+ predicate: Not(func(_ context.Context, _ telego.Update) bool { return false }),
update: telego.Update{},
matches: true,
},
{
name: "not_not_matches",
- predicate: Not(func(update telego.Update) bool { return true }),
+ predicate: Not(func(_ context.Context, _ telego.Update) bool { return true }),
update: telego.Update{},
matches: false,
},
@@ -225,6 +210,30 @@ func TestPredicates(t *testing.T) {
update: telego.Update{Message: &telego.Message{Text: testText}},
matches: false,
},
+ {
+ name: "any_command_to_me_matches",
+ predicate: AnyCommandToMe(testBotUsername),
+ update: telego.Update{Message: &telego.Message{Text: testCommand3}},
+ matches: true,
+ },
+ {
+ name: "any_command_to_me_not_matches_no_username",
+ predicate: AnyCommandToMe(testBotUsername),
+ update: telego.Update{Message: &telego.Message{Text: testCommand1}},
+ matches: false,
+ },
+ {
+ name: "any_command_to_me_not_matches_no_message",
+ predicate: AnyCommandToMe(testBotUsername),
+ update: telego.Update{},
+ matches: false,
+ },
+ {
+ name: "any_command_to_me_not_matches_no_command",
+ predicate: AnyCommandToMe(testBotUsername),
+ update: telego.Update{Message: &telego.Message{Text: testText}},
+ matches: false,
+ },
{
name: "command_equal_matches",
predicate: CommandEqual(testCommandName),
@@ -609,6 +618,78 @@ func TestPredicates(t *testing.T) {
update: telego.Update{EditedChannelPost: &telego.Message{Text: testCommand1}},
matches: false,
},
+ {
+ name: "any_business_connection_matches",
+ predicate: AnyBusinessConnection(),
+ update: telego.Update{BusinessConnection: &telego.BusinessConnection{}},
+ matches: true,
+ },
+ {
+ name: "any_business_connection_not_matches",
+ predicate: AnyBusinessConnection(),
+ update: telego.Update{},
+ matches: false,
+ },
+ {
+ name: "any_business_message_matches",
+ predicate: AnyBusinessMessage(),
+ update: telego.Update{BusinessMessage: &telego.Message{}},
+ matches: true,
+ },
+ {
+ name: "any_business_message_not_matches",
+ predicate: AnyBusinessMessage(),
+ update: telego.Update{},
+ matches: false,
+ },
+ {
+ name: "any_edited_business_message_matches",
+ predicate: AnyEditedBusinessMessage(),
+ update: telego.Update{EditedBusinessMessage: &telego.Message{}},
+ matches: true,
+ },
+ {
+ name: "any_edited_business_message_not_matches",
+ predicate: AnyEditedBusinessMessage(),
+ update: telego.Update{},
+ matches: false,
+ },
+ {
+ name: "any_deleted_business_messages_matches",
+ predicate: AnyDeletedBusinessMessages(),
+ update: telego.Update{DeletedBusinessMessages: &telego.BusinessMessagesDeleted{}},
+ matches: true,
+ },
+ {
+ name: "any_deleted_business_messages_not_matches",
+ predicate: AnyDeletedBusinessMessages(),
+ update: telego.Update{},
+ matches: false,
+ },
+ {
+ name: "any_message_reaction_matches",
+ predicate: AnyMessageReaction(),
+ update: telego.Update{MessageReaction: &telego.MessageReactionUpdated{}},
+ matches: true,
+ },
+ {
+ name: "any_message_reaction_not_matches",
+ predicate: AnyMessageReaction(),
+ update: telego.Update{},
+ matches: false,
+ },
+ {
+ name: "any_message_reaction_count_matches",
+ predicate: AnyMessageReactionCount(),
+ update: telego.Update{MessageReactionCount: &telego.MessageReactionCountUpdated{}},
+ matches: true,
+ },
+ {
+ name: "any_message_reaction_count_not_matches",
+ predicate: AnyMessageReactionCount(),
+ update: telego.Update{},
+ matches: false,
+ },
{
name: "any_inline_query_matches",
predicate: AnyInlineQuery(),
@@ -825,6 +906,18 @@ func TestPredicates(t *testing.T) {
update: telego.Update{},
matches: false,
},
+ {
+ name: "any_purchased_paid_media_matches",
+ predicate: AnyPurchasedPaidMedia(),
+ update: telego.Update{PurchasedPaidMedia: &telego.PaidMediaPurchased{}},
+ matches: true,
+ },
+ {
+ name: "any_purchased_paid_media_not_matches",
+ predicate: AnyPurchasedPaidMedia(),
+ update: telego.Update{},
+ matches: false,
+ },
{
name: "any_poll_matches",
predicate: AnyPoll(),
@@ -885,6 +978,30 @@ func TestPredicates(t *testing.T) {
update: telego.Update{},
matches: false,
},
+ {
+ name: "any_chat_boost_matches",
+ predicate: AnyChatBoost(),
+ update: telego.Update{ChatBoost: &telego.ChatBoostUpdated{}},
+ matches: true,
+ },
+ {
+ name: "any_chat_boost_not_matches",
+ predicate: AnyChatBoost(),
+ update: telego.Update{},
+ matches: false,
+ },
+ {
+ name: "any_removed_chat_boost_matches",
+ predicate: AnyRemovedChatBoost(),
+ update: telego.Update{RemovedChatBoost: &telego.ChatBoostRemoved{}},
+ matches: true,
+ },
+ {
+ name: "any_removed_chat_boost_not_matches",
+ predicate: AnyRemovedChatBoost(),
+ update: telego.Update{},
+ matches: false,
+ },
{
name: "any_message_with_caption_matches",
predicate: AnyMessageWithCaption(),
@@ -1307,9 +1424,10 @@ func TestPredicates(t *testing.T) {
},
}
+ ctx := context.Background()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- assert.Equal(t, tt.matches, tt.predicate(tt.update))
+ assert.Equal(t, tt.matches, tt.predicate(ctx, tt.update))
})
}
}
diff --git a/telegoutil/api.go b/telegoutil/api.go
index a1c3ffe2..3ace9ad9 100644
--- a/telegoutil/api.go
+++ b/telegoutil/api.go
@@ -13,7 +13,7 @@ import (
ta "github.com/mymmrac/telego/telegoapi"
)
-// namedReaderImpl represents simplest implementation of telegoapi.NamedReader
+// namedReaderImpl represents the simplest implementation of [ta.NamedReader]
type namedReaderImpl struct {
reader io.Reader
name string
@@ -27,7 +27,7 @@ func (r namedReaderImpl) Name() string {
return r.name
}
-// NameReader "names" io.Reader and returns valid telegoapi.NamedReader
+// NameReader "names" [io.Reader] and returns valid [ta.NamedReader]
func NameReader(reader io.Reader, name string) ta.NamedReader {
return namedReaderImpl{
reader: reader,
@@ -68,7 +68,7 @@ const (
)
// ValidateWebAppData validates the integrity of value provided by `window.Telegram.WebApp.initData` from web app and
-// returns url.Values containing all fields that were provided
+// returns [url.Values] containing all fields that were provided
// More info: https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app
func ValidateWebAppData(token string, data string) (url.Values, error) {
appData, err := url.ParseQuery(data)
@@ -108,7 +108,7 @@ const (
)
// ValidateLoginWidgetData validates the integrity of value provided by Telegram Login Widget and
-// returns url.Values containing all fields that were provided
+// returns [url.Values] containing all fields that were provided
// More info: https://core.telegram.org/widgets/login#checking-authorization
func ValidateLoginWidgetData(token string, data string) (url.Values, error) {
appData, err := url.ParseQuery(data)
diff --git a/telegoutil/doc.go b/telegoutil/doc.go
index 5e34cc4d..2479b9eb 100644
--- a/telegoutil/doc.go
+++ b/telegoutil/doc.go
@@ -1,7 +1,7 @@
/*
Package telegoutil provides utility methods for Telego.
-Those utility methods provides a convenient way of construction Telegram methods parameters and other types.
+Those utility methods provide a convenient way of construction Telegram methods parameters and other types.
Utilities by files:
* api.go - low-level API of Telego
@@ -9,6 +9,6 @@ Utilities by files:
* types.go - types used in methods parameters
* handler.go - handler and predicate helpers
-This package is designed to be self-contained, and other packages should not depend on utilities.
+Dev Note: This package is designed to be self-contained, and other packages of Telego should not depend on utilities.
*/
package telegoutil
diff --git a/telegoutil/handler_test.go b/telegoutil/handler_test.go
index 2538b2af..09a1b020 100644
--- a/telegoutil/handler_test.go
+++ b/telegoutil/handler_test.go
@@ -39,14 +39,14 @@ func TestParseCommand(t *testing.T) {
name: "with_username",
text: "/test@user ok",
cmd: "test",
- username: "@user",
+ username: "user",
args: []string{"ok"},
},
{
name: "multiline",
text: "/test@user ok\n test ",
cmd: "test",
- username: "@user",
+ username: "user",
args: []string{"ok", "test"},
},
}
@@ -94,14 +94,14 @@ func TestParseCommandPayload(t *testing.T) {
name: "with_username",
text: "/test@user ok",
cmd: "test",
- username: "@user",
+ username: "user",
payload: "ok",
},
{
name: "multiline",
text: "/test@user ok\n test ",
cmd: "test",
- username: "@user",
+ username: "user",
payload: "ok\n test",
},
}
diff --git a/telegoutil/message_entity.go b/telegoutil/message_entity.go
index 7495caf3..c29fcaec 100644
--- a/telegoutil/message_entity.go
+++ b/telegoutil/message_entity.go
@@ -7,20 +7,20 @@ import (
"github.com/mymmrac/telego"
)
-// MessageEntityCollection represents text and slice of telego.MessageEntity associated with it
+// MessageEntityCollection represents text and slice of [telego.MessageEntity] associated with it
type MessageEntityCollection struct {
text string
entities []telego.MessageEntity
}
-// Entity creates new MessageEntityCollection with provided text and no entities
+// Entity creates new [MessageEntityCollection] with provided text and no entities
func Entity(text string) MessageEntityCollection {
return MessageEntityCollection{
text: text,
}
}
-// Entityf creates new MessageEntityCollection with the provided format and args and no entities
+// Entityf creates new [MessageEntityCollection] with the provided format and args and no entities
func Entityf(format string, args ...any) MessageEntityCollection {
return MessageEntityCollection{
text: fmt.Sprintf(format, args...),
@@ -44,7 +44,7 @@ func (c MessageEntityCollection) SetOffset(offset int) {
}
}
-// Mention assigns mention entity and returns new collection
+// Mention assigns mention entity and returns a new collection
func (c MessageEntityCollection) Mention() MessageEntityCollection {
c.entities = append(c.entities, telego.MessageEntity{
Type: telego.EntityTypeMention,
@@ -125,7 +125,7 @@ func (c MessageEntityCollection) Italic() MessageEntityCollection {
return c
}
-// Underline assigns underline entity and returns new collection
+// Underline assigns underline entity and returns a new collection
func (c MessageEntityCollection) Underline() MessageEntityCollection {
c.entities = append(c.entities, telego.MessageEntity{
Type: telego.EntityTypeUnderline,
@@ -143,7 +143,7 @@ func (c MessageEntityCollection) Strikethrough() MessageEntityCollection {
return c
}
-// Spoiler assigns spoiler entity and returns new collection
+// Spoiler assigns spoiler entity and returns a new collection
func (c MessageEntityCollection) Spoiler() MessageEntityCollection {
c.entities = append(c.entities, telego.MessageEntity{
Type: telego.EntityTypeSpoiler,
@@ -152,7 +152,7 @@ func (c MessageEntityCollection) Spoiler() MessageEntityCollection {
return c
}
-// Blockquote assigns blockquote entity and returns new collection
+// Blockquote assigns blockquote entity and returns a new collection
func (c MessageEntityCollection) Blockquote() MessageEntityCollection {
c.entities = append(c.entities, telego.MessageEntity{
Type: telego.EntityTypeBlockquote,
@@ -161,7 +161,7 @@ func (c MessageEntityCollection) Blockquote() MessageEntityCollection {
return c
}
-// ExpandableBlockquote assigns expandable blockquote entity and returns new collection
+// ExpandableBlockquote assigns expandable blockquote entity and returns a new collection
func (c MessageEntityCollection) ExpandableBlockquote() MessageEntityCollection {
c.entities = append(c.entities, telego.MessageEntity{
Type: telego.EntityTypeExpandableBlockquote,
@@ -170,7 +170,7 @@ func (c MessageEntityCollection) ExpandableBlockquote() MessageEntityCollection
return c
}
-// Code assigns code entity and returns new collection
+// Code assigns code entity and returns a new collection
func (c MessageEntityCollection) Code() MessageEntityCollection {
c.entities = append(c.entities, telego.MessageEntity{
Type: telego.EntityTypeCode,
@@ -199,7 +199,7 @@ func (c MessageEntityCollection) TextLink(url string) MessageEntityCollection {
return c
}
-// TextMention assigns text mention entity with user and returns new collection
+// TextMention assigns text mention entity with user and returns a new collection
func (c MessageEntityCollection) TextMention(user *telego.User) MessageEntityCollection {
c.entities = append(c.entities, telego.MessageEntity{
Type: telego.EntityTypeTextMention,
diff --git a/telegoutil/methods.go b/telegoutil/methods.go
index 115ecc4e..3d2abffe 100644
--- a/telegoutil/methods.go
+++ b/telegoutil/methods.go
@@ -6,7 +6,7 @@ import (
"github.com/mymmrac/telego"
)
-// Message creates telego.SendMessageParams with required parameters
+// Message creates [telego.SendMessageParams] with required parameters
func Message(id telego.ChatID, text string) *telego.SendMessageParams {
return &telego.SendMessageParams{
ChatID: id,
@@ -14,7 +14,7 @@ func Message(id telego.ChatID, text string) *telego.SendMessageParams {
}
}
-// Messagef creates telego.SendMessageParams with required parameters and provided format
+// Messagef creates [telego.SendMessageParams] with required parameters and provided format
func Messagef(id telego.ChatID, format string, args ...any) *telego.SendMessageParams {
return &telego.SendMessageParams{
ChatID: id,
@@ -22,7 +22,7 @@ func Messagef(id telego.ChatID, format string, args ...any) *telego.SendMessageP
}
}
-// MessageWithEntities creates telego.SendMessageParams with required parameters and parsed entities
+// MessageWithEntities creates [telego.SendMessageParams] with required parameters and parsed entities
func MessageWithEntities(id telego.ChatID, entityCollections ...MessageEntityCollection) *telego.SendMessageParams {
text, entities := MessageEntities(entityCollections...)
return &telego.SendMessageParams{
@@ -32,7 +32,7 @@ func MessageWithEntities(id telego.ChatID, entityCollections ...MessageEntityCol
}
}
-// Photo creates telego.SendPhotoParams with required parameters
+// Photo creates [telego.SendPhotoParams] with required parameters
func Photo(id telego.ChatID, photo telego.InputFile) *telego.SendPhotoParams {
return &telego.SendPhotoParams{
ChatID: id,
@@ -40,7 +40,7 @@ func Photo(id telego.ChatID, photo telego.InputFile) *telego.SendPhotoParams {
}
}
-// Audio creates telego.SendAudioParams with required parameters
+// Audio creates [telego.SendAudioParams] with required parameters
func Audio(id telego.ChatID, audio telego.InputFile) *telego.SendAudioParams {
return &telego.SendAudioParams{
ChatID: id,
@@ -48,7 +48,7 @@ func Audio(id telego.ChatID, audio telego.InputFile) *telego.SendAudioParams {
}
}
-// Document creates telego.SendDocumentParams with required parameters
+// Document creates [telego.SendDocumentParams] with required parameters
func Document(id telego.ChatID, document telego.InputFile) *telego.SendDocumentParams {
return &telego.SendDocumentParams{
ChatID: id,
@@ -56,7 +56,7 @@ func Document(id telego.ChatID, document telego.InputFile) *telego.SendDocumentP
}
}
-// Video creates telego.SendVideoParams with required parameters
+// Video creates [telego.SendVideoParams] with required parameters
func Video(id telego.ChatID, video telego.InputFile) *telego.SendVideoParams {
return &telego.SendVideoParams{
ChatID: id,
@@ -64,7 +64,7 @@ func Video(id telego.ChatID, video telego.InputFile) *telego.SendVideoParams {
}
}
-// Animation creates telego.SendAnimationParams with required parameters
+// Animation creates [telego.SendAnimationParams] with required parameters
func Animation(id telego.ChatID, animation telego.InputFile) *telego.SendAnimationParams {
return &telego.SendAnimationParams{
ChatID: id,
@@ -72,7 +72,7 @@ func Animation(id telego.ChatID, animation telego.InputFile) *telego.SendAnimati
}
}
-// Voice creates telego.SendVoiceParams with required parameters
+// Voice creates [telego.SendVoiceParams] with required parameters
func Voice(id telego.ChatID, voice telego.InputFile) *telego.SendVoiceParams {
return &telego.SendVoiceParams{
ChatID: id,
@@ -80,7 +80,7 @@ func Voice(id telego.ChatID, voice telego.InputFile) *telego.SendVoiceParams {
}
}
-// VideoNote creates telego.SendVideoNoteParams with required parameters
+// VideoNote creates [telego.SendVideoNoteParams] with required parameters
func VideoNote(id telego.ChatID, videoNote telego.InputFile) *telego.SendVideoNoteParams {
return &telego.SendVideoNoteParams{
ChatID: id,
@@ -88,7 +88,7 @@ func VideoNote(id telego.ChatID, videoNote telego.InputFile) *telego.SendVideoNo
}
}
-// MediaGroup creates telego.SendMediaGroupParams with required parameters
+// MediaGroup creates [telego.SendMediaGroupParams] with required parameters
func MediaGroup(id telego.ChatID, mediaGroups ...telego.InputMedia) *telego.SendMediaGroupParams {
return &telego.SendMediaGroupParams{
ChatID: id,
@@ -96,7 +96,7 @@ func MediaGroup(id telego.ChatID, mediaGroups ...telego.InputMedia) *telego.Send
}
}
-// Location creates telego.SendLocationParams with required parameters
+// Location creates [telego.SendLocationParams] with required parameters
func Location(id telego.ChatID, latitude, longitude float64) *telego.SendLocationParams {
return &telego.SendLocationParams{
ChatID: id,
@@ -105,7 +105,7 @@ func Location(id telego.ChatID, latitude, longitude float64) *telego.SendLocatio
}
}
-// Venue creates telego.SendVenueParams with required parameters
+// Venue creates [telego.SendVenueParams] with required parameters
func Venue(id telego.ChatID, latitude, longitude float64, title, address string) *telego.SendVenueParams {
return &telego.SendVenueParams{
ChatID: id,
@@ -116,7 +116,7 @@ func Venue(id telego.ChatID, latitude, longitude float64, title, address string)
}
}
-// Contact creates telego.SendContactParams with required parameters
+// Contact creates [telego.SendContactParams] with required parameters
func Contact(id telego.ChatID, phoneNumber, firstName string) *telego.SendContactParams {
return &telego.SendContactParams{
ChatID: id,
@@ -125,7 +125,7 @@ func Contact(id telego.ChatID, phoneNumber, firstName string) *telego.SendContac
}
}
-// Poll creates telego.SendPollParams with required parameters
+// Poll creates [telego.SendPollParams] with required parameters
func Poll(id telego.ChatID, question string, options ...telego.InputPollOption) *telego.SendPollParams {
return &telego.SendPollParams{
ChatID: id,
@@ -134,15 +134,15 @@ func Poll(id telego.ChatID, question string, options ...telego.InputPollOption)
}
}
-// PollOption creates telego.InputPollOption with required parameters
+// PollOption creates [telego.InputPollOption] with required parameters
func PollOption(text string) telego.InputPollOption {
return telego.InputPollOption{
Text: text,
}
}
-// Dice creates telego.SendDiceParams with required parameters
-// Note: Emoji isn't required, but most likely you would what to specify it, you can use telego.EmojiDice or etc.
+// Dice creates [telego.SendDiceParams] with required parameters
+// Note: Emoji isn't required, but most likely you would what to specify it, you can use [telego.EmojiDice]or etc.
func Dice(id telego.ChatID, emoji string) *telego.SendDiceParams {
return &telego.SendDiceParams{
ChatID: id,
@@ -150,7 +150,7 @@ func Dice(id telego.ChatID, emoji string) *telego.SendDiceParams {
}
}
-// ChatAction creates telego.SendChatActionParams with required parameters
+// ChatAction creates [telego.SendChatActionParams] with required parameters
func ChatAction(id telego.ChatID, action string) *telego.SendChatActionParams {
return &telego.SendChatActionParams{
ChatID: id,
@@ -158,7 +158,7 @@ func ChatAction(id telego.ChatID, action string) *telego.SendChatActionParams {
}
}
-// Sticker creates telego.SendStickerParams with required parameters
+// Sticker creates [telego.SendStickerParams] with required parameters
func Sticker(id telego.ChatID, sticker telego.InputFile) *telego.SendStickerParams {
return &telego.SendStickerParams{
ChatID: id,
@@ -166,7 +166,7 @@ func Sticker(id telego.ChatID, sticker telego.InputFile) *telego.SendStickerPara
}
}
-// Invoice creates telego.SendInvoiceParams with required parameters
+// Invoice creates [telego.SendInvoiceParams] with required parameters
func Invoice(id telego.ChatID, title, description, payload, providerToken, currency string,
prices ...telego.LabeledPrice,
) *telego.SendInvoiceParams {
@@ -181,7 +181,7 @@ func Invoice(id telego.ChatID, title, description, payload, providerToken, curre
}
}
-// Game creates telego.SendGameParams with required parameters
+// Game creates [telego.SendGameParams] with required parameters
func Game(id int64, gameShortName string) *telego.SendGameParams {
return &telego.SendGameParams{
ChatID: id,
@@ -189,7 +189,7 @@ func Game(id int64, gameShortName string) *telego.SendGameParams {
}
}
-// CopyMessage creates telego.CopyMessageParams with required parameters
+// CopyMessage creates [telego.CopyMessageParams] with required parameters
func CopyMessage(id, fromID telego.ChatID, messageID int) *telego.CopyMessageParams {
return &telego.CopyMessageParams{
ChatID: id,
@@ -198,14 +198,14 @@ func CopyMessage(id, fromID telego.ChatID, messageID int) *telego.CopyMessagePar
}
}
-// CallbackQuery creates telego.AnswerCallbackQueryParams with required parameters
+// CallbackQuery creates [telego.AnswerCallbackQueryParams] with required parameters
func CallbackQuery(queryID string) *telego.AnswerCallbackQueryParams {
return &telego.AnswerCallbackQueryParams{
CallbackQueryID: queryID,
}
}
-// InlineQuery creates telego.AnswerInlineQueryParams with required parameters
+// InlineQuery creates [telego.AnswerInlineQueryParams] with required parameters
func InlineQuery(queryID string, results ...telego.InlineQueryResult) *telego.AnswerInlineQueryParams {
return &telego.AnswerInlineQueryParams{
InlineQueryID: queryID,
@@ -213,7 +213,7 @@ func InlineQuery(queryID string, results ...telego.InlineQueryResult) *telego.An
}
}
-// ShippingQuery creates telego.AnswerShippingQueryParams with required parameters
+// ShippingQuery creates [telego.AnswerShippingQueryParams] with required parameters
func ShippingQuery(queryID string, ok bool, options ...telego.ShippingOption) *telego.AnswerShippingQueryParams {
return &telego.AnswerShippingQueryParams{
ShippingQueryID: queryID,
@@ -222,7 +222,7 @@ func ShippingQuery(queryID string, ok bool, options ...telego.ShippingOption) *t
}
}
-// PreCheckoutQuery creates telego.AnswerPreCheckoutQueryParams with required parameters
+// PreCheckoutQuery creates [telego.AnswerPreCheckoutQueryParams] with required parameters
func PreCheckoutQuery(queryID string, ok bool) *telego.AnswerPreCheckoutQueryParams {
return &telego.AnswerPreCheckoutQueryParams{
PreCheckoutQueryID: queryID,
@@ -230,7 +230,7 @@ func PreCheckoutQuery(queryID string, ok bool) *telego.AnswerPreCheckoutQueryPar
}
}
-// WebAppQuery creates telego.AnswerWebAppQueryParams with required parameters
+// WebAppQuery creates [telego.AnswerWebAppQueryParams] with required parameters
func WebAppQuery(queryID string, result telego.InlineQueryResult) *telego.AnswerWebAppQueryParams {
return &telego.AnswerWebAppQueryParams{
WebAppQueryID: queryID,
@@ -238,14 +238,14 @@ func WebAppQuery(queryID string, result telego.InlineQueryResult) *telego.Answer
}
}
-// Webhook creates telego.SetWebhookParams with required parameters
+// Webhook creates [telego.SetWebhookParams] with required parameters
func Webhook(url string) *telego.SetWebhookParams {
return &telego.SetWebhookParams{
URL: url,
}
}
-// Delete creates telego.DeleteMessageParams with required parameters
+// Delete creates [telego.DeleteMessageParams] with required parameters
func Delete(id telego.ChatID, messageID int) *telego.DeleteMessageParams {
return &telego.DeleteMessageParams{
ChatID: id,
diff --git a/telegoutil/types.go b/telegoutil/types.go
index 9a785b36..b41e6f73 100644
--- a/telegoutil/types.go
+++ b/telegoutil/types.go
@@ -9,35 +9,35 @@ import (
ta "github.com/mymmrac/telego/telegoapi"
)
-// ID creates telego.ChatID from user's identifier
+// ID creates [telego.ChatID] from user's identifier
func ID(id int64) telego.ChatID {
return telego.ChatID{
ID: id,
}
}
-// Username creates telego.ChatID from username
+// Username creates [telego.ChatID] from username
func Username(username string) telego.ChatID {
return telego.ChatID{
Username: username,
}
}
-// File creates telego.InputFile from telegoapi.NamedReader
+// File creates [telego.InputFile] from telegoapi.NamedReader
func File(file ta.NamedReader) telego.InputFile {
return telego.InputFile{
File: file,
}
}
-// FileFromURL creates telego.InputFile from URL
+// FileFromURL creates [telego.InputFile] from URL
func FileFromURL(url string) telego.InputFile {
return telego.InputFile{
URL: url,
}
}
-// FileFromID creates telego.InputFile from file ID
+// FileFromID creates [telego.InputFile] from file ID
func FileFromID(id string) telego.InputFile {
return telego.InputFile{
FileID: id,
@@ -59,19 +59,19 @@ func DownloadFile(url string) ([]byte, error) {
return file, nil
}
-// Keyboard creates telego.ReplyKeyboardMarkup from slice of keyboard buttons
+// Keyboard creates [telego.ReplyKeyboardMarkup] from slice of keyboard buttons
func Keyboard(rows ...[]telego.KeyboardButton) *telego.ReplyKeyboardMarkup {
return &telego.ReplyKeyboardMarkup{
Keyboard: rows,
}
}
-// KeyboardRow creates a slice of telego.KeyboardButton
+// KeyboardRow creates a slice of [telego.KeyboardButton]
func KeyboardRow(buttons ...telego.KeyboardButton) []telego.KeyboardButton {
return buttons
}
-// KeyboardGrid creates a telego.ReplyKeyboardMarkup from grid of buttons
+// KeyboardGrid creates a [telego.ReplyKeyboardMarkup] from grid of buttons
func KeyboardGrid(buttons [][]telego.KeyboardButton) *telego.ReplyKeyboardMarkup {
return &telego.ReplyKeyboardMarkup{
Keyboard: buttons,
@@ -138,54 +138,54 @@ func KeyboardRows(rows int, buttons ...telego.KeyboardButton) [][]telego.Keyboar
return grid
}
-// KeyboardButton creates telego.KeyboardButton with required fields
+// KeyboardButton creates [telego.KeyboardButton] with required fields
func KeyboardButton(text string) telego.KeyboardButton {
return telego.KeyboardButton{
Text: text,
}
}
-// ReplyKeyboardRemove creates telego.ReplyKeyboardRemove with required fields
+// ReplyKeyboardRemove creates [telego.ReplyKeyboardRemove] with required fields
func ReplyKeyboardRemove() *telego.ReplyKeyboardRemove {
return &telego.ReplyKeyboardRemove{
RemoveKeyboard: true,
}
}
-// WebAppInfo creates telego.WebAppInfo with required fields
+// WebAppInfo creates [telego.WebAppInfo] with required fields
func WebAppInfo(url string) *telego.WebAppInfo {
return &telego.WebAppInfo{
URL: url,
}
}
-// ForceReply creates telego.ForceReply with required fields
+// ForceReply creates [telego.ForceReply] with required fields
func ForceReply() *telego.ForceReply {
return &telego.ForceReply{
ForceReply: true,
}
}
-// PollTypeAny creates telego.KeyboardButtonPollType with any type
+// PollTypeAny creates [telego.KeyboardButtonPollType] with any type
func PollTypeAny() *telego.KeyboardButtonPollType {
return &telego.KeyboardButtonPollType{}
}
-// PollTypeRegular creates telego.KeyboardButtonPollType with type regular
+// PollTypeRegular creates [telego.KeyboardButtonPollType] with type regular
func PollTypeRegular() *telego.KeyboardButtonPollType {
return &telego.KeyboardButtonPollType{
Type: telego.PollTypeRegular,
}
}
-// PollTypeQuiz creates telego.KeyboardButtonPollType with type quiz
+// PollTypeQuiz creates [telego.KeyboardButtonPollType] with type quiz
func PollTypeQuiz() *telego.KeyboardButtonPollType {
return &telego.KeyboardButtonPollType{
Type: telego.PollTypeQuiz,
}
}
-// InlineKeyboard creates telego.InlineKeyboardMarkup from slice of keyboard buttons rows
+// InlineKeyboard creates [telego.InlineKeyboardMarkup] from slice of keyboard buttons rows
func InlineKeyboard(rows ...[]telego.InlineKeyboardButton) *telego.InlineKeyboardMarkup {
return &telego.InlineKeyboardMarkup{
InlineKeyboard: rows,
@@ -197,7 +197,7 @@ func InlineKeyboardRow(buttons ...telego.InlineKeyboardButton) []telego.InlineKe
return buttons
}
-// InlineKeyboardGrid creates a telego.InlineKeyboardMarkup from grid of buttons
+// InlineKeyboardGrid creates a [telego.InlineKeyboardMarkup] from grid of buttons
func InlineKeyboardGrid(buttons [][]telego.InlineKeyboardButton) *telego.InlineKeyboardMarkup {
return &telego.InlineKeyboardMarkup{
InlineKeyboard: buttons,
@@ -264,14 +264,14 @@ func InlineKeyboardRows(rows int, buttons ...telego.InlineKeyboardButton) [][]te
return grid
}
-// InlineKeyboardButton creates telego.InlineKeyboardButton with required fields
+// InlineKeyboardButton creates [telego.InlineKeyboardButton] with required fields
func InlineKeyboardButton(text string) telego.InlineKeyboardButton {
return telego.InlineKeyboardButton{
Text: text,
}
}
-// ResultCachedAudio creates telego.InlineQueryResultCachedAudio with required fields
+// ResultCachedAudio creates [telego.InlineQueryResultCachedAudio] with required fields
func ResultCachedAudio(id, audioFileID string) *telego.InlineQueryResultCachedAudio {
return &telego.InlineQueryResultCachedAudio{
Type: telego.ResultTypeAudio,
@@ -280,7 +280,7 @@ func ResultCachedAudio(id, audioFileID string) *telego.InlineQueryResultCachedAu
}
}
-// ResultCachedDocument creates telego.InlineQueryResultCachedDocument with required fields
+// ResultCachedDocument creates [telego.InlineQueryResultCachedDocument] with required fields
func ResultCachedDocument(id, title, documentFileID string) *telego.InlineQueryResultCachedDocument {
return &telego.InlineQueryResultCachedDocument{
Type: telego.ResultTypeDocument,
@@ -290,7 +290,7 @@ func ResultCachedDocument(id, title, documentFileID string) *telego.InlineQueryR
}
}
-// ResultCachedGif creates telego.InlineQueryResultCachedGif with required fields
+// ResultCachedGif creates [telego.InlineQueryResultCachedGif] with required fields
func ResultCachedGif(id, gifFileID string) *telego.InlineQueryResultCachedGif {
return &telego.InlineQueryResultCachedGif{
Type: telego.ResultTypeGif,
@@ -299,7 +299,7 @@ func ResultCachedGif(id, gifFileID string) *telego.InlineQueryResultCachedGif {
}
}
-// ResultCachedMpeg4Gif creates telego.InlineQueryResultCachedMpeg4Gif with required fields
+// ResultCachedMpeg4Gif creates [telego.InlineQueryResultCachedMpeg4Gif] with required fields
func ResultCachedMpeg4Gif(id, mpeg4FileID string) *telego.InlineQueryResultCachedMpeg4Gif {
return &telego.InlineQueryResultCachedMpeg4Gif{
Type: telego.ResultTypeMpeg4Gif,
@@ -308,7 +308,7 @@ func ResultCachedMpeg4Gif(id, mpeg4FileID string) *telego.InlineQueryResultCache
}
}
-// ResultCachedPhoto creates telego.InlineQueryResultCachedPhoto with required fields
+// ResultCachedPhoto creates [telego.InlineQueryResultCachedPhoto] with required fields
func ResultCachedPhoto(id, photoFileID string) *telego.InlineQueryResultCachedPhoto {
return &telego.InlineQueryResultCachedPhoto{
Type: telego.ResultTypePhoto,
@@ -317,7 +317,7 @@ func ResultCachedPhoto(id, photoFileID string) *telego.InlineQueryResultCachedPh
}
}
-// ResultCachedSticker creates telego.InlineQueryResultCachedSticker with required fields
+// ResultCachedSticker creates [telego.InlineQueryResultCachedSticker] with required fields
func ResultCachedSticker(id, stickerFileID string) *telego.InlineQueryResultCachedSticker {
return &telego.InlineQueryResultCachedSticker{
Type: telego.ResultTypeSticker,
@@ -326,7 +326,7 @@ func ResultCachedSticker(id, stickerFileID string) *telego.InlineQueryResultCach
}
}
-// ResultCachedVideo creates telego.InlineQueryResultCachedVideo with required fields
+// ResultCachedVideo creates [telego.InlineQueryResultCachedVideo] with required fields
func ResultCachedVideo(id, videoFileID, title string) *telego.InlineQueryResultCachedVideo {
return &telego.InlineQueryResultCachedVideo{
Type: telego.ResultTypeVideo,
@@ -336,7 +336,7 @@ func ResultCachedVideo(id, videoFileID, title string) *telego.InlineQueryResultC
}
}
-// ResultCachedVoice creates telego.InlineQueryResultCachedVoice with required fields
+// ResultCachedVoice creates [telego.InlineQueryResultCachedVoice] with required fields
func ResultCachedVoice(id, voiceFileID, title string) *telego.InlineQueryResultCachedVoice {
return &telego.InlineQueryResultCachedVoice{
Type: telego.ResultTypeVoice,
@@ -346,7 +346,7 @@ func ResultCachedVoice(id, voiceFileID, title string) *telego.InlineQueryResultC
}
}
-// ResultArticle creates telego.InlineQueryResultArticle with required fields
+// ResultArticle creates [telego.InlineQueryResultArticle] with required fields
func ResultArticle(id, title string, inputMessageContent telego.InputMessageContent,
) *telego.InlineQueryResultArticle {
return &telego.InlineQueryResultArticle{
@@ -357,7 +357,7 @@ func ResultArticle(id, title string, inputMessageContent telego.InputMessageCont
}
}
-// ResultAudio creates telego.InlineQueryResultAudio with required fields
+// ResultAudio creates [telego.InlineQueryResultAudio] with required fields
func ResultAudio(id, audioURL, title string) *telego.InlineQueryResultAudio {
return &telego.InlineQueryResultAudio{
Type: telego.ResultTypeAudio,
@@ -367,7 +367,7 @@ func ResultAudio(id, audioURL, title string) *telego.InlineQueryResultAudio {
}
}
-// ResultContact creates telego.InlineQueryResultContact with required fields
+// ResultContact creates [telego.InlineQueryResultContact] with required fields
func ResultContact(id, phoneNumber, firstName string) *telego.InlineQueryResultContact {
return &telego.InlineQueryResultContact{
Type: telego.ResultTypeContact,
@@ -377,7 +377,7 @@ func ResultContact(id, phoneNumber, firstName string) *telego.InlineQueryResultC
}
}
-// ResultGame creates telego.InlineQueryResultGame with required fields
+// ResultGame creates [telego.InlineQueryResultGame] with required fields
func ResultGame(id, gameShortName string) *telego.InlineQueryResultGame {
return &telego.InlineQueryResultGame{
Type: telego.ResultTypeGame,
@@ -386,7 +386,7 @@ func ResultGame(id, gameShortName string) *telego.InlineQueryResultGame {
}
}
-// ResultDocument creates telego.InlineQueryResultDocument with required fields
+// ResultDocument creates [telego.InlineQueryResultDocument] with required fields
func ResultDocument(id, title, documentURL, mimeType string) *telego.InlineQueryResultDocument {
return &telego.InlineQueryResultDocument{
Type: telego.ResultTypeDocument,
@@ -397,7 +397,7 @@ func ResultDocument(id, title, documentURL, mimeType string) *telego.InlineQuery
}
}
-// ResultGif creates telego.InlineQueryResultGif with required fields
+// ResultGif creates [telego.InlineQueryResultGif] with required fields
func ResultGif(id, gifURL, thumbnailURL string) *telego.InlineQueryResultGif {
return &telego.InlineQueryResultGif{
Type: telego.ResultTypeGif,
@@ -407,7 +407,7 @@ func ResultGif(id, gifURL, thumbnailURL string) *telego.InlineQueryResultGif {
}
}
-// ResultLocation creates telego.InlineQueryResultLocation with required fields
+// ResultLocation creates [telego.InlineQueryResultLocation] with required fields
func ResultLocation(id string, latitude, longitude float64, title string) *telego.InlineQueryResultLocation {
return &telego.InlineQueryResultLocation{
Type: telego.ResultTypeLocation,
@@ -418,7 +418,7 @@ func ResultLocation(id string, latitude, longitude float64, title string) *teleg
}
}
-// ResultMpeg4Gif creates telego.InlineQueryResultMpeg4Gif with required fields
+// ResultMpeg4Gif creates [telego.InlineQueryResultMpeg4Gif] with required fields
func ResultMpeg4Gif(id, mpeg4URL, thumbnailURL string) *telego.InlineQueryResultMpeg4Gif {
return &telego.InlineQueryResultMpeg4Gif{
Type: telego.ResultTypeMpeg4Gif,
@@ -428,7 +428,7 @@ func ResultMpeg4Gif(id, mpeg4URL, thumbnailURL string) *telego.InlineQueryResult
}
}
-// ResultPhoto creates telego.InlineQueryResultPhoto with required fields
+// ResultPhoto creates [telego.InlineQueryResultPhoto] with required fields
func ResultPhoto(id, photoURL, thumbnailURL string) *telego.InlineQueryResultPhoto {
return &telego.InlineQueryResultPhoto{
Type: telego.ResultTypePhoto,
@@ -438,7 +438,7 @@ func ResultPhoto(id, photoURL, thumbnailURL string) *telego.InlineQueryResultPho
}
}
-// ResultVenue creates telego.InlineQueryResultVenue with required fields
+// ResultVenue creates [telego.InlineQueryResultVenue] with required fields
func ResultVenue(id string, latitude, longitude float64, title, address string,
) *telego.InlineQueryResultVenue {
return &telego.InlineQueryResultVenue{
@@ -451,7 +451,7 @@ func ResultVenue(id string, latitude, longitude float64, title, address string,
}
}
-// ResultVideo creates telego.InlineQueryResultVideo with required fields
+// ResultVideo creates [telego.InlineQueryResultVideo] with required fields
func ResultVideo(id, videoURL, mimeType, thumbnailURL, title string) *telego.InlineQueryResultVideo {
return &telego.InlineQueryResultVideo{
Type: telego.ResultTypeVideo,
@@ -463,7 +463,7 @@ func ResultVideo(id, videoURL, mimeType, thumbnailURL, title string) *telego.Inl
}
}
-// ResultVoice creates telego.InlineQueryResultVoice with required fields
+// ResultVoice creates [telego.InlineQueryResultVoice] with required fields
func ResultVoice(id, voiceURL, title string) *telego.InlineQueryResultVoice {
return &telego.InlineQueryResultVoice{
Type: telego.ResultTypeVoice,
@@ -473,14 +473,14 @@ func ResultVoice(id, voiceURL, title string) *telego.InlineQueryResultVoice {
}
}
-// TextMessage creates telego.InputTextMessageContent with required fields
+// TextMessage creates [telego.InputTextMessageContent] with required fields
func TextMessage(messageText string) *telego.InputTextMessageContent {
return &telego.InputTextMessageContent{
MessageText: messageText,
}
}
-// LocationMessage creates telego.InputLocationMessageContent with required fields
+// LocationMessage creates [telego.InputLocationMessageContent] with required fields
func LocationMessage(latitude, longitude float64) *telego.InputLocationMessageContent {
return &telego.InputLocationMessageContent{
Latitude: latitude,
@@ -488,7 +488,7 @@ func LocationMessage(latitude, longitude float64) *telego.InputLocationMessageCo
}
}
-// VenueMessage creates telego.InputVenueMessageContent with required fields
+// VenueMessage creates [telego.InputVenueMessageContent] with required fields
func VenueMessage(latitude, longitude float64, title, address string) *telego.InputVenueMessageContent {
return &telego.InputVenueMessageContent{
Latitude: latitude,
@@ -498,7 +498,7 @@ func VenueMessage(latitude, longitude float64, title, address string) *telego.In
}
}
-// ContactMessage creates telego.InputContactMessageContent with required fields
+// ContactMessage creates [telego.InputContactMessageContent] with required fields
func ContactMessage(phoneNumber, firstName string) *telego.InputContactMessageContent {
return &telego.InputContactMessageContent{
PhoneNumber: phoneNumber,
@@ -506,7 +506,7 @@ func ContactMessage(phoneNumber, firstName string) *telego.InputContactMessageCo
}
}
-// InvoiceMessage creates telego.InputInvoiceMessageContent with required fields
+// InvoiceMessage creates [telego.InputInvoiceMessageContent] with required fields
func InvoiceMessage(title, description, payload, providerToken, currency string, prices ...telego.LabeledPrice,
) *telego.InputInvoiceMessageContent {
return &telego.InputInvoiceMessageContent{
@@ -519,7 +519,7 @@ func InvoiceMessage(title, description, payload, providerToken, currency string,
}
}
-// MediaAnimation creates telego.InputMediaAnimation with required fields
+// MediaAnimation creates [telego.InputMediaAnimation] with required fields
func MediaAnimation(media telego.InputFile) *telego.InputMediaAnimation {
return &telego.InputMediaAnimation{
Type: telego.MediaTypeAnimation,
@@ -527,7 +527,7 @@ func MediaAnimation(media telego.InputFile) *telego.InputMediaAnimation {
}
}
-// MediaDocument creates telego.InputMediaDocument with required fields
+// MediaDocument creates [telego.InputMediaDocument] with required fields
func MediaDocument(media telego.InputFile) *telego.InputMediaDocument {
return &telego.InputMediaDocument{
Type: telego.MediaTypeDocument,
@@ -535,7 +535,7 @@ func MediaDocument(media telego.InputFile) *telego.InputMediaDocument {
}
}
-// MediaAudio creates telego.InputMediaAudio with required fields
+// MediaAudio creates [telego.InputMediaAudio] with required fields
func MediaAudio(media telego.InputFile) *telego.InputMediaAudio {
return &telego.InputMediaAudio{
Type: telego.MediaTypeAudio,
@@ -543,7 +543,7 @@ func MediaAudio(media telego.InputFile) *telego.InputMediaAudio {
}
}
-// MediaPhoto creates telego.InputMediaPhoto with required fields
+// MediaPhoto creates [telego.InputMediaPhoto] with required fields
func MediaPhoto(media telego.InputFile) *telego.InputMediaPhoto {
return &telego.InputMediaPhoto{
Type: telego.MediaTypePhoto,
@@ -551,7 +551,7 @@ func MediaPhoto(media telego.InputFile) *telego.InputMediaPhoto {
}
}
-// MediaVideo creates telego.InputMediaVideo with required fields
+// MediaVideo creates [telego.InputMediaVideo] with required fields
func MediaVideo(media telego.InputFile) *telego.InputMediaVideo {
return &telego.InputMediaVideo{
Type: telego.MediaTypeVideo,
@@ -559,35 +559,35 @@ func MediaVideo(media telego.InputFile) *telego.InputMediaVideo {
}
}
-// ScopeDefault creates telego.BotCommandScopeDefault with required fields
+// ScopeDefault creates [telego.BotCommandScopeDefault] with required fields
func ScopeDefault() *telego.BotCommandScopeDefault {
return &telego.BotCommandScopeDefault{
Type: telego.ScopeTypeDefault,
}
}
-// ScopeAllPrivateChats creates telego.BotCommandScopeAllPrivateChats with required fields
+// ScopeAllPrivateChats creates [telego.BotCommandScopeAllPrivateChats] with required fields
func ScopeAllPrivateChats() *telego.BotCommandScopeAllPrivateChats {
return &telego.BotCommandScopeAllPrivateChats{
Type: telego.ScopeTypeAllPrivateChats,
}
}
-// ScopeAllGroupChats creates telego.BotCommandScopeAllGroupChats with required fields
+// ScopeAllGroupChats creates [telego.BotCommandScopeAllGroupChats] with required fields
func ScopeAllGroupChats() *telego.BotCommandScopeAllGroupChats {
return &telego.BotCommandScopeAllGroupChats{
Type: telego.ScopeTypeAllGroupChats,
}
}
-// ScopeAllChatAdministrators creates telego.BotCommandScopeAllChatAdministrators with required fields
+// ScopeAllChatAdministrators creates [telego.BotCommandScopeAllChatAdministrators] with required fields
func ScopeAllChatAdministrators() *telego.BotCommandScopeAllChatAdministrators {
return &telego.BotCommandScopeAllChatAdministrators{
Type: telego.ScopeTypeAllChatAdministrators,
}
}
-// ScopeChat creates telego.BotCommandScopeChat with required fields
+// ScopeChat creates [telego.BotCommandScopeChat] with required fields
func ScopeChat(chatID telego.ChatID) *telego.BotCommandScopeChat {
return &telego.BotCommandScopeChat{
Type: telego.ScopeTypeChat,
@@ -595,7 +595,7 @@ func ScopeChat(chatID telego.ChatID) *telego.BotCommandScopeChat {
}
}
-// ScopeChatAdministrators creates telego.BotCommandScopeChatAdministrators with required fields
+// ScopeChatAdministrators creates [telego.BotCommandScopeChatAdministrators] with required fields
func ScopeChatAdministrators(chatID telego.ChatID) *telego.BotCommandScopeChatAdministrators {
return &telego.BotCommandScopeChatAdministrators{
Type: telego.ScopeTypeChatAdministrators,
@@ -603,7 +603,7 @@ func ScopeChatAdministrators(chatID telego.ChatID) *telego.BotCommandScopeChatAd
}
}
-// ScopeChatMember creates telego.BotCommandScopeChatMember with required fields
+// ScopeChatMember creates [telego.BotCommandScopeChatMember] with required fields
func ScopeChatMember(chatID telego.ChatID, userID int64) *telego.BotCommandScopeChatMember {
return &telego.BotCommandScopeChatMember{
Type: telego.ScopeTypeChatMember,
@@ -612,7 +612,7 @@ func ScopeChatMember(chatID telego.ChatID, userID int64) *telego.BotCommandScope
}
}
-// ErrorDataField creates telego.PassportElementErrorDataField with required fields
+// ErrorDataField creates [telego.PassportElementErrorDataField] with required fields
func ErrorDataField(sourceType, message, fieldName, dataHash string) *telego.PassportElementErrorDataField {
return &telego.PassportElementErrorDataField{
Source: telego.ErrorSourceDataField,
@@ -623,7 +623,7 @@ func ErrorDataField(sourceType, message, fieldName, dataHash string) *telego.Pas
}
}
-// ErrorFrontSide creates telego.PassportElementErrorFrontSide with required fields
+// ErrorFrontSide creates [telego.PassportElementErrorFrontSide] with required fields
func ErrorFrontSide(sourceType, message, fileHash string) *telego.PassportElementErrorFrontSide {
return &telego.PassportElementErrorFrontSide{
Source: telego.ErrorSourceFrontSide,
@@ -633,7 +633,7 @@ func ErrorFrontSide(sourceType, message, fileHash string) *telego.PassportElemen
}
}
-// ErrorReverseSide creates telego.PassportElementErrorReverseSide with required fields
+// ErrorReverseSide creates [telego.PassportElementErrorReverseSide] with required fields
func ErrorReverseSide(sourceType, message, fileHash string) *telego.PassportElementErrorReverseSide {
return &telego.PassportElementErrorReverseSide{
Source: telego.ErrorSourceReverseSide,
@@ -643,7 +643,7 @@ func ErrorReverseSide(sourceType, message, fileHash string) *telego.PassportElem
}
}
-// ErrorSelfie creates telego.PassportElementErrorSelfie with required fields
+// ErrorSelfie creates [telego.PassportElementErrorSelfie] with required fields
func ErrorSelfie(sourceType, message, fileHash string) *telego.PassportElementErrorSelfie {
return &telego.PassportElementErrorSelfie{
Source: telego.ErrorSourceSelfie,
@@ -653,7 +653,7 @@ func ErrorSelfie(sourceType, message, fileHash string) *telego.PassportElementEr
}
}
-// ErrorFile creates telego.PassportElementErrorFile with required fields
+// ErrorFile creates [telego.PassportElementErrorFile] with required fields
func ErrorFile(sourceType, message, fileHash string) *telego.PassportElementErrorFile {
return &telego.PassportElementErrorFile{
Source: telego.ErrorSourceFile,
@@ -663,7 +663,7 @@ func ErrorFile(sourceType, message, fileHash string) *telego.PassportElementErro
}
}
-// ErrorFiles creates telego.PassportElementErrorFiles with required fields
+// ErrorFiles creates [telego.PassportElementErrorFiles] with required fields
func ErrorFiles(sourceType, message string, fileHashes ...string) *telego.PassportElementErrorFiles {
return &telego.PassportElementErrorFiles{
Source: telego.ErrorSourceFiles,
@@ -673,7 +673,7 @@ func ErrorFiles(sourceType, message string, fileHashes ...string) *telego.Passpo
}
}
-// ErrorTranslationFile creates telego.PassportElementErrorTranslationFile with required fields
+// ErrorTranslationFile creates [telego.PassportElementErrorTranslationFile] with required fields
func ErrorTranslationFile(sourceType, message, fileHash string) *telego.PassportElementErrorTranslationFile {
return &telego.PassportElementErrorTranslationFile{
Source: telego.ErrorSourceTranslationFile,
@@ -683,7 +683,7 @@ func ErrorTranslationFile(sourceType, message, fileHash string) *telego.Passport
}
}
-// ErrorTranslationFiles creates telego.PassportElementErrorTranslationFiles with required fields
+// ErrorTranslationFiles creates [telego.PassportElementErrorTranslationFiles] with required fields
func ErrorTranslationFiles(sourceType, message string, fileHashes ...string,
) *telego.PassportElementErrorTranslationFiles {
return &telego.PassportElementErrorTranslationFiles{
@@ -694,7 +694,7 @@ func ErrorTranslationFiles(sourceType, message string, fileHashes ...string,
}
}
-// ErrorUnspecified creates telego.PassportElementErrorUnspecified with required fields
+// ErrorUnspecified creates [telego.PassportElementErrorUnspecified] with required fields
func ErrorUnspecified(sourceType, message, elementHash string) *telego.PassportElementErrorUnspecified {
return &telego.PassportElementErrorUnspecified{
Source: telego.ErrorSourceUnspecified,
@@ -704,7 +704,7 @@ func ErrorUnspecified(sourceType, message, elementHash string) *telego.PassportE
}
}
-// LabeledPrice creates telego.LabeledPrice with required parameters
+// LabeledPrice creates [telego.LabeledPrice] with required parameters
func LabeledPrice(label string, amount int) telego.LabeledPrice {
return telego.LabeledPrice{
Label: label,
@@ -712,7 +712,7 @@ func LabeledPrice(label string, amount int) telego.LabeledPrice {
}
}
-// ShippingOption creates telego.ShippingOption with required parameters
+// ShippingOption creates [telego.ShippingOption] with required parameters
func ShippingOption(id, title string, prices ...telego.LabeledPrice) telego.ShippingOption {
return telego.ShippingOption{
ID: id,
diff --git a/types.go b/types.go
index 0a61a5a3..40e0a78d 100644
--- a/types.go
+++ b/types.go
@@ -2987,7 +2987,7 @@ type ChatMemberUpdated struct {
}
// UnmarshalJSON converts JSON to ChatMemberUpdated
-func (c *ChatMemberUpdated) UnmarshalJSON(data []byte) error { //nolint:funlen,revive,cyclop,gocyclo
+func (c *ChatMemberUpdated) UnmarshalJSON(data []byte) error { //nolint:gocyclo
parser := json.ParserPoll.Get()
defer json.ParserPoll.Put(parser)
@@ -3685,7 +3685,7 @@ type MessageReactionUpdated struct {
}
// UnmarshalJSON converts JSON to MessageReactionUpdated
-func (u *MessageReactionUpdated) UnmarshalJSON(data []byte) error { //nolint:funlen
+func (u *MessageReactionUpdated) UnmarshalJSON(data []byte) error {
parser := json.ParserPoll.Get()
defer json.ParserPoll.Put(parser)
@@ -6793,7 +6793,7 @@ type StarTransaction struct {
}
// UnmarshalJSON converts JSON to Chat
-func (t *StarTransaction) UnmarshalJSON(data []byte) error { //nolint:gocyclo,revive,cyclop,funlen
+func (t *StarTransaction) UnmarshalJSON(data []byte) error { //nolint:gocyclo
parser := json.ParserPoll.Get()
defer json.ParserPoll.Put(parser)
diff --git a/types_setters.go b/types_setters.go
index 217b54ef..61c0731d 100644
--- a/types_setters.go
+++ b/types_setters.go
@@ -140,13 +140,13 @@ func (k KeyboardButton) WithWebApp(webApp *WebAppInfo) KeyboardButton {
// WithUserIsBot adds user is bot parameter
func (k *KeyboardButtonRequestUsers) WithUserIsBot(userIsBot bool) *KeyboardButtonRequestUsers {
- k.UserIsBot = ToPtr(userIsBot)
+ k.UserIsBot = &userIsBot
return k
}
// WithUserIsPremium adds user is premium parameter
func (k *KeyboardButtonRequestUsers) WithUserIsPremium(userIsPremium bool) *KeyboardButtonRequestUsers {
- k.UserIsPremium = ToPtr(userIsPremium)
+ k.UserIsPremium = &userIsPremium
return k
}
@@ -158,19 +158,19 @@ func (k *KeyboardButtonRequestUsers) WithMaxQuantity(maxQuantity int) *KeyboardB
// WithRequestName adds request name parameter
func (k *KeyboardButtonRequestUsers) WithRequestName(requestName bool) *KeyboardButtonRequestUsers {
- k.RequestName = ToPtr(requestName)
+ k.RequestName = &requestName
return k
}
// WithRequestUsername adds request username parameter
func (k *KeyboardButtonRequestUsers) WithRequestUsername(requestUsername bool) *KeyboardButtonRequestUsers {
- k.RequestUsername = ToPtr(requestUsername)
+ k.RequestUsername = &requestUsername
return k
}
// WithRequestPhoto adds request photo parameter
func (k *KeyboardButtonRequestUsers) WithRequestPhoto(requestPhoto bool) *KeyboardButtonRequestUsers {
- k.RequestPhoto = ToPtr(requestPhoto)
+ k.RequestPhoto = &requestPhoto
return k
}
@@ -182,19 +182,19 @@ func (k *KeyboardButtonRequestChat) WithChatIsChannel() *KeyboardButtonRequestCh
// WithChatIsForum adds chat is forum parameter
func (k *KeyboardButtonRequestChat) WithChatIsForum(chatIsForum bool) *KeyboardButtonRequestChat {
- k.ChatIsForum = ToPtr(chatIsForum)
+ k.ChatIsForum = &chatIsForum
return k
}
// WithChatHasUsername adds chat has username parameter
func (k *KeyboardButtonRequestChat) WithChatHasUsername(chatHasUsername bool) *KeyboardButtonRequestChat {
- k.ChatHasUsername = ToPtr(chatHasUsername)
+ k.ChatHasUsername = &chatHasUsername
return k
}
// WithChatIsCreated adds chat is created parameter
func (k *KeyboardButtonRequestChat) WithChatIsCreated(chatIsCreated bool) *KeyboardButtonRequestChat {
- k.ChatIsCreated = ToPtr(chatIsCreated)
+ k.ChatIsCreated = &chatIsCreated
return k
}
@@ -214,25 +214,25 @@ func (k *KeyboardButtonRequestChat) WithBotAdministratorRights(botAdministratorR
// WithBotIsMember adds bot is member parameter
func (k *KeyboardButtonRequestChat) WithBotIsMember(botIsMember bool) *KeyboardButtonRequestChat {
- k.BotIsMember = ToPtr(botIsMember)
+ k.BotIsMember = &botIsMember
return k
}
// WithRequestTitle adds request title parameter
func (k *KeyboardButtonRequestChat) WithRequestTitle(requestTitle bool) *KeyboardButtonRequestChat {
- k.RequestTitle = ToPtr(requestTitle)
+ k.RequestTitle = &requestTitle
return k
}
// WithRequestUsername adds request username parameter
func (k *KeyboardButtonRequestChat) WithRequestUsername(requestUsername bool) *KeyboardButtonRequestChat {
- k.RequestUsername = ToPtr(requestUsername)
+ k.RequestUsername = &requestUsername
return k
}
// WithRequestPhoto adds request photo parameter
func (k *KeyboardButtonRequestChat) WithRequestPhoto(requestPhoto bool) *KeyboardButtonRequestChat {
- k.RequestPhoto = ToPtr(requestPhoto)
+ k.RequestPhoto = &requestPhoto
return k
}
@@ -286,7 +286,7 @@ func (i InlineKeyboardButton) WithLoginURL(loginURL *LoginURL) InlineKeyboardBut
// WithSwitchInlineQuery adds switch inline query parameter
func (i InlineKeyboardButton) WithSwitchInlineQuery(switchInlineQuery string) InlineKeyboardButton {
- i.SwitchInlineQuery = ToPtr(switchInlineQuery)
+ i.SwitchInlineQuery = &switchInlineQuery
return i
}
@@ -294,7 +294,7 @@ func (i InlineKeyboardButton) WithSwitchInlineQuery(switchInlineQuery string) In
func (i InlineKeyboardButton) WithSwitchInlineQueryCurrentChat(
switchInlineQueryCurrentChat string,
) InlineKeyboardButton {
- i.SwitchInlineQueryCurrentChat = ToPtr(switchInlineQueryCurrentChat)
+ i.SwitchInlineQueryCurrentChat = &switchInlineQueryCurrentChat
return i
}
diff --git a/webhook.go b/webhook.go
index 882b7236..e5bd4d94 100644
--- a/webhook.go
+++ b/webhook.go
@@ -2,102 +2,64 @@ package telego
import (
"context"
- "errors"
"fmt"
- "sync"
-
- "github.com/fasthttp/router"
- "github.com/valyala/fasthttp"
"github.com/mymmrac/telego/internal/json"
)
const defaultWebhookUpdateChanBuffer = 128
-// WebhookHandler user handler for incoming updates, context will be passed into update
+// WebhookHandler user handler for incoming updates, context will be passed into update, user is responsible go pass
+// JSON data of update from his own server, and it will be decoded and returned to update chan, also user is
+// responsible for validating request (and secret token from headers)
//
// Warning: Common approach of HTTP servers is to cancel context once request connection is closed,
// but in webhook handler update is sent to the channel and not processed in request lifetime,
// so remember to wrap context in [context.WithoutCancel] as webhook helper will not do that automatically
type WebhookHandler func(ctx context.Context, data []byte) error
-// WebhookServer represents generic webhook server
-type WebhookServer interface {
- Start(address string) error
- Stop(ctx context.Context) error
- RegisterHandler(path string, handler WebhookHandler) error
-}
-
-// webhookContext represents configuration of getting updates via webhook
-type webhookContext struct {
- running bool
- configured bool
- runningLock sync.RWMutex
- stop chan struct{}
-
- server WebhookServer
-
+// webhook represents configuration of getting updates via webhook
+type webhook struct {
updateChanBuffer uint
}
-// WebhookOption represents an option that can be applied to webhookContext
-type WebhookOption func(bot *Bot, ctx *webhookContext) error
+// WebhookOption represents an option that can be applied to webhook
+type WebhookOption func(bot *Bot, ctx *webhook) error
// WithWebhookBuffer sets buffering for update chan. Default is 128.
func WithWebhookBuffer(chanBuffer uint) WebhookOption {
- return func(_ *Bot, ctx *webhookContext) error {
- ctx.updateChanBuffer = chanBuffer
- return nil
- }
-}
-
-// WithWebhookServer sets webhook server to use for webhook. Default is FastHTTPWebhookServer
-func WithWebhookServer(server WebhookServer) WebhookOption {
- return func(_ *Bot, ctx *webhookContext) error {
- if server == nil {
- return errors.New("webhook server is nil")
- }
-
- ctx.server = server
+ return func(_ *Bot, wh *webhook) error {
+ wh.updateChanBuffer = chanBuffer
return nil
}
}
// WithWebhookSet calls [Bot.SetWebhook] method before starting webhook
// Note: Calling [Bot.SetWebhook] method multiple times in a row may give "too many requests" errors
-func WithWebhookSet(params *SetWebhookParams) WebhookOption {
- return func(bot *Bot, _ *webhookContext) error {
- return bot.SetWebhook(params)
+func WithWebhookSet(ctx context.Context, params *SetWebhookParams) WebhookOption {
+ return func(bot *Bot, _ *webhook) error {
+ return bot.SetWebhook(ctx, params)
}
}
-// errWebhookStopped returned if webhook is stopped
-var errWebhookStopped = errors.New("telego: webhook stopped")
-
-// UpdatesViaWebhook receive updates in chan from webhook.
-// A new handler with a provided path will be registered on server.
-// Calling if already configured (before [Bot.StopWebhook] method) will return an error.
-// Note: Once stopped, update chan will be closed
-func (b *Bot) UpdatesViaWebhook(path string, options ...WebhookOption) (<-chan Update, error) {
- if b.webhookContext != nil {
- return nil, errors.New("telego: webhook context already exists")
+// UpdatesViaWebhook receive updates in chan from webhook. A new handler will be registered on server.
+// Calling if already running webhook or long polling will return an error.
+func (b *Bot) UpdatesViaWebhook(
+ ctx context.Context, registerHandler func(handler WebhookHandler) error, options ...WebhookOption,
+) (<-chan Update, error) {
+ if err := b.run(runningWebhook); err != nil {
+ return nil, err
}
- webhookCtx, err := b.createWebhookContext(options)
+ wh, err := b.createWebhook(options)
if err != nil {
+ b.running.Store(runningNone)
return nil, err
}
- webhookCtx.runningLock.Lock()
- defer webhookCtx.runningLock.Unlock()
-
- b.webhookContext = webhookCtx
- webhookCtx.stop = make(chan struct{})
- webhookCtx.configured = true
-
- updatesChan := make(chan Update, webhookCtx.updateChanBuffer)
+ updatesChan := make(chan Update, wh.updateChanBuffer)
- err = webhookCtx.server.RegisterHandler(path, func(ctx context.Context, data []byte) error {
+ err = registerHandler(func(ctx context.Context, data []byte) error {
b.log.Debugf("Webhook request with data: %s", string(data))
var update Update
@@ -108,132 +70,37 @@ func (b *Bot) UpdatesViaWebhook(path string, options ...WebhookOption) (<-chan U
}
select {
- case <-webhookCtx.stop:
- return errWebhookStopped
case <-ctx.Done():
return fmt.Errorf("telego: webhook handler context: %w", ctx.Err())
- default:
- if safeSend(updatesChan, update.WithContext(ctx)) {
- return errWebhookStopped
- }
+ case updatesChan <- update.WithContext(ctx):
return nil
}
})
if err != nil {
+ b.running.Store(runningNone)
return nil, fmt.Errorf("telego: webhook register handler: %w", err)
}
go func() {
- <-webhookCtx.stop
+ <-ctx.Done()
+ b.running.Store(runningNone)
close(updatesChan)
}()
return updatesChan, nil
}
-func (b *Bot) createWebhookContext(options []WebhookOption) (*webhookContext, error) {
- ctx := &webhookContext{
- server: FastHTTPWebhookServer{
- Logger: b.Logger(),
- Server: &fasthttp.Server{},
- Router: router.New(),
- },
+// createWebhook creates webhook configuration
+func (b *Bot) createWebhook(options []WebhookOption) (*webhook, error) {
+ wh := &webhook{
updateChanBuffer: defaultWebhookUpdateChanBuffer,
}
for _, option := range options {
- if err := option(b, ctx); err != nil {
- return nil, fmt.Errorf("telego: options: %w", err)
+ if err := option(b, wh); err != nil {
+ return nil, fmt.Errorf("telego: webhook options: %w", err)
}
}
- return ctx, nil
-}
-
-// StartWebhook start server for listening for webhook, blocking operation.
-// Any error that occurs will stop the webhook.
-// Calling before [Bot.UpdatesViaWebhook] method will return an error.
-// Calling if already running (before [Bot.StopWebhook] method) will return an error.
-// Note: After you done with getting updates, you should call [Bot.StopWebhook] method to stop the server
-func (b *Bot) StartWebhook(address string) error {
- ctx := b.webhookContext
- if ctx == nil {
- return errors.New("telego: webhook context does not exist")
- }
-
- ctx.runningLock.RLock()
- if !ctx.configured {
- ctx.runningLock.RUnlock()
- return errors.New("telego: webhook context not configured")
- }
-
- if ctx.running {
- ctx.runningLock.RUnlock()
- return errors.New("telego: webhook already running")
- }
- ctx.runningLock.RUnlock()
-
- ctx.runningLock.Lock()
- ctx.running = true
- ctx.runningLock.Unlock()
-
- if err := ctx.server.Start(address); err != nil {
- ctx.runningLock.Lock()
- if ctx.running {
- close(ctx.stop)
- ctx.running = false
- }
- b.webhookContext = nil
- ctx.runningLock.Unlock()
-
- return err
- }
-
- return nil
-}
-
-// IsRunningWebhook tells if webhook server is running
-func (b *Bot) IsRunningWebhook() bool {
- ctx := b.webhookContext
- if ctx == nil {
- return false
- }
-
- ctx.runningLock.RLock()
- defer ctx.runningLock.RUnlock()
-
- return ctx.running
-}
-
-// StopWebhookWithContext shutdown webhook server used in the [Bot.UpdatesViaWebhook] method.
-// Stopping will stop new updates from coming, but processing updates should be handled by the caller.
-// Stop will only ensure that no more updates will come in update chan.
-// Calling [Bot.StopWebhookWithContext] method multiple times does nothing.
-func (b *Bot) StopWebhookWithContext(ctx context.Context) error {
- webhookCtx := b.webhookContext
- if webhookCtx == nil {
- return nil
- }
-
- webhookCtx.runningLock.Lock()
- defer webhookCtx.runningLock.Unlock()
-
- if webhookCtx.running {
- err := webhookCtx.server.Stop(ctx)
-
- close(webhookCtx.stop)
- webhookCtx.running = false
-
- b.webhookContext = nil
- return err
- }
-
- b.webhookContext = nil
- return nil
-}
-
-// StopWebhook shutdown webhook server used in the [Bot.UpdatesViaWebhook] method
-// Note: For more info, see [Bot.StopWebhookWithContext] method
-func (b *Bot) StopWebhook() error {
- return b.StopWebhookWithContext(context.Background())
+ return wh, nil
}
diff --git a/webhook_handler.go b/webhook_handler.go
new file mode 100644
index 00000000..5ba7e3e2
--- /dev/null
+++ b/webhook_handler.go
@@ -0,0 +1,118 @@
+package telego
+
+import (
+ "io"
+ "net/http"
+
+ "github.com/valyala/fasthttp"
+)
+
+// WebhookSecretTokenHeader represents secret token header name, see [SetWebhookParams.SecretToken] for more details
+const WebhookSecretTokenHeader = "X-Telegram-Bot-Api-Secret-Token" //nolint:gosec
+
+// WebhookFastHTTP registers new POST handler for the desired path with optional secret token, replacing
+// the original fasthttp handler for the server
+func WebhookFastHTTP(server *fasthttp.Server, path string, secretToken ...string) func(handler WebhookHandler) error {
+ if path == "" {
+ path = "/"
+ }
+ return func(handler WebhookHandler) error {
+ server.Handler = func(fCtx *fasthttp.RequestCtx) {
+ if string(fCtx.Path()) != path {
+ fCtx.SetStatusCode(fasthttp.StatusNotFound)
+ return
+ }
+
+ if !fCtx.Request.Header.IsPost() {
+ fCtx.SetStatusCode(fasthttp.StatusMethodNotAllowed)
+ return
+ }
+
+ if len(secretToken) > 0 && secretToken[0] != string(fCtx.Request.Header.Peek(WebhookSecretTokenHeader)) {
+ fCtx.SetStatusCode(fasthttp.StatusUnauthorized)
+ return
+ }
+
+ if err := handler(fCtx, fCtx.PostBody()); err != nil {
+ fCtx.SetStatusCode(fasthttp.StatusInternalServerError)
+ return
+ }
+
+ fCtx.SetStatusCode(fasthttp.StatusOK)
+ }
+ return nil
+ }
+}
+
+// WebhookHTTPServer registers new POST handler for the desired path with optional secret token, replacing
+// the original http handler for the server
+func WebhookHTTPServer(server *http.Server, path string, secretToken ...string) func(handler WebhookHandler) error {
+ if path == "" {
+ path = "/"
+ }
+ return func(handler WebhookHandler) error {
+ server.Handler = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
+ defer func() { _ = request.Body.Close() }() //nolint:errcheck
+
+ if request.URL.Path != path {
+ writer.WriteHeader(http.StatusNotFound)
+ return
+ }
+
+ if request.Method != http.MethodPost {
+ writer.WriteHeader(http.StatusMethodNotAllowed)
+ return
+ }
+
+ if len(secretToken) > 0 && secretToken[0] != request.Header.Get(WebhookSecretTokenHeader) {
+ writer.WriteHeader(http.StatusUnauthorized)
+ return
+ }
+
+ data, err := io.ReadAll(request.Body)
+ if err != nil {
+ writer.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ if err = handler(request.Context(), data); err != nil {
+ writer.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ writer.WriteHeader(http.StatusOK)
+ })
+ return nil
+ }
+}
+
+// WebhookHTTPServeMux registers new handler for the desired pattern with optional secret token
+func WebhookHTTPServeMux(mux *http.ServeMux, pattern string, secretToken ...string) func(handler WebhookHandler) error {
+ if pattern == "" {
+ pattern = "POST /"
+ }
+ return func(handler WebhookHandler) error {
+ mux.HandleFunc(pattern, func(writer http.ResponseWriter, request *http.Request) {
+ defer func() { _ = request.Body.Close() }() //nolint:errcheck
+
+ if len(secretToken) > 0 && secretToken[0] != request.Header.Get(WebhookSecretTokenHeader) {
+ writer.WriteHeader(http.StatusUnauthorized)
+ return
+ }
+
+ data, err := io.ReadAll(request.Body)
+ if err != nil {
+ writer.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ if err = handler(request.Context(), data); err != nil {
+ writer.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+
+ writer.WriteHeader(http.StatusOK)
+ })
+ return nil
+ }
+}
diff --git a/webhook_handler_test.go b/webhook_handler_test.go
new file mode 100644
index 00000000..34508afe
--- /dev/null
+++ b/webhook_handler_test.go
@@ -0,0 +1,191 @@
+package telego
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "github.com/valyala/fasthttp"
+)
+
+func TestWebhookFastHTTP(t *testing.T) {
+ srv := &fasthttp.Server{}
+ handler := WebhookFastHTTP(srv, "/", "secret")
+
+ err := handler(func(ctx context.Context, data []byte) error {
+ require.NotNil(t, ctx)
+ if len(data) == 0 {
+ return errors.New("empty data")
+ }
+ return nil
+ })
+ require.NoError(t, err)
+
+ t.Run("success", func(t *testing.T) {
+ ctx := &fasthttp.RequestCtx{}
+ ctx.Request.SetRequestURI("/")
+ ctx.Request.Header.SetMethod(fasthttp.MethodPost)
+ ctx.Request.Header.Set(WebhookSecretTokenHeader, "secret")
+ ctx.Request.SetBody([]byte("{}"))
+ srv.Handler(ctx)
+
+ assert.Equal(t, fasthttp.StatusOK, ctx.Response.StatusCode())
+ })
+
+ t.Run("error_method", func(t *testing.T) {
+ ctx := &fasthttp.RequestCtx{}
+ ctx.Request.SetRequestURI("/")
+ ctx.Request.Header.SetMethod(fasthttp.MethodGet)
+ srv.Handler(ctx)
+
+ assert.Equal(t, fasthttp.StatusMethodNotAllowed, ctx.Response.StatusCode())
+ })
+
+ t.Run("error_handler", func(t *testing.T) {
+ ctx := &fasthttp.RequestCtx{}
+ ctx.Request.SetRequestURI("/")
+ ctx.Request.Header.SetMethod(fasthttp.MethodPost)
+ ctx.Request.Header.Set(WebhookSecretTokenHeader, "secret")
+ srv.Handler(ctx)
+
+ assert.Equal(t, fasthttp.StatusInternalServerError, ctx.Response.StatusCode())
+ })
+
+ t.Run("secret_token_invalid", func(t *testing.T) {
+ ctx := &fasthttp.RequestCtx{}
+ ctx.Request.SetRequestURI("/")
+ ctx.Request.Header.SetMethod(fasthttp.MethodPost)
+ srv.Handler(ctx)
+
+ assert.Equal(t, fasthttp.StatusUnauthorized, ctx.Response.StatusCode())
+ })
+}
+
+func TestWebhookHTTPServer(t *testing.T) {
+ srv := &http.Server{} //nolint:gosec
+ handler := WebhookHTTPServer(srv, "/", "secret")
+
+ err := handler(func(ctx context.Context, data []byte) error {
+ require.NotNil(t, ctx)
+ if len(data) == 0 {
+ return errors.New("empty data")
+ }
+ return nil
+ })
+ require.NoError(t, err)
+
+ t.Run("success", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodPost, "/", nil)
+ req.Header.Set(WebhookSecretTokenHeader, "secret")
+ req.Body = io.NopCloser(bytes.NewReader([]byte("{}")))
+ srv.Handler.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusOK, rc.Code)
+ })
+
+ t.Run("error_method", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodGet, "/", nil)
+ srv.Handler.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusMethodNotAllowed, rc.Code)
+ })
+
+ t.Run("error_handler", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(""))
+ req.Header.Set(WebhookSecretTokenHeader, "secret")
+ srv.Handler.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusInternalServerError, rc.Code)
+ })
+
+ t.Run("error_read", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodPost, "/", errReader{})
+ req.Header.Set(WebhookSecretTokenHeader, "secret")
+ srv.Handler.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusInternalServerError, rc.Code)
+ })
+
+ t.Run("secret_token_invalid", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodPost, "/", nil)
+ srv.Handler.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusUnauthorized, rc.Code)
+ })
+}
+
+func TestWebhookHTTPServeMux(t *testing.T) {
+ mux := &http.ServeMux{}
+ handler := WebhookHTTPServeMux(mux, "POST /", "secret")
+
+ err := handler(func(ctx context.Context, data []byte) error {
+ require.NotNil(t, ctx)
+ if len(data) == 0 {
+ return errors.New("empty data")
+ }
+ return nil
+ })
+ require.NoError(t, err)
+
+ t.Run("success", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodPost, "/", nil)
+ req.Header.Set(WebhookSecretTokenHeader, "secret")
+ req.Body = io.NopCloser(bytes.NewReader([]byte("{}")))
+ mux.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusOK, rc.Code)
+ })
+
+ t.Run("error_method", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodGet, "/", nil)
+ mux.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusMethodNotAllowed, rc.Code)
+ })
+
+ t.Run("error_handler", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(""))
+ req.Header.Set(WebhookSecretTokenHeader, "secret")
+ mux.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusInternalServerError, rc.Code)
+ })
+
+ t.Run("error_read", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodPost, "/", errReader{})
+ req.Header.Set(WebhookSecretTokenHeader, "secret")
+ mux.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusInternalServerError, rc.Code)
+ })
+
+ t.Run("secret_token_invalid", func(t *testing.T) {
+ rc := httptest.NewRecorder()
+ req := httptest.NewRequest(http.MethodPost, "/", nil)
+ mux.ServeHTTP(rc, req)
+
+ assert.Equal(t, http.StatusUnauthorized, rc.Code)
+ })
+}
+
+type errReader struct{}
+
+func (e errReader) Read(_ []byte) (n int, err error) {
+ return 0, errTest
+}
diff --git a/webhook_server.go b/webhook_server.go
deleted file mode 100644
index 3cd5e141..00000000
--- a/webhook_server.go
+++ /dev/null
@@ -1,255 +0,0 @@
-package telego
-
-import (
- "context"
- "errors"
- "io"
- "net/http"
- "sync"
-
- "github.com/fasthttp/router"
- "github.com/valyala/fasthttp"
-)
-
-// WebhookSecretTokenHeader represents secret token header name, see [SetWebhookParams.SecretToken] for more details
-const WebhookSecretTokenHeader = "X-Telegram-Bot-Api-Secret-Token" //nolint:gosec
-
-// FastHTTPWebhookServer represents fasthttp implementation of [WebhookServer].
-// The Server and Router are required fields, optional Logger and SecretToken can be provided.
-type FastHTTPWebhookServer struct {
- Logger Logger
- Server *fasthttp.Server
- Router *router.Router
- SecretToken string
-}
-
-// Start starts server
-func (f FastHTTPWebhookServer) Start(address string) error {
- return f.Server.ListenAndServe(address)
-}
-
-// Stop stops server
-func (f FastHTTPWebhookServer) Stop(ctx context.Context) error {
- return f.Server.ShutdownWithContext(ctx)
-}
-
-// RegisterHandler registers new POST handler for the desired path
-// Note: If server's handler is not set, it will be set to router's handler
-func (f FastHTTPWebhookServer) RegisterHandler(path string, handler WebhookHandler) error {
- f.Router.POST(path, func(ctx *fasthttp.RequestCtx) {
- if f.SecretToken != "" {
- secretToken := ctx.Request.Header.Peek(WebhookSecretTokenHeader)
- if f.SecretToken != string(secretToken) {
- if f.Logger != nil {
- f.Logger.Errorf("Webhook handler: unauthorized: secret token does not match")
- }
-
- ctx.SetStatusCode(fasthttp.StatusUnauthorized)
- return
- }
- }
-
- if err := handler(context.WithoutCancel(ctx), ctx.PostBody()); err != nil {
- if f.Logger != nil {
- f.Logger.Errorf("Webhook handler: %s", err)
- }
-
- ctx.SetStatusCode(fasthttp.StatusInternalServerError)
- return
- }
-
- ctx.SetStatusCode(fasthttp.StatusOK)
- })
-
- if f.Server.Handler == nil {
- f.Server.Handler = f.Router.Handler
- }
-
- return nil
-}
-
-// HTTPWebhookServer represents http implementation of [WebhookServer].
-// The Server and ServeMux are required fields, optional Logger and SecretToken can be provided.
-type HTTPWebhookServer struct {
- Logger Logger
- Server *http.Server
- ServeMux *http.ServeMux
- SecretToken string
-}
-
-// Start starts server
-func (h HTTPWebhookServer) Start(address string) error {
- if h.Server.Addr == "" {
- h.Server.Addr = address
- }
- if err := h.Server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
- return err
- }
-
- return nil
-}
-
-// Stop stops server
-func (h HTTPWebhookServer) Stop(ctx context.Context) error {
- return h.Server.Shutdown(ctx)
-}
-
-// RegisterHandler registers new POST handler for the desired path
-// Note: If server's handler is not set, it will be set to serve mux handler
-func (h HTTPWebhookServer) RegisterHandler(path string, handler WebhookHandler) error {
- h.ServeMux.HandleFunc(path, func(writer http.ResponseWriter, request *http.Request) {
- if !h.validateRequest(writer, request) {
- return
- }
-
- data, err := h.readData(request)
- if err != nil {
- writer.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- if err = handler(context.WithoutCancel(request.Context()), data); err != nil {
- if h.Logger != nil {
- h.Logger.Errorf("Webhook handler: %s", err)
- }
-
- writer.WriteHeader(http.StatusInternalServerError)
- return
- }
-
- writer.WriteHeader(http.StatusOK)
- })
-
- if h.Server.Handler == nil {
- h.Server.Handler = h.ServeMux
- }
-
- return nil
-}
-
-func (h HTTPWebhookServer) validateRequest(writer http.ResponseWriter, request *http.Request) bool {
- if request.Method != http.MethodPost {
- writer.WriteHeader(http.StatusMethodNotAllowed)
- return false
- }
-
- if h.SecretToken != "" {
- secretToken := request.Header.Get(WebhookSecretTokenHeader)
- if h.SecretToken != secretToken {
- if h.Logger != nil {
- h.Logger.Errorf("Webhook handler: unauthorized: secret token does not match")
- }
-
- writer.WriteHeader(http.StatusUnauthorized)
- return false
- }
- }
-
- return true
-}
-
-func (h HTTPWebhookServer) readData(request *http.Request) ([]byte, error) {
- data, err := io.ReadAll(request.Body)
- if err != nil {
- if h.Logger != nil {
- h.Logger.Errorf("Webhook handler: read body: %s", err)
- }
-
- return nil, err
- }
-
- if err = request.Body.Close(); err != nil {
- if h.Logger != nil {
- h.Logger.Errorf("Webhook handler: close body: %s", err)
- }
- }
-
- return data, nil
-}
-
-// MultiBotWebhookServer represents multi bot implementation of [WebhookServer],
-// suitable for running multiple bots from a single server
-type MultiBotWebhookServer struct {
- Server WebhookServer
-
- startOnce sync.Once
- stopOnce sync.Once
-}
-
-// Start starts server only once
-func (m *MultiBotWebhookServer) Start(address string) error {
- var err error
- m.startOnce.Do(func() {
- err = m.Server.Start(address)
- })
- return err
-}
-
-// Stop stops server only once
-func (m *MultiBotWebhookServer) Stop(ctx context.Context) error {
- var err error
- m.stopOnce.Do(func() {
- err = m.Server.Stop(ctx)
- })
- return err
-}
-
-// RegisterHandler registers new handler for the desired path
-func (m *MultiBotWebhookServer) RegisterHandler(path string, handler WebhookHandler) error {
- return m.Server.RegisterHandler(path, handler)
-}
-
-// NoOpWebhookServer represents no-op implementation of [WebhookServer],
-// suitable for cases when you want to have full control over start & stop of server manually
-type NoOpWebhookServer struct {
- RegisterHandlerFunc func(path string, handler WebhookHandler) error
-}
-
-// Start does nothing
-func (n NoOpWebhookServer) Start(_ string) error {
- return nil
-}
-
-// Stop does nothing
-func (n NoOpWebhookServer) Stop(_ context.Context) error {
- return nil
-}
-
-// RegisterHandler registers new handler for the desired path
-func (n NoOpWebhookServer) RegisterHandler(path string, handler WebhookHandler) error {
- return n.RegisterHandlerFunc(path, handler)
-}
-
-// FuncWebhookServer represents func implementation of [WebhookServer],
-// uses provided functions instead of server's methods to override behavior if any of function are not
-// provided respective server's methods will be used
-type FuncWebhookServer struct {
- Server WebhookServer
- StartFunc func(address string) error
- StopFunc func(ctx context.Context) error
- RegisterHandlerFunc func(path string, handler WebhookHandler) error
-}
-
-// Start using func or server's method
-func (f FuncWebhookServer) Start(address string) error {
- if f.StartFunc != nil {
- return f.StartFunc(address)
- }
- return f.Server.Start(address)
-}
-
-// Stop using func or server's method
-func (f FuncWebhookServer) Stop(ctx context.Context) error {
- if f.StopFunc != nil {
- return f.StopFunc(ctx)
- }
- return f.Server.Stop(ctx)
-}
-
-// RegisterHandler using func or server's method
-func (f FuncWebhookServer) RegisterHandler(path string, handler WebhookHandler) error {
- if f.RegisterHandlerFunc != nil {
- return f.RegisterHandlerFunc(path, handler)
- }
- return f.Server.RegisterHandler(path, handler)
-}
diff --git a/webhook_server_test.go b/webhook_server_test.go
deleted file mode 100644
index 5b20457a..00000000
--- a/webhook_server_test.go
+++ /dev/null
@@ -1,350 +0,0 @@
-package telego
-
-import (
- "context"
- "io"
- "net/http"
- "net/http/httptest"
- "strings"
- "testing"
- "time"
-
- "github.com/fasthttp/router"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "github.com/valyala/fasthttp"
-)
-
-func TestFastHTTPWebhookServer_RegisterHandler(t *testing.T) {
- require.Implements(t, (*WebhookServer)(nil), FastHTTPWebhookServer{})
-
- addr := testAddress(t)
-
- s := FastHTTPWebhookServer{
- Logger: testLoggerType{},
- Server: &fasthttp.Server{},
- Router: router.New(),
- SecretToken: "secret",
- }
-
- go func() {
- err := s.Start(addr)
- assert.NoError(t, err)
- }()
-
- err := s.RegisterHandler("/", func(_ context.Context, data []byte) error {
- if len(data) == 0 {
- return nil
- }
-
- return errTest
- })
- require.NoError(t, err)
-
- t.Run("success", func(t *testing.T) {
- ctx := &fasthttp.RequestCtx{}
- ctx.Request.SetRequestURI("/")
- ctx.Request.Header.SetMethod(fasthttp.MethodPost)
- ctx.Request.Header.Set(WebhookSecretTokenHeader, s.SecretToken)
- s.Server.Handler(ctx)
-
- assert.Equal(t, fasthttp.StatusOK, ctx.Response.StatusCode())
- })
-
- t.Run("error_method", func(t *testing.T) {
- ctx := &fasthttp.RequestCtx{}
- ctx.Request.SetRequestURI("/")
- ctx.Request.Header.SetMethod(fasthttp.MethodGet)
- s.Server.Handler(ctx)
-
- assert.Equal(t, fasthttp.StatusMethodNotAllowed, ctx.Response.StatusCode())
- })
-
- t.Run("error_handler", func(t *testing.T) {
- ctx := &fasthttp.RequestCtx{}
- ctx.Request.SetRequestURI("/")
- ctx.Request.Header.SetMethod(fasthttp.MethodPost)
- ctx.Request.Header.Set(WebhookSecretTokenHeader, s.SecretToken)
- ctx.Request.SetBody([]byte("err"))
- s.Server.Handler(ctx)
-
- assert.Equal(t, fasthttp.StatusInternalServerError, ctx.Response.StatusCode())
- })
-
- t.Run("secret_token_invalid", func(t *testing.T) {
- ctx := &fasthttp.RequestCtx{}
- ctx.Request.SetRequestURI("/")
- ctx.Request.Header.SetMethod(fasthttp.MethodPost)
- s.Server.Handler(ctx)
-
- assert.Equal(t, fasthttp.StatusUnauthorized, ctx.Response.StatusCode())
- })
-
- err = s.Stop(context.Background())
- require.NoError(t, err)
-}
-
-func TestHTTPWebhookServer_RegisterHandler(t *testing.T) {
- require.Implements(t, (*WebhookServer)(nil), HTTPWebhookServer{})
-
- t.Run("error_start_fail", func(t *testing.T) {
- s := HTTPWebhookServer{
- Logger: testLoggerType{},
- Server: &http.Server{}, //nolint:gosec
- ServeMux: http.NewServeMux(),
- }
-
- testAddr := testAddress(t)
- go func() {
- err := http.ListenAndServe(testAddr, nil) //nolint:gosec
- assert.NoError(t, err)
- }()
-
- time.Sleep(time.Millisecond * 10)
-
- err := s.Start(testAddr)
- require.Error(t, err)
- })
-
- t.Run("end_to_end", func(t *testing.T) {
- s := HTTPWebhookServer{
- Logger: testLoggerType{},
- Server: &http.Server{}, //nolint:gosec
- ServeMux: http.NewServeMux(),
- SecretToken: "secret",
- }
-
- go func() {
- err := s.Start(testAddress(t))
- assert.NoError(t, err)
- }()
-
- err := s.RegisterHandler("/", func(_ context.Context, data []byte) error {
- if len(data) == 0 {
- return nil
- }
-
- return errTest
- })
- require.NoError(t, err)
-
- t.Run("success", func(t *testing.T) {
- rc := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodPost, "/", nil)
- req.Header.Set(WebhookSecretTokenHeader, s.SecretToken)
-
- s.Server.Handler.ServeHTTP(rc, req)
-
- assert.Equal(t, http.StatusOK, rc.Code)
- })
-
- t.Run("error_method", func(t *testing.T) {
- rc := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodGet, "/", nil)
-
- s.Server.Handler.ServeHTTP(rc, req)
-
- assert.Equal(t, http.StatusMethodNotAllowed, rc.Code)
- })
-
- t.Run("error_handler", func(t *testing.T) {
- rc := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader("err"))
- req.Header.Set(WebhookSecretTokenHeader, s.SecretToken)
-
- s.Server.Handler.ServeHTTP(rc, req)
-
- assert.Equal(t, http.StatusInternalServerError, rc.Code)
- })
-
- t.Run("error_read", func(t *testing.T) {
- rc := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodPost, "/", errReader{})
- req.Header.Set(WebhookSecretTokenHeader, s.SecretToken)
-
- s.Server.Handler.ServeHTTP(rc, req)
-
- assert.Equal(t, http.StatusInternalServerError, rc.Code)
- })
-
- t.Run("error_close", func(t *testing.T) {
- rc := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodPost, "/", errReaderCloser{reader: strings.NewReader("ok")})
- req.Header.Set(WebhookSecretTokenHeader, s.SecretToken)
-
- s.Server.Handler.ServeHTTP(rc, req)
-
- assert.Equal(t, http.StatusInternalServerError, rc.Code)
- })
-
- t.Run("secret_token_invalid", func(t *testing.T) {
- rc := httptest.NewRecorder()
- req := httptest.NewRequest(http.MethodPost, "/", nil)
-
- s.Server.Handler.ServeHTTP(rc, req)
-
- assert.Equal(t, http.StatusUnauthorized, rc.Code)
- })
-
- err = s.Stop(context.Background())
- require.NoError(t, err)
- })
-}
-
-type errReader struct{}
-
-func (e errReader) Read(_ []byte) (n int, err error) {
- return 0, errTest
-}
-
-type errReaderCloser struct {
- reader io.Reader
-}
-
-func (e errReaderCloser) Close() error {
- return errTest
-}
-
-func (e errReaderCloser) Read(b []byte) (n int, err error) {
- return e.reader.Read(b)
-}
-
-func TestMultiBotWebhookServer_RegisterHandler(t *testing.T) {
- require.Implements(t, (*WebhookServer)(nil), &MultiBotWebhookServer{})
-
- ts := &testServer{}
- s := &MultiBotWebhookServer{
- Server: ts,
- }
-
- assert.Equal(t, 0, ts.started)
- assert.Equal(t, 0, ts.stopped)
- assert.Equal(t, 0, ts.registered)
-
- err := s.Start("")
- require.NoError(t, err)
- assert.Equal(t, 1, ts.started)
-
- err = s.Start("")
- require.NoError(t, err)
- assert.Equal(t, 1, ts.started)
-
- err = s.RegisterHandler("", nil)
- require.NoError(t, err)
- assert.Equal(t, 1, ts.registered)
-
- err = s.RegisterHandler("", nil)
- require.NoError(t, err)
- assert.Equal(t, 2, ts.registered)
-
- err = s.Stop(context.Background())
- require.NoError(t, err)
- assert.Equal(t, 1, ts.stopped)
-
- err = s.Stop(context.Background())
- require.NoError(t, err)
- assert.Equal(t, 1, ts.stopped)
-}
-
-type testServer struct {
- started int
- stopped int
- registered int
-}
-
-func (t *testServer) Start(_ string) error {
- t.started++
- return nil
-}
-
-func (t *testServer) Stop(_ context.Context) error {
- t.stopped++
- return nil
-}
-
-func (t *testServer) RegisterHandler(_ string, _ WebhookHandler) error {
- t.registered++
- return nil
-}
-
-func TestNoOpWebhookServer(t *testing.T) {
- require.Implements(t, (*WebhookServer)(nil), NoOpWebhookServer{})
-
- registered := false
- s := NoOpWebhookServer{
- RegisterHandlerFunc: func(path string, handler WebhookHandler) error {
- registered = true
- return nil
- },
- }
-
- err := s.Start("")
- require.NoError(t, err)
- err = s.Stop(nil) //nolint:staticcheck
- require.NoError(t, err)
- err = s.RegisterHandler("", nil)
- require.NoError(t, err)
- assert.True(t, registered)
-}
-
-func TestFuncWebhookServer(t *testing.T) {
- require.Implements(t, (*WebhookServer)(nil), FuncWebhookServer{})
-
- ts := &testServer{}
- s1 := FuncWebhookServer{
- Server: ts,
- }
-
- assert.Equal(t, 0, ts.started)
- assert.Equal(t, 0, ts.stopped)
- assert.Equal(t, 0, ts.registered)
-
- err := s1.Start("")
- require.NoError(t, err)
-
- err = s1.RegisterHandler("", nil)
- require.NoError(t, err)
-
- err = s1.Stop(context.Background())
- require.NoError(t, err)
-
- assert.Equal(t, 1, ts.started)
- assert.Equal(t, 1, ts.stopped)
- assert.Equal(t, 1, ts.registered)
-
- started := 0
- stopped := 0
- registered := 0
- s2 := FuncWebhookServer{
- Server: ts,
- StartFunc: func(_ string) error {
- started++
- return nil
- },
- StopFunc: func(_ context.Context) error {
- stopped++
- return nil
- },
- RegisterHandlerFunc: func(_ string, _ WebhookHandler) error {
- registered++
- return nil
- },
- }
-
- err = s2.Start("")
- require.NoError(t, err)
-
- err = s2.RegisterHandler("", nil)
- require.NoError(t, err)
-
- err = s2.Stop(context.Background())
- require.NoError(t, err)
-
- assert.Equal(t, 1, ts.started)
- assert.Equal(t, 1, ts.stopped)
- assert.Equal(t, 1, ts.registered)
-
- assert.Equal(t, 1, started)
- assert.Equal(t, 1, stopped)
- assert.Equal(t, 1, registered)
-}
diff --git a/webhook_test.go b/webhook_test.go
index e8435ae8..d6351caf 100644
--- a/webhook_test.go
+++ b/webhook_test.go
@@ -2,156 +2,65 @@ package telego
import (
"bytes"
- "net/http"
"testing"
"time"
- "github.com/fasthttp/router"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "github.com/valyala/fasthttp"
"go.uber.org/mock/gomock"
"github.com/mymmrac/telego/internal/json"
ta "github.com/mymmrac/telego/telegoapi"
)
-func testWebhookBot(t *testing.T) *Bot {
- t.Helper()
-
- b, err := NewBot(token, WithDiscardLogger())
- require.NoError(t, err)
-
- b.webhookContext = &webhookContext{
- running: false,
- configured: true,
- server: FastHTTPWebhookServer{
- Server: &fasthttp.Server{},
- Router: router.New(),
- },
- stop: make(chan struct{}),
- }
-
- return b
-}
-
-func TestBot_StartWebhook(t *testing.T) {
- t.Run("success_and_error_already_running_and_start_fail", func(t *testing.T) {
- b := testWebhookBot(t)
-
- testAddr := testAddress(t)
-
- assert.NotPanics(t, func() {
- go func() {
- err := b.StartWebhook(testAddr)
- assert.NoError(t, err)
- }()
- time.Sleep(time.Millisecond * 10)
- })
-
- assert.NotPanics(t, func() {
- err := b.StartWebhook("test")
- require.Error(t, err)
- })
-
- b.webhookContext.running = false
- assert.NotPanics(t, func() {
- err := b.StartWebhook(testAddr)
- require.Error(t, err)
- })
- })
-
- t.Run("error_not_configured", func(t *testing.T) {
- b := testWebhookBot(t)
- b.webhookContext.configured = false
-
- assert.NotPanics(t, func() {
- err := b.StartWebhook("test")
- require.Error(t, err)
- })
- })
-}
+func TestBot_UpdatesViaWebhook(t *testing.T) {
+ ctrl := gomock.NewController(t)
-func TestBot_StopWebhook(t *testing.T) {
t.Run("success", func(t *testing.T) {
- b := testWebhookBot(t)
+ b, err := NewBot(token, WithDiscardLogger())
+ require.NoError(t, err)
- assert.NotPanics(t, func() {
- err := b.StopWebhook()
- require.NoError(t, err)
+ _, err = b.UpdatesViaWebhook(testCtx, func(handler WebhookHandler) error {
+ return nil
})
+ require.NoError(t, err)
})
- t.Run("success_no_context", func(t *testing.T) {
+ t.Run("error_webhook_exist", func(t *testing.T) {
b := &Bot{}
- assert.NotPanics(t, func() {
- err := b.StopWebhook()
- require.NoError(t, err)
+ _, err := b.UpdatesViaWebhook(testCtx, func(handler WebhookHandler) error {
+ return nil
})
- })
-}
-
-func TestBot_UpdatesViaWebhook(t *testing.T) {
- t.Run("success", func(t *testing.T) {
- b, err := NewBot(token, WithDiscardLogger())
- require.NoError(t, err)
-
- srv := &fasthttp.Server{}
- _, err = b.UpdatesViaWebhook("/bot", WithWebhookServer(FastHTTPWebhookServer{
- Server: srv,
- Router: router.New(),
- }))
require.NoError(t, err)
- assert.NotPanics(t, func() {
- t.Run("invalid_path_error", func(t *testing.T) {
- ctx := &fasthttp.RequestCtx{}
- srv.Handler(ctx)
- assert.Equal(t, fasthttp.StatusNotFound, ctx.Response.StatusCode())
- })
-
- t.Run("invalid_method_error", func(t *testing.T) {
- ctx := &fasthttp.RequestCtx{}
- ctx.Request.SetRequestURI("/bot")
- srv.Handler(ctx)
- assert.Equal(t, fasthttp.StatusMethodNotAllowed, ctx.Response.StatusCode())
- })
-
- t.Run("success", func(t *testing.T) {
- ctx := &fasthttp.RequestCtx{}
- ctx.Request.SetRequestURI("/bot")
- ctx.Request.Header.SetMethod(fasthttp.MethodPost)
- ctx.Request.SetBody([]byte(`{}`))
- srv.Handler(ctx)
- assert.Equal(t, fasthttp.StatusOK, ctx.Response.StatusCode())
- })
-
- close(b.webhookContext.stop)
-
- t.Run("error_server_stopped", func(t *testing.T) {
- ctx := &fasthttp.RequestCtx{}
- ctx.Request.SetRequestURI("/bot")
- ctx.Request.Header.SetMethod(fasthttp.MethodPost)
- ctx.Request.SetBody([]byte(`{}`))
- srv.Handler(ctx)
- assert.Equal(t, fasthttp.StatusInternalServerError, ctx.Response.StatusCode())
- })
+ _, err = b.UpdatesViaWebhook(testCtx, func(handler WebhookHandler) error {
+ return nil
})
+ require.Error(t, err)
})
- t.Run("error_context_exist", func(t *testing.T) {
- b := &Bot{}
+ t.Run("error_long_polling_exist", func(t *testing.T) {
+ m := newMockedBot(ctrl)
- b.webhookContext = &webhookContext{}
- _, err := b.UpdatesViaWebhook("/bot")
- require.Error(t, err)
- })
+ m.MockRequestConstructor.EXPECT().
+ JSONRequest(gomock.Any()).
+ Return(data, nil).AnyTimes()
- t.Run("error_create_context", func(t *testing.T) {
- b := &Bot{}
+ resp := telegoResponse(t, []Update{
+ {UpdateID: 1},
+ {UpdateID: 2},
+ })
+ m.MockAPICaller.EXPECT().
+ Call(gomock.Any(), gomock.Any(), gomock.Any()).
+ Return(resp, nil).AnyTimes()
+
+ _, err := m.Bot.UpdatesViaLongPolling(testCtx, nil)
+ require.NoError(t, err)
- _, err := b.UpdatesViaWebhook("/bot", WithWebhookServer(nil))
+ _, err = m.Bot.UpdatesViaWebhook(testCtx, func(handler WebhookHandler) error {
+ return nil
+ })
require.Error(t, err)
})
@@ -159,21 +68,7 @@ func TestBot_UpdatesViaWebhook(t *testing.T) {
b, err := NewBot(token, WithDiscardLogger())
require.NoError(t, err)
- require.False(t, b.IsRunningWebhook())
-
- updates, err := b.UpdatesViaWebhook("/")
- require.NoError(t, err)
-
- require.False(t, b.IsRunningWebhook())
-
- addr := testAddress(t)
- go func() {
- startErr := b.StartWebhook(addr)
- assert.NoError(t, startErr)
- }()
- time.Sleep(time.Millisecond * 10)
-
- require.True(t, b.IsRunningWebhook())
+ pushUpdate := make(chan struct{})
expectedUpdate := Update{
UpdateID: 1,
@@ -182,75 +77,31 @@ func TestBot_UpdatesViaWebhook(t *testing.T) {
expectedUpdateBytes, err := json.Marshal(expectedUpdate)
require.NoError(t, err)
- go func() {
- resp, errHTTP := http.Post("http://"+addr, ta.ContentTypeJSON,
- bytes.NewBuffer([]byte{}))
- assert.NoError(t, errHTTP)
- assert.NoError(t, resp.Body.Close())
-
- assert.Equal(t, http.StatusInternalServerError, resp.StatusCode)
-
- resp, errHTTP = http.Post("http://"+addr, ta.ContentTypeJSON,
- bytes.NewBuffer(expectedUpdateBytes))
- assert.NoError(t, errHTTP)
- assert.NoError(t, resp.Body.Close())
-
- assert.Equal(t, http.StatusOK, resp.StatusCode)
- }()
-
- update, ok := <-updates
- require.True(t, ok)
- update.ctx = nil
-
- assert.Equal(t, expectedUpdate, update)
-
- err = b.StopWebhook()
- require.NoError(t, err)
-
- assert.False(t, b.IsRunningWebhook())
-
- _, ok = <-updates
- assert.False(t, ok)
- })
-}
-
-func TestBot_IsRunningWebhook(t *testing.T) {
- ctrl := gomock.NewController(t)
- m := newMockedBot(ctrl)
-
- t.Run("stopped", func(t *testing.T) {
- assert.False(t, m.Bot.IsRunningWebhook())
- })
-
- t.Run("running", func(t *testing.T) {
- _, err := m.Bot.UpdatesViaWebhook("/bot")
- require.NoError(t, err)
-
- go func() {
- startErr := m.Bot.StartWebhook(testAddress(t))
- assert.NoError(t, startErr)
- }()
- time.Sleep(time.Millisecond * 10)
-
- assert.True(t, m.Bot.IsRunningWebhook())
-
- err = m.Bot.StopWebhook()
+ updates, err := b.UpdatesViaWebhook(testCtx, func(handler WebhookHandler) error {
+ go func() {
+ <-pushUpdate
+ err = handler(testCtx, expectedUpdateBytes)
+ assert.NoError(t, err)
+ }()
+ return nil
+ })
require.NoError(t, err)
- assert.False(t, m.Bot.IsRunningWebhook())
- })
-
- t.Run("running_order_error", func(t *testing.T) {
- err := m.Bot.StartWebhook(testAddress(t))
- require.Error(t, err)
+ pushUpdate <- struct{}{}
- _, err = m.Bot.UpdatesViaWebhook("/bot")
- require.NoError(t, err)
+ select {
+ case update, ok := <-updates:
+ require.True(t, ok)
+ update.ctx = nil
+ assert.Equal(t, expectedUpdate, update)
+ case <-time.After(timeout):
+ t.Fatalf("Timeout")
+ }
})
}
func TestWithWebhookBuffer(t *testing.T) {
- ctx := &webhookContext{}
+ ctx := &webhook{}
buffer := uint(1)
err := WithWebhookBuffer(buffer)(nil, ctx)
@@ -258,33 +109,17 @@ func TestWithWebhookBuffer(t *testing.T) {
assert.EqualValues(t, buffer, ctx.updateChanBuffer)
}
-func TestWithWebhookServer(t *testing.T) {
- ctx := &webhookContext{}
- server := FastHTTPWebhookServer{}
-
- t.Run("success", func(t *testing.T) {
- err := WithWebhookServer(server)(nil, ctx)
- require.NoError(t, err)
- assert.EqualValues(t, server, ctx.server)
- })
-
- t.Run("error", func(t *testing.T) {
- err := WithWebhookServer(nil)(nil, ctx)
- require.Error(t, err)
- })
-}
-
func TestWithWebhookSet(t *testing.T) {
ctrl := gomock.NewController(t)
m := newMockedBot(ctrl)
- ctx := &webhookContext{}
+ ctx := &webhook{}
m.MockRequestConstructor.EXPECT().JSONRequest(gomock.Any()).Return(&ta.RequestData{
Buffer: bytes.NewBuffer(nil),
}, nil)
- m.MockAPICaller.EXPECT().Call(gomock.Any(), gomock.Any()).Return(&ta.Response{Ok: true}, nil)
+ m.MockAPICaller.EXPECT().Call(gomock.Any(), gomock.Any(), gomock.Any()).Return(&ta.Response{Ok: true}, nil)
- err := WithWebhookSet(&SetWebhookParams{})(m.Bot, ctx)
+ err := WithWebhookSet(testCtx, &SetWebhookParams{})(m.Bot, ctx)
require.NoError(t, err)
}