135 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
'use strict';
 | 
						|
 | 
						|
// hgetall converts its replies to an Object. If the reply is empty, null is returned.
 | 
						|
// These function are only called with internal data and have therefore always the same instanceof X
 | 
						|
function replyToObject (reply) {
 | 
						|
    // The reply might be a string or a buffer if this is called in a transaction (multi)
 | 
						|
    if (reply.length === 0 || !(reply instanceof Array)) {
 | 
						|
        return null;
 | 
						|
    }
 | 
						|
    var obj = {};
 | 
						|
    for (var i = 0; i < reply.length; i += 2) {
 | 
						|
        obj[reply[i].toString('binary')] = reply[i + 1];
 | 
						|
    }
 | 
						|
    return obj;
 | 
						|
}
 | 
						|
 | 
						|
function replyToStrings (reply) {
 | 
						|
    if (reply instanceof Buffer) {
 | 
						|
        return reply.toString();
 | 
						|
    }
 | 
						|
    if (reply instanceof Array) {
 | 
						|
        var res = new Array(reply.length);
 | 
						|
        for (var i = 0; i < reply.length; i++) {
 | 
						|
            // Recusivly call the function as slowlog returns deep nested replies
 | 
						|
            res[i] = replyToStrings(reply[i]);
 | 
						|
        }
 | 
						|
        return res;
 | 
						|
    }
 | 
						|
 | 
						|
    return reply;
 | 
						|
}
 | 
						|
 | 
						|
function print (err, reply) {
 | 
						|
    if (err) {
 | 
						|
        // A error always begins with Error:
 | 
						|
        console.log(err.toString());
 | 
						|
    } else {
 | 
						|
        console.log('Reply: ' + reply);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
var camelCase;
 | 
						|
// Deep clone arbitrary objects with arrays. Can't handle cyclic structures (results in a range error)
 | 
						|
// Any attribute with a non primitive value besides object and array will be passed by reference (e.g. Buffers, Maps, Functions)
 | 
						|
// All capital letters are going to be replaced with a lower case letter and a underscore infront of it
 | 
						|
function clone (obj) {
 | 
						|
    var copy;
 | 
						|
    if (Array.isArray(obj)) {
 | 
						|
        copy = new Array(obj.length);
 | 
						|
        for (var i = 0; i < obj.length; i++) {
 | 
						|
            copy[i] = clone(obj[i]);
 | 
						|
        }
 | 
						|
        return copy;
 | 
						|
    }
 | 
						|
    if (Object.prototype.toString.call(obj) === '[object Object]') {
 | 
						|
        copy = {};
 | 
						|
        var elems = Object.keys(obj);
 | 
						|
        var elem;
 | 
						|
        while (elem = elems.pop()) {
 | 
						|
            if (elem === 'tls') { // special handle tls
 | 
						|
                copy[elem] = obj[elem];
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            // Accept camelCase options and convert them to snake_case
 | 
						|
            var snake_case = elem.replace(/[A-Z][^A-Z]/g, '_$&').toLowerCase();
 | 
						|
            // If camelCase is detected, pass it to the client, so all variables are going to be camelCased
 | 
						|
            // There are no deep nested options objects yet, but let's handle this future proof
 | 
						|
            if (snake_case !== elem.toLowerCase()) {
 | 
						|
                camelCase = true;
 | 
						|
            }
 | 
						|
            copy[snake_case] = clone(obj[elem]);
 | 
						|
        }
 | 
						|
        return copy;
 | 
						|
    }
 | 
						|
    return obj;
 | 
						|
}
 | 
						|
 | 
						|
function convenienceClone (obj) {
 | 
						|
    camelCase = false;
 | 
						|
    obj = clone(obj) || {};
 | 
						|
    if (camelCase) {
 | 
						|
        obj.camel_case = true;
 | 
						|
    }
 | 
						|
    return obj;
 | 
						|
}
 | 
						|
 | 
						|
function callbackOrEmit (self, callback, err, res) {
 | 
						|
    if (callback) {
 | 
						|
        callback(err, res);
 | 
						|
    } else if (err) {
 | 
						|
        self.emit('error', err);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
function replyInOrder (self, callback, err, res, queue) {
 | 
						|
    // If the queue is explicitly passed, use that, otherwise fall back to the offline queue first,
 | 
						|
    // as there might be commands in both queues at the same time
 | 
						|
    var command_obj;
 | 
						|
    /* istanbul ignore if: TODO: Remove this as soon as we test Redis 3.2 on travis */
 | 
						|
    if (queue) {
 | 
						|
        command_obj = queue.peekBack();
 | 
						|
    } else {
 | 
						|
        command_obj = self.offline_queue.peekBack() || self.command_queue.peekBack();
 | 
						|
    }
 | 
						|
    if (!command_obj) {
 | 
						|
        process.nextTick(function () {
 | 
						|
            callbackOrEmit(self, callback, err, res);
 | 
						|
        });
 | 
						|
    } else {
 | 
						|
        var tmp = command_obj.callback;
 | 
						|
        command_obj.callback = tmp ?
 | 
						|
            function (e, r) {
 | 
						|
                tmp(e, r);
 | 
						|
                callbackOrEmit(self, callback, err, res);
 | 
						|
            } :
 | 
						|
            function (e, r) {
 | 
						|
                if (e) {
 | 
						|
                    self.emit('error', e);
 | 
						|
                }
 | 
						|
                callbackOrEmit(self, callback, err, res);
 | 
						|
            };
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
module.exports = {
 | 
						|
    reply_to_strings: replyToStrings,
 | 
						|
    reply_to_object: replyToObject,
 | 
						|
    print: print,
 | 
						|
    err_code: /^([A-Z]+)\s+(.+)$/,
 | 
						|
    monitor_regex: /^[0-9]{10,11}\.[0-9]+ \[[0-9]+ .+\]( ".+?")+$/,
 | 
						|
    clone: convenienceClone,
 | 
						|
    callback_or_emit: callbackOrEmit,
 | 
						|
    reply_in_order: replyInOrder
 | 
						|
};
 |