mirror of
https://github.com/socketio/socket.io.git
synced 2026-04-30 03:00:39 -04:00
*: initial component
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
build
|
||||
components
|
||||
9
Makefile
Normal file
9
Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
REPORTER = dot
|
||||
|
||||
test:
|
||||
@./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER) \
|
||||
--bail
|
||||
|
||||
.PHONY: test
|
||||
98
Readme.md
Normal file
98
Readme.md
Normal file
@@ -0,0 +1,98 @@
|
||||
|
||||
# socket.io-protocol
|
||||
|
||||
This repository contains the protocol specification and JavaScript
|
||||
parser for the Socket.IO protocol.
|
||||
|
||||
## Protocol version
|
||||
|
||||
**Current protocol revision:** `1`.
|
||||
|
||||
## Parser API
|
||||
|
||||
### Parser#encode(Object:packet):String
|
||||
|
||||
Encodes a `Packet` object as a string.
|
||||
|
||||
### Parser#decode(String:packet):Packet
|
||||
|
||||
Returns a `Packet` object for the given string. If a parsing error
|
||||
occurs the returned packet is an error object.
|
||||
|
||||
### Parser#types
|
||||
|
||||
Array of packet type keys.
|
||||
|
||||
### Packet
|
||||
|
||||
Each packet is represented as a vanilla `Object` with a `type` key that
|
||||
can be one of the following:
|
||||
|
||||
- `Packet#CONNECT` (`0`)
|
||||
- `Packet#DISCONNECT` (`1`)
|
||||
- `Packet#EVENT` (`2`)
|
||||
- `Packet#ACK` (`3`)
|
||||
- `Packet#ERROR` (`4`)
|
||||
|
||||
Each packet also contains a `nsp` key that indicates what namespace it
|
||||
belongs to (see "Multiplexing" below for an explanation).
|
||||
|
||||
#### EVENT
|
||||
|
||||
- `data` (`Array`) a list of arguments, the first of which is the event
|
||||
name. Arguments can contain any type of field that can result of
|
||||
`JSON` decoding, including objects and arrays of arbitrary size.
|
||||
|
||||
- `id` (`Number`) if the `id` identifier is present, it indicates that the
|
||||
server wishes to be acknowledged of the reception of this event.
|
||||
|
||||
#### ACK
|
||||
|
||||
- `data` (`Array`) see `EVENT` `data`.
|
||||
- `id` (`Number`) see `EVENT` `id`.
|
||||
|
||||
#### ERROR
|
||||
|
||||
- `data` (`Mixed`) error data
|
||||
|
||||
## Transport
|
||||
|
||||
The socket.io protocol can be delivered over a variety of transports.
|
||||
[socket.io-client](http://github.com/learnboost/socket.io-client)
|
||||
is the implementation of the protocol for the browser and Node.JS over
|
||||
[engine.io-client](http://github.com/learnboost/engine.io-client).
|
||||
|
||||
[socket.io](http://github.com/learnboost/socket.io) is the server
|
||||
implementation of the protocol over
|
||||
[engine.io](http://github.com/learnboost/engine.io).
|
||||
|
||||
## Multiplexing
|
||||
|
||||
Socket.IO has built-in multiplexing support, which means that each packet
|
||||
always belongs to a given `namespace`, identified by a path string (like
|
||||
`/this`). The corresponding key in the `Packet` object is `nsp`.
|
||||
|
||||
When the socket.io transport connection is established, a connection
|
||||
attempt to the `/` namespace is assumed (ie: the server behaves as if
|
||||
the client had sent a `CONNECT` packet to the `/` namespace).
|
||||
|
||||
In order to support multiplexing of multiple sockets under
|
||||
the same transport, additional `CONNECT` packets can be sent by the
|
||||
client to arbitrary namespace URIs (eg: `/another`).
|
||||
|
||||
When the server responds with a `CONNECT` packet to the corresponding
|
||||
namespace, the multiplexed socket is considered connected.
|
||||
|
||||
Alternatively, the server can respond with an `ERROR` packet to indicate
|
||||
a multiplexed socket connection error, such as authentication errors.
|
||||
The associated error payload varies according to each error, and can
|
||||
be user-defined.
|
||||
|
||||
After a `CONNECT` packet is received by the server for a given `nsp`,
|
||||
the client can then send and receive `EVENT` packets. If any of the
|
||||
parties receives an `EVENT` packet with an `id` field, an `ACK` packet is
|
||||
expected to confirm the reception of said packet.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
11
component.json
Normal file
11
component.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "socket.io-parser",
|
||||
"version": "0.0.1",
|
||||
"description": "socket.io protocol parser",
|
||||
"dependencies": {
|
||||
"component/json": "0.0.1"
|
||||
},
|
||||
"scripts": [
|
||||
"index.js"
|
||||
]
|
||||
}
|
||||
177
index.js
Normal file
177
index.js
Normal file
@@ -0,0 +1,177 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var json;
|
||||
|
||||
try {
|
||||
json = require('json');
|
||||
} catch(e){
|
||||
json = JSON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protocol version.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.protocol = 1;
|
||||
|
||||
/**
|
||||
* Packet types.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.types = [
|
||||
'CONNECT',
|
||||
'DISCONNECT',
|
||||
'EVENT',
|
||||
'ACK',
|
||||
'ERROR'
|
||||
];
|
||||
|
||||
/**
|
||||
* Packet type `connect`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.CONNECT = 0;
|
||||
|
||||
/**
|
||||
* Packet type `disconnect`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.DISCONNECT = 1;
|
||||
|
||||
/**
|
||||
* Packet type `event`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.EVENT = 2;
|
||||
|
||||
/**
|
||||
* Packet type `ack`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.ACK = 3;
|
||||
|
||||
/**
|
||||
* Packet type `error`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.ERROR = 4;
|
||||
|
||||
/**
|
||||
* Encode.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @return {String} encoded
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.encode = function(obj){
|
||||
var str = '';
|
||||
var nsp = false;
|
||||
|
||||
// first is type
|
||||
str += obj.type;
|
||||
|
||||
// if we have a namespace other than `/`
|
||||
// we append it followed by a comma `,`
|
||||
if (obj.nsp && '/' != obj.nsp) {
|
||||
nsp = true;
|
||||
str += obj.nsp;
|
||||
}
|
||||
|
||||
// immediately followed by the id
|
||||
if (obj.id) {
|
||||
if (nsp) {
|
||||
str += ',';
|
||||
nsp = false;
|
||||
}
|
||||
str += obj.id;
|
||||
}
|
||||
|
||||
// json data
|
||||
if (obj.data) {
|
||||
if (nsp) str += ',';
|
||||
str += json.stringify(obj.data);
|
||||
}
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode.
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Object} packet
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.decode = function(str){
|
||||
var p = {};
|
||||
var i = 0;
|
||||
|
||||
// look up type
|
||||
p.type = Number(str.charAt(0));
|
||||
if (null == exports.types[p.type]) return error();
|
||||
|
||||
// look up namespace (if any)
|
||||
if ('/' == str.charAt(i + 1)) {
|
||||
p.nsp = '';
|
||||
while (++i) {
|
||||
var c = str.charAt(i);
|
||||
if (',' == c) break;
|
||||
p.nsp += c;
|
||||
if (i + 1 == str.length) break;
|
||||
}
|
||||
} else {
|
||||
p.nsp = '/';
|
||||
}
|
||||
|
||||
// look up id
|
||||
var next = str.charAt(i + 1);
|
||||
if ('' != next && Number(next) == next) {
|
||||
p.id = '';
|
||||
while (++i) {
|
||||
var c = str.charAt(i);
|
||||
if (null == c || Number(c) != c) {
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
p.id += str.charAt(i);
|
||||
if (i + 1 == str.length) break;
|
||||
}
|
||||
}
|
||||
|
||||
// look up json data
|
||||
if (str.charAt(++i)) {
|
||||
try {
|
||||
p.data = json.parse(str.substr(i));
|
||||
} catch(e){
|
||||
return error();
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
function error(data){
|
||||
return {
|
||||
type: exports.ERROR,
|
||||
data: 'parser error'
|
||||
};
|
||||
}
|
||||
17
package.json
Normal file
17
package.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "socket.io-parser",
|
||||
"version": "0.0.1",
|
||||
"description": "socket.io protocol parser",
|
||||
"devDependencies": {
|
||||
"mocha": "*",
|
||||
"expect.js": "*"
|
||||
},
|
||||
"component": {
|
||||
"dependencies": {
|
||||
"component/json": "0.0.1"
|
||||
},
|
||||
"scripts": [
|
||||
"index.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
60
test/test.js
Normal file
60
test/test.js
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
var parser = require('..');
|
||||
var expect = require('expect.js');
|
||||
var encode = parser.encode;
|
||||
var decode = parser.decode;
|
||||
|
||||
// tests encoding and decoding a packet
|
||||
|
||||
function test(obj){
|
||||
expect(decode(encode(obj))).to.eql(obj);
|
||||
}
|
||||
|
||||
describe('parser', function(){
|
||||
|
||||
it('exposes types', function(){
|
||||
expect(parser.CONNECT).to.be.a('number');
|
||||
expect(parser.DISCONNECT).to.be.a('number');
|
||||
expect(parser.EVENT).to.be.a('number');
|
||||
expect(parser.ACK).to.be.a('number');
|
||||
expect(parser.ERROR).to.be.a('number');
|
||||
});
|
||||
|
||||
it('encodes connection', function(){
|
||||
test({
|
||||
type: parser.CONNECT,
|
||||
nsp: '/woot'
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes disconnection', function(){
|
||||
test({
|
||||
type: parser.DISCONNECT,
|
||||
nsp: '/woot'
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes an event', function(){
|
||||
test({
|
||||
type: parser.EVENT,
|
||||
data: ['a', 1, {}],
|
||||
nsp: '/'
|
||||
});
|
||||
test({
|
||||
type: parser.EVENT,
|
||||
data: ['a', 1, {}],
|
||||
id: 1,
|
||||
nsp: '/test'
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes an ack', function(){
|
||||
test({
|
||||
type: parser.ACK,
|
||||
data: ['a', 1, {}],
|
||||
id: 123,
|
||||
nsp: '/'
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user