"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContainerSession = void 0;
const container_session_1 = require("../../constants/container-session");
const error_messages_1 = require("../../constants/error-messages");
const logger_1 = require("../../logger");
const state_manager_interface_1 = require("../../state/state-manager.interface");
const detect_container_1 = require("../../util/detect-container");
const validate_required_1 = require("../../util/validate-required");
const abstract_session_1 = require("../abstract/abstract-session");
const session_definition_1 = require("../session-definition");
const session_interface_1 = require("../session.interface");
const container_session_params_interface_1 = require("./container-session-params.interface");
const transport_http_1 = require("./transport-http");
const transport_mix_1 = require("./transport-mix");
const transport_pipe_1 = require("./transport-pipe");
/**
 * Container sessions are generally used by apps that run within the Workspace application or in the same browser as the Workspace for Web.
 */
class ContainerSession extends abstract_session_1.AbstractSession {
    /** @internal */
    constructor(sessionParams) {
        super();
        this.sessionParams = sessionParams;
        this.rdpUrlRoot = '';
        this.pipeState = { ready: false };
        this.log = logger_1.logger.getLogger('session:container');
        this.log.info('Create session');
        (0, validate_required_1.validateRequired)(sessionParams, ['appKey'], 'ContainerSessionParams');
    }
    static Definition(params) {
        const sessionParams = typeof params === 'string' ? { appKey: params } : params;
        return new session_definition_1.SessionDefinitionImpl(() => new ContainerSession(sessionParams));
    }
    getOverriddenEndpoints() {
        return {};
    }
    get cookieJarSupport() {
        return true;
    }
    async getSocketCreators(api, protocol) {
        await this.checkPipeErrors();
        /**
         * execEnv was added in eapi-4132 in order to connect to df-streaming
         * Delete in future changes related to CSM and df-streaming connection
         */
        const execEnv = await (0, detect_container_1.detectContainer)();
        return [this.transportStrategy.getStreamTransport(api, protocol, execEnv)];
    }
    getStreamLoginParams() {
        return this.transportStrategy.getStreamLoginParams();
    }
    async request(requestParams) {
        await this.checkPipeErrors();
        return this.transportStrategy.request(requestParams);
    }
    async initialize() {
        try {
            this.transportStrategy = await this.createTransport();
            this.rdpUrlRoot = this.transportStrategy.rdpUrlRoot;
            await this.transportStrategy.initialize();
            await this.transportStrategy.authorize(this.getAuthParams());
            this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.EventReceived, this, session_interface_1.SessionEventCode.AuthenticationSucceeded);
        }
        catch (error) {
            this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.EventReceived, this, session_interface_1.SessionEventCode.AuthenticationFailed, error);
            this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.Error, error, this);
            throw error;
        }
    }
    async cleanUp() {
        var _a;
        await super.cleanUp();
        (_a = this.transportStrategy) === null || _a === void 0 ? void 0 : _a.cleanUp();
    }
    getAuthParams() {
        return {
            appKey: this.sessionParams.appKey,
            scope: this.sessionParams.scope || container_session_1.APP_DEFAULT_SCOPE,
        };
    }
    async createTransport() {
        const execEnv = await (0, detect_container_1.detectContainer)();
        const { appKey, bus } = this.sessionParams;
        this.log.debug('Execution env:', execEnv);
        switch (execEnv) {
            case container_session_1.ExecutionContainer.RTK:
            case container_session_1.ExecutionContainer.SXS_WEB:
            case container_session_1.ExecutionContainer.WORKSPACE_SDK:
            case container_session_1.ExecutionContainer.WEB_RW_OR_EIKON:
                return new transport_mix_1.TransportMix({ bus, execEnv, appKey });
            case container_session_1.ExecutionContainer.DESKTOP_RW_1_9:
            case container_session_1.ExecutionContainer.DESKTOP_RW_NON_1_9_OR_EIKON:
                this.checkPipePromise = this.checkPipeAvailableAndSwitch(execEnv);
                return new transport_http_1.TransportHttp({ appKey });
            default: {
                const error = new Error(error_messages_1.ErrorMessages.WRONG_TRANSPORT_TYPE);
                this.log.error(error);
                throw error;
            }
        }
    }
    async checkPipeAvailableAndSwitch(executionEnv) {
        this.log.debug(`Start checking if 'pipe' transport is available`);
        if (this.state === state_manager_interface_1.State.Closed) {
            this.log.debug(`Session is closed. Skip checking 'pipe' transport`);
            return;
        }
        try {
            const busOptions = executionEnv === container_session_1.ExecutionContainer.DESKTOP_RW_1_9 ? { disableStringify: true } : void 0;
            const pipeTransport = new transport_pipe_1.TransportPipe(this.sessionParams.bus, busOptions);
            await Promise.race([this.doSwitch(pipeTransport), this.waitMaxFor(container_session_params_interface_1.PIPE_INIT_WAIT_MAX_TIMEOUT_MS)]);
        }
        catch (error) {
            this.log.debug('Pipe channel:', error);
            this.pipeState.error = error;
        }
    }
    waitMaxFor(timeout) {
        return new Promise((res, rej) => {
            const checkErrorByTimeout = new Error(error_messages_1.ErrorMessages.STREAMING_NOT_READY_OR_UNAVAILABLE);
            setTimeout(() => rej(checkErrorByTimeout), timeout);
        });
    }
    async doSwitch(transport) {
        await transport.initialize();
        this.pipeState.ready = true;
        await transport.authorize(this.getAuthParams());
        await this.switchToPipe(transport);
        this.pipeState.error = undefined;
    }
    async switchToPipe(transport) {
        if (this.state === state_manager_interface_1.State.Closed) {
            this.log.info(`Session is closed. Switching to 'pipe' is canceled`);
            return;
        }
        await this.transportStrategy.cleanUp();
        this.rdpUrlRoot = transport.rdpUrlRoot;
        this.transportStrategy = transport;
        this.log.info(`Switched to 'pipe' transport`);
    }
    async checkPipeErrors() {
        await this.checkPipePromise;
        if (this.pipeState.ready && this.pipeState.error) {
            throw this.pipeState.error;
        }
    }
}
exports.ContainerSession = ContainerSession;
//# sourceMappingURL=data:application/json;base64, 