~stacyharper/bonsai

A Finite State Machine structured as a tree that trigger commands

2941af7 Fatal must log wathever

17 days ago

2941af7 Fatal must log wathever

18 days ago

#Bonsai

#Definitions

Bonsai is a Finite State Machine structured as a tree. It has been designed to trigger commands when successive events and/or a precise context is accepted.

There is 4 kind of transition with specific acceptation rules :

  • event transition: The received event name match the transition one
  • context transition: The state context match the transition one
  • exec transition: The transition command is run and succeed
  • delay transition: The state wait for the delay transition duration. No other accepted event is received while waiting

The state will transition following every accepted transition. If there is no more available transition, the state go back to the initial position.

#Reference

[
  {
    "type": "event",
    "event_name": "event_foo"
  },
  {
    "type": "context",
    "contexts": {
      "toto": "titi",
      "tata": "tutu"
    }
  },
  {
    "type": "delay",
    "delay_duration": 500000000
  },
  {
    "type": "exec",
    "command": [
      "echo",
      "boooh"
    ]
  },
  {
    "type": "…",
    ,
    "transitions": [
      {
        
      },
      
    ]
  }
]
#Events arent recursives

Event input can trigger one or zero event transition. The state will then follow every accepted execs, contexts or delays transitions.

#Soft locks

It is easy to soft lock the state machine if you dont plan every situation. The following example show two trees. The first one can cause soft locks :

[
  {
    "type": "event",
    "event_name": "foo",
    "transitions": [
      {
        "type": "event",
        "event_name": "bar",
        "transitions": [
          {
            "type": "exec",
            "command": [
              "yataaa"
            ]
          }
        ]
      }
    ]
  }
]

If the state machine receive "foo" but no "bar" it stay locked at this position. Maybe this is intended, maybe not. Here how to handle this :

[
  {
    "type": "event",
    "event_name": "foo",
    "transitions": [
      {
        "type": "event",
        "event_name": "bar",
        "transitions": [
          {
            "type": "exec",
            "command": [
              "yataaa"
            ]
          }
        ]
      },
      {
        "type": "delay",
        "delay_duration": 500000000
      }
    ]
  }
]

Now if the state machine receive "foo" but no "bar" in less than 0.5 seconds, it return to initial position. This is how sxmo use bonsai to support complex keybinds.

#Exec transitions

Exec transition commands are run synchronously. If you dont care about the command status or use the command as final trigger and dont want to hold the bonsai daemon, you should use ["setsid", "-f", …].

#Hole transitions

Context transitions can be used as "holes" if you dont specify context values cause it will always match. This is particulary usefull just after exec transition that can fail. In that example, if the command fails the state machine go back to initial position. You can also add childs to the context transition to exec another command :

[
  {
    "type": "event",
    "event_name": "foo",
    "transitions": [
      {
        "type": "exec",
        "command": [
          "this",
          "command",
          "can",
          "fail"
        ]
      },
      {
        "type": "context"
      }
    ]
  }
]
#How delay are cancelled

If the state machine is waiting while receiving an event or a context update, it check if there is a accepting event or context transition available. Otherwise it continue to wait.

#Usage

$ bonsaid -t my/bonsaid/tree.json -D # as daemon
$ bonsaictl -e my_event_name # trigger event
$ bonsaictl -c foo=bar toto=titi # change context
$ bonsaictl -Q # quit the daemon

#Build

$ make check
$ make
$ doas make install