1、增加状态机模块。

This commit is contained in:
redhat 2025-06-06 18:47:13 +08:00
parent a64ab4f5f9
commit 5cd7328291
2 changed files with 247 additions and 0 deletions

160
pkg/myfsm/fsm.go Normal file
View 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
View 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)
}