├── .gitignore
├── logo_bot.png
├── logo_msg.png
├── example
├── voice.aac
├── example.png
└── main.go
├── voice.go
├── file.go
├── Makefile
├── options.go
├── go.mod
├── .github
└── workflows
│ └── go.yml
├── CONTRIBUTING.md
├── LICENSE
├── button.go
├── golangci.yml
├── updates.go
├── README.md
├── go.sum
├── file_easyjson.go
├── keyboard.go
├── chat_easyjson.go
├── chat.go
├── button_easyjson.go
├── types.go
├── message.go
├── api_mock.go
├── client_test.go
├── keyboard_test.go
├── message_easyjson.go
├── bot.go
├── client.go
└── types_easyjson.go
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 | cover.out
4 | .DS_Store
--------------------------------------------------------------------------------
/logo_bot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mail-ru-im/bot-golang/HEAD/logo_bot.png
--------------------------------------------------------------------------------
/logo_msg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mail-ru-im/bot-golang/HEAD/logo_msg.png
--------------------------------------------------------------------------------
/example/voice.aac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mail-ru-im/bot-golang/HEAD/example/voice.aac
--------------------------------------------------------------------------------
/example/example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mail-ru-im/bot-golang/HEAD/example/example.png
--------------------------------------------------------------------------------
/voice.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | var (
4 | voiceMessageSupportedExtensions = map[string]bool{
5 | ".aac": true,
6 | ".ogg": true,
7 | ".m4a": true,
8 | }
9 | )
10 |
11 | const (
12 | voiceMessageLeadingRune = 'I'
13 | )
14 |
--------------------------------------------------------------------------------
/file.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | //go:generate easyjson -all file.go
4 |
5 | type File struct {
6 | // Id of the file
7 | ID string `json:"fileId"`
8 |
9 | // Type of the file
10 | Type string `json:"type"`
11 |
12 | // Size in bytes
13 | Size uint64 `json:"size"`
14 |
15 | // Name of file
16 | Name string `json:"filename"`
17 |
18 | // URL to the file
19 | URL string `json:"url"`
20 | }
21 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | all: generate test
2 |
3 | GOPATH := $(shell go env GOPATH)
4 |
5 | $(GOPATH)/bin/easyjson:
6 | go build -mod mod -o $(GOPATH)/bin/easyjson github.com/mailru/easyjson/easyjson
7 |
8 | $(GOPATH)/bin/golangci-lint:
9 | go build -mod mod -o $(GOPATH)/bin/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint
10 |
11 | .PHONY: test
12 | test:
13 | go test -v --cover -coverprofile=cover.out ./...
14 |
15 | .PHONY: lint
16 | lint: $(GOPATH)/bin/golangci-lint
17 | $(GOPATH)/bin/golangci-lint run
18 |
19 | .PHONY: generate
20 | generate: $(GOPATH)/bin/easyjson
21 | go generate
22 |
--------------------------------------------------------------------------------
/options.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | import "net/http"
4 |
5 | type BotOption interface {
6 | Type() string
7 | Value() interface{}
8 | }
9 |
10 | type BotApiURL string
11 |
12 | func (o BotApiURL) Type() string {
13 | return "api_url"
14 | }
15 |
16 | func (o BotApiURL) Value() interface{} {
17 | return string(o)
18 | }
19 |
20 | type BotDebug bool
21 |
22 | func (o BotDebug) Type() string {
23 | return "debug"
24 | }
25 |
26 | func (o BotDebug) Value() interface{} {
27 | return bool(o)
28 | }
29 |
30 | type BotHTTPClient http.Client
31 |
32 | func (o BotHTTPClient) Type() string {
33 | return "http_client"
34 | }
35 |
36 | func (o BotHTTPClient) Value() interface{} {
37 | return http.Client(o)
38 | }
39 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/mail-ru-im/bot-golang
2 |
3 | go 1.20
4 |
5 | require (
6 | github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b
7 | github.com/mailru/easyjson v0.7.7
8 | github.com/sirupsen/logrus v1.9.3
9 | github.com/stretchr/testify v1.7.0
10 | )
11 |
12 | require (
13 | github.com/davecgh/go-spew v1.1.1 // indirect
14 | github.com/josharian/intern v1.0.0 // indirect
15 | github.com/kr/text v0.2.0 // indirect
16 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
17 | github.com/pmezard/go-difflib v1.0.0 // indirect
18 | golang.org/x/sys v0.18.0 // indirect
19 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
20 | gopkg.in/yaml.v3 v3.0.0 // indirect
21 | )
22 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a golang project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go
3 |
4 | name: Go
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 |
14 |
15 | build:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v3
19 |
20 | - name: Set up Go
21 | uses: actions/setup-go@v4
22 | with:
23 | go-version: '1.21'
24 |
25 | - name: Lint
26 | run: make lint
27 |
28 | - name: Test
29 | run: make test
30 |
31 | - name: Upload coverage to Codecov
32 | uses: codecov/codecov-action@v4
33 | env:
34 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
35 | files: cover.out
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute
2 | ## Pull request
3 | Если вы решили впервые стать контрибьютером и помочь развитию open-source проекта, этот пункт для вас.
4 | 1) Делается fork основного репозитория
5 | 2) git clone https://github.com/ваш-логин/bot-golang.git
6 | 3) Локальное изменение
7 | 4) Сделайте ребейз на remote master ветку
8 | 5) git push origin <ваш-логин>
9 | 6) В удаленном репозитории нажать _compare&pull request_
10 |
11 | Также рекомендуем ознакомиться с подробной инструкцией для контрибьютеров - README.md
12 |
13 | ## Tests
14 | 1) Если добавляется новая функциональность, то покрывайте ее тестами
15 | 2) Следите за тем, чтобы тесты успешно выполнялись в PR перед мержем.
16 |
17 | ## Merge
18 | Ветка будет смержена в мастер, когда:
19 | 1) Все пайплайны пройдут успешно
20 | 2) Новая функциональность будет покрыта тестами
21 |
22 | После выполнения всех пунктов один из сотрудников проверит в ближайшее время PR и смержит его.
23 |
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 ICQ LLC (Mail.Ru Group)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/button.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | //go:generate easyjson -all button.go
4 |
5 | // Button represents a button in inline keyboard
6 | // Make sure you have URL or CallbackData in your Button.
7 | type Button struct {
8 | // Button text
9 | Text string `json:"text"`
10 |
11 | // URL to be opened
12 | // You can't use it with CallbackData
13 | URL string `json:"url,omitempty"`
14 |
15 | // Data that identify the button
16 | // You can't use it with URL
17 | CallbackData string `json:"callbackData,omitempty"`
18 |
19 | // Style of a button
20 | Style ButtonStyle `json:"style,omitempty"`
21 | }
22 |
23 | // ButtonStyle represent a style of a Button
24 | type ButtonStyle string
25 |
26 | const (
27 | ButtonPrimary ButtonStyle = "primary"
28 | ButtonAttention ButtonStyle = "attention"
29 | )
30 |
31 | // WithStyle sets ButtonStyle for Button
32 | func (v Button) WithStyle(style ButtonStyle) Button {
33 | v.Style = style
34 | return v
35 | }
36 |
37 | // NewURLButton returns new button with URL field
38 | func NewURLButton(text string, url string) Button {
39 | return Button{
40 | Text: text,
41 | URL: url,
42 | }
43 | }
44 |
45 | // NewCallbackButton returns new button with CallbackData field
46 | func NewCallbackButton(text string, callbackData string) Button {
47 | return Button{
48 | Text: text,
49 | CallbackData: callbackData,
50 | }
51 | }
52 |
53 | // ButtonResponse represents a data that is returned when a button is clicked
54 | type ButtonResponse struct {
55 | client *Client
56 |
57 | // Id of the query
58 | QueryID string `json:"queryId"`
59 |
60 | // Text of the response message
61 | Text string `json:"text"`
62 |
63 | // Display alert?
64 | ShowAlert bool `json:"showAlert"`
65 |
66 | // URL to be opened
67 | URL string `json:"url"`
68 |
69 | // CallbackData of the query (id of the pressed button).
70 | CallbackData string `json:"callbackData"`
71 | }
72 |
73 | // Send method sends your response message.
74 | // Make sure you have QueryID in your ButtonResponse.
75 | func (cl *ButtonResponse) Send() error {
76 | return cl.client.SendAnswerCallbackQuery(cl)
77 | }
78 |
--------------------------------------------------------------------------------
/example/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "log"
7 | "os"
8 | "time"
9 |
10 | botgolang "github.com/mail-ru-im/bot-golang"
11 | )
12 |
13 | func main() {
14 | token := os.Getenv("TOKEN")
15 |
16 | bot, err := botgolang.NewBot(token, botgolang.BotDebug(true))
17 | if err != nil {
18 | log.Fatalf("cannot connect to bot: %s", err)
19 | }
20 |
21 | log.Println(bot.Info)
22 |
23 | message := bot.NewTextMessage("d.dorofeev@corp.mail.ru", "Hi")
24 | if err = message.Send(); err != nil {
25 | log.Fatalf("failed to send message: %s", err)
26 | }
27 |
28 | file, err := os.Open("./example.png")
29 | if err != nil {
30 | log.Fatalf("cannot open file: %s", err)
31 | }
32 |
33 | fileMessage := bot.NewFileMessage("d.dorofeev@corp.mail.ru", file)
34 | if err := fileMessage.Send(); err != nil {
35 | log.Println(err)
36 | }
37 |
38 | if err = fileMessage.Delete(); err != nil {
39 | log.Fatalf("failed to delete message: %s", err)
40 | }
41 |
42 | if err = file.Close(); err != nil {
43 | log.Fatalf("failed to close file: %s", err)
44 | }
45 |
46 | file, err = os.Open("./voice.aac")
47 | if err != nil {
48 | log.Fatalf("cannot open file: %s", err)
49 | }
50 | defer file.Close()
51 |
52 | voiceMessage := bot.NewVoiceMessage("g.gabolaev@corp.mail.ru", file)
53 | if err := voiceMessage.Send(); err != nil {
54 | log.Println(err)
55 | }
56 |
57 | // Simple 30-seconds echo bot with buttons
58 | ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
59 | defer cancel()
60 | updates := bot.GetUpdatesChannel(ctx)
61 | for update := range updates {
62 | fmt.Println(update.Type, update.Payload)
63 | switch update.Type {
64 | case botgolang.NEW_MESSAGE:
65 | message := update.Payload.Message()
66 |
67 | helloBtn := botgolang.NewCallbackButton("Hello", "echo")
68 | goBtn := botgolang.NewURLButton("go", "https://golang.org/")
69 |
70 | keyboard := botgolang.NewKeyboard()
71 | keyboard.AddRow(helloBtn, goBtn)
72 |
73 | message.AttachInlineKeyboard(keyboard)
74 |
75 | if err := message.Send(); err != nil {
76 | log.Printf("failed to send message: %s", err)
77 | }
78 | case botgolang.EDITED_MESSAGE:
79 | message := update.Payload.Message()
80 | if err := message.Reply("do not edit!"); err != nil {
81 | log.Printf("failed to reply to message: %s", err)
82 | }
83 | case botgolang.CALLBACK_QUERY:
84 | data := update.Payload.CallbackQuery()
85 | switch data.CallbackData {
86 | case "echo":
87 | response := bot.NewButtonResponse(data.QueryID, "", "Hello World!", false)
88 | if err := response.Send(); err != nil {
89 | log.Printf("failed to reply on button click: %s", err)
90 | }
91 | }
92 | }
93 |
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/golangci.yml:
--------------------------------------------------------------------------------
1 | # This file contains all available configuration options
2 | # with their default values.
3 |
4 | # options for analysis running
5 | run:
6 | # default concurrency is a available CPU number
7 | #concurrency: 4
8 |
9 | # timeout for analysis, e.g. 30s, 5m, default is 1m
10 | deadline: 30m
11 |
12 | # include test files or not, default is true
13 | tests: false
14 |
15 | # which dirs to skip: they won't be analyzed;
16 | # can use regexp here: generated.*, regexp is applied on full path;
17 | # default value is empty list, but next dirs are always skipped independently
18 | # from this option's value:
19 | # vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
20 | skip-dirs:
21 |
22 | # which files to skip: they will be analyzed, but issues from them
23 | # won't be reported. Default value is empty list, but there is
24 | # no need to include all autogenerated files, we confidently recognize
25 | # autogenerated files. If it's not please let us know.
26 | skip-files:
27 | - "_easyjson.go"
28 | - ".pb.go"
29 |
30 | # all available settings of specific linters
31 | linters-settings:
32 | errcheck:
33 | # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`;
34 | # default is false: such cases aren't reported by default.
35 | check-blank: true
36 |
37 | govet:
38 | # report about shadowed variables
39 | check-shadowing: true
40 |
41 | golint:
42 | # minimal confidence for issues, default is 0.8
43 | min-confidence: 0.3
44 | gocyclo:
45 | # minimal code complexity to report, 30 by default (but we recommend 10-20)
46 | min-complexity: 15
47 | dupl:
48 | # tokens count to trigger issue, 150 by default
49 | threshold: 200
50 | lll:
51 | # max line length, lines longer will be reported. Default is 120.
52 | # '\t' is counted as 1 character by default, and can be changed with the tab-width option
53 | line-length: 120
54 | nakedret:
55 | # make an issue if func has more lines of code than this setting and it has naked returns; default is 30
56 | max-func-lines: 30
57 |
58 | linters:
59 | enable-all: true
60 | disable:
61 | - gochecknoglobals
62 | - gochecknoinits
63 | - bodyclose # check issue https://github.com/timakin/bodyclose/issues/16
64 | fast: false
65 |
66 | issues:
67 | exclude:
68 | - "should have comment"
69 | - "always receives"
70 | - "parameter .* is always"
71 | - "comment on exported .* should be of the form"
72 | - "Use of weak cryptographic primitive"
73 |
74 | exclude-rules:
75 | # Exclude lll issues for long lines with go:generate
76 | - linters:
77 | - lll
78 | source: "^//go:generate "
79 |
80 | output:
81 | format: tab
82 |
--------------------------------------------------------------------------------
/updates.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "time"
7 |
8 | dura "github.com/hako/durafmt"
9 | "github.com/sirupsen/logrus"
10 | )
11 |
12 | const (
13 | sleepTime = time.Second * 3
14 | )
15 |
16 | var (
17 | sleepTimeStr = dura.Parse(sleepTime)
18 | )
19 |
20 | type Updater struct {
21 | logger *logrus.Logger
22 | client *Client
23 | lastEventID int
24 | PollTime int
25 | }
26 |
27 | // NewMessageFromPart returns new message based on part message
28 | func (u *Updater) NewMessageFromPayload(message EventPayload) *Message {
29 | return &Message{
30 | client: u.client,
31 | ID: message.MsgID,
32 | Chat: Chat{ID: message.From.User.ID, Title: message.From.FirstName},
33 | Text: message.Text,
34 | Timestamp: message.Timestamp,
35 | }
36 | }
37 |
38 | func (u *Updater) RunUpdatesCheck(ctx context.Context, ch chan<- Event) {
39 | _, err := u.GetLastEventsWithContext(ctx, 0)
40 | if err != nil {
41 | u.logger.WithFields(logrus.Fields{
42 | "err": err,
43 | }).Debug("cannot make initial request to events")
44 | }
45 |
46 | for {
47 | select {
48 | case <-ctx.Done():
49 | close(ch)
50 | return
51 | default:
52 | events, err := u.GetLastEventsWithContext(ctx, u.PollTime)
53 | if err != nil {
54 | u.logger.WithFields(logrus.Fields{
55 | "err": err,
56 | "retry interval": sleepTimeStr,
57 | }).Errorf("Failed to get updates, retrying in %s ...", sleepTimeStr)
58 | time.Sleep(sleepTime)
59 |
60 | continue
61 | }
62 |
63 | for _, event := range events {
64 | event.client = u.client
65 | event.Payload.client = u.client
66 |
67 | ch <- *event
68 | }
69 | }
70 | }
71 | }
72 |
73 | func (u *Updater) GetLastEvents(pollTime int) ([]*Event, error) {
74 | return u.GetLastEventsWithContext(context.Background(), pollTime)
75 | }
76 |
77 | func (u *Updater) GetLastEventsWithContext(ctx context.Context, pollTime int) ([]*Event, error) {
78 | events, err := u.client.GetEventsWithContext(ctx, u.lastEventID, pollTime)
79 | if err != nil {
80 | u.logger.WithFields(logrus.Fields{
81 | "err": err,
82 | "events": events,
83 | }).Debug("events getting error")
84 | return events, fmt.Errorf("cannot get events: %s", err)
85 | }
86 |
87 | count := len(events)
88 | if count > 0 {
89 | u.lastEventID = events[count-1].EventID
90 | }
91 |
92 | return events, nil
93 | }
94 |
95 | func NewUpdater(client *Client, pollTime int, logger *logrus.Logger) *Updater {
96 | if pollTime == 0 {
97 | pollTime = 60
98 | }
99 |
100 | return &Updater{
101 | client: client,
102 | lastEventID: 0,
103 | PollTime: pollTime,
104 | logger: logger,
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # VK Teams Bot API for Golang
4 | [](https://github.com/mail-ru-im/bot-golang/actions/workflows/go.yml)
5 | [](https://codecov.io/github/mail-ru-im/bot-golang)
6 | [](https://pkg.go.dev/github.com/mail-ru-im/bot-golang)
7 | 
8 |
9 | ### [
VK Teams API Specification](https://teams.vk.com/botapi/)
10 |
11 | ## Getting started
12 |
13 | * Create your own bot by sending the _/newbot_ command to _Metabot_ and follow the instructions.
14 | >Note: a bot can only reply after the user has added it to his contact list, or if the user was the first to start a dialogue.
15 | * You can configure the domain that hosts your VK Teams server. When instantiating the Bot class, add the address of your domain.
16 | * An example of how to use the framework can be seen in _example/main.go_
17 |
18 | ## Install
19 | ```bash
20 | go get github.com/mail-ru-im/bot-golang
21 | ```
22 |
23 | ## Usage
24 |
25 | Create your own bot by sending the /newbot command to _Metabot_ and follow the instructions.
26 | Note a bot can only reply after the user has added it to his contacts list, or if the user was the first to start a dialogue.
27 |
28 | ### Create your bot
29 |
30 | ```go
31 | package main
32 |
33 | import "github.com/mail-ru-im/bot-golang"
34 |
35 | func main() {
36 | bot, err := botgolang.NewBot(BOT_TOKEN)
37 | if err != nil {
38 | log.Println("wrong token")
39 | }
40 |
41 | message := bot.NewTextMessage("some@mail.com", "text")
42 | message.Send()
43 | }
44 | ```
45 |
46 | ### Send and edit messages
47 |
48 | You can create, edit and reply to messages like a piece of cake.
49 |
50 | ```go
51 | message := bot.NewTextMessage("some@mail.com", "text")
52 | message.Send()
53 |
54 | message.Text = "new text"
55 |
56 | message.Edit()
57 | message.Reply("I changed my text")
58 | ```
59 |
60 | ### Subscribe events
61 |
62 | Get all updates from the channel. Use context for cancellation.
63 |
64 | ```go
65 | ctx, finish := context.WithCancel(context.Background())
66 | updates := bot.GetUpdatesChannel(ctx)
67 | for update := range updates {
68 | // your logic here
69 | }
70 | ```
71 |
72 | ### Passing options
73 |
74 | You don't need this.
75 | But if you do, you can override bot's API URL:
76 |
77 | ```go
78 | bot := botgolang.NewBot(BOT_TOKEN, botgolang.BotApiURL("https://vkteams.com/bot/v1"))
79 | ```
80 | And debug all api requests and responses:
81 |
82 | ```go
83 | bot := botgolang.NewBot(BOT_TOKEN, botgolang.BotDebug(true))
84 | ```
85 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4=
6 | github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0=
7 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
8 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
9 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
10 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
11 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
12 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
13 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
14 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
15 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
16 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
17 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
18 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
19 | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
20 | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
21 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
22 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
23 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
24 | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
25 | golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
26 | golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
27 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
28 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
29 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
30 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
31 | gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
32 | gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
33 |
--------------------------------------------------------------------------------
/file_easyjson.go:
--------------------------------------------------------------------------------
1 | // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
2 |
3 | package botgolang
4 |
5 | import (
6 | json "encoding/json"
7 | easyjson "github.com/mailru/easyjson"
8 | jlexer "github.com/mailru/easyjson/jlexer"
9 | jwriter "github.com/mailru/easyjson/jwriter"
10 | )
11 |
12 | // suppress unused package warning
13 | var (
14 | _ *json.RawMessage
15 | _ *jlexer.Lexer
16 | _ *jwriter.Writer
17 | _ easyjson.Marshaler
18 | )
19 |
20 | func easyjson8ceb9162DecodeGithubComMailRuImBotGolang(in *jlexer.Lexer, out *File) {
21 | isTopLevel := in.IsStart()
22 | if in.IsNull() {
23 | if isTopLevel {
24 | in.Consumed()
25 | }
26 | in.Skip()
27 | return
28 | }
29 | in.Delim('{')
30 | for !in.IsDelim('}') {
31 | key := in.UnsafeFieldName(false)
32 | in.WantColon()
33 | if in.IsNull() {
34 | in.Skip()
35 | in.WantComma()
36 | continue
37 | }
38 | switch key {
39 | case "fileId":
40 | out.ID = string(in.String())
41 | case "type":
42 | out.Type = string(in.String())
43 | case "size":
44 | out.Size = uint64(in.Uint64())
45 | case "filename":
46 | out.Name = string(in.String())
47 | case "url":
48 | out.URL = string(in.String())
49 | default:
50 | in.SkipRecursive()
51 | }
52 | in.WantComma()
53 | }
54 | in.Delim('}')
55 | if isTopLevel {
56 | in.Consumed()
57 | }
58 | }
59 | func easyjson8ceb9162EncodeGithubComMailRuImBotGolang(out *jwriter.Writer, in File) {
60 | out.RawByte('{')
61 | first := true
62 | _ = first
63 | {
64 | const prefix string = ",\"fileId\":"
65 | out.RawString(prefix[1:])
66 | out.String(string(in.ID))
67 | }
68 | {
69 | const prefix string = ",\"type\":"
70 | out.RawString(prefix)
71 | out.String(string(in.Type))
72 | }
73 | {
74 | const prefix string = ",\"size\":"
75 | out.RawString(prefix)
76 | out.Uint64(uint64(in.Size))
77 | }
78 | {
79 | const prefix string = ",\"filename\":"
80 | out.RawString(prefix)
81 | out.String(string(in.Name))
82 | }
83 | {
84 | const prefix string = ",\"url\":"
85 | out.RawString(prefix)
86 | out.String(string(in.URL))
87 | }
88 | out.RawByte('}')
89 | }
90 |
91 | // MarshalJSON supports json.Marshaler interface
92 | func (v File) MarshalJSON() ([]byte, error) {
93 | w := jwriter.Writer{}
94 | easyjson8ceb9162EncodeGithubComMailRuImBotGolang(&w, v)
95 | return w.Buffer.BuildBytes(), w.Error
96 | }
97 |
98 | // MarshalEasyJSON supports easyjson.Marshaler interface
99 | func (v File) MarshalEasyJSON(w *jwriter.Writer) {
100 | easyjson8ceb9162EncodeGithubComMailRuImBotGolang(w, v)
101 | }
102 |
103 | // UnmarshalJSON supports json.Unmarshaler interface
104 | func (v *File) UnmarshalJSON(data []byte) error {
105 | r := jlexer.Lexer{Data: data}
106 | easyjson8ceb9162DecodeGithubComMailRuImBotGolang(&r, v)
107 | return r.Error()
108 | }
109 |
110 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
111 | func (v *File) UnmarshalEasyJSON(l *jlexer.Lexer) {
112 | easyjson8ceb9162DecodeGithubComMailRuImBotGolang(l, v)
113 | }
114 |
--------------------------------------------------------------------------------
/keyboard.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | import (
4 | "fmt"
5 | )
6 |
7 | // Keyboard represents an inline keyboard markup
8 | // Call the NewKeyboard() func to get a keyboard instance
9 | type Keyboard struct {
10 | Rows [][]Button
11 | }
12 |
13 | // NewKeyboard returns a new keyboard instance
14 | func NewKeyboard() Keyboard {
15 | return Keyboard{
16 | Rows: make([][]Button, 0),
17 | }
18 | }
19 |
20 | // AddRows adds a row to the keyboard
21 | func (k *Keyboard) AddRow(row ...Button) {
22 | k.Rows = append(k.Rows, row)
23 | }
24 |
25 | // AddButton adds a button to the end of the row
26 | func (k *Keyboard) AddButton(rowIndex int, button Button) error {
27 | if ok := k.checkRow(rowIndex); !ok {
28 | return fmt.Errorf("no such row: %d", rowIndex)
29 | }
30 |
31 | k.Rows[rowIndex] = append(k.Rows[rowIndex], button)
32 | return nil
33 | }
34 |
35 | // DeleteRow removes the row from the keyboard
36 | func (k *Keyboard) DeleteRow(index int) error {
37 | if ok := k.checkRow(index); !ok {
38 | return fmt.Errorf("no such row: %d", index)
39 | }
40 |
41 | k.Rows = append(k.Rows[:index], k.Rows[index+1:]...)
42 | return nil
43 | }
44 |
45 | // DeleteButton removes the button from the row.
46 | // Note - at least one button should remain in a row,
47 | // if you want to delete all buttons, use the DeleteRow function
48 | func (k *Keyboard) DeleteButton(rowIndex, buttonIndex int) error {
49 | if ok := k.checkButton(rowIndex, buttonIndex); !ok {
50 | return fmt.Errorf("no button at index %d or row %d", buttonIndex, rowIndex)
51 | }
52 |
53 | if k.RowSize(rowIndex) < 2 {
54 | return fmt.Errorf("can't delete button: at least one should remain in a row")
55 | }
56 |
57 | row := &k.Rows[rowIndex]
58 | *row = append((*row)[:buttonIndex], (*row)[buttonIndex+1:]...)
59 | return nil
60 | }
61 |
62 | // ChangeButton changes the button to a new one at the specified position
63 | func (k *Keyboard) ChangeButton(rowIndex, buttonIndex int, newButton Button) error {
64 | if ok := k.checkButton(rowIndex, buttonIndex); !ok {
65 | return fmt.Errorf("no button at index %d or row %d", buttonIndex, rowIndex)
66 | }
67 |
68 | k.Rows[rowIndex][buttonIndex] = newButton
69 | return nil
70 | }
71 |
72 | // SwapRows swaps two rows in keyboard
73 | func (k *Keyboard) SwapRows(first, second int) error {
74 | if ok := k.checkRow(first); !ok {
75 | return fmt.Errorf("no such index (first): %d", first)
76 | }
77 | if ok := k.checkRow(second); !ok {
78 | return fmt.Errorf("no such index (second): %d", second)
79 | }
80 |
81 | k.Rows[first], k.Rows[second] = k.Rows[second], k.Rows[first]
82 | return nil
83 | }
84 |
85 | // RowsCount returns the number of rows
86 | func (k *Keyboard) RowsCount() int {
87 | return len(k.Rows)
88 | }
89 |
90 | // RowSize returns the number of buttons in a row.
91 | // If there is no such row, then returns -1
92 | func (k *Keyboard) RowSize(row int) int {
93 | if ok := k.checkRow(row); !ok {
94 | return -1
95 | }
96 | return len(k.Rows[row])
97 | }
98 |
99 | // GetKeyboard returns an array of button rows
100 | func (k *Keyboard) GetKeyboard() [][]Button {
101 | return k.Rows
102 | }
103 |
104 | // checkRow checks that the index of row doesnt go beyond the bounds of the array
105 | func (k *Keyboard) checkRow(i int) bool {
106 | return i >= 0 && i < len(k.Rows)
107 | }
108 |
109 | // checkButton checks that the button and row indexes doesnt go beyond the bounds of the array
110 | func (k *Keyboard) checkButton(row, button int) bool {
111 | return k.checkRow(row) && button >= 0 && button < len(k.Rows[row])
112 | }
113 |
--------------------------------------------------------------------------------
/chat_easyjson.go:
--------------------------------------------------------------------------------
1 | // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
2 |
3 | package botgolang
4 |
5 | import (
6 | json "encoding/json"
7 | easyjson "github.com/mailru/easyjson"
8 | jlexer "github.com/mailru/easyjson/jlexer"
9 | jwriter "github.com/mailru/easyjson/jwriter"
10 | )
11 |
12 | // suppress unused package warning
13 | var (
14 | _ *json.RawMessage
15 | _ *jlexer.Lexer
16 | _ *jwriter.Writer
17 | _ easyjson.Marshaler
18 | )
19 |
20 | func easyjson9b8f5552DecodeGithubComMailRuImBotGolang(in *jlexer.Lexer, out *Chat) {
21 | isTopLevel := in.IsStart()
22 | if in.IsNull() {
23 | if isTopLevel {
24 | in.Consumed()
25 | }
26 | in.Skip()
27 | return
28 | }
29 | in.Delim('{')
30 | for !in.IsDelim('}') {
31 | key := in.UnsafeFieldName(false)
32 | in.WantColon()
33 | if in.IsNull() {
34 | in.Skip()
35 | in.WantComma()
36 | continue
37 | }
38 | switch key {
39 | case "chatId":
40 | out.ID = string(in.String())
41 | case "type":
42 | out.Type = string(in.String())
43 | case "firstName":
44 | out.FirstName = string(in.String())
45 | case "lastName":
46 | out.LastName = string(in.String())
47 | case "nick":
48 | out.Nick = string(in.String())
49 | case "about":
50 | out.About = string(in.String())
51 | case "rules":
52 | out.Rules = string(in.String())
53 | case "title":
54 | out.Title = string(in.String())
55 | case "isBot":
56 | out.IsBot = bool(in.Bool())
57 | case "public":
58 | out.Public = bool(in.Bool())
59 | case "joinModeration":
60 | out.JoinModeration = bool(in.Bool())
61 | case "inviteLink":
62 | out.InviteLink = string(in.String())
63 | default:
64 | in.SkipRecursive()
65 | }
66 | in.WantComma()
67 | }
68 | in.Delim('}')
69 | if isTopLevel {
70 | in.Consumed()
71 | }
72 | }
73 | func easyjson9b8f5552EncodeGithubComMailRuImBotGolang(out *jwriter.Writer, in Chat) {
74 | out.RawByte('{')
75 | first := true
76 | _ = first
77 | {
78 | const prefix string = ",\"chatId\":"
79 | out.RawString(prefix[1:])
80 | out.String(string(in.ID))
81 | }
82 | {
83 | const prefix string = ",\"type\":"
84 | out.RawString(prefix)
85 | out.String(string(in.Type))
86 | }
87 | {
88 | const prefix string = ",\"firstName\":"
89 | out.RawString(prefix)
90 | out.String(string(in.FirstName))
91 | }
92 | {
93 | const prefix string = ",\"lastName\":"
94 | out.RawString(prefix)
95 | out.String(string(in.LastName))
96 | }
97 | {
98 | const prefix string = ",\"nick\":"
99 | out.RawString(prefix)
100 | out.String(string(in.Nick))
101 | }
102 | {
103 | const prefix string = ",\"about\":"
104 | out.RawString(prefix)
105 | out.String(string(in.About))
106 | }
107 | {
108 | const prefix string = ",\"rules\":"
109 | out.RawString(prefix)
110 | out.String(string(in.Rules))
111 | }
112 | {
113 | const prefix string = ",\"title\":"
114 | out.RawString(prefix)
115 | out.String(string(in.Title))
116 | }
117 | {
118 | const prefix string = ",\"isBot\":"
119 | out.RawString(prefix)
120 | out.Bool(bool(in.IsBot))
121 | }
122 | {
123 | const prefix string = ",\"public\":"
124 | out.RawString(prefix)
125 | out.Bool(bool(in.Public))
126 | }
127 | {
128 | const prefix string = ",\"joinModeration\":"
129 | out.RawString(prefix)
130 | out.Bool(bool(in.JoinModeration))
131 | }
132 | {
133 | const prefix string = ",\"inviteLink\":"
134 | out.RawString(prefix)
135 | out.String(string(in.InviteLink))
136 | }
137 | out.RawByte('}')
138 | }
139 |
140 | // MarshalJSON supports json.Marshaler interface
141 | func (v Chat) MarshalJSON() ([]byte, error) {
142 | w := jwriter.Writer{}
143 | easyjson9b8f5552EncodeGithubComMailRuImBotGolang(&w, v)
144 | return w.Buffer.BuildBytes(), w.Error
145 | }
146 |
147 | // MarshalEasyJSON supports easyjson.Marshaler interface
148 | func (v Chat) MarshalEasyJSON(w *jwriter.Writer) {
149 | easyjson9b8f5552EncodeGithubComMailRuImBotGolang(w, v)
150 | }
151 |
152 | // UnmarshalJSON supports json.Unmarshaler interface
153 | func (v *Chat) UnmarshalJSON(data []byte) error {
154 | r := jlexer.Lexer{Data: data}
155 | easyjson9b8f5552DecodeGithubComMailRuImBotGolang(&r, v)
156 | return r.Error()
157 | }
158 |
159 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
160 | func (v *Chat) UnmarshalEasyJSON(l *jlexer.Lexer) {
161 | easyjson9b8f5552DecodeGithubComMailRuImBotGolang(l, v)
162 | }
163 |
--------------------------------------------------------------------------------
/chat.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | //go:generate easyjson -all chat.go
4 |
5 | type ChatAction = string
6 |
7 | const (
8 | TypingAction ChatAction = "typing"
9 | LookingAction ChatAction = "looking"
10 | )
11 |
12 | type ChatType = string
13 |
14 | const (
15 | Private ChatType = "private"
16 | Group ChatType = "group"
17 | Channel ChatType = "channel"
18 | )
19 |
20 | type Chat struct {
21 | client *Client
22 | // Id of the chat
23 | ID string `json:"chatId"`
24 |
25 | // Type of the chat: channel, group or private
26 | Type ChatType `json:"type"`
27 |
28 | // First name of the user
29 | FirstName string `json:"firstName"`
30 |
31 | // Last name of the user
32 | LastName string `json:"lastName"`
33 |
34 | // Nick of the user
35 | Nick string `json:"nick"`
36 |
37 | // User about or group/channel description
38 | About string `json:"about"`
39 |
40 | // Rules of the group/channel
41 | Rules string `json:"rules"`
42 |
43 | // Title of the chat
44 | Title string `json:"title"`
45 |
46 | // Flag that indicates that requested chat is the bot
47 | IsBot bool `json:"isBot"`
48 |
49 | // Is this chat public?
50 | Public bool `json:"public"`
51 |
52 | // Is this chat has join moderation?
53 | JoinModeration bool `json:"joinModeration"`
54 |
55 | // You can send this link to all your friends
56 | InviteLink string `json:"inviteLink"`
57 | }
58 |
59 | func (c *Chat) resolveID() string {
60 | switch c.Type {
61 | case Private:
62 | return c.Nick
63 | default:
64 | return c.ID
65 | }
66 | }
67 |
68 | // Send bot actions to the chat
69 | //
70 | // You can call this method every time you change the current actions,
71 | // or every 10 seconds if the actions have not changed. After sending a
72 | // request without active action, you should not re-notify of their absence.
73 | func (c *Chat) SendActions(actions ...ChatAction) error {
74 | return c.client.SendChatActions(c.resolveID(), actions...)
75 | }
76 |
77 | // Get chat administrators list
78 | func (c *Chat) GetAdmins() ([]ChatMember, error) {
79 | return c.client.GetChatAdmins(c.ID)
80 | }
81 |
82 | // Get chat members list
83 | func (c *Chat) GetMembers() ([]ChatMember, error) {
84 | return c.client.GetChatMembers(c.ID)
85 | }
86 |
87 | // Get chat blocked users list
88 | func (c *Chat) GetBlockedUsers() ([]User, error) {
89 | return c.client.GetChatBlockedUsers(c.ID)
90 | }
91 |
92 | // Get chat join pending users list
93 | func (c *Chat) GetPendingUsers() ([]User, error) {
94 | return c.client.GetChatPendingUsers(c.ID)
95 | }
96 |
97 | // DeleteMembers removes members from chat
98 | func (c *Chat) DeleteMembers(members []string) error {
99 | return c.client.DeleteChatMembers(c.ID, members)
100 | }
101 |
102 | // AddMembers adds members to chat
103 | func (c *Chat) AddMembers(members []string) error {
104 | return c.client.AddChatMembers(c.ID, members)
105 | }
106 |
107 | // Block user and remove him from chat.
108 | // If deleteLastMessages is true, the messages written recently will be deleted
109 | func (c *Chat) BlockUser(userID string, deleteLastMessages bool) error {
110 | return c.client.BlockChatUser(c.ID, userID, deleteLastMessages)
111 | }
112 |
113 | // Unblock user in chat (but not add him back)
114 | func (c *Chat) UnblockUser(userID string) error {
115 | return c.client.UnblockChatUser(c.ID, userID)
116 | }
117 |
118 | // ResolveJoinRequest resolve specific user chat join request
119 | func (c *Chat) ResolveJoinRequest(userID string, accept bool) error {
120 | return c.client.ResolveChatPending(c.ID, userID, accept, false)
121 | }
122 |
123 | // ResolveAllJoinRequest resolve all chat join requests
124 | func (c *Chat) ResolveAllJoinRequests(accept bool) error {
125 | return c.client.ResolveChatPending(c.ID, "", accept, true)
126 | }
127 |
128 | // SetTitle changes chat title
129 | func (c *Chat) SetTitle(title string) error {
130 | return c.client.SetChatTitle(c.ID, title)
131 | }
132 |
133 | // SetAbout changes chat about
134 | func (c *Chat) SetAbout(about string) error {
135 | return c.client.SetChatAbout(c.ID, about)
136 | }
137 |
138 | // SetRules changes chat rules
139 | func (c *Chat) SetRules(rules string) error {
140 | return c.client.SetChatRules(c.ID, rules)
141 | }
142 |
143 | // AddThread adds a new thread to the specified chat and returns the thread ID
144 | func (c *Chat) AddThread(msgID string) (*Thread, error) {
145 | return c.client.AddThread(c.ID, msgID)
146 | }
147 |
148 | // AutosubscribeToThreads toggles thread auto-subscription for the chat
149 | func (c *Chat) AutosubscribeToThreads(enable, withExisting bool) error {
150 | return c.client.AutosubscribeToThreads(c.ID, enable, withExisting)
151 | }
152 |
--------------------------------------------------------------------------------
/button_easyjson.go:
--------------------------------------------------------------------------------
1 | // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
2 |
3 | package botgolang
4 |
5 | import (
6 | json "encoding/json"
7 | easyjson "github.com/mailru/easyjson"
8 | jlexer "github.com/mailru/easyjson/jlexer"
9 | jwriter "github.com/mailru/easyjson/jwriter"
10 | )
11 |
12 | // suppress unused package warning
13 | var (
14 | _ *json.RawMessage
15 | _ *jlexer.Lexer
16 | _ *jwriter.Writer
17 | _ easyjson.Marshaler
18 | )
19 |
20 | func easyjsonF248ab8DecodeGithubComMailRuImBotGolang(in *jlexer.Lexer, out *ButtonResponse) {
21 | isTopLevel := in.IsStart()
22 | if in.IsNull() {
23 | if isTopLevel {
24 | in.Consumed()
25 | }
26 | in.Skip()
27 | return
28 | }
29 | in.Delim('{')
30 | for !in.IsDelim('}') {
31 | key := in.UnsafeFieldName(false)
32 | in.WantColon()
33 | if in.IsNull() {
34 | in.Skip()
35 | in.WantComma()
36 | continue
37 | }
38 | switch key {
39 | case "queryId":
40 | out.QueryID = string(in.String())
41 | case "text":
42 | out.Text = string(in.String())
43 | case "showAlert":
44 | out.ShowAlert = bool(in.Bool())
45 | case "url":
46 | out.URL = string(in.String())
47 | case "callbackData":
48 | out.CallbackData = string(in.String())
49 | default:
50 | in.SkipRecursive()
51 | }
52 | in.WantComma()
53 | }
54 | in.Delim('}')
55 | if isTopLevel {
56 | in.Consumed()
57 | }
58 | }
59 | func easyjsonF248ab8EncodeGithubComMailRuImBotGolang(out *jwriter.Writer, in ButtonResponse) {
60 | out.RawByte('{')
61 | first := true
62 | _ = first
63 | {
64 | const prefix string = ",\"queryId\":"
65 | out.RawString(prefix[1:])
66 | out.String(string(in.QueryID))
67 | }
68 | {
69 | const prefix string = ",\"text\":"
70 | out.RawString(prefix)
71 | out.String(string(in.Text))
72 | }
73 | {
74 | const prefix string = ",\"showAlert\":"
75 | out.RawString(prefix)
76 | out.Bool(bool(in.ShowAlert))
77 | }
78 | {
79 | const prefix string = ",\"url\":"
80 | out.RawString(prefix)
81 | out.String(string(in.URL))
82 | }
83 | {
84 | const prefix string = ",\"callbackData\":"
85 | out.RawString(prefix)
86 | out.String(string(in.CallbackData))
87 | }
88 | out.RawByte('}')
89 | }
90 |
91 | // MarshalJSON supports json.Marshaler interface
92 | func (v ButtonResponse) MarshalJSON() ([]byte, error) {
93 | w := jwriter.Writer{}
94 | easyjsonF248ab8EncodeGithubComMailRuImBotGolang(&w, v)
95 | return w.Buffer.BuildBytes(), w.Error
96 | }
97 |
98 | // MarshalEasyJSON supports easyjson.Marshaler interface
99 | func (v ButtonResponse) MarshalEasyJSON(w *jwriter.Writer) {
100 | easyjsonF248ab8EncodeGithubComMailRuImBotGolang(w, v)
101 | }
102 |
103 | // UnmarshalJSON supports json.Unmarshaler interface
104 | func (v *ButtonResponse) UnmarshalJSON(data []byte) error {
105 | r := jlexer.Lexer{Data: data}
106 | easyjsonF248ab8DecodeGithubComMailRuImBotGolang(&r, v)
107 | return r.Error()
108 | }
109 |
110 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
111 | func (v *ButtonResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
112 | easyjsonF248ab8DecodeGithubComMailRuImBotGolang(l, v)
113 | }
114 | func easyjsonF248ab8DecodeGithubComMailRuImBotGolang1(in *jlexer.Lexer, out *Button) {
115 | isTopLevel := in.IsStart()
116 | if in.IsNull() {
117 | if isTopLevel {
118 | in.Consumed()
119 | }
120 | in.Skip()
121 | return
122 | }
123 | in.Delim('{')
124 | for !in.IsDelim('}') {
125 | key := in.UnsafeFieldName(false)
126 | in.WantColon()
127 | if in.IsNull() {
128 | in.Skip()
129 | in.WantComma()
130 | continue
131 | }
132 | switch key {
133 | case "text":
134 | out.Text = string(in.String())
135 | case "url":
136 | out.URL = string(in.String())
137 | case "callbackData":
138 | out.CallbackData = string(in.String())
139 | case "style":
140 | out.Style = ButtonStyle(in.String())
141 | default:
142 | in.SkipRecursive()
143 | }
144 | in.WantComma()
145 | }
146 | in.Delim('}')
147 | if isTopLevel {
148 | in.Consumed()
149 | }
150 | }
151 | func easyjsonF248ab8EncodeGithubComMailRuImBotGolang1(out *jwriter.Writer, in Button) {
152 | out.RawByte('{')
153 | first := true
154 | _ = first
155 | {
156 | const prefix string = ",\"text\":"
157 | out.RawString(prefix[1:])
158 | out.String(string(in.Text))
159 | }
160 | if in.URL != "" {
161 | const prefix string = ",\"url\":"
162 | out.RawString(prefix)
163 | out.String(string(in.URL))
164 | }
165 | if in.CallbackData != "" {
166 | const prefix string = ",\"callbackData\":"
167 | out.RawString(prefix)
168 | out.String(string(in.CallbackData))
169 | }
170 | if in.Style != "" {
171 | const prefix string = ",\"style\":"
172 | out.RawString(prefix)
173 | out.String(string(in.Style))
174 | }
175 | out.RawByte('}')
176 | }
177 |
178 | // MarshalJSON supports json.Marshaler interface
179 | func (v Button) MarshalJSON() ([]byte, error) {
180 | w := jwriter.Writer{}
181 | easyjsonF248ab8EncodeGithubComMailRuImBotGolang1(&w, v)
182 | return w.Buffer.BuildBytes(), w.Error
183 | }
184 |
185 | // MarshalEasyJSON supports easyjson.Marshaler interface
186 | func (v Button) MarshalEasyJSON(w *jwriter.Writer) {
187 | easyjsonF248ab8EncodeGithubComMailRuImBotGolang1(w, v)
188 | }
189 |
190 | // UnmarshalJSON supports json.Unmarshaler interface
191 | func (v *Button) UnmarshalJSON(data []byte) error {
192 | r := jlexer.Lexer{Data: data}
193 | easyjsonF248ab8DecodeGithubComMailRuImBotGolang1(&r, v)
194 | return r.Error()
195 | }
196 |
197 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
198 | func (v *Button) UnmarshalEasyJSON(l *jlexer.Lexer) {
199 | easyjsonF248ab8DecodeGithubComMailRuImBotGolang1(l, v)
200 | }
201 |
--------------------------------------------------------------------------------
/types.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | //go:generate easyjson -all types.go
4 |
5 | type EventType string
6 |
7 | type PartType string
8 |
9 | const (
10 | NEW_MESSAGE EventType = "newMessage"
11 | EDITED_MESSAGE EventType = "editedMessage"
12 | DELETED_MESSAGE EventType = "deletedMessage"
13 | PINNED_MESSAGE EventType = "pinnedMessage"
14 | UNPINNED_MESSAGE EventType = "unpinnedMessage"
15 | NEW_CHAT_MEMBERS EventType = "newChatMembers"
16 | LEFT_CHAT_MEMBERS EventType = "leftChatMembers"
17 | CALLBACK_QUERY EventType = "callbackQuery"
18 |
19 | STICKER PartType = "sticker"
20 | MENTION PartType = "mention"
21 | VOICE PartType = "voice"
22 | FILE PartType = "file"
23 | FORWARD PartType = "forward"
24 | REPLY PartType = "reply"
25 | )
26 |
27 | type Response struct {
28 | OK bool `json:"ok"`
29 | Description string `json:"description,omitempty"`
30 | }
31 |
32 | type Thread struct {
33 | ThreadID string `json:"threadId"`
34 | }
35 |
36 | type UserState struct {
37 | Lastseen int `json:"lastseen"`
38 | }
39 |
40 | type Subscriber struct {
41 | SN string `json:"sn"`
42 | UserState UserState `json:"userState"`
43 | }
44 |
45 | type ThreadSubscribers struct {
46 | Cursor string `json:"cursor"`
47 | Subscribers []Subscriber `json:"subscribers"`
48 | }
49 |
50 | type Photo struct {
51 | URL string `json:"url"`
52 | }
53 |
54 | type BotInfo struct {
55 | User
56 |
57 | // Nickname of the bot
58 | Nick string `json:"nick"`
59 |
60 | // Name of the bot
61 | FirstName string `json:"firstName"`
62 |
63 | // Information about the box
64 | About string `json:"about"`
65 |
66 | // A slice of avatars
67 | Photo []Photo `json:"photo"`
68 | }
69 |
70 | type eventsResponse struct {
71 | OK bool `json:"ok"`
72 | Events []*Event `json:"events"`
73 | }
74 |
75 | type User struct {
76 | ID string `json:"userId"`
77 | }
78 |
79 | type ChatMember struct {
80 | User
81 | Creator bool `json:"creator"`
82 | Admin bool `json:"admin"`
83 | }
84 |
85 | type UsersListResponse struct {
86 | List []User `json:"users"`
87 | }
88 |
89 | type MembersListResponse struct {
90 | // TODO: cursor
91 | List []ChatMember `json:"members"`
92 | }
93 |
94 | type AdminsListResponse struct {
95 | List []ChatMember `json:"admins"`
96 | }
97 |
98 | type Contact struct {
99 | User
100 | FirstName string `json:"firstName"`
101 | LastName string `json:"lastName"`
102 | }
103 |
104 | type BaseEventPayload struct {
105 | // Id of the message.
106 | // Presented in newMessage, editedMessage, deletedMessage, pinnedMessage, unpinnedMessage events.
107 | MsgID string `json:"msgId"`
108 |
109 | // Chat info.
110 | // Presented in all events.
111 | Chat Chat `json:"chat"`
112 |
113 | // Author of the message
114 | // Presented in newMessage and editedMessage events.
115 | From Contact `json:"from"`
116 |
117 | // Text of the message.
118 | // Presented in newMessage, editedMessage and pinnedMessage events.
119 | Text string `json:"text"`
120 |
121 | // Timestamp of the event.
122 | Timestamp int `json:"timestamp"`
123 |
124 | ParentMessage *ParentMessage `json:"parent_topic"`
125 | }
126 |
127 | type EventPayload struct {
128 | client *Client
129 | BaseEventPayload
130 |
131 | // Parts of the message.
132 | // Presented only in newMessage event.
133 | Parts []Part `json:"parts"`
134 |
135 | // Id of the query.
136 | // Presented only in callbackQuery event.
137 | QueryID string `json:"queryId"`
138 |
139 | // Callback message of the query (parent message for button).
140 | // Presented only in callbackQuery event.
141 | CallbackMsg BaseEventPayload `json:"message"`
142 |
143 | // CallbackData of the query (id of button).
144 | // Presented only in callbackQuery event.
145 | CallbackData string `json:"callbackData"`
146 |
147 | LeftMembers []Contact `json:"leftMembers"`
148 |
149 | NewMembers []Contact `json:"newMembers"`
150 |
151 | AddedBy Contact `json:"addedBy"`
152 |
153 | RemovedBy Contact `json:"removedBy"`
154 | }
155 |
156 | func (ep *EventPayload) Message() *Message {
157 | return message(ep.client, ep.BaseEventPayload)
158 | }
159 |
160 | func (ep *EventPayload) CallbackMessage() *Message {
161 | return message(ep.client, ep.CallbackMsg)
162 | }
163 |
164 | func message(client *Client, msg BaseEventPayload) *Message {
165 | msg.Chat.client = client
166 | return &Message{
167 | client: client,
168 | ID: msg.MsgID,
169 | Text: msg.Text,
170 | Chat: msg.Chat,
171 | Timestamp: msg.Timestamp,
172 | ParentMessage: msg.ParentMessage,
173 | }
174 | }
175 |
176 | type PartMessage struct {
177 | From Contact `json:"from"`
178 | MsgID string `json:"msgId"`
179 | Text string `json:"text"`
180 | Timestamp int `json:"timestamp"`
181 | }
182 |
183 | type PartPayload struct {
184 | FirstName string `json:"firstName"`
185 | LastName string `json:"lastName"`
186 | UserID string `json:"userId"`
187 | FileID string `json:"fileId"`
188 | Caption string `json:"caption"`
189 | Type string `json:"type"`
190 | PartMessage PartMessage `json:"message"`
191 | Message PartMessage `json:"-"`
192 | }
193 |
194 | type Event struct {
195 | client *Client
196 |
197 | // Id of the event
198 | EventID int `json:"eventId"`
199 |
200 | // Type of the event: newMessage, editedMessage, deletedMessage, pinnedMessage, unpinnedMessage, newChatMembers
201 | Type EventType `json:"type"`
202 |
203 | // Payload of the event
204 | Payload EventPayload `json:"payload"`
205 | }
206 |
207 | type Part struct {
208 | // Type of the part
209 | Type PartType `json:"type"`
210 |
211 | // Payload of the part
212 | Payload PartPayload `json:"payload"`
213 | }
214 |
215 | func (ep *EventPayload) CallbackQuery() *ButtonResponse {
216 | return &ButtonResponse{
217 | client: ep.client,
218 | QueryID: ep.QueryID,
219 | CallbackData: ep.CallbackData,
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/message.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "path/filepath"
7 | )
8 |
9 | //go:generate easyjson -all message.go
10 |
11 | type MessageContentType uint8
12 |
13 | const (
14 | Unknown MessageContentType = iota
15 | Text
16 | OtherFile
17 | Voice
18 | Deeplink
19 | )
20 |
21 | // Message represents a text message
22 | type Message struct {
23 | client *Client
24 | ContentType MessageContentType
25 |
26 | // Id of the message (for editing)
27 | ID string `json:"msgId"`
28 |
29 | // File contains file attachment of the message
30 | File *os.File `json:"-"`
31 |
32 | // Id of file to send
33 | FileID string `json:"fileId"`
34 |
35 | // Text of the message or caption for file
36 | Text string `json:"text"`
37 |
38 | // Chat where to send the message
39 | Chat Chat `json:"chat"`
40 |
41 | // Id of replied message
42 | // You can't use it with ForwardMsgID or ForwardChatID
43 | ReplyMsgID string `json:"replyMsgId"`
44 |
45 | // Id of forwarded message
46 | // You can't use it with ReplyMsgID
47 | ForwardMsgID string `json:"forwardMsgId"`
48 |
49 | // Id of a chat from which you forward the message
50 | // You can't use it with ReplyMsgID
51 | // You should use it with ForwardMsgID
52 | ForwardChatID string `json:"forwardChatId"`
53 |
54 | Timestamp int `json:"timestamp"`
55 |
56 | ParentMessage *ParentMessage `json:"parent_topic"`
57 |
58 | // The markup for the inline keyboard
59 | InlineKeyboard *Keyboard `json:"inlineKeyboardMarkup"`
60 |
61 | // The parse mode (HTML/MarkdownV2)
62 | ParseMode ParseMode `json:"parseMode"`
63 |
64 | // RequestID from library clients that is used in my-team logs
65 | RequestID string `json:"requestID"`
66 |
67 | // Use it only with content type Deeplink
68 | Deeplink string `json:"deeplink"`
69 | }
70 |
71 | func (m *Message) AttachNewFile(file *os.File) {
72 | m.File = file
73 | m.ContentType = OtherFile
74 | }
75 |
76 | func (m *Message) AttachExistingFile(fileID string) {
77 | m.FileID = fileID
78 | m.ContentType = OtherFile
79 | }
80 |
81 | func (m *Message) AttachNewVoice(file *os.File) {
82 | m.File = file
83 | m.ContentType = Voice
84 | }
85 |
86 | func (m *Message) AttachExistingVoice(fileID string) {
87 | m.FileID = fileID
88 | m.ContentType = Voice
89 | }
90 |
91 | type ParentMessage struct {
92 | ChatID string `json:"chatId"`
93 | MsgID int64 `json:"messageId"`
94 | Type string `json:"type"`
95 | }
96 |
97 | // ParseMode represent a type of text formatting
98 | type ParseMode string
99 |
100 | const (
101 | ParseModeHTML ParseMode = "HTML"
102 | ParseModeMarkdownV2 ParseMode = "MarkdownV2"
103 | )
104 |
105 | // AppendParseMode append a type of text formatting for current message
106 | func (m *Message) AppendParseMode(mode ParseMode) {
107 | m.ParseMode = mode
108 | }
109 |
110 | // AttachInlineKeyboard adds a keyboard to the message.
111 | // Note - at least one row should be in the keyboard
112 | // and there should be no empty rows
113 | func (m *Message) AttachInlineKeyboard(keyboard Keyboard) {
114 | m.InlineKeyboard = &keyboard
115 | }
116 |
117 | // Send method sends your message.
118 | // Make sure you have Text or FileID in your message.
119 | func (m *Message) Send() error {
120 | if m.client == nil {
121 | return fmt.Errorf("client is not inited, create message with constructor NewMessage, NewTextMessage, etc")
122 | }
123 |
124 | if m.Chat.ID == "" {
125 | return fmt.Errorf("message should have chat id")
126 | }
127 |
128 | switch m.ContentType {
129 | case Voice:
130 | if m.FileID != "" {
131 | return m.client.SendVoiceMessage(m)
132 | }
133 |
134 | if m.File != nil {
135 | return m.client.UploadVoice(m)
136 | }
137 | case OtherFile:
138 | if m.FileID != "" {
139 | return m.client.SendFileMessage(m)
140 | }
141 |
142 | if m.File != nil {
143 | return m.client.UploadFile(m)
144 | }
145 | case Text:
146 | return m.client.SendTextMessage(m)
147 | case Deeplink:
148 | return m.client.SendTextWithDeeplinkMessage(m)
149 | case Unknown:
150 | // need to autodetect
151 | if m.FileID != "" {
152 | // voice message's fileID always starts with 'I'
153 | if m.FileID[0] == voiceMessageLeadingRune {
154 | return m.client.SendVoiceMessage(m)
155 | }
156 | return m.client.SendFileMessage(m)
157 | }
158 |
159 | if m.File != nil {
160 | if voiceMessageSupportedExtensions[filepath.Ext(m.File.Name())] {
161 | return m.client.UploadVoice(m)
162 | }
163 | return m.client.UploadFile(m)
164 | }
165 |
166 | if m.Text != "" {
167 | return m.client.SendTextMessage(m)
168 | }
169 | }
170 |
171 | return fmt.Errorf("cannot send message or file without data")
172 | }
173 |
174 | // Edit method edits your message.
175 | // Make sure you have ID in your message.
176 | func (m *Message) Edit() error {
177 | if m.ID == "" {
178 | return fmt.Errorf("cannot edit message without id")
179 | }
180 | return m.client.EditMessage(m)
181 | }
182 |
183 | // Delete method deletes your message.
184 | // Make sure you have ID in your message.
185 | func (m *Message) Delete() error {
186 | if m.ID == "" {
187 | return fmt.Errorf("cannot delete message without id")
188 | }
189 |
190 | return m.client.DeleteMessage(m)
191 | }
192 |
193 | // Reply method replies to the message.
194 | // Make sure you have ID in the message.
195 | func (m *Message) Reply(text string) error {
196 | if m.ID == "" {
197 | return fmt.Errorf("cannot reply to message without id")
198 | }
199 |
200 | m.ReplyMsgID = m.ID
201 | m.Text = text
202 |
203 | return m.client.SendTextMessage(m)
204 | }
205 |
206 | // Forward method forwards your message to chat.
207 | // Make sure you have ID in your message.
208 | func (m *Message) Forward(chatID string) error {
209 | if m.ID == "" {
210 | return fmt.Errorf("cannot forward message without id")
211 | }
212 |
213 | m.ForwardChatID = m.Chat.ID
214 | m.ForwardMsgID = m.ID
215 | m.Chat.ID = chatID
216 |
217 | return m.client.SendTextMessage(m)
218 | }
219 |
220 | // Pin message in chat
221 | // Make sure you are admin in this chat
222 | func (m *Message) Pin() error {
223 | if m.ID == "" {
224 | return fmt.Errorf("cannot pin message without id")
225 | }
226 |
227 | return m.client.PinMessage(m)
228 | }
229 |
230 | // Unpin message in chat
231 | // Make sure you are admin in this chat
232 | func (m *Message) Unpin() error {
233 | if m.ID == "" {
234 | return fmt.Errorf("cannot unpin message without id")
235 | }
236 |
237 | return m.client.UnpinMessage(m)
238 | }
239 |
--------------------------------------------------------------------------------
/api_mock.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | import (
4 | "encoding/json"
5 | "net/http"
6 |
7 | "github.com/sirupsen/logrus"
8 | )
9 |
10 | type MockHandler struct {
11 | http.Handler
12 | logger *logrus.Logger
13 | }
14 |
15 | func (h *MockHandler) SendMessage(w http.ResponseWriter) {
16 | encoder := json.NewEncoder(w)
17 | err := encoder.Encode(&Response{
18 | OK: true,
19 | })
20 |
21 | if err != nil {
22 | h.logger.WithFields(logrus.Fields{
23 | "err": err,
24 | }).Error("cannot encode json")
25 | }
26 | }
27 |
28 | func (h *MockHandler) TokenError(w http.ResponseWriter) {
29 | encoder := json.NewEncoder(w)
30 | err := encoder.Encode(&Response{
31 | OK: false,
32 | Description: "Missing required parameter 'token'",
33 | })
34 |
35 | if err != nil {
36 | h.logger.WithFields(logrus.Fields{
37 | "err": err,
38 | }).Error("cannot encode json")
39 | }
40 | }
41 |
42 | func (h *MockHandler) GetEvents(w http.ResponseWriter) {
43 | events := `
44 | {
45 | "ok": true,
46 | "events": [
47 | {
48 | "eventId": 1,
49 | "type": "newMessage",
50 | "payload": {
51 | "msgId": "57883346846815030",
52 | "chat": {
53 | "chatId": "681869378@chat.agent",
54 | "type": "channel",
55 | "title": "The best channel"
56 | },
57 | "from": {
58 | "userId": "1234567890",
59 | "firstName": "Name",
60 | "lastName": "SurName"
61 | },
62 | "timestamp": 1546290000,
63 | "text": "Hello!",
64 | "parts": [
65 | {
66 | "type": "sticker",
67 | "payload": {
68 | "fileId": "2IWuJzaNWCJZxJWCvZhDYuJ5XDsr7hU"
69 | }
70 | },
71 | {
72 | "type": "mention",
73 | "payload": {
74 | "userId": "1234567890",
75 | "firstName": "Name",
76 | "lastName": "SurName"
77 | }
78 | },
79 | {
80 | "type": "voice",
81 | "payload": {
82 | "fileId": "IdjUEXuGdNhLKUfD5rvkE03IOax54cD"
83 | }
84 | },
85 | {
86 | "type": "file",
87 | "payload": {
88 | "fileId": "ZhSnMuaOmF7FRez2jGWuQs5zGZwlLa0",
89 | "type": "image",
90 | "caption": "Last weekend trip"
91 | }
92 | },
93 | {
94 | "type": "forward",
95 | "payload": {
96 | "message": {
97 | "msgId": "12354",
98 | "text": "test1"
99 | }
100 | }
101 | },
102 | {
103 | "type": "reply",
104 | "payload": {
105 | "message": {
106 | "msgId": "12354",
107 | "text": "test"
108 | }
109 | }
110 | }
111 | ]
112 | }
113 | },
114 | {
115 | "eventId": 2,
116 | "type": "editedMessage",
117 | "payload": {
118 | "msgId": "57883346846815030",
119 | "chat": {
120 | "chatId": "681869378@chat.agent",
121 | "type": "channel",
122 | "title": "The best channel"
123 | },
124 | "from": {
125 | "userId": "1234567890",
126 | "firstName": "Name",
127 | "lastName": "SurName"
128 | },
129 | "timestamp": 1546290000,
130 | "text": "Hello!",
131 | "editedTimestamp": 1546290099
132 | }
133 | },
134 | {
135 | "eventId": 3,
136 | "type": "deletedMessage",
137 | "payload": {
138 | "msgId": "57883346846815030",
139 | "chat": {
140 | "chatId": "681869378@chat.agent",
141 | "type": "channel",
142 | "title": "The best channel"
143 | },
144 | "timestamp": 1546290000
145 | }
146 | },
147 | {
148 | "eventId": 4,
149 | "type": "pinnedMessage",
150 | "payload": {
151 | "chat": {
152 | "chatId": "681869378@chat.agent",
153 | "type": "group",
154 | "title": "The best group"
155 | },
156 | "from": {
157 | "userId": "9876543210",
158 | "firstName": "Name",
159 | "lastName": "SurName"
160 | },
161 | "msgId": "6720509406122810000",
162 | "text": "Some important information!",
163 | "timestamp": 1564740530
164 | }
165 | },
166 | {
167 | "eventId": 5,
168 | "type": "unpinnedMessage",
169 | "payload": {
170 | "chat": {
171 | "chatId": "681869378@chat.agent",
172 | "type": "group",
173 | "title": "The best group"
174 | },
175 | "msgId": "6720509406122810000",
176 | "timestamp": 1564740530
177 | }
178 | },
179 | {
180 | "eventId": 6,
181 | "type": "newChatMembers",
182 | "payload": {
183 | "chat": {
184 | "chatId": "681869378@chat.agent",
185 | "type": "group",
186 | "title": "The best group"
187 | },
188 | "newMembers": [
189 | {
190 | "userId": "1234567890",
191 | "firstName": "Name",
192 | "lastName": "SurName"
193 | }
194 | ],
195 | "addedBy": {
196 | "userId": "9876543210",
197 | "firstName": "Name",
198 | "lastName": "SurName"
199 | }
200 | }
201 | },
202 | {
203 | "eventId": 7,
204 | "type": "leftChatMembers",
205 | "payload": {
206 | "chat": {
207 | "chatId": "681869378@chat.agent",
208 | "type": "group",
209 | "title": "The best group"
210 | },
211 | "leftMembers": [
212 | {
213 | "userId": "1234567890",
214 | "firstName": "Name",
215 | "lastName": "SurName"
216 | }
217 | ],
218 | "removedBy": {
219 | "userId": "9876543210",
220 | "firstName": "Name",
221 | "lastName": "SurName"
222 | }
223 | }
224 | },
225 | {
226 | "eventId": 8,
227 | "payload": {
228 | "callbackData": "echo",
229 | "from": {
230 | "firstName": "Name",
231 | "userId": "1234567890"
232 | },
233 | "message": {
234 | "chat": {
235 | "chatId": "1234567890",
236 | "type": "private"
237 | },
238 | "from": {
239 | "firstName": "bot_name",
240 | "nick": "bot_nick",
241 | "userId": "bot_id"
242 | },
243 | "msgId": "6720509406122810000",
244 | "text": "Some important information!",
245 | "timestamp": 1564740530
246 | },
247 | "queryId": "SVR:123456"
248 | },
249 | "type": "callbackQuery"
250 | }
251 | ]
252 | }
253 | `
254 |
255 | _, err := w.Write([]byte(events))
256 | if err != nil {
257 | h.logger.Fatal("failed to write events")
258 | }
259 | }
260 |
261 | func (h *MockHandler) SelfGet(w http.ResponseWriter, r *http.Request) {
262 |
263 | encoder := json.NewEncoder(w)
264 |
265 | if r.FormValue("chatId") == "" {
266 | err := encoder.Encode(&Response{
267 | OK: false,
268 | Description: "Missing required parameter 'chatId'",
269 | })
270 |
271 | if err != nil {
272 | h.logger.WithFields(logrus.Fields{
273 | "err": err,
274 | }).Error("cannot encode json")
275 | }
276 | }
277 |
278 | chats_getInfo := `{
279 | "about": "about user",
280 | "firstName": "User",
281 | "language": "en",
282 | "lastName": "Userov",
283 | "photo": [
284 | {
285 | "url": "https://rapi.myteaminternal/avatar/get?targetSn=test@test&size=1024"
286 | }
287 | ],
288 | "type": "private",
289 | "ok": true
290 | }`
291 |
292 | _, err := w.Write([]byte(chats_getInfo))
293 | if err != nil {
294 | h.logger.Fatal("failed to write events")
295 | }
296 | }
297 |
298 | func (h *MockHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
299 | switch {
300 | case r.FormValue("token") == "":
301 | h.TokenError(w)
302 | return
303 | case r.URL.Path == "/messages/sendText":
304 | h.SendMessage(w)
305 | return
306 | case r.URL.Path == "/events/get":
307 | h.GetEvents(w)
308 | return
309 | case r.URL.Path == "/self/get":
310 | h.SelfGet(w, r)
311 | return
312 | default:
313 | encoder := json.NewEncoder(w)
314 | err := encoder.Encode(&Response{
315 | OK: true,
316 | })
317 |
318 | if err != nil {
319 | h.logger.WithFields(logrus.Fields{
320 | "err": err,
321 | }).Error("cannot encode response")
322 | }
323 | }
324 |
325 | }
326 |
--------------------------------------------------------------------------------
/client_test.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | import (
4 | "net/http"
5 | "net/http/httptest"
6 | "net/url"
7 | "testing"
8 |
9 | "github.com/sirupsen/logrus"
10 | "github.com/stretchr/testify/assert"
11 | "github.com/stretchr/testify/require"
12 | )
13 |
14 | func TestClient_Do_OK(t *testing.T) {
15 | assert := assert.New(t)
16 | testServer := httptest.NewServer(&MockHandler{})
17 | defer func() { testServer.Close() }()
18 |
19 | client := Client{
20 | baseURL: testServer.URL,
21 | token: "test_token",
22 | client: http.DefaultClient,
23 | logger: &logrus.Logger{},
24 | }
25 |
26 | bytes, err := client.Do("/", url.Values{}, nil)
27 |
28 | assert.NoError(err)
29 | assert.JSONEq(`{"ok":true}`, string(bytes))
30 | }
31 |
32 | func TestClient_Do_Error(t *testing.T) {
33 | assert := assert.New(t)
34 | testServer := httptest.NewServer(&MockHandler{})
35 | defer func() { testServer.Close() }()
36 |
37 | client := Client{
38 | baseURL: testServer.URL,
39 | token: "",
40 | client: http.DefaultClient,
41 | logger: &logrus.Logger{},
42 | }
43 |
44 | expected := `{"ok":false, "description":"Missing required parameter 'token'"}`
45 |
46 | bytes, err := client.Do("/", url.Values{}, nil)
47 |
48 | assert.EqualError(err, "error status from API: Missing required parameter 'token'")
49 | assert.JSONEq(expected, string(bytes))
50 | }
51 |
52 | func TestClient_GetEvents_OK(t *testing.T) {
53 | assert := assert.New(t)
54 | require := require.New(t)
55 | testServer := httptest.NewServer(&MockHandler{})
56 | defer func() { testServer.Close() }()
57 |
58 | expected := []*Event{
59 | {
60 | EventID: 1,
61 | Type: NEW_MESSAGE,
62 | Payload: EventPayload{
63 | BaseEventPayload: BaseEventPayload{
64 | MsgID: "57883346846815030",
65 | Chat: Chat{
66 | ID: "681869378@chat.agent",
67 | Type: "channel",
68 | Title: "The best channel",
69 | },
70 | From: Contact{
71 | User: User{"1234567890"},
72 | FirstName: "Name",
73 | LastName: "SurName",
74 | },
75 | Text: "Hello!",
76 | Timestamp: 1546290000,
77 | },
78 | Parts: []Part{
79 | {
80 | Type: STICKER,
81 | Payload: PartPayload{
82 | FileID: "2IWuJzaNWCJZxJWCvZhDYuJ5XDsr7hU",
83 | },
84 | },
85 | {
86 | Type: MENTION,
87 | Payload: PartPayload{
88 | FirstName: "Name",
89 | LastName: "SurName",
90 | UserID: "1234567890",
91 | },
92 | },
93 | {
94 | Type: VOICE,
95 | Payload: PartPayload{
96 | FileID: "IdjUEXuGdNhLKUfD5rvkE03IOax54cD",
97 | },
98 | },
99 | {
100 | Type: FILE,
101 | Payload: PartPayload{
102 | FileID: "ZhSnMuaOmF7FRez2jGWuQs5zGZwlLa0",
103 | Caption: "Last weekend trip",
104 | Type: "image",
105 | },
106 | },
107 | {
108 | Type: FORWARD,
109 | Payload: PartPayload{
110 | PartMessage: PartMessage{
111 | MsgID: "12354",
112 | Text: "test1",
113 | },
114 | },
115 | },
116 | {
117 | Type: REPLY,
118 | Payload: PartPayload{
119 | PartMessage: PartMessage{
120 | MsgID: "12354",
121 | Text: "test",
122 | },
123 | },
124 | },
125 | },
126 | },
127 | },
128 | {
129 | EventID: 2,
130 | Type: EDITED_MESSAGE,
131 | Payload: EventPayload{
132 | BaseEventPayload: BaseEventPayload{
133 | MsgID: "57883346846815030",
134 | Chat: Chat{
135 | ID: "681869378@chat.agent",
136 | Type: "channel",
137 | Title: "The best channel",
138 | },
139 | From: Contact{
140 | User: User{"1234567890"},
141 | FirstName: "Name",
142 | LastName: "SurName",
143 | },
144 | Text: "Hello!",
145 | Timestamp: 1546290000,
146 | },
147 | },
148 | },
149 | {
150 | EventID: 3,
151 | Type: DELETED_MESSAGE,
152 | Payload: EventPayload{
153 | BaseEventPayload: BaseEventPayload{
154 | MsgID: "57883346846815030",
155 | Chat: Chat{
156 | ID: "681869378@chat.agent",
157 | Type: "channel",
158 | Title: "The best channel",
159 | },
160 | Timestamp: 1546290000,
161 | },
162 | },
163 | },
164 | {
165 | EventID: 4,
166 | Type: PINNED_MESSAGE,
167 | Payload: EventPayload{
168 | BaseEventPayload: BaseEventPayload{
169 | MsgID: "6720509406122810000",
170 | Chat: Chat{
171 | ID: "681869378@chat.agent",
172 | Type: "group",
173 | Title: "The best group",
174 | },
175 | From: Contact{
176 | User: User{"9876543210"},
177 | FirstName: "Name",
178 | LastName: "SurName",
179 | },
180 | Text: "Some important information!",
181 | Timestamp: 1564740530,
182 | },
183 | },
184 | },
185 | {
186 | EventID: 5,
187 | Type: UNPINNED_MESSAGE,
188 | Payload: EventPayload{
189 | BaseEventPayload: BaseEventPayload{
190 | MsgID: "6720509406122810000",
191 | Chat: Chat{
192 | ID: "681869378@chat.agent",
193 | Type: "group",
194 | Title: "The best group",
195 | },
196 | Timestamp: 1564740530,
197 | },
198 | },
199 | },
200 | {
201 | EventID: 6,
202 | Type: NEW_CHAT_MEMBERS,
203 | Payload: EventPayload{
204 | BaseEventPayload: BaseEventPayload{
205 | Chat: Chat{
206 | ID: "681869378@chat.agent",
207 | Type: "group",
208 | Title: "The best group",
209 | },
210 | },
211 | NewMembers: []Contact{
212 | {
213 | User: User{"1234567890"},
214 | FirstName: "Name",
215 | LastName: "SurName",
216 | },
217 | },
218 | AddedBy: Contact{
219 | User: User{"9876543210"},
220 | FirstName: "Name",
221 | LastName: "SurName",
222 | },
223 | },
224 | },
225 | {
226 | EventID: 7,
227 | Type: LEFT_CHAT_MEMBERS,
228 | Payload: EventPayload{
229 | BaseEventPayload: BaseEventPayload{
230 | Chat: Chat{
231 | ID: "681869378@chat.agent",
232 | Type: "group",
233 | Title: "The best group",
234 | },
235 | },
236 | LeftMembers: []Contact{
237 | {
238 | User: User{"1234567890"},
239 | FirstName: "Name",
240 | LastName: "SurName",
241 | },
242 | },
243 | RemovedBy: Contact{
244 | User: User{"9876543210"},
245 | FirstName: "Name",
246 | LastName: "SurName",
247 | },
248 | },
249 | },
250 | {
251 | EventID: 8,
252 | Type: CALLBACK_QUERY,
253 | Payload: EventPayload{
254 | CallbackData: "echo",
255 | CallbackMsg: BaseEventPayload{
256 | MsgID: "6720509406122810000",
257 | Chat: Chat{
258 | ID: "1234567890",
259 | Type: "private",
260 | },
261 | From: Contact{
262 | User: User{"bot_id"},
263 | FirstName: "bot_name",
264 | },
265 | Text: "Some important information!",
266 | Timestamp: 1564740530,
267 | },
268 | BaseEventPayload: BaseEventPayload{
269 | From: Contact{
270 | User: User{"1234567890"},
271 | FirstName: "Name",
272 | },
273 | },
274 | QueryID: "SVR:123456",
275 | },
276 | },
277 | }
278 |
279 | client := Client{
280 | baseURL: testServer.URL,
281 | token: "test_token",
282 | client: http.DefaultClient,
283 | logger: &logrus.Logger{},
284 | }
285 |
286 | events, err := client.GetEvents(0, 0)
287 |
288 | require.NoError(err)
289 | assert.Equal(events, expected)
290 | }
291 |
292 | func TestClient_GetInfo_OK(t *testing.T) {
293 | require := require.New(t)
294 | assert := assert.New(t)
295 | testServer := httptest.NewServer(&MockHandler{})
296 | defer func() { testServer.Close() }()
297 |
298 | client := Client{
299 | baseURL: testServer.URL,
300 | token: "test_token",
301 | client: http.DefaultClient,
302 | logger: &logrus.Logger{},
303 | }
304 |
305 | info, err := client.GetChatInfo("id_1234")
306 | require.NoError(err)
307 | assert.NotEmpty(info.ID)
308 | }
309 |
310 | func TestClient_GetInfo_Error(t *testing.T) {
311 | require := require.New(t)
312 |
313 | require.NoError(nil)
314 | }
315 |
--------------------------------------------------------------------------------
/keyboard_test.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | import (
4 | "github.com/stretchr/testify/assert"
5 | "reflect"
6 | "testing"
7 | )
8 |
9 | var (
10 | btnArray1 = []Button{{Text: "test"}, {Text: "test2"}}
11 | btnArray2 = []Button{{Text: "tes123t"}, {Text: "test123"}, {Text: "test123"}, {Text: "test2231"}}
12 | btnArray3 = []Button{{Text: "ew"}}
13 | )
14 |
15 | type fields struct {
16 | Rows [][]Button
17 | }
18 |
19 | func TestKeyboard_AddButton(t *testing.T) {
20 | type args struct {
21 | rowIndex int
22 | button Button
23 | }
24 |
25 | btn := NewURLButton("test", "mail.ru")
26 | btn2 := NewCallbackButton("test2", "asdfww34gsw35")
27 | btnRow := []Button{btn, btn2}
28 |
29 | newBtn := NewCallbackButton("newBtn", "sdtw234")
30 |
31 | expected := []Button{btn, btn2, newBtn}
32 |
33 | tests := []struct {
34 | name string
35 | fields fields
36 | args args
37 | exp fields
38 | wantErr bool
39 | }{
40 | {
41 | name: "OK",
42 | fields: fields{[][]Button{btnRow}},
43 | args: args{0, newBtn},
44 | exp: fields{[][]Button{expected}},
45 | wantErr: false,
46 | },
47 | {
48 | name: "Error",
49 | fields: fields{[][]Button{btnRow}},
50 | args: args{4, newBtn},
51 | exp: fields{[][]Button{btnRow}},
52 | wantErr: true,
53 | },
54 | }
55 | for _, tt := range tests {
56 | t.Run(tt.name, func(t *testing.T) {
57 | k := &Keyboard{
58 | Rows: tt.fields.Rows,
59 | }
60 | if err := k.AddButton(tt.args.rowIndex, tt.args.button); (err != nil) != tt.wantErr {
61 | t.Errorf("AddButton() error = %v, wantErr %v", err, tt.wantErr)
62 | }
63 | assert.Equal(t, reflect.DeepEqual(tt.exp.Rows, k.GetKeyboard()), true)
64 | })
65 | }
66 | }
67 |
68 | func TestKeyboard_AddRow(t *testing.T) {
69 | type args struct {
70 | row []Button
71 | }
72 | btn := NewURLButton("test", "mail.ru")
73 | btn2 := NewCallbackButton("test2", "asdfww34gsw35")
74 | btnRow := []Button{btn}
75 | btnRow2 := []Button{btn2}
76 |
77 | tests := []struct {
78 | name string
79 | fields fields
80 | args args
81 | exp fields
82 | }{
83 | {
84 | name: "OK_First",
85 | fields: fields{nil},
86 | args: args{row: btnRow},
87 | exp: fields{[][]Button{btnRow}},
88 | },
89 | {
90 | name: "OK_Add",
91 | fields: fields{[][]Button{btnRow}},
92 | args: args{row: btnRow2},
93 | exp: fields{[][]Button{btnRow, btnRow2}},
94 | },
95 | {
96 | name: "Nil",
97 | fields: fields{nil},
98 | args: args{row: nil},
99 | exp: fields{[][]Button{[]Button(nil)}},
100 | },
101 | }
102 | for _, tt := range tests {
103 | t.Run(tt.name, func(t *testing.T) {
104 | k := &Keyboard{
105 | Rows: tt.fields.Rows,
106 | }
107 | k.AddRow(tt.args.row...)
108 | assert.Equal(t, tt.exp.Rows, k.GetKeyboard())
109 | })
110 | }
111 | }
112 |
113 | func TestKeyboard_ChangeButton(t *testing.T) {
114 | type args struct {
115 | rowIndex int
116 | buttonIndex int
117 | newButton Button
118 | }
119 | newBtn := Button{Text: "TestButton"}
120 |
121 | array1 := make([]Button, len(btnArray1))
122 | copy(array1, btnArray1)
123 |
124 | expArray := make([]Button, len(array1))
125 | expArray[0] = newBtn
126 | expArray[1] = btnArray1[1]
127 |
128 | tests := []struct {
129 | name string
130 | fields fields
131 | args args
132 | exp fields
133 | wantErr bool
134 | }{
135 | {
136 | name: "OK",
137 | fields: fields{[][]Button{array1}},
138 | args: args{0, 0, newBtn},
139 | exp: fields{[][]Button{expArray}},
140 | wantErr: false,
141 | },
142 | {
143 | name: "Error",
144 | fields: fields{[][]Button{array1}},
145 | args: args{0, 5, newBtn},
146 | exp: fields{[][]Button{expArray}},
147 | wantErr: true,
148 | },
149 | }
150 | for _, tt := range tests {
151 | t.Run(tt.name, func(t *testing.T) {
152 | k := &Keyboard{
153 | Rows: tt.fields.Rows,
154 | }
155 | if err := k.ChangeButton(tt.args.rowIndex, tt.args.buttonIndex, tt.args.newButton); (err != nil) != tt.wantErr {
156 | t.Errorf("ChangeButton() error = %v, wantErr %v", err, tt.wantErr)
157 | }
158 | assert.Equal(t, reflect.DeepEqual(tt.exp.Rows, k.GetKeyboard()), true)
159 | })
160 | }
161 | }
162 |
163 | func TestKeyboard_DeleteButton(t *testing.T) {
164 | type args struct {
165 | rowIndex int
166 | buttonIndex int
167 | }
168 |
169 | array1 := [][]Button{btnArray1}
170 | exp1 := [][]Button{{btnArray1[1]}}
171 |
172 | tests := []struct {
173 | name string
174 | fields fields
175 | args args
176 | exp fields
177 | wantErr bool
178 | }{
179 | {
180 | name: "OK",
181 | fields: fields{array1},
182 | args: args{0, 0},
183 | exp: fields{exp1},
184 | wantErr: false,
185 | },
186 | {
187 | name: "Error",
188 | fields: fields{array1},
189 | args: args{2, 13},
190 | exp: fields{exp1},
191 | wantErr: true,
192 | },
193 | }
194 | for _, tt := range tests {
195 | t.Run(tt.name, func(t *testing.T) {
196 | k := &Keyboard{
197 | Rows: tt.fields.Rows,
198 | }
199 | if err := k.DeleteButton(tt.args.rowIndex, tt.args.buttonIndex); (err != nil) != tt.wantErr {
200 | t.Errorf("DeleteButton() error = %v, wantErr %v", err, tt.wantErr)
201 | }
202 | assert.Equal(t, tt.exp.Rows, k.GetKeyboard())
203 | })
204 | }
205 | }
206 |
207 | func TestKeyboard_DeleteRow(t *testing.T) {
208 | type args struct {
209 | index int
210 | }
211 |
212 | tests := []struct {
213 | name string
214 | fields fields
215 | args args
216 | exp fields
217 | wantErr bool
218 | }{
219 | {
220 | name: "OK",
221 | fields: fields{[][]Button{btnArray1}},
222 | args: args{0},
223 | exp: fields{[][]Button{}},
224 | wantErr: false,
225 | },
226 | {
227 | name: "Error",
228 | fields: fields{[][]Button{btnArray1}},
229 | args: args{1},
230 | exp: fields{[][]Button{btnArray1}},
231 | wantErr: true,
232 | },
233 | }
234 | for _, tt := range tests {
235 | t.Run(tt.name, func(t *testing.T) {
236 | k := &Keyboard{
237 | Rows: tt.fields.Rows,
238 | }
239 | if err := k.DeleteRow(tt.args.index); (err != nil) != tt.wantErr {
240 | t.Errorf("DeleteRow() error = %v, wantErr %v", err, tt.wantErr)
241 | }
242 | assert.Equal(t, tt.exp.Rows, k.GetKeyboard())
243 | })
244 | }
245 | }
246 |
247 | func TestKeyboard_RowSize(t *testing.T) {
248 | type args struct {
249 | row int
250 | }
251 | tests := []struct {
252 | name string
253 | fields fields
254 | args args
255 | want int
256 | }{
257 | {
258 | name: "OK",
259 | fields: fields{[][]Button{btnArray2}},
260 | args: args{0},
261 | want: len(btnArray2),
262 | },
263 | {
264 | name: "OK",
265 | fields: fields{[][]Button{btnArray2, btnArray3}},
266 | args: args{1},
267 | want: len(btnArray3),
268 | },
269 | {
270 | name: "NO_ROW",
271 | fields: fields{[][]Button{btnArray2, btnArray3}},
272 | args: args{4},
273 | want: -1,
274 | },
275 | }
276 | for _, tt := range tests {
277 | t.Run(tt.name, func(t *testing.T) {
278 | k := &Keyboard{
279 | Rows: tt.fields.Rows,
280 | }
281 | if got := k.RowSize(tt.args.row); got != tt.want {
282 | t.Errorf("RowSize() = %v, want %v", got, tt.want)
283 | }
284 | })
285 | }
286 | }
287 |
288 | func TestKeyboard_RowsCount(t *testing.T) {
289 | tests := []struct {
290 | name string
291 | fields fields
292 | want int
293 | }{
294 | {
295 | name: "OK_3",
296 | fields: fields{[][]Button{btnArray1, btnArray2, btnArray3}},
297 | want: 3,
298 | },
299 | {
300 | name: "OK_2",
301 | fields: fields{[][]Button{btnArray1, btnArray3}},
302 | want: 2,
303 | },
304 | {
305 | name: "OK_0",
306 | fields: fields{[][]Button{}},
307 | want: 0,
308 | },
309 | }
310 | for _, tt := range tests {
311 | t.Run(tt.name, func(t *testing.T) {
312 | k := &Keyboard{
313 | Rows: tt.fields.Rows,
314 | }
315 | if got := k.RowsCount(); got != tt.want {
316 | t.Errorf("RowsCount() = %v, want %v", got, tt.want)
317 | }
318 | })
319 | }
320 | }
321 |
322 | func TestKeyboard_SwapRows(t *testing.T) {
323 | type args struct {
324 | first int
325 | second int
326 | }
327 |
328 | array1 := [][]Button{btnArray1, btnArray2, btnArray3}
329 | array2 := [][]Button{btnArray3, btnArray2, btnArray1}
330 |
331 | tests := []struct {
332 | name string
333 | fields fields
334 | args args
335 | exp fields
336 | wantErr bool
337 | }{
338 | {
339 | name: "OK",
340 | fields: fields{array1},
341 | args: args{0, 2},
342 | exp: fields{array2},
343 | wantErr: false,
344 | },
345 | {
346 | name: "Error",
347 | fields: fields{array1},
348 | args: args{0, 6},
349 | exp: fields{array1},
350 | wantErr: true,
351 | },
352 | }
353 | for _, tt := range tests {
354 | t.Run(tt.name, func(t *testing.T) {
355 | k := &Keyboard{
356 | Rows: tt.fields.Rows,
357 | }
358 | if err := k.SwapRows(tt.args.first, tt.args.second); (err != nil) != tt.wantErr {
359 | t.Errorf("SwapRows() error = %v, wantErr %v", err, tt.wantErr)
360 | }
361 | assert.Equal(t, tt.exp.Rows, k.GetKeyboard())
362 | })
363 | }
364 | }
365 |
--------------------------------------------------------------------------------
/message_easyjson.go:
--------------------------------------------------------------------------------
1 | // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
2 |
3 | package botgolang
4 |
5 | import (
6 | json "encoding/json"
7 | easyjson "github.com/mailru/easyjson"
8 | jlexer "github.com/mailru/easyjson/jlexer"
9 | jwriter "github.com/mailru/easyjson/jwriter"
10 | )
11 |
12 | // suppress unused package warning
13 | var (
14 | _ *json.RawMessage
15 | _ *jlexer.Lexer
16 | _ *jwriter.Writer
17 | _ easyjson.Marshaler
18 | )
19 |
20 | func easyjson4086215fDecodeGithubComMailRuImBotGolang(in *jlexer.Lexer, out *ParentMessage) {
21 | isTopLevel := in.IsStart()
22 | if in.IsNull() {
23 | if isTopLevel {
24 | in.Consumed()
25 | }
26 | in.Skip()
27 | return
28 | }
29 | in.Delim('{')
30 | for !in.IsDelim('}') {
31 | key := in.UnsafeFieldName(false)
32 | in.WantColon()
33 | if in.IsNull() {
34 | in.Skip()
35 | in.WantComma()
36 | continue
37 | }
38 | switch key {
39 | case "chatId":
40 | out.ChatID = string(in.String())
41 | case "messageId":
42 | out.MsgID = int64(in.Int64())
43 | case "type":
44 | out.Type = string(in.String())
45 | default:
46 | in.SkipRecursive()
47 | }
48 | in.WantComma()
49 | }
50 | in.Delim('}')
51 | if isTopLevel {
52 | in.Consumed()
53 | }
54 | }
55 | func easyjson4086215fEncodeGithubComMailRuImBotGolang(out *jwriter.Writer, in ParentMessage) {
56 | out.RawByte('{')
57 | first := true
58 | _ = first
59 | {
60 | const prefix string = ",\"chatId\":"
61 | out.RawString(prefix[1:])
62 | out.String(string(in.ChatID))
63 | }
64 | {
65 | const prefix string = ",\"messageId\":"
66 | out.RawString(prefix)
67 | out.Int64(int64(in.MsgID))
68 | }
69 | {
70 | const prefix string = ",\"type\":"
71 | out.RawString(prefix)
72 | out.String(string(in.Type))
73 | }
74 | out.RawByte('}')
75 | }
76 |
77 | // MarshalJSON supports json.Marshaler interface
78 | func (v ParentMessage) MarshalJSON() ([]byte, error) {
79 | w := jwriter.Writer{}
80 | easyjson4086215fEncodeGithubComMailRuImBotGolang(&w, v)
81 | return w.Buffer.BuildBytes(), w.Error
82 | }
83 |
84 | // MarshalEasyJSON supports easyjson.Marshaler interface
85 | func (v ParentMessage) MarshalEasyJSON(w *jwriter.Writer) {
86 | easyjson4086215fEncodeGithubComMailRuImBotGolang(w, v)
87 | }
88 |
89 | // UnmarshalJSON supports json.Unmarshaler interface
90 | func (v *ParentMessage) UnmarshalJSON(data []byte) error {
91 | r := jlexer.Lexer{Data: data}
92 | easyjson4086215fDecodeGithubComMailRuImBotGolang(&r, v)
93 | return r.Error()
94 | }
95 |
96 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
97 | func (v *ParentMessage) UnmarshalEasyJSON(l *jlexer.Lexer) {
98 | easyjson4086215fDecodeGithubComMailRuImBotGolang(l, v)
99 | }
100 | func easyjson4086215fDecodeGithubComMailRuImBotGolang1(in *jlexer.Lexer, out *Message) {
101 | isTopLevel := in.IsStart()
102 | if in.IsNull() {
103 | if isTopLevel {
104 | in.Consumed()
105 | }
106 | in.Skip()
107 | return
108 | }
109 | in.Delim('{')
110 | for !in.IsDelim('}') {
111 | key := in.UnsafeFieldName(false)
112 | in.WantColon()
113 | if in.IsNull() {
114 | in.Skip()
115 | in.WantComma()
116 | continue
117 | }
118 | switch key {
119 | case "ContentType":
120 | out.ContentType = MessageContentType(in.Uint8())
121 | case "msgId":
122 | out.ID = string(in.String())
123 | case "fileId":
124 | out.FileID = string(in.String())
125 | case "text":
126 | out.Text = string(in.String())
127 | case "chat":
128 | (out.Chat).UnmarshalEasyJSON(in)
129 | case "replyMsgId":
130 | out.ReplyMsgID = string(in.String())
131 | case "forwardMsgId":
132 | out.ForwardMsgID = string(in.String())
133 | case "forwardChatId":
134 | out.ForwardChatID = string(in.String())
135 | case "timestamp":
136 | out.Timestamp = int(in.Int())
137 | case "parent_topic":
138 | if in.IsNull() {
139 | in.Skip()
140 | out.ParentMessage = nil
141 | } else {
142 | if out.ParentMessage == nil {
143 | out.ParentMessage = new(ParentMessage)
144 | }
145 | (*out.ParentMessage).UnmarshalEasyJSON(in)
146 | }
147 | case "inlineKeyboardMarkup":
148 | if in.IsNull() {
149 | in.Skip()
150 | out.InlineKeyboard = nil
151 | } else {
152 | if out.InlineKeyboard == nil {
153 | out.InlineKeyboard = new(Keyboard)
154 | }
155 | easyjson4086215fDecodeGithubComMailRuImBotGolang2(in, out.InlineKeyboard)
156 | }
157 | case "parseMode":
158 | out.ParseMode = ParseMode(in.String())
159 | case "requestID":
160 | out.RequestID = string(in.String())
161 | case "deeplink":
162 | out.Deeplink = string(in.String())
163 | default:
164 | in.SkipRecursive()
165 | }
166 | in.WantComma()
167 | }
168 | in.Delim('}')
169 | if isTopLevel {
170 | in.Consumed()
171 | }
172 | }
173 | func easyjson4086215fEncodeGithubComMailRuImBotGolang1(out *jwriter.Writer, in Message) {
174 | out.RawByte('{')
175 | first := true
176 | _ = first
177 | {
178 | const prefix string = ",\"ContentType\":"
179 | out.RawString(prefix[1:])
180 | out.Uint8(uint8(in.ContentType))
181 | }
182 | {
183 | const prefix string = ",\"msgId\":"
184 | out.RawString(prefix)
185 | out.String(string(in.ID))
186 | }
187 | {
188 | const prefix string = ",\"fileId\":"
189 | out.RawString(prefix)
190 | out.String(string(in.FileID))
191 | }
192 | {
193 | const prefix string = ",\"text\":"
194 | out.RawString(prefix)
195 | out.String(string(in.Text))
196 | }
197 | {
198 | const prefix string = ",\"chat\":"
199 | out.RawString(prefix)
200 | (in.Chat).MarshalEasyJSON(out)
201 | }
202 | {
203 | const prefix string = ",\"replyMsgId\":"
204 | out.RawString(prefix)
205 | out.String(string(in.ReplyMsgID))
206 | }
207 | {
208 | const prefix string = ",\"forwardMsgId\":"
209 | out.RawString(prefix)
210 | out.String(string(in.ForwardMsgID))
211 | }
212 | {
213 | const prefix string = ",\"forwardChatId\":"
214 | out.RawString(prefix)
215 | out.String(string(in.ForwardChatID))
216 | }
217 | {
218 | const prefix string = ",\"timestamp\":"
219 | out.RawString(prefix)
220 | out.Int(int(in.Timestamp))
221 | }
222 | {
223 | const prefix string = ",\"parent_topic\":"
224 | out.RawString(prefix)
225 | if in.ParentMessage == nil {
226 | out.RawString("null")
227 | } else {
228 | (*in.ParentMessage).MarshalEasyJSON(out)
229 | }
230 | }
231 | {
232 | const prefix string = ",\"inlineKeyboardMarkup\":"
233 | out.RawString(prefix)
234 | if in.InlineKeyboard == nil {
235 | out.RawString("null")
236 | } else {
237 | easyjson4086215fEncodeGithubComMailRuImBotGolang2(out, *in.InlineKeyboard)
238 | }
239 | }
240 | {
241 | const prefix string = ",\"parseMode\":"
242 | out.RawString(prefix)
243 | out.String(string(in.ParseMode))
244 | }
245 | {
246 | const prefix string = ",\"requestID\":"
247 | out.RawString(prefix)
248 | out.String(string(in.RequestID))
249 | }
250 | {
251 | const prefix string = ",\"deeplink\":"
252 | out.RawString(prefix)
253 | out.String(string(in.Deeplink))
254 | }
255 | out.RawByte('}')
256 | }
257 |
258 | // MarshalJSON supports json.Marshaler interface
259 | func (v Message) MarshalJSON() ([]byte, error) {
260 | w := jwriter.Writer{}
261 | easyjson4086215fEncodeGithubComMailRuImBotGolang1(&w, v)
262 | return w.Buffer.BuildBytes(), w.Error
263 | }
264 |
265 | // MarshalEasyJSON supports easyjson.Marshaler interface
266 | func (v Message) MarshalEasyJSON(w *jwriter.Writer) {
267 | easyjson4086215fEncodeGithubComMailRuImBotGolang1(w, v)
268 | }
269 |
270 | // UnmarshalJSON supports json.Unmarshaler interface
271 | func (v *Message) UnmarshalJSON(data []byte) error {
272 | r := jlexer.Lexer{Data: data}
273 | easyjson4086215fDecodeGithubComMailRuImBotGolang1(&r, v)
274 | return r.Error()
275 | }
276 |
277 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
278 | func (v *Message) UnmarshalEasyJSON(l *jlexer.Lexer) {
279 | easyjson4086215fDecodeGithubComMailRuImBotGolang1(l, v)
280 | }
281 | func easyjson4086215fDecodeGithubComMailRuImBotGolang2(in *jlexer.Lexer, out *Keyboard) {
282 | isTopLevel := in.IsStart()
283 | if in.IsNull() {
284 | if isTopLevel {
285 | in.Consumed()
286 | }
287 | in.Skip()
288 | return
289 | }
290 | in.Delim('{')
291 | for !in.IsDelim('}') {
292 | key := in.UnsafeFieldName(false)
293 | in.WantColon()
294 | if in.IsNull() {
295 | in.Skip()
296 | in.WantComma()
297 | continue
298 | }
299 | switch key {
300 | case "Rows":
301 | if in.IsNull() {
302 | in.Skip()
303 | out.Rows = nil
304 | } else {
305 | in.Delim('[')
306 | if out.Rows == nil {
307 | if !in.IsDelim(']') {
308 | out.Rows = make([][]Button, 0, 2)
309 | } else {
310 | out.Rows = [][]Button{}
311 | }
312 | } else {
313 | out.Rows = (out.Rows)[:0]
314 | }
315 | for !in.IsDelim(']') {
316 | var v1 []Button
317 | if in.IsNull() {
318 | in.Skip()
319 | v1 = nil
320 | } else {
321 | in.Delim('[')
322 | if v1 == nil {
323 | if !in.IsDelim(']') {
324 | v1 = make([]Button, 0, 1)
325 | } else {
326 | v1 = []Button{}
327 | }
328 | } else {
329 | v1 = (v1)[:0]
330 | }
331 | for !in.IsDelim(']') {
332 | var v2 Button
333 | (v2).UnmarshalEasyJSON(in)
334 | v1 = append(v1, v2)
335 | in.WantComma()
336 | }
337 | in.Delim(']')
338 | }
339 | out.Rows = append(out.Rows, v1)
340 | in.WantComma()
341 | }
342 | in.Delim(']')
343 | }
344 | default:
345 | in.SkipRecursive()
346 | }
347 | in.WantComma()
348 | }
349 | in.Delim('}')
350 | if isTopLevel {
351 | in.Consumed()
352 | }
353 | }
354 | func easyjson4086215fEncodeGithubComMailRuImBotGolang2(out *jwriter.Writer, in Keyboard) {
355 | out.RawByte('{')
356 | first := true
357 | _ = first
358 | {
359 | const prefix string = ",\"Rows\":"
360 | out.RawString(prefix[1:])
361 | if in.Rows == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
362 | out.RawString("null")
363 | } else {
364 | out.RawByte('[')
365 | for v3, v4 := range in.Rows {
366 | if v3 > 0 {
367 | out.RawByte(',')
368 | }
369 | if v4 == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
370 | out.RawString("null")
371 | } else {
372 | out.RawByte('[')
373 | for v5, v6 := range v4 {
374 | if v5 > 0 {
375 | out.RawByte(',')
376 | }
377 | (v6).MarshalEasyJSON(out)
378 | }
379 | out.RawByte(']')
380 | }
381 | }
382 | out.RawByte(']')
383 | }
384 | }
385 | out.RawByte('}')
386 | }
387 |
--------------------------------------------------------------------------------
/bot.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | /*
4 | 💥 botgolang is zero-configuration library with convenient interface.
5 | Crafted with love in @mail for your awesome bots.
6 | */
7 |
8 | import (
9 | "context"
10 | "fmt"
11 | "net/http"
12 | "os"
13 |
14 | "github.com/sirupsen/logrus"
15 | )
16 |
17 | const (
18 | defaultAPIURL = "https://api.icq.net/bot/v1"
19 | defaultDebug = false
20 | )
21 |
22 | // Bot is the main structure for interaction with API.
23 | // All fields are private, you can configure bot using config arguments in NewBot func.
24 | type Bot struct {
25 | client *Client
26 | updater *Updater
27 | logger *logrus.Logger
28 | Info *BotInfo
29 | }
30 |
31 | // AutosubscribeToThreads toggles thread auto-subscription behaviour for the specified chat.
32 | // enable – turn the feature on/off.
33 | // withExisting – if true, the bot will also subscribe to already existing threads.
34 | func (b *Bot) AutosubscribeToThreads(chatID string, enable, withExisting bool) error {
35 | return b.client.AutosubscribeToThreads(chatID, enable, withExisting)
36 | }
37 |
38 | // AddThread adds a new thread to the specified chat and returns the thread ID.
39 | func (b *Bot) AddThread(chatID, msgID string) (*Thread, error) {
40 | return b.client.AddThread(chatID, msgID)
41 | }
42 |
43 | // GetThreadSubscribers gets the subscribers list for a thread.
44 | // Either cursor or pageSize must be provided.
45 | func (b *Bot) GetThreadSubscribers(threadID string, cursor string, pageSize int) (*ThreadSubscribers, error) {
46 | return b.client.GetThreadSubscribers(threadID, cursor, pageSize)
47 | }
48 |
49 | // GetInfo returns information about bot:
50 | // id, name, about, avatar
51 | func (b *Bot) GetInfo() (*BotInfo, error) {
52 | return b.client.GetInfo()
53 | }
54 |
55 | // GetChatInfo returns information about chat:
56 | // id, type, title, public, group, inviteLink, admins
57 | func (b *Bot) GetChatInfo(chatID string) (*Chat, error) {
58 | return b.client.GetChatInfo(chatID)
59 | }
60 |
61 | // SendChatActions sends an actions like "typing, looking"
62 | func (b *Bot) SendChatActions(chatID string, actions ...ChatAction) error {
63 | return b.client.SendChatActions(chatID, actions...)
64 | }
65 |
66 | // GetChatAdmins returns chat admins list with fields:
67 | // userID, creator flag
68 | func (b *Bot) GetChatAdmins(chatID string) ([]ChatMember, error) {
69 | return b.client.GetChatAdmins(chatID)
70 | }
71 |
72 | // GetChatMem returns chat members list with fields:
73 | // userID, creator flag, admin flag
74 | func (b *Bot) GetChatMembers(chatID string) ([]ChatMember, error) {
75 | return b.client.GetChatMembers(chatID)
76 | }
77 |
78 | // GetChatBlockedUsers returns chat blocked users list:
79 | // userID
80 | func (b *Bot) GetChatBlockedUsers(chatID string) ([]User, error) {
81 | return b.client.GetChatBlockedUsers(chatID)
82 | }
83 |
84 | // GetChatPendingUsers returns chat join pending users list:
85 | // userID
86 | func (b *Bot) GetChatPendingUsers(chatID string) ([]User, error) {
87 | return b.client.GetChatPendingUsers(chatID)
88 | }
89 |
90 | // BlockChatUser blocks user and removes him from chat.
91 | // If deleteLastMessages is true, the messages written recently will be deleted
92 | func (b *Bot) BlockChatUser(chatID, userID string, deleteLastMessages bool) error {
93 | return b.client.BlockChatUser(chatID, userID, deleteLastMessages)
94 | }
95 |
96 | // UnblockChatUser unblocks user in chat
97 | func (b *Bot) UnblockChatUser(chatID, userID string) error {
98 | return b.client.UnblockChatUser(chatID, userID)
99 | }
100 |
101 | // DeleteChatMembers removes multiple members from chat
102 | func (b *Bot) DeleteChatMembers(chatID string, members []string) error {
103 | return b.client.DeleteChatMembers(chatID, members)
104 | }
105 |
106 | // AddChatMembers adds multiple members to chat
107 | func (b *Bot) AddChatMembers(chatID string, members []string) error {
108 | return b.client.AddChatMembers(chatID, members)
109 | }
110 |
111 | // ResolveChatJoinRequests resolves pending join requests for specified user or all pending users
112 | func (b *Bot) ResolveChatJoinRequests(chatID, userID string, accept, everyone bool) error {
113 | return b.client.ResolveChatPending(chatID, userID, accept, everyone)
114 | }
115 |
116 | // SetChatTitle changes chat title
117 | func (b *Bot) SetChatTitle(chatID, title string) error {
118 | return b.client.SetChatTitle(chatID, title)
119 | }
120 |
121 | // SetChatAbout changes chat about
122 | func (b *Bot) SetChatAbout(chatID, about string) error {
123 | return b.client.SetChatAbout(chatID, about)
124 | }
125 |
126 | // SetChatRules changes chat rules
127 | func (b *Bot) SetChatRules(chatID, rules string) error {
128 | return b.client.SetChatRules(chatID, rules)
129 | }
130 |
131 | // GetFileInfo returns information about file:
132 | // id, type, size, filename, url
133 | func (b *Bot) GetFileInfo(fileID string) (*File, error) {
134 | return b.client.GetFileInfo(fileID)
135 | }
136 |
137 | // NewMessage returns new message
138 | func (b *Bot) NewMessage(chatID string) *Message {
139 | return &Message{
140 | client: b.client,
141 | Chat: Chat{ID: chatID},
142 | }
143 | }
144 |
145 | // NewTextMessage returns new text message
146 | func (b *Bot) NewTextMessage(chatID, text string) *Message {
147 | return &Message{
148 | client: b.client,
149 | Chat: Chat{ID: chatID},
150 | Text: text,
151 | ContentType: Text,
152 | }
153 | }
154 |
155 | // NewTextMessageWithRequestID returns new text message with client requestID
156 | func (b *Bot) NewTextMessageWithRequestID(chatID, text, requestID string) *Message {
157 | return &Message{
158 | client: b.client,
159 | Chat: Chat{ID: chatID},
160 | Text: text,
161 | ContentType: Text,
162 | RequestID: requestID,
163 | }
164 | }
165 |
166 | // NewInlineKeyboardMessage returns new text message with inline keyboard
167 | func (b *Bot) NewInlineKeyboardMessage(chatID, text string, keyboard Keyboard) *Message {
168 | return &Message{
169 | client: b.client,
170 | Chat: Chat{ID: chatID},
171 | Text: text,
172 | ContentType: Text,
173 | InlineKeyboard: &keyboard,
174 | }
175 | }
176 |
177 | // NewDeeplinkMessage returns new text message with inline keyboard and deeplink
178 | func (b *Bot) NewDeeplinkMessage(chatID, text string, keyboard Keyboard, deeplink string) *Message {
179 | return &Message{
180 | client: b.client,
181 | Chat: Chat{ID: chatID},
182 | Text: text,
183 | ContentType: Deeplink,
184 | InlineKeyboard: &keyboard,
185 | Deeplink: deeplink,
186 | }
187 | }
188 |
189 | // NewFileMessage returns new file message
190 | func (b *Bot) NewFileMessage(chatID string, file *os.File) *Message {
191 | return &Message{
192 | client: b.client,
193 | Chat: Chat{ID: chatID},
194 | File: file,
195 | ContentType: OtherFile,
196 | }
197 | }
198 |
199 | // NewFileMessageByFileID returns new message with previously uploaded file id
200 | func (b *Bot) NewFileMessageByFileID(chatID, fileID string) *Message {
201 | return &Message{
202 | client: b.client,
203 | Chat: Chat{ID: chatID},
204 | FileID: fileID,
205 | ContentType: OtherFile,
206 | }
207 | }
208 |
209 | // NewVoiceMessage returns new voice message
210 | func (b *Bot) NewVoiceMessage(chatID string, file *os.File) *Message {
211 | return &Message{
212 | client: b.client,
213 | Chat: Chat{ID: chatID},
214 | File: file,
215 | ContentType: Voice,
216 | }
217 | }
218 |
219 | // NewVoiceMessageByFileID returns new message with previously uploaded voice file id
220 | func (b *Bot) NewVoiceMessageByFileID(chatID, fileID string) *Message {
221 | return &Message{
222 | client: b.client,
223 | Chat: Chat{ID: chatID},
224 | FileID: fileID,
225 | ContentType: Voice,
226 | }
227 | }
228 |
229 | // NewMessageFromPart returns new message based on part message
230 | func (b *Bot) NewMessageFromPart(message PartMessage) *Message {
231 | return &Message{
232 | client: b.client,
233 | ID: message.MsgID,
234 | Chat: Chat{ID: message.From.User.ID, Title: message.From.FirstName},
235 | Text: message.Text,
236 | Timestamp: message.Timestamp,
237 | }
238 | }
239 |
240 | // NewButtonResponse returns new ButtonResponse
241 | func (b *Bot) NewButtonResponse(queryID, url, text string, showAlert bool) *ButtonResponse {
242 | return &ButtonResponse{
243 | client: b.client,
244 | QueryID: queryID,
245 | Text: text,
246 | URL: url,
247 | ShowAlert: showAlert,
248 | }
249 | }
250 |
251 | func (b *Bot) NewChat(id string) *Chat {
252 | return &Chat{
253 | client: b.client,
254 | ID: id,
255 | }
256 | }
257 |
258 | // SendMessage sends a message, passed as an argument.
259 | // This method fills the argument with ID of sent message and returns an error if any.
260 | func (b *Bot) SendMessage(message *Message) error {
261 | message.client = b.client
262 | return message.Send()
263 | }
264 |
265 | // EditMessage edit a message passed as an argument.
266 | func (b *Bot) EditMessage(message *Message) error {
267 | return b.client.EditMessage(message)
268 | }
269 |
270 | // GetUpdatesChannel returns a channel, which will be filled with events.
271 | // You can pass cancellable context there and stop receiving events.
272 | // The channel will be closed after context cancellation.
273 | func (b *Bot) GetUpdatesChannel(ctx context.Context) <-chan Event {
274 | updates := make(chan Event)
275 |
276 | go b.updater.RunUpdatesCheck(ctx, updates)
277 |
278 | return updates
279 | }
280 |
281 | // NewBot returns new bot object.
282 | // All communications with bot API must go through Bot struct.
283 | // In general you don't need to configure this bot, therefore all options are optional arguments.
284 | func NewBot(token string, opts ...BotOption) (*Bot, error) {
285 | logger := logrus.New()
286 | logger.SetFormatter(&logrus.TextFormatter{
287 | FullTimestamp: true,
288 | TimestampFormat: "2006-01-02 15:04:05",
289 | })
290 |
291 | apiURL := defaultAPIURL
292 | debug := defaultDebug
293 | client := *http.DefaultClient
294 | for _, option := range opts {
295 | switch option.Type() {
296 | case "api_url":
297 | apiURL = option.Value().(string)
298 | case "debug":
299 | debug = option.Value().(bool)
300 | case "http_client":
301 | client = option.Value().(http.Client)
302 | }
303 | }
304 |
305 | if debug {
306 | logger.SetLevel(logrus.DebugLevel)
307 | }
308 |
309 | tgClient := NewCustomClient(&client, apiURL, token, logger)
310 | updater := NewUpdater(tgClient, 0, logger)
311 |
312 | info, err := tgClient.GetInfo()
313 | if err != nil {
314 | return nil, fmt.Errorf("cannot get info about bot: %s", err)
315 | }
316 |
317 | return &Bot{
318 | client: tgClient,
319 | updater: updater,
320 | logger: logger,
321 | Info: info,
322 | }, nil
323 | }
324 |
--------------------------------------------------------------------------------
/client.go:
--------------------------------------------------------------------------------
1 | package botgolang
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "encoding/json"
7 | "fmt"
8 | "io"
9 | "mime/multipart"
10 | "net/http"
11 | "net/url"
12 | "os"
13 | "strconv"
14 |
15 | "github.com/sirupsen/logrus"
16 | )
17 |
18 | type Client struct {
19 | client *http.Client
20 | token string
21 | baseURL string
22 | logger *logrus.Logger
23 | }
24 |
25 | func (c *Client) Do(path string, params url.Values, file *os.File) ([]byte, error) {
26 | return c.DoWithContext(context.Background(), path, params, file)
27 | }
28 |
29 | func (c *Client) DoWithContext(ctx context.Context, path string, params url.Values, file *os.File) ([]byte, error) {
30 | apiURL, err := url.Parse(c.baseURL + path)
31 | params.Set("token", c.token)
32 |
33 | if err != nil {
34 | return nil, fmt.Errorf("cannot parse url: %s", err)
35 | }
36 |
37 | apiURL.RawQuery = params.Encode()
38 | req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL.String(), nil)
39 | if err != nil || req == nil {
40 | return nil, fmt.Errorf("cannot init http request: %s", err)
41 | }
42 |
43 | if file != nil {
44 | buffer := &bytes.Buffer{}
45 | multipartWriter := multipart.NewWriter(buffer)
46 |
47 | fileWriter, err := multipartWriter.CreateFormFile("file", file.Name())
48 | if err != nil {
49 | return nil, fmt.Errorf("cannot create multipart writer: %s", err)
50 | }
51 |
52 | _, err = io.Copy(fileWriter, file)
53 | if err != nil {
54 | return nil, fmt.Errorf("cannot copy file into buffer: %s", err)
55 | }
56 |
57 | if err := multipartWriter.Close(); err != nil {
58 | return nil, fmt.Errorf("cannot close multipartWriter: %s", err)
59 | }
60 |
61 | req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
62 | req.Body = io.NopCloser(buffer)
63 | req.Method = http.MethodPost
64 | }
65 |
66 | c.logger.WithFields(logrus.Fields{
67 | "api_url": apiURL,
68 | }).Debug("requesting api")
69 |
70 | resp, err := c.client.Do(req)
71 | if err != nil {
72 | c.logger.WithFields(logrus.Fields{
73 | "err": err,
74 | }).Error("request error")
75 | return []byte{}, fmt.Errorf("cannot make request to bot api: %s", err)
76 | }
77 |
78 | defer func() {
79 | if err := resp.Body.Close(); err != nil {
80 | c.logger.WithFields(logrus.Fields{
81 | "err": err,
82 | }).Error("cannot close body")
83 | }
84 | }()
85 |
86 | responseBody, err := io.ReadAll(resp.Body)
87 | if err != nil {
88 | c.logger.WithFields(logrus.Fields{
89 | "err": err,
90 | }).Error("cannot read body")
91 | return []byte{}, fmt.Errorf("cannot read body: %s", err)
92 | }
93 |
94 | if c.logger.IsLevelEnabled(logrus.DebugLevel) {
95 | c.logger.WithFields(logrus.Fields{
96 | "response": responseBody,
97 | }).Debug("got response from API")
98 | }
99 |
100 | if resp.StatusCode != http.StatusOK {
101 | return nil, fmt.Errorf("error status from API: %s", resp.Status)
102 | }
103 |
104 | response := &Response{}
105 |
106 | if err := json.Unmarshal(responseBody, response); err != nil {
107 | return nil, fmt.Errorf("cannot unmarshal json: %s", err)
108 | }
109 |
110 | if !response.OK {
111 | return responseBody, fmt.Errorf("error status from API: %s", response.Description)
112 | }
113 |
114 | return responseBody, nil
115 | }
116 |
117 | func (c *Client) AutosubscribeToThreads(chatID string, enable, withExisting bool) error {
118 | if chatID == "" {
119 | return fmt.Errorf("chatID cannot be empty")
120 | }
121 |
122 | params := url.Values{
123 | "chatId": {chatID},
124 | "enable": {strconv.FormatBool(enable)},
125 | "withExisting": {strconv.FormatBool(withExisting)},
126 | }
127 |
128 | if _, err := c.Do("/threads/autosubscribe", params, nil); err != nil {
129 | return fmt.Errorf("error while requesting threads autosubscribe: %w", err)
130 | }
131 |
132 | return nil
133 | }
134 |
135 | func (c *Client) AddThread(chatID, msgID string) (*Thread, error) {
136 | if chatID == "" {
137 | return nil, fmt.Errorf("chatID cannot be empty")
138 | }
139 | if msgID == "" {
140 | return nil, fmt.Errorf("msgID cannot be empty")
141 | }
142 |
143 | params := url.Values{
144 | "chatId": {chatID},
145 | "msgId": {msgID},
146 | }
147 |
148 | response, err := c.Do("/threads/add", params, nil)
149 | if err != nil {
150 | return nil, fmt.Errorf("error while adding thread: %w", err)
151 | }
152 |
153 | thread := &Thread{}
154 | if err := json.Unmarshal(response, thread); err != nil {
155 | return nil, fmt.Errorf("error while unmarshalling thread response: %w", err)
156 | }
157 |
158 | return thread, nil
159 | }
160 |
161 | func (c *Client) GetThreadSubscribers(threadID string, cursor string, pageSize int) (*ThreadSubscribers, error) {
162 | if threadID == "" {
163 | return nil, fmt.Errorf("threadID cannot be empty")
164 | }
165 |
166 | params := url.Values{
167 | "threadId": {threadID},
168 | }
169 |
170 | if cursor != "" {
171 | params.Set("cursor", cursor)
172 | }
173 | if pageSize > 0 {
174 | params.Set("pageSize", strconv.Itoa(pageSize))
175 | }
176 |
177 | response, err := c.Do("/threads/subscribers/get", params, nil)
178 | if err != nil {
179 | return nil, fmt.Errorf("error while getting thread subscribers: %w", err)
180 | }
181 |
182 | threadSubscribers := &ThreadSubscribers{}
183 | if err := json.Unmarshal(response, threadSubscribers); err != nil {
184 | return nil, fmt.Errorf("error while unmarshalling thread subscribers response: %w", err)
185 | }
186 |
187 | return threadSubscribers, nil
188 | }
189 |
190 | func (c *Client) GetInfo() (*BotInfo, error) {
191 | response, err := c.Do("/self/get", url.Values{}, nil)
192 | if err != nil {
193 | return nil, fmt.Errorf("error while receiving information: %s", err)
194 | }
195 |
196 | info := &BotInfo{}
197 | if err := json.Unmarshal(response, info); err != nil {
198 | return nil, fmt.Errorf("error while unmarshalling information: %s", err)
199 | }
200 |
201 | return info, nil
202 | }
203 |
204 | func (c *Client) GetChatInfo(chatID string) (*Chat, error) {
205 | if chatID == "" {
206 | return nil, fmt.Errorf("chatID cannot be empty")
207 | }
208 |
209 | params := url.Values{
210 | "chatId": {chatID},
211 | }
212 | response, err := c.Do("/chats/getInfo", params, nil)
213 | if err != nil {
214 | return nil, fmt.Errorf("error while receiving information: %s", err)
215 | }
216 |
217 | chat := &Chat{
218 | client: c,
219 | ID: chatID,
220 | }
221 | if err := json.Unmarshal(response, chat); err != nil {
222 | return nil, fmt.Errorf("error while unmarshalling information: %s", err)
223 | }
224 |
225 | if chat.Type == Private {
226 | return chat, nil
227 | }
228 | return chat, nil
229 | }
230 |
231 | func (c *Client) SendChatActions(chatID string, actions ...ChatAction) error {
232 | if chatID == "" {
233 | return fmt.Errorf("chatID cannot be empty")
234 | }
235 | if len(actions) == 0 {
236 | return fmt.Errorf("actions cannot be empty")
237 | }
238 |
239 | actionsMap := make(map[ChatAction]bool)
240 | filteredActions := make([]ChatAction, 0)
241 | for _, action := range actions {
242 | if _, has := actionsMap[action]; !has {
243 | filteredActions = append(filteredActions, action)
244 | actionsMap[action] = true
245 | }
246 | }
247 | params := url.Values{
248 | "chatId": {chatID},
249 | "actions": filteredActions,
250 | }
251 | _, err := c.Do("/chats/sendActions", params, nil)
252 | if err != nil {
253 | return fmt.Errorf("error while receiving information: %s", err)
254 | }
255 | return nil
256 | }
257 |
258 | func (c *Client) GetChatAdmins(chatID string) ([]ChatMember, error) {
259 | if chatID == "" {
260 | return nil, fmt.Errorf("chatID cannot be empty")
261 | }
262 |
263 | params := url.Values{
264 | "chatId": {chatID},
265 | }
266 |
267 | response, err := c.Do("/chats/getAdmins", params, nil)
268 | if err != nil {
269 | return nil, fmt.Errorf("error while receiving admins: %s", err)
270 | }
271 |
272 | admins := new(AdminsListResponse)
273 | if err := json.Unmarshal(response, admins); err != nil {
274 | return nil, fmt.Errorf("error while unmarshalling admins: %s", err)
275 | }
276 | return admins.List, nil
277 | }
278 |
279 | func (c *Client) GetChatMembers(chatID string) ([]ChatMember, error) {
280 | if chatID == "" {
281 | return nil, fmt.Errorf("chatID cannot be empty")
282 | }
283 |
284 | params := url.Values{
285 | "chatId": {chatID},
286 | }
287 |
288 | response, err := c.Do("/chats/getMembers", params, nil)
289 | if err != nil {
290 | return nil, fmt.Errorf("error while receiving members: %s", err)
291 | }
292 |
293 | members := new(MembersListResponse)
294 | if err := json.Unmarshal(response, members); err != nil {
295 | return nil, fmt.Errorf("error while unmarshalling members: %s", err)
296 | }
297 | return members.List, nil
298 | }
299 |
300 | func (c *Client) GetChatBlockedUsers(chatID string) ([]User, error) {
301 | if chatID == "" {
302 | return nil, fmt.Errorf("chatID cannot be empty")
303 | }
304 |
305 | params := url.Values{
306 | "chatId": {chatID},
307 | }
308 |
309 | response, err := c.Do("/chats/getBlockedUsers", params, nil)
310 | if err != nil {
311 | return nil, fmt.Errorf("error while receiving blocked users: %s", err)
312 | }
313 |
314 | users := new(UsersListResponse)
315 | if err := json.Unmarshal(response, users); err != nil {
316 | return nil, fmt.Errorf("error while unmarshalling blocked users: %s", err)
317 | }
318 | return users.List, nil
319 | }
320 |
321 | func (c *Client) GetChatPendingUsers(chatID string) ([]User, error) {
322 | if chatID == "" {
323 | return nil, fmt.Errorf("chatID cannot be empty")
324 | }
325 |
326 | params := url.Values{
327 | "chatId": {chatID},
328 | }
329 |
330 | response, err := c.Do("/chats/getPendingUsers", params, nil)
331 | if err != nil {
332 | return nil, fmt.Errorf("error while receiving pending users: %s", err)
333 | }
334 |
335 | users := new(UsersListResponse)
336 | if err := json.Unmarshal(response, users); err != nil {
337 | return nil, fmt.Errorf("error while unmarshalling pending users: %s", err)
338 | }
339 | return users.List, nil
340 | }
341 |
342 | func (c *Client) BlockChatUser(chatID, userID string, deleteLastMessages bool) error {
343 | if chatID == "" {
344 | return fmt.Errorf("chatID cannot be empty")
345 | }
346 | if userID == "" {
347 | return fmt.Errorf("userID cannot be empty")
348 | }
349 |
350 | params := url.Values{
351 | "chatId": {chatID},
352 | "userId": {userID},
353 | "delLastMessages": {strconv.FormatBool(deleteLastMessages)},
354 | }
355 |
356 | response, err := c.Do("/chats/blockUser", params, nil)
357 | if err != nil {
358 | return fmt.Errorf("error while blocking user: %s", err)
359 | }
360 |
361 | users := new(UsersListResponse)
362 | if err := json.Unmarshal(response, users); err != nil {
363 | return fmt.Errorf("error while blocking user: %s", err)
364 | }
365 | return nil
366 | }
367 |
368 | func (c *Client) UnblockChatUser(chatID, userID string) error {
369 | if chatID == "" {
370 | return fmt.Errorf("chatID cannot be empty")
371 | }
372 | if userID == "" {
373 | return fmt.Errorf("userID cannot be empty")
374 | }
375 |
376 | params := url.Values{
377 | "chatId": {chatID},
378 | "userId": {userID},
379 | }
380 |
381 | response, err := c.Do("/chats/unblockUser", params, nil)
382 | if err != nil {
383 | return fmt.Errorf("error while unblocking user: %s", err)
384 | }
385 |
386 | users := new(UsersListResponse)
387 | if err := json.Unmarshal(response, users); err != nil {
388 | return fmt.Errorf("error while unblocking user: %s", err)
389 | }
390 | return nil
391 | }
392 |
393 | func (c *Client) ResolveChatPending(chatID, userID string, approve, everyone bool) error {
394 | if chatID == "" {
395 | return fmt.Errorf("chatID cannot be empty")
396 | }
397 |
398 | params := url.Values{
399 | "chatId": {chatID},
400 | "approve": {strconv.FormatBool(approve)},
401 | }
402 | if everyone {
403 | params.Set("everyone", "true")
404 | } else {
405 | params.Set("userId", userID)
406 | }
407 |
408 | if _, err := c.Do("/chats/resolvePending", params, nil); err != nil {
409 | return fmt.Errorf("error while resolving chat pendings: %s", err)
410 | }
411 | return nil
412 | }
413 |
414 | func (c *Client) DeleteChatMembers(chatID string, members []string) error {
415 | if chatID == "" {
416 | return fmt.Errorf("chatID cannot be empty")
417 | }
418 | if len(members) == 0 {
419 | return fmt.Errorf("members list cannot be empty")
420 | }
421 |
422 | membersList := make([]map[string]string, len(members))
423 | for i, member := range members {
424 | membersList[i] = map[string]string{"sn": member}
425 | }
426 |
427 | membersJSON, err := json.Marshal(membersList)
428 | if err != nil {
429 | return fmt.Errorf("error while marshalling members list: %s", err)
430 | }
431 |
432 | params := url.Values{
433 | "chatId": {chatID},
434 | "members": {string(membersJSON)},
435 | }
436 |
437 | if _, err := c.Do("/chats/members/delete", params, nil); err != nil {
438 | return fmt.Errorf("error while deleting chat members: %s", err)
439 | }
440 | return nil
441 | }
442 |
443 | func (c *Client) AddChatMembers(chatID string, members []string) error {
444 | if chatID == "" {
445 | return fmt.Errorf("chatID cannot be empty")
446 | }
447 | if len(members) == 0 {
448 | return fmt.Errorf("members list cannot be empty")
449 | }
450 |
451 | membersList := make([]map[string]string, len(members))
452 | for i, member := range members {
453 | membersList[i] = map[string]string{"sn": member}
454 | }
455 |
456 | membersJSON, err := json.Marshal(membersList)
457 | if err != nil {
458 | return fmt.Errorf("error while marshalling members list: %s", err)
459 | }
460 |
461 | params := url.Values{
462 | "chatId": {chatID},
463 | "members": {string(membersJSON)},
464 | }
465 |
466 | if _, err := c.Do("/chats/members/add", params, nil); err != nil {
467 | return fmt.Errorf("error while adding chat members: %s", err)
468 | }
469 | return nil
470 | }
471 |
472 | func (c *Client) SetChatTitle(chatID, title string) error {
473 | if chatID == "" {
474 | return fmt.Errorf("chatID cannot be empty")
475 | }
476 | if title == "" {
477 | return fmt.Errorf("title cannot be empty")
478 | }
479 |
480 | params := url.Values{
481 | "chatId": {chatID},
482 | "title": {title},
483 | }
484 |
485 | if _, err := c.Do("/chats/setTitle", params, nil); err != nil {
486 | return fmt.Errorf("error while setting chat title: %s", err)
487 | }
488 | return nil
489 | }
490 |
491 | func (c *Client) SetChatAbout(chatID, about string) error {
492 | if chatID == "" {
493 | return fmt.Errorf("chatID cannot be empty")
494 | }
495 |
496 | params := url.Values{
497 | "chatId": {chatID},
498 | "about": {about},
499 | }
500 |
501 | if _, err := c.Do("/chats/setAbout", params, nil); err != nil {
502 | return fmt.Errorf("error while setting chat about: %s", err)
503 | }
504 | return nil
505 | }
506 |
507 | func (c *Client) SetChatRules(chatID, rules string) error {
508 | if chatID == "" {
509 | return fmt.Errorf("chatID cannot be empty")
510 | }
511 |
512 | params := url.Values{
513 | "chatId": {chatID},
514 | "rules": {rules},
515 | }
516 |
517 | if _, err := c.Do("/chats/setRules", params, nil); err != nil {
518 | return fmt.Errorf("error while setting chat rules: %s", err)
519 | }
520 | return nil
521 | }
522 |
523 | func (c *Client) GetFileInfo(fileID string) (*File, error) {
524 | if fileID == "" {
525 | return nil, fmt.Errorf("fileID cannot be empty")
526 | }
527 |
528 | params := url.Values{
529 | "fileId": {fileID},
530 | }
531 | response, err := c.Do("/files/getInfo", params, nil)
532 | if err != nil {
533 | return nil, fmt.Errorf("error while receiving information: %s", err)
534 | }
535 |
536 | file := &File{}
537 | if err := json.Unmarshal(response, file); err != nil {
538 | return nil, fmt.Errorf("error while unmarshalling information: %s", err)
539 | }
540 |
541 | return file, nil
542 | }
543 |
544 | func (c *Client) GetVoiceInfo(fileID string) (*File, error) {
545 | return c.GetFileInfo(fileID)
546 | }
547 |
548 | func (c *Client) SendTextMessage(message *Message) error {
549 | if message == nil {
550 | return fmt.Errorf("message cannot be nil")
551 | }
552 | if message.Chat.ID == "" {
553 | return fmt.Errorf("chatID cannot be empty")
554 | }
555 | if message.Text == "" {
556 | return fmt.Errorf("text cannot be empty")
557 | }
558 |
559 | params := url.Values{
560 | "chatId": {message.Chat.ID},
561 | "text": {message.Text},
562 | "request-id": {message.RequestID},
563 | }
564 |
565 | if message.ReplyMsgID != "" {
566 | params.Set("replyMsgId", message.ReplyMsgID)
567 | }
568 |
569 | if message.ForwardMsgID != "" {
570 | params.Set("forwardMsgId", message.ForwardMsgID)
571 | params.Set("forwardChatId", message.ForwardChatID)
572 | }
573 |
574 | if message.InlineKeyboard != nil {
575 | data, err := json.Marshal(message.InlineKeyboard.GetKeyboard())
576 | if err != nil {
577 | return fmt.Errorf("cannot marshal inline keyboard markup: %s", err)
578 | }
579 |
580 | params.Set("inlineKeyboardMarkup", string(data))
581 | }
582 |
583 | if message.ParseMode != "" {
584 | params.Set("parseMode", string(message.ParseMode))
585 | }
586 |
587 | response, err := c.Do("/messages/sendText", params, nil)
588 | if err != nil {
589 | return fmt.Errorf("error while sending text: %s", err)
590 | }
591 |
592 | if err := json.Unmarshal(response, message); err != nil {
593 | return fmt.Errorf("cannot unmarshal response from API: %s", err)
594 | }
595 |
596 | return nil
597 | }
598 |
599 | func (c *Client) SendTextWithDeeplinkMessage(message *Message) error {
600 | if message == nil {
601 | return fmt.Errorf("message cannot be nil")
602 | }
603 | if message.Chat.ID == "" {
604 | return fmt.Errorf("chatID cannot be empty")
605 | }
606 | if message.Text == "" {
607 | return fmt.Errorf("text cannot be empty")
608 | }
609 |
610 | params := url.Values{
611 | "chatId": {message.Chat.ID},
612 | "text": {message.Text},
613 | "request-id": {message.RequestID},
614 | }
615 |
616 | if message.ReplyMsgID != "" {
617 | params.Set("replyMsgId", message.ReplyMsgID)
618 | }
619 |
620 | if message.ForwardMsgID != "" {
621 | params.Set("forwardMsgId", message.ForwardMsgID)
622 | params.Set("forwardChatId", message.ForwardChatID)
623 | }
624 |
625 | if message.InlineKeyboard != nil {
626 | data, err := json.Marshal(message.InlineKeyboard.GetKeyboard())
627 | if err != nil {
628 | return fmt.Errorf("cannot marshal inline keyboard markup: %s", err)
629 | }
630 |
631 | params.Set("inlineKeyboardMarkup", string(data))
632 | }
633 |
634 | if len(message.Deeplink) == 0 {
635 | return fmt.Errorf("deeplink can't be empty for SendTextWithDeeplink")
636 | }
637 | params.Set("deeplink", message.Deeplink)
638 |
639 | if message.ParseMode != "" {
640 | params.Set("parseMode", string(message.ParseMode))
641 | }
642 |
643 | response, err := c.Do("/messages/sendTextWithDeeplink", params, nil)
644 | if err != nil {
645 | return fmt.Errorf("error while sending text: %s", err)
646 | }
647 |
648 | if err := json.Unmarshal(response, message); err != nil {
649 | return fmt.Errorf("cannot unmarshal response from API: %s", err)
650 | }
651 |
652 | return nil
653 | }
654 |
655 | func (c *Client) EditMessage(message *Message) error {
656 | if message == nil {
657 | return fmt.Errorf("message cannot be nil")
658 | }
659 | if message.ID == "" {
660 | return fmt.Errorf("message ID cannot be empty")
661 | }
662 | if message.Chat.ID == "" {
663 | return fmt.Errorf("chatID cannot be empty")
664 | }
665 | if message.Text == "" {
666 | return fmt.Errorf("text cannot be empty")
667 | }
668 |
669 | params := url.Values{
670 | "msgId": {message.ID},
671 | "chatId": {message.Chat.ID},
672 | "text": {message.Text},
673 | }
674 |
675 | if message.InlineKeyboard != nil {
676 | data, err := json.Marshal(message.InlineKeyboard.GetKeyboard())
677 | if err != nil {
678 | return fmt.Errorf("cannot marshal inline keyboard markup: %s", err)
679 | }
680 |
681 | params.Set("inlineKeyboardMarkup", string(data))
682 | }
683 |
684 | if message.ParseMode != "" {
685 | params.Set("parseMode", string(message.ParseMode))
686 | }
687 |
688 | response, err := c.Do("/messages/editText", params, nil)
689 | if err != nil {
690 | return fmt.Errorf("error while editing text: %s", err)
691 | }
692 |
693 | if err := json.Unmarshal(response, message); err != nil {
694 | return fmt.Errorf("cannot unmarshal response from API: %s", err)
695 | }
696 |
697 | return nil
698 | }
699 |
700 | func (c *Client) DeleteMessage(message *Message) error {
701 | if message == nil {
702 | return fmt.Errorf("message cannot be nil")
703 | }
704 | if message.ID == "" {
705 | return fmt.Errorf("message ID cannot be empty")
706 | }
707 | if message.Chat.ID == "" {
708 | return fmt.Errorf("chatID cannot be empty")
709 | }
710 |
711 | params := url.Values{
712 | "msgId": {message.ID},
713 | "chatId": {message.Chat.ID},
714 | }
715 | _, err := c.Do("/messages/deleteMessages", params, nil)
716 | if err != nil {
717 | return fmt.Errorf("error while deleting message: %s", err)
718 | }
719 |
720 | return nil
721 | }
722 |
723 | func (c *Client) SendFileMessage(message *Message) error {
724 | if message == nil {
725 | return fmt.Errorf("message cannot be nil")
726 | }
727 | if message.Chat.ID == "" {
728 | return fmt.Errorf("chatID cannot be empty")
729 | }
730 | if message.FileID == "" {
731 | return fmt.Errorf("fileID cannot be empty")
732 | }
733 |
734 | params := url.Values{
735 | "chatId": {message.Chat.ID},
736 | "caption": {message.Text},
737 | "fileId": {message.FileID},
738 | }
739 |
740 | if message.ReplyMsgID != "" {
741 | params.Set("replyMsgId", message.ReplyMsgID)
742 | }
743 |
744 | if message.ForwardMsgID != "" {
745 | params.Set("forwardMsgId", message.ForwardMsgID)
746 | params.Set("forwardChatId", message.ForwardChatID)
747 | }
748 |
749 | if message.InlineKeyboard != nil {
750 | data, err := json.Marshal(message.InlineKeyboard.GetKeyboard())
751 | if err != nil {
752 | return fmt.Errorf("cannot marshal inline keyboard markup: %s", err)
753 | }
754 |
755 | params.Set("inlineKeyboardMarkup", string(data))
756 | }
757 |
758 | if message.ParseMode != "" {
759 | params.Set("parseMode", string(message.ParseMode))
760 | }
761 |
762 | response, err := c.Do("/messages/sendFile", params, nil)
763 | if err != nil {
764 | return fmt.Errorf("error while making request: %s", err)
765 | }
766 |
767 | if err := json.Unmarshal(response, message); err != nil {
768 | return fmt.Errorf("cannot unmarshal response: %s", err)
769 | }
770 |
771 | return nil
772 | }
773 |
774 | func (c *Client) SendVoiceMessage(message *Message) error {
775 | if message == nil {
776 | return fmt.Errorf("message cannot be nil")
777 | }
778 | if message.Chat.ID == "" {
779 | return fmt.Errorf("chatID cannot be empty")
780 | }
781 | if message.FileID == "" {
782 | return fmt.Errorf("fileID cannot be empty")
783 | }
784 |
785 | params := url.Values{
786 | "chatId": {message.Chat.ID},
787 | "caption": {message.Text},
788 | "fileId": {message.FileID},
789 | }
790 |
791 | if message.ReplyMsgID != "" {
792 | params.Set("replyMsgId", message.ReplyMsgID)
793 | }
794 |
795 | if message.ForwardMsgID != "" {
796 | params.Set("forwardMsgId", message.ForwardMsgID)
797 | params.Set("forwardChatId", message.ForwardChatID)
798 | }
799 |
800 | if message.InlineKeyboard != nil {
801 | data, err := json.Marshal(message.InlineKeyboard.GetKeyboard())
802 | if err != nil {
803 | return fmt.Errorf("cannot marshal inline keyboard markup: %s", err)
804 | }
805 |
806 | params.Set("inlineKeyboardMarkup", string(data))
807 | }
808 |
809 | response, err := c.Do("/messages/sendVoice", params, nil)
810 | if err != nil {
811 | return fmt.Errorf("error while making request: %s", err)
812 | }
813 |
814 | if err := json.Unmarshal(response, message); err != nil {
815 | return fmt.Errorf("cannot unmarshal response: %s", err)
816 | }
817 |
818 | return nil
819 | }
820 |
821 | func (c *Client) UploadFile(message *Message) error {
822 | if message == nil {
823 | return fmt.Errorf("message cannot be nil")
824 | }
825 | if message.Chat.ID == "" {
826 | return fmt.Errorf("chatID cannot be empty")
827 | }
828 | if message.File == nil {
829 | return fmt.Errorf("file cannot be nil")
830 | }
831 |
832 | params := url.Values{
833 | "chatId": {message.Chat.ID},
834 | "caption": {message.Text},
835 | }
836 |
837 | if message.InlineKeyboard != nil {
838 | data, err := json.Marshal(message.InlineKeyboard.GetKeyboard())
839 | if err != nil {
840 | return fmt.Errorf("cannot marshal inline keyboard markup: %s", err)
841 | }
842 |
843 | params.Set("inlineKeyboardMarkup", string(data))
844 | }
845 |
846 | response, err := c.Do("/messages/sendFile", params, message.File)
847 | if err != nil {
848 | return fmt.Errorf("error while making request: %s", err)
849 | }
850 |
851 | if err := json.Unmarshal(response, message); err != nil {
852 | return fmt.Errorf("cannot unmarshal response: %s", err)
853 | }
854 |
855 | return nil
856 | }
857 |
858 | func (c *Client) UploadVoice(message *Message) error {
859 | if message == nil {
860 | return fmt.Errorf("message cannot be nil")
861 | }
862 | if message.Chat.ID == "" {
863 | return fmt.Errorf("chatID cannot be empty")
864 | }
865 | if message.File == nil {
866 | return fmt.Errorf("file cannot be nil")
867 | }
868 |
869 | params := url.Values{
870 | "chatId": {message.Chat.ID},
871 | "caption": {message.Text},
872 | }
873 |
874 | if message.InlineKeyboard != nil {
875 | data, err := json.Marshal(message.InlineKeyboard.GetKeyboard())
876 | if err != nil {
877 | return fmt.Errorf("cannot marshal inline keyboard markup: %s", err)
878 | }
879 |
880 | params.Set("inlineKeyboardMarkup", string(data))
881 | }
882 |
883 | response, err := c.Do("/messages/sendVoice", params, message.File)
884 | if err != nil {
885 | return fmt.Errorf("error while making request: %s", err)
886 | }
887 |
888 | if err := json.Unmarshal(response, message); err != nil {
889 | return fmt.Errorf("cannot unmarshal response: %s", err)
890 | }
891 |
892 | return nil
893 | }
894 |
895 | func (c *Client) GetEvents(lastEventID int, pollTime int) ([]*Event, error) {
896 | return c.GetEventsWithContext(context.Background(), lastEventID, pollTime)
897 | }
898 |
899 | func (c *Client) GetEventsWithContext(ctx context.Context, lastEventID int, pollTime int) ([]*Event, error) {
900 | params := url.Values{
901 | "lastEventId": {strconv.Itoa(lastEventID)},
902 | "pollTime": {strconv.Itoa(pollTime)},
903 | }
904 | events := &eventsResponse{}
905 |
906 | response, err := c.DoWithContext(ctx, "/events/get", params, nil)
907 | if err != nil {
908 | return events.Events, fmt.Errorf("error while making request: %s", err)
909 | }
910 |
911 | if err := json.Unmarshal(response, events); err != nil {
912 | return events.Events, fmt.Errorf("cannot parse events: %s", err)
913 | }
914 |
915 | return events.Events, nil
916 | }
917 |
918 | func (c *Client) PinMessage(message *Message) error {
919 | if message == nil {
920 | return fmt.Errorf("message cannot be nil")
921 | }
922 | if message.Chat.ID == "" {
923 | return fmt.Errorf("chatID cannot be empty")
924 | }
925 | if message.ID == "" {
926 | return fmt.Errorf("message ID cannot be empty")
927 | }
928 |
929 | params := url.Values{
930 | "chatId": {message.Chat.ID},
931 | "msgId": {message.ID},
932 | }
933 | _, err := c.Do("/chats/pinMessage", params, nil)
934 | if err != nil {
935 | return fmt.Errorf("error while pinning message: %s", err)
936 | }
937 |
938 | return nil
939 | }
940 |
941 | func (c *Client) UnpinMessage(message *Message) error {
942 | if message == nil {
943 | return fmt.Errorf("message cannot be nil")
944 | }
945 | if message.Chat.ID == "" {
946 | return fmt.Errorf("chatID cannot be empty")
947 | }
948 | if message.ID == "" {
949 | return fmt.Errorf("message ID cannot be empty")
950 | }
951 |
952 | params := url.Values{
953 | "chatId": {message.Chat.ID},
954 | "msgId": {message.ID},
955 | }
956 | _, err := c.Do("/chats/unpinMessage", params, nil)
957 | if err != nil {
958 | return fmt.Errorf("error while unpinning message: %s", err)
959 | }
960 |
961 | return nil
962 | }
963 |
964 | func (c *Client) SendAnswerCallbackQuery(answer *ButtonResponse) error {
965 | if answer == nil {
966 | return fmt.Errorf("answer cannot be nil")
967 | }
968 | if answer.QueryID == "" {
969 | return fmt.Errorf("queryID cannot be empty")
970 | }
971 |
972 | params := url.Values{
973 | "queryId": {answer.QueryID},
974 | "text": {answer.Text},
975 | "url": {answer.URL},
976 | "showAlert": {strconv.FormatBool(answer.ShowAlert)},
977 | }
978 |
979 | _, err := c.Do("/messages/answerCallbackQuery", params, nil)
980 | if err != nil {
981 | return fmt.Errorf("error while making request: %s", err)
982 | }
983 |
984 | return nil
985 | }
986 |
987 | func NewClient(baseURL string, token string, logger *logrus.Logger) *Client {
988 | return NewCustomClient(http.DefaultClient, baseURL, token, logger)
989 | }
990 |
991 | func NewCustomClient(client *http.Client, baseURL string, token string, logger *logrus.Logger) *Client {
992 | return &Client{
993 | token: token,
994 | baseURL: baseURL,
995 | client: client,
996 | logger: logger,
997 | }
998 | }
999 |
--------------------------------------------------------------------------------
/types_easyjson.go:
--------------------------------------------------------------------------------
1 | // Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.
2 |
3 | package botgolang
4 |
5 | import (
6 | json "encoding/json"
7 | easyjson "github.com/mailru/easyjson"
8 | jlexer "github.com/mailru/easyjson/jlexer"
9 | jwriter "github.com/mailru/easyjson/jwriter"
10 | )
11 |
12 | // suppress unused package warning
13 | var (
14 | _ *json.RawMessage
15 | _ *jlexer.Lexer
16 | _ *jwriter.Writer
17 | _ easyjson.Marshaler
18 | )
19 |
20 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang(in *jlexer.Lexer, out *eventsResponse) {
21 | isTopLevel := in.IsStart()
22 | if in.IsNull() {
23 | if isTopLevel {
24 | in.Consumed()
25 | }
26 | in.Skip()
27 | return
28 | }
29 | in.Delim('{')
30 | for !in.IsDelim('}') {
31 | key := in.UnsafeFieldName(false)
32 | in.WantColon()
33 | if in.IsNull() {
34 | in.Skip()
35 | in.WantComma()
36 | continue
37 | }
38 | switch key {
39 | case "ok":
40 | out.OK = bool(in.Bool())
41 | case "events":
42 | if in.IsNull() {
43 | in.Skip()
44 | out.Events = nil
45 | } else {
46 | in.Delim('[')
47 | if out.Events == nil {
48 | if !in.IsDelim(']') {
49 | out.Events = make([]*Event, 0, 8)
50 | } else {
51 | out.Events = []*Event{}
52 | }
53 | } else {
54 | out.Events = (out.Events)[:0]
55 | }
56 | for !in.IsDelim(']') {
57 | var v1 *Event
58 | if in.IsNull() {
59 | in.Skip()
60 | v1 = nil
61 | } else {
62 | if v1 == nil {
63 | v1 = new(Event)
64 | }
65 | (*v1).UnmarshalEasyJSON(in)
66 | }
67 | out.Events = append(out.Events, v1)
68 | in.WantComma()
69 | }
70 | in.Delim(']')
71 | }
72 | default:
73 | in.SkipRecursive()
74 | }
75 | in.WantComma()
76 | }
77 | in.Delim('}')
78 | if isTopLevel {
79 | in.Consumed()
80 | }
81 | }
82 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang(out *jwriter.Writer, in eventsResponse) {
83 | out.RawByte('{')
84 | first := true
85 | _ = first
86 | {
87 | const prefix string = ",\"ok\":"
88 | out.RawString(prefix[1:])
89 | out.Bool(bool(in.OK))
90 | }
91 | {
92 | const prefix string = ",\"events\":"
93 | out.RawString(prefix)
94 | if in.Events == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
95 | out.RawString("null")
96 | } else {
97 | out.RawByte('[')
98 | for v2, v3 := range in.Events {
99 | if v2 > 0 {
100 | out.RawByte(',')
101 | }
102 | if v3 == nil {
103 | out.RawString("null")
104 | } else {
105 | (*v3).MarshalEasyJSON(out)
106 | }
107 | }
108 | out.RawByte(']')
109 | }
110 | }
111 | out.RawByte('}')
112 | }
113 |
114 | // MarshalJSON supports json.Marshaler interface
115 | func (v eventsResponse) MarshalJSON() ([]byte, error) {
116 | w := jwriter.Writer{}
117 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang(&w, v)
118 | return w.Buffer.BuildBytes(), w.Error
119 | }
120 |
121 | // MarshalEasyJSON supports easyjson.Marshaler interface
122 | func (v eventsResponse) MarshalEasyJSON(w *jwriter.Writer) {
123 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang(w, v)
124 | }
125 |
126 | // UnmarshalJSON supports json.Unmarshaler interface
127 | func (v *eventsResponse) UnmarshalJSON(data []byte) error {
128 | r := jlexer.Lexer{Data: data}
129 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang(&r, v)
130 | return r.Error()
131 | }
132 |
133 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
134 | func (v *eventsResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
135 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang(l, v)
136 | }
137 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang1(in *jlexer.Lexer, out *UsersListResponse) {
138 | isTopLevel := in.IsStart()
139 | if in.IsNull() {
140 | if isTopLevel {
141 | in.Consumed()
142 | }
143 | in.Skip()
144 | return
145 | }
146 | in.Delim('{')
147 | for !in.IsDelim('}') {
148 | key := in.UnsafeFieldName(false)
149 | in.WantColon()
150 | if in.IsNull() {
151 | in.Skip()
152 | in.WantComma()
153 | continue
154 | }
155 | switch key {
156 | case "users":
157 | if in.IsNull() {
158 | in.Skip()
159 | out.List = nil
160 | } else {
161 | in.Delim('[')
162 | if out.List == nil {
163 | if !in.IsDelim(']') {
164 | out.List = make([]User, 0, 4)
165 | } else {
166 | out.List = []User{}
167 | }
168 | } else {
169 | out.List = (out.List)[:0]
170 | }
171 | for !in.IsDelim(']') {
172 | var v4 User
173 | (v4).UnmarshalEasyJSON(in)
174 | out.List = append(out.List, v4)
175 | in.WantComma()
176 | }
177 | in.Delim(']')
178 | }
179 | default:
180 | in.SkipRecursive()
181 | }
182 | in.WantComma()
183 | }
184 | in.Delim('}')
185 | if isTopLevel {
186 | in.Consumed()
187 | }
188 | }
189 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang1(out *jwriter.Writer, in UsersListResponse) {
190 | out.RawByte('{')
191 | first := true
192 | _ = first
193 | {
194 | const prefix string = ",\"users\":"
195 | out.RawString(prefix[1:])
196 | if in.List == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
197 | out.RawString("null")
198 | } else {
199 | out.RawByte('[')
200 | for v5, v6 := range in.List {
201 | if v5 > 0 {
202 | out.RawByte(',')
203 | }
204 | (v6).MarshalEasyJSON(out)
205 | }
206 | out.RawByte(']')
207 | }
208 | }
209 | out.RawByte('}')
210 | }
211 |
212 | // MarshalJSON supports json.Marshaler interface
213 | func (v UsersListResponse) MarshalJSON() ([]byte, error) {
214 | w := jwriter.Writer{}
215 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang1(&w, v)
216 | return w.Buffer.BuildBytes(), w.Error
217 | }
218 |
219 | // MarshalEasyJSON supports easyjson.Marshaler interface
220 | func (v UsersListResponse) MarshalEasyJSON(w *jwriter.Writer) {
221 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang1(w, v)
222 | }
223 |
224 | // UnmarshalJSON supports json.Unmarshaler interface
225 | func (v *UsersListResponse) UnmarshalJSON(data []byte) error {
226 | r := jlexer.Lexer{Data: data}
227 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang1(&r, v)
228 | return r.Error()
229 | }
230 |
231 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
232 | func (v *UsersListResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
233 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang1(l, v)
234 | }
235 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang2(in *jlexer.Lexer, out *UserState) {
236 | isTopLevel := in.IsStart()
237 | if in.IsNull() {
238 | if isTopLevel {
239 | in.Consumed()
240 | }
241 | in.Skip()
242 | return
243 | }
244 | in.Delim('{')
245 | for !in.IsDelim('}') {
246 | key := in.UnsafeFieldName(false)
247 | in.WantColon()
248 | if in.IsNull() {
249 | in.Skip()
250 | in.WantComma()
251 | continue
252 | }
253 | switch key {
254 | case "lastseen":
255 | out.Lastseen = int(in.Int())
256 | default:
257 | in.SkipRecursive()
258 | }
259 | in.WantComma()
260 | }
261 | in.Delim('}')
262 | if isTopLevel {
263 | in.Consumed()
264 | }
265 | }
266 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang2(out *jwriter.Writer, in UserState) {
267 | out.RawByte('{')
268 | first := true
269 | _ = first
270 | {
271 | const prefix string = ",\"lastseen\":"
272 | out.RawString(prefix[1:])
273 | out.Int(int(in.Lastseen))
274 | }
275 | out.RawByte('}')
276 | }
277 |
278 | // MarshalJSON supports json.Marshaler interface
279 | func (v UserState) MarshalJSON() ([]byte, error) {
280 | w := jwriter.Writer{}
281 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang2(&w, v)
282 | return w.Buffer.BuildBytes(), w.Error
283 | }
284 |
285 | // MarshalEasyJSON supports easyjson.Marshaler interface
286 | func (v UserState) MarshalEasyJSON(w *jwriter.Writer) {
287 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang2(w, v)
288 | }
289 |
290 | // UnmarshalJSON supports json.Unmarshaler interface
291 | func (v *UserState) UnmarshalJSON(data []byte) error {
292 | r := jlexer.Lexer{Data: data}
293 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang2(&r, v)
294 | return r.Error()
295 | }
296 |
297 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
298 | func (v *UserState) UnmarshalEasyJSON(l *jlexer.Lexer) {
299 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang2(l, v)
300 | }
301 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang3(in *jlexer.Lexer, out *User) {
302 | isTopLevel := in.IsStart()
303 | if in.IsNull() {
304 | if isTopLevel {
305 | in.Consumed()
306 | }
307 | in.Skip()
308 | return
309 | }
310 | in.Delim('{')
311 | for !in.IsDelim('}') {
312 | key := in.UnsafeFieldName(false)
313 | in.WantColon()
314 | if in.IsNull() {
315 | in.Skip()
316 | in.WantComma()
317 | continue
318 | }
319 | switch key {
320 | case "userId":
321 | out.ID = string(in.String())
322 | default:
323 | in.SkipRecursive()
324 | }
325 | in.WantComma()
326 | }
327 | in.Delim('}')
328 | if isTopLevel {
329 | in.Consumed()
330 | }
331 | }
332 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang3(out *jwriter.Writer, in User) {
333 | out.RawByte('{')
334 | first := true
335 | _ = first
336 | {
337 | const prefix string = ",\"userId\":"
338 | out.RawString(prefix[1:])
339 | out.String(string(in.ID))
340 | }
341 | out.RawByte('}')
342 | }
343 |
344 | // MarshalJSON supports json.Marshaler interface
345 | func (v User) MarshalJSON() ([]byte, error) {
346 | w := jwriter.Writer{}
347 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang3(&w, v)
348 | return w.Buffer.BuildBytes(), w.Error
349 | }
350 |
351 | // MarshalEasyJSON supports easyjson.Marshaler interface
352 | func (v User) MarshalEasyJSON(w *jwriter.Writer) {
353 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang3(w, v)
354 | }
355 |
356 | // UnmarshalJSON supports json.Unmarshaler interface
357 | func (v *User) UnmarshalJSON(data []byte) error {
358 | r := jlexer.Lexer{Data: data}
359 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang3(&r, v)
360 | return r.Error()
361 | }
362 |
363 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
364 | func (v *User) UnmarshalEasyJSON(l *jlexer.Lexer) {
365 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang3(l, v)
366 | }
367 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang4(in *jlexer.Lexer, out *ThreadSubscribers) {
368 | isTopLevel := in.IsStart()
369 | if in.IsNull() {
370 | if isTopLevel {
371 | in.Consumed()
372 | }
373 | in.Skip()
374 | return
375 | }
376 | in.Delim('{')
377 | for !in.IsDelim('}') {
378 | key := in.UnsafeFieldName(false)
379 | in.WantColon()
380 | if in.IsNull() {
381 | in.Skip()
382 | in.WantComma()
383 | continue
384 | }
385 | switch key {
386 | case "cursor":
387 | out.Cursor = string(in.String())
388 | case "subscribers":
389 | if in.IsNull() {
390 | in.Skip()
391 | out.Subscribers = nil
392 | } else {
393 | in.Delim('[')
394 | if out.Subscribers == nil {
395 | if !in.IsDelim(']') {
396 | out.Subscribers = make([]Subscriber, 0, 2)
397 | } else {
398 | out.Subscribers = []Subscriber{}
399 | }
400 | } else {
401 | out.Subscribers = (out.Subscribers)[:0]
402 | }
403 | for !in.IsDelim(']') {
404 | var v7 Subscriber
405 | (v7).UnmarshalEasyJSON(in)
406 | out.Subscribers = append(out.Subscribers, v7)
407 | in.WantComma()
408 | }
409 | in.Delim(']')
410 | }
411 | default:
412 | in.SkipRecursive()
413 | }
414 | in.WantComma()
415 | }
416 | in.Delim('}')
417 | if isTopLevel {
418 | in.Consumed()
419 | }
420 | }
421 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang4(out *jwriter.Writer, in ThreadSubscribers) {
422 | out.RawByte('{')
423 | first := true
424 | _ = first
425 | {
426 | const prefix string = ",\"cursor\":"
427 | out.RawString(prefix[1:])
428 | out.String(string(in.Cursor))
429 | }
430 | {
431 | const prefix string = ",\"subscribers\":"
432 | out.RawString(prefix)
433 | if in.Subscribers == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
434 | out.RawString("null")
435 | } else {
436 | out.RawByte('[')
437 | for v8, v9 := range in.Subscribers {
438 | if v8 > 0 {
439 | out.RawByte(',')
440 | }
441 | (v9).MarshalEasyJSON(out)
442 | }
443 | out.RawByte(']')
444 | }
445 | }
446 | out.RawByte('}')
447 | }
448 |
449 | // MarshalJSON supports json.Marshaler interface
450 | func (v ThreadSubscribers) MarshalJSON() ([]byte, error) {
451 | w := jwriter.Writer{}
452 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang4(&w, v)
453 | return w.Buffer.BuildBytes(), w.Error
454 | }
455 |
456 | // MarshalEasyJSON supports easyjson.Marshaler interface
457 | func (v ThreadSubscribers) MarshalEasyJSON(w *jwriter.Writer) {
458 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang4(w, v)
459 | }
460 |
461 | // UnmarshalJSON supports json.Unmarshaler interface
462 | func (v *ThreadSubscribers) UnmarshalJSON(data []byte) error {
463 | r := jlexer.Lexer{Data: data}
464 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang4(&r, v)
465 | return r.Error()
466 | }
467 |
468 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
469 | func (v *ThreadSubscribers) UnmarshalEasyJSON(l *jlexer.Lexer) {
470 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang4(l, v)
471 | }
472 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang5(in *jlexer.Lexer, out *Thread) {
473 | isTopLevel := in.IsStart()
474 | if in.IsNull() {
475 | if isTopLevel {
476 | in.Consumed()
477 | }
478 | in.Skip()
479 | return
480 | }
481 | in.Delim('{')
482 | for !in.IsDelim('}') {
483 | key := in.UnsafeFieldName(false)
484 | in.WantColon()
485 | if in.IsNull() {
486 | in.Skip()
487 | in.WantComma()
488 | continue
489 | }
490 | switch key {
491 | case "threadId":
492 | out.ThreadID = string(in.String())
493 | default:
494 | in.SkipRecursive()
495 | }
496 | in.WantComma()
497 | }
498 | in.Delim('}')
499 | if isTopLevel {
500 | in.Consumed()
501 | }
502 | }
503 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang5(out *jwriter.Writer, in Thread) {
504 | out.RawByte('{')
505 | first := true
506 | _ = first
507 | {
508 | const prefix string = ",\"threadId\":"
509 | out.RawString(prefix[1:])
510 | out.String(string(in.ThreadID))
511 | }
512 | out.RawByte('}')
513 | }
514 |
515 | // MarshalJSON supports json.Marshaler interface
516 | func (v Thread) MarshalJSON() ([]byte, error) {
517 | w := jwriter.Writer{}
518 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang5(&w, v)
519 | return w.Buffer.BuildBytes(), w.Error
520 | }
521 |
522 | // MarshalEasyJSON supports easyjson.Marshaler interface
523 | func (v Thread) MarshalEasyJSON(w *jwriter.Writer) {
524 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang5(w, v)
525 | }
526 |
527 | // UnmarshalJSON supports json.Unmarshaler interface
528 | func (v *Thread) UnmarshalJSON(data []byte) error {
529 | r := jlexer.Lexer{Data: data}
530 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang5(&r, v)
531 | return r.Error()
532 | }
533 |
534 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
535 | func (v *Thread) UnmarshalEasyJSON(l *jlexer.Lexer) {
536 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang5(l, v)
537 | }
538 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang6(in *jlexer.Lexer, out *Subscriber) {
539 | isTopLevel := in.IsStart()
540 | if in.IsNull() {
541 | if isTopLevel {
542 | in.Consumed()
543 | }
544 | in.Skip()
545 | return
546 | }
547 | in.Delim('{')
548 | for !in.IsDelim('}') {
549 | key := in.UnsafeFieldName(false)
550 | in.WantColon()
551 | if in.IsNull() {
552 | in.Skip()
553 | in.WantComma()
554 | continue
555 | }
556 | switch key {
557 | case "sn":
558 | out.SN = string(in.String())
559 | case "userState":
560 | (out.UserState).UnmarshalEasyJSON(in)
561 | default:
562 | in.SkipRecursive()
563 | }
564 | in.WantComma()
565 | }
566 | in.Delim('}')
567 | if isTopLevel {
568 | in.Consumed()
569 | }
570 | }
571 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang6(out *jwriter.Writer, in Subscriber) {
572 | out.RawByte('{')
573 | first := true
574 | _ = first
575 | {
576 | const prefix string = ",\"sn\":"
577 | out.RawString(prefix[1:])
578 | out.String(string(in.SN))
579 | }
580 | {
581 | const prefix string = ",\"userState\":"
582 | out.RawString(prefix)
583 | (in.UserState).MarshalEasyJSON(out)
584 | }
585 | out.RawByte('}')
586 | }
587 |
588 | // MarshalJSON supports json.Marshaler interface
589 | func (v Subscriber) MarshalJSON() ([]byte, error) {
590 | w := jwriter.Writer{}
591 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang6(&w, v)
592 | return w.Buffer.BuildBytes(), w.Error
593 | }
594 |
595 | // MarshalEasyJSON supports easyjson.Marshaler interface
596 | func (v Subscriber) MarshalEasyJSON(w *jwriter.Writer) {
597 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang6(w, v)
598 | }
599 |
600 | // UnmarshalJSON supports json.Unmarshaler interface
601 | func (v *Subscriber) UnmarshalJSON(data []byte) error {
602 | r := jlexer.Lexer{Data: data}
603 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang6(&r, v)
604 | return r.Error()
605 | }
606 |
607 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
608 | func (v *Subscriber) UnmarshalEasyJSON(l *jlexer.Lexer) {
609 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang6(l, v)
610 | }
611 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang7(in *jlexer.Lexer, out *Response) {
612 | isTopLevel := in.IsStart()
613 | if in.IsNull() {
614 | if isTopLevel {
615 | in.Consumed()
616 | }
617 | in.Skip()
618 | return
619 | }
620 | in.Delim('{')
621 | for !in.IsDelim('}') {
622 | key := in.UnsafeFieldName(false)
623 | in.WantColon()
624 | if in.IsNull() {
625 | in.Skip()
626 | in.WantComma()
627 | continue
628 | }
629 | switch key {
630 | case "ok":
631 | out.OK = bool(in.Bool())
632 | case "description":
633 | out.Description = string(in.String())
634 | default:
635 | in.SkipRecursive()
636 | }
637 | in.WantComma()
638 | }
639 | in.Delim('}')
640 | if isTopLevel {
641 | in.Consumed()
642 | }
643 | }
644 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang7(out *jwriter.Writer, in Response) {
645 | out.RawByte('{')
646 | first := true
647 | _ = first
648 | {
649 | const prefix string = ",\"ok\":"
650 | out.RawString(prefix[1:])
651 | out.Bool(bool(in.OK))
652 | }
653 | if in.Description != "" {
654 | const prefix string = ",\"description\":"
655 | out.RawString(prefix)
656 | out.String(string(in.Description))
657 | }
658 | out.RawByte('}')
659 | }
660 |
661 | // MarshalJSON supports json.Marshaler interface
662 | func (v Response) MarshalJSON() ([]byte, error) {
663 | w := jwriter.Writer{}
664 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang7(&w, v)
665 | return w.Buffer.BuildBytes(), w.Error
666 | }
667 |
668 | // MarshalEasyJSON supports easyjson.Marshaler interface
669 | func (v Response) MarshalEasyJSON(w *jwriter.Writer) {
670 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang7(w, v)
671 | }
672 |
673 | // UnmarshalJSON supports json.Unmarshaler interface
674 | func (v *Response) UnmarshalJSON(data []byte) error {
675 | r := jlexer.Lexer{Data: data}
676 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang7(&r, v)
677 | return r.Error()
678 | }
679 |
680 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
681 | func (v *Response) UnmarshalEasyJSON(l *jlexer.Lexer) {
682 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang7(l, v)
683 | }
684 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang8(in *jlexer.Lexer, out *Photo) {
685 | isTopLevel := in.IsStart()
686 | if in.IsNull() {
687 | if isTopLevel {
688 | in.Consumed()
689 | }
690 | in.Skip()
691 | return
692 | }
693 | in.Delim('{')
694 | for !in.IsDelim('}') {
695 | key := in.UnsafeFieldName(false)
696 | in.WantColon()
697 | if in.IsNull() {
698 | in.Skip()
699 | in.WantComma()
700 | continue
701 | }
702 | switch key {
703 | case "url":
704 | out.URL = string(in.String())
705 | default:
706 | in.SkipRecursive()
707 | }
708 | in.WantComma()
709 | }
710 | in.Delim('}')
711 | if isTopLevel {
712 | in.Consumed()
713 | }
714 | }
715 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang8(out *jwriter.Writer, in Photo) {
716 | out.RawByte('{')
717 | first := true
718 | _ = first
719 | {
720 | const prefix string = ",\"url\":"
721 | out.RawString(prefix[1:])
722 | out.String(string(in.URL))
723 | }
724 | out.RawByte('}')
725 | }
726 |
727 | // MarshalJSON supports json.Marshaler interface
728 | func (v Photo) MarshalJSON() ([]byte, error) {
729 | w := jwriter.Writer{}
730 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang8(&w, v)
731 | return w.Buffer.BuildBytes(), w.Error
732 | }
733 |
734 | // MarshalEasyJSON supports easyjson.Marshaler interface
735 | func (v Photo) MarshalEasyJSON(w *jwriter.Writer) {
736 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang8(w, v)
737 | }
738 |
739 | // UnmarshalJSON supports json.Unmarshaler interface
740 | func (v *Photo) UnmarshalJSON(data []byte) error {
741 | r := jlexer.Lexer{Data: data}
742 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang8(&r, v)
743 | return r.Error()
744 | }
745 |
746 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
747 | func (v *Photo) UnmarshalEasyJSON(l *jlexer.Lexer) {
748 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang8(l, v)
749 | }
750 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang9(in *jlexer.Lexer, out *PartPayload) {
751 | isTopLevel := in.IsStart()
752 | if in.IsNull() {
753 | if isTopLevel {
754 | in.Consumed()
755 | }
756 | in.Skip()
757 | return
758 | }
759 | in.Delim('{')
760 | for !in.IsDelim('}') {
761 | key := in.UnsafeFieldName(false)
762 | in.WantColon()
763 | if in.IsNull() {
764 | in.Skip()
765 | in.WantComma()
766 | continue
767 | }
768 | switch key {
769 | case "firstName":
770 | out.FirstName = string(in.String())
771 | case "lastName":
772 | out.LastName = string(in.String())
773 | case "userId":
774 | out.UserID = string(in.String())
775 | case "fileId":
776 | out.FileID = string(in.String())
777 | case "caption":
778 | out.Caption = string(in.String())
779 | case "type":
780 | out.Type = string(in.String())
781 | case "message":
782 | (out.PartMessage).UnmarshalEasyJSON(in)
783 | default:
784 | in.SkipRecursive()
785 | }
786 | in.WantComma()
787 | }
788 | in.Delim('}')
789 | if isTopLevel {
790 | in.Consumed()
791 | }
792 | }
793 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang9(out *jwriter.Writer, in PartPayload) {
794 | out.RawByte('{')
795 | first := true
796 | _ = first
797 | {
798 | const prefix string = ",\"firstName\":"
799 | out.RawString(prefix[1:])
800 | out.String(string(in.FirstName))
801 | }
802 | {
803 | const prefix string = ",\"lastName\":"
804 | out.RawString(prefix)
805 | out.String(string(in.LastName))
806 | }
807 | {
808 | const prefix string = ",\"userId\":"
809 | out.RawString(prefix)
810 | out.String(string(in.UserID))
811 | }
812 | {
813 | const prefix string = ",\"fileId\":"
814 | out.RawString(prefix)
815 | out.String(string(in.FileID))
816 | }
817 | {
818 | const prefix string = ",\"caption\":"
819 | out.RawString(prefix)
820 | out.String(string(in.Caption))
821 | }
822 | {
823 | const prefix string = ",\"type\":"
824 | out.RawString(prefix)
825 | out.String(string(in.Type))
826 | }
827 | {
828 | const prefix string = ",\"message\":"
829 | out.RawString(prefix)
830 | (in.PartMessage).MarshalEasyJSON(out)
831 | }
832 | out.RawByte('}')
833 | }
834 |
835 | // MarshalJSON supports json.Marshaler interface
836 | func (v PartPayload) MarshalJSON() ([]byte, error) {
837 | w := jwriter.Writer{}
838 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang9(&w, v)
839 | return w.Buffer.BuildBytes(), w.Error
840 | }
841 |
842 | // MarshalEasyJSON supports easyjson.Marshaler interface
843 | func (v PartPayload) MarshalEasyJSON(w *jwriter.Writer) {
844 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang9(w, v)
845 | }
846 |
847 | // UnmarshalJSON supports json.Unmarshaler interface
848 | func (v *PartPayload) UnmarshalJSON(data []byte) error {
849 | r := jlexer.Lexer{Data: data}
850 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang9(&r, v)
851 | return r.Error()
852 | }
853 |
854 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
855 | func (v *PartPayload) UnmarshalEasyJSON(l *jlexer.Lexer) {
856 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang9(l, v)
857 | }
858 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang10(in *jlexer.Lexer, out *PartMessage) {
859 | isTopLevel := in.IsStart()
860 | if in.IsNull() {
861 | if isTopLevel {
862 | in.Consumed()
863 | }
864 | in.Skip()
865 | return
866 | }
867 | in.Delim('{')
868 | for !in.IsDelim('}') {
869 | key := in.UnsafeFieldName(false)
870 | in.WantColon()
871 | if in.IsNull() {
872 | in.Skip()
873 | in.WantComma()
874 | continue
875 | }
876 | switch key {
877 | case "from":
878 | (out.From).UnmarshalEasyJSON(in)
879 | case "msgId":
880 | out.MsgID = string(in.String())
881 | case "text":
882 | out.Text = string(in.String())
883 | case "timestamp":
884 | out.Timestamp = int(in.Int())
885 | default:
886 | in.SkipRecursive()
887 | }
888 | in.WantComma()
889 | }
890 | in.Delim('}')
891 | if isTopLevel {
892 | in.Consumed()
893 | }
894 | }
895 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang10(out *jwriter.Writer, in PartMessage) {
896 | out.RawByte('{')
897 | first := true
898 | _ = first
899 | {
900 | const prefix string = ",\"from\":"
901 | out.RawString(prefix[1:])
902 | (in.From).MarshalEasyJSON(out)
903 | }
904 | {
905 | const prefix string = ",\"msgId\":"
906 | out.RawString(prefix)
907 | out.String(string(in.MsgID))
908 | }
909 | {
910 | const prefix string = ",\"text\":"
911 | out.RawString(prefix)
912 | out.String(string(in.Text))
913 | }
914 | {
915 | const prefix string = ",\"timestamp\":"
916 | out.RawString(prefix)
917 | out.Int(int(in.Timestamp))
918 | }
919 | out.RawByte('}')
920 | }
921 |
922 | // MarshalJSON supports json.Marshaler interface
923 | func (v PartMessage) MarshalJSON() ([]byte, error) {
924 | w := jwriter.Writer{}
925 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang10(&w, v)
926 | return w.Buffer.BuildBytes(), w.Error
927 | }
928 |
929 | // MarshalEasyJSON supports easyjson.Marshaler interface
930 | func (v PartMessage) MarshalEasyJSON(w *jwriter.Writer) {
931 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang10(w, v)
932 | }
933 |
934 | // UnmarshalJSON supports json.Unmarshaler interface
935 | func (v *PartMessage) UnmarshalJSON(data []byte) error {
936 | r := jlexer.Lexer{Data: data}
937 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang10(&r, v)
938 | return r.Error()
939 | }
940 |
941 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
942 | func (v *PartMessage) UnmarshalEasyJSON(l *jlexer.Lexer) {
943 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang10(l, v)
944 | }
945 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang11(in *jlexer.Lexer, out *Part) {
946 | isTopLevel := in.IsStart()
947 | if in.IsNull() {
948 | if isTopLevel {
949 | in.Consumed()
950 | }
951 | in.Skip()
952 | return
953 | }
954 | in.Delim('{')
955 | for !in.IsDelim('}') {
956 | key := in.UnsafeFieldName(false)
957 | in.WantColon()
958 | if in.IsNull() {
959 | in.Skip()
960 | in.WantComma()
961 | continue
962 | }
963 | switch key {
964 | case "type":
965 | out.Type = PartType(in.String())
966 | case "payload":
967 | (out.Payload).UnmarshalEasyJSON(in)
968 | default:
969 | in.SkipRecursive()
970 | }
971 | in.WantComma()
972 | }
973 | in.Delim('}')
974 | if isTopLevel {
975 | in.Consumed()
976 | }
977 | }
978 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang11(out *jwriter.Writer, in Part) {
979 | out.RawByte('{')
980 | first := true
981 | _ = first
982 | {
983 | const prefix string = ",\"type\":"
984 | out.RawString(prefix[1:])
985 | out.String(string(in.Type))
986 | }
987 | {
988 | const prefix string = ",\"payload\":"
989 | out.RawString(prefix)
990 | (in.Payload).MarshalEasyJSON(out)
991 | }
992 | out.RawByte('}')
993 | }
994 |
995 | // MarshalJSON supports json.Marshaler interface
996 | func (v Part) MarshalJSON() ([]byte, error) {
997 | w := jwriter.Writer{}
998 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang11(&w, v)
999 | return w.Buffer.BuildBytes(), w.Error
1000 | }
1001 |
1002 | // MarshalEasyJSON supports easyjson.Marshaler interface
1003 | func (v Part) MarshalEasyJSON(w *jwriter.Writer) {
1004 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang11(w, v)
1005 | }
1006 |
1007 | // UnmarshalJSON supports json.Unmarshaler interface
1008 | func (v *Part) UnmarshalJSON(data []byte) error {
1009 | r := jlexer.Lexer{Data: data}
1010 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang11(&r, v)
1011 | return r.Error()
1012 | }
1013 |
1014 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1015 | func (v *Part) UnmarshalEasyJSON(l *jlexer.Lexer) {
1016 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang11(l, v)
1017 | }
1018 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang12(in *jlexer.Lexer, out *MembersListResponse) {
1019 | isTopLevel := in.IsStart()
1020 | if in.IsNull() {
1021 | if isTopLevel {
1022 | in.Consumed()
1023 | }
1024 | in.Skip()
1025 | return
1026 | }
1027 | in.Delim('{')
1028 | for !in.IsDelim('}') {
1029 | key := in.UnsafeFieldName(false)
1030 | in.WantColon()
1031 | if in.IsNull() {
1032 | in.Skip()
1033 | in.WantComma()
1034 | continue
1035 | }
1036 | switch key {
1037 | case "members":
1038 | if in.IsNull() {
1039 | in.Skip()
1040 | out.List = nil
1041 | } else {
1042 | in.Delim('[')
1043 | if out.List == nil {
1044 | if !in.IsDelim(']') {
1045 | out.List = make([]ChatMember, 0, 2)
1046 | } else {
1047 | out.List = []ChatMember{}
1048 | }
1049 | } else {
1050 | out.List = (out.List)[:0]
1051 | }
1052 | for !in.IsDelim(']') {
1053 | var v10 ChatMember
1054 | (v10).UnmarshalEasyJSON(in)
1055 | out.List = append(out.List, v10)
1056 | in.WantComma()
1057 | }
1058 | in.Delim(']')
1059 | }
1060 | default:
1061 | in.SkipRecursive()
1062 | }
1063 | in.WantComma()
1064 | }
1065 | in.Delim('}')
1066 | if isTopLevel {
1067 | in.Consumed()
1068 | }
1069 | }
1070 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang12(out *jwriter.Writer, in MembersListResponse) {
1071 | out.RawByte('{')
1072 | first := true
1073 | _ = first
1074 | {
1075 | const prefix string = ",\"members\":"
1076 | out.RawString(prefix[1:])
1077 | if in.List == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
1078 | out.RawString("null")
1079 | } else {
1080 | out.RawByte('[')
1081 | for v11, v12 := range in.List {
1082 | if v11 > 0 {
1083 | out.RawByte(',')
1084 | }
1085 | (v12).MarshalEasyJSON(out)
1086 | }
1087 | out.RawByte(']')
1088 | }
1089 | }
1090 | out.RawByte('}')
1091 | }
1092 |
1093 | // MarshalJSON supports json.Marshaler interface
1094 | func (v MembersListResponse) MarshalJSON() ([]byte, error) {
1095 | w := jwriter.Writer{}
1096 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang12(&w, v)
1097 | return w.Buffer.BuildBytes(), w.Error
1098 | }
1099 |
1100 | // MarshalEasyJSON supports easyjson.Marshaler interface
1101 | func (v MembersListResponse) MarshalEasyJSON(w *jwriter.Writer) {
1102 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang12(w, v)
1103 | }
1104 |
1105 | // UnmarshalJSON supports json.Unmarshaler interface
1106 | func (v *MembersListResponse) UnmarshalJSON(data []byte) error {
1107 | r := jlexer.Lexer{Data: data}
1108 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang12(&r, v)
1109 | return r.Error()
1110 | }
1111 |
1112 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1113 | func (v *MembersListResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
1114 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang12(l, v)
1115 | }
1116 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang13(in *jlexer.Lexer, out *EventPayload) {
1117 | isTopLevel := in.IsStart()
1118 | if in.IsNull() {
1119 | if isTopLevel {
1120 | in.Consumed()
1121 | }
1122 | in.Skip()
1123 | return
1124 | }
1125 | in.Delim('{')
1126 | for !in.IsDelim('}') {
1127 | key := in.UnsafeFieldName(false)
1128 | in.WantColon()
1129 | if in.IsNull() {
1130 | in.Skip()
1131 | in.WantComma()
1132 | continue
1133 | }
1134 | switch key {
1135 | case "parts":
1136 | if in.IsNull() {
1137 | in.Skip()
1138 | out.Parts = nil
1139 | } else {
1140 | in.Delim('[')
1141 | if out.Parts == nil {
1142 | if !in.IsDelim(']') {
1143 | out.Parts = make([]Part, 0, 0)
1144 | } else {
1145 | out.Parts = []Part{}
1146 | }
1147 | } else {
1148 | out.Parts = (out.Parts)[:0]
1149 | }
1150 | for !in.IsDelim(']') {
1151 | var v13 Part
1152 | (v13).UnmarshalEasyJSON(in)
1153 | out.Parts = append(out.Parts, v13)
1154 | in.WantComma()
1155 | }
1156 | in.Delim(']')
1157 | }
1158 | case "queryId":
1159 | out.QueryID = string(in.String())
1160 | case "message":
1161 | (out.CallbackMsg).UnmarshalEasyJSON(in)
1162 | case "callbackData":
1163 | out.CallbackData = string(in.String())
1164 | case "leftMembers":
1165 | if in.IsNull() {
1166 | in.Skip()
1167 | out.LeftMembers = nil
1168 | } else {
1169 | in.Delim('[')
1170 | if out.LeftMembers == nil {
1171 | if !in.IsDelim(']') {
1172 | out.LeftMembers = make([]Contact, 0, 1)
1173 | } else {
1174 | out.LeftMembers = []Contact{}
1175 | }
1176 | } else {
1177 | out.LeftMembers = (out.LeftMembers)[:0]
1178 | }
1179 | for !in.IsDelim(']') {
1180 | var v14 Contact
1181 | (v14).UnmarshalEasyJSON(in)
1182 | out.LeftMembers = append(out.LeftMembers, v14)
1183 | in.WantComma()
1184 | }
1185 | in.Delim(']')
1186 | }
1187 | case "newMembers":
1188 | if in.IsNull() {
1189 | in.Skip()
1190 | out.NewMembers = nil
1191 | } else {
1192 | in.Delim('[')
1193 | if out.NewMembers == nil {
1194 | if !in.IsDelim(']') {
1195 | out.NewMembers = make([]Contact, 0, 1)
1196 | } else {
1197 | out.NewMembers = []Contact{}
1198 | }
1199 | } else {
1200 | out.NewMembers = (out.NewMembers)[:0]
1201 | }
1202 | for !in.IsDelim(']') {
1203 | var v15 Contact
1204 | (v15).UnmarshalEasyJSON(in)
1205 | out.NewMembers = append(out.NewMembers, v15)
1206 | in.WantComma()
1207 | }
1208 | in.Delim(']')
1209 | }
1210 | case "addedBy":
1211 | (out.AddedBy).UnmarshalEasyJSON(in)
1212 | case "removedBy":
1213 | (out.RemovedBy).UnmarshalEasyJSON(in)
1214 | case "msgId":
1215 | out.MsgID = string(in.String())
1216 | case "chat":
1217 | (out.Chat).UnmarshalEasyJSON(in)
1218 | case "from":
1219 | (out.From).UnmarshalEasyJSON(in)
1220 | case "text":
1221 | out.Text = string(in.String())
1222 | case "timestamp":
1223 | out.Timestamp = int(in.Int())
1224 | case "parent_topic":
1225 | if in.IsNull() {
1226 | in.Skip()
1227 | out.ParentMessage = nil
1228 | } else {
1229 | if out.ParentMessage == nil {
1230 | out.ParentMessage = new(ParentMessage)
1231 | }
1232 | (*out.ParentMessage).UnmarshalEasyJSON(in)
1233 | }
1234 | default:
1235 | in.SkipRecursive()
1236 | }
1237 | in.WantComma()
1238 | }
1239 | in.Delim('}')
1240 | if isTopLevel {
1241 | in.Consumed()
1242 | }
1243 | }
1244 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang13(out *jwriter.Writer, in EventPayload) {
1245 | out.RawByte('{')
1246 | first := true
1247 | _ = first
1248 | {
1249 | const prefix string = ",\"parts\":"
1250 | out.RawString(prefix[1:])
1251 | if in.Parts == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
1252 | out.RawString("null")
1253 | } else {
1254 | out.RawByte('[')
1255 | for v16, v17 := range in.Parts {
1256 | if v16 > 0 {
1257 | out.RawByte(',')
1258 | }
1259 | (v17).MarshalEasyJSON(out)
1260 | }
1261 | out.RawByte(']')
1262 | }
1263 | }
1264 | {
1265 | const prefix string = ",\"queryId\":"
1266 | out.RawString(prefix)
1267 | out.String(string(in.QueryID))
1268 | }
1269 | {
1270 | const prefix string = ",\"message\":"
1271 | out.RawString(prefix)
1272 | (in.CallbackMsg).MarshalEasyJSON(out)
1273 | }
1274 | {
1275 | const prefix string = ",\"callbackData\":"
1276 | out.RawString(prefix)
1277 | out.String(string(in.CallbackData))
1278 | }
1279 | {
1280 | const prefix string = ",\"leftMembers\":"
1281 | out.RawString(prefix)
1282 | if in.LeftMembers == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
1283 | out.RawString("null")
1284 | } else {
1285 | out.RawByte('[')
1286 | for v18, v19 := range in.LeftMembers {
1287 | if v18 > 0 {
1288 | out.RawByte(',')
1289 | }
1290 | (v19).MarshalEasyJSON(out)
1291 | }
1292 | out.RawByte(']')
1293 | }
1294 | }
1295 | {
1296 | const prefix string = ",\"newMembers\":"
1297 | out.RawString(prefix)
1298 | if in.NewMembers == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
1299 | out.RawString("null")
1300 | } else {
1301 | out.RawByte('[')
1302 | for v20, v21 := range in.NewMembers {
1303 | if v20 > 0 {
1304 | out.RawByte(',')
1305 | }
1306 | (v21).MarshalEasyJSON(out)
1307 | }
1308 | out.RawByte(']')
1309 | }
1310 | }
1311 | {
1312 | const prefix string = ",\"addedBy\":"
1313 | out.RawString(prefix)
1314 | (in.AddedBy).MarshalEasyJSON(out)
1315 | }
1316 | {
1317 | const prefix string = ",\"removedBy\":"
1318 | out.RawString(prefix)
1319 | (in.RemovedBy).MarshalEasyJSON(out)
1320 | }
1321 | {
1322 | const prefix string = ",\"msgId\":"
1323 | out.RawString(prefix)
1324 | out.String(string(in.MsgID))
1325 | }
1326 | {
1327 | const prefix string = ",\"chat\":"
1328 | out.RawString(prefix)
1329 | (in.Chat).MarshalEasyJSON(out)
1330 | }
1331 | {
1332 | const prefix string = ",\"from\":"
1333 | out.RawString(prefix)
1334 | (in.From).MarshalEasyJSON(out)
1335 | }
1336 | {
1337 | const prefix string = ",\"text\":"
1338 | out.RawString(prefix)
1339 | out.String(string(in.Text))
1340 | }
1341 | {
1342 | const prefix string = ",\"timestamp\":"
1343 | out.RawString(prefix)
1344 | out.Int(int(in.Timestamp))
1345 | }
1346 | {
1347 | const prefix string = ",\"parent_topic\":"
1348 | out.RawString(prefix)
1349 | if in.ParentMessage == nil {
1350 | out.RawString("null")
1351 | } else {
1352 | (*in.ParentMessage).MarshalEasyJSON(out)
1353 | }
1354 | }
1355 | out.RawByte('}')
1356 | }
1357 |
1358 | // MarshalJSON supports json.Marshaler interface
1359 | func (v EventPayload) MarshalJSON() ([]byte, error) {
1360 | w := jwriter.Writer{}
1361 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang13(&w, v)
1362 | return w.Buffer.BuildBytes(), w.Error
1363 | }
1364 |
1365 | // MarshalEasyJSON supports easyjson.Marshaler interface
1366 | func (v EventPayload) MarshalEasyJSON(w *jwriter.Writer) {
1367 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang13(w, v)
1368 | }
1369 |
1370 | // UnmarshalJSON supports json.Unmarshaler interface
1371 | func (v *EventPayload) UnmarshalJSON(data []byte) error {
1372 | r := jlexer.Lexer{Data: data}
1373 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang13(&r, v)
1374 | return r.Error()
1375 | }
1376 |
1377 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1378 | func (v *EventPayload) UnmarshalEasyJSON(l *jlexer.Lexer) {
1379 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang13(l, v)
1380 | }
1381 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang14(in *jlexer.Lexer, out *Event) {
1382 | isTopLevel := in.IsStart()
1383 | if in.IsNull() {
1384 | if isTopLevel {
1385 | in.Consumed()
1386 | }
1387 | in.Skip()
1388 | return
1389 | }
1390 | in.Delim('{')
1391 | for !in.IsDelim('}') {
1392 | key := in.UnsafeFieldName(false)
1393 | in.WantColon()
1394 | if in.IsNull() {
1395 | in.Skip()
1396 | in.WantComma()
1397 | continue
1398 | }
1399 | switch key {
1400 | case "eventId":
1401 | out.EventID = int(in.Int())
1402 | case "type":
1403 | out.Type = EventType(in.String())
1404 | case "payload":
1405 | (out.Payload).UnmarshalEasyJSON(in)
1406 | default:
1407 | in.SkipRecursive()
1408 | }
1409 | in.WantComma()
1410 | }
1411 | in.Delim('}')
1412 | if isTopLevel {
1413 | in.Consumed()
1414 | }
1415 | }
1416 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang14(out *jwriter.Writer, in Event) {
1417 | out.RawByte('{')
1418 | first := true
1419 | _ = first
1420 | {
1421 | const prefix string = ",\"eventId\":"
1422 | out.RawString(prefix[1:])
1423 | out.Int(int(in.EventID))
1424 | }
1425 | {
1426 | const prefix string = ",\"type\":"
1427 | out.RawString(prefix)
1428 | out.String(string(in.Type))
1429 | }
1430 | {
1431 | const prefix string = ",\"payload\":"
1432 | out.RawString(prefix)
1433 | (in.Payload).MarshalEasyJSON(out)
1434 | }
1435 | out.RawByte('}')
1436 | }
1437 |
1438 | // MarshalJSON supports json.Marshaler interface
1439 | func (v Event) MarshalJSON() ([]byte, error) {
1440 | w := jwriter.Writer{}
1441 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang14(&w, v)
1442 | return w.Buffer.BuildBytes(), w.Error
1443 | }
1444 |
1445 | // MarshalEasyJSON supports easyjson.Marshaler interface
1446 | func (v Event) MarshalEasyJSON(w *jwriter.Writer) {
1447 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang14(w, v)
1448 | }
1449 |
1450 | // UnmarshalJSON supports json.Unmarshaler interface
1451 | func (v *Event) UnmarshalJSON(data []byte) error {
1452 | r := jlexer.Lexer{Data: data}
1453 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang14(&r, v)
1454 | return r.Error()
1455 | }
1456 |
1457 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1458 | func (v *Event) UnmarshalEasyJSON(l *jlexer.Lexer) {
1459 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang14(l, v)
1460 | }
1461 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang15(in *jlexer.Lexer, out *Contact) {
1462 | isTopLevel := in.IsStart()
1463 | if in.IsNull() {
1464 | if isTopLevel {
1465 | in.Consumed()
1466 | }
1467 | in.Skip()
1468 | return
1469 | }
1470 | in.Delim('{')
1471 | for !in.IsDelim('}') {
1472 | key := in.UnsafeFieldName(false)
1473 | in.WantColon()
1474 | if in.IsNull() {
1475 | in.Skip()
1476 | in.WantComma()
1477 | continue
1478 | }
1479 | switch key {
1480 | case "firstName":
1481 | out.FirstName = string(in.String())
1482 | case "lastName":
1483 | out.LastName = string(in.String())
1484 | case "userId":
1485 | out.ID = string(in.String())
1486 | default:
1487 | in.SkipRecursive()
1488 | }
1489 | in.WantComma()
1490 | }
1491 | in.Delim('}')
1492 | if isTopLevel {
1493 | in.Consumed()
1494 | }
1495 | }
1496 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang15(out *jwriter.Writer, in Contact) {
1497 | out.RawByte('{')
1498 | first := true
1499 | _ = first
1500 | {
1501 | const prefix string = ",\"firstName\":"
1502 | out.RawString(prefix[1:])
1503 | out.String(string(in.FirstName))
1504 | }
1505 | {
1506 | const prefix string = ",\"lastName\":"
1507 | out.RawString(prefix)
1508 | out.String(string(in.LastName))
1509 | }
1510 | {
1511 | const prefix string = ",\"userId\":"
1512 | out.RawString(prefix)
1513 | out.String(string(in.ID))
1514 | }
1515 | out.RawByte('}')
1516 | }
1517 |
1518 | // MarshalJSON supports json.Marshaler interface
1519 | func (v Contact) MarshalJSON() ([]byte, error) {
1520 | w := jwriter.Writer{}
1521 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang15(&w, v)
1522 | return w.Buffer.BuildBytes(), w.Error
1523 | }
1524 |
1525 | // MarshalEasyJSON supports easyjson.Marshaler interface
1526 | func (v Contact) MarshalEasyJSON(w *jwriter.Writer) {
1527 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang15(w, v)
1528 | }
1529 |
1530 | // UnmarshalJSON supports json.Unmarshaler interface
1531 | func (v *Contact) UnmarshalJSON(data []byte) error {
1532 | r := jlexer.Lexer{Data: data}
1533 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang15(&r, v)
1534 | return r.Error()
1535 | }
1536 |
1537 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1538 | func (v *Contact) UnmarshalEasyJSON(l *jlexer.Lexer) {
1539 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang15(l, v)
1540 | }
1541 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang16(in *jlexer.Lexer, out *ChatMember) {
1542 | isTopLevel := in.IsStart()
1543 | if in.IsNull() {
1544 | if isTopLevel {
1545 | in.Consumed()
1546 | }
1547 | in.Skip()
1548 | return
1549 | }
1550 | in.Delim('{')
1551 | for !in.IsDelim('}') {
1552 | key := in.UnsafeFieldName(false)
1553 | in.WantColon()
1554 | if in.IsNull() {
1555 | in.Skip()
1556 | in.WantComma()
1557 | continue
1558 | }
1559 | switch key {
1560 | case "creator":
1561 | out.Creator = bool(in.Bool())
1562 | case "admin":
1563 | out.Admin = bool(in.Bool())
1564 | case "userId":
1565 | out.ID = string(in.String())
1566 | default:
1567 | in.SkipRecursive()
1568 | }
1569 | in.WantComma()
1570 | }
1571 | in.Delim('}')
1572 | if isTopLevel {
1573 | in.Consumed()
1574 | }
1575 | }
1576 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang16(out *jwriter.Writer, in ChatMember) {
1577 | out.RawByte('{')
1578 | first := true
1579 | _ = first
1580 | {
1581 | const prefix string = ",\"creator\":"
1582 | out.RawString(prefix[1:])
1583 | out.Bool(bool(in.Creator))
1584 | }
1585 | {
1586 | const prefix string = ",\"admin\":"
1587 | out.RawString(prefix)
1588 | out.Bool(bool(in.Admin))
1589 | }
1590 | {
1591 | const prefix string = ",\"userId\":"
1592 | out.RawString(prefix)
1593 | out.String(string(in.ID))
1594 | }
1595 | out.RawByte('}')
1596 | }
1597 |
1598 | // MarshalJSON supports json.Marshaler interface
1599 | func (v ChatMember) MarshalJSON() ([]byte, error) {
1600 | w := jwriter.Writer{}
1601 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang16(&w, v)
1602 | return w.Buffer.BuildBytes(), w.Error
1603 | }
1604 |
1605 | // MarshalEasyJSON supports easyjson.Marshaler interface
1606 | func (v ChatMember) MarshalEasyJSON(w *jwriter.Writer) {
1607 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang16(w, v)
1608 | }
1609 |
1610 | // UnmarshalJSON supports json.Unmarshaler interface
1611 | func (v *ChatMember) UnmarshalJSON(data []byte) error {
1612 | r := jlexer.Lexer{Data: data}
1613 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang16(&r, v)
1614 | return r.Error()
1615 | }
1616 |
1617 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1618 | func (v *ChatMember) UnmarshalEasyJSON(l *jlexer.Lexer) {
1619 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang16(l, v)
1620 | }
1621 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang17(in *jlexer.Lexer, out *BotInfo) {
1622 | isTopLevel := in.IsStart()
1623 | if in.IsNull() {
1624 | if isTopLevel {
1625 | in.Consumed()
1626 | }
1627 | in.Skip()
1628 | return
1629 | }
1630 | in.Delim('{')
1631 | for !in.IsDelim('}') {
1632 | key := in.UnsafeFieldName(false)
1633 | in.WantColon()
1634 | if in.IsNull() {
1635 | in.Skip()
1636 | in.WantComma()
1637 | continue
1638 | }
1639 | switch key {
1640 | case "nick":
1641 | out.Nick = string(in.String())
1642 | case "firstName":
1643 | out.FirstName = string(in.String())
1644 | case "about":
1645 | out.About = string(in.String())
1646 | case "photo":
1647 | if in.IsNull() {
1648 | in.Skip()
1649 | out.Photo = nil
1650 | } else {
1651 | in.Delim('[')
1652 | if out.Photo == nil {
1653 | if !in.IsDelim(']') {
1654 | out.Photo = make([]Photo, 0, 4)
1655 | } else {
1656 | out.Photo = []Photo{}
1657 | }
1658 | } else {
1659 | out.Photo = (out.Photo)[:0]
1660 | }
1661 | for !in.IsDelim(']') {
1662 | var v22 Photo
1663 | (v22).UnmarshalEasyJSON(in)
1664 | out.Photo = append(out.Photo, v22)
1665 | in.WantComma()
1666 | }
1667 | in.Delim(']')
1668 | }
1669 | case "userId":
1670 | out.ID = string(in.String())
1671 | default:
1672 | in.SkipRecursive()
1673 | }
1674 | in.WantComma()
1675 | }
1676 | in.Delim('}')
1677 | if isTopLevel {
1678 | in.Consumed()
1679 | }
1680 | }
1681 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang17(out *jwriter.Writer, in BotInfo) {
1682 | out.RawByte('{')
1683 | first := true
1684 | _ = first
1685 | {
1686 | const prefix string = ",\"nick\":"
1687 | out.RawString(prefix[1:])
1688 | out.String(string(in.Nick))
1689 | }
1690 | {
1691 | const prefix string = ",\"firstName\":"
1692 | out.RawString(prefix)
1693 | out.String(string(in.FirstName))
1694 | }
1695 | {
1696 | const prefix string = ",\"about\":"
1697 | out.RawString(prefix)
1698 | out.String(string(in.About))
1699 | }
1700 | {
1701 | const prefix string = ",\"photo\":"
1702 | out.RawString(prefix)
1703 | if in.Photo == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
1704 | out.RawString("null")
1705 | } else {
1706 | out.RawByte('[')
1707 | for v23, v24 := range in.Photo {
1708 | if v23 > 0 {
1709 | out.RawByte(',')
1710 | }
1711 | (v24).MarshalEasyJSON(out)
1712 | }
1713 | out.RawByte(']')
1714 | }
1715 | }
1716 | {
1717 | const prefix string = ",\"userId\":"
1718 | out.RawString(prefix)
1719 | out.String(string(in.ID))
1720 | }
1721 | out.RawByte('}')
1722 | }
1723 |
1724 | // MarshalJSON supports json.Marshaler interface
1725 | func (v BotInfo) MarshalJSON() ([]byte, error) {
1726 | w := jwriter.Writer{}
1727 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang17(&w, v)
1728 | return w.Buffer.BuildBytes(), w.Error
1729 | }
1730 |
1731 | // MarshalEasyJSON supports easyjson.Marshaler interface
1732 | func (v BotInfo) MarshalEasyJSON(w *jwriter.Writer) {
1733 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang17(w, v)
1734 | }
1735 |
1736 | // UnmarshalJSON supports json.Unmarshaler interface
1737 | func (v *BotInfo) UnmarshalJSON(data []byte) error {
1738 | r := jlexer.Lexer{Data: data}
1739 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang17(&r, v)
1740 | return r.Error()
1741 | }
1742 |
1743 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1744 | func (v *BotInfo) UnmarshalEasyJSON(l *jlexer.Lexer) {
1745 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang17(l, v)
1746 | }
1747 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang18(in *jlexer.Lexer, out *BaseEventPayload) {
1748 | isTopLevel := in.IsStart()
1749 | if in.IsNull() {
1750 | if isTopLevel {
1751 | in.Consumed()
1752 | }
1753 | in.Skip()
1754 | return
1755 | }
1756 | in.Delim('{')
1757 | for !in.IsDelim('}') {
1758 | key := in.UnsafeFieldName(false)
1759 | in.WantColon()
1760 | if in.IsNull() {
1761 | in.Skip()
1762 | in.WantComma()
1763 | continue
1764 | }
1765 | switch key {
1766 | case "msgId":
1767 | out.MsgID = string(in.String())
1768 | case "chat":
1769 | (out.Chat).UnmarshalEasyJSON(in)
1770 | case "from":
1771 | (out.From).UnmarshalEasyJSON(in)
1772 | case "text":
1773 | out.Text = string(in.String())
1774 | case "timestamp":
1775 | out.Timestamp = int(in.Int())
1776 | case "parent_topic":
1777 | if in.IsNull() {
1778 | in.Skip()
1779 | out.ParentMessage = nil
1780 | } else {
1781 | if out.ParentMessage == nil {
1782 | out.ParentMessage = new(ParentMessage)
1783 | }
1784 | (*out.ParentMessage).UnmarshalEasyJSON(in)
1785 | }
1786 | default:
1787 | in.SkipRecursive()
1788 | }
1789 | in.WantComma()
1790 | }
1791 | in.Delim('}')
1792 | if isTopLevel {
1793 | in.Consumed()
1794 | }
1795 | }
1796 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang18(out *jwriter.Writer, in BaseEventPayload) {
1797 | out.RawByte('{')
1798 | first := true
1799 | _ = first
1800 | {
1801 | const prefix string = ",\"msgId\":"
1802 | out.RawString(prefix[1:])
1803 | out.String(string(in.MsgID))
1804 | }
1805 | {
1806 | const prefix string = ",\"chat\":"
1807 | out.RawString(prefix)
1808 | (in.Chat).MarshalEasyJSON(out)
1809 | }
1810 | {
1811 | const prefix string = ",\"from\":"
1812 | out.RawString(prefix)
1813 | (in.From).MarshalEasyJSON(out)
1814 | }
1815 | {
1816 | const prefix string = ",\"text\":"
1817 | out.RawString(prefix)
1818 | out.String(string(in.Text))
1819 | }
1820 | {
1821 | const prefix string = ",\"timestamp\":"
1822 | out.RawString(prefix)
1823 | out.Int(int(in.Timestamp))
1824 | }
1825 | {
1826 | const prefix string = ",\"parent_topic\":"
1827 | out.RawString(prefix)
1828 | if in.ParentMessage == nil {
1829 | out.RawString("null")
1830 | } else {
1831 | (*in.ParentMessage).MarshalEasyJSON(out)
1832 | }
1833 | }
1834 | out.RawByte('}')
1835 | }
1836 |
1837 | // MarshalJSON supports json.Marshaler interface
1838 | func (v BaseEventPayload) MarshalJSON() ([]byte, error) {
1839 | w := jwriter.Writer{}
1840 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang18(&w, v)
1841 | return w.Buffer.BuildBytes(), w.Error
1842 | }
1843 |
1844 | // MarshalEasyJSON supports easyjson.Marshaler interface
1845 | func (v BaseEventPayload) MarshalEasyJSON(w *jwriter.Writer) {
1846 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang18(w, v)
1847 | }
1848 |
1849 | // UnmarshalJSON supports json.Unmarshaler interface
1850 | func (v *BaseEventPayload) UnmarshalJSON(data []byte) error {
1851 | r := jlexer.Lexer{Data: data}
1852 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang18(&r, v)
1853 | return r.Error()
1854 | }
1855 |
1856 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1857 | func (v *BaseEventPayload) UnmarshalEasyJSON(l *jlexer.Lexer) {
1858 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang18(l, v)
1859 | }
1860 | func easyjson6601e8cdDecodeGithubComMailRuImBotGolang19(in *jlexer.Lexer, out *AdminsListResponse) {
1861 | isTopLevel := in.IsStart()
1862 | if in.IsNull() {
1863 | if isTopLevel {
1864 | in.Consumed()
1865 | }
1866 | in.Skip()
1867 | return
1868 | }
1869 | in.Delim('{')
1870 | for !in.IsDelim('}') {
1871 | key := in.UnsafeFieldName(false)
1872 | in.WantColon()
1873 | if in.IsNull() {
1874 | in.Skip()
1875 | in.WantComma()
1876 | continue
1877 | }
1878 | switch key {
1879 | case "admins":
1880 | if in.IsNull() {
1881 | in.Skip()
1882 | out.List = nil
1883 | } else {
1884 | in.Delim('[')
1885 | if out.List == nil {
1886 | if !in.IsDelim(']') {
1887 | out.List = make([]ChatMember, 0, 2)
1888 | } else {
1889 | out.List = []ChatMember{}
1890 | }
1891 | } else {
1892 | out.List = (out.List)[:0]
1893 | }
1894 | for !in.IsDelim(']') {
1895 | var v25 ChatMember
1896 | (v25).UnmarshalEasyJSON(in)
1897 | out.List = append(out.List, v25)
1898 | in.WantComma()
1899 | }
1900 | in.Delim(']')
1901 | }
1902 | default:
1903 | in.SkipRecursive()
1904 | }
1905 | in.WantComma()
1906 | }
1907 | in.Delim('}')
1908 | if isTopLevel {
1909 | in.Consumed()
1910 | }
1911 | }
1912 | func easyjson6601e8cdEncodeGithubComMailRuImBotGolang19(out *jwriter.Writer, in AdminsListResponse) {
1913 | out.RawByte('{')
1914 | first := true
1915 | _ = first
1916 | {
1917 | const prefix string = ",\"admins\":"
1918 | out.RawString(prefix[1:])
1919 | if in.List == nil && (out.Flags&jwriter.NilSliceAsEmpty) == 0 {
1920 | out.RawString("null")
1921 | } else {
1922 | out.RawByte('[')
1923 | for v26, v27 := range in.List {
1924 | if v26 > 0 {
1925 | out.RawByte(',')
1926 | }
1927 | (v27).MarshalEasyJSON(out)
1928 | }
1929 | out.RawByte(']')
1930 | }
1931 | }
1932 | out.RawByte('}')
1933 | }
1934 |
1935 | // MarshalJSON supports json.Marshaler interface
1936 | func (v AdminsListResponse) MarshalJSON() ([]byte, error) {
1937 | w := jwriter.Writer{}
1938 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang19(&w, v)
1939 | return w.Buffer.BuildBytes(), w.Error
1940 | }
1941 |
1942 | // MarshalEasyJSON supports easyjson.Marshaler interface
1943 | func (v AdminsListResponse) MarshalEasyJSON(w *jwriter.Writer) {
1944 | easyjson6601e8cdEncodeGithubComMailRuImBotGolang19(w, v)
1945 | }
1946 |
1947 | // UnmarshalJSON supports json.Unmarshaler interface
1948 | func (v *AdminsListResponse) UnmarshalJSON(data []byte) error {
1949 | r := jlexer.Lexer{Data: data}
1950 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang19(&r, v)
1951 | return r.Error()
1952 | }
1953 |
1954 | // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
1955 | func (v *AdminsListResponse) UnmarshalEasyJSON(l *jlexer.Lexer) {
1956 | easyjson6601e8cdDecodeGithubComMailRuImBotGolang19(l, v)
1957 | }
1958 |
--------------------------------------------------------------------------------