Cettia Protocol 1.0.0
A reference implementation and test suite for Cettia protocol.
Table of Contents
Specification
Because it’s not easy to maintain both reference implementation and specification document, for now the reference implementation takes the place of the specification document.
Reference Implementation
To help understand and implement the protocol, we provide reference implementation. It is written in easy-to-read JavaScript for Node.js with a lot of detailed notes you should be aware of. Also you can use it to verify your implementation casually and as the counterpart in your examples. See the following annotated source codes:
cettia
cettia.open
cettia.createServer
cettia.transport.createHttpStreamTransport
cettia.transport.createHttpLongpollTransport
cettia.transport.createHttpServer
cettia.transport.createWebSocketTransport
cettia.transport.createWebSocketServer
Note
- They are not for production use.
Installation
First you need to install Node.js 4+. Then type the following to install the reference implementation:
npm install cettia-protocol
Example
This echo and chat example is very simple but demonstrates essential functionalities of the protocol. In this example,
- URI is
http://localhost:8080/cettia
. echo
event is sent back to the client that sent the event.chat
event is broadcasted to every client that connected to the server.
To run example, write server.js
and client.js
by copy and paste to the folder where you have installed cettia-protocol
module. Then, open two consoles, type node server
and node client
respectively.
server.js
// Cettia part
var cettia = require("cettia-protocol");
var server = cettia.createServer();
// When a socket is created as the beginning of the lifecycle
server.on("socket", function(socket) {
console.log("on server's socket");
// Lifecycle events
// When the handshake is performed successfully
socket.on("open", function() {
console.log("on open");
});
// When the underlying transport is closed for some reason
socket.on("close", function() {
console.log("on close");
});
// When an error happens on the socket
socket.on("error", function(error) {
console.log("on error", error);
});
// When the socket has been closed for a long time i.e. 1 minute and deleted from the server as the end of the lifecycle
socket.on("delete", function() {
console.log("on delete");
});
// echo and chat events
socket.on("echo", function(data) {
console.log("on echo", data);
socket.send("echo", data);
});
socket.on("chat", function(data) {
console.log("on chat", data);
server.sockets.forEach(function(socket) {
socket.send("chat", data);
});
});
});
var httpTransportServer = cettia.transport.createHttpServer().on("transport", server.handle);
var wsTransportServer = cettia.transport.createWebSocketServer().on("transport", server.handle);
// Node.js part
var url = require("url");
var http = require("http");
var httpServer = http.createServer();
httpServer.on("request", function(req, res) {
if (url.parse(req.url).pathname === "/cettia") {
httpTransportServer.handle(req, res);
}
});
httpServer.on("upgrade", function(req, sock, head) {
if (url.parse(req.url).pathname === "/cettia") {
wsTransportServer.handle(req, sock, head);
}
});
httpServer.listen(8080);
client.js
var cettia = require("cettia-protocol");
var socket = cettia.open("http://localhost:8080/cettia", {
reconnect: function(lastDelay, lastAttempts) {
return (lastDelay || 250) * 2;
}
});
// Lifecycle events
// When the selected transport starts connecting to the server
socket.on("connecting", function() {
console.log("on connecting");
});
// When the server issues a new id for this socket as the beginning of the lifecycle and the end of the previous lifecycle
socket.on("new", function() {
console.log("on new");
});
// When the connection is established successfully
socket.on("open", function() {
console.log("on open");
});
// When an error happens on the socket
socket.on("error", function(error) {
console.error("on error", error);
});
// When the connection is closed, regarded as closed or could not be opened
socket.on("close", function() {
console.log("on close");
});
// When a reconnection is scheduled
socket.on("waiting", function(delay, attempts) {
console.log("on waiting", attempts, delay);
});
// echo and chat events
socket.on("open", function() {
// Text data
socket.send("echo", "echo");
socket.send("chat", "chat");
// Binary data
socket.send("echo", new Buffer("echo"));
socket.send("chat", new Buffer("chat"));
// Composite data
socket.send("echo", {text: "echo", binary: new Buffer("echo")});
socket.send("chat", {text: "chat", binary: new Buffer("chat")});
});
socket.on("echo", function(data) {
console.log("on echo", data);
});
socket.on("chat", function(data) {
console.log("on chat", data);
});
Note that JavaScript is a dynamic language so you can deal with both client and server in interactive mode. Open two Node consoles, copy the above scripts and paste into the each console. Then you can access and play around with the above variables on these consoles directly.
Test Suite
Test suite is provided to help write and verify the Cettia protocol implementation. Tests are written in JavaScript with the help of reference implementation and runs by Mocha, JavaScript test framework, in Node.js.
Testee
To run the test suite, you need to write a testee, a web server which brokers between test and your implementation to be tested. Because through writing testee, you will use most API of your implementation, showing your testee is good for explaining how to use your implementation.
To write a testee, see ones for the reference implementation - server testee and client testee.
Running Test
First you need to install Node.js. Then create a package.json
in an empty directory:
{
"devDependencies": {
"cettia-protocol": "1.0.0",
"mocha": "^3.2.0",
"chai": "^3.5.0",
"minimist": "^1.2.0"
}
}
And type npm install
to install modules locally and npm install mocha -g
to install Mocha globally for convenience. Then, run your testee and execute mocha
passing the following arguments:
--cettia.transports
- A set of transport to be tested in a comma-separated value. As transport name,
websocket
,httpstream
andhttplongpoll
are available. By default, it haswebsocket,httpstream,httplongpoll
.
- A set of transport to be tested in a comma-separated value. As transport name,
Testing a client implementing WebSocket transport only.
mocha ./node_modules/cettia-protocol/test/client.js --cettia.transports websocket
Note
- Because Node.js is small and can be installed locally, you can automate the protocol test programmatically by downloading and installing Node.js, installing npm modules, running tests through spawning a process and checking that process’ exit code that is the number of failed tests.