Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions demo/apps/myapp/mystatemachine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package myapp

import (
"time"

"ergo.services/ergo/act"
"ergo.services/ergo/gen"
)

// Code Lock, inspired by https://www.erlang.org/doc/system/statem.html#example-revisited

type CodeLockData struct {
buttons []int
code [4]int
}

type CodeLock struct {
act.StateMachine[CodeLockData]
}

func factoryCodeLock() gen.ProcessBehavior {
return &CodeLock{}
}

type ButtonPress struct {
Button int
}

type Lock struct{}

type ResetCode struct{}

type CodeLength struct{}

func (order *CodeLock) Init(args ...any) (act.StateMachineSpec[CodeLockData], error) {
spec := act.NewStateMachineSpec(
// The initial state.
gen.Atom("locked"),

// The initial data.
act.WithData(CodeLockData{}),

// Register a function that is called on every state change.
act.WithStateEnterCallback(enterState),

// Register a handler for the ButtonPress message
act.WithStateMessageHandler(gen.Atom("open"), handleButtonPress),

// Register the handler for the Lock message.
act.WithStateMessageHandler(gen.Atom("open"), handleLock),

// Register the handler for the ResetCode message.
act.WithStateMessageHandler(gen.Atom("open"), handleResetCode),

// Register handler for retrieving the length of the code (it would
// be nice to have an all-state handler for this)
act.WithStateCallHandler(gen.Atom("open"), handleCodeLength),
act.WithStateCallHandler(gen.Atom("locked"), handleCodeLength),
)

return spec, nil
}

func enterState(oldState gen.Atom, newState gen.Atom, data CodeLockData, proc gen.Process) (gen.Atom, CodeLockData, error) {
proc.Log().Info("state changed to %s", newState)
return newState, data, nil
}

func handleButtonPress(state gen.Atom, data CodeLockData, msg ButtonPress, proc gen.Process) (gen.Atom, CodeLockData, []act.Action, error) {
data.buttons = append(data.buttons, msg.Button)
if len(data.buttons) < len(data.code) {
// code incomplete
// reset code after 30 seconds of inactivity
reset := act.MessageTimeout{
Duration: 30 * time.Second,
Message: ResetCode{},
}
return state, data, []act.Action{reset}, nil
}
for i, b := range data.buttons {
if b != data.code[i] {
// incorrect code
// reset buttons
data.buttons = nil
return state, data, nil, nil
}
}
// code is correct
// reset buttons
// automatically lock after 10 seconds
data.buttons = nil
lockAfter10Seconds := act.StateTimeout{
Duration: 10 * time.Second,
Message: Lock{},
}
return gen.Atom("open"), data, []act.Action{lockAfter10Seconds}, nil
}

func handleLock(state gen.Atom, data CodeLockData, msg Lock, proc gen.Process) (gen.Atom, CodeLockData, []act.Action, error) {
doLock()
data.buttons = nil
return gen.Atom("locked"), data, nil, nil
}

func handleResetCode(state gen.Atom, data CodeLockData, msg ResetCode, proc gen.Process) (gen.Atom, CodeLockData, []act.Action, error) {
data.buttons = nil
return state, data, nil, nil
}

func handleCodeLength(state gen.Atom, data CodeLockData, msg Lock, proc gen.Process) (gen.Atom, CodeLockData, int, []act.Action, error) {
doLock()
return state, data, len(data.code), nil, nil
}

func doLock() {
// interact with the hardware
}

func doUnlock() {
// interact with the hardware
}
23 changes: 12 additions & 11 deletions demo/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ module demo
go 1.21.6

require (
ergo.services/application v0.0.0-20240904055159-7f2e1a954c05
ergo.services/ergo v1.999.300
ergo.services/logger v0.0.0-20240904054830-18407beea628
)
ergo.services/application v0.0.0-20240904055159-7f2e1a954c05
ergo.services/ergo v1.999.300
ergo.services/logger v0.0.0-20240904054830-18407beea628
)

require (
ergo.services/meta v0.0.0-20240904054930-a97f6add8a78 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.14.0 // indirect
)
ergo.services/meta v0.0.0-20240904054930-a97f6add8a78 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.14.0 // indirect
)