"use strict";
/*
 * Tencent is pleased to support the open source community by making
 * Hippy available.
 *
 * Copyright (C) 2017-2019 THL A29 Limited, a Tencent company.
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.listenRedisEvent = exports.RedisDB = void 0;
const redis_1 = require("redis");
const config_1 = require("@debug-server-next/config");
const log_1 = require("@debug-server-next/utils/log");
const enum_1 = require("@debug-server-next/@types/enum");
const report_1 = require("@debug-server-next/utils/report");
const base_db_1 = require("../base-db");
const log = new log_1.Logger('redis-model', enum_1.WinstonColor.BrightCyan);
/**
 * all data is store as redis hashmap
 */
class RedisDB extends base_db_1.BaseDB {
    /**
     * init redis connection
     */
    static async init() {
        try {
            RedisDB.client = createMyClient();
            const timeEnd = report_1.report.timeStart(enum_1.ReportEvent.RedisConnection);
            await RedisDB.client.connect();
            timeEnd();
            RedisDB.isInited = true;
            await Promise.all(RedisDB.opQueue.map(async ({ op, resolve, reject }) => await op(resolve, reject)));
            RedisDB.opQueue = [];
        }
        catch (e) {
            log.error('connect redis failed: %s', e.stack || e);
        }
    }
    constructor(key) {
        super(key);
        if (!RedisDB.client) {
            RedisDB.init();
        }
    }
    async get(field) {
        return this.queueWrap(async (resolve) => {
            const hashmap = await RedisDB.client.hGetAll(this.key);
            const item = hashmap[field];
            if (!item)
                return resolve(null);
            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);
            }
        });
    }
    async getAll() {
        return this.queueWrap(async (resolve) => {
            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);
        });
    }
    async upsert(field, value) {
        return this.queueWrap(async (resolve, reject) => {
            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);
            }
        });
    }
    async delete(field) {
        return this.queueWrap(async (resolve, reject) => {
            try {
                await RedisDB.client.hDel(this.key, field);
                resolve(null);
            }
            catch (e) {
                reject(e);
            }
        });
    }
    async rPush(value) {
        return this.queueWrap(async (resolve, reject) => {
            try {
                let strValue = value;
                if (typeof value !== 'string')
                    strValue = JSON.stringify(value);
                await RedisDB.client.rPush(this.key, strValue);
                resolve(null);
            }
            catch (e) {
                reject(e);
            }
        });
    }
    async getList() {
        return this.queueWrap(async (resolve, reject) => {
            try {
                const list = await RedisDB.client.lRange(this.key, 0, -1);
                resolve(list || []);
            }
            catch (e) {
                reject(e);
            }
        });
    }
    async clearList() {
        return this.queueWrap(async (resolve, reject) => {
            try {
                // will clear list if start greater than end
                await RedisDB.client.lTrim(this.key, 1, 0);
                resolve(null);
            }
            catch (e) {
                reject(e);
            }
        });
    }
    /**
     * wrap all operate after redis client connected
     */
    async queueWrap(op) {
        return new Promise((resolve, reject) => {
            if (RedisDB.isInited)
                return op(resolve, reject);
            RedisDB.opQueue.push({ op, resolve, reject });
        });
    }
}
exports.RedisDB = RedisDB;
RedisDB.isInited = false;
RedisDB.opQueue = [];
const createMyClient = () => {
    const client = (0, redis_1.createClient)({ url: config_1.config.redis.url });
    (0, exports.listenRedisEvent)(client);
    return client;
};
const listenRedisEvent = (client) => {
    client.on("error" /* RedisClientEvent.Error */, (e) => {
        log.error('redis client error: %s', (e === null || e === void 0 ? void 0 : e.stack) || e);
    });
    client.on("connect" /* RedisClientEvent.Connect */, () => log.verbose('redis connected'));
    client.on("ready" /* RedisClientEvent.Ready */, () => log.verbose('redis ready'));
    client.on("end" /* RedisClientEvent.End */, () => log.verbose('redis disconnect by quit() or disconnect()'));
    client.on("reconnecting" /* RedisClientEvent.Reconnecting */, () => {
        log.warn('redis reconnecting');
    });
};
exports.listenRedisEvent = listenRedisEvent;
