working file uploads, starting to clean up code

bot-api-6.1
Syfaro 2015-06-25 11:25:02 -05:00
parent 564e04b9a2
commit 059baffbfb
3 changed files with 331 additions and 168 deletions

2
bot.go
View File

@ -52,6 +52,8 @@ func (plugin *ColonThree) GotCommand(message Message, args []string) {
}
} else {
bot.sendMessage(NewMessage(message.Chat.Id, ":3"))
bot.sendPhoto(NewPhotoUpload(message.Chat.Id, "fox.png"))
}
}

View File

@ -1,11 +1,15 @@
package main
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"net/url"
"os"
"strconv"
)
@ -29,173 +33,6 @@ type BotApi struct {
config BotConfig
}
type ApiResponse struct {
Ok bool `json:"ok"`
Result json.RawMessage `json:"result"`
}
type Update struct {
UpdateId int `json:"update_id"`
Message Message `json:"message"`
}
type User struct {
Id int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserName string `json:"username"`
}
type GroupChat struct {
Id int `json:"id"`
Title string `json:"title"`
}
type UserOrGroupChat struct {
Id int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserName string `json:"username"`
Title string `json:"title"`
}
type Message struct {
MessageId int `json:"message_id"`
From User `json:"from"`
Date int `json:"date"`
Chat UserOrGroupChat `json:"chat"`
ForwardFrom User `json:"forward_from"`
ForwardDate int `json:"forward_date"`
ReplyToMessage *Message `json:"reply_to_message"`
Text string `json:"text"`
Audio Audio `json:"audio"`
Document Document `json:"document"`
Photo []PhotoSize `json:"photo"`
Sticker Sticker `json:"sticker"`
Video Video `json:"video"`
Contact Contact `json:"contact"`
Location Location `json:"location"`
NewChatParticipant User `json:"new_chat_participant"`
LeftChatParticipant User `json:"left_chat_participant"`
NewChatTitle string `json:"new_chat_title"`
NewChatPhoto string `json:"new_chat_photo"`
DeleteChatPhoto bool `json:"delete_chat_photo"`
GroupChatCreated bool `json:"group_chat_created"`
}
type PhotoSize struct {
FileId string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
FileSize int `json:"file_size"`
}
type Audio struct {
FileId string `json:"file_id"`
Duration int `json:"duration"`
MimeType string `json:"mime_type"`
FileSize int `json:"file_size"`
}
type Document struct {
FileId string `json:"file_id"`
Thumb PhotoSize `json:"thumb"`
FileName string `json:"file_name"`
MimeType string `json:"mime_type"`
FileSize int `json:"file_size"`
}
type Sticker struct {
FileId string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
Thumb PhotoSize `json:"thumb"`
FileSize int `json:"file_size"`
}
type Video struct {
FileId string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
Duration int `json:"duration"`
Thumb PhotoSize `json:"thumb"`
MimeType string `json:"mime_type"`
FileSize int `json:"file_size"`
Caption string `json:"caption"`
}
type Contact struct {
PhoneNumber string `json:"phone_number"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserId string `json:"user_id"`
}
type Location struct {
Longitude float32 `json:"longitude"`
Latitude float32 `json:"latitude"`
}
type UserProfilePhotos struct {
TotalCount int `json:"total_count"`
Photos []PhotoSize `json:"photos"`
}
type ReplyKeyboardMarkup struct {
Keyboard map[string]map[string]string `json:"keyboard"`
ResizeKeyboard bool `json:"resize_keyboard"`
OneTimeKeyboard bool `json:"one_time_keyboard"`
Selective bool `json:"selective"`
}
type ReplyKeyboardHide struct {
HideKeyboard bool `json:"hide_keyboard"`
Selective bool `json:"selective"`
}
type ForceReply struct {
ForceReply bool `json:"force_reply"`
Selective bool `json:"force_reply"`
}
type UpdateConfig struct {
Offset int
Limit int
Timeout int
}
type MessageConfig struct {
ChatId int
Text string
DisableWebPagePreview bool
ReplyToMessageId int
}
type ForwardConfig struct {
ChatId int
FromChatId int
MessageId int
}
type LocationConfig struct {
ChatId int
Latitude float64
Longitude float64
ReplyToMessageId int
ReplyMarkup interface{}
}
type ChatActionConfig struct {
ChatId int
Action string
}
type UserProfilePhotosConfig struct {
UserId int
Offset int
Limit int
}
func NewBotApi(config BotConfig) *BotApi {
return &BotApi{
config: config,
@ -211,7 +48,65 @@ func (bot *BotApi) makeRequest(endpoint string, params url.Values) (ApiResponse,
bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return ApiResponse{}, 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) 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 {
@ -287,6 +182,74 @@ func (bot *BotApi) forwardMessage(config ForwardConfig) (Message, error) {
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) sendLocation(config LocationConfig) (Message, error) {
v := url.Values{}
v.Add("chat_id", strconv.Itoa(config.ChatId))
@ -392,6 +355,54 @@ func (bot *BotApi) setWebhook(v url.Values) error {
return err
}
type UpdateConfig struct {
Offset int
Limit int
Timeout int
}
type MessageConfig struct {
ChatId int
Text string
DisableWebPagePreview bool
ReplyToMessageId int
}
type ForwardConfig struct {
ChatId int
FromChatId int
MessageId int
}
type PhotoConfig struct {
ChatId int
Caption string
ReplyToMessageId int
ReplyMarkup interface{}
UseExistingPhoto bool
FilePath string
FileId string
}
type LocationConfig struct {
ChatId int
Latitude float64
Longitude float64
ReplyToMessageId int
ReplyMarkup interface{}
}
type ChatActionConfig struct {
ChatId int
Action string
}
type UserProfilePhotosConfig struct {
UserId int
Offset int
Limit int
}
func NewMessage(chatId int, text string) MessageConfig {
return MessageConfig{
ChatId: chatId,
@ -409,6 +420,22 @@ func NewForward(chatId int, fromChatId int, messageId int) ForwardConfig {
}
}
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 NewLocation(chatId int, latitude float64, longitude float64) LocationConfig {
return LocationConfig{
ChatId: chatId,

134
responses.go 100644
View File

@ -0,0 +1,134 @@
package main
import (
"encoding/json"
)
type ApiResponse struct {
Ok bool `json:"ok"`
Result json.RawMessage `json:"result"`
}
type Update struct {
UpdateId int `json:"update_id"`
Message Message `json:"message"`
}
type User struct {
Id int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserName string `json:"username"`
}
type GroupChat struct {
Id int `json:"id"`
Title string `json:"title"`
}
type UserOrGroupChat struct {
Id int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserName string `json:"username"`
Title string `json:"title"`
}
type Message struct {
MessageId int `json:"message_id"`
From User `json:"from"`
Date int `json:"date"`
Chat UserOrGroupChat `json:"chat"`
ForwardFrom User `json:"forward_from"`
ForwardDate int `json:"forward_date"`
ReplyToMessage *Message `json:"reply_to_message"`
Text string `json:"text"`
Audio Audio `json:"audio"`
Document Document `json:"document"`
Photo []PhotoSize `json:"photo"`
Sticker Sticker `json:"sticker"`
Video Video `json:"video"`
Contact Contact `json:"contact"`
Location Location `json:"location"`
NewChatParticipant User `json:"new_chat_participant"`
LeftChatParticipant User `json:"left_chat_participant"`
NewChatTitle string `json:"new_chat_title"`
NewChatPhoto string `json:"new_chat_photo"`
DeleteChatPhoto bool `json:"delete_chat_photo"`
GroupChatCreated bool `json:"group_chat_created"`
}
type PhotoSize struct {
FileId string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
FileSize int `json:"file_size"`
}
type Audio struct {
FileId string `json:"file_id"`
Duration int `json:"duration"`
MimeType string `json:"mime_type"`
FileSize int `json:"file_size"`
}
type Document struct {
FileId string `json:"file_id"`
Thumb PhotoSize `json:"thumb"`
FileName string `json:"file_name"`
MimeType string `json:"mime_type"`
FileSize int `json:"file_size"`
}
type Sticker struct {
FileId string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
Thumb PhotoSize `json:"thumb"`
FileSize int `json:"file_size"`
}
type Video struct {
FileId string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
Duration int `json:"duration"`
Thumb PhotoSize `json:"thumb"`
MimeType string `json:"mime_type"`
FileSize int `json:"file_size"`
Caption string `json:"caption"`
}
type Contact struct {
PhoneNumber string `json:"phone_number"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
UserId string `json:"user_id"`
}
type Location struct {
Longitude float32 `json:"longitude"`
Latitude float32 `json:"latitude"`
}
type UserProfilePhotos struct {
TotalCount int `json:"total_count"`
Photos []PhotoSize `json:"photos"`
}
type ReplyKeyboardMarkup struct {
Keyboard map[string]map[string]string `json:"keyboard"`
ResizeKeyboard bool `json:"resize_keyboard"`
OneTimeKeyboard bool `json:"one_time_keyboard"`
Selective bool `json:"selective"`
}
type ReplyKeyboardHide struct {
HideKeyboard bool `json:"hide_keyboard"`
Selective bool `json:"selective"`
}
type ForceReply struct {
ForceReply bool `json:"force_reply"`
Selective bool `json:"force_reply"`
}