index.js 2.72 KB
/**
 * zookeeper client
 * @author: xuqi<qi.xu@yoho.cn>
 * @date: 2016/10/12
 */

'use strict';

const zookeeper = require('node-zookeeper-client');
const _ = require('lodash');

const ONE_MONTH = 60 * 60 * 24 * 30;

const getter = (client, path, memory, cache) => {
    client.getData(
        path,
        event => {
            getter(client, path, memory, cache);
        },
        (err, data, stat) => {
            if (err) {
                console.log('Got path %s data error', path);
                return;
            }

            let keys = path.replace(/^\/(pc|wap)\//, '').split('/');

            if (keys.indexOf('json') > -1) { // /pc|wap/json/... is JSON string
                try {
                    memory && _.set(memory, keys, JSON.parse(data.toString('utf8')));
                } catch (e) {
                    console.log('%s catch: %s', e.message, path, data.toString('utf8'));
                }
            } else {
                memory && _.set(memory, keys, data.toString('utf8') === 'true' ? true : false);
            }

            if (cache) {
                cache.set('zookeeper:' + path, data.toString('utf8'), ONE_MONTH).catch(console.error);
                console.log('cache %s data: %s', 'zookeeper:' + path, data.toString('utf8'));
            }

            console.log('%s data: %s', path, data.toString('utf8'));
        }
    )
};

// 遍历node path
const walkPath = (client, path, memory, cache) => {
    client.getChildren(
        path,
        (err, children, stat) => {
            if (err) {
                console.log('Failed to list children of %s due to: %s', path, err);
                return;
            }

            if (children.length === 0) {
                // watch the path
                getter(client, path, memory, cache);
            } else {
                _.forEach(children, child => {
                    walkPath(client, `${path}/${child}`, memory, cache);
                });
            }
        }
    )
};

module.exports = (server, host, memory, cache, extra = {}) => {
    let client = zookeeper.createClient(server, {
        spinDelay: 1000,
        retries: 10
    });

    client.state = Symbol();

    host = (host && _.indexOf(['pc', 'wap'], host) >= 0) ? host : 'wap';

    client.on('connected', () => {
        walkPath(client, `/${host}`, memory, cache)
    });

    client.on('state', state => {
        if (!extra || !extra.onerror) {
            return;
        }

        switch (state) {
            case zookeeper.State.DISCONNECTED:
            case zookeeper.State.EXPIRED:
            case zookeeper.State.AUTH_FAILED:
                extra.onerror({...state});
                break;
            default:
                return;
        }
    });

    client.connect();
};