commit
434756c165
@ -0,0 +1,109 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"flag" |
||||
"io/ioutil" |
||||
"log" |
||||
"strconv" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
type Config struct { |
||||
Token string `json:"token"` |
||||
} |
||||
|
||||
type Plugin interface { |
||||
GetCommand() string |
||||
GotCommand(Message, []string) |
||||
} |
||||
|
||||
type ColonThree struct { |
||||
} |
||||
|
||||
func (plugin *ColonThree) GetCommand() string { |
||||
return "/three" |
||||
} |
||||
|
||||
func (plugin *ColonThree) GotCommand(message Message, args []string) { |
||||
if len(args) > 0 { |
||||
n, err := strconv.Atoi(args[0]) |
||||
if err != nil { |
||||
msg := NewMessage(message.Chat.Id, "Bad number!") |
||||
msg.ReplyToMessageId = message.MessageId |
||||
|
||||
bot.sendMessage(msg) |
||||
|
||||
return |
||||
} |
||||
|
||||
if n > 5 { |
||||
msg := NewMessage(message.Chat.Id, "That's a bit much, no?") |
||||
msg.ReplyToMessageId = message.MessageId |
||||
|
||||
bot.sendMessage(msg) |
||||
|
||||
return |
||||
} |
||||
|
||||
for i := 0; i < n; i++ { |
||||
bot.sendMessage(NewMessage(message.Chat.Id, ":3")) |
||||
} |
||||
} else { |
||||
bot.sendMessage(NewMessage(message.Chat.Id, ":3")) |
||||
} |
||||
} |
||||
|
||||
var bot *BotApi |
||||
|
||||
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) |
||||
} |
||||
|
||||
var cfg Config |
||||
json.Unmarshal(data, &cfg) |
||||
|
||||
bot = NewBotApi(BotConfig{ |
||||
token: cfg.Token, |
||||
debug: true, |
||||
}) |
||||
|
||||
plugins := []Plugin{&ColonThree{}} |
||||
|
||||
ticker := time.NewTicker(5 * time.Second) |
||||
|
||||
lastUpdate := 0 |
||||
|
||||
for range ticker.C { |
||||
updates, err := bot.getUpdates(NewUpdate(lastUpdate + 1)) |
||||
|
||||
if err != nil { |
||||
log.Panic(err) |
||||
} |
||||
|
||||
for _, update := range updates { |
||||
lastUpdate = update.UpdateId |
||||
|
||||
if update.Message.Text == "" { |
||||
continue |
||||
} |
||||
|
||||
for _, plugin := range plugins { |
||||
parts := strings.Split(update.Message.Text, " ") |
||||
|
||||
if plugin.GetCommand() == parts[0] { |
||||
parts = append(parts[:0], parts[1:]...) |
||||
|
||||
plugin.GotCommand(update.Message, parts) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,443 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"io/ioutil" |
||||
"log" |
||||
"net/http" |
||||
"net/url" |
||||
"strconv" |
||||
) |
||||
|
||||
const ( |
||||
CHAT_TYPING = "typing" |
||||
CHAT_UPLOAD_PHOTO = "upload_photo" |
||||
CHAT_RECORD_VIDEO = "record_video" |
||||
CHAT_UPLOAD_VIDEO = "upload_video" |
||||
CHAT_RECORD_AUDIO = "record_audio" |
||||
CHAT_UPLOAD_AUDIO = "upload_audio" |
||||
CHAT_UPLOAD_DOCUMENT = "upload_document" |
||||
CHAT_FIND_LOCATION = "find_location" |
||||
) |
||||
|
||||
type BotConfig struct { |
||||
token string |
||||
debug bool |
||||
} |
||||
|
||||
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, |
||||
} |
||||
} |
||||
|
||||
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{}, nil |
||||
} |
||||
|
||||
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)) |
||||
} |
||||
|
||||
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) 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 |
||||
} |
||||
|
||||
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 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, |
||||
} |
||||
} |
Reference in new issue