comparison node_modules/socket.io/lib/index.js @ 77:cd921abc8887

added puredata trigger/OSC router
author Rob Canning <rob@foo.net>
date Tue, 15 Jul 2014 17:48:07 +0100
parents
children
comparison
equal deleted inserted replaced
76:0ae87af84e2f 77:cd921abc8887
1
2 /**
3 * Module dependencies.
4 */
5
6 var http = require('http');
7 var read = require('fs').readFileSync;
8 var parse = require('url').parse;
9 var engine = require('engine.io');
10 var client = require('socket.io-client');
11 var clientVersion = require('socket.io-client/package').version;
12 var Client = require('./client');
13 var Namespace = require('./namespace');
14 var Adapter = require('socket.io-adapter');
15 var debug = require('debug')('socket.io:server');
16 var url = require('url');
17
18 /**
19 * Module exports.
20 */
21
22 module.exports = Server;
23
24 /**
25 * Socket.IO client source.
26 */
27
28 var clientSource = read(require.resolve('socket.io-client/socket.io.js'), 'utf-8');
29
30 /**
31 * Server constructor.
32 *
33 * @param {http.Server|Number|Object} http server, port or options
34 * @param {Object} options
35 * @api public
36 */
37
38 function Server(srv, opts){
39 if (!(this instanceof Server)) return new Server(srv, opts);
40 if ('object' == typeof srv && !srv.listen) {
41 opts = srv;
42 srv = null;
43 }
44 opts = opts || {};
45 this.nsps = {};
46 this.path(opts.path || '/socket.io');
47 this.serveClient(false !== opts.serveClient);
48 this.adapter(opts.adapter || Adapter);
49 this.origins(opts.origins || '*:*');
50 this.sockets = this.of('/');
51 if (srv) this.attach(srv, opts);
52 }
53
54 /**
55 * Server request verification function, that checks for allowed origins
56 *
57 * @param {http.IncomingMessage} request
58 * @param {Function} callback to be called with the result: `fn(err, success)`
59 */
60
61 Server.prototype.checkRequest = function(req, fn) {
62 var origin = req.headers.origin || req.headers.referer;
63
64 // file:// URLs produce a null Origin which can't be authorized via echo-back
65 if ('null' == origin) origin = '*';
66
67 if (this._origins.indexOf('*:*') !== -1) return fn(null, true);
68 if (origin) {
69 try {
70 var parts = url.parse(origin);
71 parts.port = parts.port || 80;
72 var ok =
73 ~this._origins.indexOf(parts.hostname + ':' + parts.port) ||
74 ~this._origins.indexOf(parts.hostname + ':*') ||
75 ~this._origins.indexOf('*:' + parts.port);
76 return fn(null, !!ok);
77 } catch (ex) {
78 }
79 }
80 fn(null, false);
81 };
82
83 /**
84 * Sets/gets whether client code is being served.
85 *
86 * @param {Boolean} whether to serve client code
87 * @return {Server|Boolean} self when setting or value when getting
88 * @api public
89 */
90
91 Server.prototype.serveClient = function(v){
92 if (!arguments.length) return this._serveClient;
93 this._serveClient = v;
94 return this;
95 };
96
97 /**
98 * Old settings for backwards compatibility
99 */
100
101 var oldSettings = {
102 "transports": "transports",
103 "heartbeat timeout": "pingTimeout",
104 "heartbeat interval": "pingInterval",
105 "destroy buffer size": "maxHttpBufferSize"
106 };
107
108 /**
109 * Backwards compatiblity.
110 *
111 * @api public
112 */
113
114 Server.prototype.set = function(key, val){
115 if ('authorization' == key && val) {
116 this.use(function(socket, next) {
117 val(socket.request, function(err, authorized) {
118 if (err) return next(new Error(err));
119 if (!authorized) return next(new Error('Not authorized'));
120 next();
121 });
122 });
123 } else if ('origins' == key && val) {
124 this.origins(val);
125 } else if ('resource' == key) {
126 this.path(val);
127 } else if (oldSettings[key] && this.eio[oldSettings[key]]) {
128 this.eio[oldSettings[key]] = val;
129 } else {
130 console.error('Option %s is not valid. Please refer to the README.', key);
131 }
132
133 return this;
134 };
135
136 /**
137 * Sets the client serving path.
138 *
139 * @param {String} pathname
140 * @return {Server|String} self when setting or value when getting
141 * @api public
142 */
143
144 Server.prototype.path = function(v){
145 if (!arguments.length) return this._path;
146 this._path = v.replace(/\/$/, '');
147 return this;
148 };
149
150 /**
151 * Sets the adapter for rooms.
152 *
153 * @param {Adapter} pathname
154 * @return {Server|Adapter} self when setting or value when getting
155 * @api public
156 */
157
158 Server.prototype.adapter = function(v){
159 if (!arguments.length) return this._adapter;
160 this._adapter = v;
161 for (var i in this.nsps) {
162 if (this.nsps.hasOwnProperty(i)) {
163 this.nsps[i].initAdapter();
164 }
165 }
166 return this;
167 };
168
169 /**
170 * Sets the allowed origins for requests.
171 *
172 * @param {String} origins
173 * @return {Server|Adapter} self when setting or value when getting
174 * @api public
175 */
176
177 Server.prototype.origins = function(v){
178 if (!arguments.length) return this._origins;
179
180 this._origins = v;
181 return this;
182 };
183
184 /**
185 * Attaches socket.io to a server or port.
186 *
187 * @param {http.Server|Number} server or port
188 * @param {Object} options passed to engine.io
189 * @return {Server} self
190 * @api public
191 */
192
193 Server.prototype.listen =
194 Server.prototype.attach = function(srv, opts){
195 if ('function' == typeof srv) {
196 var msg = 'You are trying to attach socket.io to an express' +
197 'request handler function. Please pass a http.Server instance.';
198 throw new Error(msg);
199 }
200
201 // handle a port as a string
202 if (Number(srv) == srv) {
203 srv = Number(srv);
204 }
205
206 if ('number' == typeof srv) {
207 debug('creating http server and binding to %d', srv);
208 var port = srv;
209 srv = http.Server(function(req, res){
210 res.writeHead(404);
211 res.end();
212 });
213 srv.listen(port);
214 }
215
216 // set engine.io path to `/socket.io`
217 opts = opts || {};
218 opts.path = opts.path || '/socket.io';
219 // set origins verification
220 opts.allowRequest = this.checkRequest.bind(this);
221
222 // initialize engine
223 debug('creating engine.io instance with opts %j', opts);
224 this.eio = engine.attach(srv, opts);
225
226 // attach static file serving
227 if (this._serveClient) this.attachServe(srv);
228
229 // bind to engine events
230 this.bind(this.eio);
231
232 return this;
233 };
234
235 /**
236 * Attaches the static file serving.
237 *
238 * @param {Function|http.Server} http server
239 * @api private
240 */
241
242 Server.prototype.attachServe = function(srv){
243 debug('attaching client serving req handler');
244 var url = this._path + '/socket.io.js';
245 var evs = srv.listeners('request').slice(0);
246 var self = this;
247 srv.removeAllListeners('request');
248 srv.on('request', function(req, res) {
249 if (0 == req.url.indexOf(url)) {
250 self.serve(req, res);
251 } else {
252 for (var i = 0; i < evs.length; i++) {
253 evs[i].call(srv, req, res);
254 }
255 }
256 });
257 };
258
259 /**
260 * Handles a request serving `/socket.io.js`
261 *
262 * @param {http.Request} req
263 * @param {http.Response} res
264 * @api private
265 */
266
267 Server.prototype.serve = function(req, res){
268 if (req.headers.etag) {
269 if (clientVersion == req.headers.etag) {
270 debug('serve client 304');
271 res.writeHead(304);
272 res.end();
273 return;
274 }
275 }
276
277 debug('serve client source');
278 res.setHeader('Content-Type', 'application/javascript');
279 res.setHeader('ETag', clientVersion);
280 res.writeHead(200);
281 res.end(clientSource);
282 };
283
284 /**
285 * Binds socket.io to an engine.io instance.
286 *
287 * @param {engine.Server} engine.io (or compatible) server
288 * @return {Server} self
289 * @api public
290 */
291
292 Server.prototype.bind = function(engine){
293 this.engine = engine;
294 this.engine.on('connection', this.onconnection.bind(this));
295 return this;
296 };
297
298 /**
299 * Called with each incoming transport connection.
300 *
301 * @param {engine.Socket} socket
302 * @return {Server} self
303 * @api public
304 */
305
306 Server.prototype.onconnection = function(conn){
307 debug('incoming connection with id %s', conn.id);
308 var client = new Client(this, conn);
309 client.connect('/');
310 return this;
311 };
312
313 /**
314 * Looks up a namespace.
315 *
316 * @param {String} nsp name
317 * @param {Function} optional, nsp `connection` ev handler
318 * @api public
319 */
320
321 Server.prototype.of = function(name, fn){
322 if (!this.nsps[name]) {
323 debug('initializing namespace %s', name);
324 var nsp = new Namespace(this, name);
325 this.nsps[name] = nsp;
326 }
327 if (fn) this.nsps[name].on('connect', fn);
328 return this.nsps[name];
329 };
330
331 /**
332 * Expose main namespace (/).
333 */
334
335 ['on', 'to', 'in', 'use', 'emit', 'send', 'write'].forEach(function(fn){
336 Server.prototype[fn] = function(){
337 var nsp = this.sockets[fn];
338 return nsp.apply(this.sockets, arguments);
339 };
340 });
341
342 Namespace.flags.forEach(function(flag){
343 Server.prototype.__defineGetter__(flag, function(name){
344 this.flags.push(name);
345 return this;
346 });
347 });
348
349 /**
350 * BC with `io.listen`
351 */
352
353 Server.listen = Server;