Skip to content

Commit 077d702

Browse files
authored
Merge pull request #631 from sputn1ck/instantloopout_1
[1/?] Instant loop out: Add FSM module
2 parents 5739fa5 + 20db07d commit 077d702

13 files changed

+1205
-1
lines changed

.golangci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,5 +133,10 @@ issues:
133133

134134
# Allow fmt.Printf() in loop
135135
- path: cmd/loop/*
136+
linters:
137+
- forbidigo
138+
139+
# Allow fmt.Printf() in stateparser
140+
- path: fsm/stateparser/*
136141
linters:
137142
- forbidigo

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,7 @@ sqlc-check: sqlc
134134
@$(call print, "Verifying sql code generation.")
135135
if test -n "$$(git status --porcelain '*.go')"; then echo "SQL models not properly generated!"; git status --porcelain '*.go'; exit 1; fi
136136

137-
137+
fsm:
138+
@$(call print, "Generating state machine docs")
139+
./scripts/fsm-generate.sh;
140+
.PHONY: fsm

fsm/example_fsm.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package fsm
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
// ExampleService is an example service that we want to wait for in the FSM.
8+
type ExampleService interface {
9+
WaitForStuffHappening() (<-chan bool, error)
10+
}
11+
12+
// ExampleStore is an example store that we want to use in our exitFunc.
13+
type ExampleStore interface {
14+
StoreStuff() error
15+
}
16+
17+
// ExampleFSM implements the FSM and uses the ExampleService and ExampleStore
18+
// to implement the actions.
19+
type ExampleFSM struct {
20+
*StateMachine
21+
22+
service ExampleService
23+
store ExampleStore
24+
}
25+
26+
// NewExampleFSMContext creates a new example FSM context.
27+
func NewExampleFSMContext(service ExampleService,
28+
store ExampleStore) *ExampleFSM {
29+
30+
exampleFSM := &ExampleFSM{
31+
service: service,
32+
store: store,
33+
}
34+
exampleFSM.StateMachine = NewStateMachine(exampleFSM.GetStates())
35+
36+
return exampleFSM
37+
}
38+
39+
// States.
40+
const (
41+
InitFSM = StateType("InitFSM")
42+
StuffSentOut = StateType("StuffSentOut")
43+
WaitingForStuff = StateType("WaitingForStuff")
44+
StuffFailed = StateType("StuffFailed")
45+
StuffSuccess = StateType("StuffSuccess")
46+
)
47+
48+
// Events.
49+
var (
50+
OnRequestStuff = EventType("OnRequestStuff")
51+
OnStuffSentOut = EventType("OnStuffSentOut")
52+
OnStuffSuccess = EventType("OnStuffSuccess")
53+
)
54+
55+
// GetStates returns the states for the example FSM.
56+
func (e *ExampleFSM) GetStates() States {
57+
return States{
58+
Default: State{
59+
Transitions: Transitions{
60+
OnRequestStuff: InitFSM,
61+
},
62+
},
63+
InitFSM: State{
64+
Action: e.initFSM,
65+
Transitions: Transitions{
66+
OnStuffSentOut: StuffSentOut,
67+
OnError: StuffFailed,
68+
},
69+
},
70+
StuffSentOut: State{
71+
Action: e.waitForStuff,
72+
Transitions: Transitions{
73+
OnStuffSuccess: StuffSuccess,
74+
OnError: StuffFailed,
75+
},
76+
},
77+
StuffFailed: State{
78+
Action: NoOpAction,
79+
},
80+
StuffSuccess: State{
81+
Action: NoOpAction,
82+
},
83+
}
84+
}
85+
86+
// InitStuffRequest is the event context for the InitFSM state.
87+
type InitStuffRequest struct {
88+
Stuff string
89+
respondChan chan<- string
90+
}
91+
92+
// initFSM is the action for the InitFSM state.
93+
func (e *ExampleFSM) initFSM(eventCtx EventContext) EventType {
94+
req, ok := eventCtx.(*InitStuffRequest)
95+
if !ok {
96+
return e.HandleError(
97+
fmt.Errorf("invalid event context type: %T", eventCtx),
98+
)
99+
}
100+
101+
err := e.store.StoreStuff()
102+
if err != nil {
103+
return e.HandleError(err)
104+
}
105+
106+
req.respondChan <- req.Stuff
107+
108+
return OnStuffSentOut
109+
}
110+
111+
// waitForStuff is an action that waits for stuff to happen.
112+
func (e *ExampleFSM) waitForStuff(eventCtx EventContext) EventType {
113+
waitChan, err := e.service.WaitForStuffHappening()
114+
if err != nil {
115+
return e.HandleError(err)
116+
}
117+
118+
go func() {
119+
<-waitChan
120+
err := e.SendEvent(OnStuffSuccess, nil)
121+
if err != nil {
122+
log.Errorf("unable to send event: %v", err)
123+
}
124+
}()
125+
126+
return NoOp
127+
}

fsm/example_fsm.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
```mermaid
2+
stateDiagram-v2
3+
[*] --> InitFSM: OnRequestStuff
4+
InitFSM
5+
InitFSM --> StuffFailed: OnError
6+
InitFSM --> StuffSentOut: OnStuffSentOut
7+
StuffFailed
8+
StuffSentOut
9+
StuffSentOut --> StuffFailed: OnError
10+
StuffSentOut --> StuffSuccess: OnStuffSuccess
11+
StuffSuccess
12+
```

0 commit comments

Comments
 (0)