import { Singleton, Container, Scope, Inject } from "typescript-ioc";
import * as Redis from 'redis'
const Redlock = require('redlock');
const { promisify } = require("util");
let commands = require('redis-commands');
import { Config } from '../config/Config'
import { log4js as logger } from "ms-log4js"

@Singleton
export class RedisUtil {

    private redisClient;
    private redlock;
    private redisCommons = {};

    constructor() {
        const host = Config.getRedisLockHost()
        const port = Config.getRedisLockPort()
        const password = Config.getRedisLockPassword()
        const database = Config.getRedisLockDatabase()
        this.createRedisClient(host, Number(port), password, Number(database))

        this.redlock = new Redlock([this.redisClient], {
            retryCount: 0,//重试次数
            retryDelay: 0//重试间隔
        })
    }

    private createRedisClient(host: string, port: number, password: string = '', database: number = 0) {
        const options = {
            host: host,
            port: port,
            no_ready_check: true
        };
        this.redisClient = Redis.createClient(options);
        if (password && password !== "") {
            this.redisClient.auth(password, function () {
            });
        }
        if (database && database > 0) {
            this.redisClient.select(database, function (err, data) {
                if (err) {
                    logger.error("redis select db error: %s", err);
                }
            });
        }
        this.redisClient.on("error", function (err) {
            logger.error("redis[%s:%s/][db:%s][pwd:%s]连接失败: %s", host, port, database, password, err);
        });
        this.redisClient.on("connect", function () {
            logger.info("redis[%s:%s]连接成功!", host, port);
        });

        //当前版本Redis不支持promise，用 util.promisify 转换
        for (let command of commands.list) {
            this.redisCommons[command] = promisify(this.redisClient[command]).bind(this.redisClient);
        }

    }

    async lock(lockId: string, ms: number = 1000): Promise<any> {
        const resource = `locks:${lockId}`
        const lock = await this.redlock.lock(resource, ms)
        logger.info('加锁成功------' + resource)
        return lock
    }

    async unlock(lock: any): Promise<any> {
        if (lock) {
            await this.redlock.unlock(lock)
            logger.info('锁释放完成...' + lock.resource)
        }
    }

    /**
    * 获取
    * @param key key
    */
    async get(key: string): Promise<any> {
        return await this.redisCommons['get'](key);
    }
}