/pkg/states/README.md
/pkg/states contains common state schema mixins to make state-based APIs easier to compose and exchange. It also offers tooling for piping states between state machines.
Available State Schemas
- BasicStatesDef: Start, Ready, Healthcheck
- ConnectedStatesDef: Client connection in 4 states
- DisposedStatesDef: Async disposal
Installation States
import ssam "github.com/pancsta/asyncmachine-go/pkg/states"
Examples
Inherit from BasicStatesDef manually
// inherit BasicSchema
schema := am.SchemaMerge(ssam.BasicSchema, am.Schema{
"Foo": {Require: am.S{"Bar"}},
"Bar": {},
})
names := am.SAdd(ssam.BasicStates.Names(), am.S{"Foo", "Bar"})
Inherit from BasicStatesDef via a schema definition
// MyMachStatesDef contains all the states of the MyMach state machine.
type MyMachStatesDef struct {
*am.StatesBase
State1 string
State2 string
// inherit from BasicStatesDef
*ss.BasicStatesDef
}
// MyMachSchema represents all relations and properties of MyMachStates.
var MyMachSchema = SchemaMerge(
// inherit from BasicSchema
ss.BasicSchema,
am.Schema{
ssM.State1: {},
ssM.State2: {
Multi: true,
},
})
Inherit from BasicStatesDef via the generator
$ am-gen --name MyMach \
--states State1,State2 \
--inherit basic
Piping
A “pipe” binds a transition handler to a source state-machine and mutates the target state-machine. Only final handlers are subject to piping and the resulting mutation won’t block the source transition (it will be queued instead). The target state-machine can reject the mutation, as a part of the negotiation phase.
Pipes work only within the same Golang process, but when combined with /pkg/rpc, we can effectively pipe
states over the network. Some packages export predefined pipes for their state machines (eg /pkg/rpc and
/pkg/node).
Installation Pipes
import ampipe "github.com/pancsta/asyncmachine-go/pkg/states/pipes"
Predefined Pipes
These predefined functions should cover most of the use cases:
BindErrBindReadyBindConnectedBindBindManyBindAny
Using Pipes
// pipe RpcReady to RpcReady from rpcClient.Mach to myMach
ampipe.BindReady(rpcClient.Mach, myMach, "RpcReady", "")
// pipe Foo to FooActive and FooInactive from myMach1 to myMach2
ampipe.Bind(myMach1, myMach2, "Foo", "FooActive", "FooInactive")
Piping Manually
var source *am.Machine
var target *am.Machine
h := &struct {
ReadyState am.HandlerFinal
ReadyEnd am.HandlerFinal
}{
ReadyState: ampipe.Add(source, target, "Ready", "RpcReady"),
ReadyEnd: ampipe.Remove(source, target, "Ready", "RpcReady"),
}
source.BindHandlers(h)
Extending States
The purpose of this package is to share reusable schemas, but inheriting a full schema isn’t enough. States can also be
extended on relations-level using helpers from states_utils.go (generated), although sometimes it’s better to override
a state (eg Ready).
import (
am "github.com/pancsta/asyncmachine-go/pkg/machine"
"github.com/pancsta/asyncmachine-go/pkg/states"
ampipe "github.com/pancsta/asyncmachine-go/pkg/states/pipes"
)
// ...
MyMychStruct = am.Schema{
// inject Client states into Connected
"Connected": StateAdd(
states.ConnectedStruct[states.ConnectedStates.Connected],
am.State{
Remove: S{"RetryingConn"},
Add: S{"Handshaking"},
}),
}
// see state_utils.go
Documentation
Status
Testing, semantically versioned.
