mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-16 09:51:59 +03:00
4c24e6d56b
PR-URL: https://github.com/hasura/graphql-engine-mono/pull/6694 GitOrigin-RevId: 96938d65f8de857c87e37b7d0fc508cee6436340
77 lines
1.5 KiB
Go
77 lines
1.5 KiB
Go
package fsm
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/hasura/graphql-engine/cli/v2/internal/errors"
|
|
)
|
|
|
|
var ErrEventRejected = fmt.Errorf("event rejected")
|
|
|
|
const (
|
|
Default StateType = ""
|
|
NoOp EventType = "NoOp"
|
|
)
|
|
|
|
type StateType string
|
|
type EventType string
|
|
type EventContext interface{}
|
|
|
|
type Action interface {
|
|
Execute(eventCtx EventContext) EventType
|
|
}
|
|
|
|
type Events map[EventType]StateType
|
|
|
|
type State struct {
|
|
Action Action
|
|
Events Events
|
|
}
|
|
|
|
type States map[StateType]State
|
|
|
|
type StateMachine struct {
|
|
Previous StateType
|
|
Current StateType
|
|
States States
|
|
mutex sync.Mutex
|
|
}
|
|
|
|
func (s *StateMachine) getNextState(event EventType) (StateType, error) {
|
|
var op errors.Op = "fsm.StateMachine.getNextState"
|
|
if state, ok := s.States[s.Current]; ok {
|
|
if state.Events != nil {
|
|
if next, ok := state.Events[event]; ok {
|
|
return next, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return Default, errors.E(op, fmt.Errorf("next state: %w: %s", ErrEventRejected, event))
|
|
}
|
|
|
|
func (s *StateMachine) SendEvent(event EventType, eventCtx EventContext) error {
|
|
var op errors.Op = "fsm.StateMachine.SendEvent"
|
|
s.mutex.Lock()
|
|
defer s.mutex.Unlock()
|
|
for {
|
|
nextState, err := s.getNextState(event)
|
|
if err != nil {
|
|
return errors.E(op, fmt.Errorf("%w: %s", err, event))
|
|
}
|
|
state, ok := s.States[nextState]
|
|
if !ok || state.Action == nil {
|
|
return errors.E(op, fmt.Errorf("config error"))
|
|
}
|
|
s.Previous = s.Current
|
|
s.Current = nextState
|
|
|
|
nextEvent := state.Action.Execute(eventCtx)
|
|
if nextEvent == NoOp {
|
|
return nil
|
|
}
|
|
event = nextEvent
|
|
}
|
|
}
|