add once + singleton click interceptor (#229)

* speed up tx lock

* yolo master

* add once + singleton click interceptor

* yoooo;

* stuff

Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
This commit is contained in:
gohumble 2021-12-26 00:23:58 +01:00 committed by GitHub
parent 24108f6a1f
commit 151ed39b04
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 1 deletions

View file

@ -0,0 +1,48 @@
package once
import (
"fmt"
cmap "github.com/orcaman/concurrent-map"
log "github.com/sirupsen/logrus"
)
var onceMap cmap.ConcurrentMap
func init() {
onceMap = cmap.New()
}
func New(objectKey string) {
onceMap.Set(objectKey, cmap.New())
}
// Once creates a map of keys k1 with a map of keys k2.
// The idea is that an object with ID k1 can create a list of users k2
// that have already interacted with the object. If the user k2 is in the list,
// the object is not allowed to accessed again.
func Once(k1, k2 string) error {
i, ok := onceMap.Get(k1)
if ok {
return setOrReturn(i.(cmap.ConcurrentMap), k2)
}
userMap := cmap.New()
onceMap.Set(k1, userMap)
return setOrReturn(userMap, k2)
}
// setOrReturn sets the key k2 in the map i if it is not already set.
func setOrReturn(objectMap cmap.ConcurrentMap, k2 string) error {
if _, ok := objectMap.Get(k2); ok {
return fmt.Errorf("%s already consumed object", k2)
}
objectMap.Set(k2, true)
return nil
}
// Remove removes the key k1 from the map. Should be called after Once was called and
// the object k1 finished.
func Remove(k1 string) {
onceMap.Remove(k1)
log.Tracef("Removed key %s from onceMap (len=%d)", k1, len(onceMap.Keys()))
}

View file

@ -549,6 +549,7 @@ func (bot TipBot) getHandler() []Handler {
Interceptor: &Interceptor{
Type: CallbackInterceptor,
Before: []intercept.Func{
bot.singletonCallbackInterceptor,
bot.localizerInterceptor,
bot.loadUserInterceptor,
bot.lockInterceptor,

View file

@ -8,6 +8,7 @@ import (
"time"
"github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex"
"github.com/LightningTipBot/LightningTipBot/internal/runtime/once"
"github.com/LightningTipBot/LightningTipBot/internal/storage"
"github.com/eko/gocache/store"
@ -366,6 +367,7 @@ func (bot *TipBot) cancelInlineFaucet(ctx context.Context, c *tb.Callback, ignor
inlineFaucet.Canceled = true
runtime.IgnoreError(inlineFaucet.Set(inlineFaucet, bot.Bunt))
log.Debugf("[faucet] Faucet %s canceled.", inlineFaucet.ID)
once.Remove(inlineFaucet.ID)
}
return
}
@ -378,6 +380,7 @@ func (bot *TipBot) finishFaucet(ctx context.Context, c *tb.Callback, inlineFauce
bot.tryEditMessage(c.Message, inlineFaucet.Message, &tb.ReplyMarkup{})
inlineFaucet.Active = false
log.Debugf("[faucet] Faucet finished %s", inlineFaucet.ID)
once.Remove(inlineFaucet.ID)
}
func (bot *TipBot) cancelInlineFaucetHandler(ctx context.Context, c *tb.Callback) {

View file

@ -3,10 +3,12 @@ package telegram
import (
"context"
"fmt"
"github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex"
"reflect"
"strconv"
"github.com/LightningTipBot/LightningTipBot/internal/runtime/mutex"
"github.com/LightningTipBot/LightningTipBot/internal/runtime/once"
"github.com/LightningTipBot/LightningTipBot/internal/i18n"
i18n2 "github.com/nicksnyder/go-i18n/v2/i18n"
@ -33,6 +35,17 @@ type Interceptor struct {
OnDefer []intercept.Func
}
// singletonClickInterceptor uses the onceMap to determine whether the object k1 already interacted
// with the user k2. If so, it will return an error.
func (bot TipBot) singletonCallbackInterceptor(ctx context.Context, i interface{}) (context.Context, error) {
switch i.(type) {
case *tb.Callback:
c := i.(*tb.Callback)
return ctx, once.Once(c.Data, strconv.FormatInt(c.Sender.ID, 10))
}
return ctx, invalidTypeError
}
// unlockInterceptor invoked as onDefer interceptor
func (bot TipBot) unlockInterceptor(ctx context.Context, i interface{}) (context.Context, error) {
user := getTelegramUserFromInterface(i)