summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go')
-rw-r--r--vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go219
1 files changed, 219 insertions, 0 deletions
diff --git a/vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go b/vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go
new file mode 100644
index 00000000..b230c4c1
--- /dev/null
+++ b/vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go
@@ -0,0 +1,219 @@
+/*
+Package longpoll implements Bots Long Poll API.
+
+See more https://vk.com/dev/bots_longpoll
+*/
+package longpoll // import "github.com/SevereCloud/vksdk/v2/longpoll-bot"
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/SevereCloud/vksdk/v2"
+ "github.com/SevereCloud/vksdk/v2/api"
+ "github.com/SevereCloud/vksdk/v2/events"
+ "github.com/SevereCloud/vksdk/v2/internal"
+)
+
+// Response struct.
+type Response struct {
+ Ts string `json:"ts"`
+ Updates []events.GroupEvent `json:"updates"`
+ Failed int `json:"failed"`
+}
+
+// LongPoll struct.
+type LongPoll struct {
+ GroupID int
+ Server string
+ Key string
+ Ts string
+ Wait int
+ VK *api.VK
+ Client *http.Client
+ cancel context.CancelFunc
+
+ funcFullResponseList []func(Response)
+
+ events.FuncList
+}
+
+// NewLongPoll returns a new LongPoll.
+//
+// The LongPoll will use the http.DefaultClient.
+// This means that if the http.DefaultClient is modified by other components
+// of your application the modifications will be picked up by the SDK as well.
+func NewLongPoll(vk *api.VK, groupID int) (*LongPoll, error) {
+ lp := &LongPoll{
+ VK: vk,
+ GroupID: groupID,
+ Wait: 25,
+ Client: http.DefaultClient,
+ }
+ lp.FuncList = *events.NewFuncList()
+
+ err := lp.updateServer(true)
+
+ return lp, err
+}
+
+// NewLongPollCommunity returns a new LongPoll for community token.
+//
+// The LongPoll will use the http.DefaultClient.
+// This means that if the http.DefaultClient is modified by other components
+// of your application the modifications will be picked up by the SDK as well.
+func NewLongPollCommunity(vk *api.VK) (*LongPoll, error) {
+ resp, err := vk.GroupsGetByID(nil)
+ if err != nil {
+ return nil, err
+ }
+
+ lp := &LongPoll{
+ VK: vk,
+ GroupID: resp[0].ID,
+ Wait: 25,
+ Client: http.DefaultClient,
+ }
+ lp.FuncList = *events.NewFuncList()
+
+ err = lp.updateServer(true)
+
+ return lp, err
+}
+
+func (lp *LongPoll) updateServer(updateTs bool) error {
+ params := api.Params{
+ "group_id": lp.GroupID,
+ }
+
+ serverSetting, err := lp.VK.GroupsGetLongPollServer(params)
+ if err != nil {
+ return err
+ }
+
+ lp.Key = serverSetting.Key
+ lp.Server = serverSetting.Server
+
+ if updateTs {
+ lp.Ts = serverSetting.Ts
+ }
+
+ return nil
+}
+
+func (lp *LongPoll) check(ctx context.Context) (response Response, err error) {
+ u := fmt.Sprintf("%s?act=a_check&key=%s&ts=%s&wait=%d", lp.Server, lp.Key, lp.Ts, lp.Wait)
+
+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
+ if err != nil {
+ return response, err
+ }
+
+ resp, err := lp.Client.Do(req)
+ if err != nil {
+ return response, err
+ }
+ defer resp.Body.Close()
+
+ err = json.NewDecoder(resp.Body).Decode(&response)
+ if err != nil {
+ return response, err
+ }
+
+ err = lp.checkResponse(response)
+
+ return response, err
+}
+
+func (lp *LongPoll) checkResponse(response Response) (err error) {
+ switch response.Failed {
+ case 0:
+ lp.Ts = response.Ts
+ case 1:
+ lp.Ts = response.Ts
+ case 2:
+ err = lp.updateServer(false)
+ case 3:
+ err = lp.updateServer(true)
+ default:
+ err = &Failed{response.Failed}
+ }
+
+ return
+}
+
+func (lp *LongPoll) autoSetting(ctx context.Context) error {
+ params := api.Params{
+ "group_id": lp.GroupID,
+ "enabled": true,
+ "api_version": vksdk.API,
+ }.WithContext(ctx)
+ for _, event := range lp.ListEvents() {
+ params[string(event)] = true
+ }
+
+ // Updating LongPoll settings
+ _, err := lp.VK.GroupsSetLongPollSettings(params)
+
+ return err
+}
+
+// Run handler.
+func (lp *LongPoll) Run() error {
+ return lp.RunWithContext(context.Background())
+}
+
+// RunWithContext handler.
+func (lp *LongPoll) RunWithContext(ctx context.Context) error {
+ return lp.run(ctx)
+}
+
+func (lp *LongPoll) run(ctx context.Context) error {
+ ctx, lp.cancel = context.WithCancel(ctx)
+
+ err := lp.autoSetting(ctx)
+ if err != nil {
+ return err
+ }
+
+ for {
+ select {
+ case _, ok := <-ctx.Done():
+ if !ok {
+ return nil
+ }
+ default:
+ resp, err := lp.check(ctx)
+ if err != nil {
+ return err
+ }
+
+ ctx = context.WithValue(ctx, internal.LongPollTsKey, resp.Ts)
+
+ for _, event := range resp.Updates {
+ err = lp.Handler(ctx, event)
+ if err != nil {
+ return err
+ }
+ }
+
+ for _, f := range lp.funcFullResponseList {
+ f(resp)
+ }
+ }
+ }
+}
+
+// Shutdown gracefully shuts down the longpoll without interrupting any active connections.
+func (lp *LongPoll) Shutdown() {
+ if lp.cancel != nil {
+ lp.cancel()
+ }
+}
+
+// FullResponse handler.
+func (lp *LongPoll) FullResponse(f func(Response)) {
+ lp.funcFullResponseList = append(lp.funcFullResponseList, f)
+}