diff --git a/README.md b/README.md index b7a6a12..2fbf760 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,6 @@ -# Golang Telegram bot using the Bot API -A simple Golang bot for the Telegram Bot API +# Golang Telegram bindings for the Bot API -Really simple bot for interacting with the Telegram Bot API, not nearly done yet. Expect frequent breaking changes! +Bindings for interacting with the Telegram Bot API, not nearly done yet. All methods have been added, and all features should be available. If you want a feature that hasn't been added yet, open an issue and I'll see what I can do. - -There's a few plugins in here, named as `plugin_*.go`. - -## Getting started - -After installing all the dependencies, run - -``` -go build -./telegram-bot-api -newbot -``` - -Fill in any asked information, enable whatever plugins, etc. - -## Plugins - -All plugins implement the `Plugin` interface. - -```go -type Plugin interface { - GetName() string - GetCommands() []string - GetHelpText() []string - GotCommand(string, Message, []string) - Setup() -} -``` - -`GetName` should return the plugin's name. This must be unique! - -`GetCommands` should return a slice of strings, each command should look like `/help`, it must have the forward slash! - -`GetHelpText` should return a slice of strings with each command and usage. You many include any number of items in here. - -`GotCommand` is called when a command is executed for this plugin, the parameters are the command name, the Message struct, and a list of arguments passed to the command. The original text is available in the Message struct. - -`Setup` is called when the bot first starts, if it needs any configuration, ask here. - -To add your plugin, you must edit a line of code and then run the `go build` again. - -```go -// current version -plugins = []Plugin{&HelpPlugin{}, &ManagePlugin{}} - -// add your own plugins -plugins = []Plugin{&HelpPlugin{}, &FAPlugin{}, &ManagePlugin{}} -``` diff --git a/bot.go b/bot.go index 4ee0e6a..b037aed 100644 --- a/bot.go +++ b/bot.go @@ -1,128 +1,13 @@ -package main +package tgbotapi -import ( - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "log" - "strings" - "time" -) - -type Config struct { - Token string `json:"token"` - Plugins map[string]string `json:"plugins"` - EnabledPlugins map[string]bool `json:"enabled"` +type BotApi struct { + Token string `json:"token"` + Debug bool `json:"debug"` + Updates chan Update `json:"-"` } -type Plugin interface { - GetName() string - GetCommands() []string - GetHelpText() []string - GotCommand(string, Message, []string) - Setup() -} - -var bot *BotApi -var plugins []Plugin -var config Config -var configPath *string - -func main() { - configPath = flag.String("config", "config.json", "path to config.json") - - flag.Parse() - - data, err := ioutil.ReadFile(*configPath) - if err != nil { - log.Panic(err) - } - - json.Unmarshal(data, &config) - - bot = NewBotApi(BotConfig{ - token: config.Token, - debug: true, - }) - - plugins = []Plugin{&HelpPlugin{}, &FAPlugin{}, &ManagePlugin{}} - - for _, plugin := range plugins { - val, ok := config.EnabledPlugins[plugin.GetName()] - - if !ok { - fmt.Printf("Enable '%s'? [y/N] ", plugin.GetName()) - - var enabled string - fmt.Scanln(&enabled) - - if strings.ToLower(enabled) == "y" { - plugin.Setup() - log.Printf("Plugin '%s' started!\n", plugin.GetName()) - - config.EnabledPlugins[plugin.GetName()] = true - } else { - config.EnabledPlugins[plugin.GetName()] = false - } - } - - if val { - plugin.Setup() - log.Printf("Plugin '%s' started!\n", plugin.GetName()) - } - - saveConfig() - } - - ticker := time.NewTicker(time.Second) - - lastUpdate := 0 - - for range ticker.C { - update := NewUpdate(lastUpdate + 1) - update.Timeout = 30 - - updates, err := bot.getUpdates(update) - - if err != nil { - log.Panic(err) - } - - for _, update := range updates { - lastUpdate = update.UpdateId - - if update.Message.Text == "" { - continue - } - - for _, plugin := range plugins { - val, _ := config.EnabledPlugins[plugin.GetName()] - if !val { - continue - } - - parts := strings.Split(update.Message.Text, " ") - command := parts[0] - - for _, cmd := range plugin.GetCommands() { - if cmd == command { - if bot.config.debug { - log.Printf("'%s' matched plugin '%s'", update.Message.Text, plugin.GetName()) - } - - args := append(parts[:0], parts[1:]...) - - plugin.GotCommand(command, update.Message, args) - } - } - } - } +func NewBotApi(token string) *BotApi { + return &BotApi{ + Token: token, } } - -func saveConfig() { - data, _ := json.MarshalIndent(config, "", " ") - - ioutil.WriteFile(*configPath, data, 0600) -} diff --git a/helpers.go b/helpers.go new file mode 100644 index 0000000..0859cfc --- /dev/null +++ b/helpers.go @@ -0,0 +1,144 @@ +package tgbotapi + +import ( + "net/url" +) + +func NewMessage(chatId int, text string) MessageConfig { + return MessageConfig{ + ChatId: chatId, + Text: text, + DisableWebPagePreview: false, + ReplyToMessageId: 0, + } +} + +func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig { + return ForwardConfig{ + ChatId: chatId, + FromChatId: fromChatId, + MessageId: messageId, + } +} + +func NewPhotoUpload(chatId int, filename string) PhotoConfig { + return PhotoConfig{ + ChatId: chatId, + UseExistingPhoto: false, + FilePath: filename, + } +} + +func NewPhotoShare(chatId int, fileId string) PhotoConfig { + return PhotoConfig{ + ChatId: chatId, + UseExistingPhoto: true, + FileId: fileId, + } +} + +func NewAudioUpload(chatId int, filename string) AudioConfig { + return AudioConfig{ + ChatId: chatId, + UseExistingAudio: false, + FilePath: filename, + } +} + +func NewAudioShare(chatId int, fileId string) AudioConfig { + return AudioConfig{ + ChatId: chatId, + UseExistingAudio: true, + FileId: fileId, + } +} + +func NewDocumentUpload(chatId int, filename string) DocumentConfig { + return DocumentConfig{ + ChatId: chatId, + UseExistingDocument: false, + FilePath: filename, + } +} + +func NewDocumentShare(chatId int, fileId string) DocumentConfig { + return DocumentConfig{ + ChatId: chatId, + UseExistingDocument: true, + FileId: fileId, + } +} + +func NewStickerUpload(chatId int, filename string) StickerConfig { + return StickerConfig{ + ChatId: chatId, + UseExistingSticker: false, + FilePath: filename, + } +} + +func NewStickerShare(chatId int, fileId string) StickerConfig { + return StickerConfig{ + ChatId: chatId, + UseExistingSticker: true, + FileId: fileId, + } +} + +func NewVideoUpload(chatId int, filename string) VideoConfig { + return VideoConfig{ + ChatId: chatId, + UseExistingVideo: false, + FilePath: filename, + } +} + +func NewVideoShare(chatId int, fileId string) VideoConfig { + return VideoConfig{ + ChatId: chatId, + UseExistingVideo: true, + FileId: fileId, + } +} + +func NewLocation(chatId int, latitude float64, longitude float64) LocationConfig { + return LocationConfig{ + ChatId: chatId, + Latitude: latitude, + Longitude: longitude, + ReplyToMessageId: 0, + ReplyMarkup: nil, + } +} + +func NewChatAction(chatId int, action string) ChatActionConfig { + return ChatActionConfig{ + ChatId: chatId, + Action: action, + } +} + +func NewUserProfilePhotos(userId int) UserProfilePhotosConfig { + return UserProfilePhotosConfig{ + UserId: userId, + Offset: 0, + Limit: 0, + } +} + +func NewUpdate(offset int) UpdateConfig { + return UpdateConfig{ + Offset: offset, + Limit: 0, + Timeout: 0, + } +} + +func NewWebhook(link string) WebhookConfig { + u, _ := url.Parse(link) + + return WebhookConfig{ + Url: u, + Clear: false, + } +} diff --git a/methods.go b/methods.go index 9238950..f88c416 100644 --- a/methods.go +++ b/methods.go @@ -1,4 +1,4 @@ -package main +package tgbotapi import ( "bytes" @@ -25,607 +25,6 @@ const ( CHAT_FIND_LOCATION = "find_location" ) -type BotConfig struct { - token string - debug bool -} - -type BotApi struct { - config BotConfig -} - -func NewBotApi(config BotConfig) *BotApi { - return &BotApi{ - config: config, - } -} - -func (bot *BotApi) makeRequest(endpoint string, params url.Values) (ApiResponse, error) { - resp, err := http.PostForm("https://api.telegram.org/bot"+bot.config.token+"/"+endpoint, params) - defer resp.Body.Close() - if err != nil { - return ApiResponse{}, err - } - - bytes, err := ioutil.ReadAll(resp.Body) - if err != nil { - return ApiResponse{}, err - } - - if bot.config.debug { - log.Println(endpoint, string(bytes)) - } - - var apiResp ApiResponse - json.Unmarshal(bytes, &apiResp) - - if !apiResp.Ok { - return ApiResponse{}, errors.New(apiResp.Description) - } - - return apiResp, nil -} - -func (bot *BotApi) uploadFile(endpoint string, params map[string]string, fieldname string, filename string) (ApiResponse, error) { - var b bytes.Buffer - w := multipart.NewWriter(&b) - - f, err := os.Open(filename) - if err != nil { - return ApiResponse{}, err - } - - fw, err := w.CreateFormFile(fieldname, filename) - if err != nil { - return ApiResponse{}, err - } - - if _, err = io.Copy(fw, f); err != nil { - return ApiResponse{}, err - } - - for key, val := range params { - if fw, err = w.CreateFormField(key); err != nil { - return ApiResponse{}, err - } - - if _, err = fw.Write([]byte(val)); err != nil { - return ApiResponse{}, err - } - } - - w.Close() - - req, err := http.NewRequest("POST", "https://api.telegram.org/bot"+bot.config.token+"/"+endpoint, &b) - if err != nil { - return ApiResponse{}, err - } - - req.Header.Set("Content-Type", w.FormDataContentType()) - - client := &http.Client{} - res, err := client.Do(req) - if err != nil { - return ApiResponse{}, err - } - - bytes, err := ioutil.ReadAll(res.Body) - if err != nil { - return ApiResponse{}, err - } - - if bot.config.debug { - log.Println(string(bytes[:])) - } - - var apiResp ApiResponse - json.Unmarshal(bytes, &apiResp) - - return apiResp, nil -} - -func (bot *BotApi) getMe() (User, error) { - resp, err := bot.makeRequest("getMe", nil) - if err != nil { - return User{}, err - } - - var user User - json.Unmarshal(resp.Result, &user) - - if bot.config.debug { - log.Printf("getMe: %+v\n", user) - } - - return user, nil -} - -func (bot *BotApi) sendMessage(config MessageConfig) (Message, error) { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("text", config.Text) - v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview)) - if config.ReplyToMessageId != 0 { - v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - v.Add("reply_markup", string(data)) - } - - resp, err := bot.makeRequest("sendMessage", v) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendMessage req : %+v\n", v) - log.Printf("sendMessage resp: %+v\n", message) - } - - return message, nil -} - -func (bot *BotApi) forwardMessage(config ForwardConfig) (Message, error) { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("from_chat_id", strconv.Itoa(config.FromChatId)) - v.Add("message_id", strconv.Itoa(config.MessageId)) - - resp, err := bot.makeRequest("forwardMessage", v) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("forwardMessage req : %+v\n", v) - log.Printf("forwardMessage resp: %+v\n", message) - } - - return message, nil -} - -func (bot *BotApi) sendPhoto(config PhotoConfig) (Message, error) { - if config.UseExistingPhoto { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("photo", config.FileId) - if config.Caption != "" { - v.Add("caption", config.Caption) - } - if config.ReplyToMessageId != 0 { - v.Add("reply_to_message_id", strconv.Itoa(config.ChatId)) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - v.Add("reply_markup", string(data)) - } - - resp, err := bot.makeRequest("sendPhoto", v) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendPhoto req : %+v\n", v) - log.Printf("sendPhoto resp: %+v\n", message) - } - - return message, nil - } - - params := make(map[string]string) - params["chat_id"] = strconv.Itoa(config.ChatId) - if config.Caption != "" { - params["caption"] = config.Caption - } - if config.ReplyToMessageId != 0 { - params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - params["reply_markup"] = string(data) - } - - resp, err := bot.uploadFile("sendPhoto", params, "photo", config.FilePath) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendPhoto resp: %+v\n", message) - } - - return message, nil -} - -func (bot *BotApi) sendAudio(config AudioConfig) (Message, error) { - if config.UseExistingAudio { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("audio", config.FileId) - if config.ReplyToMessageId != 0 { - v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - v.Add("reply_markup", string(data)) - } - - resp, err := bot.makeRequest("sendAudio", v) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendAudio req : %+v\n", v) - log.Printf("sendAudio resp: %+v\n", message) - } - - return message, nil - } - - params := make(map[string]string) - - params["chat_id"] = strconv.Itoa(config.ChatId) - if config.ReplyToMessageId != 0 { - params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - params["reply_markup"] = string(data) - } - - resp, err := bot.uploadFile("sendAudio", params, "audio", config.FilePath) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendAudio resp: %+v\n", message) - } - - return message, nil -} - -func (bot *BotApi) sendDocument(config DocumentConfig) (Message, error) { - if config.UseExistingDocument { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("document", config.FileId) - if config.ReplyToMessageId != 0 { - v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - v.Add("reply_markup", string(data)) - } - - resp, err := bot.makeRequest("sendDocument", v) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendDocument req : %+v\n", v) - log.Printf("sendDocument resp: %+v\n", message) - } - - return message, nil - } - - params := make(map[string]string) - - params["chat_id"] = strconv.Itoa(config.ChatId) - if config.ReplyToMessageId != 0 { - params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - params["reply_markup"] = string(data) - } - - resp, err := bot.uploadFile("sendDocument", params, "document", config.FilePath) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendDocument resp: %+v\n", message) - } - - return message, nil -} - -func (bot *BotApi) sendSticker(config StickerConfig) (Message, error) { - if config.UseExistingSticker { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("sticker", config.FileId) - if config.ReplyToMessageId != 0 { - v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - v.Add("reply_markup", string(data)) - } - - resp, err := bot.makeRequest("sendSticker", v) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendSticker req : %+v\n", v) - log.Printf("sendSticker resp: %+v\n", message) - } - - return message, nil - } - - params := make(map[string]string) - - params["chat_id"] = strconv.Itoa(config.ChatId) - if config.ReplyToMessageId != 0 { - params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - params["reply_markup"] = string(data) - } - - resp, err := bot.uploadFile("sendSticker", params, "sticker", config.FilePath) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendSticker resp: %+v\n", message) - } - - return message, nil -} - -func (bot *BotApi) sendVideo(config VideoConfig) (Message, error) { - if config.UseExistingVideo { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("video", config.FileId) - if config.ReplyToMessageId != 0 { - v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - v.Add("reply_markup", string(data)) - } - - resp, err := bot.makeRequest("sendVideo", v) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendVideo req : %+v\n", v) - log.Printf("sendVideo resp: %+v\n", message) - } - - return message, nil - } - - params := make(map[string]string) - - params["chat_id"] = strconv.Itoa(config.ChatId) - if config.ReplyToMessageId != 0 { - params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - params["reply_markup"] = string(data) - } - - resp, err := bot.uploadFile("sendVideo", params, "video", config.FilePath) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendVideo resp: %+v\n", message) - } - - return message, nil -} - -func (bot *BotApi) sendLocation(config LocationConfig) (Message, error) { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64)) - v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64)) - if config.ReplyToMessageId != 0 { - v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) - } - if config.ReplyMarkup != nil { - data, err := json.Marshal(config.ReplyMarkup) - if err != nil { - return Message{}, err - } - - v.Add("reply_markup", string(data)) - } - - resp, err := bot.makeRequest("sendLocation", v) - if err != nil { - return Message{}, err - } - - var message Message - json.Unmarshal(resp.Result, &message) - - if bot.config.debug { - log.Printf("sendLocation req : %+v\n", v) - log.Printf("sendLocation resp: %+v\n", message) - } - - return message, nil -} - -func (bot *BotApi) sendChatAction(config ChatActionConfig) error { - v := url.Values{} - v.Add("chat_id", strconv.Itoa(config.ChatId)) - v.Add("action", config.Action) - - _, err := bot.makeRequest("sendChatAction", v) - if err != nil { - return err - } - - return nil -} - -func (bot *BotApi) getUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) { - v := url.Values{} - v.Add("user_id", strconv.Itoa(config.UserId)) - if config.Offset != 0 { - v.Add("offset", strconv.Itoa(config.Offset)) - } - if config.Limit != 0 { - v.Add("limit", strconv.Itoa(config.Limit)) - } - - resp, err := bot.makeRequest("getUserProfilePhotos", v) - if err != nil { - return UserProfilePhotos{}, err - } - - var profilePhotos UserProfilePhotos - json.Unmarshal(resp.Result, &profilePhotos) - - if bot.config.debug { - log.Printf("getUserProfilePhotos req : %+v\n", v) - log.Printf("getUserProfilePhotos resp: %+v\n", profilePhotos) - } - - return profilePhotos, nil -} - -func (bot *BotApi) getUpdates(config UpdateConfig) ([]Update, error) { - v := url.Values{} - if config.Offset > 0 { - v.Add("offset", strconv.Itoa(config.Offset)) - } - if config.Limit > 0 { - v.Add("limit", strconv.Itoa(config.Limit)) - } - if config.Timeout > 0 { - v.Add("timeout", strconv.Itoa(config.Timeout)) - } - - resp, err := bot.makeRequest("getUpdates", v) - if err != nil { - return []Update{}, err - } - - var updates []Update - json.Unmarshal(resp.Result, &updates) - - if bot.config.debug { - log.Printf("getUpdates: %+v\n", updates) - } - - return updates, nil -} - -func (bot *BotApi) setWebhook(v url.Values) error { - _, err := bot.makeRequest("setWebhook", v) - - return err -} - -type UpdateConfig struct { - Offset int - Limit int - Timeout int -} - type MessageConfig struct { ChatId int Text string @@ -705,132 +104,598 @@ type UserProfilePhotosConfig struct { Limit int } -func NewMessage(chatId int, text string) MessageConfig { - return MessageConfig{ - ChatId: chatId, - Text: text, - DisableWebPagePreview: false, - ReplyToMessageId: 0, - } +type UpdateConfig struct { + Offset int + Limit int + Timeout int } -func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig { - return ForwardConfig{ - ChatId: chatId, - FromChatId: fromChatId, - MessageId: messageId, - } +type WebhookConfig struct { + Clear bool + Url *url.URL } -func NewPhotoUpload(chatId int, filename string) PhotoConfig { - return PhotoConfig{ - ChatId: chatId, - UseExistingPhoto: false, - FilePath: filename, +func (bot *BotApi) MakeRequest(endpoint string, params url.Values) (ApiResponse, error) { + resp, err := http.PostForm("https://api.telegram.org/bot"+bot.Token+"/"+endpoint, params) + defer resp.Body.Close() + if err != nil { + return ApiResponse{}, err } + + bytes, err := ioutil.ReadAll(resp.Body) + if err != nil { + return ApiResponse{}, err + } + + if bot.Debug { + log.Println(endpoint, string(bytes)) + } + + var apiResp ApiResponse + json.Unmarshal(bytes, &apiResp) + + if !apiResp.Ok { + return ApiResponse{}, errors.New(apiResp.Description) + } + + return apiResp, nil } -func NewPhotoShare(chatId int, fileId string) PhotoConfig { - return PhotoConfig{ - ChatId: chatId, - UseExistingPhoto: true, - FileId: fileId, +func (bot *BotApi) UploadFile(endpoint string, params map[string]string, fieldname string, filename string) (ApiResponse, error) { + var b bytes.Buffer + w := multipart.NewWriter(&b) + + f, err := os.Open(filename) + if err != nil { + return ApiResponse{}, err } + + fw, err := w.CreateFormFile(fieldname, filename) + if err != nil { + return ApiResponse{}, err + } + + if _, err = io.Copy(fw, f); err != nil { + return ApiResponse{}, err + } + + for key, val := range params { + if fw, err = w.CreateFormField(key); err != nil { + return ApiResponse{}, err + } + + if _, err = fw.Write([]byte(val)); err != nil { + return ApiResponse{}, err + } + } + + w.Close() + + req, err := http.NewRequest("POST", "https://api.telegram.org/bot"+bot.Token+"/"+endpoint, &b) + if err != nil { + return ApiResponse{}, err + } + + req.Header.Set("Content-Type", w.FormDataContentType()) + + client := &http.Client{} + res, err := client.Do(req) + if err != nil { + return ApiResponse{}, err + } + + bytes, err := ioutil.ReadAll(res.Body) + if err != nil { + return ApiResponse{}, err + } + + if bot.Debug { + log.Println(string(bytes[:])) + } + + var apiResp ApiResponse + json.Unmarshal(bytes, &apiResp) + + return apiResp, nil } -func NewAudioUpload(chatId int, filename string) AudioConfig { - return AudioConfig{ - ChatId: chatId, - UseExistingAudio: false, - FilePath: filename, +func (bot *BotApi) GetMe() (User, error) { + resp, err := bot.MakeRequest("getMe", nil) + if err != nil { + return User{}, err } + + var user User + json.Unmarshal(resp.Result, &user) + + if bot.Debug { + log.Printf("getMe: %+v\n", user) + } + + return user, nil } -func NewAudioShare(chatId int, fileId string) AudioConfig { - return AudioConfig{ - ChatId: chatId, - UseExistingAudio: true, - FileId: fileId, +func (bot *BotApi) SendMessage(config MessageConfig) (Message, error) { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("text", config.Text) + v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview)) + if config.ReplyToMessageId != 0 { + v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + v.Add("reply_markup", string(data)) + } + + resp, err := bot.MakeRequest("SendMessage", v) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("SendMessage req : %+v\n", v) + log.Printf("SendMessage resp: %+v\n", message) + } + + return message, nil } -func NewDocumentUpload(chatId int, filename string) DocumentConfig { - return DocumentConfig{ - ChatId: chatId, - UseExistingDocument: false, - FilePath: filename, +func (bot *BotApi) ForwardMessage(config ForwardConfig) (Message, error) { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("from_chat_id", strconv.Itoa(config.FromChatId)) + v.Add("message_id", strconv.Itoa(config.MessageId)) + + resp, err := bot.MakeRequest("forwardMessage", v) + if err != nil { + return Message{}, err } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("forwardMessage req : %+v\n", v) + log.Printf("forwardMessage resp: %+v\n", message) + } + + return message, nil } -func NewDocumentShare(chatId int, fileId string) DocumentConfig { - return DocumentConfig{ - ChatId: chatId, - UseExistingDocument: true, - FileId: fileId, +func (bot *BotApi) SendPhoto(config PhotoConfig) (Message, error) { + if config.UseExistingPhoto { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("photo", config.FileId) + if config.Caption != "" { + v.Add("caption", config.Caption) + } + if config.ReplyToMessageId != 0 { + v.Add("reply_to_message_id", strconv.Itoa(config.ChatId)) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + v.Add("reply_markup", string(data)) + } + + resp, err := bot.MakeRequest("SendPhoto", v) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("SendPhoto req : %+v\n", v) + log.Printf("SendPhoto resp: %+v\n", message) + } + + return message, nil } + + params := make(map[string]string) + params["chat_id"] = strconv.Itoa(config.ChatId) + if config.Caption != "" { + params["caption"] = config.Caption + } + if config.ReplyToMessageId != 0 { + params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + params["reply_markup"] = string(data) + } + + resp, err := bot.UploadFile("SendPhoto", params, "photo", config.FilePath) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("SendPhoto resp: %+v\n", message) + } + + return message, nil } -func NewStickerUpload(chatId int, filename string) StickerConfig { - return StickerConfig{ - ChatId: chatId, - UseExistingSticker: false, - FilePath: filename, +func (bot *BotApi) SendAudio(config AudioConfig) (Message, error) { + if config.UseExistingAudio { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("audio", config.FileId) + if config.ReplyToMessageId != 0 { + v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + v.Add("reply_markup", string(data)) + } + + resp, err := bot.MakeRequest("sendAudio", v) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendAudio req : %+v\n", v) + log.Printf("sendAudio resp: %+v\n", message) + } + + return message, nil } + + params := make(map[string]string) + + params["chat_id"] = strconv.Itoa(config.ChatId) + if config.ReplyToMessageId != 0 { + params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + params["reply_markup"] = string(data) + } + + resp, err := bot.UploadFile("sendAudio", params, "audio", config.FilePath) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendAudio resp: %+v\n", message) + } + + return message, nil } -func NewStickerShare(chatId int, fileId string) StickerConfig { - return StickerConfig{ - ChatId: chatId, - UseExistingSticker: true, - FileId: fileId, +func (bot *BotApi) SendDocument(config DocumentConfig) (Message, error) { + if config.UseExistingDocument { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("document", config.FileId) + if config.ReplyToMessageId != 0 { + v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + v.Add("reply_markup", string(data)) + } + + resp, err := bot.MakeRequest("sendDocument", v) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendDocument req : %+v\n", v) + log.Printf("sendDocument resp: %+v\n", message) + } + + return message, nil } + + params := make(map[string]string) + + params["chat_id"] = strconv.Itoa(config.ChatId) + if config.ReplyToMessageId != 0 { + params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + params["reply_markup"] = string(data) + } + + resp, err := bot.UploadFile("sendDocument", params, "document", config.FilePath) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendDocument resp: %+v\n", message) + } + + return message, nil } -func NewVideoUpload(chatId int, filename string) VideoConfig { - return VideoConfig{ - ChatId: chatId, - UseExistingVideo: false, - FilePath: filename, +func (bot *BotApi) SendSticker(config StickerConfig) (Message, error) { + if config.UseExistingSticker { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("sticker", config.FileId) + if config.ReplyToMessageId != 0 { + v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + v.Add("reply_markup", string(data)) + } + + resp, err := bot.MakeRequest("sendSticker", v) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendSticker req : %+v\n", v) + log.Printf("sendSticker resp: %+v\n", message) + } + + return message, nil } + + params := make(map[string]string) + + params["chat_id"] = strconv.Itoa(config.ChatId) + if config.ReplyToMessageId != 0 { + params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + params["reply_markup"] = string(data) + } + + resp, err := bot.UploadFile("sendSticker", params, "sticker", config.FilePath) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendSticker resp: %+v\n", message) + } + + return message, nil } -func NewVideoShare(chatId int, fileId string) VideoConfig { - return VideoConfig{ - ChatId: chatId, - UseExistingVideo: true, - FileId: fileId, +func (bot *BotApi) SendVideo(config VideoConfig) (Message, error) { + if config.UseExistingVideo { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("video", config.FileId) + if config.ReplyToMessageId != 0 { + v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + v.Add("reply_markup", string(data)) + } + + resp, err := bot.MakeRequest("sendVideo", v) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendVideo req : %+v\n", v) + log.Printf("sendVideo resp: %+v\n", message) + } + + return message, nil } + + params := make(map[string]string) + + params["chat_id"] = strconv.Itoa(config.ChatId) + if config.ReplyToMessageId != 0 { + params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) + } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + params["reply_markup"] = string(data) + } + + resp, err := bot.UploadFile("sendVideo", params, "video", config.FilePath) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendVideo resp: %+v\n", message) + } + + return message, nil } -func NewLocation(chatId int, latitude float64, longitude float64) LocationConfig { - return LocationConfig{ - ChatId: chatId, - Latitude: latitude, - Longitude: longitude, - ReplyToMessageId: 0, - ReplyMarkup: nil, +func (bot *BotApi) SendLocation(config LocationConfig) (Message, error) { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64)) + v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64)) + if config.ReplyToMessageId != 0 { + v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) } + if config.ReplyMarkup != nil { + data, err := json.Marshal(config.ReplyMarkup) + if err != nil { + return Message{}, err + } + + v.Add("reply_markup", string(data)) + } + + resp, err := bot.MakeRequest("sendLocation", v) + if err != nil { + return Message{}, err + } + + var message Message + json.Unmarshal(resp.Result, &message) + + if bot.Debug { + log.Printf("sendLocation req : %+v\n", v) + log.Printf("sendLocation resp: %+v\n", message) + } + + return message, nil } -func NewChatAction(chatId int, action string) ChatActionConfig { - return ChatActionConfig{ - ChatId: chatId, - Action: action, +func (bot *BotApi) SendChatAction(config ChatActionConfig) error { + v := url.Values{} + v.Add("chat_id", strconv.Itoa(config.ChatId)) + v.Add("action", config.Action) + + _, err := bot.MakeRequest("sendChatAction", v) + if err != nil { + return err } + + return nil } -func NewUserProfilePhotos(userId int) UserProfilePhotosConfig { - return UserProfilePhotosConfig{ - UserId: userId, - Offset: 0, - Limit: 0, +func (bot *BotApi) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) { + v := url.Values{} + v.Add("user_id", strconv.Itoa(config.UserId)) + if config.Offset != 0 { + v.Add("offset", strconv.Itoa(config.Offset)) } + if config.Limit != 0 { + v.Add("limit", strconv.Itoa(config.Limit)) + } + + resp, err := bot.MakeRequest("getUserProfilePhotos", v) + if err != nil { + return UserProfilePhotos{}, err + } + + var profilePhotos UserProfilePhotos + json.Unmarshal(resp.Result, &profilePhotos) + + if bot.Debug { + log.Printf("getUserProfilePhotos req : %+v\n", v) + log.Printf("getUserProfilePhotos resp: %+v\n", profilePhotos) + } + + return profilePhotos, nil } -func NewUpdate(offset int) UpdateConfig { - return UpdateConfig{ - Offset: offset, - Limit: 0, - Timeout: 0, +func (bot *BotApi) GetUpdates(config UpdateConfig) ([]Update, error) { + v := url.Values{} + if config.Offset > 0 { + v.Add("offset", strconv.Itoa(config.Offset)) } + if config.Limit > 0 { + v.Add("limit", strconv.Itoa(config.Limit)) + } + if config.Timeout > 0 { + v.Add("timeout", strconv.Itoa(config.Timeout)) + } + + resp, err := bot.MakeRequest("getUpdates", v) + if err != nil { + return []Update{}, err + } + + var updates []Update + json.Unmarshal(resp.Result, &updates) + + if bot.Debug { + log.Printf("getUpdates: %+v\n", updates) + } + + return updates, nil +} + +func (bot *BotApi) SetWebhook(config WebhookConfig) error { + v := url.Values{} + if !config.Clear { + v.Add("url", config.Url.String()) + } + + _, err := bot.MakeRequest("setWebhook", v) + + return err } diff --git a/plugin_fa.go b/plugin_fa.go deleted file mode 100644 index 253870a..0000000 --- a/plugin_fa.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "fmt" - "github.com/PuerkitoBio/goquery" - "github.com/ddliu/go-httpclient" - "io" - "net/http" - "os" - "strconv" - "strings" -) - -type FAPlugin struct { -} - -func (plugin *FAPlugin) GetName() string { - return "FA Mirrorer" -} - -func (plugin *FAPlugin) GetCommands() []string { - return []string{"/fa"} -} - -func (plugin *FAPlugin) GetHelpText() []string { - return []string{"/fa [link] - mirrors an image from FurAffinity"} -} - -func (plugin *FAPlugin) Setup() { - a, ok := config.Plugins["fa_a"] - if !ok { - fmt.Print("FurAffinity Cookie a: ") - fmt.Scanln(&a) - - config.Plugins["fa_a"] = a - } - - b, ok := config.Plugins["fa_b"] - if !ok { - fmt.Print("FurAffinity Cookie b: ") - fmt.Scanln(&b) - - config.Plugins["fa_b"] = b - } -} - -func (plugin *FAPlugin) GotCommand(command string, message Message, args []string) { - if len(args) == 0 { - bot.sendMessage(NewMessage(message.Chat.Id, "You need to include a link!")) - - return - } - - bot.sendChatAction(NewChatAction(message.Chat.Id, CHAT_UPLOAD_PHOTO)) - - _, err := strconv.Atoi(args[0]) - if err == nil { - args[0] = "http://www.furaffinity.net/view/" + args[0] - } - - resp, err := httpclient.WithCookie(&http.Cookie{ - Name: "b", - Value: config.Plugins["fa_b"], - }).WithCookie(&http.Cookie{ - Name: "a", - Value: config.Plugins["fa_a"], - }).Get(args[0], nil) - if err != nil { - bot.sendMessage(NewMessage(message.Chat.Id, "ERR : "+err.Error())) - } - - defer resp.Body.Close() - - doc, err := goquery.NewDocumentFromReader(resp.Body) - if err != nil { - bot.sendMessage(NewMessage(message.Chat.Id, "ERR : "+err.Error())) - } - - sel := doc.Find("#submissionImg") - for i := range sel.Nodes { - single := sel.Eq(i) - - val, _ := single.Attr("src") - - tokens := strings.Split(val, "/") - fileName := tokens[len(tokens)-1] - - output, _ := os.Create(fileName) - defer output.Close() - defer os.Remove(output.Name()) - - resp, _ := http.Get("http:" + val) - defer resp.Body.Close() - - io.Copy(output, resp.Body) - - bot.sendPhoto(NewPhotoUpload(message.Chat.Id, output.Name())) - } -} diff --git a/plugin_help.go b/plugin_help.go deleted file mode 100644 index 25e95f1..0000000 --- a/plugin_help.go +++ /dev/null @@ -1,76 +0,0 @@ -package main - -import ( - "bytes" - "log" -) - -type HelpPlugin struct { -} - -func (plugin *HelpPlugin) GetName() string { - return "Plugins help" -} - -func (plugin *HelpPlugin) GetCommands() []string { - return []string{"/help"} -} - -func (plugin *HelpPlugin) GetHelpText() []string { - return []string{"/help (/command) - returns help about a command"} -} - -func (plugin *HelpPlugin) Setup() { -} - -func (plugin *HelpPlugin) GotCommand(command string, message Message, args []string) { - msg := NewMessage(message.Chat.Id, "") - msg.ReplyToMessageId = message.MessageId - msg.DisableWebPagePreview = true - - var buffer bytes.Buffer - - if len(args) > 0 { - for _, plug := range plugins { - for _, cmd := range plug.GetCommands() { - log.Println(cmd) - log.Println(args[0]) - log.Println(args[0][1:]) - if cmd == args[0] || cmd[1:] == args[0] { - buffer.WriteString(plug.GetName()) - buffer.WriteString("\n") - - for _, help := range plug.GetHelpText() { - buffer.WriteString(" ") - buffer.WriteString(help) - buffer.WriteString("\n") - } - } - } - } - } else { - buffer.WriteString(config.Plugins["about_text"]) - buffer.WriteString("\n\n") - - for _, plug := range plugins { - val, _ := config.EnabledPlugins[plugin.GetName()] - - buffer.WriteString(plug.GetName()) - if !val { - buffer.WriteString(" (disabled)") - } - buffer.WriteString("\n") - - for _, cmd := range plug.GetHelpText() { - buffer.WriteString(" ") - buffer.WriteString(cmd) - buffer.WriteString("\n") - } - - buffer.WriteString("\n") - } - } - - msg.Text = buffer.String() - bot.sendMessage(msg) -} diff --git a/plugin_manage.go b/plugin_manage.go deleted file mode 100644 index ed522c1..0000000 --- a/plugin_manage.go +++ /dev/null @@ -1,153 +0,0 @@ -package main - -import ( - "fmt" - "log" - "strings" -) - -type ManagePlugin struct { -} - -func (plugin *ManagePlugin) GetName() string { - return "Plugin manager" -} - -func (plugin *ManagePlugin) GetCommands() []string { - return []string{ - "/enable", - "Enable", - "/disable", - "Disable", - "/reload", - } -} - -func (plugin *ManagePlugin) GetHelpText() []string { - return []string{ - "/enable [name] - enables a plugin", - "/disable [name] - disables a plugin", - "/reload - reloads bot configuration", - } -} - -func (plugin *ManagePlugin) Setup() { -} - -func (plugin *ManagePlugin) GotCommand(command string, message Message, args []string) { - log.Println(command) - - if command == "/enable" { - keyboard := [][]string{} - - hasDisabled := false - for _, plug := range plugins { - enabled, _ := config.EnabledPlugins[plug.GetName()] - if enabled { - continue - } - - hasDisabled = true - keyboard = append(keyboard, []string{"Enable " + plug.GetName()}) - } - - if !hasDisabled { - msg := NewMessage(message.Chat.Id, "All plugins are enabled!") - msg.ReplyToMessageId = message.MessageId - - bot.sendMessage(msg) - - return - } - - msg := NewMessage(message.Chat.Id, "Please specify which plugin to enable") - msg.ReplyToMessageId = message.MessageId - msg.ReplyMarkup = ReplyKeyboardMarkup{ - Keyboard: keyboard, - OneTimeKeyboard: true, - Selective: true, - ResizeKeyboard: true, - } - - bot.sendMessage(msg) - } else if command == "Enable" { - pluginName := strings.SplitN(message.Text, " ", 2) - - msg := NewMessage(message.Chat.Id, "") - msg.ReplyToMessageId = message.MessageId - msg.ReplyMarkup = ReplyKeyboardHide{ - HideKeyboard: true, - Selective: true, - } - - _, ok := config.EnabledPlugins[pluginName[1]] - if !ok { - msg.Text = "Unknown plugin!" - msg.ReplyToMessageId = message.MessageId - bot.sendMessage(msg) - - return - } - - config.EnabledPlugins[pluginName[1]] = true - msg.Text = fmt.Sprintf("Enabled '%s'!", pluginName[1]) - bot.sendMessage(msg) - } else if command == "/disable" { - keyboard := [][]string{} - - hasEnabled := false - for _, plug := range plugins { - enabled, _ := config.EnabledPlugins[plug.GetName()] - if !enabled { - continue - } - - hasEnabled = true - keyboard = append(keyboard, []string{"Disable " + plug.GetName()}) - } - - if !hasEnabled { - msg := NewMessage(message.Chat.Id, "All plugins are disabled!") - msg.ReplyToMessageId = message.MessageId - - bot.sendMessage(msg) - - return - } - - msg := NewMessage(message.Chat.Id, "Please specify which plugin to disable") - msg.ReplyToMessageId = message.MessageId - msg.ReplyMarkup = ReplyKeyboardMarkup{ - Keyboard: keyboard, - OneTimeKeyboard: true, - Selective: true, - ResizeKeyboard: true, - } - - bot.sendMessage(msg) - } else if command == "Disable" { - pluginName := strings.SplitN(message.Text, " ", 2) - - msg := NewMessage(message.Chat.Id, "") - msg.ReplyToMessageId = message.MessageId - msg.ReplyMarkup = ReplyKeyboardHide{ - HideKeyboard: true, - Selective: true, - } - - _, ok := config.EnabledPlugins[pluginName[1]] - if !ok { - msg.Text = "Unknown plugin!" - msg.ReplyToMessageId = message.MessageId - bot.sendMessage(msg) - - return - } - - config.EnabledPlugins[pluginName[1]] = false - msg.Text = fmt.Sprintf("Disabled '%s'!", pluginName[1]) - bot.sendMessage(msg) - } - - saveConfig() -} diff --git a/responses.go b/types.go similarity index 99% rename from responses.go rename to types.go index 41fc76d..2054a99 100644 --- a/responses.go +++ b/types.go @@ -1,4 +1,4 @@ -package main +package tgbotapi import ( "encoding/json" diff --git a/updates.go b/updates.go new file mode 100644 index 0000000..0d0847a --- /dev/null +++ b/updates.go @@ -0,0 +1,22 @@ +package tgbotapi + +func (bot *BotApi) UpdatesChan(config UpdateConfig) (chan Update, error) { + bot.Updates = make(chan Update, 100) + + go func() { + updates, err := bot.GetUpdates(config) + if err != nil { + panic(err) + } + + for _, update := range updates { + if update.UpdateId > config.Offset { + config.Offset = update.UpdateId + 1 + } + + bot.Updates <- update + } + }() + + return bot.Updates, nil +}