tamtam/api.go

448 lines
11 KiB
Go
Raw Normal View History

2019-03-29 01:55:21 +03:00
/*
* TamTam Bot API
*/
2019-03-28 17:51:39 +03:00
package tamtam
2019-03-29 01:55:21 +03:00
import (
"bytes"
2019-03-29 17:51:51 +03:00
"context"
2019-03-29 01:55:21 +03:00
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
2019-03-29 17:51:51 +03:00
"time"
2019-03-29 01:55:21 +03:00
)
type Api struct {
2019-03-29 17:51:51 +03:00
key string
version string
url *url.URL
timeout int
pause int
2019-03-29 01:55:21 +03:00
}
// New TamTam Api object
func New(key string) *Api {
u, _ := url.Parse("https://botapi.tamtam.chat/")
return &Api{
2019-03-29 17:51:51 +03:00
key: key,
url: u,
version: "1.0.3",
timeout: 30,
pause: 1,
2019-03-29 01:55:21 +03:00
}
}
// region Misc methods
func (a *Api) GetMe() (*UserWithPhoto, error) {
result := new(UserWithPhoto)
values := url.Values{}
body, err := a.request(http.MethodGet, "me", values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) GetUploadURL(uploadType UploadType) (*UploadEndpoint, error) {
result := new(UploadEndpoint)
values := url.Values{}
values.Set("type", string(uploadType))
body, err := a.request(http.MethodPost, "uploads", values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
2019-03-29 17:51:51 +03:00
func (a *Api) GetUpdatesLoop(ctx context.Context, updates chan interface{}) error {
for {
select {
case <-ctx.Done():
return nil
case <-time.After(time.Duration(a.pause) * time.Second):
var marker int64
for {
upds, err := a.getUpdates(50, a.timeout, marker, []string{})
if err != nil {
return err
}
if len(upds.Updates) == 0 {
break
}
for _, u := range upds.Updates {
updates <- a.bytesToProperUpdate(u)
}
marker = upds.Marker
}
}
}
}
2019-03-29 01:55:21 +03:00
func (a *Api) GetHandler(updates chan interface{}) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
b, _ := ioutil.ReadAll(r.Body)
2019-03-29 17:51:51 +03:00
updates <- a.bytesToProperUpdate(b)
2019-03-29 01:55:21 +03:00
}
}
// endregion
// region Chat methods
func (a *Api) GetChats(count, marker int64) (*ChatList, error) {
result := new(ChatList)
values := url.Values{}
if count > 0 {
values.Set("count", strconv.Itoa(int(count)))
}
if marker > 0 {
values.Set("marker", strconv.Itoa(int(marker)))
}
body, err := a.request(http.MethodGet, "chats", values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) GetChat(chatID int64) (*Chat, error) {
result := new(Chat)
values := url.Values{}
body, err := a.request(http.MethodGet, fmt.Sprintf("chats/%d", chatID), values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) GetChatMembership(chatID int64) (*ChatMember, error) {
result := new(ChatMember)
values := url.Values{}
body, err := a.request(http.MethodGet, fmt.Sprintf("chats/%d/members/me", chatID), values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) GetChatMembers(chatID, count, marker int64) (*ChatMembersList, error) {
result := new(ChatMembersList)
values := url.Values{}
if count > 0 {
values.Set("count", strconv.Itoa(int(count)))
}
if marker > 0 {
values.Set("marker", strconv.Itoa(int(marker)))
}
body, err := a.request(http.MethodGet, fmt.Sprintf("chats/%d/members", chatID), values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) LeaveChat(chatID int64) (*SimpleQueryResult, error) {
result := new(SimpleQueryResult)
values := url.Values{}
body, err := a.request(http.MethodDelete, fmt.Sprintf("chats/%d/members/me", chatID), values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) EditChat(chatID int64, update *ChatPatch) (*Chat, error) {
result := new(Chat)
values := url.Values{}
body, err := a.request(http.MethodPatch, fmt.Sprintf("chats/%d", chatID), values, update)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) AddMember(chatID int64, users UserIdsList) (*SimpleQueryResult, error) {
result := new(SimpleQueryResult)
values := url.Values{}
body, err := a.request(http.MethodPost, fmt.Sprintf("chats/%d/members", chatID), values, users)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) RemoveMember(chatID int64, userID int64) (*SimpleQueryResult, error) {
result := new(SimpleQueryResult)
values := url.Values{}
values.Set("user_id", strconv.Itoa(int(userID)))
body, err := a.request(http.MethodDelete, fmt.Sprintf("chats/%d/members", chatID), values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) SendAction(chatID int64, action SenderAction) (*SimpleQueryResult, error) {
result := new(SimpleQueryResult)
values := url.Values{}
body, err := a.request(http.MethodPost, fmt.Sprintf("chats/%d/actions", chatID), values, ActionRequestBody{Action: action})
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
// endregion
// region Message methods
func (a *Api) GetMessages(chatID int64, messageIDs []string, from int64, to int64, count int64) (*MessageList, error) {
result := new(MessageList)
values := url.Values{}
if chatID > 0 {
values.Set("chat_id", strconv.Itoa(int(chatID)))
}
if len(messageIDs) > 0 {
for _, mid := range messageIDs {
values.Add("message_ids", mid)
}
}
if from > 0 {
values.Set("from", strconv.Itoa(int(from)))
}
if to > 0 {
values.Set("count", strconv.Itoa(int(to)))
}
if count > 0 {
values.Set("count", strconv.Itoa(int(count)))
}
body, err := a.request(http.MethodGet, "messages", values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) SendMessage(chatID int64, userID int64, message *NewMessageBody) (*Message, error) {
result := new(Message)
values := url.Values{}
if chatID > 0 {
values.Set("chat_id", strconv.Itoa(int(chatID)))
}
if userID > 0 {
values.Set("user_id", strconv.Itoa(int(userID)))
}
body, err := a.request(http.MethodPost, "messages", values, message)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) EditMessage(messageID int64, message *NewMessageBody) (*SimpleQueryResult, error) {
result := new(SimpleQueryResult)
values := url.Values{}
values.Set("message_id", strconv.Itoa(int(messageID)))
body, err := a.request(http.MethodPut, "messages", values, message)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) DeleteMessage(messageID int64) (*SimpleQueryResult, error) {
result := new(SimpleQueryResult)
values := url.Values{}
values.Set("message_id", strconv.Itoa(int(messageID)))
body, err := a.request(http.MethodDelete, "messages", values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) AnswerOnCallback(callbackID int64, callback *CallbackAnswer) (*SimpleQueryResult, error) {
result := new(SimpleQueryResult)
values := url.Values{}
values.Set("callback_id", strconv.Itoa(int(callbackID)))
body, err := a.request(http.MethodPost, "answers", values, callback)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
// endregion
// region Subscriptions
func (a *Api) GetSubscriptions() (*GetSubscriptionsResult, error) {
result := new(GetSubscriptionsResult)
values := url.Values{}
body, err := a.request(http.MethodGet, "subscriptions", values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
2019-03-29 18:05:58 +03:00
func (a *Api) Subscribe(subscribeURL string, updateTypes []string) (*SimpleQueryResult, error) {
subscription := &SubscriptionRequestBody{
Url: subscribeURL,
UpdateTypes: updateTypes,
Version: a.version,
}
2019-03-29 01:55:21 +03:00
result := new(SimpleQueryResult)
values := url.Values{}
body, err := a.request(http.MethodPost, "subscriptions", values, subscription)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) Unsubscribe(subscriptionURL string) (*SimpleQueryResult, error) {
result := new(SimpleQueryResult)
values := url.Values{}
values.Set("url", subscriptionURL)
body, err := a.request(http.MethodDelete, "subscriptions", values, nil)
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
2019-03-29 17:51:51 +03:00
// endregion
// region Internal
func (a *Api) bytesToProperUpdate(b []byte) interface{} {
u := new(Update)
_ = json.Unmarshal(b, u)
switch u.UpdateType {
case UpdateTypeMessageCallback:
upd := UpdateMessageCallback{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeMessageCreated:
upd := UpdateMessageCreated{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeMessageRemoved:
upd := UpdateMessageRemoved{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeMessageEdited:
upd := UpdateMessageEdited{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeMessageRestored:
upd := UpdateMessageRestored{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeBotAdded:
upd := UpdateBotAdded{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeBotRemoved:
upd := UpdateBotRemoved{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeUserAdded:
upd := UpdateUserAdded{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeUserRemoved:
upd := UpdateUserRemoved{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeBotStarted:
upd := UpdateBotStarted{}
_ = json.Unmarshal(b, &upd)
return upd
case UpdateTypeChatTitleChanged:
upd := UpdateChatTitleChanged{}
_ = json.Unmarshal(b, &upd)
return upd
}
return nil
}
func (a *Api) getUpdates(limit int, timeout int, marker int64, types []string) (*UpdateList, error) {
2019-03-29 01:55:21 +03:00
result := new(UpdateList)
values := url.Values{}
if limit > 0 {
values.Set("limit", strconv.Itoa(limit))
}
if timeout > 0 {
values.Set("timeout", strconv.Itoa(timeout))
}
if marker > 0 {
values.Set("marker", strconv.Itoa(int(marker)))
}
if len(types) > 0 {
for _, t := range types {
values.Add("types", t)
}
}
2019-03-29 17:51:51 +03:00
body, err := a.request(http.MethodGet, "updates", values, nil)
2019-03-29 01:55:21 +03:00
if err != nil {
return result, err
}
defer body.Close()
return result, json.NewDecoder(body).Decode(result)
}
func (a *Api) request(method, path string, query url.Values, body interface{}) (io.ReadCloser, error) {
c := http.DefaultClient
u := *a.url
u.Path = path
query.Set("access_token", a.key)
2019-03-29 17:51:51 +03:00
query.Set("v", a.version)
2019-03-29 01:55:21 +03:00
u.RawQuery = query.Encode()
j, err := json.Marshal(body)
if err != nil {
return nil, err
}
req, err := http.NewRequest(method, u.String(), bytes.NewReader(j))
if err != nil {
return nil, err
}
resp, err := c.Do(req)
if resp.StatusCode != http.StatusOK {
errObj := new(Error)
err = json.NewDecoder(resp.Body).Decode(errObj)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("code=%s message=%s error=%s", errObj.Code, errObj.Message, errObj.Error)
}
return resp.Body, err
}
// endregion