{"version":3,"file":"LongPollingTransport.js","sourceRoot":"","sources":["../../src/LongPollingTransport.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) .NET Foundation. All rights reserved.\r\n// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.\r\n\r\nimport { AbortController } from \"./AbortController\";\r\nimport { HttpError, TimeoutError } from \"./Errors\";\r\nimport { HttpClient, HttpRequest } from \"./HttpClient\";\r\nimport { ILogger, LogLevel } from \"./ILogger\";\r\nimport { ITransport, TransferFormat } from \"./ITransport\";\r\nimport { Arg, getDataDetail, sendMessage } from \"./Utils\";\r\n\r\nconst SHUTDOWN_TIMEOUT = 5 * 1000;\r\n\r\n// Not exported from 'index', this type is internal.\r\n/** @private */\r\nexport class LongPollingTransport implements ITransport {\r\n private readonly httpClient: HttpClient;\r\n private readonly accessTokenFactory: () => string | Promise;\r\n private readonly logger: ILogger;\r\n private readonly logMessageContent: boolean;\r\n\r\n private url: string;\r\n private pollAbort: AbortController;\r\n private shutdownTimer: any; // We use 'any' because this is an object in NodeJS. But it still gets passed to clearTimeout, so it doesn't really matter\r\n private shutdownTimeout: number;\r\n private running: boolean;\r\n private stopped: boolean;\r\n\r\n // This is an internal type, not exported from 'index' so this is really just internal.\r\n public get pollAborted() {\r\n return this.pollAbort.aborted;\r\n }\r\n\r\n constructor(httpClient: HttpClient, accessTokenFactory: () => string | Promise, logger: ILogger, logMessageContent: boolean, shutdownTimeout?: number) {\r\n this.httpClient = httpClient;\r\n this.accessTokenFactory = accessTokenFactory || (() => null);\r\n this.logger = logger;\r\n this.pollAbort = new AbortController();\r\n this.logMessageContent = logMessageContent;\r\n this.shutdownTimeout = shutdownTimeout || SHUTDOWN_TIMEOUT;\r\n }\r\n\r\n public async connect(url: string, transferFormat: TransferFormat): Promise {\r\n Arg.isRequired(url, \"url\");\r\n Arg.isRequired(transferFormat, \"transferFormat\");\r\n Arg.isIn(transferFormat, TransferFormat, \"transferFormat\");\r\n\r\n this.url = url;\r\n\r\n this.logger.log(LogLevel.Trace, \"(LongPolling transport) Connecting\");\r\n\r\n if (transferFormat === TransferFormat.Binary && (typeof new XMLHttpRequest().responseType !== \"string\")) {\r\n // This will work if we fix: https://github.com/aspnet/SignalR/issues/742\r\n throw new Error(\"Binary protocols over XmlHttpRequest not implementing advanced features are not supported.\");\r\n }\r\n\r\n const pollOptions: HttpRequest = {\r\n abortSignal: this.pollAbort.signal,\r\n headers: {},\r\n timeout: 90000,\r\n };\r\n\r\n if (transferFormat === TransferFormat.Binary) {\r\n pollOptions.responseType = \"arraybuffer\";\r\n }\r\n\r\n const token = await this.accessTokenFactory();\r\n this.updateHeaderToken(pollOptions, token);\r\n\r\n let closeError: Error;\r\n\r\n // Make initial long polling request\r\n // Server uses first long polling request to finish initializing connection and it returns without data\r\n const pollUrl = `${url}&_=${Date.now()}`;\r\n this.logger.log(LogLevel.Trace, `(LongPolling transport) polling: ${pollUrl}`);\r\n const response = await this.httpClient.get(pollUrl, pollOptions);\r\n if (response.statusCode !== 200) {\r\n this.logger.log(LogLevel.Error, `(LongPolling transport) Unexpected response code: ${response.statusCode}`);\r\n\r\n // Mark running as false so that the poll immediately ends and runs the close logic\r\n closeError = new HttpError(response.statusText, response.statusCode);\r\n this.running = false;\r\n } else {\r\n this.running = true;\r\n }\r\n\r\n // tslint:disable-next-line:no-floating-promises\r\n this.poll(this.url, pollOptions, closeError);\r\n return Promise.resolve();\r\n }\r\n\r\n private updateHeaderToken(request: HttpRequest, token: string) {\r\n if (token) {\r\n // tslint:disable-next-line:no-string-literal\r\n request.headers[\"Authorization\"] = `Bearer ${token}`;\r\n return;\r\n }\r\n // tslint:disable-next-line:no-string-literal\r\n if (request.headers[\"Authorization\"]) {\r\n // tslint:disable-next-line:no-string-literal\r\n delete request.headers[\"Authorization\"];\r\n }\r\n }\r\n\r\n private async poll(url: string, pollOptions: HttpRequest, closeError: Error): Promise {\r\n try {\r\n while (this.running) {\r\n // We have to get the access token on each poll, in case it changes\r\n const token = await this.accessTokenFactory();\r\n this.updateHeaderToken(pollOptions, token);\r\n\r\n try {\r\n const pollUrl = `${url}&_=${Date.now()}`;\r\n this.logger.log(LogLevel.Trace, `(LongPolling transport) polling: ${pollUrl}`);\r\n const response = await this.httpClient.get(pollUrl, pollOptions);\r\n\r\n if (response.statusCode === 204) {\r\n this.logger.log(LogLevel.Information, \"(LongPolling transport) Poll terminated by server\");\r\n\r\n this.running = false;\r\n } else if (response.statusCode !== 200) {\r\n this.logger.log(LogLevel.Error, `(LongPolling transport) Unexpected response code: ${response.statusCode}`);\r\n\r\n // Unexpected status code\r\n closeError = new HttpError(response.statusText, response.statusCode);\r\n this.running = false;\r\n } else {\r\n // Process the response\r\n if (response.content) {\r\n this.logger.log(LogLevel.Trace, `(LongPolling transport) data received. ${getDataDetail(response.content, this.logMessageContent)}`);\r\n if (this.onreceive) {\r\n this.onreceive(response.content);\r\n }\r\n } else {\r\n // This is another way timeout manifest.\r\n this.logger.log(LogLevel.Trace, \"(LongPolling transport) Poll timed out, reissuing.\");\r\n }\r\n }\r\n } catch (e) {\r\n if (!this.running) {\r\n // Log but disregard errors that occur after we were stopped by DELETE\r\n this.logger.log(LogLevel.Trace, `(LongPolling transport) Poll errored after shutdown: ${e.message}`);\r\n } else {\r\n if (e instanceof TimeoutError) {\r\n // Ignore timeouts and reissue the poll.\r\n this.logger.log(LogLevel.Trace, \"(LongPolling transport) Poll timed out, reissuing.\");\r\n } else {\r\n // Close the connection with the error as the result.\r\n closeError = e;\r\n this.running = false;\r\n }\r\n }\r\n }\r\n }\r\n } finally {\r\n // Indicate that we've stopped so the shutdown timer doesn't get registered.\r\n this.stopped = true;\r\n\r\n // Clean up the shutdown timer if it was registered\r\n if (this.shutdownTimer) {\r\n clearTimeout(this.shutdownTimer);\r\n }\r\n\r\n // Fire our onclosed event\r\n if (this.onclose) {\r\n this.logger.log(LogLevel.Trace, `(LongPolling transport) Firing onclose event. Error: ${closeError || \"\"}`);\r\n this.onclose(closeError);\r\n }\r\n\r\n this.logger.log(LogLevel.Trace, \"(LongPolling transport) Transport finished.\");\r\n }\r\n }\r\n\r\n public async send(data: any): Promise {\r\n if (!this.running) {\r\n return Promise.reject(new Error(\"Cannot send until the transport is connected\"));\r\n }\r\n return sendMessage(this.logger, \"LongPolling\", this.httpClient, this.url, this.accessTokenFactory, data, this.logMessageContent);\r\n }\r\n\r\n public async stop(): Promise {\r\n // Send a DELETE request to stop the poll\r\n try {\r\n this.running = false;\r\n this.logger.log(LogLevel.Trace, `(LongPolling transport) sending DELETE request to ${this.url}.`);\r\n\r\n const deleteOptions: HttpRequest = {\r\n headers: {},\r\n };\r\n const token = await this.accessTokenFactory();\r\n this.updateHeaderToken(deleteOptions, token);\r\n await this.httpClient.delete(this.url, deleteOptions);\r\n\r\n this.logger.log(LogLevel.Trace, \"(LongPolling transport) DELETE request accepted.\");\r\n } finally {\r\n // Abort the poll after the shutdown timeout if the server doesn't stop the poll.\r\n if (!this.stopped) {\r\n this.shutdownTimer = setTimeout(() => {\r\n this.logger.log(LogLevel.Warning, \"(LongPolling transport) server did not terminate after DELETE request, canceling poll.\");\r\n\r\n // Abort any outstanding poll\r\n this.pollAbort.abort();\r\n }, this.shutdownTimeout);\r\n }\r\n }\r\n }\r\n\r\n public onreceive: (data: string | ArrayBuffer) => void;\r\n public onclose: (error?: Error) => void;\r\n}\r\n"]}