Skip to content

Commit f3a33ae

Browse files
author
Syfaro
committed
Add support for games, among other updates.
1 parent a7f48eb commit f3a33ae

File tree

3 files changed

+216
-18
lines changed

3 files changed

+216
-18
lines changed

bot.go

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,17 @@ func (bot *BotAPI) makeMessageRequest(endpoint string, params url.Values) (Messa
105105
//
106106
// Requires the parameter to hold the file not be in the params.
107107
// File should be a string to a file path, a FileBytes struct,
108-
// or a FileReader struct.
108+
// a FileReader struct, or a url.URL.
109109
//
110110
// Note that if your FileReader has a size set to -1, it will read
111111
// the file into memory to calculate a size.
112112
func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldname string, file interface{}) (APIResponse, error) {
113113
ms := multipartstreamer.New()
114-
ms.WriteFields(params)
115114

116115
switch f := file.(type) {
117116
case string:
117+
ms.WriteFields(params)
118+
118119
fileHandle, err := os.Open(f)
119120
if err != nil {
120121
return APIResponse{}, err
@@ -128,9 +129,13 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
128129

129130
ms.WriteReader(fieldname, fileHandle.Name(), fi.Size(), fileHandle)
130131
case FileBytes:
132+
ms.WriteFields(params)
133+
131134
buf := bytes.NewBuffer(f.Bytes)
132135
ms.WriteReader(fieldname, f.Name, int64(len(f.Bytes)), buf)
133136
case FileReader:
137+
ms.WriteFields(params)
138+
134139
if f.Size != -1 {
135140
ms.WriteReader(fieldname, f.Name, f.Size, f.Reader)
136141

@@ -145,6 +150,10 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
145150
buf := bytes.NewBuffer(data)
146151

147152
ms.WriteReader(fieldname, f.Name, int64(len(data)), buf)
153+
case url.URL:
154+
params[fieldname] = f.String()
155+
156+
ms.WriteFields(params)
148157
default:
149158
return APIResponse{}, errors.New(ErrBadFileType)
150159
}
@@ -424,6 +433,20 @@ func (bot *BotAPI) SetWebhook(config WebhookConfig) (APIResponse, error) {
424433
return apiResp, nil
425434
}
426435

436+
// GetWebhookInfo allows you to fetch information about a webhook and if
437+
// one currently is set, along with pending update count and error messages.
438+
func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) {
439+
resp, err := bot.MakeRequest("getWebhookInfo", url.Values{})
440+
if err != nil {
441+
return WebhookInfo{}, err
442+
}
443+
444+
var info WebhookInfo
445+
err = json.Unmarshal(resp.Result, &info)
446+
447+
return info, err
448+
}
449+
427450
// GetUpdatesChan starts and returns a channel for getting updates.
428451
func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (<-chan Update, error) {
429452
updatesChan := make(chan Update, 100)
@@ -495,8 +518,13 @@ func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, erro
495518
v := url.Values{}
496519

497520
v.Add("callback_query_id", config.CallbackQueryID)
498-
v.Add("text", config.Text)
521+
if config.Text != "" {
522+
v.Add("text", config.Text)
523+
}
499524
v.Add("show_alert", strconv.FormatBool(config.ShowAlert))
525+
if config.URL != "" {
526+
v.Add("url", config.URL)
527+
}
500528

501529
bot.debugLog("answerCallbackQuery", v, nil)
502530

@@ -648,3 +676,18 @@ func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error)
648676

649677
return bot.MakeRequest("unbanChatMember", v)
650678
}
679+
680+
// GetGameHighScores allows you to get the high scores for a game.
681+
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
682+
v, _ := config.values()
683+
684+
resp, err := bot.MakeRequest(config.method(), v)
685+
if err != nil {
686+
return []GameHighScore{}, err
687+
}
688+
689+
var highScores []GameHighScore
690+
err = json.Unmarshal(resp.Result, &highScores)
691+
692+
return highScores, err
693+
}

configs.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ func (config PhotoConfig) method() string {
275275
// AudioConfig contains information about a SendAudio request.
276276
type AudioConfig struct {
277277
BaseFile
278+
Caption string
278279
Duration int
279280
Performer string
280281
Title string
@@ -431,6 +432,7 @@ func (config VideoConfig) method() string {
431432
// VoiceConfig contains information about a SendVoice request.
432433
type VoiceConfig struct {
433434
BaseFile
435+
Caption string
434436
Duration int
435437
}
436438

@@ -539,6 +541,90 @@ func (config ContactConfig) method() string {
539541
return "sendContact"
540542
}
541543

544+
// GameConfig allows you to send a game.
545+
type GameConfig struct {
546+
BaseChat
547+
GameShortName string
548+
}
549+
550+
func (config GameConfig) values() (url.Values, error) {
551+
v, _ := config.BaseChat.values()
552+
553+
v.Add("game_short_name", config.GameShortName)
554+
555+
return v, nil
556+
}
557+
558+
func (config GameConfig) method() string {
559+
return "sendGame"
560+
}
561+
562+
// SetGameScoreConfig allows you to update the game score in a chat.
563+
type SetGameScoreConfig struct {
564+
UserID int
565+
Score int
566+
ChatID int
567+
ChannelUsername string
568+
MessageID int
569+
InlineMessageID string
570+
EditMessage bool
571+
}
572+
573+
func (config SetGameScoreConfig) values() (url.Values, error) {
574+
v := url.Values{}
575+
576+
v.Add("user_id", strconv.Itoa(config.UserID))
577+
v.Add("score", strconv.Itoa(config.Score))
578+
if config.InlineMessageID == "" {
579+
if config.ChannelUsername == "" {
580+
v.Add("chat_id", strconv.Itoa(config.ChatID))
581+
} else {
582+
v.Add("chat_id", config.ChannelUsername)
583+
}
584+
v.Add("message_id", strconv.Itoa(config.MessageID))
585+
} else {
586+
v.Add("inline_message_id", config.InlineMessageID)
587+
}
588+
v.Add("edit_message", strconv.FormatBool(config.EditMessage))
589+
590+
return v, nil
591+
}
592+
593+
func (config SetGameScoreConfig) method() string {
594+
return "setGameScore"
595+
}
596+
597+
// GetGameHighScoresConfig allows you to fetch the high scores for a game.
598+
type GetGameHighScoresConfig struct {
599+
UserID int
600+
ChatID int
601+
ChannelUsername string
602+
MessageID int
603+
InlineMessageID string
604+
}
605+
606+
func (config GetGameHighScoresConfig) values() (url.Values, error) {
607+
v := url.Values{}
608+
609+
v.Add("user_id", strconv.Itoa(config.UserID))
610+
if config.InlineMessageID == "" {
611+
if config.ChannelUsername == "" {
612+
v.Add("chat_id", strconv.Itoa(config.ChatID))
613+
} else {
614+
v.Add("chat_id", config.ChannelUsername)
615+
}
616+
v.Add("message_id", strconv.Itoa(config.MessageID))
617+
} else {
618+
v.Add("inline_message_id", config.InlineMessageID)
619+
}
620+
621+
return v, nil
622+
}
623+
624+
func (config GetGameHighScoresConfig) method() string {
625+
return "getGameHighScores"
626+
}
627+
542628
// ChatActionConfig contains information about a SendChatAction request.
543629
type ChatActionConfig struct {
544630
BaseChat
@@ -669,6 +755,7 @@ type CallbackConfig struct {
669755
CallbackQueryID string `json:"callback_query_id"`
670756
Text string `json:"text"`
671757
ShowAlert bool `json:"show_alert"`
758+
URL string `json:"url"`
672759
}
673760

674761
// ChatMemberConfig contains information about a user in a chat for use

types.go

Lines changed: 83 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,17 @@ import (
1212
// APIResponse is a response from the Telegram API with the result
1313
// stored raw.
1414
type APIResponse struct {
15-
Ok bool `json:"ok"`
16-
Result json.RawMessage `json:"result"`
17-
ErrorCode int `json:"error_code"`
18-
Description string `json:"description"`
15+
Ok bool `json:"ok"`
16+
Result json.RawMessage `json:"result"`
17+
ErrorCode int `json:"error_code"`
18+
Description string `json:"description"`
19+
Parameters *ResponseParameters `json:"parameters"`
20+
}
21+
22+
// ResponseParameters are various errors that can be returned in APIResponse.
23+
type ResponseParameters struct {
24+
MigrateToChatID int `json:"migrate_to_chat_id"` // optional
25+
RetryAfter int `json:"retry_after"` // optional
1926
}
2027

2128
// Update is an update response, from GetUpdates.
@@ -61,12 +68,13 @@ type GroupChat struct {
6168

6269
// Chat contains information about the place a message was sent.
6370
type Chat struct {
64-
ID int64 `json:"id"`
65-
Type string `json:"type"`
66-
Title string `json:"title"` // optional
67-
UserName string `json:"username"` // optional
68-
FirstName string `json:"first_name"` // optional
69-
LastName string `json:"last_name"` // optional
71+
ID int64 `json:"id"`
72+
Type string `json:"type"`
73+
Title string `json:"title"` // optional
74+
UserName string `json:"username"` // optional
75+
FirstName string `json:"first_name"` // optional
76+
LastName string `json:"last_name"` // optional
77+
AllMembersAreAdmins bool `json:"all_members_are_administrators"` // optional
7078
}
7179

7280
// IsPrivate returns if the Chat is a private conversation.
@@ -110,6 +118,7 @@ type Message struct {
110118
Entities *[]MessageEntity `json:"entities"` // optional
111119
Audio *Audio `json:"audio"` // optional
112120
Document *Document `json:"document"` // optional
121+
Game *Game `json:"game"` // optional
113122
Photo *[]PhotoSize `json:"photo"` // optional
114123
Sticker *Sticker `json:"sticker"` // optional
115124
Video *Video `json:"video"` // optional
@@ -324,11 +333,15 @@ type InlineKeyboardMarkup struct {
324333
//
325334
// Note that some values are references as even an empty string
326335
// will change behavior.
336+
//
337+
// CallbackGame, if set, MUST be first button in first row.
327338
type InlineKeyboardButton struct {
328-
Text string `json:"text"`
329-
URL *string `json:"url,omitempty"` // optional
330-
CallbackData *string `json:"callback_data,omitempty"` // optional
331-
SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
339+
Text string `json:"text"`
340+
URL *string `json:"url,omitempty"` // optional
341+
CallbackData *string `json:"callback_data,omitempty"` // optional
342+
SwitchInlineQuery *string `json:"switch_inline_query,omitempty"` // optional
343+
SwitchInlineQueryCurrentChat *string `json:"switch_inline_query_current_chat"` // optional
344+
CallbackGame *CallbackGame `json:"callback_game"` // optional
332345
}
333346

334347
// CallbackQuery is data sent when a keyboard button with callback data
@@ -338,7 +351,9 @@ type CallbackQuery struct {
338351
From *User `json:"from"`
339352
Message *Message `json:"message"` // optional
340353
InlineMessageID string `json:"inline_message_id"` // optional
341-
Data string `json:"data"` // optional
354+
ChatInstance string `json:"chat_instance"`
355+
Data string `json:"data"` // optional
356+
GameShortName string `json:"game_short_name"` // optional
342357
}
343358

344359
// ForceReply allows the Bot to have users directly reply to it without
@@ -369,6 +384,49 @@ func (chat ChatMember) HasLeft() bool { return chat.Status == "left" }
369384
// WasKicked returns if the ChatMember was kicked from the chat.
370385
func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" }
371386

387+
// Game is a game within Telegram.
388+
type Game struct {
389+
Title string `json:"title"`
390+
Description string `json:"description"`
391+
Photo []PhotoSize `json:"photo"`
392+
Text string `json:"text"`
393+
TextEntities []MessageEntity `json:"text_entities"`
394+
Animation Animation `json:"animation"`
395+
}
396+
397+
// Animation is a GIF animation demonstrating the game.
398+
type Animation struct {
399+
FileID string `json:"file_id"`
400+
Thumb PhotoSize `json:"thumb"`
401+
FileName string `json:"file_name"`
402+
MimeType string `json:"mime_type"`
403+
FileSize int `json:"file_size"`
404+
}
405+
406+
// GameHighScore is a user's score and position on the leaderboard.
407+
type GameHighScore struct {
408+
Position int `json:"position"`
409+
User User `json:"user"`
410+
Score int `json:"score"`
411+
}
412+
413+
// CallbackGame is for starting a game in an inline keyboard button.
414+
type CallbackGame struct{}
415+
416+
// WebhookInfo is information about a currently set webhook.
417+
type WebhookInfo struct {
418+
URL string `json:"url"`
419+
HasCustomCertificate bool `json:"has_custom_certificate"`
420+
PendingUpdateCount int `json:"pending_update_count"`
421+
LastErrorDate int `json:"last_error_date"` // optional
422+
LastErrorMessage string `json:"last_error_message"` // optional
423+
}
424+
425+
// IsSet returns true if a webhook is currently set.
426+
func (info WebhookInfo) IsSet() bool {
427+
return info.URL != ""
428+
}
429+
372430
// InlineQuery is a Query from Telegram for an inline request.
373431
type InlineQuery struct {
374432
ID string `json:"id"`
@@ -460,6 +518,7 @@ type InlineQueryResultAudio struct {
460518
ID string `json:"id"` // required
461519
URL string `json:"audio_url"` // required
462520
Title string `json:"title"` // required
521+
Caption string `json:"caption"`
463522
Performer string `json:"performer"`
464523
Duration int `json:"audio_duration"`
465524
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
@@ -472,6 +531,7 @@ type InlineQueryResultVoice struct {
472531
ID string `json:"id"` // required
473532
URL string `json:"voice_url"` // required
474533
Title string `json:"title"` // required
534+
Caption string `json:"caption"`
475535
Duration int `json:"voice_duration"`
476536
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
477537
InputMessageContent interface{} `json:"input_message_content,omitempty"`
@@ -507,6 +567,14 @@ type InlineQueryResultLocation struct {
507567
ThumbHeight int `json:"thumb_height"`
508568
}
509569

570+
// InlineQueryResultGame is an inline query response game.
571+
type InlineQueryResultGame struct {
572+
Type string `json:"type"`
573+
ID string `json:"id"`
574+
GameShortName string `json:"game_short_name"`
575+
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup"`
576+
}
577+
510578
// ChosenInlineResult is an inline query result chosen by a User
511579
type ChosenInlineResult struct {
512580
ResultID string `json:"result_id"`

0 commit comments

Comments
 (0)