Node WebSocket Server

Hey there, this is an early release for Node Knockout, there'll be full documentation coming really soon, if anything's missing, try the source code.

# Node WebSocket Server is a near specification compliant implementation of the server-side WebSocket Protocol. It is built on top of Node.js as a third-party module, and is designed to support various versions of the WebSocket protocol – which is currently still an IETF Draft.

# The WebSockets protocol is a way of the browser providing a bi-directional, full-duplex communication channel which is accessible through the DOM.

Installation

# Node WebSocket Server can be easily installed via NPM or cloned from github. This module requires Node to be compiled with SSL support (which is by default enabled, if it's available), the reason for the dependency on SSL being available in Node.js is to enable Draft 76 handshaking and Secure WebSocket connections.

With Node Package Manager

# For the latest stable build:

npm install websocket-server

# Or, alternatively, you can run with the latest bleeding edge build with:

npm install websocket-server@latest

With git submodules

# Installing Node WebSocket Server as a git submodule is a recommended route for installing if you plan on deploying your application and don't want the hassle of having to check that both production and development environments are running the same module versions. Another benefit of installing as a submodule, is that the websocket server is then packaged with your code.

# The installation is as follows:

// Assumption that you are in a working git repository:
$ mkdir vendor
$ cd vendor
$ git submodule add git://github.com/miksago/node-websocket-server.git websocket-server
Initialized empty Git repository in ./websocket-server/.git/
// ...repository gets cloned...
$ git commit -m "Adding websocket-server submodule"

# Later on, in order to update your projects copy of Node WebSocket Server, simply do:

$ git submodule update

# For your collaborators, they can simply do a git pull then a git submodule init then a git submodule update. You can learn more about Git Submodules from Chapter 6.6 of the Pro Git book, which you can read online.

Contributing

# In order to contribute to this project, I ask that you follow these steps:

  1. Fork the project.
  2. Make your feature addition or bug fix.
  3. Commit, do not mess with rakefile, version, or history.
  4. Send me a pull request. Bonus points for topic branches.

Basic Usage

# The API to Node WebSocket Server is fairly simple, and stays consistent with the Node.js API's you may already be familiar with. Firstly, there are three main parts to the server, these are: The constructor, the connection instance, and the connection manager. Each of these parts interact with each other, and end up providing a clean API with which you write your server-side logic.

# An example server, that simply echoes anything that a client sends to all other connections, looks like the following:

var ws = require("websocket-server");

var server = ws.createServer();

server.addListener("connection", function(connection){
  connection.addListener("message", function(msg){
    server.send(msg);
  });
});

server.listen(8080);

# So what does the above code actually do? First, we need to require in the websocket-server library — If you have installed this module via NPM then you can require it exactly like the above does. Next, we create a server instance, by default, this server will automatically choose which version of the protocol to use when communicating with the client and it will also act as a standard http.Server instance.

# After we have a instance of ws.Server, which ws.createServer returns, we can proceed to add event listeners to the various events it emits. We use the same API as that which node's Event.EventEmitter provides to do so. In this case, we only bind to one event on the server, the Connection event. Each time a user successfully connects to the server the connection is emitted. We then watch for the message event on the emitted connection, this event occurs every time a user sends a message to the server.

API Documentation

# The API to Node WebSocket Server is split into three main parts:

  1. The require-time module, that lets you create a new websocket server
  2. The connection instance
  3. The connection manager

Module Methods

# ws.createServer( [options] );
Returns a new ws.Server instance.
This method passes it's arguments through to the ws.Server constructor, see constructor documentation for description of options.
# ws.Server( [options] );
The constructor for a new WebSocket Server.
options is an object of options to pass to the server, these are as follows:
debug:
Toggles the printing of debug messages from each component to stdout.
Type: Boolean
version:
The WebSocket protocol version the server will accept connections from, connections not matching this version will be rejected.
Type: String
Values: "auto", "draft76", "draft75"
Default: "auto"
storage:
Defines a storage model to be implemented as a member of each connection. If the value is false, no storage will be created. If the value is true, then an in memory store will be used. The value may also be an Object or Constructor, see the section on Connection.storage for more information.
Type: Boolean, Object, Constructor
server:
Defines an existing http.Server instance for the WebSocket Server to bind to.
Type: http.Server
origin:
A string or array of domains from which the server should accept connections.
Type: String, String[]
Note: This is not fully implemented
subprotocol:
A string or array of subprotocols which the server will use when communicating with clients. The server and client should negotiate which subprotocol to use if an Array of strings is passed.
Type: String, String[]
Note: This is not fully implemented

Server Instances

Throughout this section, the variable server is an instant of a ws.Server.

server.send( client_id, message )
Sends message to the client with id of client_id.
client_id: Integer
message: String
server.broadcast( message )
Sends message to all connected clients.
message: String
server.listen( port, [host] )
Same as the http.Server listen method.
server.setSecure( credentials )
Switches to using SSL to encrypt connections with the supplied credentials. Requires the client to connect using wss:// protocol, instead of the standard ws://.
credentials: crypto.Credentials
server.close()
Same as the http.Server close method.

Inherited Methods

The following methods are inherited from Events.eventEmitter.

server.addListener( event, callback )
Adds a listener for the specified event that is emitted from the server.
event: String
callback: Function
server.removeListener( event, callback )
Remove a listener from the specified event that is emitted from the server.
event: String
callback: Function
server.removeAllListeners( event )
Removes all listeners from the specified event that is emitted from the server.
event: String

Events

A Server instance can emit various events during it's life cycle. The WebSocket Server will also emit each of the http.Server events, except "connection" and "close" which are used by the WebSocket Server. These events are described as follows:

connection
Emitted whenever a client connects to the server successfully.
client: Connection
close
Emitted whenever a client disconnects from the server.
client: Connection
shutdown
Emitted when the server is closed, this event is echoed from http.Server

Connection Instances

# Each time a client connects to the server, a new connection instance is created and registered with the connection manager.

connection.id
A String, which is a unique identifier for the connection, this is based on the connection's remotePort.
connection.state
An Integer representing the current state of the connection, states are as follows:
  • 0. unknown
  • 1. opening
  • 2. waiting
  • 3. handshaking
  • 4, connected
  • 5. closing
  • 6. closed
State changes can be listened for using the stateChange event.
connection.version
A String, representing the protocol version the client is connecting from. Either draft75 or draft76.
connection.headers
An Object, these are the HTTP headers that were sent with the initial WebSocket Handshake. See http.ServerRequest for details.
connection.storage
This is an instance of your chosen Storage provider. By default, it is a in memory store with an API similar to redis. This can be disabled, in which case it will be undefined.

Methods

connection.send( data )
Sends data from the current connection to all other connections on the server, including the sending connection. This method is aliased as connection.write
data: String
connection.broadcast( data )
Sends data from the current connection to all other connections on the server, excluding the sending connection.
data: String
connection.close()
Closes the current connection and emits the "close".
connection.reject( [reason] )
Emits the "rejected" event, then proceeds to close the connection using connection.close(). The reason is used only for logging purposes.
reason: String

Inherited Methods

The following methods are inherited from Events.eventEmitter.

connection.addListener( event, callback )
Adds a listener for the specified event that is emitted from the connection.
event: String
callback: Function
connection.removeListener( event, callback )
Remove a listener from the specified event that is emitted from the connection.
event: String
callback: Function
connection.removeAllListeners( event )
Removes all listeners from the specified event that is emitted from the connection.
event: String

Events

Each connection comes with the following events that may be emitted through out it's life-cycle.

close
Emitted whenever a client or server closes the connection.
rejected
Emitted whenever the server rejects the connection.
message: function( data )
Emitted whenever a client sends a message to the server successfully.
stateChange: function( new_state, old_state )
Emitted whenever the internal connection status changes, this equates to the various of the Connection life-cycle.

Manager Instances

# ...

server.manager.length
Number of currently attached connections. This property is not writable, only readable.
server.manager.find( id, callback, [thisArg] )
Finds the Connection Instance with the given id. If a match is found, the call property of callback is called with thisArg as the value of this, with the only argument being the pointer to the Connection Instance that was matched.
server.manager.forEach( callback, [thisArg] )
... description ...
server.manager.map( callback, [thisArg] )
... description ...
server.manager.filter( callback, [thisArg] )
... description ...

Further Reading