Merge branch 'master' of https://github.com/go-telegram-bot-api/telegram-bot-api into wehook-validation

This commit is contained in:
Dmitriy Kharchenko 2020-07-21 12:06:24 +03:00
commit 20b57111fc
10 changed files with 367 additions and 55 deletions

125
bot.go
View file

@ -19,14 +19,18 @@ import (
"github.com/technoweenie/multipartstreamer"
)
type HttpClient interface {
Do(req *http.Request) (*http.Response, error)
}
// BotAPI allows you to interact with the Telegram Bot API.
type BotAPI struct {
Token string `json:"token"`
Debug bool `json:"debug"`
Buffer int `json:"buffer"`
Self User `json:"-"`
Client *http.Client `json:"-"`
Self User `json:"-"`
Client HttpClient `json:"-"`
shutdownChannel chan interface{}
apiEndpoint string
@ -36,21 +40,29 @@ type BotAPI struct {
//
// It requires a token, provided by @BotFather on Telegram.
func NewBotAPI(token string) (*BotAPI, error) {
return NewBotAPIWithClient(token, &http.Client{})
return NewBotAPIWithClient(token, APIEndpoint, &http.Client{})
}
// NewBotAPIWithAPIEndpoint creates a new BotAPI instance
// and allows you to pass API endpoint.
//
// It requires a token, provided by @BotFather on Telegram and API endpoint.
func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) {
return NewBotAPIWithClient(token, apiEndpoint, &http.Client{})
}
// NewBotAPIWithClient creates a new BotAPI instance
// and allows you to pass a http.Client.
//
// It requires a token, provided by @BotFather on Telegram.
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
// It requires a token, provided by @BotFather on Telegram and API endpoint.
func NewBotAPIWithClient(token, apiEndpoint string, client HttpClient) (*BotAPI, error) {
bot := &BotAPI{
Token: token,
Client: client,
Buffer: 100,
shutdownChannel: make(chan interface{}),
apiEndpoint: APIEndpoint,
apiEndpoint: apiEndpoint,
}
self, err := bot.GetMe()
@ -63,15 +75,22 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
return bot, nil
}
func (b *BotAPI) SetAPIEndpoint(apiEndpoint string) {
b.apiEndpoint = apiEndpoint
// SetAPIEndpoint add telegram apiEndpont to Bot
func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) {
bot.apiEndpoint = apiEndpoint
}
// MakeRequest makes a request to a specific endpoint with our token.
func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) {
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
resp, err := bot.Client.PostForm(method, params)
req, err := http.NewRequest("POST", method, strings.NewReader(params.Encode()))
if err != nil {
return APIResponse{}, err
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := bot.Client.Do(req)
if err != nil {
return APIResponse{}, err
}
@ -92,7 +111,7 @@ func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse,
if apiResp.Parameters != nil {
parameters = *apiResp.Parameters
}
return apiResp, Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
return apiResp, &Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
}
return apiResp, nil
@ -226,7 +245,11 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
}
if !apiResp.Ok {
return APIResponse{}, errors.New(apiResp.Description)
parameters := ResponseParameters{}
if apiResp.Parameters != nil {
parameters = *apiResp.Parameters
}
return apiResp, Error{Code: apiResp.ErrorCode, Message: apiResp.Description, ResponseParameters: parameters}
}
return apiResp, nil
@ -438,7 +461,7 @@ func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
// RemoveWebhook unsets the webhook.
func (bot *BotAPI) RemoveWebhook() (APIResponse, error) {
return bot.MakeRequest("setWebhook", url.Values{})
return bot.MakeRequest("deleteWebhook", url.Values{})
}
// SetWebhook sets a webhook.
@ -495,6 +518,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
for {
select {
case <-bot.shutdownChannel:
close(ch)
return
default:
}
@ -533,40 +557,46 @@ func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
ch := make(chan Update, bot.Buffer)
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
errMsg, _ := json.Marshal(map[string]string{"error": "Wrong HTTP method, required POST"})
w.WriteHeader(http.StatusMethodNotAllowed)
w.Header().Set("Content-Type", "application/json")
w.Write(errMsg)
return
}
bytes, err := ioutil.ReadAll(r.Body)
update, err := bot.HandleUpdate(r)
if err != nil {
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", "application/json")
w.Write(errMsg)
return
}
r.Body.Close()
var update Update
err = json.Unmarshal(bytes, &update)
if err != nil {
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", "application/json")
w.Write(errMsg)
_, _ = w.Write(errMsg)
return
}
ch <- update
ch <- *update
})
return ch
}
// HandleUpdate parses and returns update received via webhook
func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) {
if r.Method != http.MethodPost {
err := errors.New("wrong HTTP method required POST")
return nil, err
}
payload, err := ioutil.ReadAll(r.Body)
if err != nil {
return nil, err
}
if err := r.Body.Close(); err != nil {
return nil, err
}
var update Update
err = json.Unmarshal(payload, &update)
if err != nil {
return nil, err
}
return &update, nil
}
// AnswerInlineQuery sends a response to an inline query.
//
// Note that you must respond to an inline query within 30 seconds.
@ -762,9 +792,9 @@ func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error)
}
// RestrictChatMember to restrict a user in a supergroup. The bot must be an
//administrator in the supergroup for this to work and must have the
//appropriate admin rights. Pass True for all boolean parameters to lift
//restrictions from a user. Returns True on success.
// administrator in the supergroup for this to work and must have the
// appropriate admin rights. Pass True for all boolean parameters to lift
// restrictions from a user. Returns True on success.
func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) {
v := url.Values{}
@ -884,7 +914,7 @@ func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse
v.Add("pre_checkout_query_id", config.PreCheckoutQueryID)
v.Add("ok", strconv.FormatBool(config.OK))
if config.OK != true {
v.Add("error", config.ErrorMessage)
v.Add("error_message", config.ErrorMessage)
}
bot.debugLog("answerPreCheckoutQuery", v, nil)
@ -996,3 +1026,22 @@ func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, e
return bot.MakeRequest(config.method(), v)
}
// GetStickerSet get a sticker set.
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
v, err := config.values()
if err != nil {
return StickerSet{}, err
}
bot.debugLog(config.method(), v, nil)
res, err := bot.MakeRequest(config.method(), v)
if err != nil {
return StickerSet{}, err
}
stickerSet := StickerSet{}
err = json.Unmarshal(res.Result, &stickerSet)
if err != nil {
return StickerSet{}, err
}
return stickerSet, nil
}