mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-02-12 01:27:38 +01:00
init, just some testing
This commit is contained in:
3
node_modules/socket.io/.npmignore
generated
vendored
Normal file
3
node_modules/socket.io/.npmignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
support
|
||||
test
|
||||
examples
|
||||
6
node_modules/socket.io/.travis.yml
generated
vendored
Normal file
6
node_modules/socket.io/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.6
|
||||
|
||||
notifications:
|
||||
irc: "irc.freenode.org#socket.io"
|
||||
315
node_modules/socket.io/History.md
generated
vendored
Normal file
315
node_modules/socket.io/History.md
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
|
||||
0.9.14 / 2013-03-29
|
||||
===================
|
||||
|
||||
* manager: fix memory leak with SSL [jpallen]
|
||||
|
||||
0.9.13 / 2012-12-13
|
||||
===================
|
||||
|
||||
* package: fixed `base64id` requirement
|
||||
|
||||
0.9.12 / 2012-12-13
|
||||
===================
|
||||
|
||||
* manager: fix for latest node which is returning a clone with `listeners` [viirya]
|
||||
|
||||
0.9.11 / 2012-11-02
|
||||
===================
|
||||
|
||||
* package: move redis to optionalDependenices [3rd-Eden]
|
||||
* bumped client
|
||||
|
||||
0.9.10 / 2012-08-10
|
||||
===================
|
||||
|
||||
* Don't lowercase log messages
|
||||
* Always set the HTTP response in case an error should be returned to the client
|
||||
* Create or destroy the flash policy server on configuration change
|
||||
* Honour configuration to disable flash policy server
|
||||
* Add express 3.0 instructions on Readme.md
|
||||
* Bump client
|
||||
|
||||
0.9.9 / 2012-08-01
|
||||
==================
|
||||
|
||||
* Fixed sync disconnect xhrs handling
|
||||
* Put license text in its own file (#965)
|
||||
* Add warning to .listen() to ease the migration to Express 3.x
|
||||
* Restored compatibility with node 0.4.x
|
||||
|
||||
0.9.8 / 2012-07-24
|
||||
==================
|
||||
|
||||
* Bumped client.
|
||||
|
||||
0.9.7 / 2012-07-24
|
||||
==================
|
||||
|
||||
* Prevent crash when socket leaves a room twice.
|
||||
* Corrects unsafe usage of for..in
|
||||
* Fix for node 0.8 with `gzip compression` [vadimi]
|
||||
* Update redis to support Node 0.8.x
|
||||
* Made ID generation securely random
|
||||
* Fix Redis Store race condition in manager onOpen unsubscribe callback
|
||||
* Fix for EventEmitters always reusing the same Array instance for listeners
|
||||
|
||||
0.9.6 / 2012-04-17
|
||||
==================
|
||||
|
||||
* Fixed XSS in jsonp-polling.
|
||||
|
||||
0.9.5 / 2012-04-05
|
||||
==================
|
||||
|
||||
* Added test for polling and socket close.
|
||||
* Ensure close upon request close.
|
||||
* Fix disconnection reason being lost for polling transports.
|
||||
* Ensure that polling transports work with Connection: close.
|
||||
* Log disconnection reason.
|
||||
|
||||
0.9.4 / 2012-04-01
|
||||
==================
|
||||
|
||||
* Disconnecting from namespace improvement (#795) [DanielBaulig]
|
||||
* Bumped client with polling reconnection loop (#438)
|
||||
|
||||
0.9.3 / 2012-03-28
|
||||
==================
|
||||
|
||||
* Fix "Syntax error" on FF Web Console with XHR Polling [mikito]
|
||||
|
||||
0.9.2 / 2012-03-13
|
||||
==================
|
||||
|
||||
* More sensible close `timeout default` (fixes disconnect issue)
|
||||
|
||||
0.9.1-1 / 2012-03-02
|
||||
====================
|
||||
|
||||
* Bumped client with NPM dependency fix.
|
||||
|
||||
0.9.1 / 2012-03-02
|
||||
==================
|
||||
|
||||
* Changed heartbeat timeout and interval defaults (60 and 25 seconds)
|
||||
* Make tests work both on 0.4 and 0.6
|
||||
* Updated client (improvements + bug fixes).
|
||||
|
||||
0.9.0 / 2012-02-26
|
||||
==================
|
||||
|
||||
* Make it possible to use a regexp to match the socket.io resource URL.
|
||||
We need this because we have to prefix the socket.io URL with a variable ID.
|
||||
* Supplemental fix to gavinuhma/authfix, it looks like the same Access-Control-Origin logic is needed in the http and xhr-polling transports
|
||||
* Updated express dep for windows compatibility.
|
||||
* Combine two substr calls into one in decodePayload to improve performance
|
||||
* Minor documentation fix
|
||||
* Minor. Conform to style of other files.
|
||||
* Switching setting to 'match origin protocol'
|
||||
* Revert "Fixes leaking Redis subscriptions for #663. The local flag was not getting passed through onClientDisconnect()."
|
||||
* Revert "Handle leaked dispatch:[id] subscription."
|
||||
* Merge pull request #667 from dshaw/patch/redis-disconnect
|
||||
* Handle leaked dispatch:[id] subscription.
|
||||
* Fixes leaking Redis subscriptions for #663. The local flag was not getting passed through onClientDisconnect().
|
||||
* Prevent memory leaking on uncompleted requests & add max post size limitation
|
||||
* Fix for testcase
|
||||
* Set Access-Control-Allow-Credentials true, regardless of cookie
|
||||
* Remove assertvarnish from package as it breaks on 0.6
|
||||
* Correct irc channel
|
||||
* Added proper return after reserved field error
|
||||
* Fixes manager.js failure to close connection after transport error has happened
|
||||
* Added implicit port 80 for origin checks. fixes #638
|
||||
* Fixed bug #432 in 0.8.7
|
||||
* Set Access-Control-Allow-Origin header to origin to enable withCredentials
|
||||
* Adding configuration variable matchOriginProtocol
|
||||
* Fixes location mismatch error in Safari.
|
||||
* Use tty to detect if we should add colors or not by default.
|
||||
* Updated the package location.
|
||||
|
||||
0.8.7 / 2011-11-05
|
||||
==================
|
||||
|
||||
* Fixed memory leaks in closed clients.
|
||||
* Fixed memory leaks in namespaces.
|
||||
* Fixed websocket handling for malformed requests from proxies. [einaros]
|
||||
* Node 0.6 compatibility. [einaros] [3rd-Eden]
|
||||
* Adapted tests and examples.
|
||||
|
||||
0.8.6 / 2011-10-27
|
||||
==================
|
||||
|
||||
* Added JSON decoding on jsonp-polling transport.
|
||||
* Fixed README example.
|
||||
* Major speed optimizations [3rd-Eden] [einaros] [visionmedia]
|
||||
* Added decode/encode benchmarks [visionmedia]
|
||||
* Added support for black-listing client sent events.
|
||||
* Fixed logging options, closes #540 [3rd-Eden]
|
||||
* Added vary header for gzip [3rd-Eden]
|
||||
* Properly cleaned up async websocket / flashsocket tests, after patching node-websocket-client
|
||||
* Patched to properly shut down when a finishClose call is made during connection establishment
|
||||
* Added support for socket.io version on url and far-future Expires [3rd-Eden] [getify]
|
||||
* Began IE10 compatibility [einaros] [tbranyen]
|
||||
* Misc WebSocket fixes [einaros]
|
||||
* Added UTF8 to respone headers for htmlfile [3rd-Eden]
|
||||
|
||||
0.8.5 / 2011-10-07
|
||||
==================
|
||||
|
||||
* Added websocket draft HyBi-16 support. [einaros]
|
||||
* Fixed websocket continuation bugs. [einaros]
|
||||
* Fixed flashsocket transport name.
|
||||
* Fixed websocket tests.
|
||||
* Ensured `parser#decodePayload` doesn't choke.
|
||||
* Added http referrer verification to manager verifyOrigin.
|
||||
* Added access control for cross domain xhr handshakes [3rd-Eden]
|
||||
* Added support for automatic generation of socket.io files [3rd-Eden]
|
||||
* Added websocket binary support [einaros]
|
||||
* Added gzip support for socket.io.js [3rd-Eden]
|
||||
* Expose socket.transport [3rd-Eden]
|
||||
* Updated client.
|
||||
|
||||
0.8.4 / 2011-09-06
|
||||
==================
|
||||
|
||||
* Client build
|
||||
|
||||
0.8.3 / 2011-09-03
|
||||
==================
|
||||
|
||||
* Fixed `\n` parsing for non-JSON packets (fixes #479).
|
||||
* Fixed parsing of certain unicode characters (fixes #451).
|
||||
* Fixed transport message packet logging.
|
||||
* Fixed emission of `error` event resulting in an uncaught exception if unhandled (fixes #476).
|
||||
* Fixed; allow for falsy values as the configuration value of `log level` (fixes #491).
|
||||
* Fixed repository URI in `package.json`. Fixes #504.
|
||||
* Added text/plain content-type to handshake responses [einaros]
|
||||
* Improved single byte writes [einaros]
|
||||
* Updated socket.io-flashsocket default port from 843 to 10843 [3rd-Eden]
|
||||
* Updated client.
|
||||
|
||||
0.8.2 / 2011-08-29
|
||||
==================
|
||||
|
||||
* Updated client.
|
||||
|
||||
0.8.1 / 2011-08-29
|
||||
==================
|
||||
|
||||
* Fixed utf8 bug in send framing in websocket [einaros]
|
||||
* Fixed typo in docs [Znarkus]
|
||||
* Fixed bug in send framing for over 64kB of data in websocket [einaros]
|
||||
* Corrected ping handling in websocket transport [einaros]
|
||||
|
||||
0.8.0 / 2011-08-28
|
||||
==================
|
||||
|
||||
* Updated to work with two-level websocket versioning. [einaros]
|
||||
* Added hybi07 support. [einaros]
|
||||
* Added hybi10 support. [einaros]
|
||||
* Added http referrer verification to manager.js verifyOrigin. [einaors]
|
||||
|
||||
0.7.11 / 2011-08-27
|
||||
===================
|
||||
|
||||
* Updated socket.io-client.
|
||||
|
||||
0.7.10 / 2011-08-27
|
||||
===================
|
||||
|
||||
* Updated socket.io-client.
|
||||
|
||||
0.7.9 / 2011-08-12
|
||||
==================
|
||||
|
||||
* Updated socket.io-client.
|
||||
* Make sure we only do garbage collection when the server we receive is actually run.
|
||||
|
||||
0.7.8 / 2011-08-08
|
||||
==================
|
||||
|
||||
* Changed; make sure sio#listen passes options to both HTTP server and socket.io manager.
|
||||
* Added docs for sio#listen.
|
||||
* Added options parameter support for Manager constructor.
|
||||
* Added memory leaks tests and test-leaks Makefile task.
|
||||
* Removed auto npm-linking from make test.
|
||||
* Make sure that you can disable heartbeats. [3rd-Eden]
|
||||
* Fixed rooms memory leak [3rd-Eden]
|
||||
* Send response once we got all POST data, not immediately [Pita]
|
||||
* Fixed onLeave behavior with missing clientsk [3rd-Eden]
|
||||
* Prevent duplicate references in rooms.
|
||||
* Added alias for `to` to `in` and `in` to `to`.
|
||||
* Fixed roomClients definition.
|
||||
* Removed dependency on redis for installation without npm [3rd-Eden]
|
||||
* Expose path and querystring in handshakeData [3rd-Eden]
|
||||
|
||||
0.7.7 / 2011-07-12
|
||||
==================
|
||||
|
||||
* Fixed double dispatch handling with emit to closed clients.
|
||||
* Added test for emitting to closed clients to prevent regression.
|
||||
* Fixed race condition in redis test.
|
||||
* Changed Transport#end instrumentation.
|
||||
* Leveraged $emit instead of emit internally.
|
||||
* Made tests faster.
|
||||
* Fixed double disconnect events.
|
||||
* Fixed disconnect logic
|
||||
* Simplified remote events handling in Socket.
|
||||
* Increased testcase timeout.
|
||||
* Fixed unknown room emitting (GH-291). [3rd-Eden]
|
||||
* Fixed `address` in handshakeData. [3rd-Eden]
|
||||
* Removed transports definition in chat example.
|
||||
* Fixed room cleanup
|
||||
* Fixed; make sure the client is cleaned up after booting.
|
||||
* Make sure to mark the client as non-open if the connection is closed.
|
||||
* Removed unneeded `buffer` declarations.
|
||||
* Fixed; make sure to clear socket handlers and subscriptions upon transport close.
|
||||
|
||||
0.7.6 / 2011-06-30
|
||||
==================
|
||||
|
||||
* Fixed general dispatching when a client has closed.
|
||||
|
||||
0.7.5 / 2011-06-30
|
||||
==================
|
||||
|
||||
* Fixed dispatching to clients that are disconnected.
|
||||
|
||||
0.7.4 / 2011-06-30
|
||||
==================
|
||||
|
||||
* Fixed; only clear handlers if they were set. [level09]
|
||||
|
||||
0.7.3 / 2011-06-30
|
||||
==================
|
||||
|
||||
* Exposed handshake data to clients.
|
||||
* Refactored dispatcher interface.
|
||||
* Changed; Moved id generation method into the manager.
|
||||
* Added sub-namespace authorization. [3rd-Eden]
|
||||
* Changed; normalized SocketNamespace local eventing [dvv]
|
||||
* Changed; Use packet.reason or default to 'packet' [3rd-Eden]
|
||||
* Changed console.error to console.log.
|
||||
* Fixed; bind both servers at the same time do that the test never times out.
|
||||
* Added 304 support.
|
||||
* Removed `Transport#name` for abstract interface.
|
||||
* Changed; lazily require http and https module only when needed. [3rd-Eden]
|
||||
|
||||
0.7.2 / 2011-06-22
|
||||
==================
|
||||
|
||||
* Make sure to write a packet (of type `noop`) when closing a poll.
|
||||
This solves a problem with cross-domain requests being flagged as aborted and
|
||||
reconnection being triggered.
|
||||
* Added `noop` message type.
|
||||
|
||||
0.7.1 / 2011-06-21
|
||||
==================
|
||||
|
||||
* Fixed cross-domain XHR.
|
||||
* Added CORS test to xhr-polling suite.
|
||||
|
||||
0.7.0 / 2010-06-21
|
||||
==================
|
||||
|
||||
* http://socket.io/announcement.html
|
||||
22
node_modules/socket.io/LICENSE
generated
vendored
Normal file
22
node_modules/socket.io/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
31
node_modules/socket.io/Makefile
generated
vendored
Normal file
31
node_modules/socket.io/Makefile
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
ALL_TESTS = $(shell find test/ -name '*.test.js')
|
||||
ALL_BENCH = $(shell find benchmarks -name '*.bench.js')
|
||||
|
||||
run-tests:
|
||||
@./node_modules/.bin/expresso \
|
||||
-t 3000 \
|
||||
-I support \
|
||||
--serial \
|
||||
$(TESTFLAGS) \
|
||||
$(TESTS)
|
||||
|
||||
test:
|
||||
@$(MAKE) NODE_PATH=lib TESTS="$(ALL_TESTS)" run-tests
|
||||
|
||||
test-cov:
|
||||
@TESTFLAGS=--cov $(MAKE) test
|
||||
|
||||
test-leaks:
|
||||
@ls test/leaks/* | xargs node --expose_debug_as=debug --expose_gc
|
||||
|
||||
run-bench:
|
||||
@node $(PROFILEFLAGS) benchmarks/runner.js
|
||||
|
||||
bench:
|
||||
@$(MAKE) BENCHMARKS="$(ALL_BENCH)" run-bench
|
||||
|
||||
profile:
|
||||
@PROFILEFLAGS='--prof --trace-opt --trace-bailout --trace-deopt' $(MAKE) bench
|
||||
|
||||
.PHONY: test bench profile
|
||||
364
node_modules/socket.io/Readme.md
generated
vendored
Normal file
364
node_modules/socket.io/Readme.md
generated
vendored
Normal file
@@ -0,0 +1,364 @@
|
||||
# Socket.IO
|
||||
|
||||
Socket.IO is a Node.JS project that makes WebSockets and realtime possible in
|
||||
all browsers. It also enhances WebSockets by providing built-in multiplexing,
|
||||
horizontal scalability, automatic JSON encoding/decoding, and more.
|
||||
|
||||
## How to Install
|
||||
|
||||
```bash
|
||||
npm install socket.io
|
||||
```
|
||||
|
||||
## How to use
|
||||
|
||||
First, require `socket.io`:
|
||||
|
||||
```js
|
||||
var io = require('socket.io');
|
||||
```
|
||||
|
||||
Next, attach it to a HTTP/HTTPS server. If you're using the fantastic `express`
|
||||
web framework:
|
||||
|
||||
#### Express 3.x
|
||||
|
||||
```js
|
||||
var app = express()
|
||||
, server = require('http').createServer(app)
|
||||
, io = io.listen(server);
|
||||
|
||||
server.listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.emit('news', { hello: 'world' });
|
||||
socket.on('my other event', function (data) {
|
||||
console.log(data);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### Express 2.x
|
||||
|
||||
```js
|
||||
var app = express.createServer()
|
||||
, io = io.listen(app);
|
||||
|
||||
app.listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.emit('news', { hello: 'world' });
|
||||
socket.on('my other event', function (data) {
|
||||
console.log(data);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Finally, load it from the client side code:
|
||||
|
||||
```html
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script>
|
||||
var socket = io.connect('http://localhost');
|
||||
socket.on('news', function (data) {
|
||||
console.log(data);
|
||||
socket.emit('my other event', { my: 'data' });
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
For more thorough examples, look at the `examples/` directory.
|
||||
|
||||
## Short recipes
|
||||
|
||||
### Sending and receiving events.
|
||||
|
||||
Socket.IO allows you to emit and receive custom events.
|
||||
Besides `connect`, `message` and `disconnect`, you can emit custom events:
|
||||
|
||||
```js
|
||||
// note, io.listen(<port>) will create a http server for you
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
io.sockets.emit('this', { will: 'be received by everyone' });
|
||||
|
||||
socket.on('private message', function (from, msg) {
|
||||
console.log('I received a private message by ', from, ' saying ', msg);
|
||||
});
|
||||
|
||||
socket.on('disconnect', function () {
|
||||
io.sockets.emit('user disconnected');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Storing data associated to a client
|
||||
|
||||
Sometimes it's necessary to store data associated with a client that's
|
||||
necessary for the duration of the session.
|
||||
|
||||
#### Server side
|
||||
|
||||
```js
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.on('set nickname', function (name) {
|
||||
socket.set('nickname', name, function () { socket.emit('ready'); });
|
||||
});
|
||||
|
||||
socket.on('msg', function () {
|
||||
socket.get('nickname', function (err, name) {
|
||||
console.log('Chat message by ', name);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### Client side
|
||||
|
||||
```html
|
||||
<script>
|
||||
var socket = io.connect('http://localhost');
|
||||
|
||||
socket.on('connect', function () {
|
||||
socket.emit('set nickname', prompt('What is your nickname?'));
|
||||
socket.on('ready', function () {
|
||||
console.log('Connected !');
|
||||
socket.emit('msg', prompt('What is your message?'));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Restricting yourself to a namespace
|
||||
|
||||
If you have control over all the messages and events emitted for a particular
|
||||
application, using the default `/` namespace works.
|
||||
|
||||
If you want to leverage 3rd-party code, or produce code to share with others,
|
||||
socket.io provides a way of namespacing a `socket`.
|
||||
|
||||
This has the benefit of `multiplexing` a single connection. Instead of
|
||||
socket.io using two `WebSocket` connections, it'll use one.
|
||||
|
||||
The following example defines a socket that listens on '/chat' and one for
|
||||
'/news':
|
||||
|
||||
#### Server side
|
||||
|
||||
```js
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
var chat = io
|
||||
.of('/chat')
|
||||
.on('connection', function (socket) {
|
||||
socket.emit('a message', { that: 'only', '/chat': 'will get' });
|
||||
chat.emit('a message', { everyone: 'in', '/chat': 'will get' });
|
||||
});
|
||||
|
||||
var news = io
|
||||
.of('/news');
|
||||
.on('connection', function (socket) {
|
||||
socket.emit('item', { news: 'item' });
|
||||
});
|
||||
```
|
||||
|
||||
#### Client side:
|
||||
|
||||
```html
|
||||
<script>
|
||||
var chat = io.connect('http://localhost/chat')
|
||||
, news = io.connect('http://localhost/news');
|
||||
|
||||
chat.on('connect', function () {
|
||||
chat.emit('hi!');
|
||||
});
|
||||
|
||||
news.on('news', function () {
|
||||
news.emit('woot');
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Sending volatile messages.
|
||||
|
||||
Sometimes certain messages can be dropped. Let's say you have an app that
|
||||
shows realtime tweets for the keyword `bieber`.
|
||||
|
||||
If a certain client is not ready to receive messages (because of network slowness
|
||||
or other issues, or because he's connected through long polling and is in the
|
||||
middle of a request-response cycle), if he doesn't receive ALL the tweets related
|
||||
to bieber your application won't suffer.
|
||||
|
||||
In that case, you might want to send those messages as volatile messages.
|
||||
|
||||
#### Server side
|
||||
|
||||
```js
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
var tweets = setInterval(function () {
|
||||
getBieberTweet(function (tweet) {
|
||||
socket.volatile.emit('bieber tweet', tweet);
|
||||
});
|
||||
}, 100);
|
||||
|
||||
socket.on('disconnect', function () {
|
||||
clearInterval(tweets);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### Client side
|
||||
|
||||
In the client side, messages are received the same way whether they're volatile
|
||||
or not.
|
||||
|
||||
### Getting acknowledgements
|
||||
|
||||
Sometimes, you might want to get a callback when the client confirmed the message
|
||||
reception.
|
||||
|
||||
To do this, simply pass a function as the last parameter of `.send` or `.emit`.
|
||||
What's more, when you use `.emit`, the acknowledgement is done by you, which
|
||||
means you can also pass data along:
|
||||
|
||||
#### Server side
|
||||
|
||||
```js
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.on('ferret', function (name, fn) {
|
||||
fn('woot');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### Client side
|
||||
|
||||
```html
|
||||
<script>
|
||||
var socket = io.connect(); // TIP: .connect with no args does auto-discovery
|
||||
socket.on('connect', function () { // TIP: you can avoid listening on `connect` and listen on events directly too!
|
||||
socket.emit('ferret', 'tobi', function (data) {
|
||||
console.log(data); // data will be 'woot'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Broadcasting messages
|
||||
|
||||
To broadcast, simply add a `broadcast` flag to `emit` and `send` method calls.
|
||||
Broadcasting means sending a message to everyone else except for the socket
|
||||
that starts it.
|
||||
|
||||
#### Server side
|
||||
|
||||
```js
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.broadcast.emit('user connected');
|
||||
socket.broadcast.json.send({ a: 'message' });
|
||||
});
|
||||
```
|
||||
|
||||
### Rooms
|
||||
|
||||
Sometimes you want to put certain sockets in the same room, so that it's easy
|
||||
to broadcast to all of them together.
|
||||
|
||||
Think of this as built-in channels for sockets. Sockets `join` and `leave`
|
||||
rooms in each socket.
|
||||
|
||||
#### Server side
|
||||
|
||||
```js
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.join('justin bieber fans');
|
||||
socket.broadcast.to('justin bieber fans').emit('new fan');
|
||||
io.sockets.in('rammstein fans').emit('new non-fan');
|
||||
});
|
||||
```
|
||||
|
||||
### Using it just as a cross-browser WebSocket
|
||||
|
||||
If you just want the WebSocket semantics, you can do that too.
|
||||
Simply leverage `send` and listen on the `message` event:
|
||||
|
||||
#### Server side
|
||||
|
||||
```js
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
io.sockets.on('connection', function (socket) {
|
||||
socket.on('message', function () { });
|
||||
socket.on('disconnect', function () { });
|
||||
});
|
||||
```
|
||||
|
||||
#### Client side
|
||||
|
||||
```html
|
||||
<script>
|
||||
var socket = io.connect('http://localhost/');
|
||||
socket.on('connect', function () {
|
||||
socket.send('hi');
|
||||
|
||||
socket.on('message', function (msg) {
|
||||
// my msg
|
||||
});
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Changing configuration
|
||||
|
||||
Configuration in socket.io is TJ-style:
|
||||
|
||||
#### Server side
|
||||
|
||||
```js
|
||||
var io = require('socket.io').listen(80);
|
||||
|
||||
io.configure(function () {
|
||||
io.set('transports', ['websocket', 'flashsocket', 'xhr-polling']);
|
||||
});
|
||||
|
||||
io.configure('development', function () {
|
||||
io.set('transports', ['websocket', 'xhr-polling']);
|
||||
io.enable('log');
|
||||
});
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011 Guillermo Rauch <guillermo@learnboost.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
1
node_modules/socket.io/TODO
generated
vendored
Normal file
1
node_modules/socket.io/TODO
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
- Serve .swf client for engine.io
|
||||
64
node_modules/socket.io/benchmarks/decode.bench.js
generated
vendored
Normal file
64
node_modules/socket.io/benchmarks/decode.bench.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var benchmark = require('benchmark')
|
||||
, colors = require('colors')
|
||||
, io = require('../')
|
||||
, parser = io.parser
|
||||
, suite = new benchmark.Suite('Decode packet');
|
||||
|
||||
suite.add('string', function () {
|
||||
parser.decodePacket('4:::"2"');
|
||||
});
|
||||
|
||||
suite.add('event', function () {
|
||||
parser.decodePacket('5:::{"name":"woot"}');
|
||||
});
|
||||
|
||||
suite.add('event+ack', function () {
|
||||
parser.decodePacket('5:1+::{"name":"tobi"}');
|
||||
});
|
||||
|
||||
suite.add('event+data', function () {
|
||||
parser.decodePacket('5:::{"name":"edwald","args":[{"a": "b"},2,"3"]}');
|
||||
});
|
||||
|
||||
suite.add('heartbeat', function () {
|
||||
parser.decodePacket('2:::');
|
||||
});
|
||||
|
||||
suite.add('error', function () {
|
||||
parser.decodePacket('7:::2+0');
|
||||
});
|
||||
|
||||
var payload = parser.encodePayload([
|
||||
parser.encodePacket({ type: 'message', data: '5', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: '53d', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobar', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobarbaz', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobarbazfoobarbaz', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobarbaz', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobar', endpoint: '' })
|
||||
]);
|
||||
|
||||
suite.add('payload', function () {
|
||||
parser.decodePayload(payload);
|
||||
});
|
||||
|
||||
suite.on('cycle', function (bench, details) {
|
||||
console.log('\n' + suite.name.grey, details.name.white.bold);
|
||||
console.log([
|
||||
details.hz.toFixed(2).cyan + ' ops/sec'.grey
|
||||
, details.count.toString().white + ' times executed'.grey
|
||||
, 'benchmark took '.grey + details.times.elapsed.toString().white + ' sec.'.grey
|
||||
,
|
||||
].join(', '.grey));
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
suite.run();
|
||||
} else {
|
||||
module.exports = suite;
|
||||
}
|
||||
90
node_modules/socket.io/benchmarks/encode.bench.js
generated
vendored
Normal file
90
node_modules/socket.io/benchmarks/encode.bench.js
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var benchmark = require('benchmark')
|
||||
, colors = require('colors')
|
||||
, io = require('../')
|
||||
, parser = io.parser
|
||||
, suite = new benchmark.Suite('Encode packet');
|
||||
|
||||
suite.add('string', function () {
|
||||
parser.encodePacket({
|
||||
type: 'json'
|
||||
, endpoint: ''
|
||||
, data: '2'
|
||||
});
|
||||
});
|
||||
|
||||
suite.add('event', function () {
|
||||
parser.encodePacket({
|
||||
type: 'event'
|
||||
, name: 'woot'
|
||||
, endpoint: ''
|
||||
, args: []
|
||||
});
|
||||
});
|
||||
|
||||
suite.add('event+ack', function () {
|
||||
parser.encodePacket({
|
||||
type: 'json'
|
||||
, id: 1
|
||||
, ack: 'data'
|
||||
, endpoint: ''
|
||||
, data: { a: 'b' }
|
||||
});
|
||||
});
|
||||
|
||||
suite.add('event+data', function () {
|
||||
parser.encodePacket({
|
||||
type: 'event'
|
||||
, name: 'edwald'
|
||||
, endpoint: ''
|
||||
, args: [{a: 'b'}, 2, '3']
|
||||
});
|
||||
});
|
||||
|
||||
suite.add('heartbeat', function () {
|
||||
parser.encodePacket({
|
||||
type: 'heartbeat'
|
||||
, endpoint: ''
|
||||
})
|
||||
});
|
||||
|
||||
suite.add('error', function () {
|
||||
parser.encodePacket({
|
||||
type: 'error'
|
||||
, reason: 'unauthorized'
|
||||
, advice: 'reconnect'
|
||||
, endpoint: ''
|
||||
})
|
||||
})
|
||||
|
||||
suite.add('payload', function () {
|
||||
parser.encodePayload([
|
||||
parser.encodePacket({ type: 'message', data: '5', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: '53d', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobar', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobarbaz', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobarbazfoobarbaz', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobarbaz', endpoint: '' })
|
||||
, parser.encodePacket({ type: 'message', data: 'foobar', endpoint: '' })
|
||||
]);
|
||||
});
|
||||
|
||||
suite.on('cycle', function (bench, details) {
|
||||
console.log('\n' + suite.name.grey, details.name.white.bold);
|
||||
console.log([
|
||||
details.hz.toFixed(2).cyan + ' ops/sec'.grey
|
||||
, details.count.toString().white + ' times executed'.grey
|
||||
, 'benchmark took '.grey + details.times.elapsed.toString().white + ' sec.'.grey
|
||||
,
|
||||
].join(', '.grey));
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
suite.run();
|
||||
} else {
|
||||
module.exports = suite;
|
||||
}
|
||||
55
node_modules/socket.io/benchmarks/runner.js
generated
vendored
Normal file
55
node_modules/socket.io/benchmarks/runner.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Benchmark runner dependencies
|
||||
*/
|
||||
|
||||
var colors = require('colors')
|
||||
, path = require('path');
|
||||
|
||||
/**
|
||||
* Find all the benchmarks
|
||||
*/
|
||||
|
||||
var benchmarks_files = process.env.BENCHMARKS.split(' ')
|
||||
, all = [].concat(benchmarks_files)
|
||||
, first = all.shift()
|
||||
, benchmarks = {};
|
||||
|
||||
// find the benchmarks and load them all in our obj
|
||||
benchmarks_files.forEach(function (file) {
|
||||
benchmarks[file] = require(path.join(__dirname, '..', file));
|
||||
});
|
||||
|
||||
// setup the complete listeners
|
||||
benchmarks_files.forEach(function (file) {
|
||||
var benchmark = benchmarks[file]
|
||||
, next_file = all.shift()
|
||||
, next = benchmarks[next_file];
|
||||
|
||||
/**
|
||||
* Generate a oncomplete function for the tests, either we are done or we
|
||||
* have more benchmarks to process.
|
||||
*/
|
||||
|
||||
function complete () {
|
||||
if (!next) {
|
||||
console.log(
|
||||
'\n\nBenchmark completed in'.grey
|
||||
, (Date.now() - start).toString().green + ' ms'.grey
|
||||
);
|
||||
} else {
|
||||
console.log('\nStarting benchmark '.grey + next_file.yellow);
|
||||
next.run();
|
||||
}
|
||||
}
|
||||
|
||||
// attach the listener
|
||||
benchmark.on('complete', complete);
|
||||
});
|
||||
|
||||
/**
|
||||
* Start the benchmark
|
||||
*/
|
||||
|
||||
var start = Date.now();
|
||||
console.log('Starting benchmark '.grey + first.yellow);
|
||||
benchmarks[first].run();
|
||||
8
node_modules/socket.io/index.js
generated
vendored
Normal file
8
node_modules/socket.io/index.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
module.exports = require('./lib/socket.io');
|
||||
97
node_modules/socket.io/lib/logger.js
generated
vendored
Normal file
97
node_modules/socket.io/lib/logger.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var util = require('./util')
|
||||
, toArray = util.toArray;
|
||||
|
||||
/**
|
||||
* Log levels.
|
||||
*/
|
||||
|
||||
var levels = [
|
||||
'error'
|
||||
, 'warn'
|
||||
, 'info'
|
||||
, 'debug'
|
||||
];
|
||||
|
||||
/**
|
||||
* Colors for log levels.
|
||||
*/
|
||||
|
||||
var colors = [
|
||||
31
|
||||
, 33
|
||||
, 36
|
||||
, 90
|
||||
];
|
||||
|
||||
/**
|
||||
* Pads the nice output to the longest log level.
|
||||
*/
|
||||
|
||||
function pad (str) {
|
||||
var max = 0;
|
||||
|
||||
for (var i = 0, l = levels.length; i < l; i++)
|
||||
max = Math.max(max, levels[i].length);
|
||||
|
||||
if (str.length < max)
|
||||
return str + new Array(max - str.length + 1).join(' ');
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Logger (console).
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
var Logger = module.exports = function (opts) {
|
||||
opts = opts || {}
|
||||
this.colors = false !== opts.colors;
|
||||
this.level = 3;
|
||||
this.enabled = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Log method.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Logger.prototype.log = function (type) {
|
||||
var index = levels.indexOf(type);
|
||||
|
||||
if (index > this.level || !this.enabled)
|
||||
return this;
|
||||
|
||||
console.log.apply(
|
||||
console
|
||||
, [this.colors
|
||||
? ' \033[' + colors[index] + 'm' + pad(type) + ' -\033[39m'
|
||||
: type + ':'
|
||||
].concat(toArray(arguments).slice(1))
|
||||
);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate methods.
|
||||
*/
|
||||
|
||||
levels.forEach(function (name) {
|
||||
Logger.prototype[name] = function () {
|
||||
this.log.apply(this, [name].concat(toArray(arguments)));
|
||||
};
|
||||
});
|
||||
1027
node_modules/socket.io/lib/manager.js
generated
vendored
Normal file
1027
node_modules/socket.io/lib/manager.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
355
node_modules/socket.io/lib/namespace.js
generated
vendored
Normal file
355
node_modules/socket.io/lib/namespace.js
generated
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Socket = require('./socket')
|
||||
, EventEmitter = process.EventEmitter
|
||||
, parser = require('./parser')
|
||||
, util = require('./util');
|
||||
|
||||
/**
|
||||
* Exports the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = SocketNamespace;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @api public.
|
||||
*/
|
||||
|
||||
function SocketNamespace (mgr, name) {
|
||||
this.manager = mgr;
|
||||
this.name = name || '';
|
||||
this.sockets = {};
|
||||
this.auth = false;
|
||||
this.setFlags();
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
/**
|
||||
* Copies emit since we override it.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.$emit = EventEmitter.prototype.emit;
|
||||
|
||||
/**
|
||||
* Retrieves all clients as Socket instances as an array.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.clients = function (room) {
|
||||
var room = this.name + (room !== undefined ?
|
||||
'/' + room : '');
|
||||
|
||||
if (!this.manager.rooms[room]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return this.manager.rooms[room].map(function (id) {
|
||||
return this.socket(id);
|
||||
}, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Access logger interface.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.__defineGetter__('log', function () {
|
||||
return this.manager.log;
|
||||
});
|
||||
|
||||
/**
|
||||
* Access store.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.__defineGetter__('store', function () {
|
||||
return this.manager.store;
|
||||
});
|
||||
|
||||
/**
|
||||
* JSON message flag.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.__defineGetter__('json', function () {
|
||||
this.flags.json = true;
|
||||
return this;
|
||||
});
|
||||
|
||||
/**
|
||||
* Volatile message flag.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.__defineGetter__('volatile', function () {
|
||||
this.flags.volatile = true;
|
||||
return this;
|
||||
});
|
||||
|
||||
/**
|
||||
* Overrides the room to relay messages to (flag).
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.in = SocketNamespace.prototype.to = function (room) {
|
||||
this.flags.endpoint = this.name + (room ? '/' + room : '');
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a session id we should prevent relaying messages to (flag).
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.except = function (id) {
|
||||
this.flags.exceptions.push(id);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the default flags.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.setFlags = function () {
|
||||
this.flags = {
|
||||
endpoint: this.name
|
||||
, exceptions: []
|
||||
};
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends out a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.packet = function (packet) {
|
||||
packet.endpoint = this.name;
|
||||
|
||||
var store = this.store
|
||||
, log = this.log
|
||||
, volatile = this.flags.volatile
|
||||
, exceptions = this.flags.exceptions
|
||||
, packet = parser.encodePacket(packet);
|
||||
|
||||
this.manager.onDispatch(this.flags.endpoint, packet, volatile, exceptions);
|
||||
this.store.publish('dispatch', this.flags.endpoint, packet, volatile, exceptions);
|
||||
|
||||
this.setFlags();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends to everyone.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.send = function (data) {
|
||||
return this.packet({
|
||||
type: this.flags.json ? 'json' : 'message'
|
||||
, data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Emits to everyone (override).
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.emit = function (name) {
|
||||
if (name == 'newListener') {
|
||||
return this.$emit.apply(this, arguments);
|
||||
}
|
||||
|
||||
return this.packet({
|
||||
type: 'event'
|
||||
, name: name
|
||||
, args: util.toArray(arguments).slice(1)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves or creates a write-only socket for a client, unless specified.
|
||||
*
|
||||
* @param {Boolean} whether the socket will be readable when initialized
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.socket = function (sid, readable) {
|
||||
if (!this.sockets[sid]) {
|
||||
this.sockets[sid] = new Socket(this.manager, sid, this, readable);
|
||||
}
|
||||
|
||||
return this.sockets[sid];
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets authorization for this namespace.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.authorization = function (fn) {
|
||||
this.auth = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when a socket disconnects entirely.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.handleDisconnect = function (sid, reason, raiseOnDisconnect) {
|
||||
if (this.sockets[sid] && this.sockets[sid].readable) {
|
||||
if (raiseOnDisconnect) this.sockets[sid].onDisconnect(reason);
|
||||
delete this.sockets[sid];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs authentication.
|
||||
*
|
||||
* @param Object client request data
|
||||
* @api private
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.authorize = function (data, fn) {
|
||||
if (this.auth) {
|
||||
var self = this;
|
||||
|
||||
this.auth.call(this, data, function (err, authorized) {
|
||||
self.log.debug('client ' +
|
||||
(authorized ? '' : 'un') + 'authorized for ' + self.name);
|
||||
fn(err, authorized);
|
||||
});
|
||||
} else {
|
||||
this.log.debug('client authorized for ' + this.name);
|
||||
fn(null, true);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
SocketNamespace.prototype.handlePacket = function (sessid, packet) {
|
||||
var socket = this.socket(sessid)
|
||||
, dataAck = packet.ack == 'data'
|
||||
, manager = this.manager
|
||||
, self = this;
|
||||
|
||||
function ack () {
|
||||
self.log.debug('sending data ack packet');
|
||||
socket.packet({
|
||||
type: 'ack'
|
||||
, args: util.toArray(arguments)
|
||||
, ackId: packet.id
|
||||
});
|
||||
};
|
||||
|
||||
function error (err) {
|
||||
self.log.warn('handshake error ' + err + ' for ' + self.name);
|
||||
socket.packet({ type: 'error', reason: err });
|
||||
};
|
||||
|
||||
function connect () {
|
||||
self.manager.onJoin(sessid, self.name);
|
||||
self.store.publish('join', sessid, self.name);
|
||||
|
||||
// packet echo
|
||||
socket.packet({ type: 'connect' });
|
||||
|
||||
// emit connection event
|
||||
self.$emit('connection', socket);
|
||||
};
|
||||
|
||||
switch (packet.type) {
|
||||
case 'connect':
|
||||
if (packet.endpoint == '') {
|
||||
connect();
|
||||
} else {
|
||||
var handshakeData = manager.handshaken[sessid];
|
||||
|
||||
this.authorize(handshakeData, function (err, authorized, newData) {
|
||||
if (err) return error(err);
|
||||
|
||||
if (authorized) {
|
||||
manager.onHandshake(sessid, newData || handshakeData);
|
||||
self.store.publish('handshake', sessid, newData || handshakeData);
|
||||
connect();
|
||||
} else {
|
||||
error('unauthorized');
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ack':
|
||||
if (socket.acks[packet.ackId]) {
|
||||
socket.acks[packet.ackId].apply(socket, packet.args);
|
||||
} else {
|
||||
this.log.info('unknown ack packet');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'event':
|
||||
// check if the emitted event is not blacklisted
|
||||
if (-~manager.get('blacklist').indexOf(packet.name)) {
|
||||
this.log.debug('ignoring blacklisted event `' + packet.name + '`');
|
||||
} else {
|
||||
var params = [packet.name].concat(packet.args);
|
||||
|
||||
if (dataAck) {
|
||||
params.push(ack);
|
||||
}
|
||||
|
||||
socket.$emit.apply(socket, params);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'disconnect':
|
||||
this.manager.onLeave(sessid, this.name);
|
||||
this.store.publish('leave', sessid, this.name);
|
||||
|
||||
socket.$emit('disconnect', packet.reason || 'packet');
|
||||
break;
|
||||
|
||||
case 'json':
|
||||
case 'message':
|
||||
var params = ['message', packet.data];
|
||||
|
||||
if (dataAck)
|
||||
params.push(ack);
|
||||
|
||||
socket.$emit.apply(socket, params);
|
||||
};
|
||||
};
|
||||
249
node_modules/socket.io/lib/parser.js
generated
vendored
Normal file
249
node_modules/socket.io/lib/parser.js
generated
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Packet types.
|
||||
*/
|
||||
|
||||
var packets = exports.packets = {
|
||||
'disconnect': 0
|
||||
, 'connect': 1
|
||||
, 'heartbeat': 2
|
||||
, 'message': 3
|
||||
, 'json': 4
|
||||
, 'event': 5
|
||||
, 'ack': 6
|
||||
, 'error': 7
|
||||
, 'noop': 8
|
||||
}
|
||||
, packetslist = Object.keys(packets);
|
||||
|
||||
/**
|
||||
* Errors reasons.
|
||||
*/
|
||||
|
||||
var reasons = exports.reasons = {
|
||||
'transport not supported': 0
|
||||
, 'client not handshaken': 1
|
||||
, 'unauthorized': 2
|
||||
}
|
||||
, reasonslist = Object.keys(reasons);
|
||||
|
||||
/**
|
||||
* Errors advice.
|
||||
*/
|
||||
|
||||
var advice = exports.advice = {
|
||||
'reconnect': 0
|
||||
}
|
||||
, advicelist = Object.keys(advice);
|
||||
|
||||
/**
|
||||
* Encodes a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.encodePacket = function (packet) {
|
||||
var type = packets[packet.type]
|
||||
, id = packet.id || ''
|
||||
, endpoint = packet.endpoint || ''
|
||||
, ack = packet.ack
|
||||
, data = null;
|
||||
|
||||
switch (packet.type) {
|
||||
case 'message':
|
||||
if (packet.data !== '')
|
||||
data = packet.data;
|
||||
break;
|
||||
|
||||
case 'event':
|
||||
var ev = { name: packet.name };
|
||||
|
||||
if (packet.args && packet.args.length) {
|
||||
ev.args = packet.args;
|
||||
}
|
||||
|
||||
data = JSON.stringify(ev);
|
||||
break;
|
||||
|
||||
case 'json':
|
||||
data = JSON.stringify(packet.data);
|
||||
break;
|
||||
|
||||
case 'ack':
|
||||
data = packet.ackId
|
||||
+ (packet.args && packet.args.length
|
||||
? '+' + JSON.stringify(packet.args) : '');
|
||||
break;
|
||||
|
||||
case 'connect':
|
||||
if (packet.qs)
|
||||
data = packet.qs;
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
var reason = packet.reason ? reasons[packet.reason] : ''
|
||||
, adv = packet.advice ? advice[packet.advice] : ''
|
||||
|
||||
if (reason !== '' || adv !== '')
|
||||
data = reason + (adv !== '' ? ('+' + adv) : '')
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// construct packet with required fragments
|
||||
var encoded = type + ':' + id + (ack == 'data' ? '+' : '') + ':' + endpoint;
|
||||
|
||||
// data fragment is optional
|
||||
if (data !== null && data !== undefined)
|
||||
encoded += ':' + data;
|
||||
|
||||
return encoded;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encodes multiple messages (payload).
|
||||
*
|
||||
* @param {Array} messages
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.encodePayload = function (packets) {
|
||||
var decoded = '';
|
||||
|
||||
if (packets.length == 1)
|
||||
return packets[0];
|
||||
|
||||
for (var i = 0, l = packets.length; i < l; i++) {
|
||||
var packet = packets[i];
|
||||
decoded += '\ufffd' + packet.length + '\ufffd' + packets[i]
|
||||
}
|
||||
|
||||
return decoded;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes a packet
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
var regexp = /([^:]+):([0-9]+)?(\+)?:([^:]+)?:?([\s\S]*)?/;
|
||||
|
||||
/**
|
||||
* Wrap the JSON.parse in a seperate function the crankshaft optimizer will
|
||||
* only punish this function for the usage for try catch
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function parse (data) {
|
||||
try { return JSON.parse(data) }
|
||||
catch (e) { return false }
|
||||
}
|
||||
|
||||
exports.decodePacket = function (data) {
|
||||
var pieces = data.match(regexp);
|
||||
|
||||
if (!pieces) return {};
|
||||
|
||||
var id = pieces[2] || ''
|
||||
, data = pieces[5] || ''
|
||||
, packet = {
|
||||
type: packetslist[pieces[1]]
|
||||
, endpoint: pieces[4] || ''
|
||||
};
|
||||
|
||||
// whether we need to acknowledge the packet
|
||||
if (id) {
|
||||
packet.id = id;
|
||||
if (pieces[3])
|
||||
packet.ack = 'data';
|
||||
else
|
||||
packet.ack = true;
|
||||
}
|
||||
|
||||
// handle different packet types
|
||||
switch (packet.type) {
|
||||
case 'message':
|
||||
packet.data = data || '';
|
||||
break;
|
||||
|
||||
case 'event':
|
||||
pieces = parse(data);
|
||||
if (pieces) {
|
||||
packet.name = pieces.name;
|
||||
packet.args = pieces.args;
|
||||
}
|
||||
|
||||
packet.args = packet.args || [];
|
||||
break;
|
||||
|
||||
case 'json':
|
||||
packet.data = parse(data);
|
||||
break;
|
||||
|
||||
case 'connect':
|
||||
packet.qs = data || '';
|
||||
break;
|
||||
|
||||
case 'ack':
|
||||
pieces = data.match(/^([0-9]+)(\+)?(.*)/);
|
||||
if (pieces) {
|
||||
packet.ackId = pieces[1];
|
||||
packet.args = [];
|
||||
|
||||
if (pieces[3]) {
|
||||
packet.args = parse(pieces[3]) || [];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
pieces = data.split('+');
|
||||
packet.reason = reasonslist[pieces[0]] || '';
|
||||
packet.advice = advicelist[pieces[1]] || '';
|
||||
}
|
||||
|
||||
return packet;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes data payload. Detects multiple messages
|
||||
*
|
||||
* @return {Array} messages
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.decodePayload = function (data) {
|
||||
if (undefined == data || null == data) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (data[0] == '\ufffd') {
|
||||
var ret = [];
|
||||
|
||||
for (var i = 1, length = ''; i < data.length; i++) {
|
||||
if (data[i] == '\ufffd') {
|
||||
ret.push(exports.decodePacket(data.substr(i + 1, length)));
|
||||
i += Number(length) + 1;
|
||||
length = '';
|
||||
} else {
|
||||
length += data[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
return [exports.decodePacket(data)];
|
||||
}
|
||||
};
|
||||
143
node_modules/socket.io/lib/socket.io.js
generated
vendored
Normal file
143
node_modules/socket.io/lib/socket.io.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var client = require('socket.io-client');
|
||||
|
||||
/**
|
||||
* Version.
|
||||
*/
|
||||
|
||||
exports.version = '0.9.11';
|
||||
|
||||
/**
|
||||
* Supported protocol version.
|
||||
*/
|
||||
|
||||
exports.protocol = 1;
|
||||
|
||||
/**
|
||||
* Client that we serve.
|
||||
*/
|
||||
|
||||
exports.clientVersion = client.version;
|
||||
|
||||
/**
|
||||
* Attaches a manager
|
||||
*
|
||||
* @param {HTTPServer/Number} a HTTP/S server or a port number to listen on.
|
||||
* @param {Object} opts to be passed to Manager and/or http server
|
||||
* @param {Function} callback if a port is supplied
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.listen = function (server, options, fn) {
|
||||
if ('function' == typeof server) {
|
||||
console.warn('Socket.IO\'s `listen()` method expects an `http.Server` instance\n'
|
||||
+ 'as its first parameter. Are you migrating from Express 2.x to 3.x?\n'
|
||||
+ 'If so, check out the "Socket.IO compatibility" section at:\n'
|
||||
+ 'https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x');
|
||||
}
|
||||
|
||||
if ('function' == typeof options) {
|
||||
fn = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
if ('undefined' == typeof server) {
|
||||
// create a server that listens on port 80
|
||||
server = 80;
|
||||
}
|
||||
|
||||
if ('number' == typeof server) {
|
||||
// if a port number is passed
|
||||
var port = server;
|
||||
|
||||
if (options && options.key)
|
||||
server = require('https').createServer(options);
|
||||
else
|
||||
server = require('http').createServer();
|
||||
|
||||
// default response
|
||||
server.on('request', function (req, res) {
|
||||
res.writeHead(200);
|
||||
res.end('Welcome to socket.io.');
|
||||
});
|
||||
|
||||
server.listen(port, fn);
|
||||
}
|
||||
|
||||
// otherwise assume a http/s server
|
||||
return new exports.Manager(server, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Manager constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.Manager = require('./manager');
|
||||
|
||||
/**
|
||||
* Transport constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.Transport = require('./transport');
|
||||
|
||||
/**
|
||||
* Socket constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.Socket = require('./socket');
|
||||
|
||||
/**
|
||||
* Static constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.Static = require('./static');
|
||||
|
||||
/**
|
||||
* Store constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.Store = require('./store');
|
||||
|
||||
/**
|
||||
* Memory Store constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.MemoryStore = require('./stores/memory');
|
||||
|
||||
/**
|
||||
* Redis Store constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.RedisStore = require('./stores/redis');
|
||||
|
||||
/**
|
||||
* Parser.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.parser = require('./parser');
|
||||
369
node_modules/socket.io/lib/socket.js
generated
vendored
Normal file
369
node_modules/socket.io/lib/socket.js
generated
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var parser = require('./parser')
|
||||
, util = require('./util')
|
||||
, EventEmitter = process.EventEmitter
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = Socket;
|
||||
|
||||
/**
|
||||
* Default error event listener to prevent uncaught exceptions.
|
||||
*/
|
||||
|
||||
var defaultError = function () {};
|
||||
|
||||
/**
|
||||
* Socket constructor.
|
||||
*
|
||||
* @param {Manager} manager instance
|
||||
* @param {String} session id
|
||||
* @param {Namespace} namespace the socket belongs to
|
||||
* @param {Boolean} whether the
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Socket (manager, id, nsp, readable) {
|
||||
this.id = id;
|
||||
this.namespace = nsp;
|
||||
this.manager = manager;
|
||||
this.disconnected = false;
|
||||
this.ackPackets = 0;
|
||||
this.acks = {};
|
||||
this.setFlags();
|
||||
this.readable = readable;
|
||||
this.store = this.manager.store.client(this.id);
|
||||
this.on('error', defaultError);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
Socket.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
/**
|
||||
* Accessor shortcut for the handshake data
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.__defineGetter__('handshake', function () {
|
||||
return this.manager.handshaken[this.id];
|
||||
});
|
||||
|
||||
/**
|
||||
* Accessor shortcut for the transport type
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.__defineGetter__('transport', function () {
|
||||
return this.manager.transports[this.id].name;
|
||||
});
|
||||
|
||||
/**
|
||||
* Accessor shortcut for the logger.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.__defineGetter__('log', function () {
|
||||
return this.manager.log;
|
||||
});
|
||||
|
||||
/**
|
||||
* JSON message flag.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.__defineGetter__('json', function () {
|
||||
this.flags.json = true;
|
||||
return this;
|
||||
});
|
||||
|
||||
/**
|
||||
* Volatile message flag.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.__defineGetter__('volatile', function () {
|
||||
this.flags.volatile = true;
|
||||
return this;
|
||||
});
|
||||
|
||||
/**
|
||||
* Broadcast message flag.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.__defineGetter__('broadcast', function () {
|
||||
this.flags.broadcast = true;
|
||||
return this;
|
||||
});
|
||||
|
||||
/**
|
||||
* Overrides the room to broadcast messages to (flag)
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.to = Socket.prototype.in = function (room) {
|
||||
this.flags.room = room;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resets flags
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.setFlags = function () {
|
||||
this.flags = {
|
||||
endpoint: this.namespace.name
|
||||
, room: ''
|
||||
};
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggered on disconnect
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.onDisconnect = function (reason) {
|
||||
if (!this.disconnected) {
|
||||
this.$emit('disconnect', reason);
|
||||
this.disconnected = true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Joins a user to a room.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.join = function (name, fn) {
|
||||
var nsp = this.namespace.name
|
||||
, name = (nsp + '/') + name;
|
||||
|
||||
this.manager.onJoin(this.id, name);
|
||||
this.manager.store.publish('join', this.id, name);
|
||||
|
||||
if (fn) {
|
||||
this.log.warn('Client#join callback is deprecated');
|
||||
fn();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Un-joins a user from a room.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.leave = function (name, fn) {
|
||||
var nsp = this.namespace.name
|
||||
, name = (nsp + '/') + name;
|
||||
|
||||
this.manager.onLeave(this.id, name);
|
||||
this.manager.store.publish('leave', this.id, name);
|
||||
|
||||
if (fn) {
|
||||
this.log.warn('Client#leave callback is deprecated');
|
||||
fn();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transmits a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.packet = function (packet) {
|
||||
if (this.flags.broadcast) {
|
||||
this.log.debug('broadcasting packet');
|
||||
this.namespace.in(this.flags.room).except(this.id).packet(packet);
|
||||
} else {
|
||||
packet.endpoint = this.flags.endpoint;
|
||||
packet = parser.encodePacket(packet);
|
||||
|
||||
this.dispatch(packet, this.flags.volatile);
|
||||
}
|
||||
|
||||
this.setFlags();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches a packet
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.dispatch = function (packet, volatile) {
|
||||
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
|
||||
this.manager.transports[this.id].onDispatch(packet, volatile);
|
||||
} else {
|
||||
if (!volatile) {
|
||||
this.manager.onClientDispatch(this.id, packet, volatile);
|
||||
}
|
||||
|
||||
this.manager.store.publish('dispatch:' + this.id, packet, volatile);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores data for the client.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.set = function (key, value, fn) {
|
||||
this.store.set(key, value, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves data for the client
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.get = function (key, fn) {
|
||||
this.store.get(key, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks data for the client
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.has = function (key, fn) {
|
||||
this.store.has(key, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes data for the client
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.del = function (key, fn) {
|
||||
this.store.del(key, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Kicks client
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.disconnect = function () {
|
||||
if (!this.disconnected) {
|
||||
this.log.info('booting client');
|
||||
|
||||
if ('' === this.namespace.name) {
|
||||
if (this.manager.transports[this.id] && this.manager.transports[this.id].open) {
|
||||
this.manager.transports[this.id].onForcedDisconnect();
|
||||
} else {
|
||||
this.manager.onClientDisconnect(this.id);
|
||||
this.manager.store.publish('disconnect:' + this.id);
|
||||
}
|
||||
} else {
|
||||
this.packet({type: 'disconnect'});
|
||||
this.manager.onLeave(this.id, this.namespace.name);
|
||||
this.$emit('disconnect', 'booted');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.send = function (data, fn) {
|
||||
var packet = {
|
||||
type: this.flags.json ? 'json' : 'message'
|
||||
, data: data
|
||||
};
|
||||
|
||||
if (fn) {
|
||||
packet.id = ++this.ackPackets;
|
||||
packet.ack = true;
|
||||
this.acks[packet.id] = fn;
|
||||
}
|
||||
|
||||
return this.packet(packet);
|
||||
};
|
||||
|
||||
/**
|
||||
* Original emit function.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Socket.prototype.$emit = EventEmitter.prototype.emit;
|
||||
|
||||
/**
|
||||
* Emit override for custom events.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Socket.prototype.emit = function (ev) {
|
||||
if (ev == 'newListener') {
|
||||
return this.$emit.apply(this, arguments);
|
||||
}
|
||||
|
||||
var args = util.toArray(arguments).slice(1)
|
||||
, lastArg = args[args.length - 1]
|
||||
, packet = {
|
||||
type: 'event'
|
||||
, name: ev
|
||||
};
|
||||
|
||||
if ('function' == typeof lastArg) {
|
||||
packet.id = ++this.ackPackets;
|
||||
packet.ack = lastArg.length ? 'data' : true;
|
||||
this.acks[packet.id] = lastArg;
|
||||
args = args.slice(0, args.length - 1);
|
||||
}
|
||||
|
||||
packet.args = args;
|
||||
|
||||
return this.packet(packet);
|
||||
};
|
||||
395
node_modules/socket.io/lib/static.js
generated
vendored
Normal file
395
node_modules/socket.io/lib/static.js
generated
vendored
Normal file
@@ -0,0 +1,395 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var client = require('socket.io-client')
|
||||
, cp = require('child_process')
|
||||
, fs = require('fs')
|
||||
, util = require('./util');
|
||||
|
||||
/**
|
||||
* File type details.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
var mime = {
|
||||
js: {
|
||||
type: 'application/javascript'
|
||||
, encoding: 'utf8'
|
||||
, gzip: true
|
||||
}
|
||||
, swf: {
|
||||
type: 'application/x-shockwave-flash'
|
||||
, encoding: 'binary'
|
||||
, gzip: false
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Regexp for matching custom transport patterns. Users can configure their own
|
||||
* socket.io bundle based on the url structure. Different transport names are
|
||||
* concatinated using the `+` char. /socket.io/socket.io+websocket.js should
|
||||
* create a bundle that only contains support for the websocket.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
var bundle = /\+((?:\+)?[\w\-]+)*(?:\.v\d+\.\d+\.\d+)?(?:\.js)$/
|
||||
, versioning = /\.v\d+\.\d+\.\d+(?:\.js)$/;
|
||||
|
||||
/**
|
||||
* Export the constructor
|
||||
*/
|
||||
|
||||
exports = module.exports = Static;
|
||||
|
||||
/**
|
||||
* Static constructor
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Static (manager) {
|
||||
this.manager = manager;
|
||||
this.cache = {};
|
||||
this.paths = {};
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Static by adding default file paths.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Static.prototype.init = function () {
|
||||
/**
|
||||
* Generates a unique id based the supplied transports array
|
||||
*
|
||||
* @param {Array} transports The array with transport types
|
||||
* @api private
|
||||
*/
|
||||
function id (transports) {
|
||||
var id = transports.join('').split('').map(function (char) {
|
||||
return ('' + char.charCodeAt(0)).split('').pop();
|
||||
}).reduce(function (char, id) {
|
||||
return char +id;
|
||||
});
|
||||
|
||||
return client.version + ':' + id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a socket.io-client file based on the supplied transports.
|
||||
*
|
||||
* @param {Array} transports The array with transport types
|
||||
* @param {Function} callback Callback for the static.write
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function build (transports, callback) {
|
||||
client.builder(transports, {
|
||||
minify: self.manager.enabled('browser client minification')
|
||||
}, function (err, content) {
|
||||
callback(err, content ? new Buffer(content) : null, id(transports));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
// add our default static files
|
||||
this.add('/static/flashsocket/WebSocketMain.swf', {
|
||||
file: client.dist + '/WebSocketMain.swf'
|
||||
});
|
||||
|
||||
this.add('/static/flashsocket/WebSocketMainInsecure.swf', {
|
||||
file: client.dist + '/WebSocketMainInsecure.swf'
|
||||
});
|
||||
|
||||
// generates dedicated build based on the available transports
|
||||
this.add('/socket.io.js', function (path, callback) {
|
||||
build(self.manager.get('transports'), callback);
|
||||
});
|
||||
|
||||
this.add('/socket.io.v', { mime: mime.js }, function (path, callback) {
|
||||
build(self.manager.get('transports'), callback);
|
||||
});
|
||||
|
||||
// allow custom builds based on url paths
|
||||
this.add('/socket.io+', { mime: mime.js }, function (path, callback) {
|
||||
var available = self.manager.get('transports')
|
||||
, matches = path.match(bundle)
|
||||
, transports = [];
|
||||
|
||||
if (!matches) return callback('No valid transports');
|
||||
|
||||
// make sure they valid transports
|
||||
matches[0].split('.')[0].split('+').slice(1).forEach(function (transport) {
|
||||
if (!!~available.indexOf(transport)) {
|
||||
transports.push(transport);
|
||||
}
|
||||
});
|
||||
|
||||
if (!transports.length) return callback('No valid transports');
|
||||
build(transports, callback);
|
||||
});
|
||||
|
||||
// clear cache when transports change
|
||||
this.manager.on('set:transports', function (key, value) {
|
||||
delete self.cache['/socket.io.js'];
|
||||
Object.keys(self.cache).forEach(function (key) {
|
||||
if (bundle.test(key)) {
|
||||
delete self.cache[key];
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Gzip compress buffers.
|
||||
*
|
||||
* @param {Buffer} data The buffer that needs gzip compression
|
||||
* @param {Function} callback
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Static.prototype.gzip = function (data, callback) {
|
||||
var gzip = cp.spawn('gzip', ['-9', '-c', '-f', '-n'])
|
||||
, encoding = Buffer.isBuffer(data) ? 'binary' : 'utf8'
|
||||
, buffer = []
|
||||
, err;
|
||||
|
||||
gzip.stdout.on('data', function (data) {
|
||||
buffer.push(data);
|
||||
});
|
||||
|
||||
gzip.stderr.on('data', function (data) {
|
||||
err = data +'';
|
||||
buffer.length = 0;
|
||||
});
|
||||
|
||||
gzip.on('close', function () {
|
||||
if (err) return callback(err);
|
||||
|
||||
var size = 0
|
||||
, index = 0
|
||||
, i = buffer.length
|
||||
, content;
|
||||
|
||||
while (i--) {
|
||||
size += buffer[i].length;
|
||||
}
|
||||
|
||||
content = new Buffer(size);
|
||||
i = buffer.length;
|
||||
|
||||
buffer.forEach(function (buffer) {
|
||||
var length = buffer.length;
|
||||
|
||||
buffer.copy(content, index, 0, length);
|
||||
index += length;
|
||||
});
|
||||
|
||||
buffer.length = 0;
|
||||
callback(null, content);
|
||||
});
|
||||
|
||||
gzip.stdin.end(data, encoding);
|
||||
};
|
||||
|
||||
/**
|
||||
* Is the path a static file?
|
||||
*
|
||||
* @param {String} path The path that needs to be checked
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Static.prototype.has = function (path) {
|
||||
// fast case
|
||||
if (this.paths[path]) return this.paths[path];
|
||||
|
||||
var keys = Object.keys(this.paths)
|
||||
, i = keys.length;
|
||||
|
||||
while (i--) {
|
||||
if (-~path.indexOf(keys[i])) return this.paths[keys[i]];
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add new paths new paths that can be served using the static provider.
|
||||
*
|
||||
* @param {String} path The path to respond to
|
||||
* @param {Options} options Options for writing out the response
|
||||
* @param {Function} [callback] Optional callback if no options.file is
|
||||
* supplied this would be called instead.
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Static.prototype.add = function (path, options, callback) {
|
||||
var extension = /(?:\.(\w{1,4}))$/.exec(path);
|
||||
|
||||
if (!callback && typeof options == 'function') {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
options.mime = options.mime || (extension ? mime[extension[1]] : false);
|
||||
|
||||
if (callback) options.callback = callback;
|
||||
if (!(options.file || options.callback) || !options.mime) return false;
|
||||
|
||||
this.paths[path] = options;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a static response.
|
||||
*
|
||||
* @param {String} path The path for the static content
|
||||
* @param {HTTPRequest} req The request object
|
||||
* @param {HTTPResponse} res The response object
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Static.prototype.write = function (path, req, res) {
|
||||
/**
|
||||
* Write a response without throwing errors because can throw error if the
|
||||
* response is no longer writable etc.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function write (status, headers, content, encoding) {
|
||||
try {
|
||||
res.writeHead(status, headers || undefined);
|
||||
|
||||
// only write content if it's not a HEAD request and we actually have
|
||||
// some content to write (304's doesn't have content).
|
||||
res.end(
|
||||
req.method !== 'HEAD' && content ? content : ''
|
||||
, encoding || undefined
|
||||
);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Answers requests depending on the request properties and the reply object.
|
||||
*
|
||||
* @param {Object} reply The details and content to reply the response with
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function answer (reply) {
|
||||
var cached = req.headers['if-none-match'] === reply.etag;
|
||||
if (cached && self.manager.enabled('browser client etag')) {
|
||||
return write(304);
|
||||
}
|
||||
|
||||
var accept = req.headers['accept-encoding'] || ''
|
||||
, gzip = !!~accept.toLowerCase().indexOf('gzip')
|
||||
, mime = reply.mime
|
||||
, versioned = reply.versioned
|
||||
, headers = {
|
||||
'Content-Type': mime.type
|
||||
};
|
||||
|
||||
// check if we can add a etag
|
||||
if (self.manager.enabled('browser client etag') && reply.etag && !versioned) {
|
||||
headers['Etag'] = reply.etag;
|
||||
}
|
||||
|
||||
// see if we need to set Expire headers because the path is versioned
|
||||
if (versioned) {
|
||||
var expires = self.manager.get('browser client expires');
|
||||
headers['Cache-Control'] = 'private, x-gzip-ok="", max-age=' + expires;
|
||||
headers['Date'] = new Date().toUTCString();
|
||||
headers['Expires'] = new Date(Date.now() + (expires * 1000)).toUTCString();
|
||||
}
|
||||
|
||||
if (gzip && reply.gzip) {
|
||||
headers['Content-Length'] = reply.gzip.length;
|
||||
headers['Content-Encoding'] = 'gzip';
|
||||
headers['Vary'] = 'Accept-Encoding';
|
||||
write(200, headers, reply.gzip.content, mime.encoding);
|
||||
} else {
|
||||
headers['Content-Length'] = reply.length;
|
||||
write(200, headers, reply.content, mime.encoding);
|
||||
}
|
||||
|
||||
self.manager.log.debug('served static content ' + path);
|
||||
}
|
||||
|
||||
var self = this
|
||||
, details;
|
||||
|
||||
// most common case first
|
||||
if (this.manager.enabled('browser client cache') && this.cache[path]) {
|
||||
return answer(this.cache[path]);
|
||||
} else if (this.manager.get('browser client handler')) {
|
||||
return this.manager.get('browser client handler').call(this, req, res);
|
||||
} else if ((details = this.has(path))) {
|
||||
/**
|
||||
* A small helper function that will let us deal with fs and dynamic files
|
||||
*
|
||||
* @param {Object} err Optional error
|
||||
* @param {Buffer} content The data
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function ready (err, content, etag) {
|
||||
if (err) {
|
||||
self.manager.log.warn('Unable to serve file. ' + (err.message || err));
|
||||
return write(500, null, 'Error serving static ' + path);
|
||||
}
|
||||
|
||||
// store the result in the cache
|
||||
var reply = self.cache[path] = {
|
||||
content: content
|
||||
, length: content.length
|
||||
, mime: details.mime
|
||||
, etag: etag || client.version
|
||||
, versioned: versioning.test(path)
|
||||
};
|
||||
|
||||
// check if gzip is enabled
|
||||
if (details.mime.gzip && self.manager.enabled('browser client gzip')) {
|
||||
self.gzip(content, function (err, content) {
|
||||
if (!err) {
|
||||
reply.gzip = {
|
||||
content: content
|
||||
, length: content.length
|
||||
}
|
||||
}
|
||||
|
||||
answer(reply);
|
||||
});
|
||||
} else {
|
||||
answer(reply);
|
||||
}
|
||||
}
|
||||
|
||||
if (details.file) {
|
||||
fs.readFile(details.file, ready);
|
||||
} else if(details.callback) {
|
||||
details.callback.call(this, path, ready);
|
||||
} else {
|
||||
write(404, null, 'File handle not found');
|
||||
}
|
||||
} else {
|
||||
write(404, null, 'File not found');
|
||||
}
|
||||
};
|
||||
98
node_modules/socket.io/lib/store.js
generated
vendored
Normal file
98
node_modules/socket.io/lib/store.js
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Expose the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = Store;
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var EventEmitter = process.EventEmitter;
|
||||
|
||||
/**
|
||||
* Store interface
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Store (options) {
|
||||
this.options = options;
|
||||
this.clients = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherit from EventEmitter.
|
||||
*/
|
||||
|
||||
Store.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
/**
|
||||
* Initializes a client store
|
||||
*
|
||||
* @param {String} id
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Store.prototype.client = function (id) {
|
||||
if (!this.clients[id]) {
|
||||
this.clients[id] = new (this.constructor.Client)(this, id);
|
||||
}
|
||||
|
||||
return this.clients[id];
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys a client
|
||||
*
|
||||
* @api {String} sid
|
||||
* @param {Number} number of seconds to expire client data
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Store.prototype.destroyClient = function (id, expiration) {
|
||||
if (this.clients[id]) {
|
||||
this.clients[id].destroy(expiration);
|
||||
delete this.clients[id];
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the store
|
||||
*
|
||||
* @param {Number} number of seconds to expire client data
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Store.prototype.destroy = function (clientExpiration) {
|
||||
var keys = Object.keys(this.clients)
|
||||
, count = keys.length;
|
||||
|
||||
for (var i = 0, l = count; i < l; i++) {
|
||||
this.destroyClient(keys[i], clientExpiration);
|
||||
}
|
||||
|
||||
this.clients = {};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Client.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Store.Client = function (store, id) {
|
||||
this.store = store;
|
||||
this.id = id;
|
||||
};
|
||||
143
node_modules/socket.io/lib/stores/memory.js
generated
vendored
Normal file
143
node_modules/socket.io/lib/stores/memory.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var crypto = require('crypto')
|
||||
, Store = require('../store');
|
||||
|
||||
/**
|
||||
* Exports the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = Memory;
|
||||
Memory.Client = Client;
|
||||
|
||||
/**
|
||||
* Memory store
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Memory (opts) {
|
||||
Store.call(this, opts);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Store.
|
||||
*/
|
||||
|
||||
Memory.prototype.__proto__ = Store.prototype;
|
||||
|
||||
/**
|
||||
* Publishes a message.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Memory.prototype.publish = function () { };
|
||||
|
||||
/**
|
||||
* Subscribes to a channel
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Memory.prototype.subscribe = function () { };
|
||||
|
||||
/**
|
||||
* Unsubscribes
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Memory.prototype.unsubscribe = function () { };
|
||||
|
||||
/**
|
||||
* Client constructor
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Client () {
|
||||
Store.Client.apply(this, arguments);
|
||||
this.data = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Store.Client
|
||||
*/
|
||||
|
||||
Client.prototype.__proto__ = Store.Client;
|
||||
|
||||
/**
|
||||
* Gets a key
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Client.prototype.get = function (key, fn) {
|
||||
fn(null, this.data[key] === undefined ? null : this.data[key]);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a key
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Client.prototype.set = function (key, value, fn) {
|
||||
this.data[key] = value;
|
||||
fn && fn(null);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Has a key
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Client.prototype.has = function (key, fn) {
|
||||
fn(null, key in this.data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Deletes a key
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Client.prototype.del = function (key, fn) {
|
||||
delete this.data[key];
|
||||
fn && fn(null);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the client.
|
||||
*
|
||||
* @param {Number} number of seconds to expire data
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.destroy = function (expiration) {
|
||||
if ('number' != typeof expiration) {
|
||||
this.data = {};
|
||||
} else {
|
||||
var self = this;
|
||||
|
||||
setTimeout(function () {
|
||||
self.data = {};
|
||||
}, expiration * 1000);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
269
node_modules/socket.io/lib/stores/redis.js
generated
vendored
Normal file
269
node_modules/socket.io/lib/stores/redis.js
generated
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var crypto = require('crypto')
|
||||
, Store = require('../store')
|
||||
, assert = require('assert');
|
||||
|
||||
/**
|
||||
* Exports the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = Redis;
|
||||
Redis.Client = Client;
|
||||
|
||||
/**
|
||||
* Redis store.
|
||||
* Options:
|
||||
* - nodeId (fn) gets an id that uniquely identifies this node
|
||||
* - redis (fn) redis constructor, defaults to redis
|
||||
* - redisPub (object) options to pass to the pub redis client
|
||||
* - redisSub (object) options to pass to the sub redis client
|
||||
* - redisClient (object) options to pass to the general redis client
|
||||
* - pack (fn) custom packing, defaults to JSON or msgpack if installed
|
||||
* - unpack (fn) custom packing, defaults to JSON or msgpack if installed
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Redis (opts) {
|
||||
opts = opts || {};
|
||||
|
||||
// node id to uniquely identify this node
|
||||
var nodeId = opts.nodeId || function () {
|
||||
// by default, we generate a random id
|
||||
return Math.abs(Math.random() * Math.random() * Date.now() | 0);
|
||||
};
|
||||
|
||||
this.nodeId = nodeId();
|
||||
|
||||
// packing / unpacking mechanism
|
||||
if (opts.pack) {
|
||||
this.pack = opts.pack;
|
||||
this.unpack = opts.unpack;
|
||||
} else {
|
||||
try {
|
||||
var msgpack = require('msgpack');
|
||||
this.pack = msgpack.pack;
|
||||
this.unpack = msgpack.unpack;
|
||||
} catch (e) {
|
||||
this.pack = JSON.stringify;
|
||||
this.unpack = JSON.parse;
|
||||
}
|
||||
}
|
||||
|
||||
var redis = opts.redis || require('redis')
|
||||
, RedisClient = redis.RedisClient;
|
||||
|
||||
// initialize a pubsub client and a regular client
|
||||
if (opts.redisPub instanceof RedisClient) {
|
||||
this.pub = opts.redisPub;
|
||||
} else {
|
||||
opts.redisPub || (opts.redisPub = {});
|
||||
this.pub = redis.createClient(opts.redisPub.port, opts.redisPub.host, opts.redisPub);
|
||||
}
|
||||
if (opts.redisSub instanceof RedisClient) {
|
||||
this.sub = opts.redisSub;
|
||||
} else {
|
||||
opts.redisSub || (opts.redisSub = {});
|
||||
this.sub = redis.createClient(opts.redisSub.port, opts.redisSub.host, opts.redisSub);
|
||||
}
|
||||
if (opts.redisClient instanceof RedisClient) {
|
||||
this.cmd = opts.redisClient;
|
||||
} else {
|
||||
opts.redisClient || (opts.redisClient = {});
|
||||
this.cmd = redis.createClient(opts.redisClient.port, opts.redisClient.host, opts.redisClient);
|
||||
}
|
||||
|
||||
Store.call(this, opts);
|
||||
|
||||
this.sub.setMaxListeners(0);
|
||||
this.setMaxListeners(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Store.
|
||||
*/
|
||||
|
||||
Redis.prototype.__proto__ = Store.prototype;
|
||||
|
||||
/**
|
||||
* Publishes a message.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Redis.prototype.publish = function (name) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
this.pub.publish(name, this.pack({ nodeId: this.nodeId, args: args }));
|
||||
this.emit.apply(this, ['publish', name].concat(args));
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscribes to a channel
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Redis.prototype.subscribe = function (name, consumer, fn) {
|
||||
this.sub.subscribe(name);
|
||||
|
||||
if (consumer || fn) {
|
||||
var self = this;
|
||||
|
||||
self.sub.on('subscribe', function subscribe (ch) {
|
||||
if (name == ch) {
|
||||
function message (ch, msg) {
|
||||
if (name == ch) {
|
||||
msg = self.unpack(msg);
|
||||
|
||||
// we check that the message consumed wasnt emitted by this node
|
||||
if (self.nodeId != msg.nodeId) {
|
||||
consumer.apply(null, msg.args);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.sub.on('message', message);
|
||||
|
||||
self.on('unsubscribe', function unsubscribe (ch) {
|
||||
if (name == ch) {
|
||||
self.sub.removeListener('message', message);
|
||||
self.removeListener('unsubscribe', unsubscribe);
|
||||
}
|
||||
});
|
||||
|
||||
self.sub.removeListener('subscribe', subscribe);
|
||||
|
||||
fn && fn();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.emit('subscribe', name, consumer, fn);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unsubscribes
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Redis.prototype.unsubscribe = function (name, fn) {
|
||||
this.sub.unsubscribe(name);
|
||||
|
||||
if (fn) {
|
||||
var client = this.sub;
|
||||
|
||||
client.on('unsubscribe', function unsubscribe (ch) {
|
||||
if (name == ch) {
|
||||
fn();
|
||||
client.removeListener('unsubscribe', unsubscribe);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.emit('unsubscribe', name, fn);
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the store
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Redis.prototype.destroy = function () {
|
||||
Store.prototype.destroy.call(this);
|
||||
|
||||
this.pub.end();
|
||||
this.sub.end();
|
||||
this.cmd.end();
|
||||
};
|
||||
|
||||
/**
|
||||
* Client constructor
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Client (store, id) {
|
||||
Store.Client.call(this, store, id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Store.Client
|
||||
*/
|
||||
|
||||
Client.prototype.__proto__ = Store.Client;
|
||||
|
||||
/**
|
||||
* Redis hash get
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.get = function (key, fn) {
|
||||
this.store.cmd.hget(this.id, key, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Redis hash set
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.set = function (key, value, fn) {
|
||||
this.store.cmd.hset(this.id, key, value, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Redis hash del
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.del = function (key, fn) {
|
||||
this.store.cmd.hdel(this.id, key, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Redis hash has
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.has = function (key, fn) {
|
||||
this.store.cmd.hexists(this.id, key, function (err, has) {
|
||||
if (err) return fn(err);
|
||||
fn(null, !!has);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys client
|
||||
*
|
||||
* @param {Number} number of seconds to expire data
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Client.prototype.destroy = function (expiration) {
|
||||
if ('number' != typeof expiration) {
|
||||
this.store.cmd.del(this.id);
|
||||
} else {
|
||||
this.store.cmd.expire(this.id, expiration);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
534
node_modules/socket.io/lib/transport.js
generated
vendored
Normal file
534
node_modules/socket.io/lib/transport.js
generated
vendored
Normal file
@@ -0,0 +1,534 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var parser = require('./parser');
|
||||
|
||||
/**
|
||||
* Expose the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = Transport;
|
||||
|
||||
/**
|
||||
* Transport constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Transport (mng, data, req) {
|
||||
this.manager = mng;
|
||||
this.id = data.id;
|
||||
this.disconnected = false;
|
||||
this.drained = true;
|
||||
this.handleRequest(req);
|
||||
};
|
||||
|
||||
/**
|
||||
* Access the logger.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Transport.prototype.__defineGetter__('log', function () {
|
||||
return this.manager.log;
|
||||
});
|
||||
|
||||
/**
|
||||
* Access the store.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Transport.prototype.__defineGetter__('store', function () {
|
||||
return this.manager.store;
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles a request when it's set.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.handleRequest = function (req) {
|
||||
this.log.debug('setting request', req.method, req.url);
|
||||
this.req = req;
|
||||
|
||||
if (req.method == 'GET') {
|
||||
this.socket = req.socket;
|
||||
this.open = true;
|
||||
this.drained = true;
|
||||
this.setHeartbeatInterval();
|
||||
|
||||
this.setHandlers();
|
||||
this.onSocketConnect();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when a connection is first set.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onSocketConnect = function () { };
|
||||
|
||||
/**
|
||||
* Sets transport handlers
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.setHandlers = function () {
|
||||
var self = this;
|
||||
|
||||
// we need to do this in a pub/sub way since the client can POST the message
|
||||
// over a different socket (ie: different Transport instance)
|
||||
this.store.subscribe('heartbeat-clear:' + this.id, function () {
|
||||
self.onHeartbeatClear();
|
||||
});
|
||||
|
||||
this.store.subscribe('disconnect-force:' + this.id, function () {
|
||||
self.onForcedDisconnect();
|
||||
});
|
||||
|
||||
this.store.subscribe('dispatch:' + this.id, function (packet, volatile) {
|
||||
self.onDispatch(packet, volatile);
|
||||
});
|
||||
|
||||
this.bound = {
|
||||
end: this.onSocketEnd.bind(this)
|
||||
, close: this.onSocketClose.bind(this)
|
||||
, error: this.onSocketError.bind(this)
|
||||
, drain: this.onSocketDrain.bind(this)
|
||||
};
|
||||
|
||||
this.socket.on('end', this.bound.end);
|
||||
this.socket.on('close', this.bound.close);
|
||||
this.socket.on('error', this.bound.error);
|
||||
this.socket.on('drain', this.bound.drain);
|
||||
|
||||
this.handlersSet = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes transport handlers
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.clearHandlers = function () {
|
||||
if (this.handlersSet) {
|
||||
this.store.unsubscribe('disconnect-force:' + this.id);
|
||||
this.store.unsubscribe('heartbeat-clear:' + this.id);
|
||||
this.store.unsubscribe('dispatch:' + this.id);
|
||||
|
||||
this.socket.removeListener('end', this.bound.end);
|
||||
this.socket.removeListener('close', this.bound.close);
|
||||
this.socket.removeListener('error', this.bound.error);
|
||||
this.socket.removeListener('drain', this.bound.drain);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the connection dies
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onSocketEnd = function () {
|
||||
this.end('socket end');
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the connection dies
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onSocketClose = function (error) {
|
||||
this.end(error ? 'socket error' : 'socket close');
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the connection has an error.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onSocketError = function (err) {
|
||||
if (this.open) {
|
||||
this.socket.destroy();
|
||||
this.onClose();
|
||||
}
|
||||
|
||||
this.log.info('socket error ' + err.stack);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called when the connection is drained.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onSocketDrain = function () {
|
||||
this.drained = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called upon receiving a heartbeat packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onHeartbeatClear = function () {
|
||||
this.clearHeartbeatTimeout();
|
||||
this.setHeartbeatInterval();
|
||||
};
|
||||
|
||||
/**
|
||||
* Called upon a forced disconnection.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onForcedDisconnect = function () {
|
||||
if (!this.disconnected) {
|
||||
this.log.info('transport end by forced client disconnection');
|
||||
if (this.open) {
|
||||
this.packet({ type: 'disconnect' });
|
||||
}
|
||||
this.end('booted');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatches a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onDispatch = function (packet, volatile) {
|
||||
if (volatile) {
|
||||
this.writeVolatile(packet);
|
||||
} else {
|
||||
this.write(packet);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the close timeout.
|
||||
*/
|
||||
|
||||
Transport.prototype.setCloseTimeout = function () {
|
||||
if (!this.closeTimeout) {
|
||||
var self = this;
|
||||
|
||||
this.closeTimeout = setTimeout(function () {
|
||||
self.log.debug('fired close timeout for client', self.id);
|
||||
self.closeTimeout = null;
|
||||
self.end('close timeout');
|
||||
}, this.manager.get('close timeout') * 1000);
|
||||
|
||||
this.log.debug('set close timeout for client', this.id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the close timeout.
|
||||
*/
|
||||
|
||||
Transport.prototype.clearCloseTimeout = function () {
|
||||
if (this.closeTimeout) {
|
||||
clearTimeout(this.closeTimeout);
|
||||
this.closeTimeout = null;
|
||||
|
||||
this.log.debug('cleared close timeout for client', this.id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the heartbeat timeout
|
||||
*/
|
||||
|
||||
Transport.prototype.setHeartbeatTimeout = function () {
|
||||
if (!this.heartbeatTimeout && this.manager.enabled('heartbeats')) {
|
||||
var self = this;
|
||||
|
||||
this.heartbeatTimeout = setTimeout(function () {
|
||||
self.log.debug('fired heartbeat timeout for client', self.id);
|
||||
self.heartbeatTimeout = null;
|
||||
self.end('heartbeat timeout');
|
||||
}, this.manager.get('heartbeat timeout') * 1000);
|
||||
|
||||
this.log.debug('set heartbeat timeout for client', this.id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the heartbeat timeout
|
||||
*
|
||||
* @param text
|
||||
*/
|
||||
|
||||
Transport.prototype.clearHeartbeatTimeout = function () {
|
||||
if (this.heartbeatTimeout && this.manager.enabled('heartbeats')) {
|
||||
clearTimeout(this.heartbeatTimeout);
|
||||
this.heartbeatTimeout = null;
|
||||
this.log.debug('cleared heartbeat timeout for client', this.id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the heartbeat interval. To be called when a connection opens and when
|
||||
* a heartbeat is received.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.setHeartbeatInterval = function () {
|
||||
if (!this.heartbeatInterval && this.manager.enabled('heartbeats')) {
|
||||
var self = this;
|
||||
|
||||
this.heartbeatInterval = setTimeout(function () {
|
||||
self.heartbeat();
|
||||
self.heartbeatInterval = null;
|
||||
}, this.manager.get('heartbeat interval') * 1000);
|
||||
|
||||
this.log.debug('set heartbeat interval for client', this.id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears all timeouts.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.clearTimeouts = function () {
|
||||
this.clearCloseTimeout();
|
||||
this.clearHeartbeatTimeout();
|
||||
this.clearHeartbeatInterval();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a heartbeat
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.heartbeat = function () {
|
||||
if (this.open) {
|
||||
this.log.debug('emitting heartbeat for client', this.id);
|
||||
this.packet({ type: 'heartbeat' });
|
||||
this.setHeartbeatTimeout();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a message.
|
||||
*
|
||||
* @param {Object} packet object
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onMessage = function (packet) {
|
||||
var current = this.manager.transports[this.id];
|
||||
|
||||
if ('heartbeat' == packet.type) {
|
||||
this.log.debug('got heartbeat packet');
|
||||
|
||||
if (current && current.open) {
|
||||
current.onHeartbeatClear();
|
||||
} else {
|
||||
this.store.publish('heartbeat-clear:' + this.id);
|
||||
}
|
||||
} else {
|
||||
if ('disconnect' == packet.type && packet.endpoint == '') {
|
||||
this.log.debug('got disconnection packet');
|
||||
|
||||
if (current) {
|
||||
current.onForcedDisconnect();
|
||||
} else {
|
||||
this.store.publish('disconnect-force:' + this.id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.id && packet.ack != 'data') {
|
||||
this.log.debug('acknowledging packet automatically');
|
||||
|
||||
var ack = parser.encodePacket({
|
||||
type: 'ack'
|
||||
, ackId: packet.id
|
||||
, endpoint: packet.endpoint || ''
|
||||
});
|
||||
|
||||
if (current && current.open) {
|
||||
current.onDispatch(ack);
|
||||
} else {
|
||||
this.manager.onClientDispatch(this.id, ack);
|
||||
this.store.publish('dispatch:' + this.id, ack);
|
||||
}
|
||||
}
|
||||
|
||||
// handle packet locally or publish it
|
||||
if (current) {
|
||||
this.manager.onClientMessage(this.id, packet);
|
||||
} else {
|
||||
this.store.publish('message:' + this.id, packet);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the heartbeat interval
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.clearHeartbeatInterval = function () {
|
||||
if (this.heartbeatInterval && this.manager.enabled('heartbeats')) {
|
||||
clearTimeout(this.heartbeatInterval);
|
||||
this.heartbeatInterval = null;
|
||||
this.log.debug('cleared heartbeat interval for client', this.id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Finishes the connection and makes sure client doesn't reopen
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.disconnect = function (reason) {
|
||||
this.packet({ type: 'disconnect' });
|
||||
this.end(reason);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the connection.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.close = function () {
|
||||
if (this.open) {
|
||||
this.doClose();
|
||||
this.onClose();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called upon a connection close.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.onClose = function () {
|
||||
if (this.open) {
|
||||
this.setCloseTimeout();
|
||||
this.clearHandlers();
|
||||
this.open = false;
|
||||
this.manager.onClose(this.id);
|
||||
this.store.publish('close', this.id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleans up the connection, considers the client disconnected.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.end = function (reason) {
|
||||
if (!this.disconnected) {
|
||||
this.log.info('transport end (' + reason + ')');
|
||||
|
||||
var local = this.manager.transports[this.id];
|
||||
|
||||
this.close();
|
||||
this.clearTimeouts();
|
||||
this.disconnected = true;
|
||||
|
||||
if (local) {
|
||||
this.manager.onClientDisconnect(this.id, reason, true);
|
||||
} else {
|
||||
this.store.publish('disconnect:' + this.id, reason);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Signals that the transport should pause and buffer data.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Transport.prototype.discard = function () {
|
||||
this.log.debug('discarding transport');
|
||||
this.discarded = true;
|
||||
this.clearTimeouts();
|
||||
this.clearHandlers();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes an error packet with the specified reason and advice.
|
||||
*
|
||||
* @param {Number} advice
|
||||
* @param {Number} reason
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Transport.prototype.error = function (reason, advice) {
|
||||
this.packet({
|
||||
type: 'error'
|
||||
, reason: reason
|
||||
, advice: advice
|
||||
});
|
||||
|
||||
this.log.warn(reason, advice ? ('client should ' + advice) : '');
|
||||
this.end('error');
|
||||
};
|
||||
|
||||
/**
|
||||
* Write a packet.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Transport.prototype.packet = function (obj) {
|
||||
return this.write(parser.encodePacket(obj));
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a volatile message.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Transport.prototype.writeVolatile = function (msg) {
|
||||
if (this.open) {
|
||||
if (this.drained) {
|
||||
this.write(msg);
|
||||
} else {
|
||||
this.log.debug('ignoring volatile packet, buffer not drained');
|
||||
}
|
||||
} else {
|
||||
this.log.debug('ignoring volatile packet, transport not open');
|
||||
}
|
||||
};
|
||||
129
node_modules/socket.io/lib/transports/flashsocket.js
generated
vendored
Normal file
129
node_modules/socket.io/lib/transports/flashsocket.js
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
var WebSocket = require('./websocket');
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = FlashSocket;
|
||||
|
||||
/**
|
||||
* The FlashSocket transport is just a proxy
|
||||
* for WebSocket connections.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function FlashSocket (mng, data, req) {
|
||||
return WebSocket.call(this, mng, data, req);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inherits from WebSocket.
|
||||
*/
|
||||
|
||||
FlashSocket.prototype.__proto__ = WebSocket.prototype;
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
FlashSocket.prototype.name = 'flashsocket';
|
||||
|
||||
/**
|
||||
* Listens for new configuration changes of the Manager
|
||||
* this way we can enable and disable the flash server.
|
||||
*
|
||||
* @param {Manager} Manager instance.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
|
||||
FlashSocket.init = function (manager) {
|
||||
var server;
|
||||
function create () {
|
||||
|
||||
// Drop out immediately if the user has
|
||||
// disabled the flash policy server
|
||||
if (!manager.get('flash policy server')) {
|
||||
return;
|
||||
}
|
||||
|
||||
server = require('policyfile').createServer({
|
||||
log: function(msg){
|
||||
manager.log.info(msg);
|
||||
}
|
||||
}, manager.get('origins'));
|
||||
|
||||
server.on('close', function (e) {
|
||||
server = null;
|
||||
});
|
||||
|
||||
server.listen(manager.get('flash policy port'), manager.server);
|
||||
|
||||
manager.flashPolicyServer = server;
|
||||
}
|
||||
|
||||
// listen for origin changes, so we can update the server
|
||||
manager.on('set:origins', function (value, key) {
|
||||
if (!server) return;
|
||||
|
||||
// update the origins and compile a new response buffer
|
||||
server.origins = Array.isArray(value) ? value : [value];
|
||||
server.compile();
|
||||
});
|
||||
|
||||
// destory the server and create a new server
|
||||
manager.on('set:flash policy port', function (value, key) {
|
||||
var transports = manager.get('transports');
|
||||
if (~transports.indexOf('flashsocket')) {
|
||||
if (server) {
|
||||
if (server.port === value) return;
|
||||
// destroy the server and rebuild it on a new port
|
||||
try {
|
||||
server.close();
|
||||
}
|
||||
catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ }
|
||||
}
|
||||
create();
|
||||
}
|
||||
});
|
||||
|
||||
// create or destroy the server
|
||||
manager.on('set:flash policy server', function (value, key) {
|
||||
var transports = manager.get('transports');
|
||||
if (~transports.indexOf('flashsocket')) {
|
||||
if (server && !value) {
|
||||
// destroy the server
|
||||
try {
|
||||
server.close();
|
||||
}
|
||||
catch (e) { /* ignore exception. could e.g. be that the server isn't started yet */ }
|
||||
}
|
||||
} else if (!server && value) {
|
||||
// create the server
|
||||
create();
|
||||
}
|
||||
});
|
||||
|
||||
// only start the server
|
||||
manager.on('set:transports', function (value, key){
|
||||
if (!server && ~manager.get('transports').indexOf('flashsocket')) {
|
||||
create();
|
||||
}
|
||||
});
|
||||
// check if we need to initialize at start
|
||||
if (~manager.get('transports').indexOf('flashsocket')){
|
||||
create();
|
||||
}
|
||||
};
|
||||
82
node_modules/socket.io/lib/transports/htmlfile.js
generated
vendored
Normal file
82
node_modules/socket.io/lib/transports/htmlfile.js
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var HTTPTransport = require('./http');
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = HTMLFile;
|
||||
|
||||
/**
|
||||
* HTMLFile transport constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function HTMLFile (mng, data, req) {
|
||||
HTTPTransport.call(this, mng, data, req);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Transport.
|
||||
*/
|
||||
|
||||
HTMLFile.prototype.__proto__ = HTTPTransport.prototype;
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
HTMLFile.prototype.name = 'htmlfile';
|
||||
|
||||
/**
|
||||
* Handles the request.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTMLFile.prototype.handleRequest = function (req) {
|
||||
HTTPTransport.prototype.handleRequest.call(this, req);
|
||||
|
||||
if (req.method == 'GET') {
|
||||
req.res.writeHead(200, {
|
||||
'Content-Type': 'text/html; charset=UTF-8'
|
||||
, 'Connection': 'keep-alive'
|
||||
, 'Transfer-Encoding': 'chunked'
|
||||
});
|
||||
|
||||
req.res.write(
|
||||
'<html><body>'
|
||||
+ '<script>var _ = function (msg) { parent.s._(msg, document); };</script>'
|
||||
+ new Array(174).join(' ')
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs the write.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTMLFile.prototype.write = function (data) {
|
||||
data = '<script>_(' + JSON.stringify(data) + ');</script>';
|
||||
|
||||
if (this.response.write(data)) {
|
||||
this.drained = true;
|
||||
}
|
||||
|
||||
this.log.debug(this.name + ' writing', data);
|
||||
};
|
||||
147
node_modules/socket.io/lib/transports/http-polling.js
generated
vendored
Normal file
147
node_modules/socket.io/lib/transports/http-polling.js
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var HTTPTransport = require('./http');
|
||||
|
||||
/**
|
||||
* Exports the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = HTTPPolling;
|
||||
|
||||
/**
|
||||
* HTTP polling constructor.
|
||||
*
|
||||
* @api public.
|
||||
*/
|
||||
|
||||
function HTTPPolling (mng, data, req) {
|
||||
HTTPTransport.call(this, mng, data, req);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from HTTPTransport.
|
||||
*
|
||||
* @api public.
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.__proto__ = HTTPTransport.prototype;
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.name = 'httppolling';
|
||||
|
||||
/**
|
||||
* Override setHandlers
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.setHandlers = function () {
|
||||
HTTPTransport.prototype.setHandlers.call(this);
|
||||
this.socket.removeListener('end', this.bound.end);
|
||||
this.socket.removeListener('close', this.bound.close);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes heartbeat timeouts for polling.
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.setHeartbeatInterval = function () {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a request
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.handleRequest = function (req) {
|
||||
HTTPTransport.prototype.handleRequest.call(this, req);
|
||||
|
||||
if (req.method == 'GET') {
|
||||
var self = this;
|
||||
|
||||
this.pollTimeout = setTimeout(function () {
|
||||
self.packet({ type: 'noop' });
|
||||
self.log.debug(self.name + ' closed due to exceeded duration');
|
||||
}, this.manager.get('polling duration') * 1000);
|
||||
|
||||
this.log.debug('setting poll timeout');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears polling timeout
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.clearPollTimeout = function () {
|
||||
if (this.pollTimeout) {
|
||||
clearTimeout(this.pollTimeout);
|
||||
this.pollTimeout = null;
|
||||
this.log.debug('clearing poll timeout');
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Override clear timeouts to clear the poll timeout
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.clearTimeouts = function () {
|
||||
HTTPTransport.prototype.clearTimeouts.call(this);
|
||||
|
||||
this.clearPollTimeout();
|
||||
};
|
||||
|
||||
/**
|
||||
* doWrite to clear poll timeout
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.doWrite = function () {
|
||||
this.clearPollTimeout();
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs a write.
|
||||
*
|
||||
* @api private.
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.write = function (data, close) {
|
||||
this.doWrite(data);
|
||||
this.response.end();
|
||||
this.onClose();
|
||||
};
|
||||
|
||||
/**
|
||||
* Override end.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPPolling.prototype.end = function (reason) {
|
||||
this.clearPollTimeout();
|
||||
return HTTPTransport.prototype.end.call(this, reason);
|
||||
};
|
||||
|
||||
121
node_modules/socket.io/lib/transports/http.js
generated
vendored
Normal file
121
node_modules/socket.io/lib/transports/http.js
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var Transport = require('../transport')
|
||||
, parser = require('../parser')
|
||||
, qs = require('querystring');
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = HTTPTransport;
|
||||
|
||||
/**
|
||||
* HTTP interface constructor. For all non-websocket transports.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function HTTPTransport (mng, data, req) {
|
||||
Transport.call(this, mng, data, req);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Transport.
|
||||
*/
|
||||
|
||||
HTTPTransport.prototype.__proto__ = Transport.prototype;
|
||||
|
||||
/**
|
||||
* Handles a request.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPTransport.prototype.handleRequest = function (req) {
|
||||
|
||||
// Always set the response in case an error is returned to the client
|
||||
this.response = req.res;
|
||||
|
||||
if (req.method == 'POST') {
|
||||
var buffer = ''
|
||||
, res = req.res
|
||||
, origin = req.headers.origin
|
||||
, headers = { 'Content-Length': 1, 'Content-Type': 'text/plain; charset=UTF-8' }
|
||||
, self = this;
|
||||
|
||||
req.on('data', function (data) {
|
||||
buffer += data;
|
||||
|
||||
if (Buffer.byteLength(buffer) >= self.manager.get('destroy buffer size')) {
|
||||
buffer = '';
|
||||
req.connection.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
req.on('end', function () {
|
||||
res.writeHead(200, headers);
|
||||
res.end('1');
|
||||
|
||||
self.onData(self.postEncoded ? qs.parse(buffer).d : buffer);
|
||||
});
|
||||
|
||||
// prevent memory leaks for uncompleted requests
|
||||
req.on('close', function () {
|
||||
buffer = '';
|
||||
self.onClose();
|
||||
});
|
||||
|
||||
if (origin) {
|
||||
// https://developer.mozilla.org/En/HTTP_Access_Control
|
||||
headers['Access-Control-Allow-Origin'] = origin;
|
||||
headers['Access-Control-Allow-Credentials'] = 'true';
|
||||
}
|
||||
} else {
|
||||
Transport.prototype.handleRequest.call(this, req);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles data payload.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPTransport.prototype.onData = function (data) {
|
||||
var messages = parser.decodePayload(data);
|
||||
this.log.debug(this.name + ' received data packet', data);
|
||||
|
||||
for (var i = 0, l = messages.length; i < l; i++) {
|
||||
this.onMessage(messages[i]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the request-response cycle
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPTransport.prototype.doClose = function () {
|
||||
this.response.end();
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a payload of messages
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
HTTPTransport.prototype.payload = function (msgs) {
|
||||
this.write(parser.encodePayload(msgs));
|
||||
};
|
||||
12
node_modules/socket.io/lib/transports/index.js
generated
vendored
Normal file
12
node_modules/socket.io/lib/transports/index.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
/**
|
||||
* Export transports.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
websocket: require('./websocket')
|
||||
, flashsocket: require('./flashsocket')
|
||||
, htmlfile: require('./htmlfile')
|
||||
, 'xhr-polling': require('./xhr-polling')
|
||||
, 'jsonp-polling': require('./jsonp-polling')
|
||||
};
|
||||
97
node_modules/socket.io/lib/transports/jsonp-polling.js
generated
vendored
Normal file
97
node_modules/socket.io/lib/transports/jsonp-polling.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var HTTPPolling = require('./http-polling');
|
||||
var jsonpolling_re = /^\d+$/
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = JSONPPolling;
|
||||
|
||||
/**
|
||||
* JSON-P polling transport.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function JSONPPolling (mng, data, req) {
|
||||
HTTPPolling.call(this, mng, data, req);
|
||||
|
||||
this.head = 'io.j[0](';
|
||||
this.foot = ');';
|
||||
|
||||
if (data.query.i && jsonpolling_re.test(data.query.i)) {
|
||||
this.head = 'io.j[' + data.query.i + '](';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Transport.
|
||||
*/
|
||||
|
||||
JSONPPolling.prototype.__proto__ = HTTPPolling.prototype;
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
JSONPPolling.prototype.name = 'jsonppolling';
|
||||
|
||||
/**
|
||||
* Make sure POST are decoded.
|
||||
*/
|
||||
|
||||
JSONPPolling.prototype.postEncoded = true;
|
||||
|
||||
/**
|
||||
* Handles incoming data.
|
||||
* Due to a bug in \n handling by browsers, we expect a JSONified string.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
JSONPPolling.prototype.onData = function (data) {
|
||||
try {
|
||||
data = JSON.parse(data);
|
||||
} catch (e) {
|
||||
this.error('parse', 'reconnect');
|
||||
return;
|
||||
}
|
||||
|
||||
HTTPPolling.prototype.onData.call(this, data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs the write.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
JSONPPolling.prototype.doWrite = function (data) {
|
||||
HTTPPolling.prototype.doWrite.call(this);
|
||||
|
||||
var data = data === undefined
|
||||
? '' : this.head + JSON.stringify(data) + this.foot;
|
||||
|
||||
this.response.writeHead(200, {
|
||||
'Content-Type': 'text/javascript; charset=UTF-8'
|
||||
, 'Content-Length': Buffer.byteLength(data)
|
||||
, 'Connection': 'Keep-Alive'
|
||||
, 'X-XSS-Protection': '0'
|
||||
});
|
||||
|
||||
this.response.write(data);
|
||||
this.log.debug(this.name + ' writing', data);
|
||||
};
|
||||
36
node_modules/socket.io/lib/transports/websocket.js
generated
vendored
Normal file
36
node_modules/socket.io/lib/transports/websocket.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var protocolVersions = require('./websocket/');
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = WebSocket;
|
||||
|
||||
/**
|
||||
* HTTP interface constructor. Interface compatible with all transports that
|
||||
* depend on request-response cycles.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function WebSocket (mng, data, req) {
|
||||
var transport
|
||||
, version = req.headers['sec-websocket-version'];
|
||||
if (typeof version !== 'undefined' && typeof protocolVersions[version] !== 'undefined') {
|
||||
transport = new protocolVersions[version](mng, data, req);
|
||||
}
|
||||
else transport = new protocolVersions['default'](mng, data, req);
|
||||
if (typeof this.name !== 'undefined') transport.name = this.name;
|
||||
return transport;
|
||||
};
|
||||
362
node_modules/socket.io/lib/transports/websocket/default.js
generated
vendored
Normal file
362
node_modules/socket.io/lib/transports/websocket/default.js
generated
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var Transport = require('../../transport')
|
||||
, EventEmitter = process.EventEmitter
|
||||
, crypto = require('crypto')
|
||||
, parser = require('../../parser');
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = WebSocket;
|
||||
|
||||
/**
|
||||
* HTTP interface constructor. Interface compatible with all transports that
|
||||
* depend on request-response cycles.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function WebSocket (mng, data, req) {
|
||||
// parser
|
||||
var self = this;
|
||||
|
||||
this.parser = new Parser();
|
||||
this.parser.on('data', function (packet) {
|
||||
self.log.debug(self.name + ' received data packet', packet);
|
||||
self.onMessage(parser.decodePacket(packet));
|
||||
});
|
||||
this.parser.on('close', function () {
|
||||
self.end();
|
||||
});
|
||||
this.parser.on('error', function () {
|
||||
self.end();
|
||||
});
|
||||
|
||||
Transport.call(this, mng, data, req);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Transport.
|
||||
*/
|
||||
|
||||
WebSocket.prototype.__proto__ = Transport.prototype;
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocket.prototype.name = 'websocket';
|
||||
|
||||
/**
|
||||
* Websocket draft version
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocket.prototype.protocolVersion = 'hixie-76';
|
||||
|
||||
/**
|
||||
* Called when the socket connects.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.onSocketConnect = function () {
|
||||
var self = this;
|
||||
|
||||
this.socket.setNoDelay(true);
|
||||
|
||||
this.buffer = true;
|
||||
this.buffered = [];
|
||||
|
||||
if (this.req.headers.upgrade !== 'WebSocket') {
|
||||
this.log.warn(this.name + ' connection invalid');
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
var origin = this.req.headers['origin']
|
||||
, waitingForNonce = false;
|
||||
if(this.manager.settings['match origin protocol']){
|
||||
location = (origin.indexOf('https')>-1 ? 'wss' : 'ws') + '://' + this.req.headers.host + this.req.url;
|
||||
}else if(this.socket.encrypted){
|
||||
location = 'wss://' + this.req.headers.host + this.req.url;
|
||||
}else{
|
||||
location = 'ws://' + this.req.headers.host + this.req.url;
|
||||
}
|
||||
|
||||
if (this.req.headers['sec-websocket-key1']) {
|
||||
// If we don't have the nonce yet, wait for it (HAProxy compatibility).
|
||||
if (! (this.req.head && this.req.head.length >= 8)) {
|
||||
waitingForNonce = true;
|
||||
}
|
||||
|
||||
var headers = [
|
||||
'HTTP/1.1 101 WebSocket Protocol Handshake'
|
||||
, 'Upgrade: WebSocket'
|
||||
, 'Connection: Upgrade'
|
||||
, 'Sec-WebSocket-Origin: ' + origin
|
||||
, 'Sec-WebSocket-Location: ' + location
|
||||
];
|
||||
|
||||
if (this.req.headers['sec-websocket-protocol']){
|
||||
headers.push('Sec-WebSocket-Protocol: '
|
||||
+ this.req.headers['sec-websocket-protocol']);
|
||||
}
|
||||
} else {
|
||||
var headers = [
|
||||
'HTTP/1.1 101 Web Socket Protocol Handshake'
|
||||
, 'Upgrade: WebSocket'
|
||||
, 'Connection: Upgrade'
|
||||
, 'WebSocket-Origin: ' + origin
|
||||
, 'WebSocket-Location: ' + location
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
this.socket.write(headers.concat('', '').join('\r\n'));
|
||||
this.socket.setTimeout(0);
|
||||
this.socket.setNoDelay(true);
|
||||
this.socket.setEncoding('utf8');
|
||||
} catch (e) {
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (waitingForNonce) {
|
||||
this.socket.setEncoding('binary');
|
||||
} else if (this.proveReception(headers)) {
|
||||
self.flush();
|
||||
}
|
||||
|
||||
var headBuffer = '';
|
||||
|
||||
this.socket.on('data', function (data) {
|
||||
if (waitingForNonce) {
|
||||
headBuffer += data;
|
||||
|
||||
if (headBuffer.length < 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore the connection to utf8 encoding after receiving the nonce
|
||||
self.socket.setEncoding('utf8');
|
||||
waitingForNonce = false;
|
||||
|
||||
// Stuff the nonce into the location where it's expected to be
|
||||
self.req.head = headBuffer.substr(0, 8);
|
||||
headBuffer = '';
|
||||
|
||||
if (self.proveReception(headers)) {
|
||||
self.flush();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
self.parser.add(data);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes to the socket.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.write = function (data) {
|
||||
if (this.open) {
|
||||
this.drained = false;
|
||||
|
||||
if (this.buffer) {
|
||||
this.buffered.push(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
var length = Buffer.byteLength(data)
|
||||
, buffer = new Buffer(2 + length);
|
||||
|
||||
buffer.write('\x00', 'binary');
|
||||
buffer.write(data, 1, 'utf8');
|
||||
buffer.write('\xff', 1 + length, 'binary');
|
||||
|
||||
try {
|
||||
if (this.socket.write(buffer)) {
|
||||
this.drained = true;
|
||||
}
|
||||
} catch (e) {
|
||||
this.end();
|
||||
}
|
||||
|
||||
this.log.debug(this.name + ' writing', data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Flushes the internal buffer
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.flush = function () {
|
||||
this.buffer = false;
|
||||
|
||||
for (var i = 0, l = this.buffered.length; i < l; i++) {
|
||||
this.write(this.buffered.splice(0, 1)[0]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Finishes the handshake.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.proveReception = function (headers) {
|
||||
var self = this
|
||||
, k1 = this.req.headers['sec-websocket-key1']
|
||||
, k2 = this.req.headers['sec-websocket-key2'];
|
||||
|
||||
if (k1 && k2){
|
||||
var md5 = crypto.createHash('md5');
|
||||
|
||||
[k1, k2].forEach(function (k) {
|
||||
var n = parseInt(k.replace(/[^\d]/g, ''))
|
||||
, spaces = k.replace(/[^ ]/g, '').length;
|
||||
|
||||
if (spaces === 0 || n % spaces !== 0){
|
||||
self.log.warn('Invalid ' + self.name + ' key: "' + k + '".');
|
||||
self.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
n /= spaces;
|
||||
|
||||
md5.update(String.fromCharCode(
|
||||
n >> 24 & 0xFF,
|
||||
n >> 16 & 0xFF,
|
||||
n >> 8 & 0xFF,
|
||||
n & 0xFF));
|
||||
});
|
||||
|
||||
md5.update(this.req.head.toString('binary'));
|
||||
|
||||
try {
|
||||
this.socket.write(md5.digest('binary'), 'binary');
|
||||
} catch (e) {
|
||||
this.end();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a payload.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.payload = function (msgs) {
|
||||
for (var i = 0, l = msgs.length; i < l; i++) {
|
||||
this.write(msgs[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the connection.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.doClose = function () {
|
||||
this.socket.end();
|
||||
};
|
||||
|
||||
/**
|
||||
* WebSocket parser
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Parser () {
|
||||
this.buffer = '';
|
||||
this.i = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
Parser.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
/**
|
||||
* Adds data to the buffer.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Parser.prototype.add = function (data) {
|
||||
this.buffer += data;
|
||||
this.parse();
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses the buffer.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.parse = function () {
|
||||
for (var i = this.i, chr, l = this.buffer.length; i < l; i++){
|
||||
chr = this.buffer[i];
|
||||
|
||||
if (this.buffer.length == 2 && this.buffer[1] == '\u0000') {
|
||||
this.emit('close');
|
||||
this.buffer = '';
|
||||
this.i = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (i === 0){
|
||||
if (chr != '\u0000')
|
||||
this.error('Bad framing. Expected null byte as first frame');
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chr == '\ufffd'){
|
||||
this.emit('data', this.buffer.substr(1, i - 1));
|
||||
this.buffer = this.buffer.substr(i + 1);
|
||||
this.i = 0;
|
||||
return this.parse();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.error = function (reason) {
|
||||
this.buffer = '';
|
||||
this.i = 0;
|
||||
this.emit('error', reason);
|
||||
return this;
|
||||
};
|
||||
622
node_modules/socket.io/lib/transports/websocket/hybi-07-12.js
generated
vendored
Normal file
622
node_modules/socket.io/lib/transports/websocket/hybi-07-12.js
generated
vendored
Normal file
@@ -0,0 +1,622 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var Transport = require('../../transport')
|
||||
, EventEmitter = process.EventEmitter
|
||||
, crypto = require('crypto')
|
||||
, url = require('url')
|
||||
, parser = require('../../parser')
|
||||
, util = require('../../util');
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = WebSocket;
|
||||
exports.Parser = Parser;
|
||||
|
||||
/**
|
||||
* HTTP interface constructor. Interface compatible with all transports that
|
||||
* depend on request-response cycles.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function WebSocket (mng, data, req) {
|
||||
// parser
|
||||
var self = this;
|
||||
|
||||
this.manager = mng;
|
||||
this.parser = new Parser();
|
||||
this.parser.on('data', function (packet) {
|
||||
self.onMessage(parser.decodePacket(packet));
|
||||
});
|
||||
this.parser.on('ping', function () {
|
||||
// version 8 ping => pong
|
||||
try {
|
||||
self.socket.write('\u008a\u0000');
|
||||
}
|
||||
catch (e) {
|
||||
self.end();
|
||||
return;
|
||||
}
|
||||
});
|
||||
this.parser.on('close', function () {
|
||||
self.end();
|
||||
});
|
||||
this.parser.on('error', function (reason) {
|
||||
self.log.warn(self.name + ' parser error: ' + reason);
|
||||
self.end();
|
||||
});
|
||||
|
||||
Transport.call(this, mng, data, req);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Transport.
|
||||
*/
|
||||
|
||||
WebSocket.prototype.__proto__ = Transport.prototype;
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocket.prototype.name = 'websocket';
|
||||
|
||||
/**
|
||||
* Websocket draft version
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocket.prototype.protocolVersion = '07-12';
|
||||
|
||||
/**
|
||||
* Called when the socket connects.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.onSocketConnect = function () {
|
||||
var self = this;
|
||||
|
||||
if (typeof this.req.headers.upgrade === 'undefined' ||
|
||||
this.req.headers.upgrade.toLowerCase() !== 'websocket') {
|
||||
this.log.warn(this.name + ' connection invalid');
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
var origin = this.req.headers['sec-websocket-origin']
|
||||
, location = ((this.manager.settings['match origin protocol'] ?
|
||||
origin.match(/^https/) : this.socket.encrypted) ?
|
||||
'wss' : 'ws')
|
||||
+ '://' + this.req.headers.host + this.req.url;
|
||||
|
||||
if (!this.verifyOrigin(origin)) {
|
||||
this.log.warn(this.name + ' connection invalid: origin mismatch');
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.req.headers['sec-websocket-key']) {
|
||||
this.log.warn(this.name + ' connection invalid: received no key');
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// calc key
|
||||
var key = this.req.headers['sec-websocket-key'];
|
||||
var shasum = crypto.createHash('sha1');
|
||||
shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
key = shasum.digest('base64');
|
||||
|
||||
var headers = [
|
||||
'HTTP/1.1 101 Switching Protocols'
|
||||
, 'Upgrade: websocket'
|
||||
, 'Connection: Upgrade'
|
||||
, 'Sec-WebSocket-Accept: ' + key
|
||||
];
|
||||
|
||||
try {
|
||||
this.socket.write(headers.concat('', '').join('\r\n'));
|
||||
this.socket.setTimeout(0);
|
||||
this.socket.setNoDelay(true);
|
||||
} catch (e) {
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
this.socket.on('data', function (data) {
|
||||
self.parser.add(data);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Verifies the origin of a request.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.verifyOrigin = function (origin) {
|
||||
var origins = this.manager.get('origins');
|
||||
|
||||
if (origin === 'null') origin = '*';
|
||||
|
||||
if (origins.indexOf('*:*') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (origin) {
|
||||
try {
|
||||
var parts = url.parse(origin);
|
||||
parts.port = parts.port || 80;
|
||||
var ok =
|
||||
~origins.indexOf(parts.hostname + ':' + parts.port) ||
|
||||
~origins.indexOf(parts.hostname + ':*') ||
|
||||
~origins.indexOf('*:' + parts.port);
|
||||
if (!ok) this.log.warn('illegal origin: ' + origin);
|
||||
return ok;
|
||||
} catch (ex) {
|
||||
this.log.warn('error parsing origin');
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.log.warn('origin missing from websocket call, yet required by config');
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes to the socket.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.write = function (data) {
|
||||
if (this.open) {
|
||||
var buf = this.frame(0x81, data);
|
||||
try {
|
||||
this.socket.write(buf, 'binary');
|
||||
}
|
||||
catch (e) {
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
this.log.debug(this.name + ' writing', data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a payload.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.payload = function (msgs) {
|
||||
for (var i = 0, l = msgs.length; i < l; i++) {
|
||||
this.write(msgs[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Frame server-to-client output as a text packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.frame = function (opcode, str) {
|
||||
var dataBuffer = new Buffer(str)
|
||||
, dataLength = dataBuffer.length
|
||||
, startOffset = 2
|
||||
, secondByte = dataLength;
|
||||
if (dataLength > 65536) {
|
||||
startOffset = 10;
|
||||
secondByte = 127;
|
||||
}
|
||||
else if (dataLength > 125) {
|
||||
startOffset = 4;
|
||||
secondByte = 126;
|
||||
}
|
||||
var outputBuffer = new Buffer(dataLength + startOffset);
|
||||
outputBuffer[0] = opcode;
|
||||
outputBuffer[1] = secondByte;
|
||||
dataBuffer.copy(outputBuffer, startOffset);
|
||||
switch (secondByte) {
|
||||
case 126:
|
||||
outputBuffer[2] = dataLength >>> 8;
|
||||
outputBuffer[3] = dataLength % 256;
|
||||
break;
|
||||
case 127:
|
||||
var l = dataLength;
|
||||
for (var i = 1; i <= 8; ++i) {
|
||||
outputBuffer[startOffset - i] = l & 0xff;
|
||||
l >>>= 8;
|
||||
}
|
||||
}
|
||||
return outputBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the connection.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.doClose = function () {
|
||||
this.socket.end();
|
||||
};
|
||||
|
||||
/**
|
||||
* WebSocket parser
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Parser () {
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
masked: false,
|
||||
opcode: 0
|
||||
};
|
||||
this.overflow = null;
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.currentMessage = '';
|
||||
|
||||
var self = this;
|
||||
this.opcodeHandlers = {
|
||||
// text
|
||||
'1': function(data) {
|
||||
var finish = function(mask, data) {
|
||||
self.currentMessage += self.unmask(mask, data);
|
||||
if (self.state.lastFragment) {
|
||||
self.emit('data', self.currentMessage);
|
||||
self.currentMessage = '';
|
||||
}
|
||||
self.endPacket();
|
||||
}
|
||||
|
||||
var expectData = function(length) {
|
||||
if (self.state.masked) {
|
||||
self.expect('Mask', 4, function(data) {
|
||||
var mask = data;
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(null, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
expectData(firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expect('Length', 2, function(data) {
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expect('Length', 8, function(data) {
|
||||
if (util.unpack(data.slice(0, 4)) != 0) {
|
||||
self.error('packets with length spanning more than 32 bit is currently not supported');
|
||||
return;
|
||||
}
|
||||
var lengthBytes = data.slice(4); // note: cap to 32 bit length
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
},
|
||||
// binary
|
||||
'2': function(data) {
|
||||
var finish = function(mask, data) {
|
||||
if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list
|
||||
self.currentMessage.push(self.unmask(mask, data, true));
|
||||
if (self.state.lastFragment) {
|
||||
self.emit('binary', self.concatBuffers(self.currentMessage));
|
||||
self.currentMessage = '';
|
||||
}
|
||||
self.endPacket();
|
||||
}
|
||||
|
||||
var expectData = function(length) {
|
||||
if (self.state.masked) {
|
||||
self.expect('Mask', 4, function(data) {
|
||||
var mask = data;
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(null, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
expectData(firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expect('Length', 2, function(data) {
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expect('Length', 8, function(data) {
|
||||
if (util.unpack(data.slice(0, 4)) != 0) {
|
||||
self.error('packets with length spanning more than 32 bit is currently not supported');
|
||||
return;
|
||||
}
|
||||
var lengthBytes = data.slice(4); // note: cap to 32 bit length
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
},
|
||||
// close
|
||||
'8': function(data) {
|
||||
self.emit('close');
|
||||
self.reset();
|
||||
},
|
||||
// ping
|
||||
'9': function(data) {
|
||||
if (self.state.lastFragment == false) {
|
||||
self.error('fragmented ping is not supported');
|
||||
return;
|
||||
}
|
||||
|
||||
var finish = function(mask, data) {
|
||||
self.emit('ping', self.unmask(mask, data));
|
||||
self.endPacket();
|
||||
}
|
||||
|
||||
var expectData = function(length) {
|
||||
if (self.state.masked) {
|
||||
self.expect('Mask', 4, function(data) {
|
||||
var mask = data;
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(null, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength == 0) {
|
||||
finish(null, null);
|
||||
}
|
||||
else if (firstLength < 126) {
|
||||
expectData(firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expect('Length', 2, function(data) {
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expect('Length', 8, function(data) {
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.expect('Opcode', 2, this.processPacket);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
Parser.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
/**
|
||||
* Add new data to the parser.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Parser.prototype.add = function(data) {
|
||||
if (this.expectBuffer == null) {
|
||||
this.addToOverflow(data);
|
||||
return;
|
||||
}
|
||||
var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
|
||||
data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
|
||||
this.expectOffset += toRead;
|
||||
if (toRead < data.length) {
|
||||
// at this point the overflow buffer shouldn't at all exist
|
||||
this.overflow = new Buffer(data.length - toRead);
|
||||
data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
|
||||
}
|
||||
if (this.expectOffset == this.expectBuffer.length) {
|
||||
var bufferForHandler = this.expectBuffer;
|
||||
this.expectBuffer = null;
|
||||
this.expectOffset = 0;
|
||||
this.expectHandler.call(this, bufferForHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a piece of data to the overflow.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.addToOverflow = function(data) {
|
||||
if (this.overflow == null) this.overflow = data;
|
||||
else {
|
||||
var prevOverflow = this.overflow;
|
||||
this.overflow = new Buffer(this.overflow.length + data.length);
|
||||
prevOverflow.copy(this.overflow, 0);
|
||||
data.copy(this.overflow, prevOverflow.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a certain amount of bytes to be available, then fires a callback.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.expect = function(what, length, handler) {
|
||||
this.expectBuffer = new Buffer(length);
|
||||
this.expectOffset = 0;
|
||||
this.expectHandler = handler;
|
||||
if (this.overflow != null) {
|
||||
var toOverflow = this.overflow;
|
||||
this.overflow = null;
|
||||
this.add(toOverflow);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing a new packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.processPacket = function (data) {
|
||||
if ((data[0] & 0x70) != 0) {
|
||||
this.error('reserved fields must be empty');
|
||||
}
|
||||
this.state.lastFragment = (data[0] & 0x80) == 0x80;
|
||||
this.state.masked = (data[1] & 0x80) == 0x80;
|
||||
var opcode = data[0] & 0xf;
|
||||
if (opcode == 0) {
|
||||
// continuation frame
|
||||
this.state.opcode = this.state.activeFragmentedOperation;
|
||||
if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
|
||||
this.error('continuation frame cannot follow current opcode')
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.state.opcode = opcode;
|
||||
if (this.state.lastFragment === false) {
|
||||
this.state.activeFragmentedOperation = opcode;
|
||||
}
|
||||
}
|
||||
var handler = this.opcodeHandlers[this.state.opcode];
|
||||
if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
|
||||
else handler(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Endprocessing a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.endPacket = function() {
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
|
||||
// end current fragmented operation
|
||||
this.state.activeFragmentedOperation = null;
|
||||
}
|
||||
this.state.lastFragment = false;
|
||||
this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
|
||||
this.state.masked = false;
|
||||
this.expect('Opcode', 2, this.processPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the parser state.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.reset = function() {
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
masked: false,
|
||||
opcode: 0
|
||||
};
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.overflow = null;
|
||||
this.currentMessage = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmask received data.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.unmask = function (mask, buf, binary) {
|
||||
if (mask != null) {
|
||||
for (var i = 0, ll = buf.length; i < ll; i++) {
|
||||
buf[i] ^= mask[i % 4];
|
||||
}
|
||||
}
|
||||
if (binary) return buf;
|
||||
return buf != null ? buf.toString('utf8') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates a list of buffers.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.concatBuffers = function(buffers) {
|
||||
var length = 0;
|
||||
for (var i = 0, l = buffers.length; i < l; ++i) {
|
||||
length += buffers[i].length;
|
||||
}
|
||||
var mergedBuffer = new Buffer(length);
|
||||
var offset = 0;
|
||||
for (var i = 0, l = buffers.length; i < l; ++i) {
|
||||
buffers[i].copy(mergedBuffer, offset);
|
||||
offset += buffers[i].length;
|
||||
}
|
||||
return mergedBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.error = function (reason) {
|
||||
this.reset();
|
||||
this.emit('error', reason);
|
||||
return this;
|
||||
};
|
||||
622
node_modules/socket.io/lib/transports/websocket/hybi-16.js
generated
vendored
Normal file
622
node_modules/socket.io/lib/transports/websocket/hybi-16.js
generated
vendored
Normal file
@@ -0,0 +1,622 @@
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var Transport = require('../../transport')
|
||||
, EventEmitter = process.EventEmitter
|
||||
, crypto = require('crypto')
|
||||
, url = require('url')
|
||||
, parser = require('../../parser')
|
||||
, util = require('../../util');
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = WebSocket;
|
||||
exports.Parser = Parser;
|
||||
|
||||
/**
|
||||
* HTTP interface constructor. Interface compatible with all transports that
|
||||
* depend on request-response cycles.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function WebSocket (mng, data, req) {
|
||||
// parser
|
||||
var self = this;
|
||||
|
||||
this.manager = mng;
|
||||
this.parser = new Parser();
|
||||
this.parser.on('data', function (packet) {
|
||||
self.onMessage(parser.decodePacket(packet));
|
||||
});
|
||||
this.parser.on('ping', function () {
|
||||
// version 8 ping => pong
|
||||
try {
|
||||
self.socket.write('\u008a\u0000');
|
||||
}
|
||||
catch (e) {
|
||||
self.end();
|
||||
return;
|
||||
}
|
||||
});
|
||||
this.parser.on('close', function () {
|
||||
self.end();
|
||||
});
|
||||
this.parser.on('error', function (reason) {
|
||||
self.log.warn(self.name + ' parser error: ' + reason);
|
||||
self.end();
|
||||
});
|
||||
|
||||
Transport.call(this, mng, data, req);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Transport.
|
||||
*/
|
||||
|
||||
WebSocket.prototype.__proto__ = Transport.prototype;
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocket.prototype.name = 'websocket';
|
||||
|
||||
/**
|
||||
* Websocket draft version
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
WebSocket.prototype.protocolVersion = '16';
|
||||
|
||||
/**
|
||||
* Called when the socket connects.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.onSocketConnect = function () {
|
||||
var self = this;
|
||||
|
||||
if (typeof this.req.headers.upgrade === 'undefined' ||
|
||||
this.req.headers.upgrade.toLowerCase() !== 'websocket') {
|
||||
this.log.warn(this.name + ' connection invalid');
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
var origin = this.req.headers['origin'] || ''
|
||||
, location = ((this.manager.settings['match origin protocol'] ?
|
||||
origin.match(/^https/) : this.socket.encrypted) ?
|
||||
'wss' : 'ws')
|
||||
+ '://' + this.req.headers.host + this.req.url;
|
||||
|
||||
if (!this.verifyOrigin(origin)) {
|
||||
this.log.warn(this.name + ' connection invalid: origin mismatch');
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.req.headers['sec-websocket-key']) {
|
||||
this.log.warn(this.name + ' connection invalid: received no key');
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// calc key
|
||||
var key = this.req.headers['sec-websocket-key'];
|
||||
var shasum = crypto.createHash('sha1');
|
||||
shasum.update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
|
||||
key = shasum.digest('base64');
|
||||
|
||||
var headers = [
|
||||
'HTTP/1.1 101 Switching Protocols'
|
||||
, 'Upgrade: websocket'
|
||||
, 'Connection: Upgrade'
|
||||
, 'Sec-WebSocket-Accept: ' + key
|
||||
];
|
||||
|
||||
try {
|
||||
this.socket.write(headers.concat('', '').join('\r\n'));
|
||||
this.socket.setTimeout(0);
|
||||
this.socket.setNoDelay(true);
|
||||
} catch (e) {
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
|
||||
this.socket.on('data', function (data) {
|
||||
self.parser.add(data);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Verifies the origin of a request.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.verifyOrigin = function (origin) {
|
||||
var origins = this.manager.get('origins');
|
||||
|
||||
if (origin === 'null') origin = '*';
|
||||
|
||||
if (origins.indexOf('*:*') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (origin) {
|
||||
try {
|
||||
var parts = url.parse(origin);
|
||||
parts.port = parts.port || 80;
|
||||
var ok =
|
||||
~origins.indexOf(parts.hostname + ':' + parts.port) ||
|
||||
~origins.indexOf(parts.hostname + ':*') ||
|
||||
~origins.indexOf('*:' + parts.port);
|
||||
if (!ok) this.log.warn('illegal origin: ' + origin);
|
||||
return ok;
|
||||
} catch (ex) {
|
||||
this.log.warn('error parsing origin');
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.log.warn('origin missing from websocket call, yet required by config');
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes to the socket.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.write = function (data) {
|
||||
if (this.open) {
|
||||
var buf = this.frame(0x81, data);
|
||||
try {
|
||||
this.socket.write(buf, 'binary');
|
||||
}
|
||||
catch (e) {
|
||||
this.end();
|
||||
return;
|
||||
}
|
||||
this.log.debug(this.name + ' writing', data);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes a payload.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.payload = function (msgs) {
|
||||
for (var i = 0, l = msgs.length; i < l; i++) {
|
||||
this.write(msgs[i]);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Frame server-to-client output as a text packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.frame = function (opcode, str) {
|
||||
var dataBuffer = new Buffer(str)
|
||||
, dataLength = dataBuffer.length
|
||||
, startOffset = 2
|
||||
, secondByte = dataLength;
|
||||
if (dataLength > 65536) {
|
||||
startOffset = 10;
|
||||
secondByte = 127;
|
||||
}
|
||||
else if (dataLength > 125) {
|
||||
startOffset = 4;
|
||||
secondByte = 126;
|
||||
}
|
||||
var outputBuffer = new Buffer(dataLength + startOffset);
|
||||
outputBuffer[0] = opcode;
|
||||
outputBuffer[1] = secondByte;
|
||||
dataBuffer.copy(outputBuffer, startOffset);
|
||||
switch (secondByte) {
|
||||
case 126:
|
||||
outputBuffer[2] = dataLength >>> 8;
|
||||
outputBuffer[3] = dataLength % 256;
|
||||
break;
|
||||
case 127:
|
||||
var l = dataLength;
|
||||
for (var i = 1; i <= 8; ++i) {
|
||||
outputBuffer[startOffset - i] = l & 0xff;
|
||||
l >>>= 8;
|
||||
}
|
||||
}
|
||||
return outputBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the connection.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
WebSocket.prototype.doClose = function () {
|
||||
this.socket.end();
|
||||
};
|
||||
|
||||
/**
|
||||
* WebSocket parser
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Parser () {
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
masked: false,
|
||||
opcode: 0
|
||||
};
|
||||
this.overflow = null;
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.currentMessage = '';
|
||||
|
||||
var self = this;
|
||||
this.opcodeHandlers = {
|
||||
// text
|
||||
'1': function(data) {
|
||||
var finish = function(mask, data) {
|
||||
self.currentMessage += self.unmask(mask, data);
|
||||
if (self.state.lastFragment) {
|
||||
self.emit('data', self.currentMessage);
|
||||
self.currentMessage = '';
|
||||
}
|
||||
self.endPacket();
|
||||
}
|
||||
|
||||
var expectData = function(length) {
|
||||
if (self.state.masked) {
|
||||
self.expect('Mask', 4, function(data) {
|
||||
var mask = data;
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(null, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
expectData(firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expect('Length', 2, function(data) {
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expect('Length', 8, function(data) {
|
||||
if (util.unpack(data.slice(0, 4)) != 0) {
|
||||
self.error('packets with length spanning more than 32 bit is currently not supported');
|
||||
return;
|
||||
}
|
||||
var lengthBytes = data.slice(4); // note: cap to 32 bit length
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
},
|
||||
// binary
|
||||
'2': function(data) {
|
||||
var finish = function(mask, data) {
|
||||
if (typeof self.currentMessage == 'string') self.currentMessage = []; // build a buffer list
|
||||
self.currentMessage.push(self.unmask(mask, data, true));
|
||||
if (self.state.lastFragment) {
|
||||
self.emit('binary', self.concatBuffers(self.currentMessage));
|
||||
self.currentMessage = '';
|
||||
}
|
||||
self.endPacket();
|
||||
}
|
||||
|
||||
var expectData = function(length) {
|
||||
if (self.state.masked) {
|
||||
self.expect('Mask', 4, function(data) {
|
||||
var mask = data;
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(null, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength < 126) {
|
||||
expectData(firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expect('Length', 2, function(data) {
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expect('Length', 8, function(data) {
|
||||
if (util.unpack(data.slice(0, 4)) != 0) {
|
||||
self.error('packets with length spanning more than 32 bit is currently not supported');
|
||||
return;
|
||||
}
|
||||
var lengthBytes = data.slice(4); // note: cap to 32 bit length
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
},
|
||||
// close
|
||||
'8': function(data) {
|
||||
self.emit('close');
|
||||
self.reset();
|
||||
},
|
||||
// ping
|
||||
'9': function(data) {
|
||||
if (self.state.lastFragment == false) {
|
||||
self.error('fragmented ping is not supported');
|
||||
return;
|
||||
}
|
||||
|
||||
var finish = function(mask, data) {
|
||||
self.emit('ping', self.unmask(mask, data));
|
||||
self.endPacket();
|
||||
}
|
||||
|
||||
var expectData = function(length) {
|
||||
if (self.state.masked) {
|
||||
self.expect('Mask', 4, function(data) {
|
||||
var mask = data;
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(mask, data);
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
self.expect('Data', length, function(data) {
|
||||
finish(null, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// decode length
|
||||
var firstLength = data[1] & 0x7f;
|
||||
if (firstLength == 0) {
|
||||
finish(null, null);
|
||||
}
|
||||
else if (firstLength < 126) {
|
||||
expectData(firstLength);
|
||||
}
|
||||
else if (firstLength == 126) {
|
||||
self.expect('Length', 2, function(data) {
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
else if (firstLength == 127) {
|
||||
self.expect('Length', 8, function(data) {
|
||||
expectData(util.unpack(data));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.expect('Opcode', 2, this.processPacket);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from EventEmitter.
|
||||
*/
|
||||
|
||||
Parser.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
/**
|
||||
* Add new data to the parser.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Parser.prototype.add = function(data) {
|
||||
if (this.expectBuffer == null) {
|
||||
this.addToOverflow(data);
|
||||
return;
|
||||
}
|
||||
var toRead = Math.min(data.length, this.expectBuffer.length - this.expectOffset);
|
||||
data.copy(this.expectBuffer, this.expectOffset, 0, toRead);
|
||||
this.expectOffset += toRead;
|
||||
if (toRead < data.length) {
|
||||
// at this point the overflow buffer shouldn't at all exist
|
||||
this.overflow = new Buffer(data.length - toRead);
|
||||
data.copy(this.overflow, 0, toRead, toRead + this.overflow.length);
|
||||
}
|
||||
if (this.expectOffset == this.expectBuffer.length) {
|
||||
var bufferForHandler = this.expectBuffer;
|
||||
this.expectBuffer = null;
|
||||
this.expectOffset = 0;
|
||||
this.expectHandler.call(this, bufferForHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a piece of data to the overflow.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.addToOverflow = function(data) {
|
||||
if (this.overflow == null) this.overflow = data;
|
||||
else {
|
||||
var prevOverflow = this.overflow;
|
||||
this.overflow = new Buffer(this.overflow.length + data.length);
|
||||
prevOverflow.copy(this.overflow, 0);
|
||||
data.copy(this.overflow, prevOverflow.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for a certain amount of bytes to be available, then fires a callback.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.expect = function(what, length, handler) {
|
||||
this.expectBuffer = new Buffer(length);
|
||||
this.expectOffset = 0;
|
||||
this.expectHandler = handler;
|
||||
if (this.overflow != null) {
|
||||
var toOverflow = this.overflow;
|
||||
this.overflow = null;
|
||||
this.add(toOverflow);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start processing a new packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.processPacket = function (data) {
|
||||
if ((data[0] & 0x70) != 0) {
|
||||
this.error('reserved fields must be empty');
|
||||
return;
|
||||
}
|
||||
this.state.lastFragment = (data[0] & 0x80) == 0x80;
|
||||
this.state.masked = (data[1] & 0x80) == 0x80;
|
||||
var opcode = data[0] & 0xf;
|
||||
if (opcode == 0) {
|
||||
// continuation frame
|
||||
this.state.opcode = this.state.activeFragmentedOperation;
|
||||
if (!(this.state.opcode == 1 || this.state.opcode == 2)) {
|
||||
this.error('continuation frame cannot follow current opcode')
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.state.opcode = opcode;
|
||||
if (this.state.lastFragment === false) {
|
||||
this.state.activeFragmentedOperation = opcode;
|
||||
}
|
||||
}
|
||||
var handler = this.opcodeHandlers[this.state.opcode];
|
||||
if (typeof handler == 'undefined') this.error('no handler for opcode ' + this.state.opcode);
|
||||
else handler(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Endprocessing a packet.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.endPacket = function() {
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
if (this.state.lastFragment && this.state.opcode == this.state.activeFragmentedOperation) {
|
||||
// end current fragmented operation
|
||||
this.state.activeFragmentedOperation = null;
|
||||
}
|
||||
this.state.lastFragment = false;
|
||||
this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;
|
||||
this.state.masked = false;
|
||||
this.expect('Opcode', 2, this.processPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the parser state.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.reset = function() {
|
||||
this.state = {
|
||||
activeFragmentedOperation: null,
|
||||
lastFragment: false,
|
||||
masked: false,
|
||||
opcode: 0
|
||||
};
|
||||
this.expectOffset = 0;
|
||||
this.expectBuffer = null;
|
||||
this.expectHandler = null;
|
||||
this.overflow = null;
|
||||
this.currentMessage = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmask received data.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.unmask = function (mask, buf, binary) {
|
||||
if (mask != null) {
|
||||
for (var i = 0, ll = buf.length; i < ll; i++) {
|
||||
buf[i] ^= mask[i % 4];
|
||||
}
|
||||
}
|
||||
if (binary) return buf;
|
||||
return buf != null ? buf.toString('utf8') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates a list of buffers.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.concatBuffers = function(buffers) {
|
||||
var length = 0;
|
||||
for (var i = 0, l = buffers.length; i < l; ++i) {
|
||||
length += buffers[i].length;
|
||||
}
|
||||
var mergedBuffer = new Buffer(length);
|
||||
var offset = 0;
|
||||
for (var i = 0, l = buffers.length; i < l; ++i) {
|
||||
buffers[i].copy(mergedBuffer, offset);
|
||||
offset += buffers[i].length;
|
||||
}
|
||||
return mergedBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an error
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Parser.prototype.error = function (reason) {
|
||||
this.reset();
|
||||
this.emit('error', reason);
|
||||
return this;
|
||||
};
|
||||
11
node_modules/socket.io/lib/transports/websocket/index.js
generated
vendored
Normal file
11
node_modules/socket.io/lib/transports/websocket/index.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
/**
|
||||
* Export websocket versions.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
7: require('./hybi-07-12'),
|
||||
8: require('./hybi-07-12'),
|
||||
13: require('./hybi-16'),
|
||||
default: require('./default')
|
||||
};
|
||||
69
node_modules/socket.io/lib/transports/xhr-polling.js
generated
vendored
Normal file
69
node_modules/socket.io/lib/transports/xhr-polling.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module requirements.
|
||||
*/
|
||||
|
||||
var HTTPPolling = require('./http-polling');
|
||||
|
||||
/**
|
||||
* Export the constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = XHRPolling;
|
||||
|
||||
/**
|
||||
* Ajax polling transport.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function XHRPolling (mng, data, req) {
|
||||
HTTPPolling.call(this, mng, data, req);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inherits from Transport.
|
||||
*/
|
||||
|
||||
XHRPolling.prototype.__proto__ = HTTPPolling.prototype;
|
||||
|
||||
/**
|
||||
* Transport name
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
XHRPolling.prototype.name = 'xhr-polling';
|
||||
|
||||
/**
|
||||
* Frames data prior to write.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
XHRPolling.prototype.doWrite = function (data) {
|
||||
HTTPPolling.prototype.doWrite.call(this);
|
||||
|
||||
var origin = this.req.headers.origin
|
||||
, headers = {
|
||||
'Content-Type': 'text/plain; charset=UTF-8'
|
||||
, 'Content-Length': data === undefined ? 0 : Buffer.byteLength(data)
|
||||
, 'Connection': 'Keep-Alive'
|
||||
};
|
||||
|
||||
if (origin) {
|
||||
// https://developer.mozilla.org/En/HTTP_Access_Control
|
||||
headers['Access-Control-Allow-Origin'] = origin;
|
||||
headers['Access-Control-Allow-Credentials'] = 'true';
|
||||
}
|
||||
|
||||
this.response.writeHead(200, headers);
|
||||
this.response.write(data);
|
||||
this.log.debug(this.name + ' writing', data);
|
||||
};
|
||||
50
node_modules/socket.io/lib/util.js
generated
vendored
Normal file
50
node_modules/socket.io/lib/util.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
/*!
|
||||
* socket.io-node
|
||||
* Copyright(c) 2011 LearnBoost <dev@learnboost.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts an enumerable to an array.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.toArray = function (enu) {
|
||||
var arr = [];
|
||||
|
||||
for (var i = 0, l = enu.length; i < l; i++)
|
||||
arr.push(enu[i]);
|
||||
|
||||
return arr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unpacks a buffer to a number.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.unpack = function (buffer) {
|
||||
var n = 0;
|
||||
for (var i = 0; i < buffer.length; ++i) {
|
||||
n = (i == 0) ? buffer[i] : (n * 256) + buffer[i];
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Left pads a string.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.padl = function (s,n,c) {
|
||||
return new Array(1 + n - s.length).join(c) + s;
|
||||
}
|
||||
|
||||
72
node_modules/socket.io/package.json
generated
vendored
Normal file
72
node_modules/socket.io/package.json
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "socket.io",
|
||||
"version": "0.9.14",
|
||||
"description": "Real-time apps made cross-browser & easy with a WebSocket-like API",
|
||||
"homepage": "http://socket.io",
|
||||
"keywords": [
|
||||
"websocket",
|
||||
"socket",
|
||||
"realtime",
|
||||
"socket.io",
|
||||
"comet",
|
||||
"ajax"
|
||||
],
|
||||
"author": {
|
||||
"name": "Guillermo Rauch",
|
||||
"email": "guillermo@learnboost.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Guillermo Rauch",
|
||||
"email": "rauchg@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Arnout Kazemier",
|
||||
"email": "info@3rd-eden.com"
|
||||
},
|
||||
{
|
||||
"name": "Vladimir Dronnikov",
|
||||
"email": "dronnikov@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Einar Otto Stangvik",
|
||||
"email": "einaros@gmail.com"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/LearnBoost/socket.io.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"socket.io-client": "0.9.11",
|
||||
"policyfile": "0.0.4",
|
||||
"base64id": "0.1.0",
|
||||
"redis": "0.7.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"expresso": "0.9.2",
|
||||
"should": "*",
|
||||
"benchmark": "0.2.2",
|
||||
"microtime": "0.1.3-1",
|
||||
"colors": "0.5.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"redis": "0.7.3"
|
||||
},
|
||||
"main": "index",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"_id": "socket.io@0.9.14",
|
||||
"_engineSupported": true,
|
||||
"_npmVersion": "1.1.4",
|
||||
"_nodeVersion": "v0.6.12",
|
||||
"_defaultsLoaded": true,
|
||||
"dist": {
|
||||
"shasum": "b865c2da3ae43df4f9933dc6f37e01e84a2fd1c6"
|
||||
},
|
||||
"_from": "socket.io@0.9.14"
|
||||
}
|
||||
Reference in New Issue
Block a user