"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jwt_1 = require("./jwt");
const events = require("events");
const SocketIO = require("socket.io");
const storyboard_1 = require("storyboard");
class HttpEventEmitter extends events.EventEmitter {
    constructor() {
        super();
    }
    createEventThread(event, onListen = () => { }) {
        this.on('listen', (evt) => {
            if (event === evt) {
                onListen();
            }
        });
        return jwt_1.default.sign({
            event
        }, { expiresIn: '1d', subject: 'event' });
    }
    getEventThread(token) {
        return jwt_1.default.verify(token, { subject: 'event' });
    }
    attach(app, auth) {
        this.io = SocketIO(app);
        this.on('client_call', (data) => {
            this.io.emit('client_call', data);
        });
        Object.keys(this.io.nsps).forEach((namespace) => {
            const nsp = this.io.nsps[namespace];
            nsp.on('connect', (socket) => {
                if (!socket.auth) {
                    storyboard_1.mainStory.info('socket', `Removing socket ${socket.id} from ${namespace}`);
                    delete nsp.connected[socket.id];
                }
            });
        });
        this.io.on('server_call', (data) => {
            this.emit('server_call');
        });
        this.io.on('connection', (socket) => {
            storyboard_1.mainStory.info('socket', `Connected to ${socket.handshake.address} via ${socket.handshake.url} [${socket.id}]`);
            socket.on('authenticate', (data) => {
                try {
                    const user = auth.verifySession(data.token);
                    if (user && user !== '') {
                        storyboard_1.mainStory.info('socket', `Socket ${socket.id} authenticated as ${user}`);
                        socket.auth = user;
                        Object.keys(this.io.nsps).forEach((namespace) => {
                            storyboard_1.mainStory.info('socket', `Retablishing socket ${socket.id} for ${namespace}`);
                            const nsp = this.io.nsps[namespace];
                            nsp.connected[socket.id] = nsp.sockets[socket.id];
                        });
                    }
                }
                catch (err) {
                    storyboard_1.mainStory.warn('socket', `Could not verify session [${socket.id}]`, {
                        attach: err
                    });
                    return;
                }
            });
            socket.on('listen', (data) => {
                if (!socket.auth)
                    return;
                storyboard_1.mainStory.debug('socket', `Trying to listen to an event... [${socket.id}]`);
                if (!data.token)
                    return socket.emit('remote_error', { code: 400, message: 'Emitted a listen event without a token' });
                try {
                    const thread = this.getEventThread(data.token);
                    // Transmit the event from server to client
                    this.on(thread.event, (data) => {
                        this.io.emit(thread.event, data);
                    });
                    storyboard_1.mainStory.info('socket', `Listening to event ${thread.event} [${socket.id}]`);
                    // Inform we are watching
                    process.nextTick(() => this.emit('listen', thread.event));
                }
                catch (err) {
                    return socket.emit('remote_error', { code: 403, message: 'Emitted a listen event without a valid token' });
                }
            });
            setTimeout(() => {
                if (!socket.auth) {
                    storyboard_1.mainStory.info('socket', `Disconnecting ${socket.id} because it didn't authenticated under 10s`);
                    socket.disconnect();
                }
            }, 10000);
        });
    }
}
const emitter = new HttpEventEmitter();
exports.default = emitter;
//# sourceMappingURL=http-event.js.map