1、增加状态机模块。
This commit is contained in:
parent
a64ab4f5f9
commit
5cd7328291
160
pkg/myfsm/fsm.go
Normal file
160
pkg/myfsm/fsm.go
Normal file
@ -0,0 +1,160 @@
|
||||
package fsm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type EventName string
|
||||
|
||||
const (
|
||||
EventEntry EventName = "EventEntry"
|
||||
EventExit EventName = "EventExit"
|
||||
|
||||
EventOK EventName = "EventOK"
|
||||
EventNoProc EventName = "EventNoProc"
|
||||
)
|
||||
|
||||
type Callback func(fsm *FSM, event EventName, arg interface{}) EventName
|
||||
|
||||
type Callbacks map[string]Callback
|
||||
|
||||
type FSMState struct {
|
||||
name string
|
||||
parent string
|
||||
initState string
|
||||
processor Callback
|
||||
}
|
||||
|
||||
type FSM struct {
|
||||
name string
|
||||
currentState *FSMState
|
||||
eventNames *[]string
|
||||
fsmStats map[string]*FSMState
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
FSM *FSM
|
||||
Event string
|
||||
Src string
|
||||
Dst string
|
||||
Err error
|
||||
Args []interface{}
|
||||
canceled bool
|
||||
async bool
|
||||
cancelFunc func()
|
||||
}
|
||||
|
||||
func NewFSMState(name string, parent, initState string, processor Callback) *FSMState {
|
||||
return &FSMState{
|
||||
name: name,
|
||||
parent: parent,
|
||||
initState: initState,
|
||||
processor: processor,
|
||||
}
|
||||
}
|
||||
|
||||
func NewFSM(name string, eventNames *[]string, fsmStats ...*FSMState) (*FSM, error) {
|
||||
if len(fsmStats) == 0 {
|
||||
return nil, fmt.Errorf("initial state cannot be nil")
|
||||
}
|
||||
fsm := &FSM{
|
||||
name: name,
|
||||
currentState: fsmStats[0],
|
||||
eventNames: eventNames,
|
||||
fsmStats: make(map[string]*FSMState),
|
||||
}
|
||||
|
||||
for index := range fsmStats {
|
||||
fsm.fsmStats[fsmStats[index].name] = fsmStats[index]
|
||||
}
|
||||
|
||||
// Execute ENTRY event for initial state and its sub-states
|
||||
for tempState := fsm.currentState; tempState != nil; tempState = fsm.fsmStats[tempState.initState] {
|
||||
fsm.currentState = tempState
|
||||
if err := fsm.ExecuteEvent(EventEntry, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return fsm, nil
|
||||
}
|
||||
|
||||
func (fsm *FSM) ExecuteEvent(event EventName, arg interface{}) error {
|
||||
if fsm == nil {
|
||||
return fmt.Errorf("FSM is nil")
|
||||
}
|
||||
|
||||
log.Printf("%d %-23s STATE:%-23s EVENT:%s\n", time.Now().UnixMilli(), fsm.name, fsm.currentState.name, event)
|
||||
|
||||
tmpState := fsm.currentState
|
||||
if tmpState == nil {
|
||||
return fmt.Errorf("current state is nil")
|
||||
}
|
||||
|
||||
result := tmpState.processor(fsm, event, arg)
|
||||
for result == EventNoProc && fsm.fsmStats[tmpState.parent] != nil {
|
||||
tmpState = fsm.fsmStats[tmpState.parent]
|
||||
result = tmpState.processor(fsm, event, arg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fsm *FSM) ChangeState(newState string, arg interface{}) error {
|
||||
if newState == "" {
|
||||
return fmt.Errorf("new state cannot be nil")
|
||||
}
|
||||
|
||||
curState := fsm.currentState
|
||||
|
||||
for tempState := curState; tempState != nil; tempState = fsm.fsmStats[tempState.parent] {
|
||||
fsm.currentState = tempState
|
||||
if err := fsm.ExecuteEvent(EventExit, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if newState == tempState.name {
|
||||
if err := fsm.ExecuteEvent(EventEntry, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if found, ok := fsm.findState(fsm.fsmStats[newState], tempState); ok {
|
||||
for end := len(found) - 1; end >= 0; end-- {
|
||||
fsm.currentState = found[end]
|
||||
if err := fsm.ExecuteEvent(EventEntry, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Enter sub-states of the new state
|
||||
for tempState := fsm.fsmStats[newState].initState; fsm.fsmStats[tempState] != nil; tempState = fsm.fsmStats[tempState].initState {
|
||||
fsm.currentState = fsm.fsmStats[tempState]
|
||||
if err := fsm.ExecuteEvent(EventEntry, arg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fsm *FSM) findState(targetState, findState *FSMState) ([]*FSMState, bool) {
|
||||
var fsmStateList []*FSMState
|
||||
|
||||
for tempState := targetState; tempState != nil; tempState = fsm.fsmStats[tempState.parent] {
|
||||
|
||||
fsmStateList = append(fsmStateList, tempState)
|
||||
|
||||
if findState.parent == tempState.parent {
|
||||
return fsmStateList, true
|
||||
}
|
||||
}
|
||||
|
||||
return fsmStateList, false
|
||||
}
|
87
pkg/myfsm/fsm_test.go
Normal file
87
pkg/myfsm/fsm_test.go
Normal file
@ -0,0 +1,87 @@
|
||||
package fsm
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type myFsm struct {
|
||||
fsm *FSM
|
||||
}
|
||||
|
||||
func state1(fsm *FSM, event EventName, arg interface{}) EventName {
|
||||
switch event {
|
||||
case EventEntry:
|
||||
log.Println("state1", event)
|
||||
case EventExit:
|
||||
log.Println("state1", event)
|
||||
default:
|
||||
log.Println("state1", event)
|
||||
return EventNoProc
|
||||
}
|
||||
|
||||
return EventOK
|
||||
}
|
||||
|
||||
func state2(fsm *FSM, event EventName, arg interface{}) EventName {
|
||||
switch event {
|
||||
case EventEntry:
|
||||
log.Println("state2", event)
|
||||
case EventExit:
|
||||
log.Println("state2", event)
|
||||
default:
|
||||
log.Println("state2", event)
|
||||
return EventNoProc
|
||||
}
|
||||
|
||||
return EventOK
|
||||
}
|
||||
|
||||
func state3(fsm *FSM, event EventName, arg interface{}) EventName {
|
||||
switch event {
|
||||
case EventEntry:
|
||||
log.Println("state3", event)
|
||||
case EventExit:
|
||||
log.Println("state3", event)
|
||||
case "test event":
|
||||
log.Println("state3", event)
|
||||
default:
|
||||
log.Println("state3", event)
|
||||
return EventNoProc
|
||||
}
|
||||
|
||||
return EventOK
|
||||
}
|
||||
|
||||
func newMyFsm() *myFsm {
|
||||
state1 := NewFSMState("State1", "", "State2", state1)
|
||||
state2 := NewFSMState("State2", "State1", "", state2)
|
||||
state3 := NewFSMState("State3", "State1", "", state3)
|
||||
|
||||
fsm, err := NewFSM("MyFSM", &[]string{string(EventEntry), string(EventExit)}, state2, state1, state3)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return &myFsm{fsm: fsm}
|
||||
}
|
||||
|
||||
func Test_fsm(t *testing.T) {
|
||||
myfsm := newMyFsm()
|
||||
|
||||
if err := myfsm.fsm.ChangeState("State3", nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
myfsm.fsm.ExecuteEvent("test event", nil)
|
||||
|
||||
// Start a timer (example)
|
||||
// timerHandle := &ReactorTimerHandle{}
|
||||
// if err := fsm.StartReactorTimer(timerHandle, 0, 1000, EventEntry, nil); err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
|
||||
// Keep the program running to observeinterior
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
Loading…
Reference in New Issue
Block a user