faye
Version:
Simple pub/sub messaging for the web
133 lines (105 loc) • 3.11 kB
JavaScript
'use strict';
var Class = require('../util/class'),
assign = require('../util/assign'),
Publisher = require('../mixins/publisher'),
Grammar = require('./grammar');
var Channel = Class({
initialize: function(name) {
this.id = this.name = name;
},
push: function(message) {
this.trigger('message', message);
},
isUnused: function() {
return this.countListeners('message') === 0;
}
});
assign(Channel.prototype, Publisher);
assign(Channel, {
HANDSHAKE: '/meta/handshake',
CONNECT: '/meta/connect',
SUBSCRIBE: '/meta/subscribe',
UNSUBSCRIBE: '/meta/unsubscribe',
DISCONNECT: '/meta/disconnect',
META: 'meta',
SERVICE: 'service',
expand: function(name) {
var segments = this.parse(name),
channels = ['/**', name];
var copy = segments.slice();
copy[copy.length - 1] = '*';
channels.push(this.unparse(copy));
for (var i = 1, n = segments.length; i < n; i++) {
copy = segments.slice(0, i);
copy.push('**');
channels.push(this.unparse(copy));
}
return channels;
},
isValid: function(name) {
return Grammar.CHANNEL_NAME.test(name) ||
Grammar.CHANNEL_PATTERN.test(name);
},
parse: function(name) {
if (!this.isValid(name)) return null;
return name.split('/').slice(1);
},
unparse: function(segments) {
return '/' + segments.join('/');
},
isMeta: function(name) {
var segments = this.parse(name);
return segments ? (segments[0] === this.META) : null;
},
isService: function(name) {
var segments = this.parse(name);
return segments ? (segments[0] === this.SERVICE) : null;
},
isSubscribable: function(name) {
if (!this.isValid(name)) return null;
return !this.isMeta(name) && !this.isService(name);
},
Set: Class({
initialize: function() {
this._channels = {};
},
getKeys: function() {
var keys = [];
for (var key in this._channels) keys.push(key);
return keys;
},
remove: function(name) {
delete this._channels[name];
},
hasSubscription: function(name) {
return this._channels.hasOwnProperty(name);
},
subscribe: function(names, subscription) {
var name;
for (var i = 0, n = names.length; i < n; i++) {
name = names[i];
var channel = this._channels[name] = this._channels[name] || new Channel(name);
channel.bind('message', subscription);
}
},
unsubscribe: function(name, subscription) {
var channel = this._channels[name];
if (!channel) return false;
channel.unbind('message', subscription);
if (channel.isUnused()) {
this.remove(name);
return true;
} else {
return false;
}
},
distributeMessage: function(message) {
var channels = Channel.expand(message.channel);
for (var i = 0, n = channels.length; i < n; i++) {
var channel = this._channels[channels[i]];
if (channel) channel.trigger('message', message);
}
}
})
});
module.exports = Channel;