{"version":3,"sources":["../../../packages/core/data/gateway-connection.ts"],"names":[],"mappings":"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","file":"gateway-connection.d.ts","sourcesContent":["import { Observable, of, ReplaySubject, Subscription, throwError } from 'rxjs';\r\nimport { AjaxError, AjaxRequest, AjaxResponse } from 'rxjs/ajax';\r\nimport { catchError, expand, filter, map, mergeMap, switchMap, take, tap } from 'rxjs/operators';\r\nimport { Strings } from '../generated/strings';\r\nimport { EnvironmentModule } from '../manifest/environment-modules';\r\nimport { RpcObservableElevateClient } from '../rpc/elevate/rpc-observable-elevate-client';\r\nimport {\r\n    RpcObservableElevateError, RpcObservableElevateRequest, RpcObservableElevateResult\r\n} from '../rpc/elevate/rpc-observable-elevate-model';\r\nimport { RpcObservableElevateServer } from '../rpc/elevate/rpc-observable-elevate-server';\r\nimport { RpcForwardResponse } from '../rpc/forward/rpc-forward-model';\r\nimport { Rpc } from '../rpc/rpc';\r\nimport { RpcRelationshipType } from '../rpc/rpc-base';\r\nimport { RpcServiceForwarder } from '../rpc/rpc-forwarder';\r\nimport { AuthorizationManager } from '../security/authorization-manager';\r\nimport { SignedHttpRequestToken } from '../security/sign-on-manager';\r\nimport { CoreEnvironment } from './core-environment';\r\nimport { GatewayStatus } from './gateway-status';\r\nimport { GatewayUrlBuilder } from './gateway-url-builder';\r\nimport { GatewayUrls } from './gateway-urls';\r\nimport { Http, HttpMethod, HttpResponseRetryHandler, HttpRetryOptions } from './http';\r\nimport { headerConstants } from './http-constants';\r\nimport { Net } from './net';\r\n\r\n/**\r\n * Gateway Request options that we use to extend the AjaxRequest interface\r\n */\r\nexport interface GatewayRequestOptions {\r\n    /**\r\n     * Retry handler implementation for a request.\r\n     * These handlers are used to invoke specific functionality for non-200 status codes in the http response.\r\n     */\r\n    retryHandlers?: HttpResponseRetryHandler[];\r\n\r\n    /**\r\n     * Determines the maximum number of times that any of the retry handlers will be tried.\r\n     * before giving up and surfacing the error to the original caller\r\n     */\r\n    maxRetryCount?: number;\r\n\r\n    /**\r\n     * Observable handler to insert asynchronous logic before the actual http response is sent.\r\n     * For Example: Waiting for pending authentication to complete before adding an authentication header\r\n     */\r\n    beforeCall?: (request: GatewayRequest) => Observable<void>;\r\n}\r\n\r\n/**\r\n * Extension of AjaxRequest interface for calling the Gateway API\r\n */\r\nexport interface GatewayRequest extends AjaxRequest, GatewayRequestOptions {\r\n}\r\n\r\n/**\r\n * Initialization object data for the Gateway's base class.\r\n */\r\nexport interface GatewayRPCForwardedProperties {\r\n    /**\r\n     * The gateway URL.\r\n     */\r\n    gatewayName: string;\r\n\r\n    /**\r\n     * Indicate whether gatewayUrl option was specified. (default to be false)\r\n     */\r\n    gatewayUrlSpecified: boolean;\r\n\r\n    /**\r\n     * The stative version. (default to be null)\r\n     */\r\n    staticVersion: string;\r\n}\r\n\r\n/**\r\n * The gateway information on current gateway URL.\r\n */\r\nexport interface GatewayInformation {\r\n    /**\r\n     * The name of gateway node.\r\n     */\r\n    name: string;\r\n\r\n    /**\r\n     * Indicating if https is used.\r\n     */\r\n    secure: boolean;\r\n\r\n    /**\r\n     * The port number of gateway.\r\n     */\r\n    port: number;\r\n}\r\n\r\n/**\r\n * Condition of gateway.\r\n */\r\nexport interface GatewayCondition {\r\n    /**\r\n     * the gateway is running as service mode (installed on server operating system).\r\n     */\r\n    isServiceMode: boolean;\r\n\r\n    /**\r\n     * the gateway is elevated on the desktop mode.\r\n     */\r\n    isGatewayProcessElevated: boolean;\r\n\r\n    /**\r\n     * the user account is a member of the gateway administrators.\r\n     */\r\n    isGatewayAdmin: boolean;\r\n}\r\n\r\n/**\r\n * The Gateway Connection class for creating requests and calling the Gateway's REST API\r\n */\r\nexport class GatewayConnection extends RpcServiceForwarder {\r\n    private static rpcCommands = {\r\n        forbiddenReceived: 'forbiddenRecieved'\r\n    };\r\n\r\n    /**\r\n     * The IPv4 address for localhost\r\n     */\r\n    private readonly localhostIpV4 = '127.0.0.1';\r\n\r\n    /**\r\n     * The IPv6 address for localhost\r\n     */\r\n    private readonly localhostIpV6 = '::1';\r\n\r\n    /**\r\n     * The localhost name\r\n     */\r\n    private readonly localhost = 'localhost';\r\n\r\n    /**\r\n     * Time interval to check for internalGatewayStatus refresh.\r\n    */\r\n    private readonly lastUpdatedInternalGatewayStatusInterval = 1000 * 60 * 10; // 10 minutes\r\n\r\n    /**\r\n     * internally maintained gateway URL.\r\n     */\r\n    private internalGatewayUrl: string;\r\n\r\n    /**\r\n     * internally maintained static version.\r\n     */\r\n    private internalStaticVersion: string;\r\n\r\n    /**\r\n    * gatewayUrl param is specified.\r\n    */\r\n    private internalGatewayUrlSpecified: boolean;\r\n\r\n    /**\r\n     * Last time internal gateway status was updated in milliseconds\r\n     */\r\n    private lastUpdatedInternalGatewayStatus: number;\r\n\r\n    /**\r\n     * Internally maintained gateway status.\r\n     */\r\n    private internalGatewayStatus: Observable<GatewayStatus>;\r\n\r\n    /**\r\n     * The replay subject for gateway url to settle.\r\n     */\r\n    private gatewayUrlAwaiter = new ReplaySubject<string>(1);\r\n\r\n    /**\r\n     * The RPC observable elevate client.\r\n     */\r\n    private elevateClient: RpcObservableElevateClient = null;\r\n\r\n    /**\r\n     * The RPC observable elevate server.\r\n     */\r\n    private elevateServer: RpcObservableElevateServer = null;\r\n\r\n    /**\r\n     * The elevate callback observable.\r\n     */\r\n    private elevateCallbackInternal: () => Observable<boolean> = () => of(false);\r\n\r\n    /**\r\n     * The replay subject for navigation ready state.\r\n     */\r\n    private navigationReady = new ReplaySubject<boolean>(1);\r\n\r\n    /**\r\n     * Sets the elevate callback observable.\r\n     */\r\n    public set elevateCallback(value: () => Observable<boolean>) {\r\n        this.elevateCallbackInternal = value;\r\n        if (!this.elevateServer) {\r\n            this.elevateServer = new RpcObservableElevateServer(this.rpc);\r\n            this.elevateServer.register((_context: RpcObservableElevateRequest) => {\r\n                return this.elevateCallbackInternal()\r\n                    .pipe(\r\n                        catchError((error, _caught) =>\r\n                            throwError(() => <RpcObservableElevateError>{error: Net.getErrorMessage(error) })),\r\n                        map(result =>\r\n                            <RpcObservableElevateResult>{ elevated: result })\r\n                    );\r\n            });\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Indicates that the gateway is disabled and therefore should not be called.\r\n     */\r\n    public get disabled(): boolean {\r\n        const environment = MsftSme.self().Environment;\r\n        return environment && environment.configuration.gateway.disabled;\r\n    }\r\n\r\n    /**\r\n     * Gets the gateway URL to connect to.\r\n     */\r\n    public get gatewayUrl(): string {\r\n        return this.internalGatewayUrl;\r\n    }\r\n\r\n    /**\r\n     * Gets the gateway URL specified state.\r\n     */\r\n    public get staticVersion() {\r\n        return this.internalStaticVersion;\r\n    }\r\n\r\n    /**\r\n     * Gets the gateway URL specified state.\r\n     */\r\n    public get gatewayUrlSpecified(): boolean {\r\n        return this.internalGatewayUrlSpecified;\r\n    }\r\n\r\n    /**\r\n     * Gets the gateway URL observable while setting up.\r\n     */\r\n    public get gatewayUrlObservable(): Observable<string> {\r\n        return this.gatewayUrlAwaiter.asObservable();\r\n    }\r\n\r\n    /**\r\n     * Gets the navigation ready observable.\r\n     */\r\n    public get navigationReadyObservable(): Observable<boolean> {\r\n        return this.navigationReady.asObservable();\r\n    }\r\n\r\n    /**\r\n     * Sets the navigation ready status.\r\n     */\r\n    public set navigationReadyStatus(ready: boolean) {\r\n        this.navigationReady.next(ready);\r\n    }\r\n\r\n    /**\r\n     * Gets the gateway information.\r\n     */\r\n    public get gatewayInfo(): GatewayInformation {\r\n        if (!this.internalGatewayUrl) {\r\n            throw new Error(MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.GatewayUrlNotConfigured.message);\r\n        }\r\n\r\n        // RegEx: ('http' or 'https') '://' (('<gatewayName1>'):('<port>') or ('<gatewayName2>'))\r\n        // 0: url\r\n        // 1: https or http\r\n        // 2: <gatewayName1>:<port> or <gatewayName2>\r\n        // 3: <gatewayName1> or undefined\r\n        // 4: <port> or undefined\r\n        // 5: <gatewayName2>\r\n        const url = MsftSme.trimEnd(this.internalGatewayUrl.toLowerCase(), '/');\r\n        const match = url.match(/(http|https):\\/\\/((.+):(\\d+)|(.+))/);\r\n        if (!match) {\r\n            throw new Error(MsftSme.getStrings<Strings>().MsftSmeShell.Core.Error.GatewayUrlMalformed.message);\r\n        }\r\n\r\n        const secure = (match[1] === 'https');\r\n        const name = match[3] || match[2];\r\n        const port = parseInt(match[4], 10) || (secure ? 443 : 80);\r\n        return { name, secure, port };\r\n    }\r\n\r\n    /**\r\n     * Gets the gateway node name to make a CIM/PowerShell query to the gateway node.\r\n     */\r\n    public get gatewayName(): string {\r\n        // localhost will be used to locally query gateway node. if this causes any access problem, need to be replaced.\r\n        return 'localhost';\r\n    }\r\n\r\n    /**\r\n     * Gets gateway status from cache or sets cache if it doesn't exist.\r\n     */\r\n    private get gatewayStatus(): Observable<any> {\r\n        if (!this.internalGatewayStatus\r\n            || Date.now() - this.lastUpdatedInternalGatewayStatus > this.lastUpdatedInternalGatewayStatusInterval) {\r\n            return this.getStatus();\r\n        }\r\n\r\n        return of(this.internalGatewayStatus);\r\n    }\r\n\r\n    /**\r\n     * Initializes a new instance of the Gateway class.\r\n     *\r\n     * @param http the Http object.\r\n     * @param rpc the Rpc class.\r\n     * @patam authorizationManager the authorization manager class object.\r\n     */\r\n    constructor(public http: Http, rpc: Rpc, private authorizationManager: AuthorizationManager) {\r\n        super('gateway-connection', rpc);\r\n\r\n        // restore the AAD token if exist becase ealier access of token is required for gateway calls.\r\n        authorizationManager.signOnManager.applySignedHttpRequestToken(\r\n            <SignedHttpRequestToken>MsftSme.self().Environment.configuration?.signOn?.signedHttpRequestToken);\r\n    }\r\n\r\n    /**\r\n     * Configure the gateway URL to connect to.\r\n     */\r\n    public configureGatewayEnvironment(url: string, urlSpecified: boolean, staticVersion: string): void {\r\n        // trim last \"/\"\r\n        if (url[url.length - 1] === '/') {\r\n            url = url.substring(0, url.length - 1);\r\n        }\r\n\r\n        this.internalGatewayUrl = url;\r\n        this.internalGatewayUrlSpecified = urlSpecified,\r\n            this.internalStaticVersion = staticVersion;\r\n        this.gatewayUrlAwaiter.next(url);\r\n    }\r\n\r\n    /**\r\n     * Update the url with static version option.\r\n     * @param url the original URL including options.\r\n     * @returns updated url with \"version=\" option if staticVersion present.\r\n     */\r\n    public addStaticVersion(url: string): string {\r\n        if (MsftSme.isNullOrWhiteSpace(this.staticVersion) || this.staticVersion.indexOf('staticVersion=') < 0) {\r\n            return url;\r\n        }\r\n\r\n        const splitter = url.indexOf('?') > 0 ? '&' : '?';\r\n        return `${url}${splitter}staticVersion=${this.staticVersion}`;\r\n    }\r\n\r\n    /**\r\n     * Makes a POST call to the gateway\r\n     *\r\n     * @param relativeUrl the relative Url after \"/api\"\r\n     * @param body the body string JSON.stringfy'ed\r\n     * @param request the gateway request object.\r\n     */\r\n    public post(relativeUrl: string, body?: any, request?: GatewayRequest): Observable<any> {\r\n        const postRequest = this.createRequest(HttpMethod.Post, relativeUrl, body, request);\r\n        return this.call(postRequest);\r\n    }\r\n\r\n    /**\r\n     * Makes a GET call to the gateway\r\n     *\r\n     * @param relativeUrl the relative Url after \"/api\"\r\n     * @param request the gateway request object.\r\n     */\r\n    public get(relativeUrl: string, request?: GatewayRequest): Observable<any> {\r\n        const getRequest = this.createRequest(HttpMethod.Get, relativeUrl, null, request);\r\n        return this.call(getRequest);\r\n    }\r\n\r\n    /**\r\n     * Makes a PUT call to the gateway\r\n     *\r\n     * @param relativeUrl the relative Url after \"/api\"\r\n     * @param body the body string JSON.stringfy'ed\r\n     * @param request the gateway request object.\r\n     */\r\n    public put(relativeUrl: string, body?: string, request?: GatewayRequest): Observable<any> {\r\n        const putRequest = this.createRequest(HttpMethod.Put, relativeUrl, body, request);\r\n        return this.call(putRequest);\r\n    }\r\n\r\n    /**\r\n     * Makes a PATCH call to the gateway\r\n     *\r\n     * @param relativeUrl the relative Url after \"/api\"\r\n     * @param body the body string JSON.stringfy'ed\r\n     * @param request the gateway request object.\r\n     */\r\n    public patch(relativeUrl: string, body?: string, request?: GatewayRequest): Observable<any> {\r\n        const patchRequest = this.createRequest(HttpMethod.Patch, relativeUrl, body, request);\r\n        return this.call(patchRequest);\r\n    }\r\n\r\n    /**\r\n     * Makes a DELETE call to the gateway\r\n     *\r\n     * @param relativeUrl the relative Url after \"/api\"\r\n     * @param body the body string JSON.stringfy'ed\r\n     * @param request the gateway request object.\r\n     */\r\n    public delete(relativeUrl: string, body?: string, request?: GatewayRequest): Observable<any> {\r\n        const deleteRequest = this.createRequest(HttpMethod.Delete, relativeUrl, body, request);\r\n        return this.call(deleteRequest);\r\n    }\r\n\r\n    /**\r\n     * Makes a DELETE call to the gateway without waiting for the response.\r\n     *\r\n     * @param relativeUrl the relative Url after \"/api\"\r\n     * @param request the gateway request object.\r\n     */\r\n    public deleteQuick(relativeUrl: string, headers?: any): void {\r\n        headers[headerConstants.MODULE_NAME] = EnvironmentModule.getModuleName();\r\n        headers[headerConstants.MODULE_VERSION] = EnvironmentModule.getModuleVersion();\r\n        headers[headerConstants.ACCEPT_LANGUAGE] = CoreEnvironment.localizationManager.getLocaleId().neutral;\r\n        if (this.staticVersion) {\r\n            headers[headerConstants.STATIC_VERSION] = this.staticVersion;\r\n        }\r\n\r\n        if (this.authorizationManager.signOnManager.isSignOnTokenEnabled) {\r\n            this.authorizationManager.signOnManager.SetAadAuthorizationHeader(headers);\r\n        }\r\n\r\n        const url = Net.gatewayApi(this.gatewayUrl, relativeUrl);\r\n        this.http.deleteQuick(url, headers);\r\n    }\r\n\r\n    /**\r\n     * Creates a GatewayRequest.\r\n     *\r\n     * @param method the http method to use\r\n     * @param relativeUrl the relative Url after \"/api/\"\r\n     * @param body the body string JSON.stringfy'ed\r\n     * @param request the gateway request object to extend.\r\n     */\r\n    public createRequest(\r\n        method: string,\r\n        relativeUrl: string,\r\n        body?: any,\r\n        request?: GatewayRequest): GatewayRequest {\r\n\r\n        const defaultMaxRetry = 3;\r\n        request = MsftSme.deepAssign({}, request);\r\n\r\n        // if request is undefined, default to empty object\r\n        request = request || <GatewayRequest>{};\r\n        request.headers = request.headers || {};\r\n        (<any>request).headers[headerConstants.MODULE_NAME] = EnvironmentModule.getModuleName();\r\n        (<any>request).headers[headerConstants.MODULE_VERSION] = EnvironmentModule.getModuleVersion();\r\n        (<any>request).headers[headerConstants.ACCEPT_LANGUAGE] = CoreEnvironment.localizationManager.getLocaleId().neutral;\r\n        if (this.staticVersion) {\r\n            (<any>request).headers[headerConstants.STATIC_VERSION] = this.staticVersion;\r\n        }\r\n\r\n        // use default retry options if none are provided\r\n        const retryHandlers: HttpResponseRetryHandler[] = [];\r\n        if (this.authorizationManager.signOnManager.isSignOnTokenEnabled) {\r\n            this.authorizationManager.signOnManager.SetAadAuthorizationHeader(request.headers);\r\n            retryHandlers.push({\r\n                canHandle: (code, error) => this.authorizationManager.signOnManager.canHandleUnauthorizedLogin(code, error),\r\n                handle: (code, originalRequest, error) =>\r\n                    this.authorizationManager.signOnManager.handleUnauthorizedLogin(code, originalRequest, error)\r\n            });\r\n        }\r\n\r\n        if (request.retryHandlers != null && request.retryHandlers.length > 0) {\r\n            retryHandlers.push(...request.retryHandlers);\r\n        }\r\n\r\n        return Object.assign(request, <GatewayRequest><unknown>{\r\n            method: method,\r\n            url: relativeUrl,\r\n\r\n            // default to the passed in body, the request body, or an empty string\r\n            body: body || request.body || '',\r\n\r\n            // default to the request headers, or an empty object\r\n            headers: request.headers,\r\n\r\n            // for the next 2 props, default to true unless explicitly set to false\r\n            withCredentials: request.withCredentials === false ? false : true,\r\n            crossDomain: request.crossDomain === false ? false : true,\r\n            createXHR: () => new XMLHttpRequest(),\r\n\r\n            retryHandlers,\r\n            maxRetryCount: request.maxRetryCount === 0 ? 0 : request.maxRetryCount || defaultMaxRetry\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Make a request.\r\n     *\r\n     * @param request the request to execute against the gateway.\r\n     * @return Observable<any> the query result observable.\r\n     */\r\n    public call(request: GatewayRequest): Observable<any> {\r\n        if (!this.gatewayUrl) {\r\n            return this.gatewayUrlAwaiter.pipe(mergeMap(() => this.call(request)));\r\n        }\r\n\r\n        // create gateway url from current url if not set yet.\r\n        if (!request.url || (!request.url.startsWith('http://') && !request.url.startsWith('https://'))) {\r\n            request.url = Net.gatewayApi(this.gatewayUrl, request.url);\r\n        }\r\n\r\n        // create retry options from request\r\n        const retryOptions: HttpRetryOptions = {\r\n            handlers: (request.retryHandlers || []),\r\n            maxRetry: request.maxRetryCount\r\n        };\r\n        // create observable for our request\r\n        const requestObservable = this.http.request(request, retryOptions)\r\n            .pipe(map((response: AjaxResponse<any>) => response ? response.response : {}));\r\n\r\n        if (request.beforeCall) {\r\n            return request.beforeCall(request).pipe(mergeMap(() => requestObservable));\r\n        }\r\n\r\n        return requestObservable;\r\n    }\r\n\r\n    /**\r\n     * Gets default secure request options.\r\n     *\r\n     * @returns updated request object.\r\n     */\r\n    public get defaultHttpSecureOptions(): AjaxRequest {\r\n        const request = { ...{ headers: {} }, ...Http.defaultHttpOptions };\r\n        if (this.authorizationManager.signOnManager.isSignOnTokenEnabled) {\r\n            this.authorizationManager.signOnManager.SetAadAuthorizationHeader(request.headers);\r\n        }\r\n\r\n        return request;\r\n    }\r\n\r\n    /**\r\n     * Check if elevation is required from the error object.\r\n     *\r\n     * @param error the ajax error object.\r\n     */\r\n    public isElevationRequired(error: AjaxError): boolean {\r\n        const code = error.xhr && error.xhr.response && error.xhr.response.error && error.xhr.response.error.code;\r\n        return code === 'ElevationRequired';\r\n    }\r\n\r\n    /**\r\n     * Elevate the gateway if it's desktop mode running.\r\n     */\r\n    public elevate(): Observable<boolean> {\r\n        if (!this.elevateClient) {\r\n            this.elevateClient = new RpcObservableElevateClient(this.rpc);\r\n        }\r\n\r\n        return this.elevateClient.elevate().pipe(map(result => result.elevated));\r\n    }\r\n\r\n    /**\r\n     * Creates and returns a new URL builder for the current connection.\r\n     */\r\n    public url(): GatewayUrlBuilder {\r\n        return new GatewayUrlBuilder(this.gatewayUrl);\r\n    }\r\n\r\n    /**\r\n     * Clear the DNS cache.\r\n     */\r\n    public clearDnsCache(): Observable<void> {\r\n        const dnsCacheClearUrl = 'gateway/dnsCacheClear';\r\n        return this.delete(dnsCacheClearUrl)\r\n            .pipe(map(_ => null));\r\n    }\r\n\r\n    /**\r\n     * Polling to check if the gateway is elevated.\r\n     */\r\n    public pollingGatewayElevated(): Observable<boolean> {\r\n        // user might not respond for elevation prompt, maximum waiting time is 2.5 min.\r\n        // getElevatedStatus() takes 5000ms when the gateway is not responding.\r\n        // 2.5 min = count [30] * 5000 msec.\r\n        const uniQueId = MsftSme.getUniqueId();\r\n        const maxWaitingCount = 30;\r\n        let count = maxWaitingCount;\r\n        return this.getElevatedStatus()\r\n            .pipe(\r\n                expand(status => {\r\n                    // user accepted.\r\n                    // adds 5 calls for the gateway dead period.\r\n                    // < Restart Requested from UI >\r\n                    // 1st query: it shows success on slow performed system, the gateway is even not shutdown yet.\r\n                    // 2nd query: It could success still.\r\n                    // 3rd query: Maybe timeout because the gateway is not started yet.\r\n                    // 4rd query: Maybe timeout because the gateway is not started yet.\r\n                    // 5rd query: Maybe timeout because the gateway is down.\r\n                    // 25 = 30 - 5\r\n                    const pollingStartCount = 25;\r\n                    if (\r\n                        (\r\n                            (count <= pollingStartCount\r\n                                && (!status.error || status.isGatewayProcessElevated))\r\n                            || status.completed\r\n                        )\r\n                        && (status.id === uniQueId)\r\n                    ) {\r\n                        return of({\r\n                            completed: true,\r\n                            id: uniQueId,\r\n                            isGatewayProcessElevated: status.isGatewayProcessElevated\r\n                        });\r\n                    }\r\n\r\n                    // no response for more than 2.5 minutes.\r\n                    // gateway was stopped for long or user never responded to UAC prompt.\r\n                    if (count-- <= 0 && status.id === uniQueId) {\r\n                        return of({\r\n                            completed: true,\r\n                            id: uniQueId,\r\n                            isGatewayProcessElevated: status.isGatewayProcessElevated\r\n                        });\r\n                    }\r\n\r\n                    return this.getElevatedStatus();\r\n                }),\r\n                filter(result => result.isGatewayProcessElevated || result.completed),\r\n                take(1),\r\n                map(result => result.isGatewayProcessElevated)\r\n            );\r\n    }\r\n\r\n    /**\r\n     * Perform gateway status query but cut off if it exceeds 2.5 seconds.\r\n     */\r\n    public getElevatedStatus(): Observable<{ error: boolean, isGatewayProcessElevated: boolean, completed: boolean, id: string }> {\r\n        // if the gateway is not responding for 5000ms, cancel the call.\r\n        const callCancelTime = 5000;\r\n        return new Observable(observer => {\r\n            let subscription: Subscription = null;\r\n            let timer = setTimeout(\r\n                () => {\r\n                    // handle pending timeout of the query when the gateway doesn't respond.\r\n                    if (subscription) {\r\n                        observer.next({ error: true, isGatewayProcessElevated: false, completed: undefined, id: undefined });\r\n                        observer.complete();\r\n                        subscription.unsubscribe();\r\n                        subscription = null;\r\n                        timer = null;\r\n                    }\r\n                },\r\n                callCancelTime);\r\n            subscription = this.getStatus()\r\n                .subscribe({\r\n                    next: data => {\r\n                        observer.next({\r\n                            error: false,\r\n                            isGatewayProcessElevated: data.isGatewayProcessElevated,\r\n                            completed: undefined,\r\n                            id: undefined\r\n                        });\r\n                        observer.complete();\r\n                        subscription.unsubscribe();\r\n                        subscription = null;\r\n                        if (timer) {\r\n                            clearTimeout(timer);\r\n                        }\r\n                    },\r\n                    error: () => {\r\n                        observer.next({ error: true, isGatewayProcessElevated: false, completed: undefined, id: undefined });\r\n                        observer.complete();\r\n                        subscription.unsubscribe();\r\n                        subscription = null;\r\n                        if (timer) {\r\n                            clearTimeout(timer);\r\n                        }\r\n                    }\r\n                });\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Gets gateway machine if found in list of given nodes\r\n     * @param nodes Node names or IPs to check\r\n     * @returns Node name of gateway if found, null otherwise\r\n     */\r\n    public getGateway(nodes: string[]): Observable<string> {\r\n        return this.gatewayStatus.pipe(map(status => {\r\n            for (const node of nodes) {\r\n                if (MsftSme.isNullOrUndefined(node)) {\r\n                    continue;\r\n                }\r\n\r\n                switch (node.toLocaleLowerCase()) {\r\n                    case this.localhostIpV4:\r\n                    case this.localhostIpV6:\r\n                    case this.localhost:\r\n                    case status.fullyQualifiedDNSName?.toLocaleLowerCase():\r\n                    case status.name?.toLocaleLowerCase():\r\n                    case status.machineName?.toLocaleLowerCase():\r\n                        return node;\r\n                }\r\n\r\n                if (status.addressList?.find((address: string) => address === node)) {\r\n                    return node;\r\n                }\r\n            }\r\n\r\n            return null;\r\n        }));\r\n    }\r\n\r\n    /**\r\n     * Check gateway condition.\r\n     */\r\n    public checkCondition(): Observable<GatewayCondition> {\r\n        const result = <GatewayCondition>{};\r\n        return this.getStatus()\r\n            .pipe(\r\n                switchMap(gateway => {\r\n                    if (gateway.gatewayMode === 'Service') {\r\n                        result.isServiceMode = true;\r\n                        result.isGatewayProcessElevated = false;\r\n                        return this.getAccessCheck();\r\n                    }\r\n\r\n                    result.isServiceMode = false;\r\n                    result.isGatewayProcessElevated = gateway.isGatewayProcessElevated;\r\n                    return of(true);\r\n                }),\r\n                map((isAdmin) => {\r\n                    result.isGatewayAdmin = !!isAdmin;\r\n                    return result;\r\n                }),\r\n                take(1)\r\n            );\r\n    }\r\n\r\n    /**\r\n     * Get gateway status.\r\n     */\r\n    public getStatus(): Observable<any> {\r\n        return this.get('gateway/status').pipe(tap(status => {\r\n            this.lastUpdatedInternalGatewayStatus = Date.now();\r\n            this.internalGatewayStatus = status;\r\n        }));\r\n    }\r\n\r\n    /**\r\n     * Get user access check.\r\n     */\r\n    public getAccessCheck(): Observable<any> {\r\n        return this.get(GatewayUrls.accessCheck);\r\n    }\r\n\r\n    /**\r\n     * Called on a child service instance when onForwardInit returns from the parent\r\n     * Initialize telemetry from within here so we can leverage gateway status for telemetry metadata.\r\n     * @param data The response from the forwardInit call\r\n     */\r\n    protected onForwardInitResponse(data: RpcForwardResponse<GatewayRPCForwardedProperties>): void {\r\n        if (data.error) {\r\n            // if there is an error, we cannot continue, so throw its\r\n            throw data.error;\r\n        }\r\n\r\n        if (!MsftSme.self().Environment.configuration.gateway.disabled) {\r\n            this.internalGatewayUrl = data.result.gatewayName;\r\n            this.internalGatewayUrlSpecified = data.result.gatewayUrlSpecified;\r\n            this.internalStaticVersion = data.result.staticVersion;\r\n\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Called when a new instance of the service in another window is initialized and needs to synchronize with its parent\r\n     * @param from The RpcRelationshipType that this request is from\r\n     * @returns an observable for the all the values needed to initialize the service\r\n     */\r\n    protected onForwardInit(): Observable<GatewayRPCForwardedProperties> {\r\n        if (this.gatewayUrl) {\r\n            return of({\r\n                gatewayName: this.gatewayUrl,\r\n                gatewayUrlSpecified: this.gatewayUrlSpecified,\r\n                staticVersion: this.staticVersion\r\n            });\r\n        } else {\r\n            // if gateway value hasn't been set yet, then wait for it.\r\n            if (MsftSme.self().Environment.configuration.gateway.disabled) {\r\n                return of(null);\r\n            }\r\n\r\n            return this.gatewayUrlAwaiter\r\n                .pipe(map(url => ({\r\n                    gatewayName: url,\r\n                    gatewayUrlSpecified: this.gatewayUrlSpecified,\r\n                    staticVersion: this.staticVersion\r\n                })));\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Called when the forwarded services counterpart wants to get data from the parent\r\n     * @param from The RpcRelationshipType that this request is from\r\n     * @param name The name of the method to forward to\r\n     * @param args The arguments of the method\r\n     * @returns an observable for the result of the method call\r\n     */\r\n    protected onForwardExecute(from: RpcRelationshipType, name: string): Observable<any> {\r\n        // gatewayConnection does not allow any method calls at this time\r\n        return this.nameNotFound(name);\r\n    }\r\n\r\n    /**\r\n     * Called when the forwarded services counterpart sends a notify message\r\n     * @param from The RpcRelationshipType that this request is from\r\n     * @param name The name of the property to change\r\n     * @param value The new value of the property\r\n     * @returns an observable that completes when the property has been changed.\r\n     */\r\n    protected onForwardNotify(from: RpcRelationshipType, name: string): Observable<void> {\r\n        if (from === RpcRelationshipType.Child && name === GatewayConnection.rpcCommands.forbiddenReceived) {\r\n            // Deprecated noop version 1.1100.0 at 10/1/2020. Using ErrorMonitor.\r\n            return of(null);\r\n        }\r\n        // gatewayConnection does not allow any other notifications at this time\r\n        return this.nameNotFound(name);\r\n    }\r\n}\r\n"]}