UNPKG

10.5 kBPlain TextView Raw
1// Copyright (c) .NET Foundation. All rights reserved.
2// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
4import { DefaultReconnectPolicy } from "./DefaultReconnectPolicy";
5import { HttpConnection } from "./HttpConnection";
6import { HubConnection } from "./HubConnection";
7import { IHttpConnectionOptions } from "./IHttpConnectionOptions";
8import { IHubProtocol } from "./IHubProtocol";
9import { ILogger, LogLevel } from "./ILogger";
10import { IRetryPolicy } from "./IRetryPolicy";
11import { HttpTransportType } from "./ITransport";
12import { JsonHubProtocol } from "./JsonHubProtocol";
13import { NullLogger } from "./Loggers";
14import { Arg, ConsoleLogger } from "./Utils";
15
16// tslint:disable:object-literal-sort-keys
17const LogLevelNameMapping = {
18 trace: LogLevel.Trace,
19 debug: LogLevel.Debug,
20 info: LogLevel.Information,
21 information: LogLevel.Information,
22 warn: LogLevel.Warning,
23 warning: LogLevel.Warning,
24 error: LogLevel.Error,
25 critical: LogLevel.Critical,
26 none: LogLevel.None,
27};
28
29function parseLogLevel(name: string): LogLevel {
30 // Case-insensitive matching via lower-casing
31 // Yes, I know case-folding is a complicated problem in Unicode, but we only support
32 // the ASCII strings defined in LogLevelNameMapping anyway, so it's fine -anurse.
33 const mapping = LogLevelNameMapping[name.toLowerCase()];
34 if (typeof mapping !== "undefined") {
35 return mapping;
36 } else {
37 throw new Error(`Unknown log level: ${name}`);
38 }
39}
40
41/** A builder for configuring {@link @microsoft/signalr.HubConnection} instances. */
42export class HubConnectionBuilder {
43 /** @internal */
44 public protocol?: IHubProtocol;
45 /** @internal */
46 public httpConnectionOptions?: IHttpConnectionOptions;
47 /** @internal */
48 public url?: string;
49 /** @internal */
50 public logger?: ILogger;
51
52 /** If defined, this indicates the client should automatically attempt to reconnect if the connection is lost. */
53 /** @internal */
54 public reconnectPolicy?: IRetryPolicy;
55
56 /** Configures console logging for the {@link @microsoft/signalr.HubConnection}.
57 *
58 * @param {LogLevel} logLevel The minimum level of messages to log. Anything at this level, or a more severe level, will be logged.
59 * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
60 */
61 public configureLogging(logLevel: LogLevel): HubConnectionBuilder;
62
63 /** Configures custom logging for the {@link @microsoft/signalr.HubConnection}.
64 *
65 * @param {ILogger} logger An object implementing the {@link @microsoft/signalr.ILogger} interface, which will be used to write all log messages.
66 * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
67 */
68 public configureLogging(logger: ILogger): HubConnectionBuilder;
69
70 /** Configures custom logging for the {@link @microsoft/signalr.HubConnection}.
71 *
72 * @param {string} logLevel A string representing a LogLevel setting a minimum level of messages to log.
73 * See {@link https://docs.microsoft.com/en-us/aspnet/core/signalr/configuration#configure-logging|the documentation for client logging configuration} for more details.
74 */
75 public configureLogging(logLevel: string): HubConnectionBuilder;
76
77 /** Configures custom logging for the {@link @microsoft/signalr.HubConnection}.
78 *
79 * @param {LogLevel | string | ILogger} logging A {@link @microsoft/signalr.LogLevel}, a string representing a LogLevel, or an object implementing the {@link @microsoft/signalr.ILogger} interface.
80 * See {@link https://docs.microsoft.com/en-us/aspnet/core/signalr/configuration#configure-logging|the documentation for client logging configuration} for more details.
81 * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
82 */
83 public configureLogging(logging: LogLevel | string | ILogger): HubConnectionBuilder;
84 public configureLogging(logging: LogLevel | string | ILogger): HubConnectionBuilder {
85 Arg.isRequired(logging, "logging");
86
87 if (isLogger(logging)) {
88 this.logger = logging;
89 } else if (typeof logging === "string") {
90 const logLevel = parseLogLevel(logging);
91 this.logger = new ConsoleLogger(logLevel);
92 } else {
93 this.logger = new ConsoleLogger(logging);
94 }
95
96 return this;
97 }
98
99 /** Configures the {@link @microsoft/signalr.HubConnection} to use HTTP-based transports to connect to the specified URL.
100 *
101 * The transport will be selected automatically based on what the server and client support.
102 *
103 * @param {string} url The URL the connection will use.
104 * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
105 */
106 public withUrl(url: string): HubConnectionBuilder;
107
108 /** Configures the {@link @microsoft/signalr.HubConnection} to use the specified HTTP-based transport to connect to the specified URL.
109 *
110 * @param {string} url The URL the connection will use.
111 * @param {HttpTransportType} transportType The specific transport to use.
112 * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
113 */
114 public withUrl(url: string, transportType: HttpTransportType): HubConnectionBuilder;
115
116 /** Configures the {@link @microsoft/signalr.HubConnection} to use HTTP-based transports to connect to the specified URL.
117 *
118 * @param {string} url The URL the connection will use.
119 * @param {IHttpConnectionOptions} options An options object used to configure the connection.
120 * @returns The {@link @microsoft/signalr.HubConnectionBuilder} instance, for chaining.
121 */
122 public withUrl(url: string, options: IHttpConnectionOptions): HubConnectionBuilder;
123 public withUrl(url: string, transportTypeOrOptions?: IHttpConnectionOptions | HttpTransportType): HubConnectionBuilder {
124 Arg.isRequired(url, "url");
125
126 this.url = url;
127
128 // Flow-typing knows where it's at. Since HttpTransportType is a number and IHttpConnectionOptions is guaranteed
129 // to be an object, we know (as does TypeScript) this comparison is all we need to figure out which overload was called.
130 if (typeof transportTypeOrOptions === "object") {
131 this.httpConnectionOptions = { ...this.httpConnectionOptions, ...transportTypeOrOptions };
132 } else {
133 this.httpConnectionOptions = {
134 ...this.httpConnectionOptions,
135 transport: transportTypeOrOptions,
136 };
137 }
138
139 return this;
140 }
141
142 /** Configures the {@link @microsoft/signalr.HubConnection} to use the specified Hub Protocol.
143 *
144 * @param {IHubProtocol} protocol The {@link @microsoft/signalr.IHubProtocol} implementation to use.
145 */
146 public withHubProtocol(protocol: IHubProtocol): HubConnectionBuilder {
147 Arg.isRequired(protocol, "protocol");
148
149 this.protocol = protocol;
150 return this;
151 }
152
153 /** Configures the {@link @microsoft/signalr.HubConnection} to automatically attempt to reconnect if the connection is lost.
154 * By default, the client will wait 0, 2, 10 and 30 seconds respectively before trying up to 4 reconnect attempts.
155 */
156 public withAutomaticReconnect(): HubConnectionBuilder;
157
158 /** Configures the {@link @microsoft/signalr.HubConnection} to automatically attempt to reconnect if the connection is lost.
159 *
160 * @param {number[]} retryDelays An array containing the delays in milliseconds before trying each reconnect attempt.
161 * The length of the array represents how many failed reconnect attempts it takes before the client will stop attempting to reconnect.
162 */
163 public withAutomaticReconnect(retryDelays: number[]): HubConnectionBuilder;
164
165 /** Configures the {@link @microsoft/signalr.HubConnection} to automatically attempt to reconnect if the connection is lost.
166 *
167 * @param {IRetryPolicy} reconnectPolicy An {@link @microsoft/signalR.IRetryPolicy} that controls the timing and number of reconnect attempts.
168 */
169 public withAutomaticReconnect(reconnectPolicy: IRetryPolicy): HubConnectionBuilder;
170 public withAutomaticReconnect(retryDelaysOrReconnectPolicy?: number[] | IRetryPolicy): HubConnectionBuilder {
171 if (this.reconnectPolicy) {
172 throw new Error("A reconnectPolicy has already been set.");
173 }
174
175 if (!retryDelaysOrReconnectPolicy) {
176 this.reconnectPolicy = new DefaultReconnectPolicy();
177 } else if (Array.isArray(retryDelaysOrReconnectPolicy)) {
178 this.reconnectPolicy = new DefaultReconnectPolicy(retryDelaysOrReconnectPolicy);
179 } else {
180 this.reconnectPolicy = retryDelaysOrReconnectPolicy;
181 }
182
183 return this;
184 }
185
186 /** Creates a {@link @microsoft/signalr.HubConnection} from the configuration options specified in this builder.
187 *
188 * @returns {HubConnection} The configured {@link @microsoft/signalr.HubConnection}.
189 */
190 public build(): HubConnection {
191 // If httpConnectionOptions has a logger, use it. Otherwise, override it with the one
192 // provided to configureLogger
193 const httpConnectionOptions = this.httpConnectionOptions || {};
194
195 // If it's 'null', the user **explicitly** asked for null, don't mess with it.
196 if (httpConnectionOptions.logger === undefined) {
197 // If our logger is undefined or null, that's OK, the HttpConnection constructor will handle it.
198 httpConnectionOptions.logger = this.logger;
199 }
200
201 // Now create the connection
202 if (!this.url) {
203 throw new Error("The 'HubConnectionBuilder.withUrl' method must be called before building the connection.");
204 }
205 const connection = new HttpConnection(this.url, httpConnectionOptions);
206
207 return HubConnection.create(
208 connection,
209 this.logger || NullLogger.instance,
210 this.protocol || new JsonHubProtocol(),
211 this.reconnectPolicy);
212 }
213}
214
215function isLogger(logger: any): logger is ILogger {
216 return logger.log !== undefined;
217}