"use strict";
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
Object.defineProperty(exports, "__esModule", { value: true });
exports.TunnelConnectionBase = void 0;
const dev_tunnels_ssh_1 = require("@microsoft/dev-tunnels-ssh");
const vscode_jsonrpc_1 = require("vscode-jsonrpc");
const connectionStatus_1 = require("./connectionStatus");
const connectionStatusChangedEventArgs_1 = require("./connectionStatusChangedEventArgs");
const refreshingTunnelAccessTokenEventArgs_1 = require("./refreshingTunnelAccessTokenEventArgs");
const utils_1 = require("./utils");
const sshKeepAliveEventArgs_1 = require("./sshKeepAliveEventArgs");
/**
 * Tunnel connection base class.
 */
class TunnelConnectionBase {
    constructor(
    /**
     * Gets tunnel access scope for this tunnel session.
     */
    tunnelAccessScope) {
        this.tunnelAccessScope = tunnelAccessScope;
        this.disposeCts = new vscode_jsonrpc_1.CancellationTokenSource();
        this.status = connectionStatus_1.ConnectionStatus.None;
        this.refreshingTunnelAccessTokenEmitter = new utils_1.TrackingEmitter();
        this.connectionStatusChangedEmitter = new vscode_jsonrpc_1.Emitter();
        this.retryingTunnelConnectionEmitter = new vscode_jsonrpc_1.Emitter();
        this.forwardedPortConnectingEmitter = new vscode_jsonrpc_1.Emitter();
        this.keepAliveFailedEmitter = new vscode_jsonrpc_1.Emitter();
        this.keepAliveSucceededEmitter = new vscode_jsonrpc_1.Emitter();
        /**
         * Event for refreshing the tunnel access token.
         * The tunnel client will fire this event when it is not able to use the access token it got from the tunnel.
         */
        this.refreshingTunnelAccessToken = this.refreshingTunnelAccessTokenEmitter.event;
        /**
         * Connection status changed event.
         */
        this.connectionStatusChanged = this.connectionStatusChangedEmitter.event;
        /**
         * Event raised when a tunnel connection attempt failed and is about to be retried.
         *  An event handler can cancel the retry by setting {@link RetryingTunnelConnectionEventArgs.retry} to false.
         */
        this.retryingTunnelConnection = this.retryingTunnelConnectionEmitter.event;
        /**
         * An event which fires when a connection is made to the forwarded port.
         */
        this.forwardedPortConnecting = this.forwardedPortConnectingEmitter.event;
        /**
         * Event raised when a keep-alive message response is not received.
         */
        this.keepAliveFailed = this.keepAliveFailedEmitter.event;
        /**
         * Event raised when a keep-alive message response is received.
         */
        this.keepAliveSucceeded = this.keepAliveSucceededEmitter.event;
    }
    /**
     * Gets a value indicathing that this tunnel connection session is disposed.
     */
    get isDisposed() {
        return this.disposeCts.token.isCancellationRequested;
    }
    get isRefreshingTunnelAccessTokenEventHandled() {
        return this.refreshingTunnelAccessTokenEmitter.isSubscribed;
    }
    /**
     * Gets dispose cancellation token.
     */
    get disposeToken() {
        return this.disposeCts.token;
    }
    /**
     * Gets the connection status.
     */
    get connectionStatus() {
        return this.status;
    }
    /**
     * Sets the connection status.
     * Throws CancellationError if the session is disposed and the status being set is not ConnectionStatus.Disconnected.
     */
    set connectionStatus(value) {
        if (this.isDisposed && value !== connectionStatus_1.ConnectionStatus.Disconnected) {
            this.throwIfDisposed(`ConnectionStatus: ${value}`);
        }
        if (value === connectionStatus_1.ConnectionStatus.RefreshingTunnelAccessToken && this.status !== connectionStatus_1.ConnectionStatus.Connecting) {
            throw new Error('Refreshing tunnel access token is allowed only when connecting.');
        }
        if (value !== this.status) {
            const previousStatus = this.connectionStatus;
            this.status = value;
            this.onConnectionStatusChanged(previousStatus, value);
        }
    }
    /**
     * Gets the error that caused disconnection.
     * Undefined if not yet connected or disconnection was caused by disposing of this object.
     */
    get disconnectError() {
        return this.error;
    }
    /**
     * Sets the error that caused disconnection.
     */
    set disconnectError(e) {
        this.error = e;
    }
    onForwardedPortConnecting(e) {
        this.forwardedPortConnectingEmitter.fire(e);
    }
    /**
     * Raises the keep-alive failed event.
     */
    onKeepAliveFailed(count) {
        this.keepAliveFailedEmitter.fire(new sshKeepAliveEventArgs_1.SshKeepAliveEventArgs(count));
    }
    /**
     * Raises the keep-alive succeeded event.
     */
    onKeepAliveSucceeded(count) {
        this.keepAliveSucceededEmitter.fire(new sshKeepAliveEventArgs_1.SshKeepAliveEventArgs(count));
    }
    /**
     * Closes and disposes the tunnel session.
     */
    dispose() {
        this.disposeCts.cancel();
        this.connectionStatus = connectionStatus_1.ConnectionStatus.Disconnected;
        return Promise.resolve();
    }
    /**
     *  Notifies about a connection retry, giving the relay client a chance to delay or cancel it.
     */
    onRetrying(event) {
        this.retryingTunnelConnectionEmitter.fire(event);
    }
    /**
     * Gets the fresh tunnel access token or undefined if it cannot.
     */
    async getFreshTunnelAccessToken(cancellation) {
        const event = new refreshingTunnelAccessTokenEventArgs_1.RefreshingTunnelAccessTokenEventArgs(this.tunnelAccessScope, cancellation);
        this.refreshingTunnelAccessTokenEmitter.fire(event);
        return event.tunnelAccessToken ? await event.tunnelAccessToken : undefined;
    }
    /**
     * Event fired when the connection status has changed.
     */
    onConnectionStatusChanged(previousStatus, status) {
        // Disconnect error is provided only during disconnection, not disposal.
        const disconnectError = this.connectionStatus === connectionStatus_1.ConnectionStatus.Disconnected && !this.isDisposed ? this.disconnectError : undefined;
        const event = new connectionStatusChangedEventArgs_1.ConnectionStatusChangedEventArgs(previousStatus, status, disconnectError);
        this.connectionStatusChangedEmitter.fire(event);
    }
    /**
     * Throws CancellationError if the tunnel connection is disposed.
     */
    throwIfDisposed(message, stack) {
        if (this.isDisposed) {
            const error = new dev_tunnels_ssh_1.ObjectDisposedError(`The tunnel connection is disposed. ${message}`);
            if (stack) {
                error.stack = stack;
            }
            throw error;
        }
    }
}
exports.TunnelConnectionBase = TunnelConnectionBase;
//# sourceMappingURL=https://github.com/VSCodium/sourcemaps/releases/download/stable-4c0b0c6cc561d2d3636d1ec250935431876ce4dc/node_modules-@microsoft-dev-tunnels-connections-tunnelConnectionBase.js.map