@@ -17,14 +17,20 @@ import (
1717 "time"
1818)
1919
20+ // HTTPClient is the type needed for the bot to perform HTTP requests.
21+ type HTTPClient interface {
22+ Do (req * http.Request ) (* http.Response , error )
23+ PostForm (url string , data url.Values ) (* http.Response , error )
24+ }
25+
2026// BotAPI allows you to interact with the Telegram Bot API.
2127type BotAPI struct {
2228 Token string `json:"token"`
2329 Debug bool `json:"debug"`
2430 Buffer int `json:"buffer"`
2531
26- Self User `json:"-"`
27- Client * http. Client `json:"-"`
32+ Self User `json:"-"`
33+ Client HTTPClient `json:"-"`
2834 shutdownChannel chan interface {}
2935
3036 apiEndpoint string
@@ -34,21 +40,29 @@ type BotAPI struct {
3440//
3541// It requires a token, provided by @BotFather on Telegram.
3642func NewBotAPI (token string ) (* BotAPI , error ) {
37- return NewBotAPIWithClient (token , & http.Client {})
43+ return NewBotAPIWithClient (token , APIEndpoint , & http.Client {})
44+ }
45+
46+ // NewBotAPIWithAPIEndpoint creates a new BotAPI instance
47+ // and allows you to pass API endpoint.
48+ //
49+ // It requires a token, provided by @BotFather on Telegram and API endpoint.
50+ func NewBotAPIWithAPIEndpoint (token , apiEndpoint string ) (* BotAPI , error ) {
51+ return NewBotAPIWithClient (token , apiEndpoint , & http.Client {})
3852}
3953
4054// NewBotAPIWithClient creates a new BotAPI instance
4155// and allows you to pass a http.Client.
4256//
43- // It requires a token, provided by @BotFather on Telegram.
44- func NewBotAPIWithClient (token string , client * http. Client ) (* BotAPI , error ) {
57+ // It requires a token, provided by @BotFather on Telegram and API endpoint .
58+ func NewBotAPIWithClient (token , apiEndpoint string , client HTTPClient ) (* BotAPI , error ) {
4559 bot := & BotAPI {
4660 Token : token ,
4761 Client : client ,
4862 Buffer : 100 ,
4963 shutdownChannel : make (chan interface {}),
5064
51- apiEndpoint : APIEndpoint ,
65+ apiEndpoint : apiEndpoint ,
5266 }
5367
5468 self , err := bot .GetMe ()
@@ -411,7 +425,7 @@ func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
411425// GetUpdates fetches updates.
412426// If a WebHook is set, this will not return any data!
413427//
414- // Offset, Limit, and Timeout are optional.
428+ // Offset, Limit, Timeout, and AllowedUpdates are optional.
415429// To avoid stale items, set Offset to one higher than the previous item.
416430// Set Timeout to a large number to reduce requests so you can get updates
417431// instantly instead of having to wait between requests.
@@ -449,6 +463,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel {
449463 for {
450464 select {
451465 case <- bot .shutdownChannel :
466+ close (ch )
452467 return
453468 default :
454469 }
@@ -487,21 +502,35 @@ func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
487502 ch := make (chan Update , bot .Buffer )
488503
489504 http .HandleFunc (pattern , func (w http.ResponseWriter , r * http.Request ) {
490- ch <- bot .HandleUpdate (w , r )
505+ update , err := bot .HandleUpdate (r )
506+ if err != nil {
507+ errMsg , _ := json .Marshal (map [string ]string {"error" : err .Error ()})
508+ w .WriteHeader (http .StatusBadRequest )
509+ w .Header ().Set ("Content-Type" , "application/json" )
510+ _ , _ = w .Write (errMsg )
511+ return
512+ }
513+
514+ ch <- * update
491515 })
492516
493517 return ch
494518}
495519
496520// HandleUpdate parses and returns update received via webhook
497- func (bot * BotAPI ) HandleUpdate (res http.ResponseWriter , req * http.Request ) Update {
498- bytes , _ := ioutil .ReadAll (req .Body )
499- req .Body .Close ()
521+ func (bot * BotAPI ) HandleUpdate (r * http.Request ) (* Update , error ) {
522+ if r .Method != http .MethodPost {
523+ err := errors .New ("wrong HTTP method required POST" )
524+ return nil , err
525+ }
500526
501527 var update Update
502- json .Unmarshal (bytes , & update )
528+ err := json .NewDecoder (r .Body ).Decode (& update )
529+ if err != nil {
530+ return nil , err
531+ }
503532
504- return update
533+ return & update , nil
505534}
506535
507536// WriteToHTTPResponse writes the request to the HTTP ResponseWriter.
@@ -651,3 +680,23 @@ func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) {
651680
652681 return commands , err
653682}
683+
684+ // CopyMessage copy messages of any kind. The method is analogous to the method
685+ // forwardMessage, but the copied message doesn't have a link to the original
686+ // message. Returns the MessageID of the sent message on success.
687+ func (bot * BotAPI ) CopyMessage (config CopyMessageConfig ) (MessageID , error ) {
688+ params , err := config .params ()
689+ if err != nil {
690+ return MessageID {}, err
691+ }
692+
693+ resp , err := bot .MakeRequest (config .method (), params )
694+ if err != nil {
695+ return MessageID {}, err
696+ }
697+
698+ var messageID MessageID
699+ err = json .Unmarshal (resp .Result , & messageID )
700+
701+ return messageID , err
702+ }
0 commit comments