mirror of
https://github.com/lightninglabs/loop
synced 2024-11-13 13:10:30 +00:00
5b6f847ece
This commit adds: - a default observer to the FSM - more info to the action entry and exit funcs - an optional initial wait time for the WaitForState function
128 lines
2.7 KiB
Go
128 lines
2.7 KiB
Go
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(), 10)
|
|
|
|
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{
|
|
EmptyState: 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
|
|
}
|