feat: state is now scoped by both user id and chat id
This commit is contained in:
1 parent
4b94fcb920
commit
ec12f29fdb
3 files changed
+31
-23
No files matched your search
@@ -27,9 +27,9 @@ type EventIsolation interface {
|
||||
}
|
||||
|
||||
type FSMStorage interface {
|
||||
Get(ctx context.Context, userID int) (state.Snapshot, error)
|
||||
Get(ctx context.Context, scope isolation.Scope) (state.Snapshot, error)
|
||||
Put(ctx context.Context, state state.Snapshot) error
|
||||
Delete(ctx context.Context, userID int) error
|
||||
Delete(ctx context.Context, scope isolation.Scope) error
|
||||
}
|
||||
|
||||
type UpdateHandler interface {
|
||||
@@ -157,13 +157,13 @@ func (d *Dispatcher) handleUpdates(ch <-chan model.Update) {
|
||||
func (d *Dispatcher) handleUpdate(ctx context.Context, upd model.Update) {
|
||||
var st *state.Context
|
||||
|
||||
snapshot, err := d.fsmStorage.Get(ctx, int(upd.UserID))
|
||||
snapshot, err := d.fsmStorage.Get(ctx, isolation.Scope{UserID: upd.UserID, ChatID: upd.ChatID})
|
||||
if err != nil && !errors.Is(err, state.ErrStateNotFound) {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
if errors.Is(err, state.ErrStateNotFound) {
|
||||
st = state.New(int(upd.UserID))
|
||||
st = state.New(isolation.Scope{UserID: upd.UserID, ChatID: upd.ChatID})
|
||||
} else {
|
||||
st = state.Restore(snapshot)
|
||||
}
|
||||
@@ -177,7 +177,7 @@ func (d *Dispatcher) handleUpdate(ctx context.Context, upd model.Update) {
|
||||
|
||||
st = c.State()
|
||||
if st.State() == state.ClearState {
|
||||
if err := d.fsmStorage.Delete(ctx, int(upd.UserID)); err != nil {
|
||||
if err := d.fsmStorage.Delete(ctx, isolation.Scope{UserID: upd.UserID, ChatID: upd.ChatID}); err != nil {
|
||||
log.Error().Err(err).Send()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ type EventIsolation struct {
|
||||
ttl time.Duration
|
||||
}
|
||||
|
||||
type fsmKey struct {
|
||||
userID int64
|
||||
chatID int64
|
||||
}
|
||||
|
||||
type eventIsolationKey struct {
|
||||
userID int
|
||||
chatID int
|
||||
@@ -34,8 +39,11 @@ func NewFSMStorage() *FSMStorage {
|
||||
return &FSMStorage{}
|
||||
}
|
||||
|
||||
func (f *FSMStorage) Get(_ context.Context, userID int) (state.Snapshot, error) {
|
||||
st, ok := f.m.Load(userID)
|
||||
func (f *FSMStorage) Get(_ context.Context, scope isolation.Scope) (state.Snapshot, error) {
|
||||
st, ok := f.m.Load(fsmKey{
|
||||
userID: scope.UserID,
|
||||
chatID: scope.ChatID,
|
||||
})
|
||||
if !ok {
|
||||
return state.Snapshot{}, state.ErrStateNotFound
|
||||
}
|
||||
@@ -44,12 +52,18 @@ func (f *FSMStorage) Get(_ context.Context, userID int) (state.Snapshot, error)
|
||||
}
|
||||
|
||||
func (f *FSMStorage) Put(_ context.Context, snapshot state.Snapshot) error {
|
||||
f.m.Store(snapshot.ID, snapshot)
|
||||
f.m.Store(fsmKey{
|
||||
userID: snapshot.Scope.UserID,
|
||||
chatID: snapshot.Scope.ChatID,
|
||||
}, snapshot)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FSMStorage) Delete(_ context.Context, userID int) error {
|
||||
f.m.Delete(userID)
|
||||
func (f *FSMStorage) Delete(_ context.Context, scope isolation.Scope) error {
|
||||
f.m.Delete(fsmKey{
|
||||
userID: scope.UserID,
|
||||
chatID: scope.ChatID,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+7
-13
@@ -3,8 +3,7 @@ package state
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/abelith/gomax/v1/isolation"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -32,13 +31,13 @@ func (JSONCodec) Unmarshal(d []byte, v any) error {
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
ID int `json:"id"`
|
||||
Scope isolation.Scope `json:"id"`
|
||||
State State `json:"state"`
|
||||
Data map[string][]byte `json:"data"`
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
id int
|
||||
scope isolation.Scope
|
||||
state State
|
||||
data map[string][]byte
|
||||
codec Codec
|
||||
@@ -48,9 +47,9 @@ type Option func(*Context)
|
||||
|
||||
func WithCodec(c Codec) Option { return func(sc *Context) { sc.codec = c } }
|
||||
|
||||
func New(id int, opts ...Option) *Context {
|
||||
func New(scope isolation.Scope, opts ...Option) *Context {
|
||||
sc := &Context{
|
||||
id: id,
|
||||
scope: scope,
|
||||
data: make(map[string][]byte),
|
||||
codec: JSONCodec{},
|
||||
}
|
||||
@@ -61,7 +60,7 @@ func New(id int, opts ...Option) *Context {
|
||||
}
|
||||
|
||||
func Restore(s Snapshot, opts ...Option) *Context {
|
||||
sc := New(s.ID, opts...)
|
||||
sc := New(s.Scope, opts...)
|
||||
sc.state = s.State
|
||||
for k, v := range s.Data {
|
||||
sc.data[k] = v
|
||||
@@ -74,15 +73,10 @@ func (sc *Context) Snapshot() Snapshot {
|
||||
for k, v := range sc.data {
|
||||
data[k] = v
|
||||
}
|
||||
return Snapshot{ID: sc.id, State: sc.state, Data: data}
|
||||
return Snapshot{Scope: sc.scope, State: sc.state, Data: data}
|
||||
}
|
||||
|
||||
func (sc *Context) Set(state State) {
|
||||
log.Debug().
|
||||
Int("user_id", sc.id).
|
||||
Str("from", string(sc.state)).
|
||||
Str("to", string(state)).
|
||||
Msg("fsm state transition")
|
||||
sc.state = state
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user