fix all golint errors, add info about audio uploads

bot-api-6.1
Syfaro 2015-06-26 01:53:20 -05:00
parent 5b2104f974
commit a17651c8fe
5 changed files with 290 additions and 258 deletions

13
bot.go
View File

@ -1,23 +1,24 @@
// Methods for interacting with the Telegram Bot API. // Package tgbotapi has bindings for interacting with the Telegram Bot API.
package tgbotapi package tgbotapi
type BotApi struct { // BotAPI has methods for interacting with all of Telegram's Bot API endpoints.
type BotAPI struct {
Token string `json:"token"` Token string `json:"token"`
Debug bool `json:"debug"` Debug bool `json:"debug"`
Self User `json:"-"` Self User `json:"-"`
Updates chan Update `json:"-"` Updates chan Update `json:"-"`
} }
// Creates a new BotApi instance. // NewBotAPI creates a new BotAPI instance.
// Requires a token, provided by @BotFather on Telegram // Requires a token, provided by @BotFather on Telegram
func NewBotApi(token string) (*BotApi, error) { func NewBotAPI(token string) (*BotAPI, error) {
bot := &BotApi{ bot := &BotAPI{
Token: token, Token: token,
} }
self, err := bot.GetMe() self, err := bot.GetMe()
if err != nil { if err != nil {
return &BotApi{}, err return &BotAPI{}, err
} }
bot.Self = self bot.Self = self

View File

@ -4,195 +4,195 @@ import (
"net/url" "net/url"
) )
// Creates a new Message. // NewMessage creates a new Message.
// Perhaps set a ChatAction of CHAT_TYPING while processing. // Perhaps set a ChatAction of ChatTyping while processing.
// //
// chatId is where to send it, text is the message text. // chatID is where to send it, text is the message text.
func NewMessage(chatId int, text string) MessageConfig { func NewMessage(chatID int, text string) MessageConfig {
return MessageConfig{ return MessageConfig{
ChatId: chatId, ChatID: chatID,
Text: text, Text: text,
DisableWebPagePreview: false, DisableWebPagePreview: false,
ReplyToMessageId: 0, ReplyToMessageID: 0,
} }
} }
// Creates a new forward. // NewForward creates a new forward.
// //
// chatId is where to send it, fromChatId is the source chat, // chatID is where to send it, fromChatID is the source chat,
// and messageId is the Id of the original message. // and messageID is the ID of the original message.
func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig { func NewForward(chatID int, fromChatID int, messageID int) ForwardConfig {
return ForwardConfig{ return ForwardConfig{
ChatId: chatId, ChatID: chatID,
FromChatId: fromChatId, FromChatID: fromChatID,
MessageId: messageId, MessageID: messageID,
} }
} }
// Creates a new photo uploader. // NewPhotoUpload creates a new photo uploader.
// This requires a file on the local filesystem to upload to Telegram. // This requires a file on the local filesystem to upload to Telegram.
// Perhaps set a ChatAction of CHAT_UPLOAD_PHOTO while processing. // Perhaps set a ChatAction of ChatUploadPhoto while processing.
// //
// chatId is where to send it, filename is the path to the file. // chatID is where to send it, filename is the path to the file.
func NewPhotoUpload(chatId int, filename string) PhotoConfig { func NewPhotoUpload(chatID int, filename string) PhotoConfig {
return PhotoConfig{ return PhotoConfig{
ChatId: chatId, ChatID: chatID,
UseExistingPhoto: false, UseExistingPhoto: false,
FilePath: filename, FilePath: filename,
} }
} }
// Shares an existing photo. // NewPhotoShare shares an existing photo.
// You may use this to reshare an existing photo without reuploading it. // You may use this to reshare an existing photo without reuploading it.
// //
// chatId is where to send it, fileId is the Id of the file already uploaded. // chatID is where to send it, fileID is the ID of the file already uploaded.
func NewPhotoShare(chatId int, fileId string) PhotoConfig { func NewPhotoShare(chatID int, fileID string) PhotoConfig {
return PhotoConfig{ return PhotoConfig{
ChatId: chatId, ChatID: chatID,
UseExistingPhoto: true, UseExistingPhoto: true,
FileId: fileId, FileID: fileID,
} }
} }
// Creates a new audio uploader. // NewAudioUpload creates a new audio uploader.
// This requires a file on the local filesystem to upload to Telegram. // This requires a file on the local filesystem to upload to Telegram.
// Perhaps set a ChatAction of CHAT_RECORD_AUDIO or CHAT_UPLOAD_AUDIO while processing. // Perhaps set a ChatAction of ChatRecordAudio or ChatUploadAudio while processing.
// //
// chatId is where to send it, filename is the path to the file. // chatID is where to send it, filename is the path to the file.
func NewAudioUpload(chatId int, filename string) AudioConfig { func NewAudioUpload(chatID int, filename string) AudioConfig {
return AudioConfig{ return AudioConfig{
ChatId: chatId, ChatID: chatID,
UseExistingAudio: false, UseExistingAudio: false,
FilePath: filename, FilePath: filename,
} }
} }
// Shares an existing audio file. // NewAudioShare shares an existing audio file.
// You may use this to reshare an existing audio file without reuploading it. // You may use this to reshare an existing audio file without reuploading it.
// //
// chatId is where to send it, fileId is the Id of the audio already uploaded. // chatID is where to send it, fileID is the ID of the audio already uploaded.
func NewAudioShare(chatId int, fileId string) AudioConfig { func NewAudioShare(chatID int, fileID string) AudioConfig {
return AudioConfig{ return AudioConfig{
ChatId: chatId, ChatID: chatID,
UseExistingAudio: true, UseExistingAudio: true,
FileId: fileId, FileID: fileID,
} }
} }
// Creates a new document uploader. // NewDocumentUpload creates a new document uploader.
// This requires a file on the local filesystem to upload to Telegram. // This requires a file on the local filesystem to upload to Telegram.
// Perhaps set a ChatAction of CHAT_UPLOAD_DOCUMENT while processing. // Perhaps set a ChatAction of ChatUploadDocument while processing.
// //
// chatId is where to send it, filename is the path to the file. // chatID is where to send it, filename is the path to the file.
func NewDocumentUpload(chatId int, filename string) DocumentConfig { func NewDocumentUpload(chatID int, filename string) DocumentConfig {
return DocumentConfig{ return DocumentConfig{
ChatId: chatId, ChatID: chatID,
UseExistingDocument: false, UseExistingDocument: false,
FilePath: filename, FilePath: filename,
} }
} }
// Shares an existing document. // NewDocumentShare shares an existing document.
// You may use this to reshare an existing document without reuploading it. // You may use this to reshare an existing document without reuploading it.
// //
// chatId is where to send it, fileId is the Id of the document already uploaded. // chatID is where to send it, fileID is the ID of the document already uploaded.
func NewDocumentShare(chatId int, fileId string) DocumentConfig { func NewDocumentShare(chatID int, fileID string) DocumentConfig {
return DocumentConfig{ return DocumentConfig{
ChatId: chatId, ChatID: chatID,
UseExistingDocument: true, UseExistingDocument: true,
FileId: fileId, FileID: fileID,
} }
} }
// Creates a new sticker uploader. // NewStickerUpload creates a new sticker uploader.
// This requires a file on the local filesystem to upload to Telegram. // This requires a file on the local filesystem to upload to Telegram.
// //
// chatId is where to send it, filename is the path to the file. // chatID is where to send it, filename is the path to the file.
func NewStickerUpload(chatId int, filename string) StickerConfig { func NewStickerUpload(chatID int, filename string) StickerConfig {
return StickerConfig{ return StickerConfig{
ChatId: chatId, ChatID: chatID,
UseExistingSticker: false, UseExistingSticker: false,
FilePath: filename, FilePath: filename,
} }
} }
// Shares an existing sticker. // NewStickerShare shares an existing sticker.
// You may use this to reshare an existing sticker without reuploading it. // You may use this to reshare an existing sticker without reuploading it.
// //
// chatId is where to send it, fileId is the Id of the sticker already uploaded. // chatID is where to send it, fileID is the ID of the sticker already uploaded.
func NewStickerShare(chatId int, fileId string) StickerConfig { func NewStickerShare(chatID int, fileID string) StickerConfig {
return StickerConfig{ return StickerConfig{
ChatId: chatId, ChatID: chatID,
UseExistingSticker: true, UseExistingSticker: true,
FileId: fileId, FileID: fileID,
} }
} }
// Creates a new video uploader. // NewVideoUpload creates a new video uploader.
// This requires a file on the local filesystem to upload to Telegram. // This requires a file on the local filesystem to upload to Telegram.
// Perhaps set a ChatAction of CHAT_RECORD_VIDEO or CHAT_UPLOAD_VIDEO while processing. // Perhaps set a ChatAction of ChatRecordVideo or ChatUploadVideo while processing.
// //
// chatId is where to send it, filename is the path to the file. // chatID is where to send it, filename is the path to the file.
func NewVideoUpload(chatId int, filename string) VideoConfig { func NewVideoUpload(chatID int, filename string) VideoConfig {
return VideoConfig{ return VideoConfig{
ChatId: chatId, ChatID: chatID,
UseExistingVideo: false, UseExistingVideo: false,
FilePath: filename, FilePath: filename,
} }
} }
// Shares an existing video. // NewVideoShare shares an existing video.
// You may use this to reshare an existing video without reuploading it. // You may use this to reshare an existing video without reuploading it.
// //
// chatId is where to send it, fileId is the Id of the video already uploaded. // chatID is where to send it, fileID is the ID of the video already uploaded.
func NewVideoShare(chatId int, fileId string) VideoConfig { func NewVideoShare(chatID int, fileID string) VideoConfig {
return VideoConfig{ return VideoConfig{
ChatId: chatId, ChatID: chatID,
UseExistingVideo: true, UseExistingVideo: true,
FileId: fileId, FileID: fileID,
} }
} }
// Shares your location. // NewLocation shares your location.
// Perhaps set a ChatAction of CHAT_FIND_LOCATION while processing. // Perhaps set a ChatAction of ChatFindLocation while processing.
// //
// chatId is where to send it, latitude and longitude are coordinates. // chatID is where to send it, latitude and longitude are coordinates.
func NewLocation(chatId int, latitude float64, longitude float64) LocationConfig { func NewLocation(chatID int, latitude float64, longitude float64) LocationConfig {
return LocationConfig{ return LocationConfig{
ChatId: chatId, ChatID: chatID,
Latitude: latitude, Latitude: latitude,
Longitude: longitude, Longitude: longitude,
ReplyToMessageId: 0, ReplyToMessageID: 0,
ReplyMarkup: nil, ReplyMarkup: nil,
} }
} }
// Sets a chat action. // NewChatAction sets a chat action.
// Actions last for 5 seconds, or until your next action. // Actions last for 5 seconds, or until your next action.
// //
// chatId is where to send it, action should be set via CHAT constants. // chatID is where to send it, action should be set via CHAT constants.
func NewChatAction(chatId int, action string) ChatActionConfig { func NewChatAction(chatID int, action string) ChatActionConfig {
return ChatActionConfig{ return ChatActionConfig{
ChatId: chatId, ChatID: chatID,
Action: action, Action: action,
} }
} }
// Gets user profile photos. // NewUserProfilePhotos gets user profile photos.
// //
// userId is the Id of the user you wish to get profile photos from. // userID is the ID of the user you wish to get profile photos from.
func NewUserProfilePhotos(userId int) UserProfilePhotosConfig { func NewUserProfilePhotos(userID int) UserProfilePhotosConfig {
return UserProfilePhotosConfig{ return UserProfilePhotosConfig{
UserId: userId, UserID: userID,
Offset: 0, Offset: 0,
Limit: 0, Limit: 0,
} }
} }
// Gets updates since the last Offset. // NewUpdate gets updates since the last Offset.
// //
// offset is the last Update Id to include. // offset is the last Update ID to include.
// You likely want to set this to the last Update Id plus 1. // You likely want to set this to the last Update ID plus 1.
func NewUpdate(offset int) UpdateConfig { func NewUpdate(offset int) UpdateConfig {
return UpdateConfig{ return UpdateConfig{
Offset: offset, Offset: offset,
@ -201,14 +201,14 @@ func NewUpdate(offset int) UpdateConfig {
} }
} }
// Creates a new webhook. // NewWebhook creates a new webhook.
// //
// link is the url parsable link you wish to get the updates. // link is the url parsable link you wish to get the updates.
func NewWebhook(link string) WebhookConfig { func NewWebhook(link string) WebhookConfig {
u, _ := url.Parse(link) u, _ := url.Parse(link)
return WebhookConfig{ return WebhookConfig{
Url: u, URL: u,
Clear: false, Clear: false,
} }
} }

View File

@ -14,163 +14,176 @@ import (
"strconv" "strconv"
) )
// Constant values for ChatActions
const ( const (
CHAT_TYPING = "typing" ChatTyping = "typing"
CHAT_UPLOAD_PHOTO = "upload_photo" ChatUploadPhoto = "upload_photo"
CHAT_RECORD_VIDEO = "record_video" ChatRecordVideo = "record_video"
CHAT_UPLOAD_VIDEO = "upload_video" ChatUploadVideo = "upload_video"
CHAT_RECORD_AUDIO = "record_audio" ChatRecordAudio = "record_audio"
CHAT_UPLOAD_AUDIO = "upload_audio" ChatUploadAudio = "upload_audio"
CHAT_UPLOAD_DOCUMENT = "upload_document" ChatUploadDocument = "upload_document"
CHAT_FIND_LOCATION = "find_location" ChatFindLocation = "find_location"
) )
// MessageConfig contains information about a SendMessage request.
type MessageConfig struct { type MessageConfig struct {
ChatId int ChatID int
Text string Text string
DisableWebPagePreview bool DisableWebPagePreview bool
ReplyToMessageId int ReplyToMessageID int
ReplyMarkup interface{} ReplyMarkup interface{}
} }
// ForwardConfig contains infomation about a ForwardMessage request.
type ForwardConfig struct { type ForwardConfig struct {
ChatId int ChatID int
FromChatId int FromChatID int
MessageId int MessageID int
} }
// PhotoConfig contains information about a SendPhoto request.
type PhotoConfig struct { type PhotoConfig struct {
ChatId int ChatID int
Caption string Caption string
ReplyToMessageId int ReplyToMessageID int
ReplyMarkup interface{} ReplyMarkup interface{}
UseExistingPhoto bool UseExistingPhoto bool
FilePath string FilePath string
FileId string FileID string
} }
// AudioConfig contains information about a SendAudio request.
type AudioConfig struct { type AudioConfig struct {
ChatId int ChatID int
ReplyToMessageId int ReplyToMessageID int
ReplyMarkup interface{} ReplyMarkup interface{}
UseExistingAudio bool UseExistingAudio bool
FilePath string FilePath string
FileId string FileID string
} }
// DocumentConfig contains information about a SendDocument request.
type DocumentConfig struct { type DocumentConfig struct {
ChatId int ChatID int
ReplyToMessageId int ReplyToMessageID int
ReplyMarkup interface{} ReplyMarkup interface{}
UseExistingDocument bool UseExistingDocument bool
FilePath string FilePath string
FileId string FileID string
} }
// StickerConfig contains information about a SendSticker request.
type StickerConfig struct { type StickerConfig struct {
ChatId int ChatID int
ReplyToMessageId int ReplyToMessageID int
ReplyMarkup interface{} ReplyMarkup interface{}
UseExistingSticker bool UseExistingSticker bool
FilePath string FilePath string
FileId string FileID string
} }
// VideoConfig contains information about a SendVideo request.
type VideoConfig struct { type VideoConfig struct {
ChatId int ChatID int
ReplyToMessageId int ReplyToMessageID int
ReplyMarkup interface{} ReplyMarkup interface{}
UseExistingVideo bool UseExistingVideo bool
FilePath string FilePath string
FileId string FileID string
} }
// LocationConfig contains information about a SendLocation request.
type LocationConfig struct { type LocationConfig struct {
ChatId int ChatID int
Latitude float64 Latitude float64
Longitude float64 Longitude float64
ReplyToMessageId int ReplyToMessageID int
ReplyMarkup interface{} ReplyMarkup interface{}
} }
// ChatActionConfig contains information about a SendChatAction request.
type ChatActionConfig struct { type ChatActionConfig struct {
ChatId int ChatID int
Action string Action string
} }
// UserProfilePhotosConfig contains information about a GetUserProfilePhotos request.
type UserProfilePhotosConfig struct { type UserProfilePhotosConfig struct {
UserId int UserID int
Offset int Offset int
Limit int Limit int
} }
// UpdateConfig contains information about a GetUpdates request.
type UpdateConfig struct { type UpdateConfig struct {
Offset int Offset int
Limit int Limit int
Timeout int Timeout int
} }
// WebhookConfig contains information about a SetWebhook request.
type WebhookConfig struct { type WebhookConfig struct {
Clear bool Clear bool
Url *url.URL URL *url.URL
} }
// Makes a request to a specific endpoint with our token. // MakeRequest makes a request to a specific endpoint with our token.
// All requests are POSTs because Telegram doesn't care, and it's easier. // All requests are POSTs because Telegram doesn't care, and it's easier.
func (bot *BotApi) MakeRequest(endpoint string, params url.Values) (ApiResponse, error) { func (bot *BotAPI) MakeRequest(endpoint string, params url.Values) (APIResponse, error) {
resp, err := http.PostForm("https://api.telegram.org/bot"+bot.Token+"/"+endpoint, params) resp, err := http.PostForm("https://api.telegram.org/bot"+bot.Token+"/"+endpoint, params)
defer resp.Body.Close() defer resp.Body.Close()
if err != nil { if err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
bytes, err := ioutil.ReadAll(resp.Body) bytes, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
if bot.Debug { if bot.Debug {
log.Println(endpoint, string(bytes)) log.Println(endpoint, string(bytes))
} }
var apiResp ApiResponse var apiResp APIResponse
json.Unmarshal(bytes, &apiResp) json.Unmarshal(bytes, &apiResp)
if !apiResp.Ok { if !apiResp.Ok {
return ApiResponse{}, errors.New(apiResp.Description) return APIResponse{}, errors.New(apiResp.Description)
} }
return apiResp, nil return apiResp, nil
} }
// Makes a request to the API with a file. // UploadFile makes a request to the API with a file.
// //
// Requires the parameter to hold the file not be in the params. // Requires the parameter to hold the file not be in the params.
func (bot *BotApi) UploadFile(endpoint string, params map[string]string, fieldname string, filename string) (ApiResponse, error) { func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldname string, filename string) (APIResponse, error) {
var b bytes.Buffer var b bytes.Buffer
w := multipart.NewWriter(&b) w := multipart.NewWriter(&b)
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
fw, err := w.CreateFormFile(fieldname, filename) fw, err := w.CreateFormFile(fieldname, filename)
if err != nil { if err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
if _, err = io.Copy(fw, f); err != nil { if _, err = io.Copy(fw, f); err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
for key, val := range params { for key, val := range params {
if fw, err = w.CreateFormField(key); err != nil { if fw, err = w.CreateFormField(key); err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
if _, err = fw.Write([]byte(val)); err != nil { if _, err = fw.Write([]byte(val)); err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
} }
@ -178,7 +191,7 @@ func (bot *BotApi) UploadFile(endpoint string, params map[string]string, fieldna
req, err := http.NewRequest("POST", "https://api.telegram.org/bot"+bot.Token+"/"+endpoint, &b) req, err := http.NewRequest("POST", "https://api.telegram.org/bot"+bot.Token+"/"+endpoint, &b)
if err != nil { if err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
req.Header.Set("Content-Type", w.FormDataContentType()) req.Header.Set("Content-Type", w.FormDataContentType())
@ -186,28 +199,28 @@ func (bot *BotApi) UploadFile(endpoint string, params map[string]string, fieldna
client := &http.Client{} client := &http.Client{}
res, err := client.Do(req) res, err := client.Do(req)
if err != nil { if err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
bytes, err := ioutil.ReadAll(res.Body) bytes, err := ioutil.ReadAll(res.Body)
if err != nil { if err != nil {
return ApiResponse{}, err return APIResponse{}, err
} }
if bot.Debug { if bot.Debug {
log.Println(string(bytes[:])) log.Println(string(bytes[:]))
} }
var apiResp ApiResponse var apiResp APIResponse
json.Unmarshal(bytes, &apiResp) json.Unmarshal(bytes, &apiResp)
return apiResp, nil return apiResp, nil
} }
// Fetches the currently authenticated bot. // GetMe fetches the currently authenticated bot.
// //
// There are no parameters for this method. // There are no parameters for this method.
func (bot *BotApi) GetMe() (User, error) { func (bot *BotAPI) GetMe() (User, error) {
resp, err := bot.MakeRequest("getMe", nil) resp, err := bot.MakeRequest("getMe", nil)
if err != nil { if err != nil {
return User{}, err return User{}, err
@ -223,17 +236,17 @@ func (bot *BotApi) GetMe() (User, error) {
return user, nil return user, nil
} }
// Sends a Message to a chat. // SendMessage sends a Message to a chat.
// //
// Requires ChatId and Text. // Requires ChatID and Text.
// DisableWebPagePreview, ReplyToMessageId, and ReplyMarkup are optional. // DisableWebPagePreview, ReplyToMessageID, and ReplyMarkup are optional.
func (bot *BotApi) SendMessage(config MessageConfig) (Message, error) { func (bot *BotAPI) SendMessage(config MessageConfig) (Message, error) {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("text", config.Text) v.Add("text", config.Text)
v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview)) v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -260,14 +273,14 @@ func (bot *BotApi) SendMessage(config MessageConfig) (Message, error) {
return message, nil return message, nil
} }
// Forwards a message from one chat to another. // ForwardMessage forwards a message from one chat to another.
// //
// Requires ChatId (destionation), FromChatId (source), and MessageId. // Requires ChatID (destionation), FromChatID (source), and MessageID.
func (bot *BotApi) ForwardMessage(config ForwardConfig) (Message, error) { func (bot *BotAPI) ForwardMessage(config ForwardConfig) (Message, error) {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("from_chat_id", strconv.Itoa(config.FromChatId)) v.Add("from_chat_id", strconv.Itoa(config.FromChatID))
v.Add("message_id", strconv.Itoa(config.MessageId)) v.Add("message_id", strconv.Itoa(config.MessageID))
resp, err := bot.MakeRequest("forwardMessage", v) resp, err := bot.MakeRequest("forwardMessage", v)
if err != nil { if err != nil {
@ -285,20 +298,20 @@ func (bot *BotApi) ForwardMessage(config ForwardConfig) (Message, error) {
return message, nil return message, nil
} }
// Sends or uploads a photo to a chat. // SendPhoto sends or uploads a photo to a chat.
// //
// Requires ChatId and FileId OR FilePath. // Requires ChatID and FileID OR FilePath.
// Caption, ReplyToMessageId, and ReplyMarkup are optional. // Caption, ReplyToMessageID, and ReplyMarkup are optional.
func (bot *BotApi) SendPhoto(config PhotoConfig) (Message, error) { func (bot *BotAPI) SendPhoto(config PhotoConfig) (Message, error) {
if config.UseExistingPhoto { if config.UseExistingPhoto {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("photo", config.FileId) v.Add("photo", config.FileID)
if config.Caption != "" { if config.Caption != "" {
v.Add("caption", config.Caption) v.Add("caption", config.Caption)
} }
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
v.Add("reply_to_message_id", strconv.Itoa(config.ChatId)) v.Add("reply_to_message_id", strconv.Itoa(config.ChatID))
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -326,12 +339,12 @@ func (bot *BotApi) SendPhoto(config PhotoConfig) (Message, error) {
} }
params := make(map[string]string) params := make(map[string]string)
params["chat_id"] = strconv.Itoa(config.ChatId) params["chat_id"] = strconv.Itoa(config.ChatID)
if config.Caption != "" { if config.Caption != "" {
params["caption"] = config.Caption params["caption"] = config.Caption
} }
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -357,17 +370,18 @@ func (bot *BotApi) SendPhoto(config PhotoConfig) (Message, error) {
return message, nil return message, nil
} }
// Sends or uploads an audio clip to a chat. // SendAudio sends or uploads an audio clip to a chat.
// If using a file, the file must be encoded as an .ogg with OPUS.
// //
// Requires ChatId and FileId OR FilePath. // Requires ChatID and FileID OR FilePath.
// ReplyToMessageId and ReplyMarkup are optional. // ReplyToMessageID and ReplyMarkup are optional.
func (bot *BotApi) SendAudio(config AudioConfig) (Message, error) { func (bot *BotAPI) SendAudio(config AudioConfig) (Message, error) {
if config.UseExistingAudio { if config.UseExistingAudio {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("audio", config.FileId) v.Add("audio", config.FileID)
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -396,9 +410,9 @@ func (bot *BotApi) SendAudio(config AudioConfig) (Message, error) {
params := make(map[string]string) params := make(map[string]string)
params["chat_id"] = strconv.Itoa(config.ChatId) params["chat_id"] = strconv.Itoa(config.ChatID)
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -424,17 +438,17 @@ func (bot *BotApi) SendAudio(config AudioConfig) (Message, error) {
return message, nil return message, nil
} }
// Sends or uploads a document to a chat. // SendDocument sends or uploads a document to a chat.
// //
// Requires ChatId and FileId OR FilePath. // Requires ChatID and FileID OR FilePath.
// ReplyToMessageId and ReplyMarkup are optional. // ReplyToMessageID and ReplyMarkup are optional.
func (bot *BotApi) SendDocument(config DocumentConfig) (Message, error) { func (bot *BotAPI) SendDocument(config DocumentConfig) (Message, error) {
if config.UseExistingDocument { if config.UseExistingDocument {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("document", config.FileId) v.Add("document", config.FileID)
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -463,9 +477,9 @@ func (bot *BotApi) SendDocument(config DocumentConfig) (Message, error) {
params := make(map[string]string) params := make(map[string]string)
params["chat_id"] = strconv.Itoa(config.ChatId) params["chat_id"] = strconv.Itoa(config.ChatID)
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -491,17 +505,17 @@ func (bot *BotApi) SendDocument(config DocumentConfig) (Message, error) {
return message, nil return message, nil
} }
// Sends or uploads a sticker to a chat. // SendSticker sends or uploads a sticker to a chat.
// //
// Requires ChatId and FileId OR FilePath. // Requires ChatID and FileID OR FilePath.
// ReplyToMessageId and ReplyMarkup are optional. // ReplyToMessageID and ReplyMarkup are optional.
func (bot *BotApi) SendSticker(config StickerConfig) (Message, error) { func (bot *BotAPI) SendSticker(config StickerConfig) (Message, error) {
if config.UseExistingSticker { if config.UseExistingSticker {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("sticker", config.FileId) v.Add("sticker", config.FileID)
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -530,9 +544,9 @@ func (bot *BotApi) SendSticker(config StickerConfig) (Message, error) {
params := make(map[string]string) params := make(map[string]string)
params["chat_id"] = strconv.Itoa(config.ChatId) params["chat_id"] = strconv.Itoa(config.ChatID)
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -558,17 +572,17 @@ func (bot *BotApi) SendSticker(config StickerConfig) (Message, error) {
return message, nil return message, nil
} }
// Sends or uploads a video to a chat. // SendVideo sends or uploads a video to a chat.
// //
// Requires ChatId and FileId OR FilePath. // Requires ChatID and FileID OR FilePath.
// ReplyToMessageId and ReplyMarkup are optional. // ReplyToMessageID and ReplyMarkup are optional.
func (bot *BotApi) SendVideo(config VideoConfig) (Message, error) { func (bot *BotAPI) SendVideo(config VideoConfig) (Message, error) {
if config.UseExistingVideo { if config.UseExistingVideo {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("video", config.FileId) v.Add("video", config.FileID)
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -597,9 +611,9 @@ func (bot *BotApi) SendVideo(config VideoConfig) (Message, error) {
params := make(map[string]string) params := make(map[string]string)
params["chat_id"] = strconv.Itoa(config.ChatId) params["chat_id"] = strconv.Itoa(config.ChatID)
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageId) params["reply_to_message_id"] = strconv.Itoa(config.ReplyToMessageID)
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -625,17 +639,17 @@ func (bot *BotApi) SendVideo(config VideoConfig) (Message, error) {
return message, nil return message, nil
} }
// Sends a location to a chat. // SendLocation sends a location to a chat.
// //
// Requires ChatId, Latitude, and Longitude. // Requires ChatID, Latitude, and Longitude.
// ReplyToMessageId and ReplyMarkup are optional. // ReplyToMessageID and ReplyMarkup are optional.
func (bot *BotApi) SendLocation(config LocationConfig) (Message, error) { func (bot *BotAPI) SendLocation(config LocationConfig) (Message, error) {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64)) v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64))
v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64)) v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64))
if config.ReplyToMessageId != 0 { if config.ReplyToMessageID != 0 {
v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageId)) v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
} }
if config.ReplyMarkup != nil { if config.ReplyMarkup != nil {
data, err := json.Marshal(config.ReplyMarkup) data, err := json.Marshal(config.ReplyMarkup)
@ -662,12 +676,12 @@ func (bot *BotApi) SendLocation(config LocationConfig) (Message, error) {
return message, nil return message, nil
} }
// Sets a current action in a chat. // SendChatAction sets a current action in a chat.
// //
// Requires ChatId and a valid Action (see CHAT constants). // Requires ChatID and a valid Action (see Chat constants).
func (bot *BotApi) SendChatAction(config ChatActionConfig) error { func (bot *BotAPI) SendChatAction(config ChatActionConfig) error {
v := url.Values{} v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId)) v.Add("chat_id", strconv.Itoa(config.ChatID))
v.Add("action", config.Action) v.Add("action", config.Action)
_, err := bot.MakeRequest("sendChatAction", v) _, err := bot.MakeRequest("sendChatAction", v)
@ -678,13 +692,13 @@ func (bot *BotApi) SendChatAction(config ChatActionConfig) error {
return nil return nil
} }
// Gets a user's profile photos. // GetUserProfilePhotos gets a user's profile photos.
// //
// Requires UserId. // Requires UserID.
// Offset and Limit are optional. // Offset and Limit are optional.
func (bot *BotApi) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) { func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
v := url.Values{} v := url.Values{}
v.Add("user_id", strconv.Itoa(config.UserId)) v.Add("user_id", strconv.Itoa(config.UserID))
if config.Offset != 0 { if config.Offset != 0 {
v.Add("offset", strconv.Itoa(config.Offset)) v.Add("offset", strconv.Itoa(config.Offset))
} }
@ -708,13 +722,13 @@ func (bot *BotApi) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserPro
return profilePhotos, nil return profilePhotos, nil
} }
// Fetches updates. // GetUpdates fetches updates.
// If a WebHook is set, this will not return any data! // If a WebHook is set, this will not return any data!
// //
// Offset, Limit, and Timeout are optional. // Offset, Limit, and Timeout are optional.
// To not get old items, set Offset to one higher than the previous item. // To not get old items, set Offset to one higher than the previous item.
// Set Timeout to a large number to reduce requests and get responses instantly. // Set Timeout to a large number to reduce requests and get responses instantly.
func (bot *BotApi) GetUpdates(config UpdateConfig) ([]Update, error) { func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
v := url.Values{} v := url.Values{}
if config.Offset > 0 { if config.Offset > 0 {
v.Add("offset", strconv.Itoa(config.Offset)) v.Add("offset", strconv.Itoa(config.Offset))
@ -741,14 +755,14 @@ func (bot *BotApi) GetUpdates(config UpdateConfig) ([]Update, error) {
return updates, nil return updates, nil
} }
// Sets a webhook. // SetWebhook sets a webhook.
// If this is set, GetUpdates will not get any data! // If this is set, GetUpdates will not get any data!
// //
// Requires Url OR to set Clear to true. // Requires Url OR to set Clear to true.
func (bot *BotApi) SetWebhook(config WebhookConfig) error { func (bot *BotAPI) SetWebhook(config WebhookConfig) error {
v := url.Values{} v := url.Values{}
if !config.Clear { if !config.Clear {
v.Add("url", config.Url.String()) v.Add("url", config.URL.String())
} }
_, err := bot.MakeRequest("setWebhook", v) _, err := bot.MakeRequest("setWebhook", v)

View File

@ -4,40 +4,46 @@ import (
"encoding/json" "encoding/json"
) )
type ApiResponse struct { // APIResponse is a response from the Telegram API with the result stored raw.
type APIResponse struct {
Ok bool `json:"ok"` Ok bool `json:"ok"`
Result json.RawMessage `json:"result"` Result json.RawMessage `json:"result"`
ErrorCode int `json:"error_code"` ErrorCode int `json:"error_code"`
Description string `json:"description"` Description string `json:"description"`
} }
// Update is an update response, from GetUpdates.
type Update struct { type Update struct {
UpdateId int `json:"update_id"` UpdateID int `json:"update_id"`
Message Message `json:"message"` Message Message `json:"message"`
} }
// User is a user, contained in Message and returned by GetSelf.
type User struct { type User struct {
Id int `json:"id"` ID int `json:"id"`
FirstName string `json:"first_name"` FirstName string `json:"first_name"`
LastName string `json:"last_name"` LastName string `json:"last_name"`
UserName string `json:"username"` UserName string `json:"username"`
} }
// GroupChat is a group chat, and not currently in use.
type GroupChat struct { type GroupChat struct {
Id int `json:"id"` ID int `json:"id"`
Title string `json:"title"` Title string `json:"title"`
} }
// UserOrGroupChat is returned in Message, because it's not clear which it is.
type UserOrGroupChat struct { type UserOrGroupChat struct {
Id int `json:"id"` ID int `json:"id"`
FirstName string `json:"first_name"` FirstName string `json:"first_name"`
LastName string `json:"last_name"` LastName string `json:"last_name"`
UserName string `json:"username"` UserName string `json:"username"`
Title string `json:"title"` Title string `json:"title"`
} }
// Message is returned by almost every request, and contains data about almost anything.
type Message struct { type Message struct {
MessageId int `json:"message_id"` MessageID int `json:"message_id"`
From User `json:"from"` From User `json:"from"`
Date int `json:"date"` Date int `json:"date"`
Chat UserOrGroupChat `json:"chat"` Chat UserOrGroupChat `json:"chat"`
@ -60,64 +66,73 @@ type Message struct {
GroupChatCreated bool `json:"group_chat_created"` GroupChatCreated bool `json:"group_chat_created"`
} }
// PhotoSize contains information about photos, including ID and Width and Height.
type PhotoSize struct { type PhotoSize struct {
FileId string `json:"file_id"` FileID string `json:"file_id"`
Width int `json:"width"` Width int `json:"width"`
Height int `json:"height"` Height int `json:"height"`
FileSize int `json:"file_size"` FileSize int `json:"file_size"`
} }
// Audio contains information about audio, including ID and Duration.
type Audio struct { type Audio struct {
FileId string `json:"file_id"` FileID string `json:"file_id"`
Duration int `json:"duration"` Duration int `json:"duration"`
MimeType string `json:"mime_type"` MimeType string `json:"mime_type"`
FileSize int `json:"file_size"` FileSize int `json:"file_size"`
} }
// Document contains information about a document, including ID and a Thumbnail.
type Document struct { type Document struct {
FileId string `json:"file_id"` FileID string `json:"file_id"`
Thumb PhotoSize `json:"thumb"` Thumbnail PhotoSize `json:"thumb"`
FileName string `json:"file_name"` FileName string `json:"file_name"`
MimeType string `json:"mime_type"` MimeType string `json:"mime_type"`
FileSize int `json:"file_size"` FileSize int `json:"file_size"`
} }
// Sticker contains information about a sticker, including ID and Thumbnail.
type Sticker struct { type Sticker struct {
FileId string `json:"file_id"` FileID string `json:"file_id"`
Width int `json:"width"` Width int `json:"width"`
Height int `json:"height"` Height int `json:"height"`
Thumb PhotoSize `json:"thumb"` Thumbnail PhotoSize `json:"thumb"`
FileSize int `json:"file_size"` FileSize int `json:"file_size"`
} }
// Video contains information about a video, including ID and duration and Thumbnail.
type Video struct { type Video struct {
FileId string `json:"file_id"` FileID string `json:"file_id"`
Width int `json:"width"` Width int `json:"width"`
Height int `json:"height"` Height int `json:"height"`
Duration int `json:"duration"` Duration int `json:"duration"`
Thumb PhotoSize `json:"thumb"` Thumbnail PhotoSize `json:"thumb"`
MimeType string `json:"mime_type"` MimeType string `json:"mime_type"`
FileSize int `json:"file_size"` FileSize int `json:"file_size"`
Caption string `json:"caption"` Caption string `json:"caption"`
} }
// Contact contains information about a contact, such as PhoneNumber and UserId.
type Contact struct { type Contact struct {
PhoneNumber string `json:"phone_number"` PhoneNumber string `json:"phone_number"`
FirstName string `json:"first_name"` FirstName string `json:"first_name"`
LastName string `json:"last_name"` LastName string `json:"last_name"`
UserId string `json:"user_id"` UserID string `json:"user_id"`
} }
// Location contains information about a place, such as Longitude and Latitude.
type Location struct { type Location struct {
Longitude float32 `json:"longitude"` Longitude float32 `json:"longitude"`
Latitude float32 `json:"latitude"` Latitude float32 `json:"latitude"`
} }
// UserProfilePhotos contains information a set of user profile photos.
type UserProfilePhotos struct { type UserProfilePhotos struct {
TotalCount int `json:"total_count"` TotalCount int `json:"total_count"`
Photos []PhotoSize `json:"photos"` Photos []PhotoSize `json:"photos"`
} }
// ReplyKeyboardMarkup allows the Bot to set a custom keyboard.
type ReplyKeyboardMarkup struct { type ReplyKeyboardMarkup struct {
Keyboard [][]string `json:"keyboard"` Keyboard [][]string `json:"keyboard"`
ResizeKeyboard bool `json:"resize_keyboard"` ResizeKeyboard bool `json:"resize_keyboard"`
@ -125,11 +140,13 @@ type ReplyKeyboardMarkup struct {
Selective bool `json:"selective"` Selective bool `json:"selective"`
} }
// ReplyKeyboardHide allows the Bot to hide a custom keyboard.
type ReplyKeyboardHide struct { type ReplyKeyboardHide struct {
HideKeyboard bool `json:"hide_keyboard"` HideKeyboard bool `json:"hide_keyboard"`
Selective bool `json:"selective"` Selective bool `json:"selective"`
} }
// ForceReply allows the Bot to have users directly reply to it without additional interaction.
type ForceReply struct { type ForceReply struct {
ForceReply bool `json:"force_reply"` ForceReply bool `json:"force_reply"`
Selective bool `json:"force_reply"` Selective bool `json:"force_reply"`

View File

@ -1,7 +1,7 @@
package tgbotapi package tgbotapi
// Returns a chan that is called whenever a new message is gotten. // UpdatesChan returns a chan that is called whenever a new message is gotten.
func (bot *BotApi) UpdatesChan(config UpdateConfig) (chan Update, error) { func (bot *BotAPI) UpdatesChan(config UpdateConfig) (chan Update, error) {
bot.Updates = make(chan Update, 100) bot.Updates = make(chan Update, 100)
go func() { go func() {
@ -11,8 +11,8 @@ func (bot *BotApi) UpdatesChan(config UpdateConfig) (chan Update, error) {
} }
for _, update := range updates { for _, update := range updates {
if update.UpdateId > config.Offset { if update.UpdateID > config.Offset {
config.Offset = update.UpdateId + 1 config.Offset = update.UpdateID + 1
} }
bot.Updates <- update bot.Updates <- update