123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- import { LogLevel } from "./ILogger";
- import { TransferFormat } from "./ITransport";
- import { Arg, getDataDetail, getUserAgentHeader, Platform, sendMessage } from "./Utils";
- /** @private */
- export class ServerSentEventsTransport {
- constructor(httpClient, accessToken, logger, options) {
- this._httpClient = httpClient;
- this._accessToken = accessToken;
- this._logger = logger;
- this._options = options;
- this.onreceive = null;
- this.onclose = null;
- }
- async connect(url, transferFormat) {
- Arg.isRequired(url, "url");
- Arg.isRequired(transferFormat, "transferFormat");
- Arg.isIn(transferFormat, TransferFormat, "transferFormat");
- this._logger.log(LogLevel.Trace, "(SSE transport) Connecting.");
- // set url before accessTokenFactory because this._url is only for send and we set the auth header instead of the query string for send
- this._url = url;
- if (this._accessToken) {
- url += (url.indexOf("?") < 0 ? "?" : "&") + `access_token=${encodeURIComponent(this._accessToken)}`;
- }
- return new Promise((resolve, reject) => {
- let opened = false;
- if (transferFormat !== TransferFormat.Text) {
- reject(new Error("The Server-Sent Events transport only supports the 'Text' transfer format"));
- return;
- }
- let eventSource;
- if (Platform.isBrowser || Platform.isWebWorker) {
- eventSource = new this._options.EventSource(url, { withCredentials: this._options.withCredentials });
- }
- else {
- // Non-browser passes cookies via the dictionary
- const cookies = this._httpClient.getCookieString(url);
- const headers = {};
- headers.Cookie = cookies;
- const [name, value] = getUserAgentHeader();
- headers[name] = value;
- eventSource = new this._options.EventSource(url, { withCredentials: this._options.withCredentials, headers: { ...headers, ...this._options.headers } });
- }
- try {
- eventSource.onmessage = (e) => {
- if (this.onreceive) {
- try {
- this._logger.log(LogLevel.Trace, `(SSE transport) data received. ${getDataDetail(e.data, this._options.logMessageContent)}.`);
- this.onreceive(e.data);
- }
- catch (error) {
- this._close(error);
- return;
- }
- }
- };
- // @ts-ignore: not using event on purpose
- eventSource.onerror = (e) => {
- // EventSource doesn't give any useful information about server side closes.
- if (opened) {
- this._close();
- }
- else {
- reject(new Error("EventSource failed to connect. The connection could not be found on the server,"
- + " either the connection ID is not present on the server, or a proxy is refusing/buffering the connection."
- + " If you have multiple servers check that sticky sessions are enabled."));
- }
- };
- eventSource.onopen = () => {
- this._logger.log(LogLevel.Information, `SSE connected to ${this._url}`);
- this._eventSource = eventSource;
- opened = true;
- resolve();
- };
- }
- catch (e) {
- reject(e);
- return;
- }
- });
- }
- async send(data) {
- if (!this._eventSource) {
- return Promise.reject(new Error("Cannot send until the transport is connected"));
- }
- return sendMessage(this._logger, "SSE", this._httpClient, this._url, data, this._options);
- }
- stop() {
- this._close();
- return Promise.resolve();
- }
- _close(e) {
- if (this._eventSource) {
- this._eventSource.close();
- this._eventSource = undefined;
- if (this.onclose) {
- this.onclose(e);
- }
- }
- }
- }
- //# sourceMappingURL=ServerSentEventsTransport.js.map
|