enricostara/telegram-mt-node

View on GitHub
lib/net/http-connection.js

Summary

Maintainability
A
1 hr
Test Coverage
//     telegram-mt-node
//     Copyright 2014 Enrico Stara 'enrico.stara@gmail.com'
//     Released under the MIT License
//     https://github.com/enricostara/telegram-mt-node

//     HttpConnection class
//
// This class provides a HTTP transport to communicate with `Telegram` using `MTProto` protocol

// Import dependencies
var httpPath = '/apiw1';
var http = require('http');
var util = require('util');
var logger = require('get-log')('net.HttpConnection');

// The constructor accepts optionally an object to specify the connection address as following:
//
//     new HttpConnection({host: "173.240.5.253", port: "443"});
//
// `localhost:80` address is used as default otherwise
function HttpConnection(options) {
    options = options ?
        ({
            protocol: (options.protocol || 'http:'),
            host: (options.host || 'localhost'),
            port: (options.port || '80'),
            path: httpPath,
            withCredentials: false
        }) :
        ({
            path: 'http://localhost:80' + httpPath
        });
    this.options = util._extend({
        localAddress: process.env.LOCAL_ADDRESS
    }, options);
    this._config = JSON.stringify(this.options);
    if (logger.isDebugEnabled()) {
        logger.debug('created with %s', this._config);
    }
}

HttpConnection.prototype.connect = function (callback) {
    if (logger.isDebugEnabled()) {
        logger.debug('connected to %s', this._config);
    }
    this._writeBuffers = [];
    this._writeOffset = 0;
    this._connected = true;
    if (callback) {
        setTimeout(callback, 0);
    }
};

HttpConnection.prototype.isConnected = function () {
    return this._connected;
};

HttpConnection.prototype.write = function (data, callback) {
    this._writeBuffers.push(data);
    this._writeOffset += data.length;
    if (logger.isDebugEnabled()) {
        logger.debug('add buffer(%s) to the write buffer queue, total length %s',
            data.length, this._writeOffset);
    }
    if (callback) {
        setTimeout(callback, 0);
    }
};

HttpConnection.prototype.read = function (callback) {
    var options = util._extend(this.options, {
        method: (this._writeOffset === 0 ? 'GET' : 'POST'),
        responseType: 'arraybuffer'
    });
    this._request = this._createRequest(options, callback);
    this._request.setHeader('Content-Length', this._writeOffset);
    this._request.setHeader('Connection', 'keep-alive');
    this._request.removeHeader('Content-Type');
    this._request.removeHeader('Accept');
    var request = Buffer.concat(this._writeBuffers);
    this._writeBuffers = [];
    this._writeOffset = 0;
    if (logger.isDebugEnabled()) {
        logger.debug('content-length = %s\ncontent-type = %s\naccept = %s\nhost = %s\nconnection = %s\n',
            this._request.getHeader('Content-Length'), this._request.getHeader('Content-Type'), this._request.getHeader('Accept'),
            this._request.getHeader('Host'), this._request.getHeader('Connection'));
        logger.debug('writing request(%s) to %s', request.length, this._config);
    }
    this._request.end(request);
};

HttpConnection.prototype._createRequest = function (options, callback) {
    var request = http.request(options, function (res) {
            if (logger.isDebugEnabled()) {
                logger.debug('reading from %s\nstatus: %s\nheaders: %s',
                    this._config, res.statusCode, JSON.stringify(res.headers));
            }
            var buffers = [];
            var onData = function (data) {
                buffers.push(data);
            }
            res.on('data', onData);
            res.once('end', function () {
                request.removeListener('error', onError);
                res.removeListener('data', onData);
                var data = Buffer.concat(buffers);
                if (res.statusCode === 200) {
                    if (callback) {
                        callback(null, data);
                    }
                } else {
                    if (callback) {
                        callback(data);
                    }
                }
            });
        }.bind(this)
    );
    var onError = function (e) {
        logger.error('Error %s', e.code);
        if (callback) {
            callback(e);
        }
    };
    request.once('error', onError);
    return request;
};

// Call back, nothing else..
HttpConnection.prototype.close = function (callback) {
    if (callback) {
        this._connected = false;
        setTimeout(callback, 0);
    }
};

// Export the class
module.exports = exports = HttpConnection;