登录
注册
node.js 学习社区
分享一个原创memcache客户端 原来可以插入code的 重新编辑了下

老掉牙的酋长

2014-12-20 10:56



var net = require('net');

exports.connect = function(port, host) {
    return new memcache(port, host);
}

function memcache(port, host) {
    this.conn = null;
    this.port = port || 11211;
    this.host = host || '';
    this.error = ['ERROR', 'NOT_FOUND', 'CLIENT_ERROR', 'SERVER_ERROR'];
    this.crlf = " ";
    this.queue = [];
    this.nextData = '';
    this.init();
}

memcache.prototype = {
    init : function(){
        this.buffer = new Buffer('');
        this.cmd = null;
        this.callback = null;
        this.receiveTimes = 0;
        this.headLength = 0;
        this.bodyLength = 0;
        if (this.nextData.length > 0) this.receive(new Buffer(this.nextData));
    },
    connect : function(callback){
        if (this.conn) return callback.call(this);
        var conn = net.connect(this.port, this.host),
            self = this;
        conn.on('connect', function(){
            self.conn = conn;
            callback.call(self);
        });
        conn.on('data', function(data){
            self.receive(data);
        });
        conn.on('error', function(e){
            console.log(e);
            setTimeout(function(){
                self.connect(callback);
            }, 10);
        });
    },
    fixKey : function(key) {
        return key.substr(0, 250).replace(/\s/g, '_');
    },
    query : function(data, callback, cmd) {
        var idx = data.indexOf(' '),
            cmd = cmd || (idx == -1 ? data : data.substr(0, idx)).toLowerCase();
        this.connect(function(){
            this.queue.push({
                cmd : cmd,
                callback : callback
            });
            this.conn.write(data + this.crlf);
        });
    },
    send : function(cmd, key, value, callback, lifetime, flags) {
        if (typeof(callback) != 'function') {
            lifetime = callback;
            callback = null;
        }
        try {
            val = JSON.stringify(value);
        } catch(e) {
            try {
                val = value.toString();
            } catch(e) {
                val = '';
            }
        }
        var flags = flags || 0,
            lifetime = lifetime || 0,
            buffer = new Buffer(val),
            bufferLength = buffer.length || 0,
            query = [cmd, this.fixKey(key), flags, lifetime, bufferLength];
        this.query(query.join(' ') + this.crlf + val, callback);
    },
    receive : function(data) {
        if (this.receiveTimes == 0) {
            var last = this.queue.shift();
            this.cmd = last.cmd;
            this.callback = last.callback;
        }
        this.buffer = Buffer.concat([this.buffer, data]);
        this.receiveTimes++;
        result = this[this.cmd+'Handler']();
        if (result === null || result === undefined) return;
        try {
            this.callback(result);
        } catch(e) {}
        this.init();
    },
    add : function(key, value, callback, lifetime, flags) {
        this.send('add', key, value, callback, lifetime, flags);
    },
    set : function(key, value, callback, lifetime, flags) {
        this.send('set', key, value, callback, lifetime, flags);
    },
    replace : function(key, value, callback, lifetime, flags) {
        this.send('replace', key, value, callback, lifetime, flags);
    },
    get : function(key, callback) {
        this.query('get '+this.fixKey(key), callback);
    },
    delete : function(key, callback) {
        this.query('delete '+this.fixKey(key), callback);
    },
    flush : function(callback) {
        this.query('flush_all', callback, 'flush');
    },
    stats : function(callback) {
        this.query('stats', callback);
    },
    version : function(callback) {
        this.query('version', callback);
    },
    close : function(){
        var self = this;
        if (this.queue.length == 0) {
            this.conn.end();
            this.conn.destroy();
            this.conn = null;
        } else {
            setTimeout(function(){
                self.close();
            }, 10);
        }
    },
    getLine : function(data, line){
        if (Buffer.isBuffer(data)) data = data.toString();
        var line = line ? parseInt(line) : 0,
            data = data.split(" ");
        return data[line] ? data[line]+" " : false;
    },
    storeHandler : function(){
        var line = this.getLine(this.buffer);
        this.nextData = this.buffer.slice(new Buffer(line).length);
        if (line.toLowerCase().trim() == 'stored') {
            return true;
        } else {
            return false;
        }
    },
    addHandler : function(){
        return this.storeHandler();
    },
    setHandler : function(){
        return this.storeHandler();
    },
    replaceHandler : function(){
        return this.storeHandler();
    },
    getHandler : function(){
        if (this.receiveTimes == 1) {
            //第一次开始接收数据
            var line = this.getLine(this.buffer),
                header = line.split(/\s+/g);
            //不存在此KEY
            if (header[0].toLowerCase() == 'end') return false;
            this.headLength = new Buffer(line).length;
            this.bodyLength = parseInt(header[3]);
        }
            //实际buffer长度
        var bufferLength = this.buffer.length,
            //buffer应有的长度
            dataLength = this.headLength + this.bodyLength + 'END'.length + 2 * this.crlf.length;
        if (bufferLength >= dataLength) {
            var body = this.buffer.slice(this.headLength, this.headLength + this.bodyLength).toString();
            this.nextData = this.buffer.slice(dataLength).toString();
            try {
                return JSON.parse(body);
            } catch(e) {
                return body;
            }
        }
        return null;
    },
    deleteHandler : function(){
        var line = this.getLine(this.buffer);
        this.nextData = this.buffer.slice(new Buffer(line).length);
        if (line.toLowerCase().trim() == 'deleted') {
            return true;
        } else {
            return false;
        }
    },
    flushHandler : function(){
        var line = this.getLine(this.buffer);
        this.nextData = this.buffer.slice(new Buffer(line).length);
        if (line.toLowerCase().trim() == 'ok') {
            return true;
        } else {
            return false;
        }
    },
    statsHandler : function(){
        var buffer = this.buffer.toString(),
            idx = buffer.indexOf('END');
        if (idx != -1) {
            lines = buffer.trim().split(" ");
            var stats = {};
            for(var i=0; i<lines.length-1; i++) {
                var line = lines[i].trim().split(/\s+/g);
                stats[line[1]] = line[2];
            }
            this.nextData = new Buffer(buffer.substr(idx + 'END'.length + this.crlf.length));
            return stats;
        }
        return null;
    },
    versionHandler : function(){
        var line = this.getLine(this.buffer),
            header = line.split(/\s+/);
        this.nextData = this.buffer.slice(new Buffer(line).length);
        return header[1];
    }
}

原文引自:http://cnodejs.org/topic/50cac152637ffa41555a7367

回复 · 0

发表回复

你可以在回复中 @ 其他人