konversi

1.0.0 • Public • Published

konversi

WebSocket chat server.

Build Status

NPM

NOTE: Client side module is still only in planning phase and is not available yet.

Why

Because no one should be spending any more time building scalable chat service.

Example

Server:

& npm install -g konversi
& konversi -c /path/to/config/file.json

> ==== konversi server ======================
> version:  x.x.x
> environment:  dev
> time:     Thu, 01 Jan 1970 00:00:00 GMT
> Listening on: 0.0.0.0:80/chat
> ===========================================

That's it, you are done. Now just use a socket.io client to connect and send messages.

Client:

var socket_1 = io(path, { path: '/chat' });

// Perform handshake first
socket_1.emit('rooms:handshake', Date.now(), null, 'userID=ClientName');

// Only this socket will receive handshake confirmation or error
socket_1.on('rooms:handshake', function () {
    socket_1.emit('rooms:join', Date.now(), 'my-room-id', 'my-name');
});

socket_1.on('rooms:join', function (id, from, name) {
    // Make sure this join event is for this socket
    if (from === socket._1.id) {
        socket.emit(
            'rooms:message', // event ID
            Date.now(), // arbitrary message id number
            'my-room-id', // destination
            'greetings!' // message content
        );
        return;
    }

    // otherwise maybe make note about other sockets connecting
    // or do whatever else with this information
    otherSocketsInRoom.push([id, name]);
});

Usage

When you install and run Konversi $ konversi, it will look for the ./konversi folder in the current directory which may contain config folder.

Note: if you specify custom environment, corresponding config file, must exist.

Available application flags are:

  • -c | cfg - path to custom configuration json file.

Several config files can be provided this was which would be mixed into one in the order they appear in application arguments. This is useful when using one or more configuration files to provide default values.

See config section for more details.

Documentation

If you do need to customize Konversi functionality, do read alon. Create a Github issue, ask a question, make a pull request all is welcome.

Extending functionality of a base Konversi module is done using plugins. All that is, is just a folder structure that konversi plugin loader expects to find 3 types of implementation files in.

  • ./konversi/config/ - environmentName.json files defining environment vars.
  • ./konversi/plugins/ - your plugin definitions.
  • ./konversi/routers/ - underlying is a restify server which you can use to define http routes on top of web sockets.

Module index

  • ChatServer Application http server and socket.io manager.

  • Namespace Wraps socket.io namespaces and manages its attached APIs (SocketRouters).

  • SocketRouter Defines a collection of socket.io events and response logic functions.

  • SocketHandler Wrapper for socket.io connection object.

  • config Stores and retrieves application config values

  • constants Stores application constants

  • modules

  • middleware Provides mechanism to validate and parse user input.

    • validationRules
    • queryParser
  • utils Control flow helper

    • stack
  • run() Main application entry point.


ChatServer

Singleton main application server. This manages attached namespaces and underlying http server.

Module index exposes only ChatServer factory and a reference to the restify library.

{
   <function(): ChatServer>: instance
   <Restify>: restify
}

ChatServer#namespace(Namespace: name)

Attach new namespace definition to this server.

  • throws - namespace already registered.

ChatServer#getNamespace(string: name)

Finds and return a namespace

ChatServer#listen()

Builds server namespaces and its routers and starts listening for incoming connections.

ChatServer#close()

Closes server and socket connections.

ChatServer#getSocketsCount()

Returns number of connected sockets

ChatServer#toString()

Returns server header string.


Namespace

Defines socket.io namespace and manages event routers attached to it.

Namespace(string:id)

Creates new instance of namespace.

Namespace#id

String id

Namespace#url

Url address for this namespace

Namespace#namespace

Socket.io namespace object.

Namespace#use(SocketRouter|function: handler)

Register SocketRouter or if handler is a function a middleware function. The difference is that middleware function executes before all routers in this namespace.

Namespace#has(string: routerName)

Returns true if this namespace has a router with provided name.

Namespace#on(string: name, function: handler)

Register socket event on the namespace scope.

Namespace#getSocket(string: socketId, boolean isConnected)

Returns socket by the provided id, if isConnected is false then this functions will also search sockets in recent connections pool.


SocketRouter

Defines and serves as a group for a set of custom socket.io events.

SocketRouter(options)

Options are:

  • : name - Must provide router name
  • : set_events_prefix - Default=true. Prepends socket name to all of this router's event definitions.
  • : max_listeners - nodejs EventEmitter value.

SocketRouter#name

String name

SocketRouter#initialiseRouter()

Abstract function, use this to define router content.

SocketRouter#reset()

Deletes and resets all previously defined events for this router.

SocketRouter#use(function: middleware)

Attaches a middleware function to this router.

SocketRouter event functions

All event function signatures are as follows:

  • function[]|function: tasks - Event callback stack
  • number: priority - Sort order of this stack when calling event register multiple times.

function(socketHandler, eventId, input, next) - response stack function

SocketRouter#beforeAll(function[]: tasks, boolean: priority): SocketRouter
SocketRouter#afterAll(function[]: tasks, boolean: priority): SocketRouter
SocketRouter#response(function[]: tasks, boolean: priority): SocketRouter
SocketRouter#connection(function[]: tasks, boolean: priority): SocketRouter
SocketRouter#disconnect(function[]: tasks, boolean: priority): SocketRouter
SocketRouter#validation(function[]: tasks, boolean: priority): SocketRouter
SocketRouter#error(function[]: tasks, boolean: priority): SocketRouter
SocketRouter#on(function[]: tasks, boolean: priority): SocketRouter

Register event

SocketRouter#expect(function[]: tasks, boolean: priority): SocketRouter

Register event which has to be called before any other.

SocketRouter#bounceMessage([string: asEvent][, boolean: withBody]) : function

Creates an even stack function which will echo the message back to the originating socket connection. Specifying withBody=true will result in message body to be included in the echo message.

SocketRouter#proxyMessage([string: asEvent]) : function

Creates an event stack function which will propagate received message to the addressed room by the event's address argument.

SocketRouter#bounceError([string: asEvent]) : function

Will create a function which echoes any errors back to the originating client.


SocketHandler

Socket handler serves as a proxy to socket object and provides custom functionality within Conversi framework.

SocketHandler#id

Same as socket.id. Id is used as an address property of all messages from a given socket.

SocketHandler#address

This value overrides default id property for message address references. Default is null.

SocketHandler#socket

Reference to underlying socket object.

SocketHandler#isRoomMember(string: roomID)

Returns true if this socket joned provided room.

SocketHandler#getStore(SocketRouter: router)

Returns a persistent hash object associated with a given router. This object lives as long as this connection stays open.

SocketHandler#on(string: eventID, function: callback)

This is a decorator function used to, well decorate event transmitted data into a common to Konversi framework form.

Callback function definition is: function(socketRouter, eventId, input)

* socketRouter - This socket handler object
* eventID - String id of the event
* input - Emitted event content
    * id - Arbitrary id number (as string)
SocketHandler#to
SocketHandler#in
SocketHandler#emit

These three functions are here for convenience and are equivalent to those found on socket.io socket object.


config

Serves as a simple value dictionary with an added safety mechanism which will throw an error if a non existing parameter is tried.

This is using a ConfigManager utility, which can be found here.

It short, users can provide .json files filled with actual values or use "{{ENV_VAR_NAME}}" pattern to access those values from node.env during application runtime.

config#get(string: argumentAddress);

Returns existing config member value.

  • argumentAddress - full stop delimited string value pointing to a member inside a config object hash.
Default config object.
{
    pluginDirectory: './conversi', // where konversi should expect to find extentions

    // Options expected by restify server
    server: {
        port: 80,
        options: {} // same as restify.js server config
    },

    // Options expected by socket.io
    io: {
        path: '/chat',
        serveClient: false
    },

    // Options expected by redis adapter
    redisAdapter: {
        enable: false, // by default it is turned off
        host: 'localhost',
        port: 6379
    },

    // Configures verious aspecs of Konversi module
    behavior: {
        userInput: {
            maxAddressIdLength: 50,
            maxMessageLength: 5000
        }
    }
}

Constants

A collection of predefined values used by this module.

{
	DEFAULT_NAMESPACE_ID,
	DEFAULT_NAMESPACE_NAME,

	EVENT_CONNECTION,
	EVENT_DISCONNECT,
	EVENT_ERROR,

	EVENT_HANDSHAKE,
	EVENT_JOIN,
	EVENT_LEAVE,
	EVENT_MESSAGE,

	PARAM_RECONNECTION
}

Modules

These are implementations of vanilla Konversi functionality. Custom modules should be authored in a similar fashion as these core modules.

When you start basic Konversi application these api's is what you interact with.

Synopsis

The following APIs are described using the folllowing notation:
Left side is event trigger and right side is a response.

  • <request> --> <response> Left side is event trigger and right side is a response.
  • --> This is a message proxy, i.e. message propagation to addressed clients.
  • <-> This is a message bounce, i.e. message being echoed back to the origination client. It's primary use is confirmation mechanism.
Request/response arguments

Konversi expects all event trigger requests to be in the following form:

  • string: id - Arbitrary numeric value.
  • string: address - Destination id value either socket id or room name.
  • string: body - Message body

RootNamespaceRouter

This does not do anything and serves the only purpose of being provided to plugins to manipulate and extend with custom events.


ChatRoomRouter

The meat of the Konversi application. This modules provides chat room routing api.

<connection> - use queryParam[reconnection]=Y/N to specify if the connection is a re-connection. This will avoid broadcasting duplicate 'rooms:join' events.

<handshake>: setup socket connection
--> <rooms:join>, <-> <rooms:join> - when default rooms is set
<-> <rooms:handshake>

<rooms:message>: send message to a room by ID
--> <rooms:message> - broadcast event to all sockets in a room
<-> <rooms:error> - If addressing to a room before joining it.

<rooms:join>:
--> <rooms:join>
<-> <rooms:join>

<rooms:leave>:
--> <rooms:leave>
<-> <rooms:leave>


PmRouter

Routes personal messages.

<pm:message>: send a direct personal message --> <pm:message>


Middleware

  • validationRules - Collection of validation rules ready to be used

    • default - {number:id, string:addr, sting:body}
    • noAddress - {null:addr}
    • bodyParser - validates 'body' string as a query string
  • queryParser - maps query params to SocketHandler.queryParams

    • create - creates query params middleware function
    • parser - query params implementations
      • number - maps a query parameter as a number
      • translate - transforms query parameter to a specific value

    e.g :

      var router = new Router('chat');
      var queryParser = queryParser.create({
          [paramName]: queryParser.parser.translate({
      	    "Y": true,
      	    "N": false
      	    //,"undefined": true // makes this parameter optional
      });
      router.use(queryParser);
      
      router.connection(function (socketRouter, next) {
          // http://localhost/socket.io?paramName=Y
          socketRouter.queryParams // {paramName: true}
      });
    

Utils

stack

Flow control utility helper functions, wrapping response stack functions into async callback functions.

  • series(function|function[] : stack, function:callback)
  • conditional(function : condition, function|function[] : trueStack, function|function[] : falseStack)

Run function

This is the entry point of the module and is what invoked when Konversi is started as a global module.

If you rather use this module as an internal dependency make sure you call this function yourself.

License

MIT. Copyright (c) 2015 Dmitry Matveev
See LICENSE

Readme

Keywords

Package Sidebar

Install

npm i konversi

Weekly Downloads

2

Version

1.0.0

License

MIT

Last publish

Collaborators

  • dmitrymatveev