"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const WS = __importStar(require("ws"));
const events_1 = require("events");
const Utils = __importStar(require("../../util/src"));
class ACSocket extends events_1.EventEmitter {
    constructor() {
        super();
        this.port = 4000;
        //  heartbeat check
        setInterval(() => {
            if (this.server) {
                this.server.clients.forEach((client) => {
                    if (client.isAlive === false) {
                        client.terminate();
                        this.emit('close', { client });
                    }
                });
            }
        }, 10000);
    }
    run() {
        return __awaiter(this, void 0, void 0, function* () {
            this.port = yield Utils.ACUtils.localPort();
            this.server = new WS.Server({
                port: this.port,
                clientTracking: true
            });
            this.server.on('error', (err) => {
                this.emit('server-error', err);
            });
            this.server.on('pong', () => {
            });
            this.server.on('listening', () => {
                this.emit('listening');
            });
            this.server.on('connection', (client, req) => {
                client.isAlive = true;
                if (req.headers.session) {
                    //  client 挂载 session
                    client.session = JSON.parse(decodeURI(typeof req.headers.session === 'string' ? req.headers.session : '{}'));
                }
                this.emit('connection', { client, req });
                client.on('error', (e) => {
                    client.isAlive = false;
                    this.emit('error', { client, e });
                });
                client.on('close', (e) => {
                    client.isAlive = false;
                    this.emit('close', { client, e });
                });
                client.on('pong', () => {
                    client.isAlive = true;
                });
                client.on('message', (message) => {
                    if (!SocketCenter.handle(message)) {
                        this.emit('message', { client, message });
                    }
                });
            });
            return new Promise((resolve, rejects) => {
                resolve();
            });
        });
    }
    close() {
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, rejects) => {
                if (this.server) {
                    this.server.close((err) => {
                        if (err) {
                            rejects(err);
                        }
                        else {
                            resolve();
                        }
                    });
                }
            });
        });
    }
    //  主动断链
    closeClient(token) {
        return __awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, rejects) => {
                let code = -1;
                const clients = this.wsclients();
                clients.forEach(element => {
                    if (token === element.session.token) {
                        element.terminate();
                        this.emit('close', { client: element });
                        code = 0;
                    }
                });
                if (code === -1) {
                    resolve();
                }
                else {
                    rejects();
                }
            });
        });
    }
    broadcase(message) {
        if (this.server) {
            this.server.clients.forEach((element) => {
                if (element.readyState === WS.OPEN) {
                    if (message.token && message.token !== element.session.token) {
                        //  条件广播
                        element.send(message.data);
                    }
                    else {
                        //  全局广播
                        element.send(message.data);
                    }
                }
            });
        }
    }
    send(message) {
        if (this.server) {
            this.server.clients.forEach((element) => {
                if (element.readyState === WS.OPEN) {
                    if (element.session && message.token === element.session.token) {
                        //  指定发送
                        element.send(message.data);
                    }
                }
            });
        }
    }
    //  获取当前已连接的client信息
    clients() {
        const sessions = new Array();
        this.wsclients().forEach(element => {
            const info = element.session;
            if (info) {
                info.readyState = element.readyState;
                sessions.push(info);
            }
        });
        return sessions;
    }
    wsclients() {
        const clients = new Array();
        if (this.server && this.server.clients) {
            this.server.clients.forEach((element) => {
                if (element.isAlive === true) {
                    clients.push(element);
                }
            });
        }
        return clients;
    }
    //  建链信息
    qrvalue() {
        const info = this.connectInfo();
        return `alipays://platformapi/startApp?appId=80000002&action=connect&ip=${info.ip}&port=${info.port}`;
    }
    connectInfo() {
        return {
            port: this.port,
            ip: Utils.ACUtils.localIP()
        };
    }
    //  带有callback能力的请求接口
    request(req, callback) {
        if (callback) {
            const cbid = SocketCenter.register(callback);
            req.id = cbid;
            req.data.id = req.id;
            this.send({
                token: req.token,
                data: JSON.stringify(req.data)
            });
        }
        else {
            this.send({
                token: req.token,
                data: JSON.stringify(req.data)
            });
        }
    }
}
exports.default = ACSocket;
var SocketCenter;
(function (SocketCenter) {
    const store = new Map();
    let index = 0;
    SocketCenter.methods = {
        callback: 'socket.callback'
    };
    function register(callback) {
        const id = `socket_request_${index++}`;
        store.set(id, callback);
        return id;
    }
    SocketCenter.register = register;
    function handle(data) {
        let can = false;
        try {
            const resp = JSON.parse(data);
            if (resp.id) {
                const callback = store.get(resp.id);
                if (callback) {
                    callback(resp);
                    store.delete(resp.id);
                    can = true;
                }
            }
        }
        catch (e) {
        }
        finally {
            return can;
        }
    }
    SocketCenter.handle = handle;
})(SocketCenter = exports.SocketCenter || (exports.SocketCenter = {}));
//# sourceMappingURL=socket.js.map