Skip to content

Commit

Permalink
Merge pull request #631 from sputn1ck/instantloopout_1
Browse files Browse the repository at this point in the history
[1/?] Instant loop out: Add FSM module
  • Loading branch information
sputn1ck authored Sep 7, 2023
2 parents 5739fa5 + 20db07d commit 077d702
Show file tree
Hide file tree
Showing 13 changed files with 1,205 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,10 @@ issues:

# Allow fmt.Printf() in loop
- path: cmd/loop/*
linters:
- forbidigo

# Allow fmt.Printf() in stateparser
- path: fsm/stateparser/*
linters:
- forbidigo
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,7 @@ sqlc-check: sqlc
@$(call print, "Verifying sql code generation.")
if test -n "$$(git status --porcelain '*.go')"; then echo "SQL models not properly generated!"; git status --porcelain '*.go'; exit 1; fi


fsm:
@$(call print, "Generating state machine docs")
./scripts/fsm-generate.sh;
.PHONY: fsm
127 changes: 127 additions & 0 deletions fsm/example_fsm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package fsm

import (
"fmt"
)

// ExampleService is an example service that we want to wait for in the FSM.
type ExampleService interface {
WaitForStuffHappening() (<-chan bool, error)
}

// ExampleStore is an example store that we want to use in our exitFunc.
type ExampleStore interface {
StoreStuff() error
}

// ExampleFSM implements the FSM and uses the ExampleService and ExampleStore
// to implement the actions.
type ExampleFSM struct {
*StateMachine

service ExampleService
store ExampleStore
}

// NewExampleFSMContext creates a new example FSM context.
func NewExampleFSMContext(service ExampleService,
store ExampleStore) *ExampleFSM {

exampleFSM := &ExampleFSM{
service: service,
store: store,
}
exampleFSM.StateMachine = NewStateMachine(exampleFSM.GetStates())

return exampleFSM
}

// States.
const (
InitFSM = StateType("InitFSM")
StuffSentOut = StateType("StuffSentOut")
WaitingForStuff = StateType("WaitingForStuff")
StuffFailed = StateType("StuffFailed")
StuffSuccess = StateType("StuffSuccess")
)

// Events.
var (
OnRequestStuff = EventType("OnRequestStuff")
OnStuffSentOut = EventType("OnStuffSentOut")
OnStuffSuccess = EventType("OnStuffSuccess")
)

// GetStates returns the states for the example FSM.
func (e *ExampleFSM) GetStates() States {
return States{
Default: State{
Transitions: Transitions{
OnRequestStuff: InitFSM,
},
},
InitFSM: State{
Action: e.initFSM,
Transitions: Transitions{
OnStuffSentOut: StuffSentOut,
OnError: StuffFailed,
},
},
StuffSentOut: State{
Action: e.waitForStuff,
Transitions: Transitions{
OnStuffSuccess: StuffSuccess,
OnError: StuffFailed,
},
},
StuffFailed: State{
Action: NoOpAction,
},
StuffSuccess: State{
Action: NoOpAction,
},
}
}

// InitStuffRequest is the event context for the InitFSM state.
type InitStuffRequest struct {
Stuff string
respondChan chan<- string
}

// initFSM is the action for the InitFSM state.
func (e *ExampleFSM) initFSM(eventCtx EventContext) EventType {
req, ok := eventCtx.(*InitStuffRequest)
if !ok {
return e.HandleError(
fmt.Errorf("invalid event context type: %T", eventCtx),
)
}

err := e.store.StoreStuff()
if err != nil {
return e.HandleError(err)
}

req.respondChan <- req.Stuff

return OnStuffSentOut
}

// waitForStuff is an action that waits for stuff to happen.
func (e *ExampleFSM) waitForStuff(eventCtx EventContext) EventType {
waitChan, err := e.service.WaitForStuffHappening()
if err != nil {
return e.HandleError(err)
}

go func() {
<-waitChan
err := e.SendEvent(OnStuffSuccess, nil)
if err != nil {
log.Errorf("unable to send event: %v", err)
}
}()

return NoOp
}
12 changes: 12 additions & 0 deletions fsm/example_fsm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
```mermaid
stateDiagram-v2
[*] --> InitFSM: OnRequestStuff
InitFSM
InitFSM --> StuffFailed: OnError
InitFSM --> StuffSentOut: OnStuffSentOut
StuffFailed
StuffSentOut
StuffSentOut --> StuffFailed: OnError
StuffSentOut --> StuffSuccess: OnStuffSuccess
StuffSuccess
```
Loading

0 comments on commit 077d702

Please sign in to comment.