-
Notifications
You must be signed in to change notification settings - Fork 117
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #631 from sputn1ck/instantloopout_1
[1/?] Instant loop out: Add FSM module
- Loading branch information
Showing
13 changed files
with
1,205 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
Oops, something went wrong.