yog-ral
Version:
node-ral with mcpack and nshead
170 lines (147 loc) • 4.29 kB
JavaScript
/*
* fis
* http://fis.baidu.com/
* 2014/8/14
*/
;
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;