partner-trustlink.js 6.39 KB
var winston = require('winston');
var request = require('request');
var strftime = require('strftime');
var url = require('url');
var xor = require('base64-xor');
var http = require('http');
var xml = require('xml');
var xml2js = require('xml2js').parseString;
var redis = require('redis');

var max_retry = 0;
var sleep_before_retry = 2000;

var config;
var callbackReport;
var aaa;
var logger;
var options;
var redisClient;

function start(_config, _callbackReport, options) {
    config = _config;
    callbackReport = _callbackReport

    if (options && options.aaa) {
            aaa = options.aaa;
    }

    if (options && options.logger) {
        logger = options.logger;
    } else {
        logger = new winston.Logger({
            transports: [
              new (winston.transports.Console)()
            ]
        });
    }

    createRedisClient();
    createReverseReportServer();
}

function createReverseReportServer() {
    var httpServer = http.createServer(onReverseReport).listen(config.h2h_out.listen_port, function() {
        logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
    });
}

function onReverseReport(req, res) {
    res.end('OK');

    var qs = url.parse(req.url, true).query;
    logger.info('Reverse Report', {url: req.url, qs: qs});
}

function calculateSignature(ts, destination, password) {
    var a = ts + destination.substr(destination.length - 4);
    var b = destination.substr(destination.length - 4).split('').reverse().join('') + password;

    return xor.encode(a,b);
}

function createXmlPayload(task, userid, password) {
    var ts = strftime('%H%M%S', new Date());

    var signature = calculateSignature(ts, task.destination, password);

    var payload = {
        evoucher: [
            {command: 'TOPUP'},
            {product: task.remoteProduct},
            {userid: userid},
            {time: ts},
            {msisdn: task.destination},
            {partner_trxid: task.requestId},
            {signature: signature},
            {trxke: 1},
        ]
    };

    if (logger) {
        logger.verbose('Generate xml payload', {payload: payload});
    }

    return "<?xml version=\"1.0\" ?>\n" + xml(payload);
}

function topupRequestHit(task, retry) {
    if (retry === undefined) {
        retry = max_retry;
    }

    var payload = createXmlPayload(task, config.h2h_out.userid, config.h2h_out.password);

    var partner = url.parse(config.h2h_out.partner);

    var request_options = {
        host: partner.hostname,
        path: partner.path,
        port: partner.port,
        method: "POST",
        headers: {
            'Content-Type': 'text/xml',
            'Content-Length': Buffer.byteLength(payload)
        }
    };

    var buffer = "";

    logger.info('Requesting to partner', {request_options: request_options});

    var req = http.request(request_options, function( res )    {

        logger.verbose('Status code: ' + res.statusCode );
        var buffer = "";
        res.on( "data", function( data ) { buffer = buffer + data; } );
        res.on( "end", function( data ) {
            logger.verbose('Got direct response from partner', {resp: buffer});
            directResponseHandler(buffer, task);
        });

    });

    req.on('error', function(e) {
        logger.warn('problem with request: ' + e.message);
        callbackReport(task.requestId, '68', e.message);
        return;
    });

    logger.verbose('Sending payload to partner', {payload: payload});
    req.write( payload );
    req.end();
}

function directResponseHandler(body, task) {

    logger.info('Got direct response');

    xml2js(body, function (err, result) {
        if (err) {
            logger.warn('Error parsing xml', {body: body});
            callbackReport(task.requestId, '68', buffer);
            return;
        }

        logger.info('Direct response parsed', {result: result});

        var response_code = '68';

        var request_id = task.requestId;
        var status = result.evoucher.result[0].trim();
        var message = result.evoucher.value[0].string[0].trim();

        if (message.indexOf('SUKSES') >= 0) {
            var sn = getSNFromMessage(message);
            message = 'SN=' + sn + '; ' + message;

            response_code = '00';
        }
        else if (message.indexOf('GAGAL') >= 0) {
            response_code = '40';
        }
        else if (message.indexOf('atau Password atau IP  tidak terdaftar') >= 0) {
            response_code = '40';
        }
        else {
            response_code = '68';
        }

        callbackReport(request_id, response_code, message);
    });
}

function getSNFromMessage(message) {
    try {
        var sn_match = message.match(/SN=(\w+)/);
        return sn_match[1].trim();
    }
    catch(e) {
        return;
    }
}

function topupRequest(task, retry) {
    var key = 'DUPCHECK.gw:' + config.globals.gateway_name + '.prod:' + task.remoteProduct + '.dest:' + task.destination + '.date:' + strftime('%Y%m%d', new Date);
    redisClient.get(key, function(err, data) {
        if (err) {
            callbackReport(task.requestId, '40', 'Gagal cek anti transaksi duplikat (redis error)');
            return;
        }

        if (!data) {
            logger.verbose('Belum ada trx dengan tujuan dan denom yang sama pada hari ini. Lanjutkan.');

            redisClient.set(key, JSON.stringify(task));
            redisClient.expire(key, 3600 * 24 * 2);

            topupRequestHit(task, retry);

        } else {

            try {
                var taskOnRedis = JSON.parse(data);
                if (task.requestId == taskOnRedis.requestId) {
                    logger.verbose('Sudah ada trx dengan tujuan dan denom yg sama, requestId jg sama. Lanjutkan.')
                    topupRequestHit(task, retry);
                } else {
                    logger.verbose('Sudah ada trx dengan tujuan dan denom yg sama, requestId tidak sama. Batalkan.')
                    callbackReport(task.requestId, '55', 'Transaksi duplikat')
                }
            }
            catch(errJSONParse) {
                callbackReport(task.requestId, '68', "error parsing json");
            }
        }

    });
}

function createRedisClient() {
    try {
        redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host);
    } catch(err) {
        logger.info("Error creating redis client");
    }
}

exports.start = start;
exports.topupRequest = topupRequest;
exports.calculateSignature = calculateSignature;