All Projects → dyrkin → fsm

dyrkin / fsm

Licence: MIT license
Finite State Machine for Go inspired by Akka FSM

Programming Languages

go
31211 projects - #10 most used programming language

Projects that are alternatives of or similar to fsm

Automata
A Python library for simulating finite automata, pushdown automata, and Turing machines
Stars: ✭ 121 (+105.08%)
Mutual labels:  fsm, finite-state-machine
use-state-machine
Use Finite State Machines with React Hooks
Stars: ✭ 28 (-52.54%)
Mutual labels:  fsm, finite-state-machine
Statelin
A finite state machine for Kotlin and Android
Stars: ✭ 134 (+127.12%)
Mutual labels:  fsm, finite-state-machine
Afsm
C++14 Finite State Machine library
Stars: ✭ 113 (+91.53%)
Mutual labels:  fsm, finite-state-machine
as fsm
A finite state machine implementation for elixir
Stars: ✭ 14 (-76.27%)
Mutual labels:  fsm, finite-state-machine
Microwf
A simple finite state machine (FSM) with workflow character where you define your workflows in code.
Stars: ✭ 122 (+106.78%)
Mutual labels:  fsm, finite-state-machine
pastafarian
A tiny event-based finite state machine
Stars: ✭ 20 (-66.1%)
Mutual labels:  fsm, finite-state-machine
Jstate
Advanced state machines in Java.
Stars: ✭ 84 (+42.37%)
Mutual labels:  fsm, finite-state-machine
raider
OWASP Raider: a novel framework for manipulating the HTTP processes of persistent sessions
Stars: ✭ 88 (+49.15%)
Mutual labels:  fsm, finite-state-machine
Fluent State Machine
Fluent API for creating state machines in C#
Stars: ✭ 195 (+230.51%)
Mutual labels:  fsm, finite-state-machine
Alexafsm
With alexafsm, developers can model dialog agents with first-class concepts such as states, attributes, transition, and actions. alexafsm also provides visualization and other tools to help understand, test, debug, and maintain complex FSM conversations.
Stars: ✭ 103 (+74.58%)
Mutual labels:  fsm, finite-state-machine
FiniteStateMachine
This project is a finite state machine designed to be used in games.
Stars: ✭ 45 (-23.73%)
Mutual labels:  fsm, finite-state-machine
Finity
A finite state machine library for Node.js and the browser with a friendly configuration DSL.
Stars: ✭ 88 (+49.15%)
Mutual labels:  fsm, finite-state-machine
stateless
Finite State Machine porting from Stateless C#
Stars: ✭ 25 (-57.63%)
Mutual labels:  fsm, finite-state-machine
Fsm
Finite State Machine for Go
Stars: ✭ 1,269 (+2050.85%)
Mutual labels:  fsm, finite-state-machine
Django Fsm
Django friendly finite state machine support
Stars: ✭ 1,898 (+3116.95%)
Mutual labels:  fsm, finite-state-machine
Stateless4j
Lightweight Java State Machine
Stars: ✭ 658 (+1015.25%)
Mutual labels:  fsm, finite-state-machine
Floatsidebar.js
Lightweight (2kb gzipped), zero-dependency javascript library for making float sidebars based on the finite state machine
Stars: ✭ 56 (-5.08%)
Mutual labels:  fsm, finite-state-machine
Nanostate
🚦- Small Finite State Machines
Stars: ✭ 151 (+155.93%)
Mutual labels:  fsm, finite-state-machine
visual-automata
Visual Automata is a Python 3 library built as a wrapper for the Automata library to add more visualization features.
Stars: ✭ 55 (-6.78%)
Mutual labels:  fsm, finite-state-machine

Finite State Machine for Go

Overview

The FSM (Finite State Machine) is best described in the Erlang design principles

A FSM can be described as a set of relations of the form:

State(S) x Event(E) -> Actions (A), State(S')

These relations are interpreted as meaning:

If we are in state S and the event E occurs, we should perform the actions A and make a transition to the state S'.

A Simple Example

The code is taken from the article Akka Finite State Machine (FSM) and At Most Once Semantics

import (
	"fmt"
	"github.com/dyrkin/fsm"
)

//states
const InitialState = "Initial"
const AwaitFromState = "AwaitFrom"
const AwaitToState = "AwaitTo"
const DoneState = "Done"

//messages
type Transfer struct {
	source chan int
	target chan int
	amount int
}

const Done = "Done"
const Failed = "Failed"

//data
type WireTransferData struct {
	source chan int
	target chan int
	amount int
	client *fsm.FSM
}

func newWireTransfer(transferred chan bool) *fsm.FSM {
	wt := fsm.NewFSM()

	wt.StartWith(InitialState, nil)

	wt.When(InitialState)(
		func(event *fsm.Event) *fsm.NextState {
			transfer, transferOk := event.Message.(*Transfer)
			if transferOk && event.Data == nil {
				transfer.source <- transfer.amount
				return wt.Goto(AwaitFromState).With(
					&WireTransferData{transfer.source, transfer.target, transfer.amount, wt},
				)
			}
			return wt.DefaultHandler()(event)
		})

	wt.When(AwaitFromState)(
		func(event *fsm.Event) *fsm.NextState {
			data, dataOk := event.Data.(*WireTransferData)
			if dataOk {
				switch event.Message {
				case Done:
					data.target <- data.amount
					return wt.Goto(AwaitToState)
				case Failed:
					go data.client.Send(Failed)
					return wt.Stay()
				}
			}
			return wt.DefaultHandler()(event)
		})

	wt.When(AwaitToState)(
		func(event *fsm.Event) *fsm.NextState {
			data, dataOk := event.Data.(*WireTransferData)
			if dataOk {
				switch event.Message {
				case Done:
					transferred <- true
					return wt.Stay()
				case Failed:
					go data.client.Stay()
				}
			}
			return wt.DefaultHandler()(event)
		})
	return wt
}

The basic strategy is to instantiate FSM and specifying the possible states:

  • NewFSM() instantiates new FSM
  • StartWith() defines the initial state and initial data
  • Then there is one When(<state>)(<event handler fn>) declaration per state to be handled.

In this case will start in the Initial state with all values uninitialized. The only type of message which can be received in the Initial state is the initial Transfer request at which point a withdraw amount is sent to the source account and the state machine transitions to the AwaitFrom state.

When the system is in the AwaitFrom state the only two messages that can be received are Done or Failure from the source account. If the Done business acknowledgement is received the system will send a deposit amount to the target account and transition to the AwaitTo state.

When the system is in the AwaitTo state the only two messages that can be received are the Done or Failure from the target account.

To run the code above you can use the following code:

func main() {

	transferred := make(chan bool)

	wireTransfer := newWireTransfer(transferred)

	transfer := &Transfer{
		source: make(chan int),
		target: make(chan int),
		amount: 30,
	}

	source := func() {
		withdrawAmount := <-transfer.source
		fmt.Printf("Withdrawn from source account: %d\n", withdrawAmount)
		wireTransfer.Send(Done)
	}

	target := func() {
		topupAmount := <-transfer.target
		fmt.Printf("ToppedUp target account: %d\n", topupAmount)
		wireTransfer.Send(Done)
	}

	go source()
	go target()

	go wireTransfer.Send(transfer)

	if done := <-transferred; !done {
		panic("Something went wrong")
	}

	fmt.Println("DONE")
}

It will produce the following output:

Withdrawn from source account: 30
ToppedUp target account: 30
DONE

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].