From 4f343e00669f96451bb5a11b7e83c7ecd8503e5a Mon Sep 17 00:00:00 2001 From: Alexander Kiryukhin Date: Fri, 29 Mar 2019 17:51:51 +0300 Subject: Api version 1.0.3 GetUpdatesLoop --- api.go | 154 +++++++++++++++++++++++++++++++------------------- examples/example_1.go | 10 +++- examples/example_2.go | 72 +++++++++++++++++++++++ models.go | 6 +- 4 files changed, 180 insertions(+), 62 deletions(-) create mode 100644 examples/example_2.go diff --git a/api.go b/api.go index a756231..1ad4611 100644 --- a/api.go +++ b/api.go @@ -5,6 +5,7 @@ package tamtam import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -12,19 +13,26 @@ import ( "net/http" "net/url" "strconv" + "time" ) type Api struct { - key string - url *url.URL + key string + version string + url *url.URL + timeout int + pause int } // New TamTam Api object func New(key string) *Api { u, _ := url.Parse("https://botapi.tamtam.chat/") return &Api{ - key: key, - url: u, + key: key, + url: u, + version: "1.0.3", + timeout: 30, + pause: 1, } } @@ -53,58 +61,35 @@ func (a *Api) GetUploadURL(uploadType UploadType) (*UploadEndpoint, error) { return result, json.NewDecoder(body).Decode(result) } +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 + } + } + } +} + func (a *Api) GetHandler(updates chan interface{}) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() - u := new(Update) b, _ := ioutil.ReadAll(r.Body) - _ = json.Unmarshal(b, u) - switch u.UpdateType { - case UpdateTypeMessageCallback: - upd := new(UpdateMessageCallback) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeMessageCreated: - upd := new(UpdateMessageCreated) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeMessageRemoved: - upd := new(UpdateMessageRemoved) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeMessageEdited: - upd := new(UpdateMessageEdited) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeMessageRestored: - upd := new(UpdateMessageRestored) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeBotAdded: - upd := new(UpdateBotAdded) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeBotRemoved: - upd := new(UpdateBotRemoved) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeUserAdded: - upd := new(UpdateUserAdded) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeUserRemoved: - upd := new(UpdateUserRemoved) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeBotStarted: - upd := new(UpdateBotStarted) - _ = json.Unmarshal(b, upd) - updates <- *upd - case UpdateTypeChatTitleChanged: - upd := new(UpdateChatTitleChanged) - _ = json.Unmarshal(b, upd) - updates <- *upd - } + updates <- a.bytesToProperUpdate(b) } } @@ -346,7 +331,63 @@ func (a *Api) Unsubscribe(subscriptionURL string) (*SimpleQueryResult, error) { return result, json.NewDecoder(body).Decode(result) } -func (a *Api) GetUpdates(limit int, timeout int, marker int64, types []string) (*UpdateList, error) { +// 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) { result := new(UpdateList) values := url.Values{} if limit > 0 { @@ -363,7 +404,7 @@ func (a *Api) GetUpdates(limit int, timeout int, marker int64, types []string) ( values.Add("types", t) } } - body, err := a.request(http.MethodDelete, "updates", values, nil) + body, err := a.request(http.MethodGet, "updates", values, nil) if err != nil { return result, err } @@ -371,15 +412,12 @@ func (a *Api) GetUpdates(limit int, timeout int, marker int64, types []string) ( return result, json.NewDecoder(body).Decode(result) } -// endregion - -// region Internal - 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) + query.Set("v", a.version) u.RawQuery = query.Encode() j, err := json.Marshal(body) if err != nil { diff --git a/examples/example_1.go b/examples/example_1.go index 428b99a..a1fb967 100644 --- a/examples/example_1.go +++ b/examples/example_1.go @@ -1,5 +1,8 @@ // +build ignore +/** + * Webhook example + */ package main import ( @@ -23,9 +26,12 @@ func main() { log.Printf("Get chat: %#v %#v", chat, err) msgs, err := api.GetMessages(chats.Chats[0].ChatId, nil, 0, 0, 0) log.Printf("Get messages: %#v %#v", msgs, err) - + subs, _ := api.GetSubscriptions() + for _, s := range subs.Subscriptions { + _, _ = api.Unsubscribe(s.Url) + } subscriptionResp, err := api.Subscribe(&tamtam.SubscriptionRequestBody{ - Url: "https://4940675e.ngrok.io/webhook", // Replace by your webhook! + Url: " https://576df2ec.ngrok.io/webhook", // Replace by your webhook! }) log.Printf("Subscription: %#v %#v", subscriptionResp, err) diff --git a/examples/example_2.go b/examples/example_2.go new file mode 100644 index 0000000..74547fa --- /dev/null +++ b/examples/example_2.go @@ -0,0 +1,72 @@ +// +build ignore + +/** + * Updates loop example + */ +package main + +import ( + "context" + "fmt" + "github.com/neonxp/tamtam" + "log" + "os" + "os/signal" +) + +func main() { + // Initialisation + api := tamtam.New(os.Getenv("TOKEN")) + + // Some methods demo: + info, err := api.GetMe() + log.Printf("Get me: %#v %#v", info, err) + chats, err := api.GetChats(0, 0) + log.Printf("Get chats: %#v %#v", chats, err) + chat, err := api.GetChat(chats.Chats[0].ChatId) + log.Printf("Get chat: %#v %#v", chat, err) + subs, _ := api.GetSubscriptions() + for _, s := range subs.Subscriptions { + _, _ = api.Unsubscribe(s.Url) + } + ch := make(chan interface{}, 1) // Channel with updates from TamTam + + ctx, cancel := context.WithCancel(context.Background()) + + go func() { + for { + select { + case upd := <-ch: + log.Printf("Received: %#v", upd) + switch upd := upd.(type) { + case tamtam.UpdateMessageCreated: + res, err := api.SendMessage(0, upd.Message.Sender.UserId, &tamtam.NewMessageBody{ + Text: fmt.Sprintf("Hello, %s! Your message: %s", upd.Message.Sender.Name, upd.Message.Body.Text), + }) + log.Printf("Answer: %#v %#v", res, err) + default: + log.Printf("Unknown type: %#v", upd) + } + case <-ctx.Done(): + return + } + + } + }() + + go func() { + exit := make(chan os.Signal) + signal.Notify(exit, os.Kill, os.Interrupt) + select { + case <-exit: + cancel() + case <-ctx.Done(): + return + } + }() + + if err := api.GetUpdatesLoop(ctx, ch); err != nil { + log.Fatalln(err) + } + +} diff --git a/models.go b/models.go index 1900e44..7ee7888 100644 --- a/models.go +++ b/models.go @@ -3,6 +3,8 @@ */ package tamtam +import "encoding/json" + type ActionRequestBody struct { Action SenderAction `json:"action"` } @@ -373,7 +375,7 @@ type Message struct { // Forwarder or replied message Link LinkedMessage `json:"link,omitempty"` // Body of created message. Text + attachments. Could be null if message contains only forwarded message. - Body MessageBody `json:"message"` + Body MessageBody `json:"body"` } // Schema representing body of message @@ -687,7 +689,7 @@ type UpdateUserRemoved struct { // List of all updates in chats your bot participated in type UpdateList struct { // Page of updates - Updates []Update `json:"updates"` + Updates []json.RawMessage `json:"updates"` // Pointer to the next data page Marker int64 `json:"marker"` } -- cgit v1.2.3