'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var core = require('@cmmn/core');

class EventEmitter {
    constructor() {
        this.listeners = new Map();
    }
    on(event, listener) {
        this.listeners.getOrAdd(event, () => new Set()).add(listener);
    }
    once(event, listener) {
        const onceListener = data => {
            this.off(event, onceListener);
            listener(data);
        };
        this.on(event, onceListener);
    }
    off(event, listener) {
        var _a;
        (_a = this.listeners.get(event)) === null || _a === void 0 ? void 0 : _a.delete(listener);
    }
    emit(event, data) {
        var _a;
        (_a = this.listeners.get(event)) === null || _a === void 0 ? void 0 : _a.forEach(listener => listener(data));
    }
    dispose() {
        this.listeners.clear();
    }
}

class ClientConnection extends EventEmitter {
    constructor(socket, userInfo) {
        super();
        this.socket = socket;
        this.userInfo = userInfo;
        this.decoder = new TextDecoder();
        this.listenPingPong();
        this.socket.on('message', this.onMessage);
        this.socket.on('close', () => this.emit('close'));
    }
    listenPingPong() {
        let pongReceived = true;
        const pingInterval = setInterval(() => {
            if (!pongReceived) {
                this.socket.close();
                clearInterval(pingInterval);
            }
            else {
                pongReceived = false;
                try {
                    this.socket.ping();
                }
                catch (e) {
                    this.socket.close();
                }
            }
        }, pingTimeout);
        this.socket.on('pong', () => {
            pongReceived = true;
        });
    }
    send(message) {
        // const buffer = new Buffer(JSON.stringify(message), 'utf8');
        this.socket.send(JSON.stringify(message));
    }
    onMessage(data) {
        const stringData = typeof data === "string" ? data : this.decoder.decode(data);
        const message = JSON.parse(stringData);
        if (message.type !== 'signal')
            return;
        this.emit('signal', {
            ...message,
            from: this.userInfo
        });
    }
    close() {
        super.dispose();
        this.socket.close();
    }
}
__decorate([
    core.bind,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], ClientConnection.prototype, "onMessage", null);
const pingTimeout = 30000;

class ServerRoom {
    constructor(name) {
        this.name = name;
        this.users = new Map();
    }
    addClient(connection) {
        this.users.forEach(c => c.send({
            type: "announce",
            room: this.name,
            users: [connection.userInfo]
        }));
        connection.send({
            type: "announce",
            room: this.name,
            users: Array.from(this.users.values()).map(x => x.userInfo)
        });
        if (this.users.has(connection.userInfo.user))
            this.users.get(connection.userInfo.user).close();
        this.users.set(connection.userInfo.user, connection);
        connection.on('signal', this.onSignal);
        connection.on('close', () => this.users.delete(connection.userInfo.user));
    }
    onSignal(message) {
        var _a;
        (_a = this.users.get(message.to)) === null || _a === void 0 ? void 0 : _a.send(message);
    }
}
__decorate([
    core.bind,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], ServerRoom.prototype, "onSignal", null);

class TokenParser {
}

exports.YjsWebrtcController = class YjsWebrtcController {
    constructor(parser) {
        this.parser = parser;
        this.rooms = new Map();
        this.subscribedTopics = new Set();
    }
    async handleConnection(socket) {
        socket.on('message', async (msg) => {
            var _a;
            try {
                const registerMessage = await this.GetRegistrationMessage(msg);
                if (!registerMessage)
                    return;
                const userInfo = {
                    user: registerMessage.token.User,
                    accessMode: registerMessage.token.AccessMode
                };
                console.log(userInfo.user);
                const room = this.rooms.getOrAdd(registerMessage.room, name => new ServerRoom(name));
                const connection = new ClientConnection(socket, userInfo);
                room.addClient(connection);
                this.subscribedTopics.add(room);
            }
            catch (e) {
                return e ? ((_a = e.message) !== null && _a !== void 0 ? _a : e) : 'unknown error';
            }
        });
    }
    async GetRegistrationMessage(msg) {
        const messageStr = msg.toString('utf8');
        const message = JSON.parse(messageStr);
        console.log(message);
        if (message.type !== 'register') {
            return;
        }
        const token = await this.parser.Parse(message.info.token);
        if (!token) {
            throw new Error('unauthorized');
        }
        return {
            room: message.info.room,
            token: token
        };
    }
};
exports.YjsWebrtcController = __decorate([
    core.Injectable(),
    __metadata("design:paramtypes", [TokenParser])
], exports.YjsWebrtcController);

exports.TokenParser = TokenParser;
//# sourceMappingURL=server.cjs.map
