Merge branch 'release/2.1' into dev
This commit is contained in:
commit
29ddc6a3e5
|
|
@ -22,8 +22,8 @@
|
|||
"build:rollup": "node ../node_modules/rollup/bin/rollup -c",
|
||||
"pretest": "npm run build",
|
||||
"test": "dotnet build && npm run test-only",
|
||||
"test-only": "ts-node --project ./selenium/tsconfig.json ./selenium/run-tests.ts",
|
||||
"ci-test": "ts-node --project ./selenium/tsconfig.json ./selenium/run-ci-tests.ts"
|
||||
"test-only": "ts-node --project ./selenium/tsconfig-selenium.json ./selenium/run-tests.ts",
|
||||
"ci-test": "ts-node --project ./selenium/tsconfig-selenium.json ./selenium/run-ci-tests.ts"
|
||||
},
|
||||
"author": "",
|
||||
"license": "Apache-2.0"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
import { DefaultHttpClient, HttpClient, HttpRequest, HttpResponse, HttpTransportType, HubConnection, IHubConnectionOptions, IStreamSubscriber, JsonHubProtocol, LogLevel } from "@aspnet/signalr";
|
||||
import { DefaultHttpClient, HttpClient, HttpRequest, HttpResponse, HttpTransportType, HubConnection, HubConnectionBuilder, IHttpConnectionOptions, IStreamSubscriber, JsonHubProtocol, LogLevel } from "@aspnet/signalr";
|
||||
import { MessagePackHubProtocol } from "@aspnet/signalr-protocol-msgpack";
|
||||
|
||||
import { eachTransport, eachTransportAndProtocol } from "./Common";
|
||||
|
|
@ -10,25 +10,35 @@ import { TestLogger } from "./TestLogger";
|
|||
const TESTHUBENDPOINT_URL = "/testhub";
|
||||
const TESTHUB_NOWEBSOCKETS_ENDPOINT_URL = "/testhub-nowebsockets";
|
||||
|
||||
const commonOptions: IHubConnectionOptions = {
|
||||
logMessageContent: true,
|
||||
logger: TestLogger.instance,
|
||||
};
|
||||
|
||||
// On slower CI machines, these tests sometimes take longer than 5s
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10 * 1000;
|
||||
|
||||
const commonOptions: IHttpConnectionOptions = {
|
||||
logMessageContent: true,
|
||||
};
|
||||
|
||||
function getConnectionBuilder(transportType?: HttpTransportType, url?: string, options?: IHttpConnectionOptions): HubConnectionBuilder {
|
||||
let actualOptions: IHttpConnectionOptions = options || {};
|
||||
if (transportType) {
|
||||
actualOptions.transport = transportType;
|
||||
}
|
||||
actualOptions = { ...actualOptions, ...commonOptions };
|
||||
|
||||
return new HubConnectionBuilder()
|
||||
.configureLogging(TestLogger.instance)
|
||||
.withUrl(url || TESTHUBENDPOINT_URL, actualOptions);
|
||||
}
|
||||
|
||||
describe("hubConnection", () => {
|
||||
eachTransportAndProtocol((transportType, protocol) => {
|
||||
describe("using " + protocol.name + " over " + HttpTransportType[transportType] + " transport", async () => {
|
||||
it("can invoke server method and receive result", (done) => {
|
||||
const message = "你好,世界!";
|
||||
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error).toBeUndefined();
|
||||
done();
|
||||
|
|
@ -51,11 +61,10 @@ describe("hubConnection", () => {
|
|||
it("can invoke server method non-blocking and not receive result", (done) => {
|
||||
const message = "你好,世界!";
|
||||
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error).toBe(undefined);
|
||||
done();
|
||||
|
|
@ -74,11 +83,9 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("can invoke server method structural object and receive structural result", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.on("CustomObject", (customObject) => {
|
||||
expect(customObject.Name).toBe("test");
|
||||
|
|
@ -100,11 +107,9 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("can stream server method and receive result", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error).toBe(undefined);
|
||||
|
|
@ -134,11 +139,9 @@ describe("hubConnection", () => {
|
|||
|
||||
it("rethrows an exception from the server when invoking", (done) => {
|
||||
const errorMessage = "An unexpected error occurred invoking 'ThrowException' on the server. InvalidOperationException: An error occurred.";
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.start().then(() => {
|
||||
hubConnection.invoke("ThrowException", "An error occurred.").then(() => {
|
||||
|
|
@ -158,11 +161,9 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("throws an exception when invoking streaming method with invoke", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.start().then(() => {
|
||||
hubConnection.invoke("EmptyStream").then(() => {
|
||||
|
|
@ -182,11 +183,9 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("throws an exception when receiving a streaming result for method called with invoke", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.start().then(() => {
|
||||
hubConnection.invoke("Stream").then(() => {
|
||||
|
|
@ -207,11 +206,9 @@ describe("hubConnection", () => {
|
|||
|
||||
it("rethrows an exception from the server when streaming", (done) => {
|
||||
const errorMessage = "An unexpected error occurred invoking 'StreamThrowException' on the server. InvalidOperationException: An error occurred.";
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.start().then(() => {
|
||||
hubConnection.stream("StreamThrowException", "An error occurred.").subscribe({
|
||||
|
|
@ -236,11 +233,9 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("throws an exception when invoking hub method with stream", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.start().then(() => {
|
||||
hubConnection.stream("Echo", "42").subscribe({
|
||||
|
|
@ -265,11 +260,9 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("can receive server calls", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
const message = "你好 SignalR!";
|
||||
|
||||
|
|
@ -297,11 +290,9 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("can receive server calls without rebinding handler when restarted", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
const message = "你好 SignalR!";
|
||||
|
||||
|
|
@ -354,11 +345,9 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("closed with error if hub cannot be created", (done) => {
|
||||
const hubConnection = new HubConnection("http://" + document.location.host + "/uncreatable", {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType, "http://" + document.location.host + "/uncreatable")
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error.message).toEqual("Server returned an error on close: Connection closed with an error. InvalidOperationException: Unable to resolve service for type 'System.Object' while attempting to activate 'FunctionalTests.UncreatableHub'.");
|
||||
|
|
@ -368,11 +357,10 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("can handle different types", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error).toBe(undefined);
|
||||
done();
|
||||
|
|
@ -412,11 +400,10 @@ describe("hubConnection", () => {
|
|||
});
|
||||
|
||||
it("can receive different types", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error).toBe(undefined);
|
||||
done();
|
||||
|
|
@ -458,11 +445,9 @@ describe("hubConnection", () => {
|
|||
it("can be restarted", (done) => {
|
||||
const message = "你好,世界!";
|
||||
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
let closeCount = 0;
|
||||
hubConnection.onclose((error) => {
|
||||
|
|
@ -512,11 +497,11 @@ describe("hubConnection", () => {
|
|||
|
||||
try {
|
||||
const jwtToken = await getJwtToken("http://" + document.location.host + "/generateJwtToken");
|
||||
const hubConnection = new HubConnection("/authorizedhub", {
|
||||
|
||||
const hubConnection = getConnectionBuilder(transportType, "/authorizedhub", {
|
||||
accessTokenFactory: () => jwtToken,
|
||||
...commonOptions,
|
||||
transport: transportType,
|
||||
});
|
||||
}).build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error).toBe(undefined);
|
||||
done();
|
||||
|
|
@ -539,11 +524,10 @@ describe("hubConnection", () => {
|
|||
const message = "你好,世界!";
|
||||
|
||||
try {
|
||||
const hubConnection = new HubConnection("/authorizedhub", {
|
||||
const hubConnection = getConnectionBuilder(transportType, "/authorizedhub", {
|
||||
accessTokenFactory: () => getJwtToken("http://" + document.location.host + "/generateJwtToken"),
|
||||
...commonOptions,
|
||||
transport: transportType,
|
||||
});
|
||||
}).build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error).toBe(undefined);
|
||||
done();
|
||||
|
|
@ -566,11 +550,10 @@ describe("hubConnection", () => {
|
|||
const message = "你好,世界!";
|
||||
|
||||
try {
|
||||
const hubConnection = new HubConnection("/authorizedhub", {
|
||||
const hubConnection = getConnectionBuilder(transportType, "/authorizedhub", {
|
||||
accessTokenFactory: () => getJwtToken("http://" + document.location.host + "/generateJwtToken"),
|
||||
...commonOptions,
|
||||
transport: transportType,
|
||||
});
|
||||
}).build();
|
||||
|
||||
hubConnection.onclose((error) => {
|
||||
expect(error).toBe(undefined);
|
||||
done();
|
||||
|
|
@ -591,11 +574,8 @@ describe("hubConnection", () => {
|
|||
|
||||
if (transportType !== HttpTransportType.LongPolling) {
|
||||
it("terminates if no messages received within timeout interval", (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
timeoutInMilliseconds: 100,
|
||||
transport: transportType,
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(transportType).build();
|
||||
hubConnection.serverTimeoutInMilliseconds = 100;
|
||||
|
||||
const timeout = setTimeout(200, () => {
|
||||
fail("Server timeout did not fire within expected interval");
|
||||
|
|
@ -615,10 +595,9 @@ describe("hubConnection", () => {
|
|||
|
||||
if (typeof EventSource !== "undefined") {
|
||||
it("allows Server-Sent Events when negotiating for JSON protocol", async (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUB_NOWEBSOCKETS_ENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol: new JsonHubProtocol(),
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(undefined, TESTHUB_NOWEBSOCKETS_ENDPOINT_URL)
|
||||
.withHubProtocol(new JsonHubProtocol())
|
||||
.build();
|
||||
|
||||
try {
|
||||
await hubConnection.start();
|
||||
|
|
@ -633,10 +612,9 @@ describe("hubConnection", () => {
|
|||
}
|
||||
|
||||
it("skips Server-Sent Events when negotiating for MessagePack protocol", async (done) => {
|
||||
const hubConnection = new HubConnection(TESTHUB_NOWEBSOCKETS_ENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol: new MessagePackHubProtocol(),
|
||||
});
|
||||
const hubConnection = getConnectionBuilder(undefined, TESTHUB_NOWEBSOCKETS_ENDPOINT_URL)
|
||||
.withHubProtocol(new MessagePackHubProtocol())
|
||||
.build();
|
||||
|
||||
try {
|
||||
await hubConnection.start();
|
||||
|
|
@ -657,10 +635,9 @@ describe("hubConnection", () => {
|
|||
throw new Error("Kick rocks");
|
||||
};
|
||||
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
protocol: new JsonHubProtocol(),
|
||||
});
|
||||
const hubConnection = getConnectionBuilder()
|
||||
.withHubProtocol(new JsonHubProtocol())
|
||||
.build();
|
||||
|
||||
try {
|
||||
await hubConnection.start();
|
||||
|
|
@ -693,10 +670,10 @@ describe("hubConnection", () => {
|
|||
}
|
||||
|
||||
const testClient = new TestClient();
|
||||
const hubConnection = new HubConnection(TESTHUBENDPOINT_URL, {
|
||||
...commonOptions,
|
||||
const hubConnection = getConnectionBuilder(HttpTransportType.LongPolling, TESTHUBENDPOINT_URL, {
|
||||
httpClient: testClient,
|
||||
});
|
||||
}).build();
|
||||
|
||||
try {
|
||||
await hubConnection.start();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
import { HubConnection } from "../src/HubConnection";
|
||||
import { IHubConnectionOptions } from "../src/HubConnection";
|
||||
import { HubConnection, JsonHubProtocol } from "../src/HubConnection";
|
||||
import { IConnection } from "../src/IConnection";
|
||||
import { HubMessage, IHubProtocol, MessageType } from "../src/IHubProtocol";
|
||||
import { ILogger, LogLevel } from "../src/ILogger";
|
||||
import { HttpTransportType, ITransport, TransferFormat } from "../src/ITransport";
|
||||
import { NullLogger } from "../src/Loggers";
|
||||
import { IStreamSubscriber } from "../src/Stream";
|
||||
import { TextMessageFormat } from "../src/TextMessageFormat";
|
||||
|
||||
import { asyncit as it, captureException, delay, PromiseSource } from "./Utils";
|
||||
|
||||
const commonOptions: IHubConnectionOptions = {
|
||||
logger: null,
|
||||
};
|
||||
function createHubConnection(connection: IConnection, logger?: ILogger, protocol?: IHubProtocol) {
|
||||
return new HubConnection(connection, logger || NullLogger.instance, protocol || new JsonHubProtocol());
|
||||
}
|
||||
|
||||
describe("HubConnection", () => {
|
||||
|
||||
describe("start", () => {
|
||||
it("sends negotiation message", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
await hubConnection.start();
|
||||
expect(connection.sentData.length).toBe(1);
|
||||
expect(JSON.parse(connection.sentData[0])).toEqual({
|
||||
|
|
@ -36,7 +36,7 @@ describe("HubConnection", () => {
|
|||
it("sends a non blocking invocation", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
const invokePromise = hubConnection.send("testMethod", "arg", 42)
|
||||
.catch((_) => { }); // Suppress exception and unhandled promise rejection warning.
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ describe("HubConnection", () => {
|
|||
it("sends an invocation", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
const invokePromise = hubConnection.invoke("testMethod", "arg", 42)
|
||||
.catch((_) => { }); // Suppress exception and unhandled promise rejection warning.
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ describe("HubConnection", () => {
|
|||
};
|
||||
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { logger: null, protocol: mockProtocol });
|
||||
const hubConnection = createHubConnection(connection, null, mockProtocol);
|
||||
|
||||
const data = "{}" + TextMessageFormat.RecordSeparator;
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ describe("HubConnection", () => {
|
|||
};
|
||||
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { logger: null, protocol: mockProtocol });
|
||||
const hubConnection = createHubConnection(connection, null, mockProtocol);
|
||||
|
||||
// handshake response + message separator
|
||||
const data = [0x7b, 0x7d, 0x1e];
|
||||
|
|
@ -126,7 +126,7 @@ describe("HubConnection", () => {
|
|||
mockProtocol.onreceive = (d) => receivedProcotolData = d as ArrayBuffer;
|
||||
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { logger: null, protocol: mockProtocol });
|
||||
const hubConnection = createHubConnection(connection, null, mockProtocol);
|
||||
|
||||
// handshake response + message separator + message pack message
|
||||
const data = [
|
||||
|
|
@ -151,7 +151,7 @@ describe("HubConnection", () => {
|
|||
mockProtocol.onreceive = (d) => receivedProcotolData = d as string;
|
||||
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { logger: null, protocol: mockProtocol });
|
||||
const hubConnection = createHubConnection(connection, null, mockProtocol);
|
||||
|
||||
const data = "{}" + TextMessageFormat.RecordSeparator + "{\"type\":6}" + TextMessageFormat.RecordSeparator;
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("rejects the promise when an error is received", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
const invokePromise = hubConnection.invoke("testMethod", "arg", 42);
|
||||
|
|
@ -175,7 +175,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("resolves the promise when a result is received", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
const invokePromise = hubConnection.invoke("testMethod", "arg", 42);
|
||||
|
|
@ -188,7 +188,7 @@ describe("HubConnection", () => {
|
|||
it("completes pending invocations when stopped", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -202,7 +202,7 @@ describe("HubConnection", () => {
|
|||
it("completes pending invocations when connection is lost", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -226,7 +226,7 @@ describe("HubConnection", () => {
|
|||
},
|
||||
} as ILogger;
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { logger });
|
||||
const hubConnection = createHubConnection(connection, logger);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ describe("HubConnection", () => {
|
|||
},
|
||||
} as ILogger;
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { logger });
|
||||
const hubConnection = createHubConnection(connection, logger);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -271,7 +271,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("all handlers can be unregistered with just the method name", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -304,7 +304,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("a single handler can be unregistered with the method name and handler", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -337,7 +337,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("can't register the same handler multiple times", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -359,7 +359,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("callback invoked when servers invokes a method on the client", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -379,7 +379,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("stop on handshake error", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
let closeError: Error = null;
|
||||
hubConnection.onclose((e) => closeError = e);
|
||||
|
|
@ -391,7 +391,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("stop on close message", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
let isClosed = false;
|
||||
let closeError: Error = null;
|
||||
|
|
@ -412,7 +412,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("stop on error close message", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
let isClosed = false;
|
||||
let closeError: Error = null;
|
||||
|
|
@ -434,7 +434,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("can have multiple callbacks", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -457,7 +457,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("can unsubscribe from on", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -488,7 +488,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("unsubscribing from non-existing callbacks no-ops", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
hubConnection.off("_", () => { });
|
||||
hubConnection.on("message", (t) => { });
|
||||
|
|
@ -507,7 +507,7 @@ describe("HubConnection", () => {
|
|||
} as ILogger;
|
||||
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { logger });
|
||||
const hubConnection = createHubConnection(connection, logger);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -542,7 +542,7 @@ describe("HubConnection", () => {
|
|||
it("sends an invocation", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
const invokePromise = hubConnection.stream("testStream", "arg", 42);
|
||||
|
||||
// Verify the message is sent
|
||||
|
|
@ -563,7 +563,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("completes with an error when an error is yielded", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -579,7 +579,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("completes the observer when a completion is received", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -595,7 +595,7 @@ describe("HubConnection", () => {
|
|||
it("completes pending streams when stopped", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
const observer = new TestObserver();
|
||||
hubConnection.stream<any>("testMethod")
|
||||
.subscribe(observer);
|
||||
|
|
@ -608,7 +608,7 @@ describe("HubConnection", () => {
|
|||
it("completes pending streams when connection is lost", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
const observer = new TestObserver();
|
||||
hubConnection.stream<any>("testMethod")
|
||||
.subscribe(observer);
|
||||
|
|
@ -622,7 +622,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("yields items as they arrive", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -646,7 +646,7 @@ describe("HubConnection", () => {
|
|||
it("does not require error function registered", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
const observer = hubConnection.stream("testMethod").subscribe(NullSubscriber.instance);
|
||||
|
||||
// Typically this would be called by the transport
|
||||
|
|
@ -657,7 +657,7 @@ describe("HubConnection", () => {
|
|||
it("does not require complete function registered", async () => {
|
||||
const connection = new TestConnection();
|
||||
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
const observer = hubConnection.stream("testMethod").subscribe(NullSubscriber.instance);
|
||||
|
||||
// Send completion to trigger observer.complete()
|
||||
|
|
@ -667,7 +667,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("can be canceled", () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
|
||||
connection.receiveHandshakeResponse();
|
||||
|
||||
|
|
@ -696,7 +696,7 @@ describe("HubConnection", () => {
|
|||
describe("onClose", () => {
|
||||
it("can have multiple callbacks", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
let invocations = 0;
|
||||
hubConnection.onclose((e) => invocations++);
|
||||
hubConnection.onclose((e) => invocations++);
|
||||
|
|
@ -707,7 +707,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("callbacks receive error", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
let error: Error;
|
||||
hubConnection.onclose((e) => error = e);
|
||||
|
||||
|
|
@ -718,7 +718,7 @@ describe("HubConnection", () => {
|
|||
|
||||
it("ignores null callbacks", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
hubConnection.onclose(null);
|
||||
hubConnection.onclose(undefined);
|
||||
// Typically this would be called by the transport
|
||||
|
|
@ -732,7 +732,7 @@ describe("HubConnection", () => {
|
|||
// Receive the ping mid-invocation so we can see that the rest of the flow works fine
|
||||
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, commonOptions);
|
||||
const hubConnection = createHubConnection(connection);
|
||||
const invokePromise = hubConnection.invoke("testMethod", "arg", 42);
|
||||
|
||||
connection.receive({ type: MessageType.Ping });
|
||||
|
|
@ -743,7 +743,8 @@ describe("HubConnection", () => {
|
|||
|
||||
it("does not terminate if messages are received", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 });
|
||||
const hubConnection = createHubConnection(connection);
|
||||
hubConnection.serverTimeoutInMilliseconds = 100;
|
||||
|
||||
const p = new PromiseSource<Error>();
|
||||
hubConnection.onclose((e) => p.resolve(e));
|
||||
|
|
@ -768,7 +769,8 @@ describe("HubConnection", () => {
|
|||
|
||||
it("does not timeout if message was received before HubConnection.start", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 });
|
||||
const hubConnection = createHubConnection(connection);
|
||||
hubConnection.serverTimeoutInMilliseconds = 100;
|
||||
|
||||
const p = new PromiseSource<Error>();
|
||||
hubConnection.onclose((e) => p.resolve(e));
|
||||
|
|
@ -795,7 +797,8 @@ describe("HubConnection", () => {
|
|||
|
||||
it("terminates if no messages received within timeout interval", async () => {
|
||||
const connection = new TestConnection();
|
||||
const hubConnection = new HubConnection(connection, { ...commonOptions, timeoutInMilliseconds: 100 });
|
||||
const hubConnection = createHubConnection(connection);
|
||||
hubConnection.serverTimeoutInMilliseconds = 100;
|
||||
|
||||
const p = new PromiseSource<Error>();
|
||||
hubConnection.onclose((e) => p.resolve(e));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,245 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
import { HubConnectionBuilder } from "../src/HubConnectionBuilder";
|
||||
|
||||
import { HubConnection } from "../src";
|
||||
import { HttpRequest, HttpResponse } from "../src/HttpClient";
|
||||
import { IHttpConnectionOptions } from "../src/HttpConnection";
|
||||
import { HubMessage, IHubProtocol } from "../src/IHubProtocol";
|
||||
import { ILogger, LogLevel } from "../src/ILogger";
|
||||
import { TransferFormat, HttpTransportType } from "../src/ITransport";
|
||||
import { NullLogger } from "../src/Loggers";
|
||||
import { TestHttpClient } from "./TestHttpClient";
|
||||
import { asyncit as it, PromiseSource } from "./Utils";
|
||||
|
||||
const allTransportsNegotiateResponse = {
|
||||
availableTransports: [
|
||||
{ transport: "WebSockets", transferFormats: ["Text", "Binary"] },
|
||||
{ transport: "ServerSentEvents", transferFormats: ["Text"] },
|
||||
{ transport: "LongPolling", transferFormats: ["Text", "Binary"] },
|
||||
],
|
||||
connectionId: "abc123",
|
||||
};
|
||||
|
||||
const longPollingNegotiateResponse = {
|
||||
availableTransports: [
|
||||
{ transport: "LongPolling", transferFormats: ["Text", "Binary"] },
|
||||
],
|
||||
connectionId: "abc123",
|
||||
};
|
||||
|
||||
const commonHttpOptions: IHttpConnectionOptions = {
|
||||
logMessageContent: true,
|
||||
};
|
||||
|
||||
describe("HubConnectionBuilder", () => {
|
||||
eachMissingValue((val, name) => {
|
||||
it(`configureLogging throws if logger is ${name}`, () => {
|
||||
const builder = new HubConnectionBuilder();
|
||||
expect(() => builder.configureLogging(val)).toThrow(new Error("The 'logging' argument is required."));
|
||||
});
|
||||
|
||||
it(`withUrl throws if url is ${name}`, () => {
|
||||
const builder = new HubConnectionBuilder();
|
||||
expect(() => builder.withUrl(val)).toThrow(new Error("The 'url' argument is required."));
|
||||
});
|
||||
|
||||
it(`withHubProtocol throws if protocol is ${name}`, () => {
|
||||
const builder = new HubConnectionBuilder();
|
||||
expect(() => builder.withHubProtocol(val)).toThrow(new Error("The 'protocol' argument is required."));
|
||||
});
|
||||
});
|
||||
|
||||
it("builds HubConnection with HttpConnection using provided URL", async () => {
|
||||
const pollSent = new PromiseSource<HttpRequest>();
|
||||
const pollCompleted = new PromiseSource<HttpResponse>();
|
||||
const testClient = createTestClient(pollSent, pollCompleted.promise)
|
||||
.on("POST", "http://example.com?id=abc123", (req) => {
|
||||
// Respond from the poll with the handshake response
|
||||
pollCompleted.resolve(new HttpResponse(204, "No Content", "{}"));
|
||||
return new HttpResponse(202);
|
||||
});
|
||||
const connection = createConnectionBuilder()
|
||||
.withUrl("http://example.com", {
|
||||
...commonHttpOptions,
|
||||
httpClient: testClient,
|
||||
})
|
||||
.build();
|
||||
|
||||
// Start the connection
|
||||
const closed = makeClosedPromise(connection);
|
||||
await connection.start();
|
||||
|
||||
const pollRequest = await pollSent.promise;
|
||||
expect(pollRequest.url).toMatch(/http:\/\/example.com\?id=abc123.*/);
|
||||
|
||||
await closed;
|
||||
});
|
||||
|
||||
it("can configure transport type", async () => {
|
||||
const protocol = new TestProtocol();
|
||||
|
||||
const pollSent = new PromiseSource<HttpRequest>();
|
||||
const pollCompleted = new PromiseSource<HttpResponse>();
|
||||
const negotiateReceived = new PromiseSource<HttpRequest>();
|
||||
const testClient = createTestClient(pollSent, pollCompleted.promise, allTransportsNegotiateResponse);
|
||||
|
||||
const builder = createConnectionBuilder()
|
||||
.withUrl("http://example.com", HttpTransportType.WebSockets)
|
||||
.withHubProtocol(protocol);
|
||||
expect(builder.httpConnectionOptions.transport).toBe(HttpTransportType.WebSockets);
|
||||
});
|
||||
|
||||
it("can configure hub protocol", async () => {
|
||||
const protocol = new TestProtocol();
|
||||
|
||||
const pollSent = new PromiseSource<HttpRequest>();
|
||||
const pollCompleted = new PromiseSource<HttpResponse>();
|
||||
const negotiateReceived = new PromiseSource<HttpRequest>();
|
||||
const testClient = createTestClient(pollSent, pollCompleted.promise)
|
||||
.on("POST", "http://example.com?id=abc123", (req) => {
|
||||
// Respond from the poll with the handshake response
|
||||
negotiateReceived.resolve(req);
|
||||
pollCompleted.resolve(new HttpResponse(204, "No Content", "{}"));
|
||||
return new HttpResponse(202);
|
||||
});
|
||||
|
||||
const connection = createConnectionBuilder()
|
||||
.withUrl("http://example.com", {
|
||||
...commonHttpOptions,
|
||||
httpClient: testClient,
|
||||
})
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
|
||||
// Start the connection
|
||||
const closed = makeClosedPromise(connection);
|
||||
await connection.start();
|
||||
|
||||
const negotiateRequest = await negotiateReceived.promise;
|
||||
expect(negotiateRequest.content).toBe(`{"protocol":"${protocol.name}","version":1}\x1E`);
|
||||
|
||||
await closed;
|
||||
});
|
||||
|
||||
|
||||
it("allows logger to be replaced", async () => {
|
||||
let loggedMessages = 0;
|
||||
const logger = {
|
||||
log() {
|
||||
loggedMessages += 1;
|
||||
}
|
||||
}
|
||||
const connection = createConnectionBuilder(logger)
|
||||
.withUrl("http://example.com")
|
||||
.build();
|
||||
|
||||
try {
|
||||
await connection.start();
|
||||
} catch {
|
||||
// Ignore failures
|
||||
}
|
||||
|
||||
expect(loggedMessages).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("uses logger for both HttpConnection and HubConnection", async () => {
|
||||
const logger = new CaptureLogger();
|
||||
const connection = createConnectionBuilder(logger)
|
||||
.withUrl("http://example.com")
|
||||
.build();
|
||||
|
||||
try {
|
||||
await connection.start();
|
||||
} catch {
|
||||
// Ignore failures
|
||||
}
|
||||
|
||||
// A HubConnection message
|
||||
expect(logger.messages).toContain("Starting HubConnection.");
|
||||
|
||||
// An HttpConnection message
|
||||
expect(logger.messages).toContain("Starting connection with transfer format 'Text'.");
|
||||
});
|
||||
|
||||
it("does not replace HttpConnectionOptions logger if provided", async () => {
|
||||
const hubConnectionLogger = new CaptureLogger();
|
||||
const httpConnectionLogger = new CaptureLogger();
|
||||
const connection = createConnectionBuilder(hubConnectionLogger)
|
||||
.withUrl("http://example.com", { logger: httpConnectionLogger })
|
||||
.build();
|
||||
|
||||
try {
|
||||
await connection.start();
|
||||
} catch {
|
||||
// Ignore failures
|
||||
}
|
||||
|
||||
// A HubConnection message
|
||||
expect(hubConnectionLogger.messages).toContain("Starting HubConnection.");
|
||||
expect(httpConnectionLogger.messages).not.toContain("Starting HubConnection.");
|
||||
|
||||
// An HttpConnection message
|
||||
expect(httpConnectionLogger.messages).toContain("Starting connection with transfer format 'Text'.");
|
||||
expect(hubConnectionLogger.messages).not.toContain("Starting connection with transfer format 'Text'.");
|
||||
});
|
||||
});
|
||||
|
||||
class CaptureLogger implements ILogger {
|
||||
public readonly messages: string[] = [];
|
||||
|
||||
public log(logLevel: LogLevel, message: string): void {
|
||||
this.messages.push(message);
|
||||
}
|
||||
}
|
||||
|
||||
class TestProtocol implements IHubProtocol {
|
||||
public name: string = "test";
|
||||
public version: number = 1;
|
||||
public transferFormat: TransferFormat = TransferFormat.Text;
|
||||
public parseMessages(input: any, logger: ILogger): HubMessage[] {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
public writeMessage(message: HubMessage) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
function createConnectionBuilder(logger?: ILogger | LogLevel): HubConnectionBuilder {
|
||||
// We don't want to spam test output with logs. This can be changed as needed
|
||||
return new HubConnectionBuilder()
|
||||
.configureLogging(logger || NullLogger.instance);
|
||||
}
|
||||
|
||||
function createTestClient(pollSent: PromiseSource<HttpRequest>, pollCompleted: Promise<HttpResponse>, negotiateResponse?: any): TestHttpClient {
|
||||
let firstRequest = true;
|
||||
return new TestHttpClient()
|
||||
.on("POST", "http://example.com/negotiate", () => negotiateResponse || longPollingNegotiateResponse)
|
||||
.on("GET", /http:\/\/example.com\?id=abc123&_=.*/, (req) => {
|
||||
if (firstRequest) {
|
||||
firstRequest = false;
|
||||
return new HttpResponse(200);
|
||||
} else {
|
||||
pollSent.resolve(req);
|
||||
return pollCompleted;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function makeClosedPromise(connection: HubConnection): Promise<void> {
|
||||
const closed = new PromiseSource();
|
||||
connection.onclose((error) => {
|
||||
if (error) {
|
||||
closed.reject(error);
|
||||
} else {
|
||||
closed.resolve();
|
||||
}
|
||||
});
|
||||
return closed.promise;
|
||||
}
|
||||
|
||||
function eachMissingValue(callback: (val: undefined | null, name: string) => void) {
|
||||
callback(null, "null");
|
||||
callback(undefined, "undefined");
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import { HttpClient, HttpRequest, HttpResponse } from "../src/HttpClient";
|
||||
|
||||
type TestHttpHandlerResult = any;
|
||||
type TestHttpHandlerResult = string | HttpResponse | any;
|
||||
export type TestHttpHandler = (request: HttpRequest, next?: (request: HttpRequest) => Promise<HttpResponse>) => Promise<TestHttpHandlerResult> | TestHttpHandlerResult;
|
||||
|
||||
export class TestHttpClient extends HttpClient {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export function delay(durationInMilliseconds: number): Promise<void> {
|
|||
return source.promise;
|
||||
}
|
||||
|
||||
export class PromiseSource<T> {
|
||||
export class PromiseSource<T = void> {
|
||||
public promise: Promise<T>;
|
||||
|
||||
private resolver: (value?: T | PromiseLike<T>) => void;
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@ export interface HttpRequest {
|
|||
}
|
||||
|
||||
export class HttpResponse {
|
||||
constructor(statusCode: number);
|
||||
constructor(statusCode: number, statusText: string);
|
||||
constructor(statusCode: number, statusText: string, content: string);
|
||||
constructor(statusCode: number, statusText: string, content: ArrayBuffer);
|
||||
constructor(
|
||||
public readonly statusCode: number,
|
||||
public readonly statusText: string,
|
||||
public readonly content: string | ArrayBuffer) {
|
||||
public readonly statusText?: string,
|
||||
public readonly content?: string | ArrayBuffer) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,15 +10,10 @@ import { JsonHubProtocol } from "./JsonHubProtocol";
|
|||
import { NullLogger } from "./Loggers";
|
||||
import { IStreamResult } from "./Stream";
|
||||
import { TextMessageFormat } from "./TextMessageFormat";
|
||||
import { createLogger, Subject } from "./Utils";
|
||||
import { Arg, createLogger, Subject } from "./Utils";
|
||||
|
||||
export { JsonHubProtocol };
|
||||
|
||||
export interface IHubConnectionOptions extends IHttpConnectionOptions {
|
||||
protocol?: IHubProtocol;
|
||||
timeoutInMilliseconds?: number;
|
||||
}
|
||||
|
||||
const DEFAULT_TIMEOUT_IN_MS: number = 30 * 1000;
|
||||
|
||||
export class HubConnection {
|
||||
|
|
@ -31,27 +26,22 @@ export class HubConnection {
|
|||
private id: number;
|
||||
private closedCallbacks: Array<(error?: Error) => void>;
|
||||
private timeoutHandle: NodeJS.Timer;
|
||||
private timeoutInMilliseconds: number;
|
||||
private receivedHandshakeResponse: boolean;
|
||||
|
||||
constructor(url: string, options?: IHubConnectionOptions);
|
||||
constructor(connection: IConnection, options?: IHubConnectionOptions);
|
||||
constructor(urlOrConnection: string | IConnection, options: IHubConnectionOptions = {}) {
|
||||
options = options || {};
|
||||
public serverTimeoutInMilliseconds: number;
|
||||
|
||||
this.timeoutInMilliseconds = options.timeoutInMilliseconds || DEFAULT_TIMEOUT_IN_MS;
|
||||
constructor(connection: IConnection, logger: ILogger, protocol: IHubProtocol) {
|
||||
Arg.isRequired(connection, "connection");
|
||||
Arg.isRequired(logger, "logger");
|
||||
Arg.isRequired(protocol, "protocol");
|
||||
|
||||
this.protocol = options.protocol || new JsonHubProtocol();
|
||||
this.serverTimeoutInMilliseconds = DEFAULT_TIMEOUT_IN_MS;
|
||||
|
||||
this.logger = logger;
|
||||
this.protocol = protocol;
|
||||
this.connection = connection;
|
||||
this.handshakeProtocol = new HandshakeProtocol();
|
||||
|
||||
if (typeof urlOrConnection === "string") {
|
||||
this.connection = new HttpConnection(urlOrConnection, options);
|
||||
} else {
|
||||
this.connection = urlOrConnection;
|
||||
}
|
||||
|
||||
this.logger = createLogger(options.logger);
|
||||
|
||||
this.connection.onreceive = (data: any) => this.processIncomingData(data);
|
||||
this.connection.onclose = (error?: Error) => this.connectionClosed(error);
|
||||
|
||||
|
|
@ -293,7 +283,7 @@ export class HubConnection {
|
|||
private configureTimeout() {
|
||||
if (!this.connection.features || !this.connection.features.inherentKeepAlive) {
|
||||
// Set the timeout timer
|
||||
this.timeoutHandle = setTimeout(() => this.serverTimeout(), this.timeoutInMilliseconds);
|
||||
this.timeoutHandle = setTimeout(() => this.serverTimeout(), this.serverTimeoutInMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
import { HttpConnection, IHttpConnectionOptions } from "./HttpConnection";
|
||||
import { HubConnection, JsonHubProtocol } from "./HubConnection";
|
||||
import { IHubProtocol } from "./IHubProtocol";
|
||||
import { ILogger, LogLevel } from "./ILogger";
|
||||
import { HttpTransportType } from "./ITransport";
|
||||
import { NullLogger } from "./Loggers";
|
||||
import { Arg, ConsoleLogger } from "./Utils";
|
||||
|
||||
export class HubConnectionBuilder {
|
||||
/** @internal */
|
||||
public protocol: IHubProtocol;
|
||||
/** @internal */
|
||||
public httpConnectionOptions: IHttpConnectionOptions;
|
||||
/** @internal */
|
||||
public url: string;
|
||||
/** @internal */
|
||||
public logger: ILogger;
|
||||
|
||||
public configureLogging(logging: LogLevel | ILogger): HubConnectionBuilder {
|
||||
Arg.isRequired(logging, "logging");
|
||||
|
||||
if (isLogger(logging)) {
|
||||
this.logger = logging;
|
||||
} else {
|
||||
this.logger = new ConsoleLogger(logging);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public withUrl(url: string): HubConnectionBuilder;
|
||||
public withUrl(url: string, options: IHttpConnectionOptions): HubConnectionBuilder;
|
||||
public withUrl(url: string, transportType: HttpTransportType): HubConnectionBuilder;
|
||||
public withUrl(url: string, transportTypeOrOptions?: IHttpConnectionOptions | HttpTransportType): HubConnectionBuilder {
|
||||
Arg.isRequired(url, "url");
|
||||
|
||||
this.url = url;
|
||||
|
||||
// Flow-typing knows where it's at. Since HttpTransportType is a number and IHttpConnectionOptions is guaranteed
|
||||
// to be an object, we know (as does TypeScript) this comparison is all we need to figure out which overload was called.
|
||||
if (typeof transportTypeOrOptions === "object") {
|
||||
this.httpConnectionOptions = transportTypeOrOptions;
|
||||
} else {
|
||||
this.httpConnectionOptions = {
|
||||
transport: transportTypeOrOptions,
|
||||
};
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public withHubProtocol(protocol: IHubProtocol): HubConnectionBuilder {
|
||||
Arg.isRequired(protocol, "protocol");
|
||||
|
||||
this.protocol = protocol;
|
||||
return this;
|
||||
}
|
||||
|
||||
public build(): HubConnection {
|
||||
// If httpConnectionOptions has a logger, use it. Otherwise, override it with the one
|
||||
// provided to configureLogger
|
||||
const httpConnectionOptions = this.httpConnectionOptions || {};
|
||||
|
||||
// If it's 'null', the user **explicitly** asked for null, don't mess with it.
|
||||
if (httpConnectionOptions.logger === undefined) {
|
||||
// If our logger is undefined or null, that's OK, the HttpConnection constructor will handle it.
|
||||
httpConnectionOptions.logger = this.logger;
|
||||
}
|
||||
|
||||
// Now create the connection
|
||||
if (!this.url) {
|
||||
throw new Error("The 'HubConnectionBuilder.withUrl' method must be called before building the connection.");
|
||||
}
|
||||
const connection = new HttpConnection(this.url, httpConnectionOptions);
|
||||
|
||||
return new HubConnection(
|
||||
connection,
|
||||
this.logger || NullLogger.instance,
|
||||
this.protocol || new JsonHubProtocol());
|
||||
}
|
||||
}
|
||||
|
||||
function isLogger(logger: any): logger is ILogger {
|
||||
return logger.log !== undefined;
|
||||
}
|
||||
|
|
@ -164,11 +164,8 @@ export class ConsoleLogger implements ILogger {
|
|||
case LogLevel.Information:
|
||||
console.info(`${LogLevel[logLevel]}: ${message}`);
|
||||
break;
|
||||
case LogLevel.Trace:
|
||||
case LogLevel.Debug:
|
||||
console.debug(`${LogLevel[logLevel]}: ${message}`);
|
||||
break;
|
||||
default:
|
||||
// console.debug only goes to attached debuggers in Node, so we use console.log for Trace and Debug
|
||||
console.log(`${LogLevel[logLevel]}: ${message}`);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export * from "./Errors";
|
|||
export * from "./HttpClient";
|
||||
export * from "./HttpConnection";
|
||||
export * from "./HubConnection";
|
||||
export * from "./HubConnectionBuilder";
|
||||
export * from "./IConnection";
|
||||
export * from "./IHubProtocol";
|
||||
export * from "./ILogger";
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
"noImplicitAny": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noEmitOnError": true,
|
||||
"stripInternal": true,
|
||||
"lib": [ "es5", "es2015.promise", "es2015.iterable", "dom" ]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,10 @@
|
|||
<script src="lib/signalr-client/signalr.js"></script>
|
||||
<script>
|
||||
let transportType = signalR.HttpTransportType[getParameterByName('transport')] || signalR.HttpTransportType.WebSockets;
|
||||
let connection = new signalR.HubConnection('/chat', { transport: transportType, logger: signalR.LogLevel.Information });
|
||||
let connection = new signalR.HubConnectionBuilder()
|
||||
.configureLogging(signalR.LogLevel.Information)
|
||||
.withUrl("/chat", transportType)
|
||||
.build();
|
||||
|
||||
connection.onclose(e => {
|
||||
if (e) {
|
||||
|
|
|
|||
|
|
@ -70,8 +70,11 @@
|
|||
transport: transportType,
|
||||
accessTokenFactory: function () { return tokens[clientId]; }
|
||||
};
|
||||
connection = new signalR.HubConnectionBuilder()
|
||||
.withUrl("/broadcast", options)
|
||||
.configureLogging(signalR.LogLevel.Information)
|
||||
.build();
|
||||
|
||||
connection = new signalR.HubConnection('/broadcast', options);
|
||||
connection.on('Message', function (from, message) {
|
||||
appendLog(clientId, from + ': ' + message);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -139,14 +139,17 @@
|
|||
new signalR.protocols.msgpack.MessagePackHubProtocol() :
|
||||
new signalR.JsonHubProtocol();
|
||||
|
||||
let options = { logger: signalR.LogLevel.Trace, protocol: protocol };
|
||||
|
||||
var options = {};
|
||||
if (transportDropdown.value !== "Automatic") {
|
||||
options.transport = signalR.HttpTransportType[transportDropdown.value];
|
||||
}
|
||||
|
||||
console.log('http://' + document.location.host + '/' + hubRoute);
|
||||
connection = new signalR.HubConnection(hubRoute, options);
|
||||
connection = new signalR.HubConnectionBuilder()
|
||||
.configureLogging(signalR.LogLevel.Trace)
|
||||
.withUrl(hubRoute, options)
|
||||
.withHubProtocol(protocol)
|
||||
.build();
|
||||
connection.on('Send', function (msg) {
|
||||
addLine('message-list', msg);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -53,7 +53,10 @@
|
|||
});
|
||||
|
||||
click('connectButton', function () {
|
||||
connection = new signalR.HubConnection('/streaming', { transport: transportType, logger: signalR.LogLevel.Trace });
|
||||
connection = new signalR.HubConnectionBuilder()
|
||||
.configureLogging(signalR.LogLevel.Trace)
|
||||
.withUrl("/streaming", transportType)
|
||||
.build();
|
||||
|
||||
connection.onclose(function () {
|
||||
channelButton.disabled = true;
|
||||
|
|
|
|||
Loading…
Reference in New Issue