From b01a28d34668975a34a08e4f4d6063ad260ad764 Mon Sep 17 00:00:00 2001 From: Daniil Suvorov Date: Sun, 12 Jan 2025 16:42:33 +0300 Subject: [PATCH 1/6] feat: update golang to 1.22 (#305) --- .gitattributes | 1 + .github/workflows/golangci-lint.yml | 2 +- .github/workflows/test.yml | 2 +- .golangci.yml | 20 ++++- api/api.go | 3 +- api/api_test.go | 2 +- api/oauth/oauth.go | 4 +- callback/callback_test.go | 1 - events/events.go | 112 ---------------------------- go.mod | 2 +- longpoll-bot/longpoll.go | 2 +- longpoll-bot/longpoll_test.go | 2 - longpoll-user/longpoll.go | 4 - longpoll-user/v3/extra.go | 2 +- marusia/cards.go | 4 +- 15 files changed, 30 insertions(+), 133 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..d207b180 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.go text eol=lf diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 2b3ca2a2..d052fedf 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -15,4 +15,4 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v4 with: - version: v1.56.2 + version: v1.63.4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 796e8315..4e979560 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -5,7 +5,7 @@ jobs: test: strategy: matrix: - go-version: [1.21.x, 1.x] + go-version: [1.22.x, 1.x] platform: [ubuntu-latest] runs-on: ${{ matrix.platform }} steps: diff --git a/.golangci.yml b/.golangci.yml index f420e31f..3c698075 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -32,7 +32,7 @@ linters: - asciicheck - nolintlint - gofumpt - - goerr113 + - err113 - tparallel - errorlint - paralleltest @@ -67,7 +67,7 @@ linters: - gocheckcompilerdirectives - asasalint - - musttag + # - musttag - gosmopolitan - mirror @@ -81,6 +81,18 @@ linters: - wrapcheck + - copyloopvar + - intrange + + - fatcontext + - canonicalheader + + - iface + + - exptostd + - nilnesserr + - usetesting + # - testpackage # TODO: Fix testpackage # - noctx # TODO: Fix noctx @@ -122,6 +134,8 @@ linters: # - protogetter # - spancheck +# - recvcheck # false positive + # depricated # - maligned # - interfacer @@ -159,4 +173,4 @@ linters-settings: testifylint: enable-all: true disable: - - require-error # f func false positive + - require-error # f func false positive diff --git a/api/api.go b/api/api.go index e0c02d42..ddcede1b 100644 --- a/api/api.go +++ b/api/api.go @@ -207,6 +207,7 @@ func buildQuery(sliceParams ...Params) (context.Context, url.Values) { case "access_token": continue case ":context": + //nolint:fatcontext ctx = value.(context.Context) default: query.Set(key, FmtValue(value, 0)) @@ -396,7 +397,7 @@ func fmtReflectValue(value reflect.Value, depth int) string { case reflect.Array, reflect.Slice: s := "" - for i := 0; i < f.Len(); i++ { + for i := range f.Len() { if i > 0 { s += "," } diff --git a/api/api_test.go b/api/api_test.go index a1c4a16f..92378a9d 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -217,7 +217,7 @@ func TestVK_RequestLimit(t *testing.T) { var wg sync.WaitGroup - for i := 0; i < 20; i++ { + for range 20 { wg.Add(1) go func() { diff --git a/api/oauth/oauth.go b/api/oauth/oauth.go index 3f2c8e30..6700003a 100644 --- a/api/oauth/oauth.go +++ b/api/oauth/oauth.go @@ -60,8 +60,8 @@ const ( // CheckScope ... func CheckScope(scope int, permissions ...int) bool { - for i := 0; i < len(permissions); i++ { - if scope&permissions[i] != permissions[i] { + for _, value := range permissions { + if scope&value != value { return false } } diff --git a/callback/callback_test.go b/callback/callback_test.go index 834bc7c2..8981ae5f 100644 --- a/callback/callback_test.go +++ b/callback/callback_test.go @@ -189,7 +189,6 @@ func TestCallback_HandleFunc(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() diff --git a/events/events.go b/events/events.go index 3ec3006b..d8044357 100644 --- a/events/events.go +++ b/events/events.go @@ -164,8 +164,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g if sliceFunc, ok := fl.special[e.Type]; ok { for _, f := range sliceFunc { - f := f - if fl.goroutine { go func() { f(ctx, e) }() } else { @@ -182,8 +180,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.messageNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -197,8 +193,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.messageReply { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -212,8 +206,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.messageEdit { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -227,8 +219,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.messageAllow { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -242,8 +232,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.messageDeny { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -257,8 +245,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.messageTypingState { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -272,8 +258,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.messageEvent { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -287,8 +271,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.photoNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -302,8 +284,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.photoCommentNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -317,8 +297,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.photoCommentEdit { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -332,8 +310,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.photoCommentRestore { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -347,8 +323,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.photoCommentDelete { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -362,8 +336,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.audioNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -377,8 +349,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.videoNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -392,8 +362,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.videoCommentNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -407,8 +375,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.videoCommentEdit { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -422,8 +388,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.videoCommentRestore { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -437,8 +401,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.videoCommentDelete { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -452,8 +414,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.wallPostNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -467,8 +427,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.wallRepost { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -482,8 +440,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.wallReplyNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -497,8 +453,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.wallReplyEdit { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -512,8 +466,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.wallReplyRestore { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -527,8 +479,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.wallReplyDelete { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -542,8 +492,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.boardPostNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -557,8 +505,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.boardPostEdit { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -572,8 +518,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.boardPostRestore { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -587,8 +531,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.boardPostDelete { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -602,8 +544,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.marketCommentNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -617,8 +557,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.marketCommentEdit { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -632,8 +570,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.marketCommentRestore { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -647,8 +583,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.marketCommentDelete { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -662,8 +596,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.marketOrderNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -677,8 +609,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.marketOrderEdit { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -692,8 +622,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.groupLeave { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -707,8 +635,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.groupJoin { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -722,8 +648,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.userBlock { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -737,8 +661,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.userUnblock { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -752,8 +674,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.pollVoteNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -767,8 +687,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.groupOfficersEdit { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -782,8 +700,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.groupChangeSettings { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -797,8 +713,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.groupChangePhoto { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -812,8 +726,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.vkpayTransaction { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -827,8 +739,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.leadFormsNew { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -842,8 +752,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.appPayload { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -857,8 +765,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.messageRead { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -872,8 +778,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.likeAdd { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -887,8 +791,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.likeRemove { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -902,8 +804,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.donutSubscriptionCreate { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -917,8 +817,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.donutSubscriptionProlonged { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -932,8 +830,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.donutSubscriptionExpired { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -947,8 +843,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.donutSubscriptionCancelled { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -962,8 +856,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.donutSubscriptionPriceChanged { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -977,8 +869,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.donutMoneyWithdraw { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { @@ -992,8 +882,6 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } for _, f := range fl.donutMoneyWithdrawError { - f := f - if fl.goroutine { go func() { f(ctx, obj) }() } else { diff --git a/go.mod b/go.mod index ff0dddb3..56fc31ba 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/SevereCloud/vksdk/v3 -go 1.21 +go 1.22 require ( github.com/gorilla/schema v1.4.1 diff --git a/longpoll-bot/longpoll.go b/longpoll-bot/longpoll.go index 16a6ba9b..b9ef69fc 100644 --- a/longpoll-bot/longpoll.go +++ b/longpoll-bot/longpoll.go @@ -248,7 +248,7 @@ func (lp *LongPoll) run(ctx context.Context) error { return err } - ctx = context.WithValue(ctx, internal.LongPollTsKey, resp.Ts) + ctx := context.WithValue(ctx, internal.LongPollTsKey, resp.Ts) for _, event := range resp.Updates { err = lp.Handler(ctx, event) diff --git a/longpoll-bot/longpoll_test.go b/longpoll-bot/longpoll_test.go index 78456fc8..53d5d3ca 100644 --- a/longpoll-bot/longpoll_test.go +++ b/longpoll-bot/longpoll_test.go @@ -173,7 +173,6 @@ func TestLongPoll_checkResponse(t *testing.T) { //nolint: tparallel }, } for _, tt := range tests { //nolint: paralleltest - tt := tt t.Run(tt.name, func(t *testing.T) { if err := lp.checkResponse(tt.argResponse); (err != nil) != tt.wantErr { t.Errorf("LongPoll.checkResponse() error = %v, wantErr %v", err, tt.wantErr) @@ -254,7 +253,6 @@ func TestParseResponse(t *testing.T) { } for _, test := range tests { - test := test t.Run(test.name, func(t *testing.T) { t.Parallel() diff --git a/longpoll-user/longpoll.go b/longpoll-user/longpoll.go index b1d834a5..0142666a 100644 --- a/longpoll-user/longpoll.go +++ b/longpoll-user/longpoll.go @@ -210,8 +210,6 @@ func (lp LongPoll) handler(event []interface{}) error { key := int(event[0].(float64)) for _, f := range lp.funcList[key] { - f := f - if lp.goroutine { go func() { _ = f(event) }() } else { @@ -242,8 +240,6 @@ func (lp *LongPoll) Run() error { } for _, f := range lp.funcFullResponseList { - f := f - if lp.goroutine { go func() { f(resp) }() } else { diff --git a/longpoll-user/v3/extra.go b/longpoll-user/v3/extra.go index 4b1b8496..eb168588 100644 --- a/longpoll-user/v3/extra.go +++ b/longpoll-user/v3/extra.go @@ -194,7 +194,7 @@ func interfaceToIDSlice(slice interface{}) ([]int, error) { result := make([]int, reflectedSlice.Len()) - for i := 0; i < reflectedSlice.Len(); i++ { + for i := range reflectedSlice.Len() { v, ok := reflectedSlice.Index(i).Interface().(float64) if !ok { return nil, &failedCast{reflectedSlice.Index(i).Interface()} diff --git a/marusia/cards.go b/marusia/cards.go index 5e8e1e4e..592427f4 100644 --- a/marusia/cards.go +++ b/marusia/cards.go @@ -79,8 +79,8 @@ func NewItemsList(items ...CardItem) *Card { func NewImageList(imageIDs ...int) *Card { items := make([]CardItem, len(imageIDs)) - for i := 0; i < len(imageIDs); i++ { - items[i].ImageID = imageIDs[i] + for i, value := range imageIDs { + items[i].ImageID = value } return NewItemsList(items...) From 1d644e55561791b5448b6878f2ca8517eba74077 Mon Sep 17 00:00:00 2001 From: Gaiaz Iusipov Date: Mon, 20 Jan 2025 17:51:52 +0300 Subject: [PATCH 2/6] Fix golangci-lint GitHub Action (#308) --- .github/workflows/golangci-lint.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index d052fedf..c820e01e 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -8,11 +8,11 @@ jobs: name: lint runs-on: ubuntu-latest steps: + - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version: 1.* - - uses: actions/checkout@v4 - name: golangci-lint - uses: golangci/golangci-lint-action@v4 + uses: golangci/golangci-lint-action@v6 with: version: v1.63.4 From cdf36aa58d49a0e95f7cf8fa9ef8aed7fadfefed Mon Sep 17 00:00:00 2001 From: Gaiaz Iusipov Date: Thu, 20 Feb 2025 20:07:25 +0800 Subject: [PATCH 3/6] feat: Add MessagesMessage.LastReactionID --- object/messages.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/object/messages.go b/object/messages.go index 5b7444a6..b5d5b71b 100644 --- a/object/messages.go +++ b/object/messages.go @@ -44,6 +44,9 @@ type MessagesMessage struct { Action MessagesMessageAction `json:"action"` Attachments []MessagesMessageAttachment `json:"attachments"` + // LastReactionID is the last reaction id set on this message. + LastReactionID int `json:"last_reaction_id"` + // Unique auto-incremented number for all messages with this peer. ConversationMessageID int `json:"conversation_message_id"` From 3e264d156f72089065fa3df5cae6c565274b438e Mon Sep 17 00:00:00 2001 From: Gaiaz Iusipov Date: Sun, 23 Feb 2025 19:05:44 +0800 Subject: [PATCH 4/6] feat: improve performance (#311) --- callback/callback.go | 28 +++- callback/callback_test.go | 52 +++--- events/events.go | 338 +++++++++++++++++++++++++++++++------- events/events_test.go | 2 +- longpoll-bot/longpoll.go | 22 +-- streaming/streaming.go | 8 +- 6 files changed, 343 insertions(+), 107 deletions(-) diff --git a/callback/callback.go b/callback/callback.go index 5a382c84..f813ae29 100644 --- a/callback/callback.go +++ b/callback/callback.go @@ -12,6 +12,7 @@ import ( "log" "net/http" "strconv" + "sync" "time" "github.com/SevereCloud/vksdk/v3/events" @@ -31,7 +32,7 @@ type Callback struct { // If nil, logging is done via the log package's standard logger. ErrorLog *log.Logger - events.FuncList + *events.FuncList } // NewCallback return *Callback. @@ -40,26 +41,35 @@ func NewCallback() *Callback { Title: "vksdk", ConfirmationKeys: make(map[int]string), SecretKeys: make(map[int]string), - FuncList: *events.NewFuncList(), + FuncList: events.NewFuncList(), } return cb } -func (cb Callback) confirmationKey(groupID int) string { - if cb.ConfirmationKeys[groupID] != "" { - return cb.ConfirmationKeys[groupID] +func (cb *Callback) confirmationKey(groupID int) string { + if v := cb.ConfirmationKeys[groupID]; v != "" { + return v } return cb.ConfirmationKey } +var groupEventPool = sync.Pool{ //nolint:gochecknoglobals + New: func() any { + return &events.GroupEvent{Object: make(json.RawMessage, 0, 1024)} + }, +} + // HandleFunc handler. func (cb *Callback) HandleFunc(w http.ResponseWriter, r *http.Request) { - decoder := json.NewDecoder(r.Body) + e := groupEventPool.Get().(*events.GroupEvent) + defer func() { + *e = events.GroupEvent{Object: e.Object[:0]} + groupEventPool.Put(e) + }() - var e events.GroupEvent - if err := decoder.Decode(&e); err != nil { + if err := json.NewDecoder(r.Body).Decode(e); err != nil { cb.logf("callback: %v", err) http.Error(w, "Bad Request", http.StatusBadRequest) @@ -109,7 +119,7 @@ func (cb *Callback) HandleFunc(w http.ResponseWriter, r *http.Request) { } ctx = context.WithValue(ctx, internal.CallbackRemove, removeFunc) - if err := cb.Handler(ctx, e); err != nil { + if err := cb.Handler(ctx, *e); err != nil { cb.logf("callback: %v", err) http.Error(w, "Bad Request", http.StatusBadRequest) diff --git a/callback/callback_test.go b/callback/callback_test.go index 8981ae5f..2f1969cb 100644 --- a/callback/callback_test.go +++ b/callback/callback_test.go @@ -2,13 +2,17 @@ package callback_test import ( "bytes" + "context" + "encoding/json" "log" "net/http" "net/http/httptest" "testing" "github.com/SevereCloud/vksdk/v3/callback" + "github.com/SevereCloud/vksdk/v3/events" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestCallback_HandleFunc(t *testing.T) { @@ -169,12 +173,6 @@ func TestCallback_HandleFunc(t *testing.T) { body: `{"type": "confirmation", "group_id": 123456, "secret": "secret_123456"}`, expected: "confirmation_123456", }, - { - name: "check bad message_new", - fields: fields{}, - body: `{"type": "message_new", "object": 1}`, - expected: "Bad Request\n", - }, { name: "check good message_new", fields: fields{}, @@ -192,19 +190,14 @@ func TestCallback_HandleFunc(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - cb := callback.Callback{ - ConfirmationKeys: tt.fields.ConfirmationKeys, - ConfirmationKey: tt.fields.ConfirmationKey, - SecretKeys: tt.fields.SecretKeys, - SecretKey: tt.fields.SecretKey, - } + cb := callback.NewCallback() + cb.ConfirmationKeys = tt.fields.ConfirmationKeys + cb.ConfirmationKey = tt.fields.ConfirmationKey + cb.SecretKeys = tt.fields.SecretKeys + cb.SecretKey = tt.fields.SecretKey - jsonStr := []byte(tt.body) - - req, err := http.NewRequest(http.MethodPost, "/callback", bytes.NewBuffer(jsonStr)) - if err != nil { - t.Fatal(err) - } + req, err := http.NewRequest(http.MethodPost, "/callback", bytes.NewBufferString(tt.body)) + require.NoError(t, err) rr := httptest.NewRecorder() handler := http.HandlerFunc(cb.HandleFunc) @@ -223,6 +216,25 @@ func TestNewCallback(t *testing.T) { assert.NotNil(t, cb) } +func TestCallback_Handler(t *testing.T) { + t.Parallel() + + t.Run("bad message_new object", func(t *testing.T) { + t.Parallel() + + cb := callback.NewCallback() + cb.MessageNew(func(context.Context, events.MessageNewObject) {}) + + event := events.GroupEvent{ + Type: events.EventMessageNew, + Object: json.RawMessage("1"), + } + + err := cb.Handler(context.Background(), event) + require.Error(t, err) + }) +} + func TestCallback_ErrorLog(t *testing.T) { t.Parallel() @@ -232,9 +244,7 @@ func TestCallback_ErrorLog(t *testing.T) { cb.ErrorLog = log.New(&buf, "", 0) req, err := http.NewRequest(http.MethodPost, "/callback", bytes.NewBuffer([]byte{})) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) rr := httptest.NewRecorder() handler := http.HandlerFunc(cb.HandleFunc) diff --git a/events/events.go b/events/events.go index d8044357..211f1345 100644 --- a/events/events.go +++ b/events/events.go @@ -157,7 +157,7 @@ func NewFuncList() *FuncList { } // Handler group event handler. -func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:gocyclo +func (fl *FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:gocyclo ctx = context.WithValue(ctx, internal.GroupIDKey, e.GroupID) ctx = context.WithValue(ctx, internal.EventIDKey, e.EventID) ctx = context.WithValue(ctx, internal.EventVersionKey, e.V) @@ -174,6 +174,10 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g switch e.Type { case EventMessageNew: + if len(fl.messageNew) == 0 { + break + } + var obj MessageNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -181,12 +185,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.messageNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMessageReply: + if len(fl.messageReply) == 0 { + break + } + var obj MessageReplyObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -194,12 +202,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.messageReply { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMessageEdit: + if len(fl.messageEdit) == 0 { + break + } + var obj MessageEditObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -207,12 +219,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.messageEdit { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMessageAllow: + if len(fl.messageAllow) == 0 { + break + } + var obj MessageAllowObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -220,12 +236,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.messageAllow { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMessageDeny: + if len(fl.messageDeny) == 0 { + break + } + var obj MessageDenyObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -233,12 +253,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.messageDeny { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMessageTypingState: // На основе ответа + if len(fl.messageTypingState) == 0 { + break + } + var obj MessageTypingStateObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -246,12 +270,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.messageTypingState { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMessageEvent: + if len(fl.messageEvent) == 0 { + break + } + var obj MessageEventObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -259,12 +287,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.messageEvent { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventPhotoNew: + if len(fl.photoNew) == 0 { + break + } + var obj PhotoNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -272,12 +304,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.photoNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventPhotoCommentNew: + if len(fl.photoCommentNew) == 0 { + break + } + var obj PhotoCommentNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -285,12 +321,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.photoCommentNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventPhotoCommentEdit: + if len(fl.photoCommentEdit) == 0 { + break + } + var obj PhotoCommentEditObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -298,12 +338,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.photoCommentEdit { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventPhotoCommentRestore: + if len(fl.photoCommentRestore) == 0 { + break + } + var obj PhotoCommentRestoreObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -311,12 +355,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.photoCommentRestore { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventPhotoCommentDelete: + if len(fl.photoCommentDelete) == 0 { + break + } + var obj PhotoCommentDeleteObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -324,12 +372,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.photoCommentDelete { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventAudioNew: + if len(fl.audioNew) == 0 { + break + } + var obj AudioNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -337,12 +389,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.audioNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventVideoNew: + if len(fl.videoNew) == 0 { + break + } + var obj VideoNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -350,12 +406,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.videoNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventVideoCommentNew: + if len(fl.videoCommentNew) == 0 { + break + } + var obj VideoCommentNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -363,12 +423,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.videoCommentNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventVideoCommentEdit: + if len(fl.videoCommentEdit) == 0 { + break + } + var obj VideoCommentEditObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -376,12 +440,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.videoCommentEdit { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventVideoCommentRestore: + if len(fl.videoCommentRestore) == 0 { + break + } + var obj VideoCommentRestoreObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -389,12 +457,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.videoCommentRestore { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventVideoCommentDelete: + if len(fl.videoCommentDelete) == 0 { + break + } + var obj VideoCommentDeleteObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -402,12 +474,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.videoCommentDelete { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventWallPostNew: + if len(fl.wallPostNew) == 0 { + break + } + var obj WallPostNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -415,12 +491,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.wallPostNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventWallRepost: + if len(fl.wallRepost) == 0 { + break + } + var obj WallRepostObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -428,12 +508,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.wallRepost { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventWallReplyNew: + if len(fl.wallReplyNew) == 0 { + break + } + var obj WallReplyNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -441,12 +525,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.wallReplyNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventWallReplyEdit: + if len(fl.wallReplyEdit) == 0 { + break + } + var obj WallReplyEditObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -454,12 +542,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.wallReplyEdit { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventWallReplyRestore: + if len(fl.wallReplyRestore) == 0 { + break + } + var obj WallReplyRestoreObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -467,12 +559,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.wallReplyRestore { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventWallReplyDelete: + if len(fl.wallReplyDelete) == 0 { + break + } + var obj WallReplyDeleteObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -480,12 +576,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.wallReplyDelete { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventBoardPostNew: + if len(fl.boardPostNew) == 0 { + break + } + var obj BoardPostNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -493,12 +593,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.boardPostNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventBoardPostEdit: + if len(fl.boardPostEdit) == 0 { + break + } + var obj BoardPostEditObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -506,12 +610,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.boardPostEdit { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventBoardPostRestore: + if len(fl.boardPostRestore) == 0 { + break + } + var obj BoardPostRestoreObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -519,12 +627,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.boardPostRestore { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventBoardPostDelete: + if len(fl.boardPostDelete) == 0 { + break + } + var obj BoardPostDeleteObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -532,12 +644,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.boardPostDelete { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMarketCommentNew: + if len(fl.marketCommentNew) == 0 { + break + } + var obj MarketCommentNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -545,12 +661,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.marketCommentNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMarketCommentEdit: + if len(fl.marketCommentEdit) == 0 { + break + } + var obj MarketCommentEditObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -558,12 +678,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.marketCommentEdit { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMarketCommentRestore: + if len(fl.marketCommentRestore) == 0 { + break + } + var obj MarketCommentRestoreObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -571,12 +695,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.marketCommentRestore { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMarketCommentDelete: + if len(fl.marketCommentDelete) == 0 { + break + } + var obj MarketCommentDeleteObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -584,12 +712,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.marketCommentDelete { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMarketOrderNew: + if len(fl.marketOrderNew) == 0 { + break + } + var obj MarketOrderNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -597,12 +729,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.marketOrderNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMarketOrderEdit: + if len(fl.marketOrderEdit) == 0 { + break + } + var obj MarketOrderEditObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -610,12 +746,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.marketOrderEdit { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventGroupLeave: + if len(fl.groupLeave) == 0 { + break + } + var obj GroupLeaveObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -623,12 +763,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.groupLeave { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventGroupJoin: + if len(fl.groupJoin) == 0 { + break + } + var obj GroupJoinObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -636,12 +780,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.groupJoin { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventUserBlock: + if len(fl.userBlock) == 0 { + break + } + var obj UserBlockObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -649,12 +797,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.userBlock { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventUserUnblock: + if len(fl.userUnblock) == 0 { + break + } + var obj UserUnblockObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -662,12 +814,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.userUnblock { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventPollVoteNew: + if len(fl.pollVoteNew) == 0 { + break + } + var obj PollVoteNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -675,12 +831,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.pollVoteNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventGroupOfficersEdit: + if len(fl.groupOfficersEdit) == 0 { + break + } + var obj GroupOfficersEditObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -688,12 +848,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.groupOfficersEdit { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventGroupChangeSettings: + if len(fl.groupChangeSettings) == 0 { + break + } + var obj GroupChangeSettingsObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -701,12 +865,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.groupChangeSettings { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventGroupChangePhoto: + if len(fl.groupChangePhoto) == 0 { + break + } + var obj GroupChangePhotoObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -714,12 +882,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.groupChangePhoto { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventVkpayTransaction: + if len(fl.vkpayTransaction) == 0 { + break + } + var obj VkpayTransactionObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -727,12 +899,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.vkpayTransaction { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventLeadFormsNew: + if len(fl.leadFormsNew) == 0 { + break + } + var obj LeadFormsNewObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -740,12 +916,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.leadFormsNew { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventAppPayload: + if len(fl.appPayload) == 0 { + break + } + var obj AppPayloadObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -753,12 +933,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.appPayload { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventMessageRead: + if len(fl.messageRead) == 0 { + break + } + var obj MessageReadObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -766,12 +950,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.messageRead { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventLikeAdd: + if len(fl.likeAdd) == 0 { + break + } + var obj LikeAddObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -779,12 +967,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.likeAdd { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventLikeRemove: + if len(fl.likeRemove) == 0 { + break + } + var obj LikeRemoveObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -792,12 +984,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.likeRemove { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventDonutSubscriptionCreate: + if len(fl.donutSubscriptionCreate) == 0 { + break + } + var obj DonutSubscriptionCreateObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -805,12 +1001,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.donutSubscriptionCreate { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventDonutSubscriptionProlonged: + if len(fl.donutSubscriptionProlonged) == 0 { + break + } + var obj DonutSubscriptionProlongedObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -818,12 +1018,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.donutSubscriptionProlonged { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventDonutSubscriptionExpired: + if len(fl.donutSubscriptionExpired) == 0 { + break + } + var obj DonutSubscriptionExpiredObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -831,12 +1035,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.donutSubscriptionExpired { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventDonutSubscriptionCancelled: + if len(fl.donutSubscriptionCancelled) == 0 { + break + } + var obj DonutSubscriptionCancelledObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -844,12 +1052,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.donutSubscriptionCancelled { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventDonutSubscriptionPriceChanged: + if len(fl.donutSubscriptionPriceChanged) == 0 { + break + } + var obj DonutSubscriptionPriceChangedObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -857,12 +1069,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.donutSubscriptionPriceChanged { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventDonutMoneyWithdraw: + if len(fl.donutMoneyWithdraw) == 0 { + break + } + var obj DonutMoneyWithdrawObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -870,12 +1086,16 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.donutMoneyWithdraw { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } } case EventDonutMoneyWithdrawError: + if len(fl.donutMoneyWithdrawError) == 0 { + break + } + var obj DonutMoneyWithdrawErrorObject if err := json.Unmarshal(e.Object, &obj); err != nil { return fmt.Errorf("events: %w", err) @@ -883,7 +1103,7 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g for _, f := range fl.donutMoneyWithdrawError { if fl.goroutine { - go func() { f(ctx, obj) }() + go func() { f(context.WithoutCancel(ctx), obj) }() } else { f(ctx, obj) } @@ -894,7 +1114,7 @@ func (fl FuncList) Handler(ctx context.Context, e GroupEvent) error { //nolint:g } // ListEvents return list of events. -func (fl FuncList) ListEvents() []EventType { +func (fl *FuncList) ListEvents() []EventType { return fl.eventsList } @@ -905,10 +1125,6 @@ func (fl *FuncList) Goroutine(v bool) { // OnEvent handler. func (fl *FuncList) OnEvent(eventType EventType, f func(context.Context, GroupEvent)) { - if fl.special == nil { - fl.special = make(map[EventType][]func(context.Context, GroupEvent)) - } - fl.special[eventType] = append(fl.special[eventType], f) fl.eventsList = append(fl.eventsList, eventType) } diff --git a/events/events_test.go b/events/events_test.go index 99555394..20625c59 100644 --- a/events/events_test.go +++ b/events/events_test.go @@ -2383,7 +2383,7 @@ func TestFuncList_DonutMoneyWithdrawError(t *testing.T) { func TestFuncList_OnEvent(t *testing.T) { t.Parallel() - var fl events.FuncList + fl := events.NewFuncList() fl.OnEvent("wtf_event", func(_ context.Context, e events.GroupEvent) { assert.NotEmpty(t, e) diff --git a/longpoll-bot/longpoll.go b/longpoll-bot/longpoll.go index b9ef69fc..74ab300f 100644 --- a/longpoll-bot/longpoll.go +++ b/longpoll-bot/longpoll.go @@ -40,7 +40,7 @@ type LongPoll struct { funcFullResponseList []func(Response) - events.FuncList + *events.FuncList } // NewLongPoll returns a new LongPoll. @@ -50,12 +50,12 @@ type LongPoll struct { // 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, + VK: vk, + GroupID: groupID, + Wait: 25, + Client: http.DefaultClient, + FuncList: events.NewFuncList(), } - lp.FuncList = *events.NewFuncList() err := lp.updateServer(true) @@ -74,12 +74,12 @@ func NewLongPollCommunity(vk *api.VK) (*LongPoll, error) { } lp := &LongPoll{ - VK: vk, - GroupID: resp.Groups[0].ID, - Wait: 25, - Client: http.DefaultClient, + VK: vk, + GroupID: resp.Groups[0].ID, + Wait: 25, + Client: http.DefaultClient, + FuncList: events.NewFuncList(), } - lp.FuncList = *events.NewFuncList() err = lp.updateServer(true) diff --git a/streaming/streaming.go b/streaming/streaming.go index f3d30c74..0fd8e06d 100644 --- a/streaming/streaming.go +++ b/streaming/streaming.go @@ -134,7 +134,7 @@ type Streaming struct { Dialer *websocket.Dialer // A Dialer contains options for connecting to WebSocket server UserAgent string // UserAgent sent in the request. - inShutdown int32 + inShutdown atomic.Bool eventFunc []func(Event) } @@ -281,7 +281,7 @@ func (s *Streaming) OnEvent(f func(Event)) { // Run starting stream. func (s *Streaming) Run() error { - atomic.StoreInt32(&s.inShutdown, 0) + s.inShutdown.Store(false) u := url.URL{ Scheme: "wss", @@ -317,7 +317,7 @@ func (s *Streaming) Run() error { c.SetPingHandler(nil) - for atomic.LoadInt32(&s.inShutdown) == 0 { + for !s.inShutdown.Load() { var r response _, message, err := c.ReadMessage() @@ -349,7 +349,7 @@ func (s *Streaming) Run() error { // Shutdown gracefully shuts down the stream. func (s *Streaming) Shutdown() { - atomic.StoreInt32(&s.inShutdown, 1) + s.inShutdown.Store(true) } // NewStreaming returns a new Streaming. From 8e43ccf796626b5ad10363db28e8fce4cff950e7 Mon Sep 17 00:00:00 2001 From: Daniil Suvorov Date: Sun, 23 Feb 2025 14:19:22 +0300 Subject: [PATCH 5/6] ci: update golangci-lint to 1.64.5 --- .github/workflows/golangci-lint.yml | 2 +- .golangci.yml | 2 +- api/oauth/oauth.go | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index c820e01e..2d5b22a0 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -15,4 +15,4 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v6 with: - version: v1.63.4 + version: v1.64.5 diff --git a/.golangci.yml b/.golangci.yml index 3c698075..c4816e2d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -51,7 +51,6 @@ linters: - contextcheck - ireturn - nilnil - - tenv - nestif - grouper - decorder @@ -144,6 +143,7 @@ linters: # - deadcode # - structcheck # - varcheck +# - tenv issues: exclude-rules: diff --git a/api/oauth/oauth.go b/api/oauth/oauth.go index 6700003a..489096c9 100644 --- a/api/oauth/oauth.go +++ b/api/oauth/oauth.go @@ -7,6 +7,8 @@ import ( "github.com/SevereCloud/vksdk/v3/api" ) +// OAuth addresses. +// //nolint:gochecknoglobals var ( OAuthHost = "oauth.vk.com" From 0b6050115ffcb4f2f49b97a9e300e4b028bf544e Mon Sep 17 00:00:00 2001 From: Daniil Suvorov Date: Sun, 23 Feb 2025 14:20:11 +0300 Subject: [PATCH 6/6] docs: 3.1.0 version --- doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc.go b/doc.go index a5449682..6b62363a 100644 --- a/doc.go +++ b/doc.go @@ -7,6 +7,6 @@ package vksdk // Module constants. const ( - Version = "3.0.1" + Version = "3.1.0" API = "5.199" )