You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
4.2 KiB
153 lines
4.2 KiB
/** |
|
* Copyright (c) 2013 Yahoo! Inc. All rights reserved. |
|
* |
|
* Copyrights licensed under the MIT License. See the accompanying LICENSE file |
|
* for terms. |
|
*/ |
|
|
|
|
|
var events = require('events'); |
|
var Path = require('./Path.js'); |
|
var Event = require('./Event.js'); |
|
|
|
function WatcherManager() { |
|
this.dataWatchers = {}; |
|
this.childWatchers = {}; |
|
this.existenceWatchers = {}; |
|
} |
|
|
|
function registerWatcher(self, type, path, watcher) { |
|
var watchers = self[type + 'Watchers'], |
|
watcherExists = false; |
|
|
|
Path.validate(path); |
|
|
|
if (typeof watcher !== 'function') { |
|
throw new Error('watcher must be a valid function.'); |
|
} |
|
|
|
watchers[path] = watchers[path] || new events.EventEmitter(); |
|
watcherExists = watchers[path].listeners('notification').some(function (l) { |
|
// This is rather hacky since node.js wraps the listeners using an |
|
// internal function. |
|
return l === watcher || l.listener === watcher; |
|
}); |
|
|
|
if (!watcherExists) { |
|
watchers[path].once('notification', watcher); |
|
} |
|
} |
|
|
|
function getWatcherPaths(self, type) { |
|
var watchers = self[type + 'Watchers'], |
|
result = []; |
|
|
|
Object.keys(watchers).forEach(function (path) { |
|
if (watchers[path].listeners('notification').length > 0) { |
|
result.push(path); |
|
} |
|
}); |
|
|
|
return result; |
|
} |
|
|
|
WatcherManager.prototype.registerDataWatcher = function (path, watcher) { |
|
registerWatcher(this, 'data', path, watcher); |
|
}; |
|
|
|
WatcherManager.prototype.getDataWatcherPaths = function () { |
|
return getWatcherPaths(this, 'data'); |
|
}; |
|
|
|
WatcherManager.prototype.registerChildWatcher = function (path, watcher) { |
|
registerWatcher(this, 'child', path, watcher); |
|
}; |
|
|
|
WatcherManager.prototype.getChildWatcherPaths = function () { |
|
return getWatcherPaths(this, 'child'); |
|
}; |
|
|
|
WatcherManager.prototype.registerExistenceWatcher = function (path, watcher) { |
|
registerWatcher(this, 'existence', path, watcher); |
|
}; |
|
|
|
WatcherManager.prototype.getExistenceWatcherPaths = function () { |
|
return getWatcherPaths(this, 'existence'); |
|
}; |
|
|
|
WatcherManager.prototype.emit = function (watcherEvent) { |
|
if (!watcherEvent) { |
|
throw new Error('watcherEvent must be a valid object.'); |
|
} |
|
|
|
var emitters = [], |
|
event; |
|
|
|
switch (watcherEvent.type) { |
|
case Event.NODE_DATA_CHANGED: |
|
case Event.NODE_CREATED: |
|
if (this.dataWatchers[watcherEvent.path]) { |
|
emitters.push(this.dataWatchers[watcherEvent.path]); |
|
delete this.dataWatchers[watcherEvent.path]; |
|
} |
|
|
|
if (this.existenceWatchers[watcherEvent.path]) { |
|
emitters.push(this.existenceWatchers[watcherEvent.path]); |
|
delete this.existenceWatchers[watcherEvent.path]; |
|
} |
|
break; |
|
case Event.NODE_CHILDREN_CHANGED: |
|
if (this.childWatchers[watcherEvent.path]) { |
|
emitters.push(this.childWatchers[watcherEvent.path]); |
|
delete this.childWatchers[watcherEvent.path]; |
|
} |
|
break; |
|
case Event.NODE_DELETED: |
|
if (this.dataWatchers[watcherEvent.path]) { |
|
emitters.push(this.dataWatchers[watcherEvent.path]); |
|
delete this.dataWatchers[watcherEvent.path]; |
|
} |
|
if (this.childWatchers[watcherEvent.path]) { |
|
emitters.push(this.childWatchers[watcherEvent.path]); |
|
delete this.childWatchers[watcherEvent.path]; |
|
} |
|
break; |
|
default: |
|
throw new Error('Unknown event type: ' + watcherEvent.type); |
|
} |
|
|
|
if (emitters.length < 1) { |
|
return; |
|
} |
|
|
|
event = Event.create(watcherEvent); |
|
|
|
emitters.forEach(function (emitter) { |
|
emitter.emit('notification', event); |
|
}); |
|
}; |
|
|
|
WatcherManager.prototype.isEmpty = function () { |
|
var empty = true, |
|
watchers, |
|
paths, |
|
i, |
|
j; |
|
|
|
watchers = [this.dataWatchers, this.existenceWatchers, this.childWatchers]; |
|
|
|
for (i = 0; i < watchers.length; i += 1) { |
|
paths = Object.keys(watchers[i]); |
|
|
|
for (j = 0; j < paths.length; j += 1) { |
|
if (watchers[i][paths[j]].listeners('notification').length > 0) { |
|
empty = false; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
return empty; |
|
}; |
|
|
|
module.exports = WatcherManager;
|
|
|