socketioMEANseed/server/node_modules/socket.io/lib/namespace.js
server/node_modules/socket.io/lib/namespace.jsRaw
1
2/**
3 * Module dependencies.
4 */
5
6var Socket = require('./socket');
7var Emitter = require('events').EventEmitter;
8var parser = require('socket.io-parser');
9var debug = require('debug')('socket.io:namespace');
10var hasBin = require('has-binary');
11
12/**
13 * Module exports.
14 */
15
16module.exports = exports = Namespace;
17
18/**
19 * Blacklisted events.
20 */
21
22exports.events = [
23 'connect', // for symmetry with client
24 'connection',
25 'newListener'
26];
27
28/**
29 * Flags.
30 */
31
32exports.flags = [
33 'json',
34 'volatile',
35 'local'
36];
37
38/**
39 * `EventEmitter#emit` reference.
40 */
41
42var emit = Emitter.prototype.emit;
43
44/**
45 * Namespace constructor.
46 *
47 * @param {Server} server instance
48 * @param {Socket} name
49 * @api private
50 */
51
52function Namespace(server, name){
53 this.name = name;
54 this.server = server;
55 this.sockets = {};
56 this.connected = {};
57 this.fns = [];
58 this.ids = 0;
59 this.initAdapter();
60}
61
62/**
63 * Inherits from `EventEmitter`.
64 */
65
66Namespace.prototype.__proto__ = Emitter.prototype;
67
68/**
69 * Apply flags from `Socket`.
70 */
71
72exports.flags.forEach(function(flag){
73 Object.defineProperty(Namespace.prototype, flag, {
74 get: function() {
75 this.flags = this.flags || {};
76 this.flags[flag] = true;
77 return this;
78 }
79 });
80});
81
82/**
83 * Initializes the `Adapter` for this nsp.
84 * Run upon changing adapter by `Server#adapter`
85 * in addition to the constructor.
86 *
87 * @api private
88 */
89
90Namespace.prototype.initAdapter = function(){
91 this.adapter = new (this.server.adapter())(this);
92};
93
94/**
95 * Sets up namespace middleware.
96 *
97 * @return {Namespace} self
98 * @api public
99 */
100
101Namespace.prototype.use = function(fn){
102 this.fns.push(fn);
103 return this;
104};
105
106/**
107 * Executes the middleware for an incoming client.
108 *
109 * @param {Socket} socket that will get added
110 * @param {Function} fn last fn call in the middleware
111 * @api private
112 */
113
114Namespace.prototype.run = function(socket, fn){
115 var fns = this.fns.slice(0);
116 if (!fns.length) return fn(null);
117
118 function run(i){
119 fns[i](socket, function(err){
120 // upon error, short-circuit
121 if (err) return fn(err);
122
123 // if no middleware left, summon callback
124 if (!fns[i + 1]) return fn(null);
125
126 // go on to next
127 run(i + 1);
128 });
129 }
130
131 run(0);
132};
133
134/**
135 * Targets a room when emitting.
136 *
137 * @param {String} name
138 * @return {Namespace} self
139 * @api public
140 */
141
142Namespace.prototype.to =
143Namespace.prototype.in = function(name){
144 this.rooms = this.rooms || [];
145 if (!~this.rooms.indexOf(name)) this.rooms.push(name);
146 return this;
147};
148
149/**
150 * Adds a new client.
151 *
152 * @return {Socket}
153 * @api private
154 */
155
156Namespace.prototype.add = function(client, query, fn){
157 debug('adding socket to nsp %s', this.name);
158 var socket = new Socket(this, client, query);
159 var self = this;
160 this.run(socket, function(err){
161 process.nextTick(function(){
162 if ('open' == client.conn.readyState) {
163 if (err) return socket.error(err.data || err.message);
164
165 // track socket
166 self.sockets[socket.id] = socket;
167
168 // it's paramount that the internal `onconnect` logic
169 // fires before user-set events to prevent state order
170 // violations (such as a disconnection before the connection
171 // logic is complete)
172 socket.onconnect();
173 if (fn) fn();
174
175 // fire user-set events
176 self.emit('connect', socket);
177 self.emit('connection', socket);
178 } else {
179 debug('next called after client was closed - ignoring socket');
180 }
181 });
182 });
183 return socket;
184};
185
186/**
187 * Removes a client. Called by each `Socket`.
188 *
189 * @api private
190 */
191
192Namespace.prototype.remove = function(socket){
193 if (this.sockets.hasOwnProperty(socket.id)) {
194 delete this.sockets[socket.id];
195 } else {
196 debug('ignoring remove for %s', socket.id);
197 }
198};
199
200/**
201 * Emits to all clients.
202 *
203 * @return {Namespace} self
204 * @api public
205 */
206
207Namespace.prototype.emit = function(ev){
208 if (~exports.events.indexOf(ev)) {
209 emit.apply(this, arguments);
210 } else {
211 // set up packet object
212 var args = Array.prototype.slice.call(arguments);
213 var parserType = parser.EVENT; // default
214 if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary
215
216 var packet = { type: parserType, data: args };
217
218 if ('function' == typeof args[args.length - 1]) {
219 throw new Error('Callbacks are not supported when broadcasting');
220 }
221
222 this.adapter.broadcast(packet, {
223 rooms: this.rooms,
224 flags: this.flags
225 });
226
227 delete this.rooms;
228 delete this.flags;
229 }
230 return this;
231};
232
233/**
234 * Sends a `message` event to all clients.
235 *
236 * @return {Namespace} self
237 * @api public
238 */
239
240Namespace.prototype.send =
241Namespace.prototype.write = function(){
242 var args = Array.prototype.slice.call(arguments);
243 args.unshift('message');
244 this.emit.apply(this, args);
245 return this;
246};
247
248/**
249 * Gets a list of clients.
250 *
251 * @return {Namespace} self
252 * @api public
253 */
254
255Namespace.prototype.clients = function(fn){
256 this.adapter.clients(this.rooms, fn);
257 // delete rooms flag for scenario:
258 // .in('room').clients() (GH-1978)
259 delete this.rooms;
260 return this;
261};
262
263/**
264 * Sets the compress flag.
265 *
266 * @param {Boolean} compress if `true`, compresses the sending data
267 * @return {Socket} self
268 * @api public
269 */
270
271Namespace.prototype.compress = function(compress){
272 this.flags = this.flags || {};
273 this.flags.compress = compress;
274 return this;
275};