UNPKG

yog-ral

Version:

node-ral with mcpack and nshead

170 lines (147 loc) 4.29 kB
/* * fis * http://fis.baidu.com/ * 2014/8/14 */ 'use strict'; var nshead = require('nshead'); var Socket = require('net').Socket; var util = require('util'); var Stream = require('stream').Stream; var Protocol = require('node-ral').Protocol; var logger = require('node-ral').Logger('NsHeadProtocol'); var NSHEAD_LEN = 36; function NsHeadProtocol() { Protocol.call(this); } util.inherits(NsHeadProtocol, Protocol); NsHeadProtocol.prototype.getName = function () { return 'nshead'; }; NsHeadProtocol.prototype.normalizeConfig = NsHeadProtocol.normalizeConfig = function (config) { config.nshead = config.nshead || {}; config.nshead.logID = config.nshead.logID || config.logID; return config; }; NsHeadProtocol.prototype._request = function (config, callback) { var me = this; function writeData(socket, data) { var nh = me._packNshead(config.nshead, data.length); // write head socket.write(Buffer.concat([nh, data])); } logger.trace('request start ' + JSON.stringify(config.server)); var socket = new Socket(); socket.connect({ host: config.server.host, port: config.server.port }); socket.on('connect', function () { var response = new ResponseStream(); response.on('end', function () { socket.end(); }); callback && callback(response); socket.pipe(response); }); var input = new InputStream(socket); if (config.payload) { writeData(socket, config.payload); } else { input.on('data', function (data) { writeData(socket, data); }); } return input; }; NsHeadProtocol.prototype._packNshead = function (config, bodyLen) { var data = { 'id': config.id || 0, 'version': config.version || 0, 'log_id': config.logID, 'magic_num': config.magicNum || 0xfb709394, 'reserved': config.reserved || 0, 'provider': config.provider || 'yog-ral', 'body_len': bodyLen }; return nshead.pack(data); }; NsHeadProtocol.prototype._unpackNshead = function (strNshead) { return nshead.unpack(strNshead); }; function InputStream(socket) { this.writable = true; this.data = null; this.chunks = []; this.socket = socket; var me = this; socket.on('error', function (err) { me.emit('error', err); }); } util.inherits(InputStream, Stream); InputStream.prototype.abort = function () { this.socket.end(); }; InputStream.prototype.write = function (chunk) { //store the data if (!Buffer.isBuffer(chunk)) { chunk = new Buffer(chunk); } this.chunks.push(chunk); }; InputStream.prototype.end = function () { try { var data = Buffer.concat(this.chunks); this.chunks = []; //emit data at once this.emit('data', data); this.emit('end'); } catch (ex) { this.emit('error', ex); } }; function ResponseStream() { this.writable = true; this.data = null; this.complete = false; } util.inherits(ResponseStream, Stream); ResponseStream.prototype.write = function (chunk) { var pack; var nh; if (!Buffer.isBuffer(chunk)) { chunk = new Buffer(chunk); } this.data = !!this.data ? Buffer.concat([this.data, chunk]) : chunk; var data = this.data; if (data.length >= NSHEAD_LEN) { try { nh = nshead.unpack(data.slice(0, NSHEAD_LEN)); this.emit('extras', { headers: nh }); } catch (ex) { logger.trace('response failed ' + ex.message); this.emit('error', ex); } if (data.length >= nh.body_len + NSHEAD_LEN) { pack = data.slice(NSHEAD_LEN, nh.body_len + NSHEAD_LEN); this.complete = true; this.emit('data', pack); this.emit('end', pack); logger.trace('response end'); } } }; ResponseStream.prototype.end = function () { if (this.complete === false) { logger.warning('response failed socket connection closed unexpectedly'); this.emit('error', new Error('socket connection closed unexpectedly')); return; } }; module.exports = NsHeadProtocol;