Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

#16 API refactoring continues. Use Streams-like API.

  • Loading branch information...
commit 7863ee08a69ede673fc52a4b81e38c9fcd011916 1 parent a394b16
@majek majek authored
View
73 README.md
@@ -155,7 +155,7 @@ receiving connection wasn't seen for 5 seconds.
### Server instance
-Once you have instantiated `Server` class you can hook it to the
+Once you have create `Server` instance you can hook it to the
[http server instance](http://nodejs.org/docs/v0.4.10/api/http.html#http.createServer).
```javascript
@@ -172,7 +172,7 @@ constructor.
and emits following event:
<dl>
-<dt>connection(connection)</dt>
+<dt>Event: connection (connection)</dt>
<dd>A new connection has been successfully opened.</dd>
</dl>
@@ -182,32 +182,40 @@ handlers.
### Connection instance
-A `Connection` instance has following methods and properties:
+A `Connection` instance supports
+[Node Stream API](http://nodejs.org/docs/v0.5.8/api/streams.html) and
+has following methods and properties:
<dl>
-<dt>readyState</dt>
-<dd>A property describing a state of the connecion.</dd>
+<dt>Property: readable (boolean)</dt>
+<dd>Is the stream readable?</dd>
-<dt>send(message)</dt>
+<dt>Property: writable (boolean)</dt>
+<dd>Is the stream writable?</dd>
+
+<dt>write(message)</dt>
<dd>Sends a message over opened connection. It's illegal to send a
- message after the connection was closed (either by 'close' method
- or 'close' event).</dd>
+ message after the connection was closed (either after 'close' or
+ 'end' method or 'close' event).</dd>
-<dt>close([status], [reason])</dt>
-<dd>Asks the remote client to disconnect. 'status' and 'reason'
+<dt>close([code], [reason])</dt>
+<dd>Asks the remote client to disconnect. 'code' and 'reason'
parameters are optional and can be used to share the reason of
disconnection.</dd>
+
+<dt>end()</dt>
+<dd>Asks the remote client to disconnect with default 'code' and
+ 'reason' values.</dd>
+
</dl>
-A `Connection` instance is also an
-[EventEmitter](http://nodejs.org/docs/v0.4.10/api/events.html#events.EventEmitter),
-and emits following events:
+A `Connection` instance emits the following events:
<dl>
-<dt>message(message)</dt>
+<dt>Event: data (message)</dt>
<dd>A message arrived on the connection.</dd>
-<dt>close()</dt>
+<dt>Event: close ()</dt>
<dd>Connection was closed. This event is triggered exactly once for
every connection.</dd>
</dl>
@@ -220,7 +228,7 @@ sjs.on('connection', function(conn) {
conn.on('close', function() {
console.log('close ' + conn);
});
- conn.on('message', function(message) {
+ conn.on('data', function(message) {
console.log('message ' + conn,
message);
});
@@ -230,36 +238,9 @@ sjs.on('connection', function(conn) {
### Footnote
A fully working echo server does need a bit more boilerplate (to
-handle unanswered requests), here it is:
-
-```javascript
-var http = require('http');
-var sockjs = require('sockjs');
-
-var sockjs_opts = {sockjs_url:
- "http://sockjs.github.com/sockjs-client/sockjs-latest.min.js"};
-
-var sjs = sockjs.createServer(sockjs_opts);
-sjs.on('connection', function(conn) {
- conn.on('message', function(message) {
- conn.send(message);
- });
- conn.on('close', function() {});
-});
-
-var server = http.createServer();
-server.addListener('request', function(req, res) {
- res.writeHead(404);
- res.end('404 not found');
-});
-server.addListener('upgrade', function(req, con) {
- con.end();
-});
-
-sjs.installHandlers(server, {prefix:'[/]echo'});
-
-server.listen(9999, '0.0.0.0');
-```
+handle unanswered requests), see the
+[`echo` example](https://github.com/sockjs/sockjs-node/tree/master/examples/echo)
+for a full code.
### Examples
View
8 examples/echo/server.js
@@ -5,10 +5,10 @@ var node_static = require('node-static');
// 1. Echo sockjs server
var sockjs_opts = {sockjs_url: "http://sockjs.github.com/sockjs-client/sockjs-latest.min.js"};
-var sjs_echo = new sockjs.Server(sockjs_opts);
+var sjs_echo = sockjs.createServer(sockjs_opts);
sjs_echo.on('connection', function(conn) {
- conn.on('message', function(message) {
- conn.send(message);
+ conn.on('data', function(message) {
+ conn.write(message);
});
});
@@ -28,5 +28,3 @@ sjs_echo.installHandlers(server, {prefix:'[/]echo'});
console.log(' [*] Listening on 0.0.0.0:9999' );
server.listen(9999, '0.0.0.0');
-
-
View
8 src/sockjs.coffee
@@ -153,9 +153,9 @@ exports.listen = (http_server, options) ->
class DeprecatedConnectionWrapper extends events.EventEmitter
constructor: (@conn) ->
@id = @conn.id
- @conn.on 'message', (message) =>
+ @conn.on 'data', (message) =>
@emit('message', {data:message})
- @conn.on 'close', (e) =>
+ @conn.on 'close', () =>
e =
status: 1001
reason: 'Session timed out'
@@ -163,7 +163,7 @@ class DeprecatedConnectionWrapper extends events.EventEmitter
@emit('close', e)
send: (m) ->
- @conn.send(m)
+ @conn.write(m)
close: (a, b) ->
@conn.close(a, b)
@@ -172,7 +172,7 @@ class DeprecatedConnectionWrapper extends events.EventEmitter
@conn.toString()
DeprecatedConnectionWrapper.prototype.__defineGetter__ 'readyState', ->
- @conn.readyState
+ if @conn.readable then 1 else 3
class DeprecatedServerWrapper extends events.EventEmitter
View
54 src/transport.coffee
@@ -1,4 +1,4 @@
-events = require('events')
+stream = require('stream')
uuid = require('node-uuid')
class Transport
@@ -12,14 +12,44 @@ closeFrame = (status, reason) ->
return 'c' + JSON.stringify([status, reason])
+class SockJSConnection extends stream.Stream
+ constructor: (@_session) ->
+ @id = uuid()
+
+ toString: ->
+ return '<SockJSConnection ' + @id + '>'
+
+ write: (string) ->
+ return @_session.send('' + string)
+
+ end: (string) ->
+ if string
+ @write(string)
+ @close()
+ return null
+
+ close: (code, reason) ->
+ @_session.close(code, reason)
+
+ destroy: () ->
+ @removeAllListeners()
+ @end()
+
+ destroySoon: () ->
+ @destroy()
+
+SockJSConnection.prototype.__defineGetter__ 'readable', ->
+ @_session.readyState is Transport.OPEN
+SockJSConnection.prototype.__defineGetter__ 'writable', ->
+ @_session.readyState is Transport.OPEN
+
MAP = {}
-class Session extends events.EventEmitter
+class Session
constructor: (@session_id, server) ->
@heartbeat_delay = server.options.heartbeat_delay
@disconnect_delay = server.options.disconnect_delay
- @id = uuid()
@send_buffer = []
@is_closing = false
@readyState = Transport.CONNECTING
@@ -27,9 +57,10 @@ class Session extends events.EventEmitter
MAP[@session_id] = @
@timeout_cb = => @didTimeout()
@to_tref = setTimeout(@timeout_cb, @disconnect_delay)
+ @connection = new SockJSConnection(@)
@emit_open = =>
@emit_open = null
- server.emit('connection', @)
+ server.emit('connection', @connection)
register: (recv) ->
if @recv
@@ -89,22 +120,28 @@ class Session extends events.EventEmitter
if @recv
throw Error('RECV_STILL_THERE')
@readyState = Transport.CLOSED
- @emit('close')
+ # Node streaming API is broken. Reader defines 'close' and 'end'
+ # but Writer defines only 'close'. 'End' isn't optional though.
+ # http://nodejs.org/docs/v0.5.8/api/streams.html#event_close_
+ @connection.emit('end')
+ @connection.emit('close')
+ @connection = null
if @session_id
delete MAP[@session_id]
@session_id = null
didMessage: (payload) ->
if @readyState is Transport.OPEN
- @emit('message', payload)
+ @connection.emit('data', payload)
return
send: (payload) ->
if @readyState isnt Transport.OPEN
- throw Error('INVALID_STATE_ERR')
+ return false
@send_buffer.push('' + payload)
if @recv
@tryFlush()
+ return true
close: (status=1000, reason="Normal closure") ->
if @readyState isnt Transport.OPEN
@@ -116,9 +153,8 @@ class Session extends events.EventEmitter
@recv.doSendFrame(@close_frame)
if @recv
@unregister
+ return true
- toString: ->
- return '<Session ' + @id + '>'
Session.bySessionId = (session_id) ->
Please sign in to comment.
Something went wrong with that request. Please try again.