The package fsm
provides a simple Non-Hierarchical Finite State Machine based on the event. Support Go 1.5+
.
$ go get -u github.com/xgfone/go-fsm
package main
import (
"fmt"
gofsm "github.com/xgfone/go-fsm"
)
func main() {
const (
StateFoo = gofsm.State("StateFoo")
StateBar = gofsm.State("StateBar")
)
const (
EventFoo = gofsm.Event("EventFoo")
EventBar = gofsm.Event("EventBar")
)
fsm := gofsm.New()
fsm.SetCurrent(StateFoo)
/// Add the state transitions.
var barCount int
gofsm.Source(StateFoo).WithTarget(StateBar).WithEvent(EventBar).Add(fsm) // No Action
gofsm.Target(StateFoo).WithSource(StateBar).WithEvent(EventFoo).
WithAction(func(fsm *gofsm.FSM, data interface{}) (transition bool) { // Set Action
// TODO: do business something
// Here as the example, after trigger the event EventFoo two twice,
// transition the state to the target.
if barCount > 0 {
barCount = 0
transition = true
} else {
barCount++
}
return
}).
Add(fsm)
/// Set the listener of the state change.
fsm.OnEnter(func(s gofsm.State) { fmt.Printf("OnEnter: %s\n", s) })
fsm.OnExit(func(s gofsm.State) { fmt.Printf("OnExit: %s\n", s) })
fsm.OnEnterState(StateFoo, func(s gofsm.State) { fmt.Printf("OnEnterState: %s\n", s) })
fsm.OnEnterState(StateBar, func(s gofsm.State) { fmt.Printf("OnEnterState: %s\n", s) })
fsm.OnExitState(StateFoo, func(s gofsm.State) { fmt.Printf("OnExitState: %s\n", s) })
fsm.OnExitState(StateBar, func(s gofsm.State) { fmt.Printf("OnExitState: %s\n", s) })
fsm.OnTransition(func(last, current gofsm.State) {
fmt.Printf("OnTransition: %s -> %s\n", last, current)
})
/// Print the states and events
fmt.Printf("Events: %v\n", fsm.Events())
fmt.Printf("States: %v\n", fsm.States())
fmt.Printf("TerminationStates: %v\n", fsm.Terminations()) // No Termination States
/// Send the events to the state machine
fmt.Println("------ Transition ------")
last := fsm.Current()
err := fsm.SendEvent(EventBar, nil)
fmt.Printf("Event: %s, State: %s -> %s, Result: %v\n\n", EventBar, last, fsm.Current(), err)
fmt.Println("------ Transition ------")
last = fsm.Current()
err = fsm.SendEvent(EventFoo, nil)
fmt.Printf("Event: %s, State: %s -> %s, Result: %v\n\n", EventFoo, last, fsm.Current(), err)
fmt.Println("------ Transition ------")
last = fsm.Current()
err = fsm.SendEvent(EventFoo, nil)
fmt.Printf("Event: %s, State: %s -> %s, Result: %v\n\n", EventFoo, last, fsm.Current(), err)
fmt.Println("------ Transition ------")
last = fsm.Current()
err = fsm.SendEvent(EventFoo, nil)
fmt.Printf("Event: %s, State: %s -> %s, Result: %v\n\n", EventFoo, last, fsm.Current(), err)
fmt.Println("------ Transition ------")
last = fsm.Current()
err = fsm.SendEvent(EventBar, nil)
fmt.Printf("Event: %s, State: %s -> %s, Result: %v\n\n", EventBar, last, fsm.Current(), err)
// Print the Graphviz visualizer.
fmt.Println("------ Graphviz ------")
fmt.Println(fsm.VisualizeGraphviz())
// Print the Mermaid FlowChart visualizer.
fmt.Println("------ Mermaid FlowChart ------")
fmt.Println(fsm.VisualizeMermaidFlowChart("#aaaaaa"))
// Print the Mermaid StateDiagram visualizer.
fmt.Println("------ Mermaid StateDiagram ------")
fmt.Println(fsm.VisualizeMermaidStateDiagram())
// Output:
// Events: [EventBar EventFoo]
// States: [StateFoo StateBar]
// TerminationStates: []
// ------ Transition ------
// OnExitState: StateFoo
// OnExit: StateFoo
// OnEnterState: StateBar
// OnEnter: StateBar
// OnTransition: StateFoo -> StateBar
// Event: EventBar, State: StateFoo -> StateBar, Result: <nil>
//
// ------ Transition ------
// Event: EventFoo, State: StateBar -> StateBar, Result: source state 'StateBar' transition for the event 'EventFoo' is suspended
//
// ------ Transition ------
// OnExitState: StateBar
// OnExit: StateBar
// OnEnterState: StateFoo
// OnEnter: StateFoo
// OnTransition: StateBar -> StateFoo
// Event: EventFoo, State: StateBar -> StateFoo, Result: <nil>
//
// ------ Transition ------
// Event: EventFoo, State: StateFoo -> StateFoo, Result: no transition for the event 'EventFoo'
//
// ------ Transition ------
// OnExitState: StateFoo
// OnExit: StateFoo
// OnEnterState: StateBar
// OnEnter: StateBar
// OnTransition: StateFoo -> StateBar
// Event: EventBar, State: StateFoo -> StateBar, Result: <nil>
//
// ------ Graphviz ------
// digraph fsm {
// "StateBar" -> "StateFoo" [ label = "EventFoo" ];
// "StateFoo" -> "StateBar" [ label = "EventBar" ];
//
// "StateBar";
// "StateFoo";
// }
//
// ------ Mermaid FlowChart ------
// graph LR
// id0[StateBar]
// id1[StateFoo]
//
// id0 --> |EventFoo| id1
// id1 --> |EventBar| id0
//
// style id0 fill:#aaaaaa
//
// ------ Mermaid StateDiagram ------
// stateDiagram-v2
// [*] --> StateBar
// StateBar --> StateFoo: EventFoo
// StateFoo --> StateBar: EventBar
//
}