Skip to content

Repository files navigation

librefsm

A lightweight, hierarchical finite state machine library for Go.

Part of the Librescoot open-source platform.

Overview

librefsm is a flexible FSM library designed for building robust state machines with support for hierarchical states, guards, timers, and conditional transitions. Originally developed for the Librescoot project to manage vehicle state logic.

Features

  • Hierarchical States: Organize states in parent-child relationships
  • Condition & Junction States: Automatic state transitions based on runtime conditions
  • Guards: Conditional transition execution
  • Timers: Declarative timeout support with automatic cleanup
  • Event Queue: Asynchronous and synchronous event processing
  • Type Safety: Strongly-typed state and event IDs
  • State Callbacks: Entry and exit actions for each state
  • Transition Actions: Execute code during state transitions

Installation

go get github.com/librescoot/librefsm

Quick Start

package main

import (
    "context"
    "github.com/librescoot/librefsm"
)

func main() {
    // Build state machine - string literals work directly
    def := librefsm.NewDefinition().
        State("off").
        State("on").
        Transition("off", "toggle", "on").
        Transition("on", "toggle", "off").
        Initial("off")

    // Create and start machine
    m, _ := def.Build()
    m.Start(context.Background())

    // Send events
    m.Send(librefsm.Event{ID: "toggle"}) // off -> on
    m.Send(librefsm.Event{ID: "toggle"}) // on -> off

    m.Stop()
}

Advanced Example

With callbacks, typed constants, and timers:

package main

import (
    "context"
    "fmt"
    "time"

    "github.com/librescoot/librefsm"
)

// Define typed constants for compile-time safety
const (
    StateOff  librefsm.StateID = "off"
    StateOn   librefsm.StateID = "on"
    EvToggle  librefsm.EventID = "toggle"
    EvTimeout librefsm.EventID = "timeout"
)

func main() {
    def := librefsm.NewDefinition().
        State(StateOff,
            librefsm.WithOnEnter(func(c *librefsm.Context) error {
                fmt.Println("Light off")
                return nil
            }),
        ).
        State(StateOn,
            librefsm.WithTimeout(5*time.Second, EvTimeout),
            librefsm.WithOnEnter(func(c *librefsm.Context) error {
                fmt.Println("Light on (auto-off in 5s)")
                return nil
            }),
        ).
        Transition(StateOff, EvToggle, StateOn).
        Transition(StateOn, EvToggle, StateOff).
        Transition(StateOn, EvTimeout, StateOff).
        Initial(StateOff)

    m, _ := def.Build()
    m.Start(context.Background())

    m.SendSync(librefsm.Event{ID: EvToggle}) // off -> on
    time.Sleep(6 * time.Second)               // wait for timeout -> off

    m.Stop()
}

Simplified Timeout Transitions

Use WithTimeoutTransition to automatically create the timeout transition without manually defining the event:

def := librefsm.NewDefinition().
    State(StateOff,
        librefsm.WithOnEnter(func(c *librefsm.Context) error {
            fmt.Println("Light off")
            return nil
        }),
    ).
    State(StateOn,
        // Automatically transitions to StateOff after 5 seconds
        librefsm.WithTimeoutTransition(5*time.Second, StateOff),
        librefsm.WithOnEnter(func(c *librefsm.Context) error {
            fmt.Println("Light on (auto-off in 5s)")
            return nil
        }),
    ).
    Transition(StateOff, EvToggle, StateOn).
    Transition(StateOn, EvToggle, StateOff).
    // No need to manually define the timeout transition
    Initial(StateOff)

Documentation

See example_test.go for comprehensive examples including:

  • Traffic light FSM with timers
  • Vehicle state machine with hierarchical states and guards
  • Condition and junction state usage

Testing

go test -v

License

This project is dual-licensed. The source code is available under the GNU Affero General Public License v3.0. The maintainers reserve the right to grant separate licenses for commercial distribution; please contact the maintainers to discuss commercial licensing.

AGPL v3

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


Part of the Librescoot project

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages