Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mooremachine

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mooremachine - npm Package Compare versions

Comparing version 1.4.2 to 2.0.0

261

lib/fsm.js

@@ -9,2 +9,96 @@ // Copyright 2015 Joyent, Inc.

function FSMStateHandle(fsm, state, link) {
this.fsh_fsm = fsm;
this.fsh_link = link;
this.fsh_state = state;
this.fsh_valid = true;
this.fsh_listeners = [];
this.fsh_timeouts = [];
this.fsh_intervals = [];
this.fsh_immediates = [];
this.fsh_validTransitions = undefined;
this.fsh_nextState = undefined;
}
FSMStateHandle.prototype.validTransitions = function (states) {
assert.arrayOfString(states, 'states');
this.fsh_validTransitions = states;
};
FSMStateHandle.prototype.gotoState = function (state) {
if (!this.fsh_valid) {
throw (new Error('FSM attempted to leave state ' +
this.fsh_state + ' towards ' + state + ' via a handle ' +
'that was already used to enter state ' +
this.fsh_nextState));
}
if (this.fsh_validTransitions !== undefined) {
if (this.fsh_validTransitions.indexOf(state) === -1) {
throw (new Error('Invalid FSM transition: ' +
this.fsh_state + ' => ' + state));
}
}
this.fsh_valid = false;
this.fsh_nextState = state;
return (this.fsh_fsm._gotoState(state));
};
FSMStateHandle.prototype.disconnect = function () {
var ls = this.fsh_listeners;
for (var i = 0; i < ls.length; ++i) {
ls[i][0].removeListener(ls[i][1], ls[i][2]);
}
var ts = this.fsh_timeouts;
for (i = 0; i < ts.length; ++i) {
clearTimeout(ts[i]);
}
var is = this.fsh_intervals;
for (i = 0; i < is.length; ++i) {
clearInterval(is[i]);
}
var ims = this.fsh_immediates;
for (i = 0; i < ims.length; ++i) {
clearImmediate(ims[i]);
}
this.fsh_listeners = [];
this.fsh_timeouts = [];
this.fsh_intervals = [];
this.fsh_immediates = [];
if (this.fsh_link !== undefined)
this.fsh_link.disconnect();
};
FSMStateHandle.prototype.on = function (obj, evt, cb) {
obj.on(evt, cb);
this.fsh_listeners.push([obj, evt, cb]);
};
FSMStateHandle.prototype.interval = function (interval, cb) {
var timer = setInterval(cb, interval);
this.fsh_intervals.push(timer);
return (timer);
};
FSMStateHandle.prototype.timeout = function (timeout, cb) {
var timer = setTimeout(cb, timeout);
this.fsh_timeouts.push(timer);
return (timer);
};
FSMStateHandle.prototype.immediate = function (cb) {
var timer = setImmediate(cb);
this.fsh_immediates.push(timer);
return (timer);
};
FSMStateHandle.prototype.callback = function (cb) {
var s = this;
return (function () {
var args = arguments;
if (s.fsh_valid)
return (cb.apply(this, args));
return (undefined);
});
};
/*

@@ -18,11 +112,11 @@ * fsm.js: a small library for Moore finite state machines.

*
* The state function takes up to 4 arguments -- on, once, timeout and onState.
* These are used in order to gang together callbacks that result in a state
* transition out of this state. The "on" and "once" functions act on an
* EventEmitter, "timeout" is a wrapper around setTimeout, and "onState" allows
* you to make your FSM transition when another FSM reaches a given state. The
* idea behind using these is that all callbacks you register in this way will
* automatically get de-registered (and any timers cleaned up) as soon as the
* FSM leaves its current state. This way we avoid any stale callbacks from a
* previous state being called with new data.
* The state function takes one argument -- the state handle. This is used in
* order to gang together callbacks that result in a state transition out of
* this state. The "on" function acts on an EventEmitter, "timeout" is a
* wrapper around setTimeout. The state handle also contains the "gotoState"
* method, which is used to transition to a new state. The idea behind using
* the on/timeout/etc functions is that all callbacks you register in this way
* will automatically get de-registered (and any timers cleaned up) as soon as
* the FSM leaves its current state. This way we avoid any stale callbacks
* from a previous state being called with new data.
*

@@ -35,13 +129,11 @@ * FSM also supports "sub-states", which share their callbacks with the rest of

assert.string(defState, 'default state');
this.fsm_stListeners = [];
this.fsm_stTimers = [];
this.fsm_history = [];
this.fsm_handle = undefined;
this.fsm_inTransition = false;
this.fsm_nextState = undefined;
this.fsm_validTransitions = undefined;
if (this.fsm_allStateEvents === undefined)
this.fsm_allStateEvents = [];
this.fsm_state = undefined;
this.fsm_toEmit = [];
EventEmitter.call(this);
this.gotoState(defState);
this._gotoState(defState);
}

@@ -59,7 +151,2 @@ util.inherits(FSM, EventEmitter);

FSM.prototype.validTransitions = function (states) {
assert.arrayOfString(states, 'states');
this.fsm_validTransitions = states;
};
FSM.prototype.allStateEvent = function (evt) {

@@ -72,29 +159,4 @@ assert.string(evt, 'event');

/*
* Calls a callback when this FSM reaches a given state. This is for use by
* external non-FSM things -- if an FSM wants to listen to another FSM, it
* should use sOnState (or the onState argument to a state func).
*/
FSM.prototype.onState = function (state, cb) {
assert.string(state, 'state');
assert.func(cb, 'callback');
if (this.fsm_state === state ||
this.fsm_state.indexOf(state + '.') === 0) {
cb();
return;
}
var self = this;
function stateCb(newState) {
if (newState !== state &&
newState.indexOf(state + '.') !== 0) {
self.once('stateChanged', stateCb);
return;
}
cb();
}
self.once('stateChanged', stateCb);
};
/* Transition the FSM to a new state. */
FSM.prototype.gotoState = function (state) {
FSM.prototype._gotoState = function (state) {
assert.string(state, 'state');

@@ -108,9 +170,2 @@

if (this.fsm_validTransitions !== undefined) {
if (this.fsm_validTransitions.indexOf(state) === -1) {
throw (new Error('Invalid FSM transition: ' +
this.fsm_state + ' => ' + state));
}
}
/*

@@ -122,13 +177,5 @@ * If we're changing to a state that is not a sub-state of this one,

var newParts = state.split('.');
if (parts[0] !== newParts[0]) {
var ls = this.fsm_stListeners;
for (var i = 0; i < ls.length; ++i) {
ls[i][0].removeListener(ls[i][1], ls[i][2]);
}
var ts = this.fsm_stTimers;
for (i = 0; i < ts.length; ++i) {
clearTimeout(ts[i]);
}
this.fsm_stTimers = [];
this.fsm_stListeners = [];
if (parts[0] !== newParts[0] && this.fsm_handle !== undefined) {
this.fsm_handle.disconnect();
this.fsm_handle = undefined;
}

@@ -146,2 +193,4 @@

this.fsm_handle = new FSMStateHandle(this, state, this.fsm_handle);
this.fsm_history.push(state);

@@ -151,7 +200,4 @@ if (this.fsm_history.length >= 8)

this.fsm_validTransitions = undefined;
this.fsm_inTransition = true;
f.call(this, this.sOn.bind(this), this.sOnce.bind(this),
this.sTimeout.bind(this), this.sOnState.bind(this));
f.call(this, this.fsm_handle);
this.fsm_inTransition = false;

@@ -169,3 +215,12 @@

this.emit('stateChanged', state);
this.fsm_toEmit.push(state);
if (this.fsm_toEmit.length === 1) {
setImmediate(function () {
var ss = self.fsm_toEmit;
self.fsm_toEmit = [];
ss.forEach(function (s) {
self.emit('stateChanged', s);
});
});
}

@@ -175,72 +230,4 @@ var next = this.fsm_nextState;

this.fsm_nextState = undefined;
this.gotoState(next);
this._gotoState(next);
}
};
/*
* These are the per-state event registration functions, which are bound and
* then passed as the args to state funcs.
*/
FSM.prototype.sOn = function (obj, evt, cb) {
obj.on(evt, cb);
this.fsm_stListeners.push([obj, evt, cb]);
};
FSM.prototype.sOnce = function (obj, evt, cb) {
obj.once(evt, cb);
this.fsm_stListeners.push([obj, evt, cb]);
};
FSM.prototype.sTimeout = function (timeout, cb) {
var timer = setTimeout(cb, timeout);
this.fsm_stTimers.push(timer);
return (timer);
};
FSM.prototype.sOnState = function (obj, state, cb) {
assert.string(state, 'state');
assert.func(cb, 'callback');
if (obj.fsm_state === state ||
obj.fsm_state.indexOf(state + '.') === 0) {
cb();
return;
}
var self = this;
function stateCb(newState) {
if (newState !== state &&
newState.indexOf(state + '.') !== 0) {
self.sOnce(obj, 'stateChanged', stateCb);
return;
}
cb();
}
this.sOnce(obj, 'stateChanged', stateCb);
};
/*
* Wraps a conventional node callback async function up into an EventEmitter so
* that it can be used as a state transition trigger.
*/
FSM.wrap = function _fsmWrap(fun) {
function fsm_cb_wrapper() {
var args = Array.prototype.slice.call(arguments);
var eve = new EventEmitter();
var self = this;
var cb = function () {
var resArgs = Array.prototype.slice.call(arguments);
var err = resArgs.shift();
if (err) {
eve.emit('error', err);
} else {
resArgs.unshift('return');
eve.emit.apply(eve, resArgs);
}
};
args.push(cb);
eve.run = function () {
fun.apply(self, args);
};
return (eve);
}
return (fsm_cb_wrapper);
};
{
"name": "mooremachine",
"version": "1.4.2",
"version": "2.0.0",
"description": "Moore finite state machines",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

@@ -81,22 +81,21 @@ mooremachine

ThingFSM.prototype.state_stopped = function (on) {
var self = this;
on(this, 'startAsserted', function () {
self.gotoState('connecting');
ThingFSM.prototype.state_stopped = function (S) {
S.on(this, 'startAsserted', function () {
S.gotoState('connecting');
});
};
ThingFSM.prototype.state_connecting = function (on) {
ThingFSM.prototype.state_connecting = function (S) {
var self = this;
this.tf_sock = mod_net.connect(...);
on(this.tf_sock, 'connect', function () {
self.gotoState('connected');
S.on(this.tf_sock, 'connect', function () {
S.gotoState('connected');
});
on(this.tf_sock, 'error', function (err) {
S.on(this.tf_sock, 'error', function (err) {
self.tf_lastError = err;
self.gotoState('error');
S.gotoState('error');
});
};
ThingFSM.prototype.state_error = function (on, once, timeout) {
ThingFSM.prototype.state_error = function (S) {
var self = this;

@@ -109,4 +108,4 @@ if (this.tf_sock !== undefined)

/* Retry the connection in 5 seconds */
timeout(5000, function () {
self.gotoState('connecting');
S.timeout(5000, function () {
S.gotoState('connecting');
});

@@ -137,3 +136,3 @@ };

### `mod_mooremachine#state_name(on, once, timeout, onState)`
### `FSM#state_name(stateHandle)`

@@ -144,32 +143,23 @@ State entry functions. These run exactly once, at entry to the new state. They

The `on`, `once`, `timeout` and `onState` arguments are functions that should be
used to set up events that can lead to a state transition. The `on` function is
like `EventEmitter#on`, but any handlers set up with it will be automatically
torn down as soon as the FSM leaves its current state. Similar for `once` and
`timeout`. The `onState` function is used in place of calling
`mod_mooremachine#onState` on another FSM.
The `stateHandle` argument is a handle giving access to functions that should be
used to set up events that can lead to a state transition. It provides
replacements for `EventEmitter#on`, `setTimeout`, and other mechanisms for async
event handling, which are automatically torn down as soon as the FSM leaves its
current state. This prevents erroneous state transitions from a dangling
callback left behind by a previous state.
Parameters:
- `on`: Function `(emitter, event, cb)`, sets up an event callback like
`EventEmitter#on`. Parameters:
- `emitter`: an EventEmitter
- `event`: a String, name of the event
- `cb`: a Function, callback to run when the event happens
- `once`: Function `(emitter, event, cb)`, like `on` but only runs once
- `timeout`: Function `(timeout, cb)`, like `setTimeout()`. Parameters:
- `timeout`: Number, milliseconds until the callback runs
- `cb`: a Function, callback to run
- `onState`: Function `(fsm, state, cb)`
It is permissible to call `stateHandle.gotoState()` immediately within the
`state_` function.
### `mod_mooremachine#validTransitions(possibleStates)`
Caution should be used when emitting events or making synchronous calls within a
`state_` function -- if it is possible for the handler of the event or callee to
call back into the FSM or emit an event itself that may cause the FSM to
transition, then the results of this occurring synchronously within the state
entry function may be undesirable. It is highly recommended to emit any events
within a `setImmediate()` callback.
Should be called from a state entry function. Sets the list of valid transitions
that are possible out of the current state. Any attempt to transition the FSM
out of the current state to a state not on this list (using `gotoState()`) will
throw an error.
Parameters:
- `possibleStates`: Array of String, names of valid states
- `stateHandle`, an Object, instance of `mod_mooremachine.FSMStateHandle`
### `mod_mooremachine#allStateEvent(name)`
### `FSM#allStateEvent(name)`

@@ -184,7 +174,7 @@ Adds an "all-state event". Should be called in the constructor for an FSM

### `mod_mooremachine#getState()`
### `FSM#getState()`
Returns a String, full current state of the FSM (including sub-state).
### `mod_mooremachine#isInState(state)`
### `FSM#isInState(state)`

@@ -198,24 +188,42 @@ Tests whether the FSM is in the given state, or any sub-state of it.

### `mod_mooremachine#onState(state, cb)`
## State handles
Runs a callback on the next time that the FSM enters a given state or any
sub-state of it.
### `FSMStateHandle#gotoState(state)`
Parameters:
- `state`: String, state to test for
- `cb`: Function `(newState)`
Transitions the FSM into the given new state. Can only be called once per state
handle.
### `mod_mooremachine#gotoState(state)`
### `FSMStateHandle#on(emitter, event, cb)`
Causes the FSM to enter the given new state.
Works like `EventEmitter#on`: equivalent to `emitter.on(event, cb)` but
registers the callback for removal as soon as the FSM moves out of the current
state.
### `FSMStateHandle#timeout(timeoutMs, cb)`
Equivalent to `setTimeout(cb, timeoutMs)`, but registers the timer for clearing
as soon as the FSM moves out of the current state.
Returns: the timer handle.
### `FSMStateHandle#interval(intervalMs, cb)`
Equivalent to `setInterval(cb, intervalMs)`, but registers the timer for
clearing as soon as the FSM moves out of the current state.
### `FSMStateHandle#validTransitions(possibleStates)`
Should be called from a state entry function. Sets the list of valid transitions
that are possible out of the current state. Any attempt to transition the FSM
out of the current state to a state not on this list (using `gotoState()`) will
throw an error.
Parameters:
- `state`: String, state to enter
- `possibleStates`: Array of String, names of valid states
### `mod_mooremachine.FSM.wrap(fun)`
### `FSMStateHandle#gotoState(state)`
Wraps a conventional node callback function up into an EventEmitter, to make
life a little easier with `on()`.
Causes the FSM to enter the given new state.
Parameters:
- `fun`: Function `(cb)`
- `state`: String, state to enter

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc