UNPKG

zoodubbo

Version:

A Javascript module for Node.js to connect Dubbo service by node-zookeeper-client.

364 lines (326 loc) 8.38 kB
/** * Created by Corey600 on 2016/6/24. */ 'use strict'; // require thirdpart modules var debug = require('debug'); var hessian = require('hessian.js'); var Buffer = require('safe-buffer').Buffer; // require custom modules var response = require('./status'); // print debug info var info = debug('zoodubbo:info'); /** * header length. * * @type {number} */ var HEADER_LENGTH = 16; /** * magic header. * * @type {number} */ var MAGIC = 0xdabb; /** * high 8bit of magic header. * * @type {number} */ var MAGIC_HIGH = MAGIC >> 8; /** * low 8bit of magic header. * * @type {number} */ var MAGIC_LOW = MAGIC & 0x00ff; /** * message flag. * * @type {number} */ var FLAG_REQUEST = 0x80; var FLAG_TWOWAY = 0x40; var FLAG_EVENT = 0x20; /** * serialization protocol flag mask. * * @type {number} */ var SERIALIZATION_MASK = 0x1f; /** * dubbo 传输协议体 body 的最大长度 * 协议允许的最大长度为 2^32-1 = 4294967296 * 建议的最大长度为 100K = 100 * 1024 * 8 = 819200 * * @type {number} */ var MAX_LENGTH = 819200; /** * 基础类型定义 * * @type {{ * boolean: string, * int: string, * short: string, * long: string, * double: string, * float: string * }} */ var typeRef = { boolean: 'Z', int: 'I', short: 'S', long: 'J', double: 'D', float: 'F' }; /** * Constructor of Codec. * * @returns {Invoker} * @constructor */ function Codec() { this._chunks = []; this._heap = null; this._bl = 0; } /** * 以 dubbo传输协议 包装请求数据 * 协议格式 <header><bodydata> * 传输协议参考文档: * http://blog.csdn.net/quhongwei_zhanqiu/article/details/41702829 * http://dubbo.io/dubbo_protocol_header.jpg-version=1&modificationDate=1335251744000.jpg * * @param {Invoker} invoker * @param {Object} provider * @param {String} method * @param {Array} args * @returns {Buffer} * @public */ Codec.prototype.encodeRequest = function (invoker, provider, method, args) { var body = this._buildBody(invoker, provider, method, args); var head = this._buildHead(body.length); return Buffer.concat([head, body]); }; /** * 清楚所有添加的数据块 * * @public */ Codec.prototype.clearChunk = function () { this._chunks = []; }; /** * 添加一个数据块至末尾 * * @param chunk * @returns {boolean} */ Codec.prototype.pushChunk = function (chunk) { var self = this; var arr; if (!self._chunks.length) { arr = Array.prototype.slice.call(chunk.slice(0, HEADER_LENGTH)); self._bl = self._parseLength(arr); } self._chunks.push(chunk); self._heap = Buffer.concat(self._chunks); return (self._heap.length >= self._bl); }; /** * 解码返回数据 * * @param {Function} cb * @returns {*} */ Codec.prototype.decodeResponse = function (cb) { return this._parseBody(this._heap, cb); }; /** * 编码传输协议头 <header> * 协议头 定长 16个字节(128位) * 0 - 1B dubbo协议魔数(short) 固定为 0xda 0xbb * 2 - 2B 消息标志位 * 3 - 3B 状态位 * 4 -11B 设置消息的id long类型 * 12 -15B 设置消息体body长度 int类型 * ----------------------------------------------------------------------------------------------- * | Bit offset | 0-7 | 8-15 | 16-20 | 21 | 22 | 23 | 24-31 | * ----------------------------------------------------------------------------------------------- * | 0 | Magic High | Magic Low | Serialization id | event | Two way | Req/res | status | * ----------------------------------------------------------------------------------------------- * | 32-95 | id (long) | * ----------------------------------------------------------------------------------------------- * | 96-127 | data length | * ----------------------------------------------------------------------------------------------- * * @param {Number} length 长度 * @returns {SafeBuffer} * @private */ Codec.prototype._buildHead = function (length) { var len = length; var head = [0xda, 0xbb, 0xc2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; var i = 15; if (len > MAX_LENGTH) { throw new Error('Data length too large: ' + len + ', max payload: ' + MAX_LENGTH); } while (256 <= len) { head.splice(i, 1, len % 256); i -= 1; len >>= 8; } head.splice(i, 1, len); return new Buffer(head); }; /** * 序列化传输协议体 <bodydata> * 1. dubbo的版本信息 * 2. 服务接口名 * 3. 服务的版本号 * 4. 调服务的方法名 * 5. 调服务的方法的参数描述符 * 6. 遍历传输的参数值逐个序列化 * 7. 将整个附属信息map对象attachments序列化 * * @param {Invoker} invoker * @param {Object} provider * @param {String} method * @param {Array} args * @returns {Buffer} * @private */ Codec.prototype._buildBody = function (invoker, provider, method, args) { var encoder = new hessian.EncoderV2(); var path = invoker._path; var dubbo = invoker._dubbo || provider.dubbo; var version = invoker._version || provider.version; var timeout = (invoker._timeout || provider['default.timeout'] || '60000') + ''; encoder.write(dubbo); encoder.write(path); encoder.write(version); encoder.write(method); var index; var len = args.length; // 调服务的方法的参数描述符 var type; var _paramTypes = ''; if (args && len) { for (index = 0; index < len; index += 1) { type = args[index].$class; _paramTypes += type && ~type.indexOf('.') ? 'L' + type.replace(/\./gi, '/') + ';' : typeRef[type]; } } encoder.write(_paramTypes); // 遍历传输的参数值逐个序列化 if (args && len) { for (index = 0; index < len; index += 1) { encoder.write(args[index]); } } // 将整个附属信息map对象attachments序列化 var _attchments = { $class: 'java.util.HashMap', $: { path: path, interface: path, timeout: timeout, version: version } }; encoder.write(_attchments); var byteBuffer = encoder.byteBuffer; byteBuffer = byteBuffer.get(0, encoder.byteBuffer._offset); return byteBuffer; }; /** * 解码协议头,获取数据体长度 * * @param {Array} head * @returns {number} * @private */ Codec.prototype._parseLength = function (head) { var length = HEADER_LENGTH; var ans = 1; // head的最后4B数据表示长度, 16581375 = 255^3 while (16581375 >= ans) { var item = head.pop(); if (0 < item) { length += item * ans; } ans *= 256; } return length; }; /** * 解码协议体 * * @param {Buffer} heap * @param {Function} cb * @returns {*} * @private */ Codec.prototype._parseBody = function (heap, cb) { // 检验魔数 if (heap[0] !== MAGIC_HIGH || heap[1] !== MAGIC_LOW) { return cb(new Error('Magic header is wrong!')); } // 检查序列化协议 if (2 !== (heap[2] & SERIALIZATION_MASK)) { // hessian2 的协议ID为 2 return cb(new Error('Unknown serialization protocol! Only hessian2 is supported.')); } // 打印标志位 info('FLAG_REQUEST:' + (heap[2] & FLAG_REQUEST) + ', FLAG_TWOWAY:' + (heap[2] & FLAG_TWOWAY) + ', FLAG_EVENT:' + (heap[2] & FLAG_EVENT)); if (heap[3] !== response.CODE.OK) { // error捕获 return cb(new Error( decodeURIComponent(heap.slice(HEADER_LENGTH + 2, heap.length - 1).toString()) )); } var buf; var flag; var ret; try { // 反序列化 buf = new hessian.DecoderV2(heap.slice(HEADER_LENGTH, heap.length)); // 结果标志位为数据段第一个字节,为 0x90 0x91 0x92其中之一 // 实际为hessian协议的简化整数表示,反序列化后为: 0 1 2 // RESPONSE_WITH_EXCEPTION = 0; // RESPONSE_VALUE = 1; // RESPONSE_NULL_VALUE = 2; flag = buf.readInt(); } catch (err) { return cb(err); } info('flag: ' + flag); if (2 === flag) { // 无返回值 return cb(false); } try { ret = buf.read(); } catch (err) { return cb(err); } if (ret instanceof Error) { return cb(ret); } if (0 === flag) { return cb(new Error(ret)); } return cb(false, ret); }; /** * Expose `Codec`. * * @type {Codec} */ module.exports = Codec;