mirror of
https://github.com/ChuckNorrison/LightningTipBot.git
synced 2026-08-19 13:18:12 +02:00
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:
parent
24108f6a1f
commit
151ed39b04
4 changed files with 66 additions and 1 deletions
48
internal/runtime/once/once.go
Normal file
48
internal/runtime/once/once.go
Normal 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()))
|
||||
}
|
||||
|
|
@ -549,6 +549,7 @@ func (bot TipBot) getHandler() []Handler {
|
|||
Interceptor: &Interceptor{
|
||||
Type: CallbackInterceptor,
|
||||
Before: []intercept.Func{
|
||||
bot.singletonCallbackInterceptor,
|
||||
bot.localizerInterceptor,
|
||||
bot.loadUserInterceptor,
|
||||
bot.lockInterceptor,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue