"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DesktopSession = void 0;
const detect_browser_1 = require("detect-browser");
const isString_1 = __importDefault(require("lodash/isString"));
const url_1 = require("url");
const url_join_1 = __importDefault(require("url-join"));
const common_1 = require("@refinitiv-data/common");
const config_1 = require("../../config");
const handshake_1 = require("../../handshake/handshake");
const logger_1 = require("../../logger");
const merge_request_params_1 = require("../../util/merge-request-params");
const validate_required_1 = require("../../util/validate-required");
const webSocket_helper_1 = require("../../util/webSocket-helper");
const abstract_session_1 = require("../abstract/abstract-session");
const session_definition_1 = require("../session-definition");
const session_interface_1 = require("../session.interface");
const build_desktop_session_login_data_1 = require("./build-desktop-session-login-data");
const desktop_session_params_interface_1 = require("./desktop-session-params.interface");
/**
 * Desktop sessions are used to connect applications to the data platform through the Workspace desktop application.
 */
class DesktopSession extends abstract_session_1.AbstractSession {
    /** @internal */
    constructor(sessionParams) {
        super();
        this.sessionParams = sessionParams;
        this.socketCreatorsMap = new Map();
        this.log = logger_1.logger.getLogger('session:desktop');
        this.log.info('Create session');
        this.log.debug('Session options:', sessionParams);
        (0, validate_required_1.validateRequired)(sessionParams, ['appKey'], 'DesktopSessionParams');
        this.port = sessionParams.port || this.defaultPort;
        this.log.debug('Port to be used by session:', this.port);
    }
    static Definition(params) {
        return new session_definition_1.SessionDefinitionImpl(() => new DesktopSession((0, isString_1.default)(params) ? { appKey: params } : params));
    }
    get rdpUrlRoot() {
        return config_1.config.get('sessions').desktop['default-session']['platform-paths'].rdp;
    }
    get defaultPort() {
        return Number(new URL(config_1.config.get('sessions').desktop['default-session']['base-url']).port);
    }
    get baseUrl() {
        const { hostname, protocol, pathname } = new URL(config_1.config.get('sessions').desktop['default-session']['base-url']);
        return (0, url_1.format)({ protocol, hostname, port: this.port, pathname });
    }
    get udfUrlRoot() {
        return config_1.config.get('sessions').desktop['default-session']['platform-paths'].udf;
    }
    get tsiUrlRoot() {
        return config_1.config.get('sessions').desktop['default-session']['platform-paths'].tsi;
    }
    get handshakeEndpoint() {
        return config_1.config.get('sessions').desktop['default-session']['handshake-url'];
    }
    get uuid() {
        return process.env.REFINITIV_AAA_USER_ID;
    }
    /**
     * This method is related to the endpoints overriding in the configuration file.
     * 'sessions' section in the config file contains different types of sessions,
     * and each session might have a specific block to override common endpoint(s)
     * api/url/path for this particular session.
     * Overridden endpoint has a higher priority then common one.
     *
     * An empty object is returned if there are no overridden endpoints
     */
    getOverriddenEndpoints() {
        return config_1.config.get('sessions').desktop['default-session'].apis || {};
    }
    /**
     * Enable cookies support
     */
    get cookieJarSupport() {
        var _a;
        return ((_a = (0, detect_browser_1.detect)()) === null || _a === void 0 ? void 0 : _a.type) === 'node';
    }
    /**
     * Send a request in order to validate if proxy is running and appKey is valid
     */
    async initialize() {
        try {
            const handshakePayload = (0, handshake_1.getHandshakePayload)(this.sessionParams.appKey, this.uuid);
            const { data: { access_token, token_type }, } = await this.request({
                method: common_1.HttpMethod.POST,
                url: this.handshakeEndpoint,
                body: handshakePayload,
            });
            this.accessToken = access_token;
            this.tokenType = token_type[0].toUpperCase() + token_type.slice(1);
            this.emitAuthenticationSuccess();
        }
        catch (err) {
            const { status } = err.response || {};
            if (status === common_1.HttpCode.FORBIDDEN || status === common_1.HttpCode.NOT_FOUND) {
                await this.request({ method: common_1.HttpMethod.POST, url: this.udfUrlRoot });
                this.emitAuthenticationSuccess();
                return;
            }
            this.emitAuthenticationFailed(err);
            throw err;
        }
    }
    async request(sessionRequestParams) {
        const headers = { [desktop_session_params_interface_1.APPLICATION_ID_HEADER]: this.sessionParams.appKey };
        if (this.accessToken) {
            headers[desktop_session_params_interface_1.AUTHORIZATION_HEADER] = `${this.tokenType} ${this.accessToken}`;
        }
        const requestConfig = (0, merge_request_params_1.mergeRequestParams)(this.baseUrl, sessionRequestParams, headers);
        return this.httpClient.request(requestConfig);
    }
    async getSocketCreators(api, protocolName) {
        if (protocolName !== 'tr_json2' && protocolName !== 'rdp_streaming') {
            throw new Error(`"${protocolName}" streaming connection type is not supported!`);
        }
        if (!this.socketCreatorsMap.has(api)) {
            const socketCreators = await this.requestWebSocketList(api, protocolName);
            this.socketCreatorsMap.set(api, socketCreators);
        }
        return this.socketCreatorsMap.get(api);
    }
    getStreamLoginParams() {
        const streamAuthParams = {
            appKey: this.sessionParams.appKey,
            accessToken: this.accessToken,
            tokenType: this.tokenType,
        };
        return (0, build_desktop_session_login_data_1.buildDesktopSessionLoginData)(streamAuthParams);
    }
    prepareWebSocketCreators(endpointsList, protocol) {
        return endpointsList.services.map(({ endpoint, port }) => {
            const endpointWithPort = endpoint.replace('localhost', `localhost:${port}`);
            const options = {
                headers: {
                    [desktop_session_params_interface_1.AUTHORIZATION_HEADER]: `${this.tokenType} ${this.accessToken}`,
                },
            };
            return (0, webSocket_helper_1.prepareSocketCreator)(`ws://${endpointWithPort}`, protocol, options);
        });
    }
    getStreamingDiscoveryEndpoint(api) {
        const [dataApi, service, endpoint] = api.split('/');
        if (!(dataApi && service && endpoint)) {
            throw new Error(`Parameter 'api' is not correct. Please check your config.`);
        }
        const discoveryEndpoint = config_1.config.get(`apis.${dataApi}.${service}`).url || '';
        const path = config_1.config.get(`apis.${dataApi}.${service}.endpoints.${endpoint}.path`) || '/';
        return (0, url_join_1.default)(this.rdpUrlRoot, discoveryEndpoint, path);
    }
    /**
     *
     * @param api Name of streaming connection in the configuration file. ('streaming/pricing/main', 'streaming/trading-analytics/redi'...)
     * @param protocol websocket protocol
     */
    async requestWebSocketList(api, protocol) {
        try {
            const { data: endpointsList } = await this.request({
                url: this.getStreamingDiscoveryEndpoint(api),
                method: common_1.HttpMethod.GET,
            });
            return this.prepareWebSocketCreators(endpointsList, protocol);
        }
        catch (err) {
            this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.Error, err, this);
            throw err;
        }
    }
    emitAuthenticationSuccess() {
        this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.EventReceived, this, session_interface_1.SessionEventCode.AuthenticationSucceeded);
    }
    emitAuthenticationFailed(err) {
        this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.EventReceived, this, session_interface_1.SessionEventCode.AuthenticationFailed, err);
        this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.Error, err, this);
    }
    async checkPipeErrors() {
        return Promise.resolve(void 0);
    }
}
exports.DesktopSession = DesktopSession;
//# sourceMappingURL=data:application/json;base64, 