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