seneca-sm
v1.0.1
Published
A state machine implementation plugin for Seneca
Downloads
4
Readme
State-machine plugin for Seneca
seneca-sm
Seneca State-Machine Plugin
This plugin stores and execute a state-machine context. The state machine have two main concepts: States and Commands. At each moment the state machine can be in one single state. In each state there can be defined one or more commands, result of these commands changing the state of the state machine.
Seneca State-Machine Plugin
Install
npm install seneca-sm
Usage
Initialisation
seneca.act( 'role: sm, create: instance', config, function( err, context ) {
})
Executing commands
seneca.act( 'role: sm, cmd: command-name', {sm_name: sm_name, ....}, function( err, data ) {
})
where:
- sm-name is the name of the state-machine as it was set in the configuration
- command-name the command to be executed for current state. Should be defined in the configuration.
- some_data optional JSON containing additional-data for command
Retrieving state machine context
seneca.act( 'role: sm, get: context', {sm_name: sm_name} function( err, context ) {
})
Set data in state-machine context
This command will set some data in the state machine context. This data will be sent to all commands executed on the state machine.
seneca.act( 'role: sm, set: data', {sm_name: sm_name, ....}, function( err, context ) {
})
Load a specific state-machine context
This command can be called after a sm is initialized to change its internal state from the default state to a specific one
seneca.act( 'role: sm, load: state', { sm_name: sm_name, state: state_to_load}, function( err, context ) {
})
Remove state-machine context
This command will close the state machine. This state machine cannot be used anymore. A new state machine with same name can be started.
seneca.act( 'role: sm, drop: instance', {sm_name: sm_name}, function( err, context ) {
})
Configuration
Configuration structure for state machine is:
- validate if configuration will be strict validated when instance is created.
- name name of the state machine - it will be used as role configuration when state machine actions will be called
- states object defining the states and commands. Key is the state and value an object with
- defaults default behavior for this state - TBD
- initState default state for state machine. One single state should have this parameter true
- events allows adding event hooks trigered when the state changes
- before called before the state execution - can be the child of the root states object or child of a state
- pattern seneca pattern defining the action to be called before the state execution
- after called after a state is executed - can be the child of the root states object or child of a state
- pattern seneca pattern defining the action to be called after the state execution
- before called before the state execution - can be the child of the root states object or child of a state
- commands array with all commands for current state
- key command to be executed for this state
- pattern seneca pattern defining the action to be called to execute the state
- next define transitions based on seneca action result
- err define next status in case of error - this is a String
- success value can be:
- String in this case defines next status in case that Seneca action defined by pattern returns success data
- Array of objects with following structure:
- schema Parambulator schema to be applied on callback data
- state next state in case Parambulator schema matches data
Example
The following simple state machine will be used as example.
The configuration to be used for this state machine is:
{
validate: true,
name: 'sm1',
states: {
events: {
before: {
pattern: "role: 'transport', execute: 'before_any_state_change'"
},
after: {
pattern: "role: 'transport', execute: 'after_any_state_change'"
}
},
"INIT": {
initState: true,
defaults: {
next: {
error: "INIT"
}
},
commands: {
execute: {
pattern: "role: 'transport', execute: 'connect'",
next: {
success: "NOT_CONFIGURED"
}
},
disconnect: {
pattern: "role: 'transport', execute: 'disconnect'",
next: {
success: "INIT"
}
}
}
},
"NOT_CONFIGURED": {
commands: {
execute: {
pattern: "role: 'transport', send: 'config'",
next: {
error: "DISCONNECTED",
success: "CONNECTED"
}
},
disconnect: {
pattern: "role: 'transport', execute: 'disconnect'",
next: {
error: "INIT",
success: "DISCONNECTED"
}
}
},
events: {
before: {
pattern: "role: 'transport', execute: 'before_notconfigured_state_change'"
},
after: {
pattern: "role: 'transport', execute: 'after_notconfigured_state_change'"
}
}
},
"CONNECTED": {
commands: {
execute: {
pattern: "role: 'transport', send: 'some_command'",
next: {
error: "DISCONNECTED",
success: "CONNECTED"
}
},
disconnect: {
pattern: "role: 'transport', execute: 'disconnect'",
next: {
error: "INIT",
success: "DISCONNECTED"
}
}
}
},
"DISCONNECTED": {
commands: {
execute: {
cmd: '',
pattern: "role: 'transport', execute: 'cleanup'",
next: {
error: "INIT",
success: "INIT"
}
},
disconnect: {
pattern: "role: 'transport', execute: 'disconnect'",
next: {
error: "INIT",
success: "DISCONNECTED"
}
}
}
}
}
}
Test
npm test
Example
For an example of state machine implementation please check this repository State Machine Example
Contributing
We encourage participation. If you feel you can help in any way, be it with examples, extra testing, or new features please get in touch.