Adding loggers to TS client

This commit is contained in:
Pawel Kadluczka 2017-08-21 17:51:24 -07:00 committed by Pawel Kadluczka
parent 978f5cebc0
commit e4c1b888ca
9 changed files with 124 additions and 38 deletions

View File

@ -3,6 +3,8 @@ import { IConnection } from "./IConnection"
import { ITransport, TransferMode, TransportType, WebSocketTransport, ServerSentEventsTransport, LongPollingTransport } from "./Transports"
import { IHttpClient, HttpClient } from "./HttpClient"
import { IHttpConnectionOptions } from "./IHttpConnectionOptions"
import { ILogger, LogLevel } from "./ILogger"
import { NullLogger } from "./Loggers"
const enum ConnectionState {
Initial,
@ -19,10 +21,11 @@ interface INegotiateResponse {
export class HttpConnection implements IConnection {
private connectionState: ConnectionState;
private url: string;
private connectionId: string;
private httpClient: IHttpClient;
private readonly httpClient: IHttpClient;
private readonly logger: ILogger;
private readonly options: IHttpConnectionOptions;
private transport: ITransport;
private options: IHttpConnectionOptions;
private connectionId: string;
private startPromise: Promise<void>;
readonly features: any = {};
@ -30,6 +33,7 @@ export class HttpConnection implements IConnection {
constructor(url: string, options: IHttpConnectionOptions = {}) {
this.url = url;
this.httpClient = options.httpClient || new HttpClient();
this.logger = options.logger || new NullLogger();
this.connectionState = ConnectionState.Initial;
this.options = options;
}
@ -74,7 +78,7 @@ export class HttpConnection implements IConnection {
this.changeState(ConnectionState.Connecting, ConnectionState.Connected);
}
catch (e) {
console.log("Failed to start the connection. " + e);
this.logger.log(LogLevel.Error, "Failed to start the connection. " + e);
this.connectionState = ConnectionState.Disconnected;
this.transport = null;
throw e;
@ -86,13 +90,13 @@ export class HttpConnection implements IConnection {
transport = TransportType[availableTransports[0]];
}
if (transport === TransportType.WebSockets && availableTransports.indexOf(TransportType[transport]) >= 0) {
return new WebSocketTransport();
return new WebSocketTransport(this.logger);
}
if (transport === TransportType.ServerSentEvents && availableTransports.indexOf(TransportType[transport]) >= 0) {
return new ServerSentEventsTransport(this.httpClient);
return new ServerSentEventsTransport(this.httpClient, this.logger);
}
if (transport === TransportType.LongPolling && availableTransports.indexOf(TransportType[transport]) >= 0) {
return new LongPollingTransport(this.httpClient);
return new LongPollingTransport(this.httpClient, this.logger);
}
if (this.isITransport(transport)) {

View File

@ -6,21 +6,27 @@ import { IHubProtocol, ProtocolType, MessageType, HubMessage, CompletionMessage,
import { JsonHubProtocol } from "./JsonHubProtocol";
import { TextMessageFormat } from "./Formatters"
import { Base64EncodedHubProtocol } from "./Base64EncodedHubProtocol"
import { ILogger, LogLevel } from "./ILogger"
import { NullLogger } from "./Loggers"
export { TransportType } from "./Transports"
export { HttpConnection } from "./HttpConnection"
export { JsonHubProtocol } from "./JsonHubProtocol"
export { LogLevel } from "./ILogger"
export { ConsoleLogger } from "./Loggers"
export class HubConnection {
private connection: IConnection;
private readonly connection: IConnection;
private readonly logger: ILogger;
private protocol: IHubProtocol;
private callbacks: Map<string, (invocationUpdate: CompletionMessage | ResultMessage) => void>;
private methods: Map<string, (...args: any[]) => void>;
private id: number;
private connectionClosedCallback: ConnectionClosed;
private protocol: IHubProtocol;
constructor(connection: IConnection, protocol: IHubProtocol = new JsonHubProtocol()) {
constructor(connection: IConnection, logger: ILogger = new NullLogger(), protocol: IHubProtocol = new JsonHubProtocol()) {
this.connection = connection;
this.logger = logger || new NullLogger();
this.protocol = protocol || new JsonHubProtocol();
this.connection.onDataReceived = data => {
this.onDataReceived(data);
@ -57,7 +63,7 @@ export class HubConnection {
}
break;
default:
console.log("Invalid message type: " + data);
this.logger.log(LogLevel.Warning, "Invalid message type: " + data);
break;
}
}
@ -72,7 +78,7 @@ export class HubConnection {
}
}
else {
console.log(`No client method with the name '${invocationMessage.target}' found.`);
this.logger.log(LogLevel.Warning, `No client method with the name '${invocationMessage.target}' found.`);
}
}

View File

@ -1,7 +1,9 @@
import { IHttpClient } from "./HttpClient"
import { TransportType, ITransport } from "./Transports"
import { ILogger } from "./ILogger";
export interface IHttpConnectionOptions {
httpClient?: IHttpClient;
transport?: TransportType | ITransport;
logger?: ILogger;
}

View File

@ -0,0 +1,10 @@
export enum LogLevel {
Information = 0,
Warning,
Error,
None
}
export interface ILogger {
log(logLevel: LogLevel, message: string): void;
}

View File

@ -0,0 +1,20 @@
import { ILogger, LogLevel } from "./ILogger"
export class NullLogger implements ILogger {
log(logLevel: LogLevel, message: string): void {
}
}
export class ConsoleLogger implements ILogger {
private readonly minimumLogLevel: LogLevel;
constructor(minimumLogLevel: LogLevel) {
this.minimumLogLevel = minimumLogLevel;
}
log(logLevel: LogLevel, message: string): void {
if (logLevel >= this.minimumLogLevel) {
console.log(`${LogLevel[logLevel]}: ${message}`);
}
}
}

View File

@ -1,6 +1,7 @@
import { DataReceived, TransportClosed } from "./Common"
import { IHttpClient } from "./HttpClient"
import { HttpError } from "./HttpError"
import { ILogger, LogLevel } from "./ILogger"
export enum TransportType {
WebSockets,
@ -22,8 +23,13 @@ export interface ITransport {
}
export class WebSocketTransport implements ITransport {
private readonly logger: ILogger;
private webSocket: WebSocket;
constructor(logger: ILogger) {
this.logger = logger;
}
connect(url: string, requestedTransferMode: TransferMode): Promise<TransferMode> {
return new Promise<TransferMode>((resolve, reject) => {
@ -35,7 +41,7 @@ export class WebSocketTransport implements ITransport {
}
webSocket.onopen = (event: Event) => {
console.log(`WebSocket connected to ${url}`);
this.logger.log(LogLevel.Information, `WebSocket connected to ${url}`);
this.webSocket = webSocket;
resolve(requestedTransferMode);
};
@ -45,7 +51,7 @@ export class WebSocketTransport implements ITransport {
};
webSocket.onmessage = (message: MessageEvent) => {
console.log(`(WebSockets transport) data received: ${message.data}`);
this.logger.log(LogLevel.Information, `(WebSockets transport) data received: ${message.data}`);
if (this.onDataReceived) {
this.onDataReceived(message.data);
}
@ -86,12 +92,14 @@ export class WebSocketTransport implements ITransport {
}
export class ServerSentEventsTransport implements ITransport {
private readonly httpClient: IHttpClient;
private readonly logger: ILogger;
private eventSource: EventSource;
private url: string;
private httpClient: IHttpClient;
constructor(httpClient: IHttpClient) {
constructor(httpClient: IHttpClient, logger: ILogger) {
this.httpClient = httpClient;
this.logger = logger;
}
connect(url: string, requestedTransferMode: TransferMode): Promise<TransferMode> {
@ -107,7 +115,7 @@ export class ServerSentEventsTransport implements ITransport {
eventSource.onmessage = (e: MessageEvent) => {
if (this.onDataReceived) {
try {
console.log(`(SSE transport) data received: ${e.data}`);
this.logger.log(LogLevel.Information, `(SSE transport) data received: ${e.data}`);
this.onDataReceived(e.data);
} catch (error) {
if (this.onClosed) {
@ -128,7 +136,7 @@ export class ServerSentEventsTransport implements ITransport {
}
eventSource.onopen = () => {
console.log(`SSE connected to ${this.url}`);
this.logger.log(LogLevel.Information, `SSE connected to ${this.url}`);
this.eventSource = eventSource;
// SSE is a text protocol
resolve(TransferMode.Text);
@ -156,13 +164,16 @@ export class ServerSentEventsTransport implements ITransport {
}
export class LongPollingTransport implements ITransport {
private readonly httpClient: IHttpClient;
private readonly logger: ILogger;
private url: string;
private httpClient: IHttpClient;
private pollXhr: XMLHttpRequest;
private shouldPoll: boolean;
constructor(httpClient: IHttpClient) {
constructor(httpClient: IHttpClient, logger: ILogger) {
this.httpClient = httpClient;
this.logger = logger;
}
connect(url: string, requestedTransferMode: TransferMode): Promise<TransferMode> {
@ -187,11 +198,11 @@ export class LongPollingTransport implements ITransport {
if (this.onDataReceived) {
try {
if (pollXhr.response) {
console.log(`(LongPolling transport) data received: ${pollXhr.response}`);
this.logger.log(LogLevel.Information, `(LongPolling transport) data received: ${pollXhr.response}`);
this.onDataReceived(pollXhr.response);
}
else {
console.log(`(LongPolling transport) timed out`);
this.logger.log(LogLevel.Information, "(LongPolling transport) timed out");
}
} catch (error) {
if (this.onClosed) {

View File

@ -3,4 +3,5 @@ export * from "./HttpConnection"
export * from "./HttpClient"
export * from "./HubConnection"
export * from "./Transports"
export * from "./Loggers"

View File

@ -29,7 +29,11 @@ describe('connection', () => {
eachTransport(transportType => {
it(`over ${signalR.TransportType[transportType]} can send and receive messages`, done => {
const message = "Hello World!";
let connection = new signalR.HttpConnection(ECHOENDPOINT_URL, { transport: transportType });
let connection = new signalR.HttpConnection(ECHOENDPOINT_URL,
{
transport: transportType,
logger: new signalR.ConsoleLogger(signalR.LogLevel.Information)
});
let received = "";
connection.onDataReceived = data => {

View File

@ -5,8 +5,12 @@ describe('hubConnection', () => {
describe(`${protocol.name} over ${signalR.TransportType[transportType]} transport`, () => {
it(`can invoke server method and receive result`, done => {
const message = "你好,世界!";
let hubConnection = new signalR.HubConnection(
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
hubConnection.onClosed = error => {
expect(error).toBe(undefined);
done();
@ -32,8 +36,13 @@ describe('hubConnection', () => {
});
it(`can stream server method and receive result`, done => {
let hubConnection = new signalR.HubConnection(
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
hubConnection.onClosed = error => {
expect(error).toBe(undefined);
done();
@ -65,8 +74,13 @@ describe('hubConnection', () => {
it(`rethrows an exception from the server when invoking`, done => {
const errorMessage = "An error occurred.";
let hubConnection = new signalR.HubConnection(
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
hubConnection.start()
.then(() => {
@ -93,8 +107,13 @@ describe('hubConnection', () => {
it(`rethrows an exception from the server when streaming`, done => {
const errorMessage = "An error occurred.";
let hubConnection = new signalR.HubConnection(
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
hubConnection.start()
.then(() => {
@ -120,20 +139,25 @@ describe('hubConnection', () => {
});
it(`can receive server calls`, done => {
let client = new signalR.HubConnection(
new signalR.HttpConnection(TESTHUBENDPOINT_URL, { transport: transportType }), protocol);
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
TESTHUBENDPOINT_URL,
{ transport: transportType, logger: logger }),
logger,
protocol);
const message = "你好 SignalR";
let callbackPromise = new Promise((resolve, reject) => {
client.on("Message", msg => {
hubConnection.on("Message", msg => {
expect(msg).toBe(message);
resolve();
});
});
client.start()
hubConnection.start()
.then(() => {
return Promise.all([client.invoke('InvokeWithString', message), callbackPromise]);
return Promise.all([hubConnection.invoke('InvokeWithString', message), callbackPromise]);
})
.then(() => {
return stop();
@ -154,8 +178,12 @@ describe('hubConnection', () => {
ServerSentEvents: "Error occurred"
};
let hubConnection = new signalR.HubConnection(
new signalR.HttpConnection(`http://${document.location.host}/uncreatable`, { transport: transportType }), protocol);
let logger = new signalR.ConsoleLogger(signalR.LogLevel.Information);
let hubConnection = new signalR.HubConnection(new signalR.HttpConnection(
`http://${document.location.host}/uncreatable`,
{ transport: transportType, logger: logger }),
logger,
protocol);
hubConnection.onClosed = error => {
expect(error.message).toMatch(errorRegex[signalR.TransportType[transportType]]);