Event-driven Finite State Machine
This is a helper module for implementing finite state machines that react to events on an event bus.
The event bus is provided externally and must have implemented the following methods:
emit(event, arg)
on(event, handler)
with handle:(arg) => {...}
removeListener(event, handler)
For further details have a look into the documentation of native events provided by NodeJS.
Example
A little guessing game:
// Input event busconst rl = ;const input = rl; // Output event busconst EventEmitter = ;const output = ;output;output; // FSMconst EDFSM = ;;
API
Creating a new FSM factory:
const EDFSM = ;const edfsmFactory = ;
Creates a new FSM factory with given opts
:
fsmName
: Human-readable name describing the FSM. Used for logging.inputs
: Object containing multiple input busses. Theiron()
methods are accessible by callingi[key](event, () => {...})
inside the states.outputs
: Object containing multiple output busses. Events are emitted by callingo[key](event, () => {...})
inside the states.input
: Instance of the main input event bus. Can be used instead of theinputs
option. Event listeners are installed by callingi(event, () => {...})
inside the state.output
: Instance of the output event bus. Can be used instead of theoutputs
option. Can be the same instance asinput
. Events can be emitted by callingo(event, arg)
inside the states.firstState
: The name of the entry state. If not given, the first state will become the entry state.log
: Object containing logging callbacks. All callbacks have this interface:(msg, obj) => {}
, whereasmsg
is the log message andobj
contains further machine-readable details.debug
: Message about FMS construction, destruction and state changeswarn
: Warnings about unconsumed output messageserror
: Error log.
States are defined and attached like this:
edfsmFactory;
name
: The state's name for addressing it.ctx
: Context object of the current instance of the FSM. You can store any kind of information in there.i
: This interface is used if the FSM optioninput
is set. Helper method for setting up listeners to input events:i(event, (arg) => {...})
. The listener will be removed automatically when the state is left. You do not have to take care about that.i[key]
: This interface is used if the FSM optioninputs
is set. Helper method for setting up listeners to input events:i[key](event, (arg) => {...})
.key
is the respective input item. The listener will be removed automatically when the state is left. You do not have to take care about that.o
: This interface is used if the FSM optionoutput
is set. Helper method for emitting events on the output event bus:o(event, arg)
.o[key]
: This interface is used if the FSM optionoutputs
is set. Helper method for emitting events on the output event bus:o[key](event, arg)
.key
is the respective output item.next
: Method to be called if the current state shall be left:next(state)
. For transitioning to another state, put the state's name in the argument. If you want to destroy the current FSM instance, statenull
or an instance ofError
as the first argument.next.timeout
: Likenext
but delayed bytimeout
milliseconds:next.timeout(timeout, state)
. If the current state is left before the timeout elapsed, it will be cleared automatically. The timeout can be retriggered by calling this method again.
You can define a special state that will be entered before the FSM instance gets destroyed:
edfsmFactory;
In addition to the handler's arguments as they are described above, these arugments are handed over to the handler:
err
: Will contain the error if thenext
call in the previous state contained an error. Otherwise this isundefined
.lastState
: The name of the previous state.
Instances can be created by calling:
edfsmFactory;
ctx
: Object containing the context that the state handlers will access and use for storing instance-related information.onEnd
: Callback that will be called once the FSM instance has been destroyed.