gestalt
Advanced tools
Comparing version 0.0.6 to 0.0.7
@@ -118,4 +118,9 @@ var gestalt = require('../lib/gestalt'); | ||
file.on('ready', on_load_config_file ); | ||
file.on('invalid', function(err, source) { console.log(err,source); }); | ||
file.on('state', function( state_change ) { | ||
if( state_change.state == 'invalid' ) { | ||
console.log( 'file invalid: ', state_change.data ); | ||
} else if ( state_change.state == 'ready' ) { | ||
on_load_config_file( state_change ); | ||
} | ||
}); | ||
@@ -122,0 +127,0 @@ config.addDefault( file ); |
@@ -7,10 +7,9 @@ var gestalt = require('../lib/gestalt'); | ||
var cf = new ConfigFile({ source: config_yaml, format: 'yaml' } ); | ||
cf.on('invalid', function(err,source) { | ||
console.log("Error in %s", source); | ||
console.log(err); | ||
cf.on('state', function(state_change ) { | ||
if( state_change.state == 'invalid' ) { | ||
console.log("Error loading", state_change.data); | ||
} else if ( state_change.state == 'ready' ) { | ||
console.log( cf.get('new:foo') ); | ||
} | ||
}); | ||
cf.on('ready', function() { | ||
console.log( cf.get('new:foo') ); | ||
cf.report(); | ||
}); |
@@ -112,2 +112,8 @@ var util = require('util'), | ||
p._hook_up_ = function( config ) { | ||
var self = this; | ||
config.on('change', function(change) {self._react_(config,change) } ); | ||
config.on('state', function(change_state) { self._state_react_(config, change_state) } ); | ||
this._state_react_( config ); | ||
} | ||
p.addDefault = function( config ) { | ||
@@ -117,11 +123,3 @@ // Add a configuration object to the low-priority end of the stack | ||
this._contents_.push( config ); | ||
var link = function(change) { | ||
self._react_( config, change ); | ||
}; | ||
self._linkage_.push(link); | ||
config.on('change', link ); | ||
config.on('ready', function() {self._check_ready_() } ); | ||
config.on('invalid', function() {self.state('invalid');} ); | ||
// TODO: fix this | ||
this.state( config.state() ); | ||
this._hook_up_( config ); | ||
config._touch_(); | ||
@@ -134,17 +132,18 @@ }; | ||
this._contents_.unshift( config ); | ||
var link = function(change) { | ||
self._react_( config, change ); | ||
}; | ||
this._linkage_.unshift( link ); | ||
config.on('change', link ); | ||
config.on('ready', function() {self._check_ready_() } ); | ||
config.on('invalid', function() {self.state('invalid');} ); | ||
// TODO: fix this | ||
this.state( config.state() ); | ||
this._hook_up_( config ); | ||
config._touch_(); | ||
}; | ||
p._check_ready_ = function() { | ||
if( _.all( this._contents_, function(config) { return config.state() === 'ready' } ) ) { | ||
this.state('ready'); | ||
p._state_react_ = function( config, change_state ) { | ||
var state = change_state ? change_state.state : config.state(); | ||
var data = change_state ? change_state.data : undefined; | ||
if( state == 'invalid' ) { | ||
this.state( state, data ); | ||
} else if (state == 'ready' ) { | ||
if( _.all( this._contents_, function(config) { return config.state() === 'ready' } ) ) { | ||
this.state('ready',data); | ||
} | ||
} else { | ||
this.state( 'not ready', data ); | ||
} | ||
@@ -151,0 +150,0 @@ } |
@@ -37,13 +37,13 @@ var EventEmitter = require('events').EventEmitter, | ||
p.state = function(state, extra) { | ||
if( state === 'ready') { | ||
this._state_ = 'ready'; | ||
this.emit('ready'); | ||
} else if(state === 'loading') { | ||
this._state_ = 'loading'; | ||
this.emit('loading'); | ||
} else if(state === 'invalid') { | ||
this.emit('invalid', extra); | ||
this._state_ = 'invalid'; | ||
p.state = function(state, data) { | ||
if( ! state ) { | ||
return this._state_; | ||
} | ||
if( this._state_ != state || state == 'invalid' ) { | ||
var so = { state: state, old_state: this._state, data: data }; | ||
this._state_ = state; | ||
this.emit('state', so); | ||
} | ||
return this._state_; | ||
@@ -228,6 +228,21 @@ } | ||
return { | ||
change: function(change) { self.emit('change', addPrefix(change,prefix) ); }, | ||
delete: function() {}, | ||
ready: function() { self.state('ready') }, | ||
invalid: function() { self.state('invalid') } | ||
change: function(change) { | ||
self.emit('change', addPrefix(change,prefix) ); | ||
}, | ||
state: function(state_change) { | ||
if( state_change.state == 'invalid' ) { | ||
this.state( 'invalid', state_change.data ); | ||
} else if (state_change.state == 'ready' ) { | ||
if( _.chain( this._values_) | ||
.values() | ||
.filter( function(x) { return x instanceof Configuration ;} ) | ||
.all( function(x) { return x.state() == 'ready' } ) | ||
.value() | ||
) { | ||
this.state('ready', state_change.data ); | ||
} | ||
} else { | ||
this.state( 'not ready', data ); | ||
} | ||
} | ||
}; | ||
@@ -234,0 +249,0 @@ } |
@@ -37,4 +37,3 @@ var fs = require('fs'), | ||
if( !_.isObject( object ) ) { | ||
self.state('invalid', self._source_ + " contains no data."); | ||
return; | ||
object = {}; | ||
} | ||
@@ -41,0 +40,0 @@ |
@@ -35,11 +35,7 @@ var parsers = require('./format').parsers, | ||
org.on('ready', function() { | ||
self.keys(); | ||
self.state('ready'); | ||
}); | ||
org.on( 'state', function( state_change ) { | ||
self.keys(); | ||
self.state( state_change.state, state_change.data ); | ||
}); | ||
org.on('invalid',function(err,source) { | ||
self.state('invalid', err); | ||
}); | ||
this.keys(); | ||
@@ -46,0 +42,0 @@ } |
@@ -52,8 +52,8 @@ | ||
if( state != ZooKeeper.ZOO_CONNECTED_STATE ) { | ||
self.emit('invalid', "lost zk connection", self._source_ ); | ||
self.state('invalid', "lost zk connection: " + self._source_ ); | ||
} else { | ||
self.emit('invalid', "found zk connection", self._source_ ); | ||
self.state('ready', "found zk connection"); | ||
} | ||
} else { | ||
console.log( "Unkown type: " + type ); | ||
self.state('invalid',"Unkown zookeper event type: " + type ); | ||
} | ||
@@ -74,9 +74,8 @@ }; | ||
} catch(e) { | ||
self.emit('invalid', e, self._source_ ); | ||
self.state('invalid', e + self._source_ ); | ||
return; | ||
} | ||
self.set('data', object, self._source_ + "&version=" + stat.version ); | ||
// Emit a 'loaded' event. | ||
self.emit('loaded'); | ||
// Tell the world we are ready | ||
self.state('ready'); | ||
} | ||
@@ -87,3 +86,3 @@ }; | ||
if(rc) { | ||
self.emit('invalid', error, self._source_); | ||
self.state('invalid', error + self._source_); | ||
return; | ||
@@ -133,3 +132,3 @@ } else { | ||
if(err) { | ||
self.emit('invalid', err, self._soruce_); | ||
self.state('invalid', err + self._soruce_); | ||
} else { | ||
@@ -164,3 +163,3 @@ zk.aw_get( self._path_, watch_cb, data_cb ); | ||
if(err) { | ||
self.emit('invalid', err, self._soruce_); | ||
self.state('invalid', err + self._soruce_); | ||
} | ||
@@ -167,0 +166,0 @@ if(self._options_.create_paths) { |
{ | ||
"name": "gestalt", | ||
"version": "0.0.6", | ||
"version": "0.0.7", | ||
"author": "Chris Howe <chris@howeville.com>", | ||
@@ -5,0 +5,0 @@ "description": "Event driven configuration management.", |
110
README.md
@@ -99,2 +99,50 @@ # gestalt | ||
Configuration objects also have a ready/invalid/other state. When | ||
everything about the configuration is loaded the way it expects that | ||
it should be, it enters a 'ready' state. If something has gone wrong | ||
in a way that might require some attention, it enters an 'invalid' | ||
state. Other states are possible - most configuration objects start in | ||
a 'not ready' state, but particular implementations might add some other | ||
special states. | ||
State propagates from children to parents and from contained objects | ||
to containers. The parent/container will become invalid if any of its | ||
children/contents become 'invalid'. Also, a parent/container will only become | ||
'ready' if all of its children/contents are 'ready'. If no sub-configuration | ||
is invalid, but not all of them are ready, parents and containers become | ||
'not ready'. | ||
On state transitions (and whenever further 'invalid' states are | ||
encountered) configuration objects will emit a 'state' message. The | ||
payload object is of the form: | ||
```javascript | ||
{ state: 'ready', | ||
old_state: 'not ready', | ||
data: 'arbitrary data that might help explain the transition' | ||
} | ||
``` | ||
To reiterate, there are three main states a Configuration object can | ||
be in: | ||
- 'ready' This means that there were no problems getting to the | ||
configuration data. You can read data from it, and set up | ||
listeners. | ||
- 'invalid' Something has gone wrong. We may not be able to get in | ||
contact with the data source, or there may have been a problem | ||
parsing the data. In any case, the data contained in the | ||
configuration object may be corrupt, out of date, or wrong. When a | ||
configuration object goes into an 'invalid' state, the program should | ||
stop consuming configuration data from the object and seek a way to remedy | ||
the invalid state. | ||
- 'not ready', (and others). The configuration object is not ready for reads. | ||
It will send out another 'state' event when it is ready or when something | ||
actually goes wrong. 'not ready' states are not an error state, but while | ||
a configuration is in a 'not ready' state, you may not be able to rely on | ||
the contents to be accurate, up to date, or even present. | ||
## Containers | ||
@@ -187,9 +235,12 @@ | ||
The mapper can be a function as above, or it can be a simple | ||
java object with old values as keys and new values as corresponding | ||
values. Keys not present in the object will be mapped out of the | ||
RemapConfig. | ||
Not surprisingly, there are a couple of restrictions on this type of | ||
configuration object. First, it is read only. Second, the remapper | ||
configuration object. First, it is read only. Second, the mapper | ||
function can show that it ignores part of the object space by | ||
returning undefined for some values. For the rest of the values, it | ||
must make sure to return unique new names for different old names. | ||
Third, the toObject function does not try to detect array-like | ||
objects. | ||
@@ -224,7 +275,26 @@ Remapped objects do pass on events, and can be used as overrides or | ||
- desctructure_arrays | ||
This option is similar to destructure_assignments, only it only controls | ||
whether or not to destructure array objects. It is true by default - when changed | ||
to false, arrays will be valid configuration values. | ||
Note, if you turn off destructure_arrays or destructure_assignments, the configuration | ||
object will not react to internal changes in the structured values. In particular; | ||
```javascript | ||
config.set("a",[1,2,3]); // emits a change | ||
congig.get("a")[0] = 7 // !!! does not emit a change !!! | ||
``` | ||
- initial_state | ||
State to transition to after initialization. Defaults to 'ready' for | ||
many configuration objects. Defaults to 'not_ready' for files, | ||
zookeeper, and other objects that load asynchonously. | ||
many configuration objects. Defaults to 'not ready' for files, | ||
zookeeper, and other objects that load asynchonously. Note that the | ||
configuration object is created in a 'not ready' state, and the | ||
transizion to its initial_state actually happens in the next tick after | ||
creation. | ||
@@ -263,3 +333,2 @@ - get(name) | ||
- keys() | ||
@@ -307,2 +376,15 @@ | ||
- removePatternListener( callback ) | ||
Removes a previously added listener callback. | ||
- state( state, data ) | ||
If no arguments are given, it returns the current state of the object. | ||
If a state it given, it transitions the configuration to that | ||
state. If the object's state has actually changed (or if we get | ||
another 'invalid' when it was already in an invalid state) it will | ||
emit a 'state' event, passing the data argument on in the state change | ||
payload along with the new and old states. | ||
#### Events | ||
@@ -323,17 +405,7 @@ | ||
- ready | ||
- state | ||
A ready event is emitted when the object becomes ready for use. For | ||
ConfigFile objects, this means that the file has been loaded. For | ||
other objects, it might mean something different. By default, a | ||
configuration object will emit a 'ready' event in the next tick after | ||
it was initialized. This behavior can be changed by setting the | ||
'initial_state' option to 'not ready' and then changing the state to | ||
'ready' through some other means (e.g. upon successfully loading a file). | ||
When the object's state changes between 'invalid', 'ready' and 'not ready', it will | ||
emit 'change' events. | ||
- invalid | ||
An invalid event is fired when something goes wrong - for instance if there is a problem parsing | ||
a configuration file. While a configuration is in an invalid state, you should not trust its | ||
data until it becomes ready again. | ||
@@ -21,4 +21,9 @@ var vows = require('vows'), | ||
var config = new ConfigFile( {source: config_json, format: 'json'} ); | ||
config.on('invalid', function() { promise.emit('failure', config); }); | ||
config.on('ready', function() { promise.emit('success', config); }); | ||
config.on('state', function(state_change) { | ||
if( state_change.state == 'invalid' ) { | ||
promise.emit('failure', config); | ||
} else if ( state_change.state == 'ready' ) { | ||
promise.emit('success', config); | ||
} | ||
}); | ||
return promise; | ||
@@ -37,4 +42,9 @@ }, | ||
var config = new ConfigFile( {source: config_yaml, format: 'yaml'} ); | ||
config.on('invalid', function() { promise.emit('failure', config); }); | ||
config.on('ready', function() { promise.emit('success', config); }); | ||
config.on('state', function(state_change) { | ||
if( state_change.state == 'invalid' ) { | ||
promise.emit('failure', config); | ||
} else if ( state_change.state == 'ready' ) { | ||
promise.emit('success', config); | ||
} | ||
}); | ||
return promise; | ||
@@ -55,4 +65,10 @@ }, | ||
var config = new ConfigFile( { source: config_ini, format: 'ini'} ); | ||
config.on('invalid', function() { promise.emit('failure', config); }); | ||
config.on('ready', function() { promise.emit('success', config); }); | ||
config.on('state', function(state_change) { | ||
if( state_change.state == 'invalid' ) { | ||
promise.emit('failure', config); | ||
} else if ( state_change.state == 'ready' ) { | ||
promise.emit('success', config); | ||
} | ||
}); | ||
//config.emit('loaded'); | ||
@@ -59,0 +75,0 @@ return promise; |
2455
406
122705
36