diff options
| author | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-11-28 11:18:14 +0100 |
|---|---|---|
| committer | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-11-28 11:18:42 +0100 |
| commit | e9f8db8ee8fccf60e58deb1d72766f94a053bb16 (patch) | |
| tree | ffa5a9be67717ecc8ff7bdc03d5f96028facb0e3 /internal/fsm | |
| parent | b4ff890ec2b459148d893499a34a6d2954530369 (diff) | |
Document: Add comments for most functions and packages
Errors and test files still need to be done. Also some getters are
changed by removing the 'get' prefix
Diffstat (limited to 'internal/fsm')
| -rw-r--r-- | internal/fsm/fsm.go | 71 |
1 files changed, 50 insertions, 21 deletions
diff --git a/internal/fsm/fsm.go b/internal/fsm/fsm.go index b51a5c9..b8fd644 100644 --- a/internal/fsm/fsm.go +++ b/internal/fsm/fsm.go @@ -1,3 +1,5 @@ +// Package fsm defines a finite state machine and has the ability to save this state machine to a graph file +// This graph file can be visualized using mermaid.js package fsm import ( @@ -10,7 +12,9 @@ import ( ) type ( + //StateID represents the Identifier of the state FSMStateID int8 + //StateIDSlice represents the list of state identifiers FSMStateIDSlice []FSMStateID ) @@ -26,8 +30,11 @@ func (v FSMStateIDSlice) Swap(i, j int) { v[i], v[j] = v[j], v[i] } +// Transition indicates an arrow in the state graph type FSMTransition struct { + // To represents the to-be-new state To FSMStateID + // Description is what type of message the arrow gets in the graph Description string } @@ -35,45 +42,60 @@ type ( FSMStates map[FSMStateID]FSMState ) +// State represents a single node in the graph type FSMState struct { + // Transitions indicates which out arrows this node has Transitions []FSMTransition - - // Which state to go back to on a back transition - BackState FSMStateID } +// FSM represents the total graph type FSM struct { + // States is the map from state ID to states States FSMStates + + // Current is the current state represented by the identifier Current FSMStateID - // Info to be passed from the parent state + // Name represents the descriptive name of this state machine Name string + + // StateCallback is the function ran when a transition occurs + // It takes the old state, the new state and the data and returns if this is handled by the client StateCallback func(FSMStateID, FSMStateID, interface{}) bool + + // Directory represents the path where the state graph is stored Directory string - Debug bool - GetName func(FSMStateID) string + + // Generate represents whether we want to generate the graph + Generate bool + + // GetStateName gets the name of a state as a string + GetStateName func(FSMStateID) string } +// Init initializes the state machine and sets it to the given current state func (fsm *FSM) Init( current FSMStateID, states map[FSMStateID]FSMState, callback func(FSMStateID, FSMStateID, interface{}) bool, directory string, nameGen func(FSMStateID) string, - debug bool, + generate bool, ) { fsm.States = states fsm.Current = current fsm.StateCallback = callback fsm.Directory = directory - fsm.GetName = nameGen - fsm.Debug = debug + fsm.GetStateName = nameGen + fsm.Generate = generate } +// InState returns whether or not the state machine is in the given 'check' state func (fsm *FSM) InState(check FSMStateID) bool { return check == fsm.Current } +// HasTransition checks whether or not the state machine has a transition to the given 'check' state func (fsm *FSM) HasTransition(check FSMStateID) bool { for _, transitionState := range fsm.States[fsm.Current].Transitions { if transitionState.To == check { @@ -84,11 +106,13 @@ func (fsm *FSM) HasTransition(check FSMStateID) bool { return false } +// getGraphFilename gets the full path to the graph filename including the .graph extension func (fsm *FSM) getGraphFilename(extension string) string { debugPath := path.Join(fsm.Directory, "graph") return fmt.Sprintf("%s%s", debugPath, extension) } +// writeGraph writes the state machine to a .graph file func (fsm *FSM) writeGraph() { graph := fsm.GenerateGraph() graphFile := fsm.getGraphFilename(".graph") @@ -107,18 +131,18 @@ func (fsm *FSM) writeGraph() { } } -func (fsm *FSM) GoBack() { - fsm.GoTransition(fsm.States[fsm.Current].BackState) -} - +// GoTransitionRequired transitions the state machine to a new state with associated state data 'data' +// If this transition is not handled by the client, it returns an error func (fsm *FSM) GoTransitionRequired(newState FSMStateID, data interface{}) error { oldState := fsm.Current if !fsm.GoTransitionWithData(newState, data) { - return types.NewWrappedError("failed required transition", fmt.Errorf("required transition not handled, from: %s -> to: %s", fsm.GetName(oldState), fsm.GetName(newState))) + return types.NewWrappedError("failed required transition", fmt.Errorf("required transition not handled, from: %s -> to: %s", fsm.GetStateName(oldState), fsm.GetStateName(newState))) } return nil } +// GoTransitionWithData is a helper that transitions the state machine toward the 'newState' with associated state data 'data' +// It returns whether or not the transition is handled by the client func (fsm *FSM) GoTransitionWithData(newState FSMStateID, data interface{}) bool { ok := fsm.HasTransition(newState) @@ -126,7 +150,7 @@ func (fsm *FSM) GoTransitionWithData(newState FSMStateID, data interface{}) bool if ok { oldState := fsm.Current fsm.Current = newState - if fsm.Debug { + if fsm.Generate { fsm.writeGraph() } @@ -136,11 +160,14 @@ func (fsm *FSM) GoTransitionWithData(newState FSMStateID, data interface{}) bool return handled } +// GoTransition is an alias to call GoTransitionWithData but have an empty string as data func (fsm *FSM) GoTransition(newState FSMStateID) bool { // No data means the callback is never required return fsm.GoTransitionWithData(newState, "") } +// generateMermaidGraph generates a graph suitable to be converted by the mermaid.js tool +// it returns the graph as a string func (fsm *FSM) generateMermaidGraph() string { graph := "graph TD\n" sortedFSM := make(FSMStateIDSlice, 0, len(fsm.States)) @@ -152,15 +179,15 @@ func (fsm *FSM) generateMermaidGraph() string { transitions := fsm.States[state].Transitions for _, transition := range transitions { if state == fsm.Current { - graph += "\nstyle " + fsm.GetName(state) + " fill:cyan\n" + graph += "\nstyle " + fsm.GetStateName(state) + " fill:cyan\n" } else { - graph += "\nstyle " + fsm.GetName(state) + " fill:white\n" + graph += "\nstyle " + fsm.GetStateName(state) + " fill:white\n" } - graph += fsm.GetName( + graph += fsm.GetStateName( state, - ) + "(" + fsm.GetName( + ) + "(" + fsm.GetStateName( state, - ) + ") " + "-->|" + transition.Description + "| " + fsm.GetName( + ) + ") " + "-->|" + transition.Description + "| " + fsm.GetStateName( transition.To, ) + "\n" } @@ -168,8 +195,10 @@ func (fsm *FSM) generateMermaidGraph() string { return graph } +// GenerateGraph generates a mermaid graph if the state machine is initialized +// If the graph cannot be generated, it returns the empty string func (fsm *FSM) GenerateGraph() string { - if fsm.GetName != nil { + if fsm.GetStateName != nil { return fsm.generateMermaidGraph() } |
