"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.listenRedisEvent = exports.RedisDB = void 0;
const redis_1 = require("redis");
const config_1 = require("@/config");
const log_1 = require("@/utils/log");
const enum_1 = require("@/@types/enum");
const aegis_1 = require("@/utils/aegis");
const base_db_1 = require("../base-db");
const log = new log_1.Logger('redis-model', enum_1.WinstonColor.BrightCyan);
/**
 * 封装 redis 的增删查改接口（注：value 统一存储为 hashmap 格式）
 * 线上环境多机部署时用此模型
 */
class RedisDB extends base_db_1.BaseDB {
    constructor(key) {
        super(key);
        if (!RedisDB.client) {
            RedisDB.init();
        }
    }
    /**
     * 初始化数据库连接
     */
    static async init() {
        try {
            RedisDB.client = createMyClient();
            // ⚠️ Publisher, Subscriber 必须 connect 之后再开始发布订阅，否则会先进入 PubSub mode，不能发送 AUTH 命令
            const timeEnd = aegis_1.timeStart(enum_1.ReportEvent.RedisConnection);
            await RedisDB.client.connect();
            timeEnd();
            RedisDB.isInited = true;
            await Promise.all(RedisDB.opQueue.map(async (op) => await op()));
            RedisDB.opQueue = [];
        }
        catch (e) {
            log.error('connect redis failed: %s', e.stack || e);
        }
    }
    async get(field) {
        return new Promise((resolve) => {
            const op = async () => {
                const hashmap = await RedisDB.client.hGetAll(this.key);
                const item = hashmap[field];
                try {
                    const itemObj = JSON.parse(item);
                    return resolve(itemObj);
                }
                catch (e) {
                    log.error('parse redis hashmap error, key: %s, field: %s, value: %s', this.key, field, item);
                    return resolve(null);
                }
            };
            if (RedisDB.isInited)
                return op();
            RedisDB.opQueue.push(op);
        });
    }
    /**
     * 查询 hashmap 的所有 value
     */
    async getAll() {
        return new Promise((resolve) => {
            const op = async () => {
                const hashmap = await RedisDB.client.hGetAll(this.key);
                const result = Object.values(hashmap)
                    .map((item) => {
                    let itemObj;
                    try {
                        itemObj = JSON.parse(item);
                    }
                    catch (e) {
                        log.error('parse redis hashmap fail, key: %s', item);
                    }
                    return itemObj;
                })
                    .filter((v) => v);
                resolve(result);
            };
            if (RedisDB.isInited)
                return op();
            RedisDB.opQueue.push(op);
        });
    }
    async upsert(field, value) {
        return new Promise((resolve, reject) => {
            const op = async () => {
                let strValue = value;
                if (typeof value !== 'string')
                    strValue = JSON.stringify(value);
                try {
                    await RedisDB.client.hSet(this.key, field, strValue);
                    resolve(null);
                }
                catch (e) {
                    reject(e);
                }
            };
            if (RedisDB.isInited)
                return op();
            RedisDB.opQueue.push(op);
        });
    }
    async delete(field) {
        return new Promise((resolve, reject) => {
            const op = async () => {
                try {
                    await RedisDB.client.hDel(this.key, field);
                    resolve(null);
                }
                catch (e) {
                    reject(e);
                }
            };
            if (RedisDB.isInited)
                return op();
            RedisDB.opQueue.push(op);
        });
    }
}
exports.RedisDB = RedisDB;
RedisDB.isInited = false;
RedisDB.opQueue = [];
const createMyClient = () => {
    const client = redis_1.createClient({ url: config_1.config.redis.url });
    exports.listenRedisEvent(client);
    return client;
};
const listenRedisEvent = (client) => {
    client.on("error" /* Error */, (e) => {
        log.error('redis client error: %s', (e === null || e === void 0 ? void 0 : e.stack) || e);
    });
    client.on("connect" /* Connect */, () => log.info('redis connected'));
    client.on("ready" /* Ready */, () => log.info('redis ready'));
    client.on("end" /* End */, () => log.warn('redis disconnect by quit() or disconnect()'));
    client.on("reconnecting" /* Reconnecting */, () => {
        log.warn('redis reconnecting');
    });
};
exports.listenRedisEvent = listenRedisEvent;
