<repo_name>irineu/eight-protocol<file_sep>/examples/echo/echoServer.js
////////////////////////////////////////
//IT WILL NOT WORK WITH TELNET CLIENT!!!
////////////////////////////////////////

import constants from "../helpers/constants.js";
import protocol from "../../index.js";

var server =  new protocol.server(constants.port);

server.on('server_listening', function(){
	console.log("Server is up! Now waiting for connections");
});

server.on('client_connected', function(socketClient){
	console.log("NEW CLIENT CONNECTED! \t id:"+socketClient.id+" origin:"+socketClient.address().address);
});

server.on('client_close', function(socketClient){
	console.log("CLIENT DISCONNECTED! \t id:"+socketClient.id);
});

server.on("data", function(socketClient, header, dataBuffer){
	console.log("MESSAGE RECEIVED! \t id:"+socketClient.id+" message:"+dataBuffer.toString());
});<file_sep>/examples/chat/client.js
import protocol from "../../index.js";
import readline from 'readline';

var client = new protocol.client("0.0.0.0", 7890);


//this is a way for easily read lines, see more at: https://nodejs.org/api/readline.html
let rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

client.on("client_connected", function(socket){
    console.log("Connected on server!");
});

client.on("client_end", function(socket){
	//exit when lost connectio with the server
    process.exit(0);
});


client.on("data", function(socket, header, dataBuffer){
    
    //Based in a property (transaction) on header, we can handle de message:
    switch(header.transaction){
    	case "ID":
    		rl.question('Type your name: ', (answer) => {
				protocol.send(socket, {transaction : "ID", date : Date.now()}, answer);
			});
    	break;
    	case "WELCOME":
    		//start asking for messages to send
    		recursiveInput();
    	break;
    	case "MESSAGE":
    		//print a message
    		console.log(dataBuffer.toString());
    	break;
    	case "ERROR":
    		console.log("SERVER ERROR: " +dataBuffer.toString());
    		process.exit(1);
    	break;
    	default:
    		console.log("Unrecognized transaction "+ header.transaction);
    	break;
    }
});

function recursiveInput(){
	rl.question('', (answer) => {
		if(answer)
			protocol.send(client.socket, {transaction : "MESSAGE", date : Date.now()}, answer);
		recursiveInput();
	});
}<file_sep>/README.md
# eight-protocol [![Build Status](https://travis-ci.org/irineu/eight-protocol.svg?branch=master)](https://travis-ci.org/irineu/eight-protocol)
NodeJS socket communication lib over a protocol with 8 bytes descriptor 

### Deprecation disclaimer:
This project will not be longer updated. Hachi NIO Protocol works like the 8-protocol but will have much more features. Please check: [https://github.com/irineu/hachi-nio-js](https://github.com/irineu/hachi-nio-js)

## Objective
When you test a simple socket communication, in the more of times everything works fine, but when your project grow up, after publish and test with remote and bad connections, you will get some problems with truncated messages or messages with extra data (part of the next message). It is normal. You will need create a protocol to handle that situation, maybe implement a header or a terminator (bad ideia), maybe you are already frustated with that notice.

The eight protocol is an implementation plug-and-play of a transparent protocol for handle those situations for you, and the most important: it does not change your code too much.

The message transfered is distributed in two sections:
##### Header
A Key/Value object to identify the message (like: transaction, id, token, type, etc...) like an HTTP header. It will be transformed into a JSON.
##### Body
Binary Data, you can pass anything here (Strings, Serialized Objects, Images, Files, etc...) you can use the header do describe the content of the message.

## Quick Start

##### Server
```javascript
var protocol = require("eight-protocol");
var server =  new protocol.server(7890);

server.on('server_listening', function(){
	console.log("Server ir up! Now waiting for connections");
});

server.on('client_connected', function(socketClient){
	console.log("NEW CLIENT CONNECTED!");
});

server.on("data", function(socketClient, header, dataBuffer){
	console.log("MESSAGE RECEIVED!",header,dataBuffer.toString());
});

server.on('client_close', function(socketClient){
	console.log("CLIENT DISCONNECTED!");
});
```

##### Client
```javascript
var protocol = require("eight-protocol");
var client = new protocol.client("0.0.0.0", 7890);

client.on("client_connected", function(socket){
	console.log("Connected on the server");
	//Send message
	protocol.send(socket, {transaction : "GREETINGS"}, "Hello World!");
})
```

## API

`protocol.send(socket, header, buffer, [callback]);`
Send a message for the given socket.
* Socket - The nodejs socket from the new connection callback
* Header - Key/Value object, it will be converted internally to a JSON String
* Buffer - Your data, must be a buffer or String
* Callback (optional) - A callback function with and error parameter if it have

### Server
`new protocol.server(port, [debug]);`
Instantiate a new server and try to start listen imediatly
* port - must be an integer, it will be the respective TCP port to listen
* debug (optional) - must be a boolean, if `true`, the lib will print some informations like message size, incoming bytes, outcoming bytes, etc.
 
##### Events

| Event name       | Description                  |
|------------------|---------------------------------------------------------------------------------------------------------------|
| client_connected | callback(clientSocket : Socket) - When a new client connection is established on the server                   |
| client_close     | callback(clientSocket : Socket, hadError : Boolean)When a client disconnect from the server                   |
| client_end       | callback(clientSocket : Socket) - When a client connection ends                                               |
| client_timeout   | callback(clientSocket : Socket) - When a client timeout                                                       |
| client_error     | callback(clientSocket : Socket, error : Object) - When client socket gives an error                           |
| data             | callback(clientSocket : Socket, header : Object , dataBuffer : Buffer) - When receive a message from a client |
| server_error     | callback(error : Object) - When the server gives an error                                                     |
| server_listening | callback() - When the server start listening                                                                  |

### Client

`new protocol.client(address, port, timeout, debug)`

Instantiate a new client and try connect imediatly

* Address - Must me and string, should be the remote ip address
* port - must be an integer, it will be the respective TCP port to listen
* timeout (optional) - must be an integer, will set the socket timeout (see more at https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback)
* debug (optional) - must be a boolean, if true, the lib will print some informations like message size, incoming bytes, outcoming bytes, etc.

##### Events

| Event name       | Description                                                                                                   |
|------------------|---------------------------------------------------------------------------------------------------------------|
| client_connected | callback(clientSocket : Socket) - When connection is established on the server                                |
| client_close     | callback(clientSocket : Socket, hadError : Boolean) When disconnect from the server                           |
| client_end       | callback(clientSocket : Socket) - When connection ends                                                        |
| client_timeout   | callback(clientSocket : Socket) - When connection timedout                                                    |
| client_error     | callback(clientSocket : Socket, error : Object) - When client socket gives an error                           |
| data             | callback(clientSocket : Socket, header : Object , dataBuffer : Buffer) - When receive a message from a Server |
<file_sep>/test/test.js
var assert = require('assert');
var protocol = require('./../index');

describe("Client/Server", function(){
	var server = {
		instance : null,
		clients : []
	}

	var client;
	var serverPort = 7890;

	describe('#server:listen()', function() {
		it('should start server', function(done) {
			server.instance = new protocol.server(serverPort, false);
			server.instance.once('server_listening', function(){
				done();
			});
		});
	});

	describe('#client:connect()', function() {
		it('should connect on server', function(done) {
			client = new protocol.client("0.0.0.0", serverPort);

			server.instance.once("client_connected", function(socket){
				server.clients.push(socket);
			})

			client.once('client_connected', function(socket){
			   done();
			});
		});
	});

	describe('#client:send/server:recv()', function() {
		it('should send a message for the server', function(done) {

			var _header = {key1: "put", key2: "any", key3: "data"};
			var _data  = "It will be a binary data client";

			server.instance.once("data", function(socket, header, dataBuffer){
				assert.equal(dataBuffer,	_data);
				assert.equal(header.key1,	_header.key1);
				assert.equal(header.key2,	_header.key2);
				done();
			})

			protocol.send(client.socket,_header,_data);
		});
	});

	describe('#client:recv/server:send()', function() {
		it('should receive a message from the server', function(done) {

			var _header = {key1: "put 1", key2: "any 2", key3: "data 3"};
			var _data  = "It will be a binary data from server";

			client.once("data",  function(socket, header, dataBuffer){
				assert.equal(dataBuffer,	_data);
				assert.equal(header.key1,	_header.key1);
				assert.equal(header.key2,	_header.key2);assert.equal(dataBuffer,_data);
				done();
			});

			protocol.send(server.clients[0],_header,_data);
		});
	});

	describe('#server:onDisconnect()', function() {
		it('should reconize when a client disconnect', function(done) {

			var _header = {key1: "put 1", key2: "any 2", key3: "data 3"};
			var _data  = "It will be a binary data from server";

			server.instance.once("client_close",  function(socket, header, dataBuffer){
				assert.equal(server.clients[0].id,	socket.id);
			});

			server.instance.once("client_end",  function(socket, header, dataBuffer){
				assert.equal(server.clients[0].id,	socket.id);
				done();
			});

			client.socket.end();
		});
	});

	describe('#client:onDisconnect()', function() {
		it('should reconize when the server disconnect a client', function(done) {
			this.timeout(1000);
			client = new protocol.client("0.0.0.0", serverPort);

			server.instance.once("client_connected", function(socket){
				server.clients.push(socket);

				setTimeout(function(){
					socket.end();
				},200);
			})

			client.once('client_connected', function(socket){
				client.once("client_end", function(){
					done();
				});
			});
		});
	});

	describe('#server:onDisconnect()', function() {
		it('should reconize when a client disconnect from the server', function(done) {
			this.timeout(5000);

			server.instance.once("client_connected", function(socket){
				var s = socket;
				server.instance.once("client_end", function(socket){
					assert.equal(socket.id, s.id);
					done();
				});
			});

			client = new protocol.client("0.0.0.0", serverPort);
			client.once('client_connected', function(socket){
				
				setTimeout(function(){
					socket.end();
				},200);
				
			});
		});
	});

});
