DSL to comfortably define finite state machines for node.js
Want to see pretty graphs? Log in now!
npm install fluent-fsm
|6||downloads in the last week|
|24||downloads in the last month|
|Last Published By|
|Version||0.1.6 last updated 9 months ago|
|Dependencies (9)||express, group-by, moment, optimist, stringsim, underscore, underscore.string, socket.io, socket.io-client|
Here are the main features:
- Express compact state transitions with regular expressions!
- Debug your FSM on line with a mini-server (powered by
socketio) with D3js rendering.
You can see above a live demonstration of what you'll see when you connect to your fsm with a browser [^1]. And yes, you can attach to different FSMs simultaneously by using different ports.
Note: The fsm runs server-side, on node! This is not compatible with browsers at the moment.
To install, use
npm install fluent-fsm
Import the prototype in your program:
fsm = require('fsmexpress').fsm;
Create fsm and instantiate states
Create a finite state machine:
fs = new fsm()
Define states (
fs.define-as-states([ 'II' 'SI' 'PI' 'OI' 'IS' 'SS' 'PS' 'OS' 'IP' 'SP' 'PP' 'OP' 'IC' 'SC' 'PC' 'OC' 'error' ]) fs.define-as-initial('II')
Define a transition (optionally using a regular expression) from all states beginning with
I excluding some states (
IC) on a specific event (
an_event) and register function
action_to_trigger to be triggered contextually:
fs.add_rule from: 'I(.+)' excluding: 'IP IC' at: 'an_event' jumpTo: 'S-' execute: action_to_trigger
Note: the target state
S- is a state beginning with
S and ending with the matched text in
(.+) in the
from expression. So the above statement will generate only two different state transitions (because
'IP' 'IC' are not allowed
II -> SI IS -> SS
Unfold and optimize
After the state transitions have been setup, invoke
unfold to generate actual state transition rules:
Prune states that are not reachable:
Linking to an event emitter
To register an event emitter:
the_event_emitter should be a Node
Emitter object. The FSM registers its own listeners to enable state transition internal methods. Practically, let's assume that we have the following event emitter:
class tester extends EventEmitter run_op: ~> @emit 'anEvent' setTimeout(@run_tr, 300) run_tr: ~> @emit 'anEvent2' setTimeout(@run_fl, 300) run_fl: ~> @emit 'anotherEvent' setTimeout(@run_op, 300)
Let's register it and start the finite state machine:
tst = new tester() # Register event emitter and start the fsm fs.registerEventEmitter(tst) fs.start()
You can have a visual representation of the FSM that is served through a small web service (screenshot above):
red = "#9d261d" gre = "#46a546" blu = "#049cdb" # GUI related stuff.. fs.prepare-emit() fs.mark transition: '.+', with-color: 'lightgrey' fs.mark transition: '.+Open', with-color: "#gre" fs.mark transition: '.+Close', with-dashed-color: "#gre" fs.mark transition: 'failed.+', with-color: "indianred" fs.mark state: '.+', with-color: 'lightgrey' fs.mark state: 'error', with-color: 'indianred' fs.mark state: fs.initial, with-color: "#gre" fs.mark state: fs.final, with-color: "lightsteelblue" console.log fs.data fs.serve(6970, 'my fsm')
You can see live state transitions (wherever the fsm is, even remotely, provided that the port can be accessed).
[^1]: Event generation is simulated in this page.