"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PlatformSession = void 0;
const detect_browser_1 = require("detect-browser");
const url_join_1 = __importDefault(require("url-join"));
const config_1 = require("../../config");
const error_messages_1 = require("../../constants/error-messages");
const omm_stream_interface_1 = require("../../delivery/stream/omm-stream.interface");
const logger_1 = require("../../logger");
const oauth_1 = require("../../oauth");
const merge_request_params_1 = require("../../util/merge-request-params");
const abstract_session_1 = require("../abstract/abstract-session");
const session_definition_1 = require("../session-definition");
const session_interface_1 = require("../session.interface");
const platform_session_validator_1 = require("./platform-session-validator");
const transport_host_1 = require("./transport-host");
const transport_rdp_1 = require("./transport-rdp");
/**
 * Platform sessions are used to connect applications directly to the Refinitiv Data Platform or to a Refinitiv Real-Time Distribution System.
 * Not
 */
class PlatformSession extends abstract_session_1.AbstractSession {
    /** @internal */
    constructor(sessionParams) {
        super();
        this.sessionParams = sessionParams;
        this.isEndpointSupported = false;
        this.onRefreshSucceed = (token) => {
            this.log.debug(`${session_interface_1.SessionEvent.EventReceived} => ${session_interface_1.SessionEventCode.RefreshSucceeded}`);
            this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.EventReceived, this, session_interface_1.SessionEventCode.RefreshSucceeded);
            this.refreshStreamToken();
        };
        this.onTokenExpired = async (error) => {
            this.log.error(`${session_interface_1.SessionEvent.EventReceived} => ${session_interface_1.SessionEventCode.RefreshFailed}`);
            this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.EventReceived, this, session_interface_1.SessionEventCode.RefreshFailed, error);
            this.log.error(`${session_interface_1.SessionEvent.Error} => ${error.message}`);
            this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.Error, error, this);
            await this.close();
        };
        this.log = logger_1.logger.getLogger('session:platform');
        this.log.info('Create session');
        (0, platform_session_validator_1.validatePlatformSessionParams)(sessionParams);
        this.streamingTransport = this.getStreamingTransport(sessionParams);
        this.defineSessionProps(sessionParams);
    }
    /**
     * Creates a definition object for the platform session.
     * @param params An object literal with properties necessary to create a definition of the platform session
     * @return New instance of session definition
     */
    static Definition(params) {
        return new session_definition_1.SessionDefinitionImpl(() => new PlatformSession(params));
    }
    get config() {
        return config_1.config.get('sessions').platform['default-session'];
    }
    get baseUrl() {
        return this.config['base-url'];
    }
    get tokenEndpoint() {
        const { url, token } = this.config.auth;
        return (0, url_join_1.default)(this.baseUrl, url, token);
    }
    /**
     * This method is related to the endpoints overriding in the configration 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').platform['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';
    }
    /**
     * This is a method that sends a login request to open the session and then sets a timer for automatic token refresh.
     */
    async initialize() {
        const sessionInitialization = [];
        if (this.isEndpointSupported) {
            sessionInitialization.push(this.tokenProvider.login());
        }
        if ('host' in this.sessionParams) {
            sessionInitialization.push(this.getOMMStreamConnection(omm_stream_interface_1.DEFAULT_OMM_STREAMING_CONNECTION_NAME, false));
        }
        try {
            await Promise.all(sessionInitialization);
            this.log.debug(`${session_interface_1.SessionEvent.EventReceived} => ${session_interface_1.SessionEventCode.AuthenticationSucceeded}`);
            this.sessionEventsEmitter.emit(session_interface_1.SessionEvent.EventReceived, this, session_interface_1.SessionEventCode.AuthenticationSucceeded);
            this.registerTokenListeners();
        }
        catch (err) {
            this.log.error(`${session_interface_1.SessionEvent.EventReceived} => ${session_interface_1.SessionEventCode.AuthenticationFailed}`);
            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);
            await this.cleanUp();
            throw err;
        }
    }
    async request(requestParams) {
        if (!this.isEndpointSupported) {
            throw new Error(error_messages_1.ErrorMessages.ONLY_STREAMING_CONNECTION);
        }
        const headers = {
            Authorization: `Bearer ${this.tokenProvider.getToken()}`,
            Accept: 'application/json',
        };
        const requestConfig = (0, merge_request_params_1.mergeRequestParams)(this.baseUrl, requestParams, headers);
        return this.httpClient.request(requestConfig);
    }
    /**
     *
     * @param api Name of streaming connection in the configuration file. ('streaming/pricing/main, streaming/trading/redi, ...')
     * @param protocol websocket protocol
     */
    async getSocketCreators(api, protocol) {
        return this.streamingTransport.getSocketCreators(api, protocol);
    }
    getStreamLoginParams() {
        return this.streamingTransport.getStreamLoginParams();
    }
    /**
     * This is a method that closes the session. It clears the timer for automatic token refresh.
     */
    async cleanUp() {
        var _a, _b;
        (_a = this.tokenProvider) === null || _a === void 0 ? void 0 : _a.stopRefresh();
        (_b = this.tokenProvider) === null || _b === void 0 ? void 0 : _b.removeAllListeners();
        return super.cleanUp();
    }
    refreshStreamToken() {
        if (this.streamingTransport.isRefreshRequired) {
            Array.from(this.streamConnections.values()).forEach(streamConnection => {
                streamConnection.refresh();
            });
        }
    }
    getStreamingTransport(sessionParams) {
        if ('host' in sessionParams) {
            this.log.debug('Transport HOST is used. Host:', sessionParams.host);
            return new transport_host_1.TransportHost(sessionParams.host, sessionParams.dacs);
        }
        else if ('userName' in sessionParams && 'password' in sessionParams) {
            const transportRdpParams = {
                dacs: sessionParams.dacs,
                userName: sessionParams.userName,
                getAccessToken: () => this.tokenProvider.getToken(),
                request: this.request.bind(this),
            };
            this.log.debug('Transport RDP is used.');
            return new transport_rdp_1.TransportRdp(transportRdpParams);
        }
        const err = new Error('Wrong streaming transport type for Platform Session');
        this.log.error(err);
        throw err;
    }
    defineSessionProps(sessionParams) {
        if ('userName' in sessionParams && 'password' in sessionParams) {
            this.isEndpointSupported = true;
            this.tokenProvider = new oauth_1.AccessTokenProviderImpl(this.sessionParams.appKey, () => this.tokenEndpoint, sessionParams);
        }
    }
    registerTokenListeners() {
        var _a, _b, _c;
        (_a = this.tokenProvider) === null || _a === void 0 ? void 0 : _a.on(oauth_1.TokenProviderEvent.AuthenticationSucceeded, this.onRefreshSucceed);
        (_b = this.tokenProvider) === null || _b === void 0 ? void 0 : _b.on(oauth_1.TokenProviderEvent.RefreshSucceeded, this.onRefreshSucceed);
        (_c = this.tokenProvider) === null || _c === void 0 ? void 0 : _c.on(oauth_1.TokenProviderEvent.TokenExpired, this.onTokenExpired);
    }
    async checkPipeErrors() {
        return Promise.resolve(void 0);
    }
}
exports.PlatformSession = PlatformSession;
//# sourceMappingURL=data:application/json;base64, 