You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
1.2 KiB
Go
72 lines
1.2 KiB
Go
package fsm
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
)
|
|
|
|
type State string
|
|
|
|
type Event string
|
|
|
|
type Action func(ctx context.Context) error
|
|
|
|
type Node struct {
|
|
State
|
|
Transitions map[Event]*Transition
|
|
}
|
|
|
|
type Transition struct {
|
|
*Node
|
|
Action
|
|
}
|
|
|
|
type StateMachine struct {
|
|
initialNode *Node
|
|
CurrentNode *Node
|
|
}
|
|
|
|
func (m *StateMachine) getCurrentNode() *Node {
|
|
return m.CurrentNode
|
|
}
|
|
|
|
func (m *StateMachine) getNextNode(event Event) (*Node, error) {
|
|
if m.CurrentNode == nil {
|
|
return nil, fmt.Errorf("nowhere to go anymore!\n")
|
|
}
|
|
|
|
transition, ok := m.CurrentNode.Transitions[event]
|
|
if !ok {
|
|
return nil, fmt.Errorf("invalid event: %v", event)
|
|
}
|
|
|
|
return transition.Node, nil
|
|
}
|
|
|
|
func (m *StateMachine) Transition(ctx context.Context, event Event) (*Node, error) {
|
|
node, err := m.getNextNode(event) // gets current node
|
|
if err != nil {
|
|
return nil, fmt.Errorf(err.Error())
|
|
}
|
|
|
|
err = m.CurrentNode.Transitions[event].Action(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(err.Error())
|
|
}
|
|
|
|
m.CurrentNode = node
|
|
|
|
return m.CurrentNode, nil
|
|
}
|
|
|
|
func NewStateMachine(initialNode *Node) *StateMachine {
|
|
if initialNode == nil {
|
|
return &StateMachine{}
|
|
}
|
|
|
|
return &StateMachine{
|
|
initialNode: initialNode,
|
|
CurrentNode: initialNode,
|
|
}
|
|
}
|