From a36ca539258ee740dc581ead09abafb622517621 Mon Sep 17 00:00:00 2001 From: Syfaro Date: Wed, 10 Mar 2021 16:36:15 -0500 Subject: [PATCH] Add to and update docs. --- docs/SUMMARY.md | 16 ++--- docs/changelog.md | 19 ++++++ docs/examples/command-handling.md | 74 +++++++++++------------ docs/examples/inline-keyboard.md | 80 +++++++++++++++++++++++++ docs/examples/keyboard.md | 74 +++++++++++------------ docs/getting-started/files.md | 14 ++--- docs/getting-started/important-notes.md | 46 ++++++++++++++ 7 files changed, 235 insertions(+), 88 deletions(-) create mode 100644 docs/changelog.md create mode 100644 docs/examples/inline-keyboard.md create mode 100644 docs/getting-started/important-notes.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 027cf35..81e3837 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,15 +1,17 @@ # Summary - [Getting Started](./getting-started/README.md) - * [Library Structure](./getting-started/library-structure.md) - * [Files](./getting-started/files.md) + - [Library Structure](./getting-started/library-structure.md) + - [Files](./getting-started/files.md) + - [Important Notes](./getting-started/important-notes.md) - [Examples](./examples/README.md) - * [Command Handling](./examples/command-handling.md) - * [Keyboard](./examples/keyboard.md) -- [Change Log]() + - [Command Handling](./examples/command-handling.md) + - [Keyboard](./examples/keyboard.md) + - [Inline Keyboard](./examples/inline-keyboard.md) +- [Change Log](./changelog.md) # Contributing - [Internals](./internals/README.md) - * [Adding Endpoints](./internals/adding-endpoints.md) - * [Uploading Files](./internals/uploading-files.md) + - [Adding Endpoints](./internals/adding-endpoints.md) + - [Uploading Files](./internals/uploading-files.md) diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..83fffa1 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,19 @@ +# Change Log + +## v5 + +**Work In Progress** + +- Remove all methods that return `(APIResponse, error)`. + - Use the `Request` method instead. + - For more information, see [Library Structure][library-structure]. +- Remove all `New*Upload` and `New*Share` methods, replace with `New*`. + - Use different [file types][files] to specify if upload or share. +- Rename `UploadFile` to `UploadFiles`, accept `[]RequestFile` instead of a + single fieldname and file. +- Fix methods returning `APIResponse` and errors to always use pointers. +- Update user IDs to `int64` because of Bot API changes. +- Add missing Bot API features. + +[library-structure]: ./getting-started/library-structure.md#methods +[files]: ./getting-started/files.md diff --git a/docs/examples/command-handling.md b/docs/examples/command-handling.md index 6458617..d1d8b29 100644 --- a/docs/examples/command-handling.md +++ b/docs/examples/command-handling.md @@ -6,55 +6,55 @@ This is a simple example of changing behavior based on a provided command. package main import ( - "log" - "os" + "log" + "os" - "github.com/go-telegram-bot-api/telegram-bot-api" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) func main() { - bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_APITOKEN")) - if err != nil { - log.Panic(err) - } + bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_APITOKEN")) + if err != nil { + log.Panic(err) + } - bot.Debug = true + bot.Debug = true - log.Printf("Authorized on account %s", bot.Self.UserName) + log.Printf("Authorized on account %s", bot.Self.UserName) - u := tgbotapi.NewUpdate(0) - u.Timeout = 60 + u := tgbotapi.NewUpdate(0) + u.Timeout = 60 - updates := bot.GetUpdatesChan(u) + updates := bot.GetUpdatesChan(u) - for update := range updates { - if update.Message == nil { // ignore any non-Message updates - continue - } + for update := range updates { + if update.Message == nil { // ignore any non-Message updates + continue + } - if !update.Message.IsCommand() { // ignore any non-command Messages - continue - } + if !update.Message.IsCommand() { // ignore any non-command Messages + continue + } - // Create a new MessageConfig. We don't have text yet, - // so we leave it empty. - msg := tgbotapi.NewMessage(update.Message.Chat.ID, "") + // Create a new MessageConfig. We don't have text yet, + // so we leave it empty. + msg := tgbotapi.NewMessage(update.Message.Chat.ID, "") - // Extract the command from the Message. - switch update.Message.Command() { - case "help": - msg.Text = "I understand /sayhi and /status." - case "sayhi": - msg.Text = "Hi :)" - case "status": - msg.Text = "I'm ok." - default: - msg.Text = "I don't know that command" - } + // Extract the command from the Message. + switch update.Message.Command() { + case "help": + msg.Text = "I understand /sayhi and /status." + case "sayhi": + msg.Text = "Hi :)" + case "status": + msg.Text = "I'm ok." + default: + msg.Text = "I don't know that command" + } - if _, err := bot.Send(msg); err != nil { - log.Panic(err) - } - } + if _, err := bot.Send(msg); err != nil { + log.Panic(err) + } + } } ``` diff --git a/docs/examples/inline-keyboard.md b/docs/examples/inline-keyboard.md new file mode 100644 index 0000000..e14ee63 --- /dev/null +++ b/docs/examples/inline-keyboard.md @@ -0,0 +1,80 @@ +# Inline Keyboard + +This bot waits for you to send it the message "open" before sending you an +inline keyboard containing a URL and some numbers. When a number is clicked, it +sends you a message with your selected number. + +```go +package main + +import ( + "log" + "os" + + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" +) + +var numericKeyboard = tgbotapi.NewInlineKeyboardMarkup( + tgbotapi.NewInlineKeyboardRow( + tgbotapi.NewInlineKeyboardButtonURL("1.com", "http://1.com"), + tgbotapi.NewInlineKeyboardButtonData("2", "2"), + tgbotapi.NewInlineKeyboardButtonData("3", "3"), + ), + tgbotapi.NewInlineKeyboardRow( + tgbotapi.NewInlineKeyboardButtonData("4", "4"), + tgbotapi.NewInlineKeyboardButtonData("5", "5"), + tgbotapi.NewInlineKeyboardButtonData("6", "6"), + ), +) + +func main() { + bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_APITOKEN")) + if err != nil { + log.Panic(err) + } + + bot.Debug = true + + log.Printf("Authorized on account %s", bot.Self.UserName) + + u := tgbotapi.NewUpdate(0) + u.Timeout = 60 + + updates := bot.GetUpdatesChan(u) + + // Loop through each update. + for update := range updates { + // Check if we've gotten a message update. + if update.Message != nil { + // Construct a new message from the given chat ID and containing + // the text that we received. + msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) + + // If the message was open, add a copy of our numeric keyboard. + switch update.Message.Text { + case "open": + msg.ReplyMarkup = numericKeyboard + + } + + // Send the message. + if _, err = bot.Send(msg); err != nil { + panic(err) + } + } else if update.CallbackQuery != nil { + // Respond to the callback query, telling Telegram to show the user + // a message with the data received. + callback := tgbotapi.NewCallback(update.CallbackQuery.ID, update.CallbackQuery.Data) + if _, err := bot.Request(callback); err != nil { + panic(err) + } + + // And finally, send a message containing the data received. + msg := tgbotapi.NewMessage(update.CallbackQuery.Message.Chat.ID, update.CallbackQuery.Data) + if _, err := bot.Send(msg); err != nil { + panic(err) + } + } + } +} +``` diff --git a/docs/examples/keyboard.md b/docs/examples/keyboard.md index 96acf1a..d67a915 100644 --- a/docs/examples/keyboard.md +++ b/docs/examples/keyboard.md @@ -7,57 +7,57 @@ when you send "close" message. package main import ( - "log" - "os" + "log" + "os" - "github.com/go-telegram-bot-api/telegram-bot-api" + tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) var numericKeyboard = tgbotapi.NewReplyKeyboard( - tgbotapi.NewKeyboardButtonRow( - tgbotapi.NewKeyboardButton("1"), - tgbotapi.NewKeyboardButton("2"), - tgbotapi.NewKeyboardButton("3"), - ), - tgbotapi.NewKeyboardButtonRow( - tgbotapi.NewKeyboardButton("4"), - tgbotapi.NewKeyboardButton("5"), - tgbotapi.NewKeyboardButton("6"), - ), + tgbotapi.NewKeyboardButtonRow( + tgbotapi.NewKeyboardButton("1"), + tgbotapi.NewKeyboardButton("2"), + tgbotapi.NewKeyboardButton("3"), + ), + tgbotapi.NewKeyboardButtonRow( + tgbotapi.NewKeyboardButton("4"), + tgbotapi.NewKeyboardButton("5"), + tgbotapi.NewKeyboardButton("6"), + ), ) func main() { - bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_APITOKEN")) - if err != nil { - log.Panic(err) - } + bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_APITOKEN")) + if err != nil { + log.Panic(err) + } - bot.Debug = true + bot.Debug = true - log.Printf("Authorized on account %s", bot.Self.UserName) + log.Printf("Authorized on account %s", bot.Self.UserName) - u := tgbotapi.NewUpdate(0) - u.Timeout = 60 + u := tgbotapi.NewUpdate(0) + u.Timeout = 60 - updates := bot.GetUpdatesChan(u) + updates := bot.GetUpdatesChan(u) - for update := range updates { - if update.Message == nil { // ignore non-Message updates - continue - } + for update := range updates { + if update.Message == nil { // ignore non-Message updates + continue + } - msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) + msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) - switch update.Message.Text { - case "open": - msg.ReplyMarkup = numericKeyboard - case "close": - msg.ReplyMarkup = tgbotapi.NewRemoveKeyboard(true) - } + switch update.Message.Text { + case "open": + msg.ReplyMarkup = numericKeyboard + case "close": + msg.ReplyMarkup = tgbotapi.NewRemoveKeyboard(true) + } - if _, err := bot.Send(msg); err != nil { - log.Panic(err) - } - } + if _, err := bot.Send(msg); err != nil { + log.Panic(err) + } + } } ``` diff --git a/docs/getting-started/files.md b/docs/getting-started/files.md index 63ed235..952f1f4 100644 --- a/docs/getting-started/files.md +++ b/docs/getting-started/files.md @@ -3,13 +3,13 @@ Telegram supports specifying files in many different formats. In order to accommodate them all, there are multiple structs and type aliases required. -| Type | Description | -| ---- | ----------- | -| `string` | Used as a local path to a file | -| `FileID` | Existing file ID on Telegram's servers | -| `FileURL` | URL to file, must be served with expected MIME type | -| `FileReader` | Use an `io.Reader` to provide a file. Lazily read to save memory. | -| `FileBytes` | `[]byte` containing file data. Prefer to use `FileReader` to save memory. | +| Type | Description | +| ------------ | ------------------------------------------------------------------------- | +| `string` | Used as a local path to a file | +| `FileID` | Existing file ID on Telegram's servers | +| `FileURL` | URL to file, must be served with expected MIME type | +| `FileReader` | Use an `io.Reader` to provide a file. Lazily read to save memory. | +| `FileBytes` | `[]byte` containing file data. Prefer to use `FileReader` to save memory. | ## `string` diff --git a/docs/getting-started/important-notes.md b/docs/getting-started/important-notes.md new file mode 100644 index 0000000..dbf7358 --- /dev/null +++ b/docs/getting-started/important-notes.md @@ -0,0 +1,46 @@ +# Important Notes + +The Telegram Bot API has a few potentially unanticipated behaviors. Here are a +few of them. If any behavior was surprising to you, please feel free to open a +pull request! + +## Callback Queries + +- Every callback query must be answered, even if there is nothing to display to + the user. Failure to do so will show a loading icon on the keyboard until the + operation times out. + +## ChatMemberUpdated + +- In order to receive `chat_member` and updates, you must explicitly add it to + your `allowed_updates` when getting updates or setting your webhook. + +## Entities use UTF16 + +- When extracting text entities using offsets and lengths, characters can appear + to be in incorrect positions. This is because Telegram uses UTF16 lengths + while Golang uses UTF8. It's possible to convert between the two, see + [issue #231][issue-231] for more details. + +[issue-231]: https://github.com/go-telegram-bot-api/telegram-bot-api/issues/231 + +## GetUpdatesChan + +- This method is very basic and likely unsuitable for production use. Consider + creating your own implementation instead, as it's very simple to replicate. +- This method only allows your bot to process one update at a time. You can + spawn goroutines to handle updates concurrently or switch to webhooks instead. + Webhooks are suggested for high traffic bots. + +## Nil Updates + +- At most one of the fields in an `Update` will be set to a non-nil value. When + evaluating updates, you must make sure you check that the field is not nil + before trying to access any of it's fields. + +## User and Chat ID size + +- These types require up to 52 significant bits to store correctly, making a + 64-bit integer type required in most languages. They are already `int64` types + in this library, but make sure you use correct types when saving them to a + database or passing them to another language.