Merge pull request #29 from zhulik/master
Major overhaul to make everything easier to usepull/33/head
commit
b034326d85
@ -0,0 +1,2 @@ |
|||||||
|
.idea/ |
||||||
|
coverage.out |
@ -0,0 +1,5 @@ |
|||||||
|
language: go |
||||||
|
|
||||||
|
go: |
||||||
|
- 1.4 |
||||||
|
- tip |
@ -0,0 +1,498 @@ |
|||||||
|
package tgbotapi |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"io" |
||||||
|
"net/url" |
||||||
|
"strconv" |
||||||
|
) |
||||||
|
|
||||||
|
// Telegram constants
|
||||||
|
const ( |
||||||
|
// APIEndpoint is the endpoint for all API methods, with formatting for Sprintf
|
||||||
|
APIEndpoint = "https://api.telegram.org/bot%s/%s" |
||||||
|
// FileEndpoint is the endpoint for downloading a file from Telegram
|
||||||
|
FileEndpoint = "https://api.telegram.org/file/bot%s/%s" |
||||||
|
) |
||||||
|
|
||||||
|
// Constant values for ChatActions
|
||||||
|
const ( |
||||||
|
ChatTyping = "typing" |
||||||
|
ChatUploadPhoto = "upload_photo" |
||||||
|
ChatRecordVideo = "record_video" |
||||||
|
ChatUploadVideo = "upload_video" |
||||||
|
ChatRecordAudio = "record_audio" |
||||||
|
ChatUploadAudio = "upload_audio" |
||||||
|
ChatUploadDocument = "upload_document" |
||||||
|
ChatFindLocation = "find_location" |
||||||
|
) |
||||||
|
|
||||||
|
// API errors
|
||||||
|
const ( |
||||||
|
// APIForbidden happens when a token is bad
|
||||||
|
APIForbidden = "forbidden" |
||||||
|
) |
||||||
|
|
||||||
|
// Constant values for ParseMode in MessageConfig
|
||||||
|
const ( |
||||||
|
ModeMarkdown = "Markdown" |
||||||
|
) |
||||||
|
|
||||||
|
//Chattable represents any event in chat(MessageConfig, PhotoConfig, ChatActionConfig and others)
|
||||||
|
type Chattable interface { |
||||||
|
Values() (url.Values, error) |
||||||
|
Method() string |
||||||
|
} |
||||||
|
|
||||||
|
//Fileable represents any file event(PhotoConfig, DocumentConfig, AudioConfig, VoiceConfig, VideoConfig, StickerConfig)
|
||||||
|
type Fileable interface { |
||||||
|
Chattable |
||||||
|
Params() (map[string]string, error) |
||||||
|
Name() string |
||||||
|
GetFile() interface{} |
||||||
|
UseExistingFile() bool |
||||||
|
} |
||||||
|
|
||||||
|
// BaseChat is base struct for all chat event(Message, Photo and so on)
|
||||||
|
type BaseChat struct { |
||||||
|
ChatID int |
||||||
|
ChannelUsername string |
||||||
|
ReplyToMessageID int |
||||||
|
ReplyMarkup interface{} |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of BaseChat
|
||||||
|
func (chat *BaseChat) Values() (url.Values, error) { |
||||||
|
v := url.Values{} |
||||||
|
if chat.ChannelUsername != "" { |
||||||
|
v.Add("chat_id", chat.ChannelUsername) |
||||||
|
} else { |
||||||
|
v.Add("chat_id", strconv.Itoa(chat.ChatID)) |
||||||
|
} |
||||||
|
|
||||||
|
if chat.ReplyToMessageID != 0 { |
||||||
|
v.Add("reply_to_message_id", strconv.Itoa(chat.ReplyToMessageID)) |
||||||
|
} |
||||||
|
|
||||||
|
if chat.ReplyMarkup != nil { |
||||||
|
data, err := json.Marshal(chat.ReplyMarkup) |
||||||
|
if err != nil { |
||||||
|
return v, err |
||||||
|
} |
||||||
|
|
||||||
|
v.Add("reply_markup", string(data)) |
||||||
|
} |
||||||
|
|
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// BaseFile is base struct for all file events(PhotoConfig, DocumentConfig, AudioConfig, VoiceConfig, VideoConfig, StickerConfig)
|
||||||
|
type BaseFile struct { |
||||||
|
BaseChat |
||||||
|
FilePath string |
||||||
|
File interface{} |
||||||
|
FileID string |
||||||
|
UseExisting bool |
||||||
|
} |
||||||
|
|
||||||
|
// Params returns map[string]string representation of BaseFile
|
||||||
|
func (file BaseFile) Params() (map[string]string, error) { |
||||||
|
params := make(map[string]string) |
||||||
|
|
||||||
|
if file.ChannelUsername != "" { |
||||||
|
params["chat_id"] = file.ChannelUsername |
||||||
|
} else { |
||||||
|
params["chat_id"] = strconv.Itoa(file.ChatID) |
||||||
|
} |
||||||
|
|
||||||
|
if file.ReplyToMessageID != 0 { |
||||||
|
params["reply_to_message_id"] = strconv.Itoa(file.ReplyToMessageID) |
||||||
|
} |
||||||
|
|
||||||
|
if file.ReplyMarkup != nil { |
||||||
|
data, err := json.Marshal(file.ReplyMarkup) |
||||||
|
if err != nil { |
||||||
|
return params, err |
||||||
|
} |
||||||
|
|
||||||
|
params["reply_markup"] = string(data) |
||||||
|
} |
||||||
|
|
||||||
|
return params, nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetFile returns abstract representation of File inside BaseFile
|
||||||
|
func (file BaseFile) GetFile() interface{} { |
||||||
|
var result interface{} |
||||||
|
if file.FilePath == "" { |
||||||
|
result = file.File |
||||||
|
} else { |
||||||
|
result = file.FilePath |
||||||
|
} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
// UseExistingFile returns true if BaseFile contains already uploaded file by FileID
|
||||||
|
func (file BaseFile) UseExistingFile() bool { |
||||||
|
return file.UseExisting |
||||||
|
} |
||||||
|
|
||||||
|
// MessageConfig contains information about a SendMessage request.
|
||||||
|
type MessageConfig struct { |
||||||
|
BaseChat |
||||||
|
Text string |
||||||
|
ParseMode string |
||||||
|
DisableWebPagePreview bool |
||||||
|
ReplyMarkup interface{} |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of MessageConfig
|
||||||
|
func (config MessageConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
v.Add("text", config.Text) |
||||||
|
v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview)) |
||||||
|
if config.ParseMode != "" { |
||||||
|
v.Add("parse_mode", config.ParseMode) |
||||||
|
} |
||||||
|
|
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Message
|
||||||
|
func (config MessageConfig) Method() string { |
||||||
|
return "SendMessage" |
||||||
|
} |
||||||
|
|
||||||
|
// ForwardConfig contains information about a ForwardMessage request.
|
||||||
|
type ForwardConfig struct { |
||||||
|
BaseChat |
||||||
|
FromChatID int |
||||||
|
FromChannelUsername string |
||||||
|
MessageID int |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of ForwardConfig
|
||||||
|
func (config ForwardConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
v.Add("from_chat_id", strconv.Itoa(config.FromChatID)) |
||||||
|
v.Add("message_id", strconv.Itoa(config.MessageID)) |
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Forward
|
||||||
|
func (config ForwardConfig) Method() string { |
||||||
|
return "forwardMessage" |
||||||
|
} |
||||||
|
|
||||||
|
// PhotoConfig contains information about a SendPhoto request.
|
||||||
|
type PhotoConfig struct { |
||||||
|
BaseFile |
||||||
|
Caption string |
||||||
|
} |
||||||
|
|
||||||
|
// Params returns map[string]string representation of PhotoConfig
|
||||||
|
func (config PhotoConfig) Params() (map[string]string, error) { |
||||||
|
params, _ := config.BaseFile.Params() |
||||||
|
|
||||||
|
if config.Caption != "" { |
||||||
|
params["caption"] = config.Caption |
||||||
|
} |
||||||
|
|
||||||
|
return params, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of PhotoConfig
|
||||||
|
func (config PhotoConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
|
||||||
|
v.Add(config.Name(), config.FileID) |
||||||
|
if config.Caption != "" { |
||||||
|
v.Add("caption", config.Caption) |
||||||
|
} |
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Name return field name for uploading file
|
||||||
|
func (config PhotoConfig) Name() string { |
||||||
|
return "photo" |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Photo
|
||||||
|
func (config PhotoConfig) Method() string { |
||||||
|
return "SendPhoto" |
||||||
|
} |
||||||
|
|
||||||
|
// AudioConfig contains information about a SendAudio request.
|
||||||
|
type AudioConfig struct { |
||||||
|
BaseFile |
||||||
|
Duration int |
||||||
|
Performer string |
||||||
|
Title string |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of AudioConfig
|
||||||
|
func (config AudioConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
|
||||||
|
v.Add(config.Name(), config.FileID) |
||||||
|
if config.Duration != 0 { |
||||||
|
v.Add("duration", strconv.Itoa(config.Duration)) |
||||||
|
} |
||||||
|
|
||||||
|
if config.Performer != "" { |
||||||
|
v.Add("performer", config.Performer) |
||||||
|
} |
||||||
|
if config.Title != "" { |
||||||
|
v.Add("title", config.Title) |
||||||
|
} |
||||||
|
|
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Params returns map[string]string representation of AudioConfig
|
||||||
|
func (config AudioConfig) Params() (map[string]string, error) { |
||||||
|
params, _ := config.BaseFile.Params() |
||||||
|
|
||||||
|
if config.Duration != 0 { |
||||||
|
params["duration"] = strconv.Itoa(config.Duration) |
||||||
|
} |
||||||
|
|
||||||
|
if config.Performer != "" { |
||||||
|
params["performer"] = config.Performer |
||||||
|
} |
||||||
|
if config.Title != "" { |
||||||
|
params["title"] = config.Title |
||||||
|
} |
||||||
|
|
||||||
|
return params, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Name return field name for uploading file
|
||||||
|
func (config AudioConfig) Name() string { |
||||||
|
return "audio" |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Audio
|
||||||
|
func (config AudioConfig) Method() string { |
||||||
|
return "SendAudio" |
||||||
|
} |
||||||
|
|
||||||
|
// DocumentConfig contains information about a SendDocument request.
|
||||||
|
type DocumentConfig struct { |
||||||
|
BaseFile |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of DocumentConfig
|
||||||
|
func (config DocumentConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
|
||||||
|
v.Add(config.Name(), config.FileID) |
||||||
|
|
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Params returns map[string]string representation of DocumentConfig
|
||||||
|
func (config DocumentConfig) Params() (map[string]string, error) { |
||||||
|
params, _ := config.BaseFile.Params() |
||||||
|
|
||||||
|
return params, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Name return field name for uploading file
|
||||||
|
func (config DocumentConfig) Name() string { |
||||||
|
return "document" |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Document
|
||||||
|
func (config DocumentConfig) Method() string { |
||||||
|
return "sendDocument" |
||||||
|
} |
||||||
|
|
||||||
|
// StickerConfig contains information about a SendSticker request.
|
||||||
|
type StickerConfig struct { |
||||||
|
BaseFile |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of StickerConfig
|
||||||
|
func (config StickerConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
|
||||||
|
v.Add(config.Name(), config.FileID) |
||||||
|
|
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Params returns map[string]string representation of StickerConfig
|
||||||
|
func (config StickerConfig) Params() (map[string]string, error) { |
||||||
|
params, _ := config.BaseFile.Params() |
||||||
|
|
||||||
|
return params, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Name return field name for uploading file
|
||||||
|
func (config StickerConfig) Name() string { |
||||||
|
return "sticker" |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Sticker
|
||||||
|
func (config StickerConfig) Method() string { |
||||||
|
return "sendSticker" |
||||||
|
} |
||||||
|
|
||||||
|
// VideoConfig contains information about a SendVideo request.
|
||||||
|
type VideoConfig struct { |
||||||
|
BaseFile |
||||||
|
Duration int |
||||||
|
Caption string |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of VideoConfig
|
||||||
|
func (config VideoConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
|
||||||
|
v.Add(config.Name(), config.FileID) |
||||||
|
if config.Duration != 0 { |
||||||
|
v.Add("duration", strconv.Itoa(config.Duration)) |
||||||
|
} |
||||||
|
if config.Caption != "" { |
||||||
|
v.Add("caption", config.Caption) |
||||||
|
} |
||||||
|
|
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Params returns map[string]string representation of VideoConfig
|
||||||
|
func (config VideoConfig) Params() (map[string]string, error) { |
||||||
|
params, _ := config.BaseFile.Params() |
||||||
|
|
||||||
|
return params, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Name return field name for uploading file
|
||||||
|
func (config VideoConfig) Name() string { |
||||||
|
return "video" |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Video
|
||||||
|
func (config VideoConfig) Method() string { |
||||||
|
return "sendVideo" |
||||||
|
} |
||||||
|
|
||||||
|
// VoiceConfig contains information about a SendVoice request.
|
||||||
|
type VoiceConfig struct { |
||||||
|
BaseFile |
||||||
|
Duration int |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of VoiceConfig
|
||||||
|
func (config VoiceConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
|
||||||
|
v.Add(config.Name(), config.FileID) |
||||||
|
if config.Duration != 0 { |
||||||
|
v.Add("duration", strconv.Itoa(config.Duration)) |
||||||
|
} |
||||||
|
|
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Params returns map[string]string representation of VoiceConfig
|
||||||
|
func (config VoiceConfig) Params() (map[string]string, error) { |
||||||
|
params, _ := config.BaseFile.Params() |
||||||
|
|
||||||
|
if config.Duration != 0 { |
||||||
|
params["duration"] = strconv.Itoa(config.Duration) |
||||||
|
} |
||||||
|
|
||||||
|
return params, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Name return field name for uploading file
|
||||||
|
func (config VoiceConfig) Name() string { |
||||||
|
return "voice" |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Voice
|
||||||
|
func (config VoiceConfig) Method() string { |
||||||
|
return "sendVoice" |
||||||
|
} |
||||||
|
|
||||||
|
// LocationConfig contains information about a SendLocation request.
|
||||||
|
type LocationConfig struct { |
||||||
|
BaseChat |
||||||
|
Latitude float64 |
||||||
|
Longitude float64 |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of LocationConfig
|
||||||
|
func (config LocationConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
|
||||||
|
v.Add("latitude", strconv.FormatFloat(config.Latitude, 'f', 6, 64)) |
||||||
|
v.Add("longitude", strconv.FormatFloat(config.Longitude, 'f', 6, 64)) |
||||||
|
|
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending Location
|
||||||
|
func (config LocationConfig) Method() string { |
||||||
|
return "sendLocation" |
||||||
|
} |
||||||
|
|
||||||
|
// ChatActionConfig contains information about a SendChatAction request.
|
||||||
|
type ChatActionConfig struct { |
||||||
|
BaseChat |
||||||
|
Action string |
||||||
|
} |
||||||
|
|
||||||
|
// Values returns url.Values representation of ChatActionConfig
|
||||||
|
func (config ChatActionConfig) Values() (url.Values, error) { |
||||||
|
v, _ := config.BaseChat.Values() |
||||||
|
v.Add("action", config.Action) |
||||||
|
return v, nil |
||||||
|
} |
||||||
|
|
||||||
|
// Method returns Telegram API method name for sending ChatAction
|
||||||
|
func (config ChatActionConfig) Method() string { |
||||||
|
return "sendChatAction" |
||||||
|
} |
||||||
|
|
||||||
|
// UserProfilePhotosConfig contains information about a GetUserProfilePhotos request.
|
||||||
|
type UserProfilePhotosConfig struct { |
||||||
|
UserID int |
||||||
|
Offset int |
||||||
|
Limit int |
||||||
|
} |
||||||
|
|
||||||
|
// FileConfig has information about a file hosted on Telegram
|
||||||
|
type FileConfig struct { |
||||||
|
FileID string |
||||||
|
} |
||||||
|
|
||||||
|
// UpdateConfig contains information about a GetUpdates request.
|
||||||
|
type UpdateConfig struct { |
||||||
|
Offset int |
||||||
|
Limit int |
||||||
|
Timeout int |
||||||
|
} |
||||||
|
|
||||||
|
// WebhookConfig contains information about a SetWebhook request.
|
||||||
|
type WebhookConfig struct { |
||||||
|
URL *url.URL |
||||||
|
Certificate interface{} |
||||||
|
} |
||||||
|
|
||||||
|
// FileBytes contains information about a set of bytes to upload as a File.
|
||||||
|
type FileBytes struct { |
||||||
|
Name string |
||||||
|
Bytes []byte |
||||||
|
} |
||||||
|
|
||||||
|
// FileReader contains information about a reader to upload as a File.
|
||||||
|
// If Size is -1, it will read the entire Reader into memory to calculate a Size.
|
||||||
|
type FileReader struct { |
||||||
|
Name string |
||||||
|
Reader io.Reader |
||||||
|
Size int64 |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -0,0 +1,18 @@ |
|||||||
|
-----BEGIN CERTIFICATE----- |
||||||
|
MIIC0zCCAbugAwIBAgIJAPYfllX657axMA0GCSqGSIb3DQEBCwUAMAAwHhcNMTUx |
||||||
|
MTIxMTExMDQxWhcNMjUwODIwMTExMDQxWjAAMIIBIjANBgkqhkiG9w0BAQEFAAOC |
||||||
|
AQ8AMIIBCgKCAQEAoMMSIIgYx8pT8Kz1O8Ukd/JVyqBQYRSo0enqEzo7295VROXq |
||||||
|
TUthbEbdi0OczUfl4IsAWppOSRrDwEguJZ0cJ/r6IxGsbrCdQr2MjgiomYtAXKKQ |
||||||
|
GAGL5Wls+AzcRNV0OszVJzkDNFYZzgNejyitGJSNEQMyU8r2gyPyIWP9MQKQst8y |
||||||
|
Mg91R/7l9jwf6AWwNxykZlYZurtsQ6XsBPZpF9YOFL7vZYPhKUFiNEm+74RpojC7 |
||||||
|
Gt6nztYAUI2V/F+1uoXAr8nLpbj9SD0VSwyZLRG1uIVLBzhb0lfOIzAvJ45EKki9 |
||||||
|
nejyoXfH1U5+iMzdSAdcy3MCBhpEZwJPqhDqeQIDAQABo1AwTjAdBgNVHQ4EFgQU |
||||||
|
JE0RLM+ohLnlDz0Qk0McCxtDK2MwHwYDVR0jBBgwFoAUJE0RLM+ohLnlDz0Qk0Mc |
||||||
|
CxtDK2MwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAEmgME00JYuYZ |
||||||
|
4wNaGrJskZ05ZnP+TXJusmBui9ToQ4UoykuyY5rsdGQ3SdzXPLdmd2nfMsw63iK2 |
||||||
|
D7rjcH/rmn6fRccZqN0o0SXd/EuHeIoeW1Xnnivbt71b6mcOAeNg1UsMYxnMAVl0 |
||||||
|
ywdkta8gURltagSfXoUbqlnSxn/zCwqaxxcQXA/CnunvRsFtQrwWjDBPg/BPULHX |
||||||
|
DEh2AactGtnGqEZ5iap/VCOVnmL6iPdJ1x5UIF/gS6U96wL+GHfcs1jCvPg+GEwR |
||||||
|
3inh9oTXG9L21ge4lbGiPUIMBjtVcB3bXuQbOfec9Cr3ZhcQeZj680BIRxD/pNpA |
||||||
|
O/XeCfjfkw== |
||||||
|
-----END CERTIFICATE----- |
After Width: | Height: | Size: 84 KiB |
@ -0,0 +1,28 @@ |
|||||||
|
-----BEGIN PRIVATE KEY----- |
||||||
|
MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCgwxIgiBjHylPw |
||||||
|
rPU7xSR38lXKoFBhFKjR6eoTOjvb3lVE5epNS2FsRt2LQ5zNR+XgiwBamk5JGsPA |
||||||
|
SC4lnRwn+vojEaxusJ1CvYyOCKiZi0BcopAYAYvlaWz4DNxE1XQ6zNUnOQM0VhnO |
||||||
|
A16PKK0YlI0RAzJTyvaDI/IhY/0xApCy3zIyD3VH/uX2PB/oBbA3HKRmVhm6u2xD |
||||||
|
pewE9mkX1g4Uvu9lg+EpQWI0Sb7vhGmiMLsa3qfO1gBQjZX8X7W6hcCvyculuP1I |
||||||
|
PRVLDJktEbW4hUsHOFvSV84jMC8njkQqSL2d6PKhd8fVTn6IzN1IB1zLcwIGGkRn |
||||||
|
Ak+qEOp5AgMBAAECggEBAJ/dPCJzlEjhL5XPONLmGXzZ1Gx5/VR86eBMv0O9jhb3 |
||||||
|
wk2QYO3aPxggZGD/rGcKz1L6hzCR77WM0wpb/N/Um1I6pxHGmnU8VjYvLh10CM0f |
||||||
|
h7JWyfnFV+ubagxFJamhpkJuvKyTaldaI7EU8qxj47Xky18Wka53z6nbTgXcW8Sm |
||||||
|
V4CJy9OHNgKJQnylX6zOAaxVngSGde3xLslLjsYK4w9b2+OkCSUST2XXdo+ZLXxl |
||||||
|
cs0lEPFRM1Xh9/E6UrDrJMHHzio53L/W/+a8sIar1upgSY52pyD/tA7VSrAJ9nYC |
||||||
|
RezOU81VTLfMO+TYmgZzSUQJYh0cR4yqJe+wgl4U550CgYEA1EcS6Z+PO5Pr3u2+ |
||||||
|
XevawSAal6y9ONkkdOoASC977W37nn0E1wlQo41dR6DESCJfiSMeN0KbmXj5Wnc/ |
||||||
|
ADu+73iGwC90G9Qs9sjD7KAFBJvuj0V8hxvpWRdIBBbf7rlOj3CV0iXRYjkJbyJa |
||||||
|
cxuR0kiv4gTWmm5Cq+5ir8t1Oc8CgYEAwd+xOaDerNR481R+QmENFw+oR2EVMq3Q |
||||||
|
B/vinLK0PemQWrh32iBcd+vhSilOSQtUm1nko1jLK8C4s8X2vZYua4m5tcK9VqCt |
||||||
|
maCCq/ffxzsoW/GN8japnduz+qA+hKWJzW/aYR8tsOeqzjVqj4iIqPI4HuokrDi/ |
||||||
|
UD/QLgq5UTcCgYEAk2ZC0Kx15dXB7AtDq63xOTcUoAtXXRkSgohV58npEKXVGWkQ |
||||||
|
Kk0SjG7Fvc35XWlY0z3qZk6/AuOIqfOxcHUMEPatAtgwlH5RNo+T1EQNF/U6wotq |
||||||
|
e9q6vp026XgEyJwt29Y+giy2ZrDaRywgiFs1d0H3t0bKyXMUopQmPJFXdesCgYEA |
||||||
|
psCxXcDpZjxGX/zPsGZrbOdxtRtisTlg0k0rp93pO8tV90HtDHeDMT54g2ItzJPr |
||||||
|
TMev6XOpJNPZyf6+8GhpOuO2EQkT85u2VYoCeslz95gBabvFfIzZrUZYcnw76bm8 |
||||||
|
YjAP5DN+CEfq2PyG0Df+W1ojPSvlKSCSJQMOG1vr81cCgYEAkjPY5WR99uJxYBNI |
||||||
|
OTFMSkETgDUbPXBu/E/h5Dtn79v8Moj9FvC7+q6sg9qXhrGhfK2xDev3/sTrbS/E |
||||||
|
Gcf8UNIne3AXsoAS8MtkOwJXHkYaTIboIYgDX4LlDmbGQlIRaWgyh2POI6VtjLBT |
||||||
|
ms6AdsdpIB6As9xNUBUwj/RnTZQ= |
||||||
|
-----END PRIVATE KEY----- |
Binary file not shown.
Binary file not shown.
@ -1,92 +0,0 @@ |
|||||||
// Package tgutils provides extra functions to make certain tasks easier.
|
|
||||||
package tgutils |
|
||||||
|
|
||||||
import ( |
|
||||||
"github.com/syfaro/telegram-bot-api" |
|
||||||
"os" |
|
||||||
"os/exec" |
|
||||||
"path/filepath" |
|
||||||
"strconv" |
|
||||||
"sync" |
|
||||||
"time" |
|
||||||
) |
|
||||||
|
|
||||||
var rand uint32 |
|
||||||
var randmu sync.Mutex |
|
||||||
|
|
||||||
func reseed() uint32 { |
|
||||||
return uint32(time.Now().UnixNano() + int64(os.Getpid())) |
|
||||||
} |
|
||||||
|
|
||||||
func nextSuffix() string { |
|
||||||
randmu.Lock() |
|
||||||
r := rand |
|
||||||
if r == 0 { |
|
||||||
r = reseed() |
|
||||||
} |
|
||||||
r = r*1664525 + 1013904223 // constants from Numerical Recipes
|
|
||||||
rand = r |
|
||||||
randmu.Unlock() |
|
||||||
return strconv.Itoa(int(1e9 + r%1e9))[1:] |
|
||||||
} |
|
||||||
|
|
||||||
// this function ripped from ioutils.TempFile, except with a suffix, instead of prefix.
|
|
||||||
func tempFileWithSuffix(dir, suffix string) (f *os.File, err error) { |
|
||||||
if dir == "" { |
|
||||||
dir = os.TempDir() |
|
||||||
} |
|
||||||
|
|
||||||
nconflict := 0 |
|
||||||
for i := 0; i < 10000; i++ { |
|
||||||
name := filepath.Join(dir, nextSuffix()+suffix) |
|
||||||
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) |
|
||||||
if os.IsExist(err) { |
|
||||||
if nconflict++; nconflict > 10 { |
|
||||||
randmu.Lock() |
|
||||||
rand = reseed() |
|
||||||
randmu.Unlock() |
|
||||||
} |
|
||||||
continue |
|
||||||
} |
|
||||||
break |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
// EncodeAudio takes a file and attempts to convert it to a .ogg for Telegram.
|
|
||||||
// It then updates the path to the audio file in the AudioConfig.
|
|
||||||
//
|
|
||||||
// This function requires ffmpeg and opusenc to be installed on the system!
|
|
||||||
func EncodeAudio(audio *tgbotapi.AudioConfig) error { |
|
||||||
f, err := tempFileWithSuffix(os.TempDir(), "_tgutils.ogg") |
|
||||||
if err != nil { |
|
||||||
return err |
|
||||||
} |
|
||||||
defer f.Close() |
|
||||||
|
|
||||||
ffmpegArgs := []string{ |
|
||||||
"-i", |
|
||||||
audio.FilePath, |
|
||||||
"-f", |
|
||||||
"wav", |
|
||||||
"-", |
|
||||||
} |
|
||||||
|
|
||||||
opusArgs := []string{ |
|
||||||
"--bitrate", |
|
||||||
"256", |
|
||||||
"-", |
|
||||||
f.Name(), |
|
||||||
} |
|
||||||
|
|
||||||
c1 := exec.Command("ffmpeg", ffmpegArgs...) |
|
||||||
c2 := exec.Command("opusenc", opusArgs...) |
|
||||||
|
|
||||||
c2.Stdin, _ = c1.StdoutPipe() |
|
||||||
c2.Stdout = os.Stdout |
|
||||||
c2.Start() |
|
||||||
c1.Run() |
|
||||||
c2.Wait() |
|
||||||
|
|
||||||
return nil |
|
||||||
} |
|
@ -0,0 +1,74 @@ |
|||||||
|
package tgbotapi_test |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/Syfaro/telegram-bot-api" |
||||||
|
"testing" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
func TestUserStringWith(t *testing.T) { |
||||||
|
user := tgbotapi.User{0, "Test", "Test", ""} |
||||||
|
|
||||||
|
if user.String() != "Test Test" { |
||||||
|
t.Fail() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestUserStringWithUserName(t *testing.T) { |
||||||
|
user := tgbotapi.User{0, "Test", "Test", "@test"} |
||||||
|
|
||||||
|
if user.String() != "@test" { |
||||||
|
t.Fail() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestMessageIsGroup(t *testing.T) { |
||||||
|
from := tgbotapi.User{ID: 0} |
||||||
|
chat := tgbotapi.Chat{ID: 10} |
||||||
|
message := tgbotapi.Message{From: from, Chat: chat} |
||||||
|
|
||||||
|
if message.IsGroup() != true { |
||||||
|
t.Fail() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestMessageTime(t *testing.T) { |
||||||
|
message := tgbotapi.Message{Date: 0} |
||||||
|
|
||||||
|
date := time.Unix(0, 0) |
||||||
|
if message.Time() != date { |
||||||
|
t.Fail() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestChatIsPrivate(t *testing.T) { |
||||||
|
chat := tgbotapi.Chat{ID: 10, Type: "private"} |
||||||
|
|
||||||
|
if chat.IsPrivate() != true { |
||||||
|
t.Fail() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestChatIsGroup(t *testing.T) { |
||||||
|
chat := tgbotapi.Chat{ID: 10, Type: "group"} |
||||||
|
|
||||||
|
if chat.IsGroup() != true { |
||||||
|
t.Fail() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestChatIsChannel(t *testing.T) { |
||||||
|
chat := tgbotapi.Chat{ID: 10, Type: "channel"} |
||||||
|
|
||||||
|
if chat.IsChannel() != true { |
||||||
|
t.Fail() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func TestFileLink(t *testing.T) { |
||||||
|
file := tgbotapi.File{FilePath: "test/test.txt"} |
||||||
|
|
||||||
|
if file.Link("token") != "https://api.telegram.org/file/bottoken/test/test.txt" { |
||||||
|
t.Fail() |
||||||
|
} |
||||||
|
} |
@ -1,33 +0,0 @@ |
|||||||
package tgbotapi |
|
||||||
|
|
||||||
import ( |
|
||||||
"log" |
|
||||||
"time" |
|
||||||
) |
|
||||||
|
|
||||||
// UpdatesChan starts a channel for getting updates.
|
|
||||||
func (bot *BotAPI) UpdatesChan(config UpdateConfig) error { |
|
||||||
bot.Updates = make(chan Update, 100) |
|
||||||
|
|
||||||
go func() { |
|
||||||
for { |
|
||||||
updates, err := bot.GetUpdates(config) |
|
||||||
if err != nil { |
|
||||||
log.Println(err) |
|
||||||
log.Println("Failed to get updates, retrying in 3 seconds...") |
|
||||||
time.Sleep(time.Second * 3) |
|
||||||
|
|
||||||
continue |
|
||||||
} |
|
||||||
|
|
||||||
for _, update := range updates { |
|
||||||
if update.UpdateID >= config.Offset { |
|
||||||
config.Offset = update.UpdateID + 1 |
|
||||||
bot.Updates <- update |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
}() |
|
||||||
|
|
||||||
return nil |
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
package tgbotapi |
|
||||||
|
|
||||||
import ( |
|
||||||
"encoding/json" |
|
||||||
"io/ioutil" |
|
||||||
"net/http" |
|
||||||
) |
|
||||||
|
|
||||||
// ListenForWebhook registers a http handler for a webhook.
|
|
||||||
func (bot *BotAPI) ListenForWebhook(pattern string) { |
|
||||||
bot.Updates = make(chan Update, 100) |
|
||||||
|
|
||||||
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { |
|
||||||
bytes, _ := ioutil.ReadAll(r.Body) |
|
||||||
|
|
||||||
var update Update |
|
||||||
json.Unmarshal(bytes, &update) |
|
||||||
|
|
||||||
bot.Updates <- update |
|
||||||
}) |
|
||||||
} |
|
Reference in new issue