mirror of
https://github.com/socketio/socket.io.git
synced 2026-01-11 16:08:24 -05:00
Compare commits
245 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3fc530abe | ||
|
|
d0dfa54dcb | ||
|
|
198b836759 | ||
|
|
a75f46f06f | ||
|
|
2a91fd57c7 | ||
|
|
fe891293b2 | ||
|
|
6e450f75b4 | ||
|
|
22c985cae6 | ||
|
|
fea3d79a2c | ||
|
|
d3dde130b7 | ||
|
|
899de7f873 | ||
|
|
f1a3e8db2a | ||
|
|
dad82c3343 | ||
|
|
a6cbf6b205 | ||
|
|
580100d491 | ||
|
|
acb9cb421d | ||
|
|
6d5d7e4411 | ||
|
|
ddb3445f3d | ||
|
|
6eb9807f17 | ||
|
|
abe2394a24 | ||
|
|
7012ba6c64 | ||
|
|
7b0073c00f | ||
|
|
0313ad0ea3 | ||
|
|
d310d42472 | ||
|
|
709ceba00a | ||
|
|
b29312bc61 | ||
|
|
51901160df | ||
|
|
ab1b36e13f | ||
|
|
f7a2f35590 | ||
|
|
c348737fe6 | ||
|
|
dde3737165 | ||
|
|
8df4c7931b | ||
|
|
1dfacc6647 | ||
|
|
35a0fe0377 | ||
|
|
3b00312fa7 | ||
|
|
7b420295ef | ||
|
|
c504315982 | ||
|
|
520b5c37d5 | ||
|
|
09f446eca0 | ||
|
|
aecf3bf71c | ||
|
|
6c0a79e2b9 | ||
|
|
8683206e31 | ||
|
|
988d9d2346 | ||
|
|
b73d9bea4e | ||
|
|
d4fb6a5904 | ||
|
|
0517c609ba | ||
|
|
aa9438fee2 | ||
|
|
aee466cc71 | ||
|
|
65f75d7732 | ||
|
|
279c52a4c5 | ||
|
|
67d1a67b1c | ||
|
|
aae68d74b1 | ||
|
|
bf5897cedc | ||
|
|
a1a1c6657a | ||
|
|
2a4f7ae161 | ||
|
|
dba0576ca9 | ||
|
|
ba90f0991b | ||
|
|
9a54e9cace | ||
|
|
9df4cb64b8 | ||
|
|
c8f525868a | ||
|
|
a39d7c2ae4 | ||
|
|
4ba266d404 | ||
|
|
6b49779420 | ||
|
|
b1775b1cb8 | ||
|
|
ef52967301 | ||
|
|
fde38b1bd7 | ||
|
|
75da57abb2 | ||
|
|
21ea31a34e | ||
|
|
e2ebd4349b | ||
|
|
b771f74a22 | ||
|
|
8744007dc7 | ||
|
|
3658928ee7 | ||
|
|
210e688732 | ||
|
|
ae5420b727 | ||
|
|
d5b3bb46f8 | ||
|
|
575d35a371 | ||
|
|
e41483be9e | ||
|
|
c79e787671 | ||
|
|
a2f6bb99d6 | ||
|
|
3e4061bfef | ||
|
|
4c1d691fe5 | ||
|
|
514aeb4fcd | ||
|
|
876833198d | ||
|
|
4d36d6c01a | ||
|
|
43fa075ec4 | ||
|
|
91c7bde34b | ||
|
|
874a4a8535 | ||
|
|
93b571406e | ||
|
|
98af793f07 | ||
|
|
3f72dd3322 | ||
|
|
d0d38220fb | ||
|
|
f8aa157d5d | ||
|
|
0e13e9a268 | ||
|
|
916872587f | ||
|
|
a7072845ea | ||
|
|
425409945b | ||
|
|
5826ef0bb5 | ||
|
|
14e32a9bad | ||
|
|
1dde0f3947 | ||
|
|
342faf2197 | ||
|
|
12c6ee132d | ||
|
|
c9d909c993 | ||
|
|
125ab51338 | ||
|
|
b31ac18554 | ||
|
|
53cdd8f1fc | ||
|
|
81aea995ed | ||
|
|
1b2d902f33 | ||
|
|
9536437907 | ||
|
|
56fe26661d | ||
|
|
29974ac777 | ||
|
|
ef23c74bea | ||
|
|
49423d70bc | ||
|
|
715c7f99b4 | ||
|
|
f2ea965c6b | ||
|
|
a93d05a9f3 | ||
|
|
5ce06d3088 | ||
|
|
816bfec783 | ||
|
|
0a17c90d7a | ||
|
|
3645741b86 | ||
|
|
f2a7322b5a | ||
|
|
97c6568f65 | ||
|
|
8814825a35 | ||
|
|
58eaecad27 | ||
|
|
94157e650e | ||
|
|
0935b81da2 | ||
|
|
afa871bb8a | ||
|
|
1b01e16a6c | ||
|
|
bd6f638c8f | ||
|
|
83b36e54ac | ||
|
|
2f0d9d05af | ||
|
|
429eb0cb7c | ||
|
|
ac8e8598d7 | ||
|
|
9ba6d47ec7 | ||
|
|
3d49cafd03 | ||
|
|
77ca2dcbda | ||
|
|
7e4aa4fa64 | ||
|
|
b46e480f65 | ||
|
|
5e92dd8663 | ||
|
|
f981d3f050 | ||
|
|
f57505fee7 | ||
|
|
f8f1b132a1 | ||
|
|
f7f83bc09f | ||
|
|
b8ded0d725 | ||
|
|
086ccd2708 | ||
|
|
864857cb6f | ||
|
|
e5a7e422f9 | ||
|
|
f5b75151bd | ||
|
|
0523b655da | ||
|
|
d9415a38e4 | ||
|
|
ca82c09bf2 | ||
|
|
b9aaa1607c | ||
|
|
d1304c5d82 | ||
|
|
bd479a9cd6 | ||
|
|
a116d7765a | ||
|
|
1c6620d564 | ||
|
|
dba462e6da | ||
|
|
19c4422361 | ||
|
|
8242dd01ef | ||
|
|
17960ed038 | ||
|
|
d9996f0470 | ||
|
|
24d06d76dd | ||
|
|
4e4bbf918e | ||
|
|
b49f5c82f2 | ||
|
|
5bd67195de | ||
|
|
73fe547956 | ||
|
|
973e6cc982 | ||
|
|
4a0091b25a | ||
|
|
a1bf85b57f | ||
|
|
62ad812ee5 | ||
|
|
9ae8ed6929 | ||
|
|
4a11c16cc2 | ||
|
|
b88a758857 | ||
|
|
3352d1d726 | ||
|
|
e68557fab6 | ||
|
|
136fe960b7 | ||
|
|
da358084f0 | ||
|
|
1b4f6a5324 | ||
|
|
99346eddc5 | ||
|
|
051ffa0440 | ||
|
|
fa4fa3365a | ||
|
|
bafa184c6b | ||
|
|
e3149d5833 | ||
|
|
ae9d5277a9 | ||
|
|
2e440722a6 | ||
|
|
3fe6d4e8ec | ||
|
|
3b93c1c562 | ||
|
|
e89f82a9b0 | ||
|
|
1b90ae2587 | ||
|
|
9658e32e7a | ||
|
|
99d76664aa | ||
|
|
23eefa527a | ||
|
|
b49b35b26f | ||
|
|
16483375a7 | ||
|
|
ec305bd8df | ||
|
|
af07a1c649 | ||
|
|
5863903d44 | ||
|
|
f56d4acce6 | ||
|
|
8ea37b7351 | ||
|
|
b3cb18d910 | ||
|
|
0e41561d56 | ||
|
|
83709e9487 | ||
|
|
6f4051aaa7 | ||
|
|
87bf6910b5 | ||
|
|
8946b4ed4c | ||
|
|
a40068b5f3 | ||
|
|
9e29ec9b2b | ||
|
|
624e7cb14f | ||
|
|
b4954d767a | ||
|
|
f6eb53f5e1 | ||
|
|
9c80317574 | ||
|
|
d163d891ef | ||
|
|
54726105cb | ||
|
|
3d9e52cf93 | ||
|
|
ad74f2ff88 | ||
|
|
cf1c1273b3 | ||
|
|
1f43c4abb5 | ||
|
|
d6e6e8a2f8 | ||
|
|
fbd36b613d | ||
|
|
480b1a05bd | ||
|
|
ef729b72b4 | ||
|
|
63e197083b | ||
|
|
968e94e42b | ||
|
|
c18ed5fd4d | ||
|
|
1f7da938bd | ||
|
|
4b89bce182 | ||
|
|
8c19eef07a | ||
|
|
662b30669b | ||
|
|
001373ee17 | ||
|
|
246f3bb5c3 | ||
|
|
68d06ec94c | ||
|
|
a1feca1bd3 | ||
|
|
968105a239 | ||
|
|
2e8e26613a | ||
|
|
fbdb94d146 | ||
|
|
55572122f3 | ||
|
|
a1170a3aa6 | ||
|
|
0954301d7e | ||
|
|
328a9df8eb | ||
|
|
d99e30fca7 | ||
|
|
561dd6fd79 | ||
|
|
e9e2a91cea | ||
|
|
8a3a111a7f | ||
|
|
bd87e4dc35 | ||
|
|
71c253e992 | ||
|
|
55fb100fc0 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,3 +9,4 @@ lib-cov
|
||||
benchmarks/*.png
|
||||
node_modules
|
||||
coverage
|
||||
.idea
|
||||
@@ -1,3 +1,4 @@
|
||||
support
|
||||
test
|
||||
examples
|
||||
.gitignore
|
||||
|
||||
17
.travis.yml
17
.travis.yml
@@ -1,13 +1,20 @@
|
||||
sudo: false
|
||||
before_install:
|
||||
- npm install -g npm@'>=1.4.3'
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
- "0.12"
|
||||
- "4"
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- node_js: "0.11"
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
#matrix:
|
||||
#fast_finish: true
|
||||
#allow_failures:
|
||||
#- node_js: "0.11"
|
||||
|
||||
notifications:
|
||||
irc: "irc.freenode.org#socket.io"
|
||||
|
||||
162
History.md
162
History.md
@@ -1,4 +1,166 @@
|
||||
|
||||
1.4.5 / 2016-01-26
|
||||
==================
|
||||
|
||||
* fix closing the underlying `http.Server`
|
||||
|
||||
1.4.4 / 2016-01-10
|
||||
==================
|
||||
|
||||
* package: bump `engine.io`
|
||||
|
||||
1.4.3 / 2016-01-08
|
||||
==================
|
||||
|
||||
* bump `socket.io-client`
|
||||
|
||||
1.4.2 / 2016-01-07
|
||||
==================
|
||||
|
||||
* bump `engine.io`
|
||||
|
||||
1.4.1 / 2016-01-07
|
||||
==================
|
||||
|
||||
* version bump
|
||||
|
||||
1.4.0 / 2015-11-28
|
||||
==================
|
||||
|
||||
* socket.io: increase large binary data test timeout
|
||||
* package: bump `engine.io` for release
|
||||
* trigger callback even when joining an already joined room
|
||||
* package: bump parser
|
||||
* namespace: clear rooms flag after a clients call (fixes #1978)
|
||||
* package: bump `socket.io-parser`
|
||||
* fixed tests with large data
|
||||
* fixed a typo in the example code
|
||||
* package: bump mocha
|
||||
* package: bump `has-binary` and `zuul-ngrok`
|
||||
* package: bump `engine.io` and `socket.io-client`
|
||||
* README: clarified documentation of Socket.in
|
||||
* README: fixed up legacy repo links
|
||||
* test: better timeout for stress test
|
||||
* socket: don't set request property which has a getter
|
||||
* removed proxy index file
|
||||
* support flags on namespace
|
||||
* improve Socket#packet and Client#packet
|
||||
* socket: warn node_redis-style about missing `error`
|
||||
* test: added failing test
|
||||
* test: increase timeout for large binary data test
|
||||
* package: bump `has-binary` to work with all objects (fixes #1955)
|
||||
* fix origin verification default https port [evanlucas]
|
||||
* support compression [nkzawa]
|
||||
* changed type of `Client#sockets`, `Namespace#sockets` and `Socket#rooms` to maps (instead of arrays)
|
||||
|
||||
1.3.7 / 2015-09-21
|
||||
==================
|
||||
|
||||
* package: bump `socket.io-client` for node4 compatibility
|
||||
* package: bump `engine.io` for node4 compatibility
|
||||
|
||||
1.3.6 / 2015-07-14
|
||||
==================
|
||||
|
||||
* package: bump `engine.io` to fix build on windows
|
||||
|
||||
1.3.5 / 2015-03-03
|
||||
==================
|
||||
|
||||
* package: bump `socket.io-parser`
|
||||
|
||||
1.3.4 / 2015-02-14
|
||||
==================
|
||||
|
||||
* package: bump `socket.io-client`
|
||||
|
||||
1.3.3 / 2015-02-03
|
||||
==================
|
||||
|
||||
* socket: warn node_redis-style about missing `error`
|
||||
* package: bump parser to better handle bad binary packets
|
||||
|
||||
1.3.2 / 2015-01-19
|
||||
==================
|
||||
|
||||
* no change on this release
|
||||
|
||||
1.3.1 / 2015-01-19
|
||||
==================
|
||||
|
||||
* no change on this release
|
||||
* package: bump `engine.io`
|
||||
|
||||
1.3.0 / 2015-01-19
|
||||
==================
|
||||
|
||||
* package: bump `engine.io`
|
||||
* add test for reconnection after server restarts [rase-]
|
||||
* update license with up-to-date year range [fay-jai]
|
||||
* fix leaving unknown rooms [defunctzombie]
|
||||
* allow null origins when allowed origins is a function [drewblaisdell]
|
||||
* fix tests on node 0.11
|
||||
* package: fix `npm test` to run on windows
|
||||
* package: bump `debug` v2.1.0 [coderaiser]
|
||||
* added tests for volatile [rase-]
|
||||
|
||||
1.2.1 / 2014-11-21
|
||||
==================
|
||||
|
||||
* fix protocol violations and improve error handling (GH-1880)
|
||||
* package: bump `engine.io` for websocket leak fix [3rd-Eden]
|
||||
* style tweaks
|
||||
|
||||
1.2.0 / 2014-10-27
|
||||
==================
|
||||
|
||||
* package: bump `engine.io`
|
||||
* downloads badge
|
||||
* add test to check that empty rooms are autopruned
|
||||
* added Server#origins(v:Function) description for dynamic CORS
|
||||
* added test coverage for Server#origins(function) for dynamic CORS
|
||||
* added optional Server#origins(function) for dynamic CORS
|
||||
* fix usage example for Server#close
|
||||
* package: fix main file for example application 'chat'
|
||||
* package: bump `socket.io-parser`
|
||||
* update README http ctor to createServer()
|
||||
* bump adapter with a lot of fixes for room bookkeeping
|
||||
|
||||
1.1.0 / 2014-09-04
|
||||
==================
|
||||
|
||||
* examples: minor fix of escaping
|
||||
* testing for equivalence of namespaces starting with / or without
|
||||
* update index.js
|
||||
* added relevant tests
|
||||
* take "" and "/" as equivalent namespaces on server
|
||||
* use svg instead of png to get better image quality in readme
|
||||
* make CI build faster
|
||||
* fix splice arguments and `socket.rooms` value update in `socket.leaveAll`.
|
||||
* client cannot connect to non-existing namespaces
|
||||
* bump engine.io version to get the cached IP address
|
||||
* fixed handshake object address property and made the test case more strict.
|
||||
* package: bump `engine.io`
|
||||
* fixed the failing test where server crashes on disconnect involving connectBuffer
|
||||
* npmignore: ignore `.gitignore` (fixes #1607)
|
||||
* test: added failing case for `socket.disconnect` and nsps
|
||||
* fix repo in package.json
|
||||
* improve Close documentation
|
||||
* use ephemeral ports
|
||||
* fix: We should use the standard http protocol to handler the etag header.
|
||||
* override default browser font-family for inputs
|
||||
* update has-binary-data to 1.0.3
|
||||
* add close specs
|
||||
* add ability to stop the http server even if not created inside socket.io
|
||||
* make sure server gets close
|
||||
* Add test case for checking that reconnect_failed is fired only once upon failure
|
||||
* package: bump `socket.io-parser` for `component-emitter` dep fix
|
||||
|
||||
1.0.6 / 2014-06-19
|
||||
==================
|
||||
|
||||
* package: bump `socket.io-client`
|
||||
|
||||
1.0.5 / 2014-06-16
|
||||
==================
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2014 Automattic <dev@cloudup.com>
|
||||
Copyright (c) 2014-2015 Automattic <dev@cloudup.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
115
Readme.md
115
Readme.md
@@ -1,8 +1,12 @@
|
||||
|
||||
# socket.io
|
||||
|
||||
[](http://travis-ci.org/Automattic/socket.io)
|
||||
[](http://badge.fury.io/js/socket.io)
|
||||
[](https://travis-ci.org/socketio/socket.io)
|
||||
[](https://david-dm.org/socketio/socket.io)
|
||||
[](https://david-dm.org/socketio/socket.io#info=devDependencies)
|
||||

|
||||

|
||||
[](http://slack.socket.io)
|
||||
|
||||
## How to use
|
||||
|
||||
@@ -10,7 +14,7 @@ The following example attaches socket.io to a plain Node.JS
|
||||
HTTP server listening on port `3000`.
|
||||
|
||||
```js
|
||||
var server = require('http').Server();
|
||||
var server = require('http').createServer();
|
||||
var io = require('socket.io')(server);
|
||||
io.on('connection', function(socket){
|
||||
socket.on('event', function(data){});
|
||||
@@ -36,7 +40,7 @@ function.
|
||||
|
||||
```js
|
||||
var app = require('express')();
|
||||
var server = require('http').Server(app);
|
||||
var server = require('http').createServer(app);
|
||||
var io = require('socket.io')(server);
|
||||
io.on('connection', function(){ /* … */ });
|
||||
server.listen(3000);
|
||||
@@ -49,7 +53,7 @@ handler function, but only by calling the `callback` method.
|
||||
|
||||
```js
|
||||
var app = require('koa')();
|
||||
var server = require('http').Server(app.callback());
|
||||
var server = require('http').createServer(app.callback());
|
||||
var io = require('socket.io')(server);
|
||||
io.on('connection', function(){ /* … */ });
|
||||
server.listen(3000);
|
||||
@@ -84,7 +88,7 @@ server.listen(3000);
|
||||
|
||||
The same options passed to socket.io are always passed to
|
||||
the `engine.io` `Server` that gets created. See engine.io
|
||||
[options](https://github.com/learnboost/engine.io#methods-1)
|
||||
[options](https://github.com/socketio/engine.io#methods-1)
|
||||
as reference.
|
||||
|
||||
### Server(srv:http#Server, opts:Object)
|
||||
@@ -126,7 +130,7 @@ server.listen(3000);
|
||||
|
||||
Sets the adapter `v`. Defaults to an instance of the `Adapter` that
|
||||
ships with socket.io which is memory based. See
|
||||
[socket.io-adapter](https://github.com/Automattic/socket.io-adapter).
|
||||
[socket.io-adapter](https://github.com/socketio/socket.io-adapter).
|
||||
|
||||
If no arguments are supplied this method returns the current value.
|
||||
|
||||
@@ -136,6 +140,15 @@ server.listen(3000);
|
||||
|
||||
If no arguments are supplied this method returns the current value.
|
||||
|
||||
### Server#origins(v:Function):Server
|
||||
|
||||
Sets the allowed origins as dynamic function. Function takes two arguments `origin:String` and `callback(error, success)`, where `success` is a boolean value indicating whether origin is allowed or not.
|
||||
|
||||
__Potential drawbacks__:
|
||||
* in some situations, when it is not possible to determine `origin` it may have value of `*`
|
||||
* As this function will be executed for every request, it is advised to make this function work as fast as possible
|
||||
* If `socket.io` is used together with `Express`, the CORS headers will be affected only for `socket.io` requests. For Express can use [cors](https://github.com/expressjs/cors)
|
||||
|
||||
|
||||
### Server#sockets:Namespace
|
||||
|
||||
@@ -157,7 +170,7 @@ server.listen(3000);
|
||||
|
||||
### Server#bind(srv:engine#Server):Server
|
||||
|
||||
Advanced use only. Binds the server to a specific engine.io `Server`
|
||||
Advanced use only. Binds the server to a specific engine.io `Server`
|
||||
(or compatible API) instance.
|
||||
|
||||
### Server#onconnection(socket:engine#Socket):Server
|
||||
@@ -167,14 +180,14 @@ server.listen(3000);
|
||||
|
||||
### Server#of(nsp:String):Namespace
|
||||
|
||||
Initializes and retrieves the given `Namespace` by its pathname
|
||||
Initializes and retrieves the given `Namespace` by its pathname
|
||||
identifier `nsp`.
|
||||
|
||||
If the namespace was already initialized it returns it right away.
|
||||
|
||||
### Server#emit
|
||||
|
||||
Emits an event to all connected clients. The following two are
|
||||
Emits an event to all connected clients. The following two are
|
||||
equivalent:
|
||||
|
||||
```js
|
||||
@@ -185,6 +198,24 @@ server.listen(3000);
|
||||
|
||||
For other available methods, see `Namespace` below.
|
||||
|
||||
### Server#close
|
||||
|
||||
Closes socket server
|
||||
|
||||
```js
|
||||
var Server = require('socket.io');
|
||||
var PORT = 3030;
|
||||
var server = require('http').Server();
|
||||
|
||||
var io = Server(PORT);
|
||||
|
||||
io.close(); // Close current server
|
||||
|
||||
server.listen(PORT); // PORT is free to use
|
||||
|
||||
io = Server(server);
|
||||
```
|
||||
|
||||
### Server#use
|
||||
|
||||
See `Namespace#use` below.
|
||||
@@ -212,6 +243,40 @@ server.listen(3000);
|
||||
Hash of `Socket` objects that are connected to this namespace indexed
|
||||
by `id`.
|
||||
|
||||
### Namespace#clients(fn:Function)
|
||||
|
||||
Gets a list of client IDs connected to this namespace (across all nodes if applicable).
|
||||
|
||||
An example to get all clients in a namespace:
|
||||
|
||||
```js
|
||||
var io = require('socket.io')();
|
||||
io.of('/chat').clients(function(error, clients){
|
||||
if (error) throw error;
|
||||
console.log(clients); // => [PZDoMHjiu8PYfRiKAAAF, Anw2LatarvGVVXEIAAAD]
|
||||
});
|
||||
```
|
||||
|
||||
An example to get all clients in namespace's room:
|
||||
|
||||
```js
|
||||
var io = require('socket.io')();
|
||||
io.of('/chat').in('general').clients(function(error, clients){
|
||||
if (error) throw error;
|
||||
console.log(clients); // => [Anw2LatarvGVVXEIAAAD]
|
||||
});
|
||||
```
|
||||
|
||||
As with broadcasting, the default is all clients from the default namespace ('/'):
|
||||
|
||||
```js
|
||||
var io = require('socket.io')();
|
||||
io.clients(function(error, clients){
|
||||
if (error) throw error;
|
||||
console.log(clients); // => [6em3d4TJP8Et9EMNAAAA, G5p55dHhGgUnLUctAAAB]
|
||||
});
|
||||
```
|
||||
|
||||
### Namespace#use(fn:Function):Namespace
|
||||
|
||||
Registers a middleware, which is a function that gets executed for
|
||||
@@ -236,9 +301,10 @@ server.listen(3000);
|
||||
clients. A `Socket` belongs to a certain `Namespace` (by default `/`)
|
||||
and uses an underlying `Client` to communicate.
|
||||
|
||||
### Socket#rooms:Array
|
||||
### Socket#rooms:Object
|
||||
|
||||
A list of strings identifying the rooms this socket is in.
|
||||
A hash of strings identifying the rooms this socket is in, indexed by
|
||||
room name.
|
||||
|
||||
### Socket#client:Client
|
||||
|
||||
@@ -246,7 +312,7 @@ server.listen(3000);
|
||||
|
||||
### Socket#conn:Socket
|
||||
|
||||
A reference to the underyling `Client` transport connection (engine.io
|
||||
A reference to the underlying `Client` transport connection (engine.io
|
||||
`Socket` object).
|
||||
|
||||
### Socket#request:Request
|
||||
@@ -285,7 +351,7 @@ server.listen(3000);
|
||||
|
||||
The mechanics of joining rooms are handled by the `Adapter`
|
||||
that has been configured (see `Server#adapter` above), defaulting to
|
||||
[socket.io-adapter](https://github.com/Automattic/socket.io-adapter).
|
||||
[socket.io-adapter](https://github.com/socketio/socket.io-adapter).
|
||||
|
||||
### Socket#leave(name:String[, fn:Function]):Socket
|
||||
|
||||
@@ -296,10 +362,9 @@ server.listen(3000);
|
||||
|
||||
The mechanics of leaving rooms are handled by the `Adapter`
|
||||
that has been configured (see `Server#adapter` above), defaulting to
|
||||
[socket.io-adapter](https://github.com/Automattic/socket.io-adapter).
|
||||
[socket.io-adapter](https://github.com/socketio/socket.io-adapter).
|
||||
|
||||
### Socket#to(room:String):Socket
|
||||
### Socket#in(room:String):Socket
|
||||
|
||||
Sets a modifier for a subsequent event emission that the event will
|
||||
only be _broadcasted_ to sockets that have joined the given `room`.
|
||||
@@ -313,6 +378,22 @@ server.listen(3000);
|
||||
});
|
||||
```
|
||||
|
||||
### Socket#in(room:String):Socket
|
||||
|
||||
Same as `Socket#to`
|
||||
|
||||
### Socket#compress(v:Boolean):Socket
|
||||
|
||||
Sets a modifier for a subsequent event emission that the event data will
|
||||
only be _compressed_ if the value is `true`. Defaults to `true` when you don't call the method.
|
||||
|
||||
```js
|
||||
var io = require('socket.io')();
|
||||
io.on('connection', function(socket){
|
||||
socket.compress(false).emit('an event', { some: 'data' });
|
||||
});
|
||||
```
|
||||
|
||||
### Client
|
||||
|
||||
The `Client` class represents an incoming transport (engine.io)
|
||||
@@ -331,7 +412,7 @@ server.listen(3000);
|
||||
|
||||
## Debug / logging
|
||||
|
||||
Socket.IO is powered by [debug](http://github.com/visionmedia/debug).
|
||||
Socket.IO is powered by [debug](https://github.com/visionmedia/debug).
|
||||
In order to see all the debug output, run your app with the environment variable
|
||||
`DEBUG` including the desired scope.
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@ $ npm install
|
||||
$ node .
|
||||
```
|
||||
|
||||
And point your browser to `http://localhost:3000`. Optionally specify
|
||||
And point your browser to `http://localhost:3000`. Optionally, specify
|
||||
a port by supplying the `PORT` env variable.
|
||||
|
||||
## Features
|
||||
|
||||
- Multiple users can join a chat room by entering a unique username
|
||||
- Multiple users can join a chat room by each entering a unique username
|
||||
on website load.
|
||||
- Users can type chat messages to the chat room
|
||||
- Users can type chat messages to the chat room.
|
||||
- A notification is sent to all users when a user joins or leaves
|
||||
the chatroom
|
||||
the chatroom.
|
||||
|
||||
@@ -14,8 +14,6 @@ app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// Chatroom
|
||||
|
||||
// usernames which are currently connected to the chat
|
||||
var usernames = {};
|
||||
var numUsers = 0;
|
||||
|
||||
io.on('connection', function (socket) {
|
||||
@@ -32,10 +30,10 @@ io.on('connection', function (socket) {
|
||||
|
||||
// when the client emits 'add user', this listens and executes
|
||||
socket.on('add user', function (username) {
|
||||
if (addedUser) return;
|
||||
|
||||
// we store the username in the socket session for this client
|
||||
socket.username = username;
|
||||
// add the client's username to the global list
|
||||
usernames[username] = username;
|
||||
++numUsers;
|
||||
addedUser = true;
|
||||
socket.emit('login', {
|
||||
@@ -64,9 +62,7 @@ io.on('connection', function (socket) {
|
||||
|
||||
// when the user disconnects.. perform this
|
||||
socket.on('disconnect', function () {
|
||||
// remove the username from global usernames list
|
||||
if (addedUser) {
|
||||
delete usernames[socket.username];
|
||||
--numUsers;
|
||||
|
||||
// echo globally that this client has left
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "socket.io-chat",
|
||||
"version": "0.0.0",
|
||||
"description": "A simple chat client using socket.io",
|
||||
"main": "app.js",
|
||||
"main": "index.js",
|
||||
"author": "Grant Timmerman",
|
||||
"private": true,
|
||||
"license": "BSD",
|
||||
|
||||
@@ -7,7 +7,7 @@ $(function() {
|
||||
'#3b88eb', '#3824aa', '#a700ff', '#d300e7'
|
||||
];
|
||||
|
||||
// Initialize varibles
|
||||
// Initialize variables
|
||||
var $window = $(window);
|
||||
var $usernameInput = $('.usernameInput'); // Input for username
|
||||
var $messages = $('.messages'); // Messages area
|
||||
@@ -30,7 +30,7 @@ $(function() {
|
||||
if (data.numUsers === 1) {
|
||||
message += "there's 1 participant";
|
||||
} else {
|
||||
message += "there're " + data.numUsers + " participants";
|
||||
message += "there are " + data.numUsers + " participants";
|
||||
}
|
||||
log(message);
|
||||
}
|
||||
@@ -229,7 +229,7 @@ $(function() {
|
||||
socket.on('login', function (data) {
|
||||
connected = true;
|
||||
// Display the welcome message
|
||||
var message = "Welcome to Socket.IO Chat — ";
|
||||
var message = "Welcome to Socket.IO Chat – ";
|
||||
log(message, {
|
||||
prepend: true
|
||||
});
|
||||
@@ -263,4 +263,4 @@ $(function() {
|
||||
socket.on('stop typing', function (data) {
|
||||
removeChatTyping(data);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
}
|
||||
|
||||
html {
|
||||
font-weight: 300;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html, input {
|
||||
font-family:
|
||||
"HelveticaNeue-Light",
|
||||
"Helvetica Neue Light",
|
||||
@@ -13,8 +18,6 @@ html {
|
||||
Arial,
|
||||
"Lucida Grande",
|
||||
sans-serif;
|
||||
font-weight: 300;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html, body {
|
||||
@@ -144,4 +147,4 @@ ul {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ module.exports = Client;
|
||||
* Client constructor.
|
||||
*
|
||||
* @param {Server} server instance
|
||||
* @param {Socket} connection
|
||||
* @param {Socket} conn
|
||||
* @api private
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@ function Client(server, conn){
|
||||
this.id = conn.id;
|
||||
this.request = conn.request;
|
||||
this.setup();
|
||||
this.sockets = [];
|
||||
this.sockets = {};
|
||||
this.nsps = {};
|
||||
this.connectBuffer = [];
|
||||
}
|
||||
@@ -42,22 +42,30 @@ function Client(server, conn){
|
||||
Client.prototype.setup = function(){
|
||||
this.onclose = this.onclose.bind(this);
|
||||
this.ondata = this.ondata.bind(this);
|
||||
this.onerror = this.onerror.bind(this);
|
||||
this.ondecoded = this.ondecoded.bind(this);
|
||||
|
||||
this.decoder.on('decoded', this.ondecoded);
|
||||
this.conn.on('data', this.ondata);
|
||||
this.conn.on('error', this.onerror);
|
||||
this.conn.on('close', this.onclose);
|
||||
};
|
||||
|
||||
/**
|
||||
* Connects a client to a namespace.
|
||||
*
|
||||
* @param {String} namespace name
|
||||
* @param {String} name namespace
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.connect = function(name){
|
||||
debug('connecting to namespace %s', name);
|
||||
var nsp = this.server.of(name);
|
||||
var nsp = this.server.nsps[name];
|
||||
if (!nsp) {
|
||||
this.packet({ type: parser.ERROR, nsp: name, data : 'Invalid namespace'});
|
||||
return;
|
||||
}
|
||||
|
||||
if ('/' != name && !this.nsps['/']) {
|
||||
this.connectBuffer.push(name);
|
||||
return;
|
||||
@@ -65,12 +73,12 @@ Client.prototype.connect = function(name){
|
||||
|
||||
var self = this;
|
||||
var socket = nsp.add(this, function(){
|
||||
self.sockets.push(socket);
|
||||
self.sockets[socket.id] = socket;
|
||||
self.nsps[nsp.name] = socket;
|
||||
|
||||
if ('/' == nsp.name && self.connectBuffer) {
|
||||
if ('/' == nsp.name && self.connectBuffer.length > 0) {
|
||||
self.connectBuffer.forEach(self.connect, self);
|
||||
delete self.connectBuffer;
|
||||
self.connectBuffer = [];
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -82,12 +90,12 @@ Client.prototype.connect = function(name){
|
||||
*/
|
||||
|
||||
Client.prototype.disconnect = function(){
|
||||
var socket;
|
||||
// we don't use a for loop because the length of
|
||||
// `sockets` changes upon each iteration
|
||||
while (socket = this.sockets.shift()) {
|
||||
socket.disconnect();
|
||||
for (var id in this.sockets) {
|
||||
if (this.sockets.hasOwnProperty(id)) {
|
||||
this.sockets[id].disconnect();
|
||||
}
|
||||
}
|
||||
this.sockets = {};
|
||||
this.close();
|
||||
};
|
||||
|
||||
@@ -98,10 +106,9 @@ Client.prototype.disconnect = function(){
|
||||
*/
|
||||
|
||||
Client.prototype.remove = function(socket){
|
||||
var i = this.sockets.indexOf(socket);
|
||||
if (~i) {
|
||||
var nsp = this.sockets[i].nsp.name;
|
||||
this.sockets.splice(i, 1);
|
||||
if (this.sockets.hasOwnProperty(socket.id)) {
|
||||
var nsp = this.sockets[socket.id].nsp.name;
|
||||
delete this.sockets[socket.id];
|
||||
delete this.nsps[nsp];
|
||||
} else {
|
||||
debug('ignoring remove for %s', socket.id);
|
||||
@@ -126,25 +133,25 @@ Client.prototype.close = function(){
|
||||
* Writes a packet to the transport.
|
||||
*
|
||||
* @param {Object} packet object
|
||||
* @param {Boolean} whether packet is already encoded
|
||||
* @param {Boolean} whether packet is volatile
|
||||
* @param {Object} opts
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.packet = function(packet, preEncoded, volatile){
|
||||
Client.prototype.packet = function(packet, opts){
|
||||
opts = opts || {};
|
||||
var self = this;
|
||||
|
||||
// this writes to the actual connection
|
||||
function writeToEngine(encodedPackets) {
|
||||
if (volatile && !self.conn.transport.writable) return;
|
||||
if (opts.volatile && !self.conn.transport.writable) return;
|
||||
for (var i = 0; i < encodedPackets.length; i++) {
|
||||
self.conn.write(encodedPackets[i]);
|
||||
self.conn.write(encodedPackets[i], { compress: opts.compress });
|
||||
}
|
||||
}
|
||||
|
||||
if ('open' == this.conn.readyState) {
|
||||
debug('writing packet %j', packet);
|
||||
if(!preEncoded) { // not broadcasting, need to encode
|
||||
if (!opts.preEncoded) { // not broadcasting, need to encode
|
||||
this.encoder.encode(packet, function (encodedPackets) { // encode, then write results to engine
|
||||
writeToEngine(encodedPackets);
|
||||
});
|
||||
@@ -163,7 +170,12 @@ Client.prototype.packet = function(packet, preEncoded, volatile){
|
||||
*/
|
||||
|
||||
Client.prototype.ondata = function(data){
|
||||
this.decoder.add(data);
|
||||
// try/catch is needed for protocol violations (GH-1880)
|
||||
try {
|
||||
this.decoder.add(data);
|
||||
} catch(e) {
|
||||
this.onerror(e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -185,6 +197,22 @@ Client.prototype.ondecoded = function(packet) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an error.
|
||||
*
|
||||
* @param {Object} err object
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.onerror = function(err){
|
||||
for (var id in this.sockets) {
|
||||
if (this.sockets.hasOwnProperty(id)) {
|
||||
this.sockets[id].onerror(err);
|
||||
}
|
||||
}
|
||||
this.onclose('client error');
|
||||
};
|
||||
|
||||
/**
|
||||
* Called upon transport close.
|
||||
*
|
||||
@@ -199,10 +227,12 @@ Client.prototype.onclose = function(reason){
|
||||
this.destroy();
|
||||
|
||||
// `nsps` and `sockets` are cleaned up seamlessly
|
||||
var socket;
|
||||
while (socket = this.sockets.shift()) {
|
||||
socket.onclose(reason);
|
||||
for (var id in this.sockets) {
|
||||
if (this.sockets.hasOwnProperty(id)) {
|
||||
this.sockets[id].onclose(reason);
|
||||
}
|
||||
}
|
||||
this.sockets = {};
|
||||
|
||||
this.decoder.destroy(); // clean up decoder
|
||||
};
|
||||
@@ -215,6 +245,7 @@ Client.prototype.onclose = function(reason){
|
||||
|
||||
Client.prototype.destroy = function(){
|
||||
this.conn.removeListener('data', this.ondata);
|
||||
this.conn.removeListener('error', this.onerror);
|
||||
this.conn.removeListener('close', this.onclose);
|
||||
this.decoder.removeListener('decoded', this.ondecoded);
|
||||
};
|
||||
|
||||
90
lib/index.js
90
lib/index.js
@@ -5,7 +5,6 @@
|
||||
|
||||
var http = require('http');
|
||||
var read = require('fs').readFileSync;
|
||||
var parse = require('url').parse;
|
||||
var engine = require('engine.io');
|
||||
var client = require('socket.io-client');
|
||||
var clientVersion = require('socket.io-client/package').version;
|
||||
@@ -30,8 +29,8 @@ var clientSource = read(require.resolve('socket.io-client/socket.io.js'), 'utf-8
|
||||
/**
|
||||
* Server constructor.
|
||||
*
|
||||
* @param {http.Server|Number|Object} http server, port or options
|
||||
* @param {Object} options
|
||||
* @param {http.Server|Number|Object} srv http server, port or options
|
||||
* @param {Object} opts
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -54,21 +53,25 @@ function Server(srv, opts){
|
||||
/**
|
||||
* Server request verification function, that checks for allowed origins
|
||||
*
|
||||
* @param {http.IncomingMessage} request
|
||||
* @param {Function} callback to be called with the result: `fn(err, success)`
|
||||
* @param {http.IncomingMessage} req request
|
||||
* @param {Function} fn callback to be called with the result: `fn(err, success)`
|
||||
*/
|
||||
|
||||
Server.prototype.checkRequest = function(req, fn) {
|
||||
var origin = req.headers.origin || req.headers.referer;
|
||||
|
||||
// file:// URLs produce a null Origin which can't be authorized via echo-back
|
||||
if ('null' == origin) origin = '*';
|
||||
if ('null' == origin || null == origin) origin = '*';
|
||||
|
||||
if (!!origin && typeof(this._origins) == 'function') return this._origins(origin, fn);
|
||||
if (this._origins.indexOf('*:*') !== -1) return fn(null, true);
|
||||
if (origin) {
|
||||
try {
|
||||
var parts = url.parse(origin);
|
||||
parts.port = parts.port || 80;
|
||||
var defaultPort = 'https:' == parts.protocol ? 443 : 80;
|
||||
parts.port = parts.port != null
|
||||
? parts.port
|
||||
: defaultPort;
|
||||
var ok =
|
||||
~this._origins.indexOf(parts.hostname + ':' + parts.port) ||
|
||||
~this._origins.indexOf(parts.hostname + ':*') ||
|
||||
@@ -83,7 +86,7 @@ Server.prototype.checkRequest = function(req, fn) {
|
||||
/**
|
||||
* Sets/gets whether client code is being served.
|
||||
*
|
||||
* @param {Boolean} whether to serve client code
|
||||
* @param {Boolean} v whether to serve client code
|
||||
* @return {Server|Boolean} self when setting or value when getting
|
||||
* @api public
|
||||
*/
|
||||
@@ -136,7 +139,7 @@ Server.prototype.set = function(key, val){
|
||||
/**
|
||||
* Sets the client serving path.
|
||||
*
|
||||
* @param {String} pathname
|
||||
* @param {String} v pathname
|
||||
* @return {Server|String} self when setting or value when getting
|
||||
* @api public
|
||||
*/
|
||||
@@ -150,7 +153,7 @@ Server.prototype.path = function(v){
|
||||
/**
|
||||
* Sets the adapter for rooms.
|
||||
*
|
||||
* @param {Adapter} pathname
|
||||
* @param {Adapter} v pathname
|
||||
* @return {Server|Adapter} self when setting or value when getting
|
||||
* @api public
|
||||
*/
|
||||
@@ -169,7 +172,7 @@ Server.prototype.adapter = function(v){
|
||||
/**
|
||||
* Sets the allowed origins for requests.
|
||||
*
|
||||
* @param {String} origins
|
||||
* @param {String} v origins
|
||||
* @return {Server|Adapter} self when setting or value when getting
|
||||
* @api public
|
||||
*/
|
||||
@@ -193,7 +196,7 @@ Server.prototype.origins = function(v){
|
||||
Server.prototype.listen =
|
||||
Server.prototype.attach = function(srv, opts){
|
||||
if ('function' == typeof srv) {
|
||||
var msg = 'You are trying to attach socket.io to an express' +
|
||||
var msg = 'You are trying to attach socket.io to an express ' +
|
||||
'request handler function. Please pass a http.Server instance.';
|
||||
throw new Error(msg);
|
||||
}
|
||||
@@ -211,13 +214,14 @@ Server.prototype.attach = function(srv, opts){
|
||||
res.end();
|
||||
});
|
||||
srv.listen(port);
|
||||
|
||||
}
|
||||
|
||||
// set engine.io path to `/socket.io`
|
||||
opts = opts || {};
|
||||
opts.path = opts.path || '/socket.io';
|
||||
opts.path = opts.path || this.path();
|
||||
// set origins verification
|
||||
opts.allowRequest = this.checkRequest.bind(this);
|
||||
opts.allowRequest = opts.allowRequest || this.checkRequest.bind(this);
|
||||
|
||||
// initialize engine
|
||||
debug('creating engine.io instance with opts %j', opts);
|
||||
@@ -226,6 +230,9 @@ Server.prototype.attach = function(srv, opts){
|
||||
// attach static file serving
|
||||
if (this._serveClient) this.attachServe(srv);
|
||||
|
||||
// Export http server
|
||||
this.httpServer = srv;
|
||||
|
||||
// bind to engine events
|
||||
this.bind(this.eio);
|
||||
|
||||
@@ -235,7 +242,7 @@ Server.prototype.attach = function(srv, opts){
|
||||
/**
|
||||
* Attaches the static file serving.
|
||||
*
|
||||
* @param {Function|http.Server} http server
|
||||
* @param {Function|http.Server} srv http server
|
||||
* @api private
|
||||
*/
|
||||
|
||||
@@ -246,7 +253,7 @@ Server.prototype.attachServe = function(srv){
|
||||
var self = this;
|
||||
srv.removeAllListeners('request');
|
||||
srv.on('request', function(req, res) {
|
||||
if (0 == req.url.indexOf(url)) {
|
||||
if (0 === req.url.indexOf(url)) {
|
||||
self.serve(req, res);
|
||||
} else {
|
||||
for (var i = 0; i < evs.length; i++) {
|
||||
@@ -265,8 +272,9 @@ Server.prototype.attachServe = function(srv){
|
||||
*/
|
||||
|
||||
Server.prototype.serve = function(req, res){
|
||||
if (req.headers.etag) {
|
||||
if (clientVersion == req.headers.etag) {
|
||||
var etag = req.headers['if-none-match'];
|
||||
if (etag) {
|
||||
if (clientVersion == etag) {
|
||||
debug('serve client 304');
|
||||
res.writeHead(304);
|
||||
res.end();
|
||||
@@ -284,7 +292,7 @@ Server.prototype.serve = function(req, res){
|
||||
/**
|
||||
* Binds socket.io to an engine.io instance.
|
||||
*
|
||||
* @param {engine.Server} engine.io (or compatible) server
|
||||
* @param {engine.Server} engine engine.io (or compatible) server
|
||||
* @return {Server} self
|
||||
* @api public
|
||||
*/
|
||||
@@ -298,7 +306,7 @@ Server.prototype.bind = function(engine){
|
||||
/**
|
||||
* Called with each incoming transport connection.
|
||||
*
|
||||
* @param {engine.Socket} socket
|
||||
* @param {engine.Socket} conn
|
||||
* @return {Server} self
|
||||
* @api public
|
||||
*/
|
||||
@@ -313,26 +321,49 @@ Server.prototype.onconnection = function(conn){
|
||||
/**
|
||||
* Looks up a namespace.
|
||||
*
|
||||
* @param {String} nsp name
|
||||
* @param {Function} optional, nsp `connection` ev handler
|
||||
* @param {String} name nsp name
|
||||
* @param {Function} fn optional, nsp `connection` ev handler
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Server.prototype.of = function(name, fn){
|
||||
if (!this.nsps[name]) {
|
||||
if (String(name)[0] !== '/') name = '/' + name;
|
||||
|
||||
var nsp = this.nsps[name];
|
||||
if (!nsp) {
|
||||
debug('initializing namespace %s', name);
|
||||
var nsp = new Namespace(this, name);
|
||||
nsp = new Namespace(this, name);
|
||||
this.nsps[name] = nsp;
|
||||
}
|
||||
if (fn) this.nsps[name].on('connect', fn);
|
||||
return this.nsps[name];
|
||||
if (fn) nsp.on('connect', fn);
|
||||
return nsp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes server connection
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Server.prototype.close = function(){
|
||||
for (var id in this.nsps['/'].sockets) {
|
||||
if (this.nsps['/'].sockets.hasOwnProperty(id)) {
|
||||
this.nsps['/'].sockets[id].onclose();
|
||||
}
|
||||
}
|
||||
|
||||
this.engine.close();
|
||||
|
||||
if(this.httpServer){
|
||||
this.httpServer.close();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose main namespace (/).
|
||||
*/
|
||||
|
||||
['on', 'to', 'in', 'use', 'emit', 'send', 'write'].forEach(function(fn){
|
||||
['on', 'to', 'in', 'use', 'emit', 'send', 'write', 'clients', 'compress'].forEach(function(fn){
|
||||
Server.prototype[fn] = function(){
|
||||
var nsp = this.sockets[fn];
|
||||
return nsp.apply(this.sockets, arguments);
|
||||
@@ -340,8 +371,9 @@ Server.prototype.of = function(name, fn){
|
||||
});
|
||||
|
||||
Namespace.flags.forEach(function(flag){
|
||||
Server.prototype.__defineGetter__(flag, function(name){
|
||||
this.flags.push(name);
|
||||
Server.prototype.__defineGetter__(flag, function(){
|
||||
this.sockets.flags = this.sockets.flags || {};
|
||||
this.sockets.flags[flag] = true;
|
||||
return this;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,7 +7,7 @@ var Socket = require('./socket');
|
||||
var Emitter = require('events').EventEmitter;
|
||||
var parser = require('socket.io-parser');
|
||||
var debug = require('debug')('socket.io:namespace');
|
||||
var hasBin = require('has-binary-data');
|
||||
var hasBin = require('has-binary');
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
@@ -29,7 +29,10 @@ exports.events = [
|
||||
* Flags.
|
||||
*/
|
||||
|
||||
exports.flags = ['json'];
|
||||
exports.flags = [
|
||||
'json',
|
||||
'volatile'
|
||||
];
|
||||
|
||||
/**
|
||||
* `EventEmitter#emit` reference.
|
||||
@@ -48,11 +51,10 @@ var emit = Emitter.prototype.emit;
|
||||
function Namespace(server, name){
|
||||
this.name = name;
|
||||
this.server = server;
|
||||
this.sockets = [];
|
||||
this.sockets = {};
|
||||
this.connected = {};
|
||||
this.fns = [];
|
||||
this.ids = 0;
|
||||
this.acks = {};
|
||||
this.initAdapter();
|
||||
}
|
||||
|
||||
@@ -102,7 +104,7 @@ Namespace.prototype.use = function(fn){
|
||||
* Executes the middleware for an incoming client.
|
||||
*
|
||||
* @param {Socket} socket that will get added
|
||||
* @param {Function} last fn call in the middleware
|
||||
* @param {Function} fn last fn call in the middleware
|
||||
* @api private
|
||||
*/
|
||||
|
||||
@@ -158,7 +160,7 @@ Namespace.prototype.add = function(client, fn){
|
||||
if (err) return socket.error(err.data || err.message);
|
||||
|
||||
// track socket
|
||||
self.sockets.push(socket);
|
||||
self.sockets[socket.id] = socket;
|
||||
|
||||
// it's paramount that the internal `onconnect` logic
|
||||
// fires before user-set events to prevent state order
|
||||
@@ -185,9 +187,8 @@ Namespace.prototype.add = function(client, fn){
|
||||
*/
|
||||
|
||||
Namespace.prototype.remove = function(socket){
|
||||
var i = this.sockets.indexOf(socket);
|
||||
if (~i) {
|
||||
this.sockets.splice(i, 1);
|
||||
if (this.sockets.hasOwnProperty(socket.id)) {
|
||||
delete this.sockets[socket.id];
|
||||
} else {
|
||||
debug('ignoring remove for %s', socket.id);
|
||||
}
|
||||
@@ -240,3 +241,32 @@ Namespace.prototype.write = function(){
|
||||
this.emit.apply(this, args);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a list of clients.
|
||||
*
|
||||
* @return {Namespace} self
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Namespace.prototype.clients = function(fn){
|
||||
this.adapter.clients(this.rooms, fn);
|
||||
// delete rooms flag for scenario:
|
||||
// .in('room').clients() (GH-1978)
|
||||
delete this.rooms;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the compress flag.
|
||||
*
|
||||
* @param {Boolean} compress if `true`, compresses the sending data
|
||||
* @return {Socket} self
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Namespace.prototype.compress = function(compress){
|
||||
this.flags = this.flags || {};
|
||||
this.flags.compress = compress;
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ var Emitter = require('events').EventEmitter;
|
||||
var parser = require('socket.io-parser');
|
||||
var url = require('url');
|
||||
var debug = require('debug')('socket.io:socket');
|
||||
var hasBin = require('has-binary-data');
|
||||
var hasBin = require('has-binary');
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
@@ -59,11 +59,10 @@ function Socket(nsp, client){
|
||||
this.nsp = nsp;
|
||||
this.server = nsp.server;
|
||||
this.adapter = this.nsp.adapter;
|
||||
this.id = client.id;
|
||||
this.request = client.request;
|
||||
this.id = nsp.name + '#' + client.id;
|
||||
this.client = client;
|
||||
this.conn = client.conn;
|
||||
this.rooms = [];
|
||||
this.rooms = {};
|
||||
this.acks = {};
|
||||
this.connected = true;
|
||||
this.disconnected = false;
|
||||
@@ -89,7 +88,7 @@ flags.forEach(function(flag){
|
||||
});
|
||||
|
||||
/**
|
||||
* `request` engine.io shorcut.
|
||||
* `request` engine.io shortcut.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
@@ -108,7 +107,7 @@ Socket.prototype.buildHandshake = function(){
|
||||
return {
|
||||
headers: this.request.headers,
|
||||
time: (new Date) + '',
|
||||
address: this.request.connection.address(),
|
||||
address: this.conn.remoteAddress,
|
||||
xdomain: !!this.request.headers.origin,
|
||||
secure: !!this.request.connection.encrypted,
|
||||
issued: +(new Date),
|
||||
@@ -132,10 +131,11 @@ Socket.prototype.emit = function(ev){
|
||||
var packet = {};
|
||||
packet.type = hasBin(args) ? parser.BINARY_EVENT : parser.EVENT;
|
||||
packet.data = args;
|
||||
var flags = this.flags || {};
|
||||
|
||||
// access last argument to see if it's an ACK callback
|
||||
if ('function' == typeof args[args.length - 1]) {
|
||||
if (this._rooms || (this.flags && this.flags.broadcast)) {
|
||||
if (this._rooms || flags.broadcast) {
|
||||
throw new Error('Callbacks are not supported when broadcasting');
|
||||
}
|
||||
|
||||
@@ -144,15 +144,18 @@ Socket.prototype.emit = function(ev){
|
||||
packet.id = this.nsp.ids++;
|
||||
}
|
||||
|
||||
if (this._rooms || (this.flags && this.flags.broadcast)) {
|
||||
if (this._rooms || flags.broadcast) {
|
||||
this.adapter.broadcast(packet, {
|
||||
except: [this.id],
|
||||
rooms: this._rooms,
|
||||
flags: this.flags
|
||||
flags: flags
|
||||
});
|
||||
} else {
|
||||
// dispatch packet
|
||||
this.packet(packet);
|
||||
this.packet(packet, {
|
||||
volatile: flags.volatile,
|
||||
compress: flags.compress
|
||||
});
|
||||
}
|
||||
|
||||
// reset flags
|
||||
@@ -196,20 +199,22 @@ Socket.prototype.write = function(){
|
||||
* Writes a packet.
|
||||
*
|
||||
* @param {Object} packet object
|
||||
* @param {Object} opts options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.packet = function(packet, preEncoded){
|
||||
Socket.prototype.packet = function(packet, opts){
|
||||
packet.nsp = this.nsp.name;
|
||||
var volatile = this.flags && this.flags.volatile;
|
||||
this.client.packet(packet, preEncoded, volatile);
|
||||
opts = opts || {};
|
||||
opts.compress = false !== opts.compress;
|
||||
this.client.packet(packet, opts);
|
||||
};
|
||||
|
||||
/**
|
||||
* Joins a room.
|
||||
*
|
||||
* @param {String} room
|
||||
* @param {Function} optional, callback
|
||||
* @param {Function} fn optional, callback
|
||||
* @return {Socket} self
|
||||
* @api private
|
||||
*/
|
||||
@@ -217,11 +222,14 @@ Socket.prototype.packet = function(packet, preEncoded){
|
||||
Socket.prototype.join = function(room, fn){
|
||||
debug('joining room %s', room);
|
||||
var self = this;
|
||||
if (~this.rooms.indexOf(room)) return this;
|
||||
if (this.rooms.hasOwnProperty(room)) {
|
||||
fn && fn(null);
|
||||
return this;
|
||||
}
|
||||
this.adapter.add(this.id, room, function(err){
|
||||
if (err) return fn && fn(err);
|
||||
debug('joined room %s', room);
|
||||
self.rooms.push(room);
|
||||
self.rooms[room] = room;
|
||||
fn && fn(null);
|
||||
});
|
||||
return this;
|
||||
@@ -231,7 +239,7 @@ Socket.prototype.join = function(room, fn){
|
||||
* Leaves a room.
|
||||
*
|
||||
* @param {String} room
|
||||
* @param {Function} optional, callback
|
||||
* @param {Function} fn optional, callback
|
||||
* @return {Socket} self
|
||||
* @api private
|
||||
*/
|
||||
@@ -242,7 +250,7 @@ Socket.prototype.leave = function(room, fn){
|
||||
this.adapter.del(this.id, room, function(err){
|
||||
if (err) return fn && fn(err);
|
||||
debug('left room %s', room);
|
||||
self.rooms.splice(self.rooms.indexOf(room, 1));
|
||||
delete self.rooms[room];
|
||||
fn && fn(null);
|
||||
});
|
||||
return this;
|
||||
@@ -256,6 +264,7 @@ Socket.prototype.leave = function(room, fn){
|
||||
|
||||
Socket.prototype.leaveAll = function(){
|
||||
this.adapter.delAll(this.id);
|
||||
this.rooms = {};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -267,9 +276,9 @@ Socket.prototype.leaveAll = function(){
|
||||
|
||||
Socket.prototype.onconnect = function(){
|
||||
debug('socket connected - writing packet');
|
||||
this.nsp.connected[this.id] = this;
|
||||
this.join(this.id);
|
||||
this.packet({ type: parser.CONNECT });
|
||||
this.nsp.connected[this.id] = this;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -329,7 +338,7 @@ Socket.prototype.onevent = function(packet){
|
||||
/**
|
||||
* Produces an ack callback to emit with an event.
|
||||
*
|
||||
* @param {Number} packet id
|
||||
* @param {Number} id packet id
|
||||
* @api private
|
||||
*/
|
||||
|
||||
@@ -348,6 +357,8 @@ Socket.prototype.ack = function(id){
|
||||
type: type,
|
||||
data: args
|
||||
});
|
||||
|
||||
sent = true;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -379,10 +390,26 @@ Socket.prototype.ondisconnect = function(){
|
||||
this.onclose('client namespace disconnect');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a client error.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.onerror = function(err){
|
||||
if (this.listeners('error').length) {
|
||||
this.emit('error', err);
|
||||
} else {
|
||||
console.error('Missing error handler on `socket`.');
|
||||
console.error(err.stack);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called upon closing. Called by `Client`.
|
||||
*
|
||||
* @param {String} reason
|
||||
* @throw {Error} optional error object
|
||||
* @api private
|
||||
*/
|
||||
|
||||
@@ -401,7 +428,7 @@ Socket.prototype.onclose = function(reason){
|
||||
/**
|
||||
* Produces an `error` packet.
|
||||
*
|
||||
* @param {Object} error object
|
||||
* @param {Object} err error object
|
||||
* @api private
|
||||
*/
|
||||
|
||||
@@ -412,7 +439,7 @@ Socket.prototype.error = function(err){
|
||||
/**
|
||||
* Disconnects this client.
|
||||
*
|
||||
* @param {Boolean} if `true`, closes the underlying connection
|
||||
* @param {Boolean} close if `true`, closes the underlying connection
|
||||
* @return {Socket} self
|
||||
* @api public
|
||||
*/
|
||||
@@ -427,3 +454,17 @@ Socket.prototype.disconnect = function(close){
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the compress flag.
|
||||
*
|
||||
* @param {Boolean} compress if `true`, compresses the sending data
|
||||
* @return {Socket} self
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.compress = function(compress){
|
||||
this.flags = this.flags || {};
|
||||
this.flags.compress = compress;
|
||||
return this;
|
||||
};
|
||||
|
||||
29
package.json
29
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "socket.io",
|
||||
"version": "1.0.5",
|
||||
"version": "1.4.5",
|
||||
"description": "node.js realtime framework server",
|
||||
"keywords": [
|
||||
"realtime",
|
||||
@@ -11,27 +11,30 @@
|
||||
"socket",
|
||||
"io"
|
||||
],
|
||||
"main": "./lib/index",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/LearnBoost/socket.io"
|
||||
"url": "git://github.com/Automattic/socket.io"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
"test": "mocha --reporter dot --slow 200ms --bail"
|
||||
},
|
||||
"dependencies": {
|
||||
"engine.io": "1.3.0",
|
||||
"socket.io-parser": "2.2.0",
|
||||
"socket.io-client": "1.0.5",
|
||||
"socket.io-adapter": "0.2.0",
|
||||
"has-binary-data": "0.1.1",
|
||||
"debug": "0.7.4"
|
||||
"engine.io": "1.6.8",
|
||||
"socket.io-parser": "2.2.6",
|
||||
"socket.io-client": "1.4.5",
|
||||
"socket.io-adapter": "0.4.0",
|
||||
"has-binary": "0.1.7",
|
||||
"debug": "2.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "1.16.2",
|
||||
"expect.js": "0.3.1",
|
||||
"supertest": "0.8.2",
|
||||
"superagent": "0.17.0",
|
||||
"istanbul": "0.2.3"
|
||||
"istanbul": "0.4.1",
|
||||
"mocha": "2.3.4",
|
||||
"superagent": "1.6.1",
|
||||
"supertest": "1.1.0",
|
||||
"zuul-ngrok": "3.2.0"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
|
||||
11
test/fixtures/server-close.js
vendored
Normal file
11
test/fixtures/server-close.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
var server = require('http').createServer();
|
||||
var ioc = require('socket.io-client');
|
||||
var io = require('../..')(server);
|
||||
|
||||
var srv = server.listen(function() {
|
||||
var socket = ioc('ws://localhost:' + server.address().port);
|
||||
socket.on('connect', function() {
|
||||
io.close();
|
||||
socket.close();
|
||||
});
|
||||
});
|
||||
1207
test/socket.io.js
1207
test/socket.io.js
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user