"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("../constants");
const types_1 = require("@deepstream/types");
const utils_1 = require("./utils");
/**
 * The MessageProcessor consumes blocks of parsed messages emitted by the
 * ConnectionEndpoint, checks if they are permissioned and - if they
 * are - forwards them.
 */
class MessageProcessor {
    constructor(config, services) {
        this.services = services;
        this.bulkResults = new Map();
        this.onPermissionResponse = this.onPermissionResponse.bind(this);
        this.onBulkPermissionResponse = this.onBulkPermissionResponse.bind(this);
    }
    /**
     * There will only ever be one consumer of forwarded messages. So rather than using
     * events - and their performance overhead - the messageProcessor exposes
     * this method that's expected to be overwritten.
     */
    onAuthenticatedMessage(socketWrapper, message) {
    }
    /**
     * This method is the way the message processor accepts input. It receives arrays
     * of parsed messages, iterates through them and issues permission requests for
     * each individual message
     *
     * @todo The responses from the permission service might arrive in any arbitrary order - order them
     * @todo Handle permission handler timeouts
     */
    process(socketWrapper, parsedMessages) {
        const length = parsedMessages.length;
        for (let i = 0; i < length; i++) {
            const message = parsedMessages[i];
            if (message.topic === constants_1.TOPIC.CONNECTION && message.action === constants_1.CONNECTION_ACTION.PING) {
                // Each connection endpoint is responsible for dealing with ping connections
                continue;
            }
            if (message.names && message.names.length > 0) {
                const uuid = utils_1.getUid();
                if (this.bulkResults.has(uuid)) {
                    this.services.logger.error(types_1.EVENT.NOT_VALID_UUID, `Invalid uuid used twice ${uuid}`, { uuid });
                }
                this.bulkResults.set(uuid, {
                    total: message.names.length,
                    completed: 0
                });
                const l = message.names.length;
                for (let j = 0; j < l; j++) {
                    this.services.permission.canPerformAction(socketWrapper, { ...message, name: message.names[j] }, this.onBulkPermissionResponse, { originalMessage: message, uuid });
                }
                continue;
            }
            this.services.permission.canPerformAction(socketWrapper, message, this.onPermissionResponse, {});
        }
    }
    onBulkPermissionResponse(socketWrapper, message, passItOn, error, result) {
        const bulkResult = this.bulkResults.get(passItOn.uuid);
        if (error !== null || result === false) {
            passItOn.originalMessage.names.splice(passItOn.originalMessage.names.indexOf(passItOn.originalMessage.name), 1);
            this.processInvalidResponse(socketWrapper, message, error, result);
        }
        if (bulkResult.total !== bulkResult.completed + 1) {
            bulkResult.completed = bulkResult.completed + 1;
            return;
        }
        this.bulkResults.delete(passItOn.uuid);
        if (message.names.length > 0) {
            this.onAuthenticatedMessage(socketWrapper, passItOn.originalMessage);
        }
    }
    /**
     * Processes the response that's returned by the permission service.
     */
    onPermissionResponse(socketWrapper, message, passItOn, error, result) {
        if (error !== null || result === false) {
            this.processInvalidResponse(socketWrapper, message, error, result);
        }
        else {
            this.onAuthenticatedMessage(socketWrapper, message);
        }
    }
    processInvalidResponse(socketWrapper, message, error, result) {
        if (error !== null) {
            this.services.logger.warn(constants_1.RECORD_ACTION[constants_1.RECORD_ACTION.MESSAGE_PERMISSION_ERROR], error.toString(), { message });
            const permissionErrorMessage = {
                topic: message.topic,
                action: constants_1.ACTIONS[message.topic].MESSAGE_PERMISSION_ERROR,
                originalAction: message.action,
                name: message.name,
                isError: true
            };
            if (message.correlationId) {
                permissionErrorMessage.correlationId = message.correlationId;
            }
            socketWrapper.sendMessage(permissionErrorMessage);
            return;
        }
        if (result !== true) {
            const permissionDeniedMessage = {
                topic: message.topic,
                action: constants_1.ACTIONS[message.topic].MESSAGE_DENIED,
                originalAction: message.action,
                name: message.name,
                isError: true
            };
            if (message.correlationId) {
                permissionDeniedMessage.correlationId = message.correlationId;
            }
            socketWrapper.sendMessage(permissionDeniedMessage);
            return;
        }
    }
}
exports.default = MessageProcessor;
//# sourceMappingURL=message-processor.js.map