# RAI - Request-Answer-Interface

**rai** is a node.js module to easily generate text based command line servers.
When a client sends something to the server, the first word of the line is
treated as a command and the rest of the line as binary payload.

[![Build Status](https://secure.travis-ci.org/andris9/rai.png)](http://travis-ci.org/andris9/rai)

In addition to line based commands, there's also a data mode, to transmit
everygting received. And there's also an option to switch to TLS mode for
secure connections.

This way it is trivial to create SMTP, POP3 or similar servers.

## Installation

    npm install rai
    
## Usage

### Simple server

    var RAIServer = require("rai").RAIServer;
    
    // create a RAIServer on port 1234
    var server = new RAIServer();
    server.listen(1234);
    
    // Start listening for client connections
    server.on("connect", function(client){
    
        // Greet the client
        client.send("Hello!");
        
        // Wait for a command
        client.on("command", function(command, payload){
        
            if(command == "STATUS"){
                client.send("Status is OK!");
            }else if(command == "QUIT"){
                client.send("Goodbye");
                client.end();
            }else{
                client.send("Unknown command");
            }
        
        });
    
    });

Server only emits `'connect'` and `'error'` events, while the client 
objects emit `'timeout'`, `'error'` and `'end'` in addition to data 
related events.

### Starting a server

Server can be started with `new RAIServer([options])` where options is an optional
parameters object with the following properties:

  * **debug** - if set to true print traffic to console
  * **disconnectOnTimeout** - if set to true close the connection on disconnect
  * **secureConnection** - if set to true close the connection on disconnect
  * **credentials** - credentials for secureConnection and STARTTLS
  * **timeout** - timeout in milliseconds for disconnecting the client, defaults to 0 (no timeout)
  
Once the server has been set up, it can start listening for client connections
with `server.listen(port[, hostname][, callback])`. Callback function gets an error
object as a parameter if the listening failed.

    var server = new RAIServer();
    server.listen(25); // start listening for port 25 on "localhost"

### Closing server

Server can be closed with `server.end([callback])` where callback is run when
the server is finally closed.

### Sending data

Data can be sent with `client.send(data)` where `data` is either a String or
a Buffer. `"\r\n"` is automatically appended to the data.

    client.send("Greetings!");

### Forcing connection close

Connections can be ended with `client.end()`

    if(command == "QUIT"){
        client.send("Good bye!");
        client.end();
    }

### TLS mode

TLS can be switched on with `client.startTLS([credentials][, callback])` and the status can
be listened with `'tls'` (emitted when secure connection is established)

`credentials` is an object with strings of pem encoded `key`, `cert` and optionally an
array `ca`. If `credentials` is not supplied, an autogenerated value is used.

    if(command == "STARTTLS"){
        client.startTLS();
    }
    
    client.on("tls", function(){
        console.log("Switched to secure connection");
    });

If `callback` is not set `'tls'` will be emitted on connection upgrade.

### Data mode

Data mode can be turned on with `client.startDataMode([endSequence])` and incoming
chunks can be received with `'data'`. The end of data mode can be detected by
`'ready'`.

`endSequence` is a String for matching the end (entire line) of the data stream.
By default it's `"."` which is suitable for SMTP and POP3.

    if(command == "DATA"){
        client.send("End data with <CR><LF>.<CR><LF>");
        client.startDataMode();
    }

    client.on("data", function(chunk){
        console.log("Data from client:", chunk);
    });
    
    client.on("ready", function(){
        client.send("Data received");
    });

## Testing

There is a possibility to set up a mockup client which sends a batch of commands
one by one to the server and returns the last response and an array of all responses(except the TLS negotiation).

    var runClientMockup = require("rai").runClientMockup;
    
    var cmds = ["EHLO FOOBAR", "STARTTLS", "QUIT"];
    runClientMockup(25, "mail.hot.ee", cmds, function(lastResponse, allResponses){
        console.log("Final:", lastResponse.toString("utf-8").trim());
        console.log("All:", allResponses.map(function(e){
            return e.toString("utf-8").trim()
        }).join(', '));
    });

`runClientMockup` has he following parameters in the following order:

  * **port** - Port number
  * **host** - Hostname to connect to
  * **commands** - Command list (an array) to be sent to server
  * **callback** - Callback function to run on completion
  * **debug** - if set to true log all input/output

Response from the callback function is a Buffer and contains the
last data received from the server and an array of Buffers with all data received from the server.

## License

**MIT**