Source: service/config.js

var consts = require('../consts');
var ERR = consts.ERR;
var RootKey = consts.RootKey;

module.exports = function (service, opts) {
    var mq = service.mq;
    return {

        /**
         * 解析配置值
         * @method config#_parse
         * @param {String} doc 被解析的字符串
         * 成功响应:
         * doc: 结果{value: 值}
         * 错误响应:
         * doc: {
         *  err: 错误码,
         *  msg: 错误信息
         * }
         */
        _parse: function(doc) {
            var self = this;
            try{
                doc = JSON.parse(doc);
                if(doc.expire && doc.time + doc.expire * 1000 < Date.now()){
                    return ERR.config.FA_CONFIG_EXPIRED;
                }else{
                    return doc;
                }
            }catch(e){
                return ERR.config.FA_PARSE_CONFIG;
            }
        },

        /**
         * 字符串化配置值
         * @method config#_stringify
         * @param {Object} [opts={}] 参数
         * @example
         * opts参数:{
         *  value: 配置值(可选, 默认null)
         *  expire: 过期时间, 单位秒, 0代表永不过期(可选, 默认0)
         * }
         * 返回结果字符串
         */
        _stringify: function(opts) {
            var value = opts.value || null;
            var expire = opts.expire || 0;
            var time = Date.now();
            var v = {
                value: value,
                time: time,
                expire: expire
            };
            return JSON.stringify(v);
        },

        /**
         * 设置配置信息
         * @method config#setConfig
         * @param {Object} [opts={}] 参数
         * @example
         * opts参数:{
         *  root: 根(可选)
         *  key: 配置项(必填)
         *  value: 配置值(可选, 默认null)
         *  expire: 过期时间, 单位秒, 0代表永不过期(可选, 默认0)
         * }
         * @param {callback} [cb=function(err,doc){}] 回调
         * @example
         * cb参数格式:
         * 成功响应:
         * doc: 结果(true or false)
         * 错误响应:
         * doc: {
         *  err: 错误码,
         *  msg: 错误信息
         * }
         */
        setConfig: function(opts, cb) {
            opts = opts || {};
            var root = opts.root || RootKey;
            var key = opts.key;
            if(!key){
                return cb(new Error(ERR.FA_PARAMS.msg), ERR.FA_PARAMS);
            }
            mq.hset(root, key, this._stringify(opts), function(err, doc) {
                if (err) {
                    cb(err, ERR.config.FA_SET_CONFIG);
                } else {
                    cb(null, true);
                }
            });
        },

        /**
         * 设置多个配置信息
         * @method config#setConfigs
         * @param {Object} [opts={}] 参数
         * @example
         * opts参数:{
         *  root: 根(可选)
         *  value: 配置对象(可选, 默认{})
         *  expire: 过期时间, 单位秒, 0代表永不过期(可选, 默认0)
         * }
         * @param {callback} [cb=function(err,doc){}] 回调
         * @example
         * cb参数格式:
         * 成功响应:
         * doc: 结果(true or false)
         * 错误响应:
         * doc: {
         *  err: 错误码,
         *  msg: 错误信息
         * }
         */
        setConfigs: function(opts, cb) {
            opts = opts || {};
            var root = opts.root || RootKey;
            var value = opts.value || {};
            var o = {
                root: root,
                expire: opts.expire || 0
            };
            var v = [];
            for(var key in value){
                var o = {
                    value: value[key],
                    expire: opts.expire || 0
                };
                var val = this._stringify(o);
                v.push(key);
                v.push(val);
            }
            mq.client.hmset(root, v, function(err, doc) {
                if (err) {
                    cb(err, ERR.config.FA_SET_CONFIG);
                } else {
                    cb(null, true);
                }
            });
        },

        /**
         * 获取配置信息
         * @method config#getConfig
         * @param {Object} [opts={}] 参数
         * @example
         * opts参数:{
         *  root: 根(可选)
         *  key: 配置项(必填)
         * }
         * @param {callback} [cb=function(err,doc){}] 回调
         * @example
         * cb参数格式:
         * 成功响应:
         * doc: 配置值(基本类型, 对象或者数组)
         * 错误响应:
         * doc: {
         *  err: 错误码,
         *  msg: 错误信息
         * }
         */
        getConfig: function(opts, cb) {
            var self = this;
            opts = opts || {};
            var root = opts.root || RootKey;
            var key = opts.key;
            if(!key){
                return cb(new Error(ERR.FA_PARAMS.msg), ERR.FA_PARAMS);
            }
            mq.hget(root, key, function(err, doc) {
                if (err) {
                    cb(err, ERR.config.FA_GET_CONFIG);
                } else {
                    if(!doc) return cb(null, null);
                    doc = self._parse(doc);
                    if(doc.err){
                        if(doc == ERR.config.FA_CONFIG_EXPIRED){
                            self.delConfig(opts, function(err, doc){});
                        }
                        return cb(new Error(doc.msg), doc);
                    }
                    cb(null, doc.value);
                }
            });
        },

        /**
         * 删除配置信息
         * @method config#delConfig
         * @param {Object} [opts={}] 参数
         * @example
         * opts参数:{
         *  root: 根(可选)
         *  key: 配置项(必填)
         *  all: 是否全部删除(可选)
         * }
         * @param {callback} [cb=function(err,doc){}] 回调
         * @example
         * cb参数格式:
         * 成功响应:
         * doc: 结果(true or false)
         * 错误响应:
         * doc: {
         *  err: 错误码,
         *  msg: 错误信息
         * }
         */
        delConfig: function(opts, cb) {
            opts = opts || {};
            var root = opts.root || RootKey;
            var key = opts.key;
            if(opts.all){
                return this.delRoot(opts, cb);
            }
            if(!key){
                return cb(new Error(ERR.FA_PARAMS.msg), ERR.FA_PARAMS);
            }
            mq.hdel(root, key, function(err, doc) {
                if (err) {
                    cb(err, ERR.config.FA_DEL_CONFIG);
                } else {
                    cb(null, true);
                }
            });
        },

        /**
         * 删除根配置, 所有根下面的配置信息都被删除
         * @method config#delRoot
         * @param {Object} [opts={}] 参数
         * @example
         * opts参数:{
         *  root: 根(可选)
         * }
         * @param {callback} [cb=function(err,doc){}] 回调
         * @example
         * cb参数格式:
         * 成功响应:
         * doc: 结果(true or false)
         * 错误响应:
         * doc: {
         *  err: 错误码,
         *  msg: 错误信息
         * }
         */
        delRoot: function(opts, cb) {
            opts = opts || {};
            var root = opts.root || RootKey;
            mq.del(root, function(err, doc){
                if (err) {
                    cb(err, ERR.config.FA_DEL_CONFIG);
                } else {
                    cb(null, true);
                }
            });
        },

        /**
         * 列出所有配置项
         * @method config#listConfig
         * @param {Object} [opts={}] 参数
         * @example
         * opts参数:{
         *  root: 根(可选)
         *  all: 是否包含值(可选)
         * }
         * @param {callback} [cb=function(err,doc){}] 回调
         * @example
         * cb参数格式:
         * 成功响应:
         * doc: 结果数组或者对象(all=true时)
         * 错误响应:
         * doc: {
         *  err: 错误码,
         *  msg: 错误信息
         * }
         */
        listConfig: function(opts, cb) {
            var self = this;
            opts = opts || {};
            var root = opts.root || RootKey;
            var _cb = function(err, doc) {
                if (err) {
                    cb(err, ERR.config.FA_LIST_CONFIG);
                } else {
                    if(!doc) return cb(null, null);
                    if(opts.all){
                        for(var key in doc){
                            var _doc = self._parse(doc[key]);
                            if(_doc.value){
                                doc[key] = _doc.value;
                            }else{
                                delete doc[key];
                            }
                        }
                    }
                    cb(null, doc);
                }
            };
            if(opts.all){
                mq.hgetall(root, _cb);
            }else{
                mq.hkeys(root, _cb);
            }
        }

    };
};