diff --git a/.codeclimate.yml b/.codeclimate.yml
deleted file mode 100644
index afc5a1e..0000000
--- a/.codeclimate.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-engines:
- eslint:
- enabled: true
-ratings:
- paths:
- - "bin/eslint.js"
-exclude_paths:
-- "node_modules/**"
-- "tests/**"
diff --git a/.gitignore b/.gitignore
index 6b1d8fe..01db8ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,5 @@ node_modules
# Compiled api docs
api_docs
/log.txt
+/bin/kalm.min.js
+/bin/kalm.min.js.map
diff --git a/.travis.yml b/.travis.yml
index d848029..5929118 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,4 +1,4 @@
language: node_js
node_js:
- "5.0"
-script: "npm run-script test"
+script: "npm run-script test && node tests/benchmarks/index.js"
diff --git a/README.md b/README.md
index f043078..df21b13 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,22 @@
+
# Kalm
+*The Socket Optimizer*
[![Kalm](https://img.shields.io/npm/v/kalm.svg)](https://www.npmjs.com/package/kalm)
[![Build Status](https://travis-ci.org/fed135/Kalm.svg?branch=master)](https://travis-ci.org/fed135/Kalm)
-[![Code Climate](https://codeclimate.com/github/fed135/Kalm/badges/gpa.svg)](https://codeclimate.com/github/fed135/Kalm)
[![Dependencies Status](https://david-dm.org/fed135/Kalm.svg)](https://www.npmjs.com/package/kalm)
-[![Current Stage](https://img.shields.io/badge/stage-alpha-blue.svg)](https://codeclimate.com/github/fed135/Kalm)
+[![Current Stage](https://img.shields.io/badge/stage-beta-blue.svg)](https://codeclimate.com/github/fed135/Kalm)
+---
-A library to simplify and optimize your Socket communications.
+Simplify and optimize your Socket communications with:
-- Packet bundling
-- Packet minification
+- Packet bundling and minification
- Easy-to-use single syntax for all protocols
-- Channels for all protocols
-- Plug-and-play
-- Ultra-flexible and extensible
+- Event channels for all protocols
+- Ultra-flexible and extensible adapters
+
+---
## Installation
@@ -24,92 +26,101 @@ A library to simplify and optimize your Socket communications.
## Usage
+**Server**
+
+```node
var Kalm = require('Kalm');
- var client = new Kalm.Client({
- hostname: '0.0.0.0', // Some ip
- port: 3000, // Some port
- adapter: 'tcp',
+ // Create a server, a listener for incomming connections
+ var server = new Kalm.Server({
+ port: 6000,
+ adapter: 'udp',
encoder: 'msg-pack',
channels: {
- 'myEvent': function(data) {} // Handler
+ messageEvent: function(data) { // Handler - new connections will register to these events
+ console.log('User sent message ' + data.body);
+ }
}
});
- client.send('myEvent', {foo: 'bar'}); // Can send Objects, Strings or Buffers
- client.channel('someOtherEvent', function() {}); // Can add other handlers dynamically
+ // When a connection is received, send a message to all connected users
+ server.on('connection', function(client) { // Handler, where client is an instance of Kalm.Client
+ server.broadcast('userEvent', 'A new user has connected');
+ });
+
+```
- var server = new Kalm.Server({
- port: 6000,
- adapter: 'udp',
- encoder: 'json',
+**Client**
+
+```node
+ // Create a connection to the server
+ var client = new Kalm.Client({
+ hostname: '0.0.0.0', // Server's IP
+ port: 6000, // Server's port
+ adapter: 'udp', // Server's adapter
+ encoder: 'msg-pack', // Server's encoder
channels: {
- 'myEvent': function(data) {} // Handler - new connections will register to these events
+ 'userEvent': function(data) {
+ console.log('Server: ' + data);
+ }
}
});
- server.on('connection', function(client) {} // Handler, where client is an instance of Kalm.Client
- server.broadcast('someOtherEvent', 'hello!');
+ client.send('messageEvent', {body: 'This is an object!'}); // Can send Objects, Strings or Buffers
+ client.channel('someOtherEvent', function() {}); // Can add other handlers dynamically
+```
## Performance analysis
-### Requests per minute
+**Requests per minute**
-| | IPC | TCP | UDP | Web Sockets |
-|---|---|---|---|---|
-| Raw | 1332330 | 844750 | 822690 | - |
-| Kalm | 5558920 | 1102570 | 5219490 | - |
-| **Result** | +417.2% | +30.5% | +634.5% | - |
+
*Benchmarks based on a single-thread queue test with Kalm default bundling settings AND msg-pack enabled*
-*5 run average*
+**Bytes transfered**
-### Bytes transfered
+
-| | IPC | TCP | UDP | WebSockets |
-|---|---|---|---|---|
-| Raw | 81000 | 81000 | 57000 | - |
-| Kalm | 6759 | 6759 | 8601 | - |
-| **Result** | 11.9x less | 11.9x less | 6.6x less | - |
-
-*Using wireshark - number of bytes transfered per 1000 requests*
+*Number of bytes transfered per 1000 requests*
## Adapters
Allow you to easily use different socket types, hassle-free
-| **Type** | **Library used** | **Status** |
-|---|---|---|
-| IPC | | STABLE |
-| TCP | | STABLE |
-| UDP | | STABLE |
-| [kalm-websocket](https://github.com/fed135/kalm-websocket) | [socket.io](http://socket.io/) | DEV |
+- ipc (bundled)
+- tcp (bundled)
+- udp (bundled)
+- [kalm-websocket](https://github.com/fed135/kalm-websocket)
## Encoders
-Encode the payloads before emitting.
+Encodes/Decodes the payloads
-| **Type** | **Library used** | **Status** |
-|---|---|---|
-| JSON | | STABLE |
-| MSG-PACK | [msgpack-lite](https://github.com/kawanet/msgpack-lite) | STABLE |
+- json (bundled)
+- msg-pack (bundled)
-## Middleware
+## Loading custom adapters
-Perform batch operation of payloads.
+The framework is flexible enough so that you can load your own custom adapters, encoders or middlewares - say you wanted support for protocols like zmq, WebSockets or have yaml encoding.
-| **Type** | **Library used** | **Status** |
-|---|---|---|
-| Bundler | | STABLE |
+```node
+ // Custom adapter loading example
+ var Kalm = require('Kalm');
+ var MyCustomAdapter = require('my-custom-adapter');
----
+ Kalm.adapters.register('my-custom-adapter', MyCustomAdapter);
-The framework is flexible enough so that you can load your own custom adapters, encoders or middlewares - say you wanted support for protocols like zmq, WebSockets or have yaml encoding.
+ var server = new Kalm.Server({
+ port: 3000,
+ adapter: 'my-custom-adapter',
+ encoder: 'msg-pack'
+ });
+```
## Run tests
@@ -119,11 +130,9 @@ The framework is flexible enough so that you can load your own custom adapters,
## Debugging
-By default, all Kalm logs are absorbed. They can be enabled through the DEBUG environement variable. See [debug](https://github.com/visionmedia/debug) for more info.
-
-Ex:
+By default, all Kalm logs are hidden. They can be enabled through the DEBUG environement variable. See [debug](https://github.com/visionmedia/debug) for more info.
- $ DEBUG=kalm
+ export DEBUG=kalm
## Roadmap
@@ -135,5 +144,3 @@ Ex:
I am looking for contributors to help improve the codebase and create adapters, encoders and middleware.
Email me for details.
-
-Thank you!
diff --git a/index.js b/index.js
index 9baa2c9..0f63482 100644
--- a/index.js
+++ b/index.js
@@ -7,12 +7,6 @@
/* Requires ------------------------------------------------------------------*/
var Kalm = require('./src');
-var pkg = require('./package');
-
-/* Init ----------------------------------------------------------------------*/
-
-Kalm.Client.pkg = pkg;
-Kalm.Server.pkg = pkg;
/* Exports -------------------------------------------------------------------*/
diff --git a/package.json b/package.json
index 5597c58..479caee 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,11 @@
{
"name": "kalm",
- "version": "0.1.2",
+ "version": "0.2.0",
"description": "The socket optimizer",
"main": "./index.js",
"scripts": {
- "test": "mocha tests/index.js"
+ "test": "mocha tests/index.js",
+ "build": "webpack -p -d -j --define process.env.NODE_ENV='\"browser\"' --config ./webpack.config"
},
"repository": {
"type": "git",
@@ -33,8 +34,6 @@
"homepage": "https://github.com/fed135/Kalm#readme",
"devDependencies": {
"chai": "3.4.x",
- "coveralls": "2.11.x",
- "istanbul": "0.4.x",
"mocha": "2.4.x"
},
"dependencies": {
diff --git a/src/Channel.js b/src/Channel.js
new file mode 100644
index 0000000..9a2f83b
--- /dev/null
+++ b/src/Channel.js
@@ -0,0 +1,99 @@
+/**
+ * Channel class
+ * @class Channel
+ * @exports {Channel}
+ */
+
+'use strict';
+
+/* Methods -------------------------------------------------------------------*/
+
+class Channel {
+
+ /**
+ * Channel constructor
+ * @constructor
+ * @param {Socket} socket An optionnal socket object to use for communication
+ * @param {object} options The configuration options for the client
+ */
+ constructor(name, options, client) {
+ this.name = name;
+ this.options = options;
+
+ this._client = client;
+ this._emitter = client._emit.bind(client);
+
+ this._timer = null;
+ this._packets = [];
+ this._handlers = [];
+ }
+
+ /**
+ * Tells the channel to process the payload to send
+ * @method send
+ * @memberof Channel
+ * @param {object|string} payload The payload to process
+ */
+ send(payload) {
+ this._packets.push(payload);
+
+ // Bundling process
+ if (this._packets.length >= this.options.maxPackets) {
+ if (this._timer !== null) {
+ clearTimeout(this._timer);
+ this._timer = null;
+ }
+
+ this._emit();
+ return;
+ }
+
+ if (this._timer === null) {
+ this._timer = setTimeout(this._emit.bind(this), this.options.delay);
+ }
+ }
+
+ /**
+ * Alerts the client to emit the packets for this channel
+ * @private
+ * @method _emit
+ * @memberof Channel
+ */
+ _emit() {
+ this._emitter(this.name, this._packets);
+ this._packets.length = 0;
+ }
+
+ /**
+ * Adds a method that listens to this channel
+ * @method addHandler
+ * @memberof Channel
+ * @param {function} method The method to bind
+ */
+ addHandler(method) {
+ this._handlers.push(method);
+ }
+
+ /**
+ * Handles channel data
+ * @method handleData
+ * @memberof Channel
+ * @param {array} payload The received payload
+ */
+ handleData(payload) {
+ var _reqs = payload.length;
+ var _listeners = this._handlers.length;
+ var i;
+ var c;
+
+ for (i = 0; i<_reqs; i++) {
+ for (c = 0; c<_listeners; c++) {
+ this._handlers[c](payload[i], this._client);
+ }
+ }
+ };
+}
+
+/* Exports -------------------------------------------------------------------*/
+
+module.exports = Channel;
\ No newline at end of file
diff --git a/src/Client.js b/src/Client.js
index c1fe511..3ccfb80 100644
--- a/src/Client.js
+++ b/src/Client.js
@@ -8,180 +8,174 @@
/* Requires ------------------------------------------------------------------*/
-var util = require('util');
-var EventEmitter = require('events').EventEmitter;
+const EventEmitter = require('events').EventEmitter;
-var debug = require('debug')('kalm');
+const debug = require('debug')('kalm');
+var defaults = require('./defaults');
var adapters = require('./adapters');
var encoders = require('./encoders');
-var middleware = require('./middleware');
-/* Methods -------------------------------------------------------------------*/
+var Channel = require('./Channel');
-Client.UID = 0;
+/* Local variables -----------------------------------------------------------*/
-/**
- * Client constructor
- * @constructor
- * @param {Socket} socket An optionnal socket object to use for communication
- * @param {object} options The configuration options for the client
- */
-function Client(socket, options) {
- EventEmitter.call(this);
-
- this.uid = Client.UID++;
-
- if (options === undefined) {
- options = socket;
- socket = null;
- }
- options = options || {};
-
- this.options = {
- // Basic info
- hostname: options.hostname || '0.0.0.0',
- port: options.port || 80,
- // Adapter
- adapter: options.adapter || 'ipc',
- // Encoding
- encoder: options.encoder || 'json',
- // Transformations (middleware)
- transform: options.transform || {
- bundler: {
- maxPackets: 512,
- delay: 16
- }
+const _channelBase = '/';
+
+/* Methods -------------------------------------------------------------------*/
+
+class Client extends EventEmitter{
+
+ /**
+ * Client constructor
+ * @constructor
+ * @param {Socket} socket An optionnal socket object to use for communication
+ * @param {object} options The configuration options for the client
+ */
+ constructor(socket, options) {
+ super();
+ if (options === undefined) {
+ options = socket;
+ socket = null;
}
- };
-
- // List of channels
- this.channels = {};
- // Populate channels
- if (options.channels) {
- for (var c in options.channels) {
- this.channel(c, options.channels[c]);
+ options = options || {};
+
+ this.options = {
+ // Basic info
+ hostname: options.hostname || defaults.hostname,
+ port: options.port || defaults.port,
+ // Adapter
+ adapter: options.adapter || defaults.adapter,
+ // Encoding
+ encoder: options.encoder || defaults.encoder,
+ // Transformations (middleware)
+ bundler: options.bundler || defaults.bundler
+ };
+
+ // List of channels
+ this.channels = {};
+
+ // Populate channels
+ if (options.channels) {
+ for (var c in options.channels) {
+ this.channel(c, options.channels[c]);
+ }
}
- }
- // Socket object
- this.use(socket);
-
- // Data packets - transient state - by channel
- this.packets = {};
-}
+ // Socket object
+ this.use(socket);
+ }
-/**
- * Creates a channel for the client
- * @method channel
- * @memberof Client
- * @param {string} name The name of the channel.
- * @param {function} handler The handler to add to the channel
- * @returns {Client} The client, for chaining
- */
-Client.prototype.channel = function(name, handler) {
- name = name || '/';
+ /**
+ * Creates a channel for the client
+ * @method channel
+ * @memberof Client
+ * @param {string} name The name of the channel.
+ * @param {function} handler The handler to add to the channel
+ * @returns {Client} The client, for chaining
+ */
+ channel(name, handler) {
+ name = name || _channelBase;
+
+ if (!this.channels.hasOwnProperty(name)) {
+ debug(
+ 'log: new channel ' +
+ this.options.adapter + '://' + this.options.hostname + ':' +
+ this.options.port + '/' + name
+ );
+ this.channels[name] = new Channel(
+ name,
+ this.options.bundler,
+ this
+ );
+ }
- if (name[0] !== '/') name = '/' + name;
+ if (handler) {
+ this.channels[name].addHandler(handler);
+ }
- if (!(name in this.channels)) {
- debug(
- 'log: new channel ' +
- this.options.adapter + '://' + this.options.hostname + ':' +
- this.options.port + name
- );
- this.channels[name] = [];
+ return this;
}
- this.channels[name].push(handler);
- return this;
-};
+ /**
+ * Defines a socket to use for communication, disconnects previous connection
+ * @method use
+ * @memberof Client
+ * @param {Socket} socket The socket to use
+ * @returns {Client} The client, for chaining
+ */
+ use(socket) {
+ if (this.socket) {
+ debug('log: disconnecting current socket');
+ adapters.resolve(this.options.adapter).disconnect(this.socket);
+ }
-/**
- * Defines a socket to use for communication, disconnects previous connection
- * @method use
- * @memberof Client
- * @param {Socket} socket The socket to use
- * @returns {Client} The client, for chaining
- */
-Client.prototype.use = function(socket) {
- if (this.socket) {
- adapters.resolve(this.options.adapter).disconnect(this.socket);
+ this.socket = this._createSocket(socket);
+ return this;
}
- this.socket = this._createSocket(socket);
- return this;
-};
-
-/**
- * Queues a packet for transfer on the given channel
- * @method send
- * @memberof Client
- * @param {string} channel The channel to send to data through
- * @param {string|object} payload The payload to send
- * @returns {Client} The client, for chaining
- */
-Client.prototype.send = function(channel, payload) {
- channel = channel || '/';
- if (!this.packets[channel]) this.packets[channel] = [];
- this.packets[channel].push(payload);
- // Go through middlewares
- middleware.process(this, channel, payload);
-
- return this;
-};
+ /**
+ * Queues a packet for transfer on the given channel
+ * @method send
+ * @memberof Client
+ * @param {string} name The channel to send to data through
+ * @param {string|object} payload The payload to send
+ * @returns {Client} The client, for chaining
+ */
+ send(name, payload) {
+ if (!this.channels.hasOwnProperty(name)) {
+ this.channel(name);
+ }
+ this.channels[name].send(payload);
+ return this;
+ }
-/**
- * Creates or attaches a socket for the appropriate adapter
- * @private
- * @method _createSocket
- * @memberof Client
- * @param {Socket} socket The socket to use
- * @returns {Socket} The created or attached socket for the client
- */
-Client.prototype._createSocket = function(socket) {
- return adapters.resolve(this.options.adapter).createSocket(this, socket);
-};
+ /**
+ * Creates or attaches a socket for the appropriate adapter
+ * @private
+ * @method _createSocket
+ * @memberof Client
+ * @param {Socket} socket The socket to use
+ * @returns {Socket} The created or attached socket for the client
+ */
+ _createSocket(socket) {
+ return adapters.resolve(this.options.adapter).createSocket(this, socket);
+ }
-/**
- * Sends a packet - triggered by middlewares
- * @private
- * @method _emit
- * @memberof Client
- * @param {string} channel The channel targeted for transfer
- */
-Client.prototype._emit = function(channel) {
- adapters.resolve(this.options.adapter).send(
- this.socket,
- encoders.resolve(this.options.encoder).encode({
- c: channel,
- d: this.packets[channel]
- })
- );
- this.packets[channel].length = 0;
-}
+ /**
+ * Sends a packet - triggered by middlewares
+ * @private
+ * @method _emit
+ * @memberof Client
+ * @param {string} channel The channel targeted for transfer
+ */
+ _emit(channel, packets) {
+ adapters.resolve(this.options.adapter).send(
+ this.socket,
+ encoders.resolve(this.options.encoder).encode({
+ c: channel,
+ d: packets
+ })
+ );
+ }
-/**
- * Handler for receiving data through the listener
- * @private
- * @method _handleRequest
- * @memberof Client
- * @param {Buffer} evt The data received
- */
-Client.prototype._handleRequest = function(evt) {
- var raw = encoders.resolve(this.options.encoder).decode(evt);
- if (raw.c[0] !== '/') raw.c = '/' + raw.c;
-
- if (raw.c in this.channels) {
- for (var i = 0; i= 0; i--) {
- this.connections[i].send(channel, payload);
+ /**
+ * Adds a channel to listen for on attached clients
+ * @method channel
+ * @memberof Server
+ * @param {string} name The name of the channel to attach
+ * @param {function} handler The handler to attach to the channel
+ * @returns {Server} Returns itself for chaining
+ */
+ channel(name, handler) {
+ this.channels[name] = handler;
+
+ for (var i = this.connections.length - 1; i >= 0; i--) {
+ this.connections[i].channel(name, handler);
+ }
+
+ return this;
}
- return this;
-};
+ /**
+ * Sends data to all connected clients
+ * @method broadcast
+ * @memberof Server
+ * @param {string} channel The name of the channel to send to
+ * @param {string|object} payload The payload to send
+ * @returns {Server} Returns itself for chaining
+ */
+ broadcast(channel, payload) {
+ for (var i = this.connections.length - 1; i >= 0; i--) {
+ this.connections[i].send(channel, payload);
+ }
+
+ return this;
+ }
-/**
- * Closes the server
- * @method stop
- * @memberof Server
- * @param {function} callback The callback method for the operation
- */
-Server.prototype.stop = function(callback) {
- this.connections.length = 0;
- if (this.listener) {
- adapters.resolve(this.options.adapter).stop(this, callback);
+ /**
+ * Closes the server
+ * @method stop
+ * @memberof Server
+ * @param {function} callback The callback method for the operation
+ */
+ stop(callback) {
+ debug('warn: stopping server');
+ if (this.listener) {
+ adapters.resolve(this.options.adapter).stop(this, callback);
+ }
+ else {
+ callback();
+ }
}
-};
-/**
- * Handler for receiving a new connection
- * @private
- * @method _handleRequest
- * @memberof Server
- * @param {Socket} socket The received connection socket
- */
-Server.prototype._handleRequest = function(socket) {
- var client = new Client(socket, {
- adapter: this.options.adapter,
- encoder: this.options.encoder,
- channels: this.channels
- });
- this.connections.push(client);
- this.emit('connection', client);
- return client;
-};
-
-util.inherits(Server, EventEmitter);
+ /**
+ * Handler for receiving a new connection
+ * @private
+ * @method _handleRequest
+ * @memberof Server
+ * @param {Socket} socket The received connection socket
+ */
+ _handleRequest(socket) {
+ var client = new Client(socket, {
+ adapter: this.options.adapter,
+ encoder: this.options.encoder,
+ channels: this.channels
+ });
+ this.connections.push(client);
+ this.emit('connection', client);
+ return client;
+ }
+}
/* Exports -------------------------------------------------------------------*/
diff --git a/src/adapters/index.js b/src/adapters/index.js
index d1fd1c8..dad29fb 100644
--- a/src/adapters/index.js
+++ b/src/adapters/index.js
@@ -7,19 +7,16 @@
/* Requires ------------------------------------------------------------------*/
-var ipc = require('./ipc.adapter');
-var tcp = require('./tcp.adapter');
-var udp = require('./udp.adapter');
+const debug = require('debug')('kalm');
-var debug = require('debug')('kalm');
+var list = {};
-/* Local variables -----------------------------------------------------------*/
-
-var list = {
- ipc: ipc,
- tcp: tcp,
- udp: udp
-};
+// If running in the browser, do not load net adapters
+if (process.env.NODE_ENV !== 'browser') {
+ list.ipc = require('./ipc.adapter');
+ list.tcp = require('./tcp.adapter');
+ list.udp = require('./udp.adapter');
+}
/* Methods -------------------------------------------------------------------*/
@@ -30,7 +27,7 @@ var list = {
* @returns {object|undefined} The adapter
*/
function resolve(name) {
- if (list[name]) {
+ if (list.hasOwnProperty(name)) {
return list[name];
}
else {
diff --git a/src/adapters/ipc.adapter.js b/src/adapters/ipc.adapter.js
index af4e5db..08b6a72 100644
--- a/src/adapters/ipc.adapter.js
+++ b/src/adapters/ipc.adapter.js
@@ -8,12 +8,14 @@
/* Requires ------------------------------------------------------------------*/
-var net = require('net');
-var fs = require('fs');
+const net = require('net');
+const fs = require('fs');
+
+const debug = require('debug')('kalm');
/* Local variables -----------------------------------------------------------*/
-var defaultPath = '/tmp/app.socket-';
+const _path = '/tmp/app.socket-';
/* Methods -------------------------------------------------------------------*/
@@ -24,17 +26,31 @@ var defaultPath = '/tmp/app.socket-';
* @param {function} callback The callback for the operation
*/
function listen(server, callback) {
- fs.unlink(defaultPath + server.options.port, function _bindSocket() {
+ fs.unlink(_path + server.options.port, () => {
server.listener = net.createServer(server._handleRequest.bind(server));
- server.listener.listen(defaultPath + server.options.port, callback);
- server.listener.on('error', function _handleServerError(err) {
+ server.listener.listen(_path + server.options.port, callback);
+ server.listener.on('error', (err) => {
+ debug('error: ' + err);
server.emit('error', err);
});
});
};
+/**
+ * Stops the server.
+ * @method stop
+ * @param {Server} server The server object
+ * @param {function} callback The success callback for the operation
+ */
function stop(server, callback) {
- server.listener.close(callback || function() {});
+ server.connections.forEach((e) => {
+ e.socket.destroy();
+ });
+
+ process.nextTick(() => {
+ server.connections.length = 0;
+ server.listener.close(callback || function() {});
+ });
}
/**
@@ -44,7 +60,7 @@ function stop(server, callback) {
* @param {Buffer} payload The body of the request
*/
function send(socket, payload) {
- socket.write(payload);
+ if (socket) socket.write(payload);
};
/**
@@ -56,13 +72,19 @@ function send(socket, payload) {
*/
function createSocket(client, socket) {
if (!socket) {
- socket = net.connect(defaultPath + client.options.port);
+ socket = net.connect(_path + client.options.port);
}
socket.on('data', client._handleRequest.bind(client));
- socket.on('error', function _handleSocketError(err) {
+ socket.on('error', (err) => {
+ debug('error: ' + err);
client.emit('error', err);
});
+ // Will auto-reconnect
+ socket.on('close', () => {
+ client.socket = null;
+ });
+
return socket;
};
diff --git a/src/adapters/tcp.adapter.js b/src/adapters/tcp.adapter.js
index 7bbda79..1063ca1 100644
--- a/src/adapters/tcp.adapter.js
+++ b/src/adapters/tcp.adapter.js
@@ -8,7 +8,9 @@
/* Requires ------------------------------------------------------------------*/
-var net = require('net');
+const net = require('net');
+
+const debug = require('debug')('kalm');
/* Methods -------------------------------------------------------------------*/
@@ -21,7 +23,8 @@ var net = require('net');
function listen(server, callback) {
server.listener = net.createServer(server._handleRequest.bind(server));
server.listener.listen(server.options.port, callback);
- server.listener.on('error', function _handleServerError(err) {
+ server.listener.on('error', (err) => {
+ debug('error: ' + err);
server.emit('error', err);
});
}
@@ -33,7 +36,7 @@ function listen(server, callback) {
* @param {Buffer} payload The body of the request
*/
function send(socket, payload) {
- socket.write(payload);
+ if (socket) socket.write(payload);
}
/**
@@ -43,7 +46,14 @@ function send(socket, payload) {
* @param {function} callback The success callback for the operation
*/
function stop(server, callback) {
- server.listener.close(callback || function() {});
+ server.connections.forEach((e) => {
+ e.socket.destroy();
+ });
+
+ process.nextTick(() => {
+ server.connections.length = 0;
+ server.listener.close(callback || function() {});
+ });
}
/**
@@ -58,10 +68,16 @@ function createSocket(client, socket) {
socket = net.connect(client.options.port, client.options.hostname);
}
socket.on('data', client._handleRequest.bind(client));
- socket.on('error', function _handleSocketError(err) {
+ socket.on('error', (err) => {
+ debug('error: ' + err);
client.emit('error', err);
});
+ // Will auto-reconnect
+ socket.on('close', () => {
+ client.socket = null;
+ });
+
return socket;
}
diff --git a/src/adapters/udp.adapter.js b/src/adapters/udp.adapter.js
index cf984d4..51f17d2 100644
--- a/src/adapters/udp.adapter.js
+++ b/src/adapters/udp.adapter.js
@@ -8,10 +8,15 @@
/* Requires ------------------------------------------------------------------*/
-var dgram = require('dgram');
+const dgram = require('dgram');
+
+const debug = require('debug')('kalm');
/* Helpers -------------------------------------------------------------------*/
+/**
+ * Creates a socket + Client on UDP data
+ */
function _handleNewSocket(data, origin) {
var key = origin.address+':'+origin.port;
@@ -39,9 +44,13 @@ function _handleNewSocket(data, origin) {
function listen(server, callback) {
server.listener = dgram.createSocket('udp4');
server.listener.on('message', _handleNewSocket.bind(server));
+ server.listener.on('error', (err) => {
+ debug('error: ' + err);
+ server.emit('error', err);
+ });
server.listener.bind(server.options.port, '127.0.0.1');
- process.nextTick(callback);
+ callback();
};
/**
@@ -51,7 +60,6 @@ function listen(server, callback) {
* @param {Buffer} payload The body of the request
*/
function send(socket, payload) {
- console.log('send');
socket.send(
payload,
0,
@@ -68,6 +76,7 @@ function send(socket, payload) {
* @param {function} callback The success callback for the operation
*/
function stop(server, callback) {
+ server.connections.length = 0;
if (server.listener && server.listener.close) {
server.listener.close(callback);
}
@@ -87,6 +96,10 @@ function createSocket(client, soc) {
var socket = dgram.createSocket('udp4');
socket.__port = client.options.port;
socket.__hostname = client.options.hostname;
+ socket.on('error', (err) => {
+ debug('error: ' + err);
+ client.emit('error', err);
+ });
return socket;
};
diff --git a/src/defaults.js b/src/defaults.js
new file mode 100644
index 0000000..86979ee
--- /dev/null
+++ b/src/defaults.js
@@ -0,0 +1,18 @@
+/**
+ * Default properties for new Clients/ Servers
+ */
+
+'use strict'
+
+/* Exports -------------------------------------------------------------------*/
+
+module.exports = {
+ hostname: '0.0.0.0',
+ port: 3000,
+ adapter: 'tcp',
+ encoder: 'msg-pack',
+ bundler: {
+ maxPackets: 2048,
+ delay: 16
+ }
+};
\ No newline at end of file
diff --git a/src/encoders/index.js b/src/encoders/index.js
index 8e9e52d..f2d5a1d 100644
--- a/src/encoders/index.js
+++ b/src/encoders/index.js
@@ -10,7 +10,7 @@
var json = require('./json');
var msgPack = require('./msg-pack');
-var debug = require('debug')('kalm');
+const debug = require('debug')('kalm');
/* Local variables -----------------------------------------------------------*/
@@ -28,7 +28,7 @@ var list = {
* @returns {object|undefined} The encoder
*/
function resolve(name) {
- if (list[name]) {
+ if (list.hasOwnProperty(name)) {
return list[name];
}
else {
diff --git a/src/encoders/msg-pack.js b/src/encoders/msg-pack.js
index a95af3c..0ff77f5 100644
--- a/src/encoders/msg-pack.js
+++ b/src/encoders/msg-pack.js
@@ -8,8 +8,8 @@
/* Requires ------------------------------------------------------------------*/
-var msgDecode = require('msgpack-decode');
-var msgPack = require('msgpack-lite');
+const msgDecode = require('msgpack-decode');
+const msgPack = require('msgpack-lite');
/* Methods -------------------------------------------------------------------*/
diff --git a/src/index.js b/src/index.js
index 103b42a..e9c95cd 100644
--- a/src/index.js
+++ b/src/index.js
@@ -11,7 +11,7 @@ var Client = require('./Client');
var Server = require('./Server');
var adapters = require('./adapters');
var encoders = require('./encoders');
-var middleware = require('./middleware');
+var defaults = require('./defaults');
/* Exports -------------------------------------------------------------------*/
@@ -20,5 +20,5 @@ module.exports = {
Server: Server,
adapters: adapters,
encoders: encoders,
- middleware: middleware
+ defaults: defaults
};
\ No newline at end of file
diff --git a/src/middleware/bundler.js b/src/middleware/bundler.js
deleted file mode 100644
index 22a4e42..0000000
--- a/src/middleware/bundler.js
+++ /dev/null
@@ -1,37 +0,0 @@
-function process(client, channel, payload) {
- var options = client.options.transform.bundler;
-
- if (!client.__bundler) {
- client.__bundler = {
- timers: {}
- };
- }
-
- if (client.packets[channel].length > options.maxPackets) {
- if (client.__bundler.timers[channel]) {
- clearTimeout(client.__bundler.timers[channel]);
- }
- client._emit.call(client, channel);
- }
-
- if (!client.__bundler.timers[channel]) {
- client.__bundler.timers[channel] = setTimeout(
- function _emitBundle() {
- client._emit.call(client, channel);
- },
- options.delay
- );
- }
-}
- // Bundling logic
- // -----------------------------
- // Add new calls to the bundle stack
- // If stack length exceeds limit OR
- // If time since last chunk sent is greater than the delay -
- // AND there is an item in the stack
- // Send.
- // If an item is added and delay timer is not started, start it.
-
-module.exports = {
- process: process
-};
\ No newline at end of file
diff --git a/src/middleware/index.js b/src/middleware/index.js
deleted file mode 100644
index 0adbb79..0000000
--- a/src/middleware/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-var bundler = require('./bundler');
-
-var list = {
- bundler: bundler
-};
-
-function process(client, channel, payload) {
- for (var t in client.options.transform) {
- if (t in list) list[t].process(client, channel, payload);
- }
-}
-
-function register(name, mod) {
- list[name] = mod;
-}
-
-module.exports = {
- process: process,
- register: register
-};
\ No newline at end of file
diff --git a/tests/benchmarks/raw-ipc.test.js b/tests/benchmarks/adapters/ipc.js
similarity index 64%
rename from tests/benchmarks/raw-ipc.test.js
rename to tests/benchmarks/adapters/ipc.js
index 88c2fa8..394c596 100644
--- a/tests/benchmarks/raw-ipc.test.js
+++ b/tests/benchmarks/adapters/ipc.js
@@ -8,8 +8,7 @@
var net = require('net');
-var settings = require('./settings');
-var Kalm = require('../../index');
+var settings = require('../settings');
/* Local variables -----------------------------------------------------------*/
@@ -17,29 +16,46 @@ var server;
var client;
var count = 0;
+var handbreak = true;
/* Methods -------------------------------------------------------------------*/
+function _absorb(err) {
+ console.log(err);
+ return true;
+}
+
function setup(resolve) {
server = net.createServer(function(socket) {
+ socket.on('error', _absorb);
socket.on('data', function() {
count++;
});
});
+ handbreak = false;
+ server.on('error', _absorb);
server.listen('/tmp/app.socket-' + settings.port, resolve);
}
function teardown(resolve) {
- if (server) server.close();
- server = null;
- client = null;
- resolve(count);
+ if (client) client.destroy();
+ if (server) server.close(function() {
+ server = null;
+ client = null;
+ resolve(count);
+ });
+}
+
+function stop(resolve) {
+ handbreak = true;
+ setTimeout(resolve, 0);
}
function step(resolve) {
- if (!server) return;
+ if (handbreak) return;
if (!client) {
client = net.connect('/tmp/app.socket-' + settings.port);
+ client.on('error', _absorb);
}
client.write(JSON.stringify(settings.testPayload));
@@ -51,5 +67,6 @@ function step(resolve) {
module.exports = {
setup: setup,
teardown: teardown,
- step: step
+ step: step,
+ stop: stop
};
\ No newline at end of file
diff --git a/tests/benchmarks/kalm.test.js b/tests/benchmarks/adapters/kalm.js
similarity index 70%
rename from tests/benchmarks/kalm.test.js
rename to tests/benchmarks/adapters/kalm.js
index f25accf..d80b53b 100644
--- a/tests/benchmarks/kalm.test.js
+++ b/tests/benchmarks/adapters/kalm.js
@@ -6,8 +6,8 @@
/* Requires ------------------------------------------------------------------*/
-var settings = require('./settings');
-var Kalm = require('../../index');
+var settings = require('../settings');
+var Kalm = require('../../../index');
/* Local variables -----------------------------------------------------------*/
@@ -15,6 +15,7 @@ var server;
var client;
var count = 0;
+var handbreak = true;
/* Methods -------------------------------------------------------------------*/
@@ -29,28 +30,33 @@ function setup(resolve) {
count++;
});
+ handbreak = false;
server.on('ready', resolve);
}
function teardown(resolve) {
- if (server) server.stop();
- server = null;
- client = null;
- resolve(count);
+ if (server) server.stop(function() {
+ server = null;
+ client = null;
+ resolve(count);
+ });
+}
+
+function stop(resolve) {
+ handbreak = true;
+ setTimeout(resolve, 0);
}
function step(resolve) {
- if (!server) return;
+ if (handbreak) return;
if (!client) {
client = new Kalm.Client({
port: settings.port,
adapter: settings.adapter,
encoder: settings.encoder,
- transform: {
- bundler: {
- maxPackets: settings.bundlerMaxPackets,
- delay: settings.bundlerDelay
- }
+ bundler: {
+ maxPackets: settings.bundlerMaxPackets,
+ delay: settings.bundlerDelay
},
hostname: '0.0.0.0'
});
@@ -65,5 +71,6 @@ function step(resolve) {
module.exports = {
setup: setup,
teardown: teardown,
- step: step
+ step: step,
+ stop: stop
};
\ No newline at end of file
diff --git a/tests/benchmarks/raw.test.js b/tests/benchmarks/adapters/tcp.js
similarity index 63%
rename from tests/benchmarks/raw.test.js
rename to tests/benchmarks/adapters/tcp.js
index daabb70..586c4b0 100644
--- a/tests/benchmarks/raw.test.js
+++ b/tests/benchmarks/adapters/tcp.js
@@ -8,8 +8,7 @@
var net = require('net');
-var settings = require('./settings');
-var Kalm = require('../../index');
+var settings = require('../settings');
/* Local variables -----------------------------------------------------------*/
@@ -17,31 +16,49 @@ var server;
var client;
var count = 0;
+var handbreak = true;
/* Methods -------------------------------------------------------------------*/
+function _absorb(err) {
+ console.log(err);
+ return;
+}
+
function setup(resolve) {
server = net.createServer(function(socket) {
socket.on('data', function() {
count++;
});
+ socket.on('error', _absorb);
});
+ handbreak = false;
+ server.on('error', _absorb);
server.listen(settings.port, resolve);
}
function teardown(resolve) {
- if (server) server.close();
- server = null;
- client = null;
- resolve(count);
+ if (client) client.destroy();
+ if (server) server.close(function() {
+ server = null;
+ client = null;
+ resolve(count);
+ });
+}
+
+function stop(resolve) {
+ handbreak = true;
+ setTimeout(resolve, 0);
}
function step(resolve) {
- if (!server) return;
+ if (handbreak) return;
if (!client) {
client = net.connect(settings.port, '0.0.0.0');
+ client.on('error', _absorb);
}
+ if (client)
client.write(JSON.stringify(settings.testPayload));
resolve();
}
@@ -51,5 +68,6 @@ function step(resolve) {
module.exports = {
setup: setup,
teardown: teardown,
- step: step
+ step: step,
+ stop: stop
};
\ No newline at end of file
diff --git a/tests/benchmarks/raw-udp.test.js b/tests/benchmarks/adapters/udp.js
similarity index 75%
rename from tests/benchmarks/raw-udp.test.js
rename to tests/benchmarks/adapters/udp.js
index 90526bc..0ead264 100644
--- a/tests/benchmarks/raw-udp.test.js
+++ b/tests/benchmarks/adapters/udp.js
@@ -8,7 +8,7 @@
var dgram = require('dgram');
-var settings = require('./settings');
+var settings = require('../settings');
/* Local variables -----------------------------------------------------------*/
@@ -16,16 +16,24 @@ var server;
var client;
var count = 0;
+var handbreak = true;
/* Methods -------------------------------------------------------------------*/
+function _absorb(err) {
+ console.log(err);
+ return;
+}
+
function setup(resolve) {
server = dgram.createSocket('udp4');
server.on('message', function() {
count++;
});
+ handbreak = false;
+ server.on('error', _absorb);
server.bind(settings.port, '0.0.0.0');
- process.nextTick(resolve);
+ resolve();
}
function teardown(resolve) {
@@ -36,10 +44,16 @@ function teardown(resolve) {
});
}
+function stop(resolve) {
+ handbreak = true;
+ setTimeout(resolve, 0);
+}
+
function step(resolve) {
- if (!server) return;
+ if (handbreak) return;
if (!client) {
client = dgram.createSocket('udp4');
+ client.on('error', _absorb);
}
var payload = new Buffer(JSON.stringify(settings.testPayload));
@@ -59,5 +73,6 @@ function step(resolve) {
module.exports = {
setup: setup,
teardown: teardown,
- step: step
+ step: step,
+ stop: stop
};
\ No newline at end of file
diff --git a/tests/benchmarks/index.js b/tests/benchmarks/index.js
index f1f23c6..26d6adf 100644
--- a/tests/benchmarks/index.js
+++ b/tests/benchmarks/index.js
@@ -1,33 +1,51 @@
-// TODO: Cleanup!
+/**
+ * Kalm benchmarking
+ */
-var Kalm = require('./kalm.test');
-//var Raw = require('./raw.test');
-//var Raw = require('./raw-ipc.test');
-var Raw = require('./raw-udp.test');
-//var Raw = require('./raw-ws.test');
+'use strict';
+
+/* Requires ------------------------------------------------------------------*/
+
+var Kalm = require('./adapters/kalm');
+var TCP = require('./adapters/tcp');
+var IPC = require('./adapters/ipc');
+var UDP = require('./adapters/udp');
var settings = require('./settings');
-var maxCount = null;
-var curr = 0;
+/* Local variables -----------------------------------------------------------*/
+
+var _maxCount = null;
+var _curr = 0;
+
+var Suite = {
+ ipc: IPC,
+ tcp: TCP,
+ udp: UDP
+};
-function _kalm(resolve) {
- curr = 0;
- Kalm.setup(function() {
- setTimeout(function() {
- Kalm.teardown(function(total) {
- console.log('kalm: ' + total);
- resolve();
+var tests = [];
+var adpts;
+var results = {};
+
+/* Methods -------------------------------------------------------------------*/
+
+function _measure(adapter, resolve) {
+ _curr = 0;
+ adapter.setup(function _setupHandler() {
+ setTimeout(function _stopAdapter() {
+ adapter.stop(function _finish() {
+ adapter.teardown(resolve);
});
}, settings.testDuration);
function _repeat() {
- if (maxCount !== null) {
- if (curr >= maxCount) return;
- curr++;
+ if (_maxCount !== null) {
+ if (_curr >= _maxCount) return;
+ _curr++;
}
- setImmediate(function() {
- Kalm.step(_repeat);
+ setImmediate(function _stepHandler() {
+ adapter.step(_repeat);
});
}
@@ -35,31 +53,63 @@ function _kalm(resolve) {
});
}
-function _raw(resolve) {
- curr = 0;
- Raw.setup(function() {
- setTimeout(function() {
- Raw.teardown(function(total) {
- console.log('raw: ' + total);
- resolve();
- });
- }, settings.testDuration);
+function _updateSettings(obj, resolve) {
+ settings.adapter = obj.adapter || settings.adapter;
+ resolve();
+}
- function _repeat() {
- if (maxCount !== null) {
- if (curr >= maxCount) return;
- curr++;
- }
+function _errorHandler(err) {
+ console.log(err);
+}
- setImmediate(function() {
- Raw.step(_repeat);
- });
- }
+function _postResults() {
+ console.log(JSON.stringify(results));
+ // Do something with the info
+ process.exit();
+}
- _repeat();
+/* Init ----------------------------------------------------------------------*/
+
+
+// Roll port number
+settings.port = 3000 + Math.round(Math.random()*1000);
+
+var adpts = Object.keys(Suite).map(function(k) {
+ return {
+ adapter: k,
+ settings: {adapter: k},
+ raw: Suite[k],
+ kalm: Kalm
+ };
+});
+
+adpts.forEach(function(i) {
+ tests.push(function(resolve) {
+ console.log('Configuring ' + i.adapter);
+ _updateSettings(i.settings, resolve);
});
-}
-_kalm(function() {
- _raw(process.exit);
-})
\ No newline at end of file
+ tests.push(function(resolve) {
+ console.log('Measuring raw ' + i.adapter);
+ _measure(i.raw, function(total) {
+ results['raw_' + i.adapter] = total;
+ resolve();
+ });
+ });
+
+ tests.push(function(resolve) {
+ console.log('Measuring Kalm ' + i.adapter);
+ _measure(i.kalm, function(total) {
+ results['kalm_' + i.adapter] = total;
+ resolve();
+ });
+ });
+});
+
+tests.push(_postResults);
+
+tests.reduce(function(current, next) {
+ return current.then(function(resolve) {
+ return new Promise(next).then(resolve, _errorHandler);
+ }, _errorHandler);
+}, Promise.resolve());
\ No newline at end of file
diff --git a/tests/benchmarks/settings.js b/tests/benchmarks/settings.js
index 7a25554..17b8793 100644
--- a/tests/benchmarks/settings.js
+++ b/tests/benchmarks/settings.js
@@ -3,7 +3,7 @@ module.exports = {
encoder: 'msg-pack',
port: 3000,
bundlerDelay: 16,
- bundlerMaxPackets: 512,
+ bundlerMaxPackets: 2048,
testDuration: 1000 * 60,
testPayload: { foo: 'bar'},
testChannel: 'test'
diff --git a/tests/index.js b/tests/index.js
index 5af573d..072a720 100644
--- a/tests/index.js
+++ b/tests/index.js
@@ -1,31 +1,218 @@
+/**
+ * Kalm test suite
+ */
+
+'use strict';
+
+/* Requires ------------------------------------------------------------------*/
+
var assert = require('chai').assert;
var Kalm = require('../index');
-describe('Starting service', function() {
- it('constructor', function(done) {
- var server = new Kalm.Server({
- port: 3000,
- adapter: 'ipc',
- encoder: 'msg-pack'
+/* Models --------------------------------------------------------------------*/
+
+var adapterFormat = {
+ listen: function() {},
+ send: function() {},
+ stop: function() {},
+ createSocket: function() {},
+ disconnect: function() {}
+};
+
+var encoderFormat = {
+ encode: function() {},
+ decode: function() {}
+};
+
+/* Suite ---------------------------------------------------------------------*/
+
+describe('Index', function() {
+ it('Kalm', function() {
+ assert.property(Kalm, 'Client', 'Client not exposed in Kalm index');
+ assert.property(Kalm, 'Server', 'Server not exposed in Kalm index');
+ assert.property(Kalm, 'adapters', 'adapters not exposed in Kalm index');
+ assert.property(Kalm, 'encoders', 'encoders not exposed in Kalm index');
+ });
+});
+
+describe('Adapters', function() {
+
+ it('index', function() {
+ assert.isFunction(Kalm.adapters.register, 'register method not valid in Kalm adapters');
+ assert.isFunction(Kalm.adapters.resolve, 'resolve method not valid in Kalm adapters');
+ });
+
+ describe('bundled', function() {
+ it('ipc', function() {
+ var ipc_test = Kalm.adapters.resolve('ipc');
+ assert.isObject(ipc_test, 'ipc is not a valid adapter object');
+ allMembersTypeMatch(ipc_test, adapterFormat);
+ });
+
+ it('tcp', function() {
+ var tcp_test = Kalm.adapters.resolve('tcp');
+ assert.isObject(tcp_test, 'tcp is not a valid adapter object');
+ allMembersTypeMatch(tcp_test, adapterFormat);
+ });
+
+ it('udp', function() {
+ var udp_test = Kalm.adapters.resolve('udp');
+ assert.isObject(udp_test, 'udp is not a valid adapter object');
+ allMembersTypeMatch(udp_test, adapterFormat);
+ });
+ });
+
+ describe('methods', function() {
+ it('register', function() {
+ Kalm.adapters.register('test', adapterFormat);
+ Kalm.adapters.register('test2', null);
+ });
+
+ it('resolve', function() {
+ assert.deepEqual(Kalm.adapters.resolve('test'), adapterFormat);
+ assert.equal(Kalm.adapters.resolve('test2'), null);
+ assert.equal(Kalm.adapters.resolve('test3'), null);
+ });
+ });
+});
+
+describe('Encoders', function() {
+
+ it('index', function() {
+ assert.isFunction(Kalm.encoders.register, 'register method not valid in Kalm encoders');
+ assert.isFunction(Kalm.encoders.resolve, 'resolve method not valid in Kalm encoders');
+ });
+
+ describe('bundled', function() {
+ var objTest = {foo: 'bar'};
+ var strTest = '{"foo":"bar}';
+
+ it('json', function() {
+ var json_test = Kalm.encoders.resolve('json');
+ assert.isObject(json_test, 'json is not a valid encoder object');
+ allMembersTypeMatch(json_test, encoderFormat);
+
+ assert.instanceOf(json_test.encode(objTest), Buffer, 'json encoder does not output a buffer');
+ assert.deepEqual(json_test.decode(json_test.encode(objTest)), objTest, 'Object is not the same after json decoding.');
+ });
+
+ it('msg-pack', function() {
+ var msg_test = Kalm.encoders.resolve('msg-pack');
+ assert.isObject(msg_test, 'msg-pack is not a valid encoder object');
+ allMembersTypeMatch(msg_test, encoderFormat);
+
+ assert.instanceOf(msg_test.encode(objTest), Buffer, 'msg-pack encoder does not output a buffer');
+ assert.deepEqual(msg_test.decode(msg_test.encode(objTest)), objTest, 'Object is not the same after msg-pack decoding.');
+ });
+ });
+
+ describe('methods', function() {
+ it('register', function() {
+ Kalm.encoders.register('test', encoderFormat);
+ Kalm.encoders.register('test2', null);
+ });
+
+ it('resolve', function() {
+ assert.deepEqual(Kalm.encoders.resolve('test'), encoderFormat);
+ assert.equal(Kalm.encoders.resolve('test2'), null);
+ assert.equal(Kalm.encoders.resolve('test3'), null);
+ });
+ });
+});
+
+describe('Smoke test', function() {
+ var server;
+ var client;
+
+ it('run ipc + json', function(done) {
+ server = new Kalm.Server({adapter:'ipc', encoder:'json'});
+ server.channel('test', function(data) {
+ assert.deepEqual(data, {foo:'bar'});
+ server.stop(done);
+ });
+
+ server.on('ready', function() {
+ client = new Kalm.Client({adapter:'ipc', encoder:'json'});
+ client.send('test', {foo:'bar'});
+ });
+ });
+
+ it('run ipc + msg-pack', function(done) {
+ server = new Kalm.Server({adapter:'ipc', encoder: 'msg-pack'});
+ server.channel('test', function(data) {
+ assert.deepEqual(data, {foo:'bar'});
+ server.stop(done);
});
server.on('ready', function() {
- var client = new Kalm.Client({
- port: 3000,
- adapter: 'ipc',
- encoder:'msg-pack',
- hostname: '0.0.0.0'
- });
- client.send('test', 'data');
- client.send('test', 'data2');
+ client = new Kalm.Client({adapter:'ipc', encoder: 'msg-pack'});
+ client.send('test', {foo:'bar'});
+ });
+ });
- client.send('test2', 'data3');
- done();
+ it('run tcp + json', function(done) {
+ server = new Kalm.Server({adapter:'tcp', encoder:'json'});
+ server.channel('test', function(data) {
+ assert.deepEqual(data, {foo:'bar'});
+ server.stop(done);
});
- server.on('error', function(err) {
- console.log('Server error:');
- console.log(err.stack);
+ server.on('ready', function() {
+ client = new Kalm.Client({adapter:'tcp', encoder:'json'});
+ client.send('test', {foo:'bar'});
});
});
-});
\ No newline at end of file
+
+ it('run tcp + msg-pack', function(done) {
+ server = new Kalm.Server({encoder: 'msg-pack', adapter:'tcp'});
+ server.channel('test', function(data) {
+ assert.deepEqual(data, {foo:'bar'});
+ server.stop(done);
+ });
+
+ server.on('ready', function() {
+ client = new Kalm.Client({encoder: 'msg-pack', adapter:'tcp'});
+ client.send('test', {foo:'bar'});
+ });
+ });
+
+ it('run udp + json', function(done) {
+ server = new Kalm.Server({adapter:'udp', encoder:'json'});
+ server.channel('test', function(data) {
+ assert.deepEqual(data, {foo:'bar'});
+ server.stop(done);
+ });
+
+ server.on('ready', function() {
+ client = new Kalm.Client({adapter:'udp', encoder:'json'});
+ client.send('test', {foo:'bar'});
+ });
+ });
+
+ it('run udp + msg-pack', function(done) {
+ server = new Kalm.Server({encoder: 'msg-pack', adapter:'udp'});
+ server.channel('test', function(data) {
+ assert.deepEqual(data, {foo:'bar'});
+ server.stop(done);
+ });
+
+ server.on('ready', function() {
+ client = new Kalm.Client({encoder: 'msg-pack', adapter:'udp'});
+ client.send('test', {foo:'bar'});
+ });
+ });
+});
+
+/* Tooling -------------------------------------------------------------------*/
+
+/**
+ * Checks that all properties are present and of the proper type
+ */
+function allMembersTypeMatch(set1, model) {
+ for (var i in model) {
+ var type = typeof model[i];
+ assert.property(set1, i, 'property ' + i + ' is missing');
+ assert.typeOf(set1[i], type, 'property ' + i + ' should be ' + type);
+ }
+ return true;
+}
\ No newline at end of file
diff --git a/tests/test.js b/tests/test.js
deleted file mode 100644
index 30265ff..0000000
--- a/tests/test.js
+++ /dev/null
@@ -1,40 +0,0 @@
-var Kalm = require('../index');
-
-var server = new Kalm.Server({
- port: 3000,
- adapter: 'ipc',
- encoder: 'msg-pack',
- channels: {
- channel1: function(data) {
- console.log('GOT "' + data + '" on channel1!');
- },
- '/': function(data) {
- console.log('GOT "' + data + '" on main channel!');
- }
- }
-});
-
-server.on('connection', function(client) {
- // Do stuff
- client.send('greetings', 'Hi there!');
-});
-
-server.on('ready', function() {
- var client = new Kalm.Client({
- port: 3000,
- adapter: 'ipc',
- encoder:'msg-pack',
- hostname: '0.0.0.0',
- channels: {
- greetings: function(data) {
- console.log('Server [greetings]: ' + data);
- }
- }
- });
-
- client.send('channel1', 'some data');
- client.send('channel1', 'some more data');
- setTimeout(function() {
- client.send(null, {message:'object'});
- }, 1000);
-});
\ No newline at end of file
diff --git a/webpack.config b/webpack.config
new file mode 100644
index 0000000..d236a0c
--- /dev/null
+++ b/webpack.config
@@ -0,0 +1,15 @@
+module.exports = {
+ entry: __dirname + '/index.js',
+ context: __dirname,
+ output: {
+ filename: 'kalm.min.js',
+ path: __dirname + '/bin',
+ library: 'kalm',
+ libraryTarget: 'amd'
+ },
+ modules: {
+ loaders: [
+ { test: /\.js$/, loader: 'val'}
+ ]
+ }
+};