Decouple IConnection.ts and HubConnection.ts from http (#566)

* Decouple IConnection.ts and HubConnection.ts from http
- Removed TransportType from start
- Renamed Connection.ts to HttpConnection.ts
This commit is contained in:
David Fowler 2017-06-16 06:54:55 +02:00 committed by GitHub
parent 0298868c00
commit d169b96d2d
12 changed files with 84 additions and 81 deletions

View File

@ -1,6 +1,6 @@
import { IHttpClient } from "../Microsoft.AspNetCore.SignalR.Client.TS/HttpClient"
import { Connection } from "../Microsoft.AspNetCore.SignalR.Client.TS/Connection"
import { ISignalROptions } from "../Microsoft.AspNetCore.SignalR.Client.TS/ISignalROptions"
import { HttpConnection } from "../Microsoft.AspNetCore.SignalR.Client.TS/HttpConnection"
import { IHttpConnectionOptions } from "../Microsoft.AspNetCore.SignalR.Client.TS/IHttpConnectionOptions"
import { DataReceived, TransportClosed } from "../Microsoft.AspNetCore.SignalR.Client.TS/Common"
import { ITransport, TransportType } from "../Microsoft.AspNetCore.SignalR.Client.TS/Transports"
import { eachTransport } from "./Common";
@ -8,7 +8,7 @@ import { eachTransport } from "./Common";
describe("Connection", () => {
it("starting connection fails if getting id fails", async (done) => {
let options: ISignalROptions = {
let options: IHttpConnectionOptions = {
httpClient: <IHttpClient>{
options(url: string): Promise<string> {
return Promise.reject("error");
@ -17,9 +17,9 @@ describe("Connection", () => {
return Promise.resolve("");
}
}
} as ISignalROptions;
} as IHttpConnectionOptions;
let connection = new Connection("http://tempuri.org", options);
let connection = new HttpConnection("http://tempuri.org", options);
try {
await connection.start();
@ -33,28 +33,28 @@ describe("Connection", () => {
});
it("cannot start a running connection", async (done) => {
let options: ISignalROptions = {
let options: IHttpConnectionOptions = {
httpClient: <IHttpClient>{
options(url: string): Promise<string> {
connection.start()
.then(() => {
fail();
done();
})
.catch((error: Error) => {
expect(error.message).toBe("Cannot start a connection that is not in the 'Initial' state.");
done();
});
.then(() => {
fail();
done();
})
.catch((error: Error) => {
expect(error.message).toBe("Cannot start a connection that is not in the 'Initial' state.");
done();
});
return Promise.reject("error");
return Promise.reject("error");
},
get(url: string): Promise<string> {
return Promise.resolve("");
}
}
} as ISignalROptions;
} as IHttpConnectionOptions;
let connection = new Connection("http://tempuri.org", options);
let connection = new HttpConnection("http://tempuri.org", options);
try {
await connection.start();
@ -66,7 +66,7 @@ describe("Connection", () => {
});
it("cannot start a stopped connection", async (done) => {
let options: ISignalROptions = {
let options: IHttpConnectionOptions = {
httpClient: <IHttpClient>{
options(url: string): Promise<string> {
return Promise.reject("error");
@ -75,9 +75,9 @@ describe("Connection", () => {
return Promise.resolve("");
}
}
} as ISignalROptions;
} as IHttpConnectionOptions;
let connection = new Connection("http://tempuri.org", options);
let connection = new HttpConnection("http://tempuri.org", options);
try {
// start will fail and transition the connection to the Disconnected state
@ -99,7 +99,7 @@ describe("Connection", () => {
});
it("can stop a starting connection", async (done) => {
let options: ISignalROptions = {
let options: IHttpConnectionOptions = {
httpClient: <IHttpClient>{
options(url: string): Promise<string> {
connection.stop();
@ -110,9 +110,9 @@ describe("Connection", () => {
return Promise.resolve("");
}
}
} as ISignalROptions;
} as IHttpConnectionOptions;
var connection = new Connection("http://tempuri.org", options);
var connection = new HttpConnection("http://tempuri.org", options);
try {
await connection.start();
@ -125,23 +125,12 @@ describe("Connection", () => {
});
it("can stop a non-started connection", async (done) => {
var connection = new Connection("http://tempuri.org");
var connection = new HttpConnection("http://tempuri.org");
await connection.stop();
done();
});
it("preserves users connection string", async done => {
let options: ISignalROptions = {
httpClient: <IHttpClient>{
options(url: string): Promise<string> {
return Promise.resolve("{ \"connectionId\": \"42\" }");
},
get(url: string): Promise<string> {
return Promise.resolve("");
}
}
} as ISignalROptions;
let connectUrl: string;
let fakeTransport: ITransport = {
connect(url: string): Promise<void> {
@ -156,10 +145,23 @@ describe("Connection", () => {
onClosed: undefined
}
var connection = new Connection("http://tempuri.org?q=myData", options);
let options: IHttpConnectionOptions = {
httpClient: <IHttpClient>{
options(url: string): Promise<string> {
return Promise.resolve("{ \"connectionId\": \"42\" }");
},
get(url: string): Promise<string> {
return Promise.resolve("");
}
},
transport: fakeTransport
} as IHttpConnectionOptions;
var connection = new HttpConnection("http://tempuri.org?q=myData", options);
try {
await connection.start(fakeTransport);
await connection.start();
fail();
done();
}
@ -172,7 +174,7 @@ describe("Connection", () => {
eachTransport((requestedTransport: TransportType) => {
it(`Connection cannot be started if requested ${TransportType[requestedTransport]} transport not available on server`, async done => {
let options: ISignalROptions = {
let options: IHttpConnectionOptions = {
httpClient: <IHttpClient>{
options(url: string): Promise<string> {
return Promise.resolve("{ \"connectionId\": \"42\", \"availableTransports\": [] }");
@ -180,12 +182,13 @@ describe("Connection", () => {
get(url: string): Promise<string> {
return Promise.resolve("");
}
}
} as ISignalROptions;
},
transport: requestedTransport
} as IHttpConnectionOptions;
var connection = new Connection("http://tempuri.org", options);
var connection = new HttpConnection("http://tempuri.org", options);
try {
await connection.start(requestedTransport);
await connection.start();
fail();
done();
}
@ -197,7 +200,7 @@ describe("Connection", () => {
});
it(`Connection cannot be started if no transport available on server and no transport requested`, async done => {
let options: ISignalROptions = {
let options: IHttpConnectionOptions = {
httpClient: <IHttpClient>{
options(url: string): Promise<string> {
return Promise.resolve("{ \"connectionId\": \"42\", \"availableTransports\": [] }");
@ -206,9 +209,9 @@ describe("Connection", () => {
return Promise.resolve("");
}
}
} as ISignalROptions;
} as IHttpConnectionOptions;
var connection = new Connection("http://tempuri.org", options);
var connection = new HttpConnection("http://tempuri.org", options);
try {
await connection.start();
fail();

View File

@ -211,7 +211,7 @@ describe("HubConnection", () => {
});
class TestConnection implements IConnection {
start(transportType: TransportType | ITransport): Promise<void> {
start(): Promise<void> {
return Promise.resolve();
};

View File

@ -2,7 +2,7 @@ import { DataReceived, ConnectionClosed } from "./Common"
import { IConnection } from "./IConnection"
import { ITransport, TransportType, WebSocketTransport, ServerSentEventsTransport, LongPollingTransport } from "./Transports"
import { IHttpClient, HttpClient } from "./HttpClient"
import { ISignalROptions } from "./ISignalROptions"
import { IHttpConnectionOptions } from "./IHttpConnectionOptions"
enum ConnectionState {
Initial,
@ -16,32 +16,34 @@ interface INegotiateResponse {
availableTransports: string[]
}
export class Connection implements IConnection {
export class HttpConnection implements IConnection {
private connectionState: ConnectionState;
private url: string;
private connectionId: string;
private httpClient: IHttpClient;
private transport: ITransport;
private options: IHttpConnectionOptions;
private startPromise: Promise<void>;
constructor(url: string, options: ISignalROptions = {}) {
constructor(url: string, options: IHttpConnectionOptions = {}) {
this.url = url;
this.httpClient = options.httpClient || new HttpClient();
this.connectionState = ConnectionState.Initial;
this.options = options;
}
async start(transport?: TransportType | ITransport): Promise<void> {
async start(): Promise<void> {
if (this.connectionState != ConnectionState.Initial) {
return Promise.reject(new Error("Cannot start a connection that is not in the 'Initial' state."));
}
this.connectionState = ConnectionState.Connecting;
this.startPromise = this.startInternal(transport);
this.startPromise = this.startInternal();
return this.startPromise;
}
private async startInternal(transportType: TransportType | ITransport): Promise<void> {
private async startInternal(): Promise<void> {
try {
let negotiatePayload = await this.httpClient.options(this.url);
let negotiateResponse: INegotiateResponse = JSON.parse(negotiatePayload);
@ -54,7 +56,7 @@ export class Connection implements IConnection {
this.url += (this.url.indexOf("?") == -1 ? "?" : "&") + `id=${this.connectionId}`;
this.transport = this.createTransport(transportType, negotiateResponse.availableTransports);
this.transport = this.createTransport(this.options.transport, negotiateResponse.availableTransports);
this.transport.onDataReceived = this.onDataReceived;
this.transport.onClosed = e => this.stopConnection(true, e);
await this.transport.connect(this.url);

View File

@ -1,10 +1,9 @@
import { ConnectionClosed } from "./Common"
import { IConnection } from "./IConnection"
import { Connection } from "./Connection"
import { TransportType } from "./Transports"
import { Subject, Observable } from "./Observable"
export { Connection } from "./Connection"
export { TransportType } from "./Transports"
export { HttpConnection } from "./HttpConnection"
import { IHubProtocol, MessageType, HubMessage, CompletionMessage, ResultMessage, InvocationMessage } from "./IHubProtocol";
import { JsonHubProtocol } from "./JsonHubProtocol";
@ -16,14 +15,8 @@ export class HubConnection {
private connectionClosedCallback: ConnectionClosed;
private protocol: IHubProtocol;
static create(url: string, queryString?: string): HubConnection {
return new this(new Connection(url, queryString))
}
constructor(connection: IConnection);
constructor(url: string, queryString?: string);
constructor(connectionOrUrl: IConnection | string, queryString?: string) {
this.connection = typeof connectionOrUrl === "string" ? new Connection(connectionOrUrl, queryString) : connectionOrUrl;
constructor(connection: IConnection) {
this.connection = connection;
this.connection.onDataReceived = data => {
this.onDataReceived(data);
};
@ -96,8 +89,8 @@ export class HubConnection {
}
}
start(transportType?: TransportType): Promise<void> {
return this.connection.start(transportType);
start(): Promise<void> {
return this.connection.start();
}
stop(): void {

View File

@ -2,7 +2,7 @@ import { DataReceived, ConnectionClosed } from "./Common"
import { TransportType, ITransport } from "./Transports"
export interface IConnection {
start(transportType: TransportType | ITransport): Promise<void>;
start(): Promise<void>;
send(data: any): Promise<void>;
stop(): void;

View File

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

View File

@ -1,5 +0,0 @@
import {IHttpClient} from "./HttpClient"
export interface ISignalROptions {
httpClient?: IHttpClient;
}

View File

@ -1,5 +1,5 @@
export * from "./Common"
export * from "./Connection"
export * from "./HttpConnection"
export * from "./HttpClient"
export * from "./HubConnection"
export * from "./Transports"

View File

@ -17,7 +17,8 @@
<script src="lib/signalr-client/signalr-client.js"></script>
<script>
let transportType = signalR.TransportType[getParameterByName('transport')] || signalR.TransportType.WebSockets;
let connection = new signalR.HubConnection(`http://${document.location.host}/chat`, 'formatType=json&format=text');
let http = new signalR.HttpConnection(`http://${document.location.host}/chat`, { transport: transportType });
let connection = new signalR.HubConnection(http);
connection.onClosed = e => {
if (e) {
@ -59,7 +60,7 @@ connection.on('Send', (userName, message) => {
document.getElementById('messages').appendChild(child);
});
connection.start(transportType).catch(err => appendLine(err, 'red'));
connection.start().catch(err => appendLine(err, 'red'));
document.getElementById('sendmessage').addEventListener('submit', event => {
let data = document.getElementById('new-message').value;

View File

@ -81,7 +81,8 @@ let transportType = signalR.TransportType[getParameterByName('transport')] || si
document.getElementById('head1').innerHTML = signalR.TransportType[transportType];
let connection = new signalR.HubConnection(`http://${document.location.host}/hubs`, 'formatType=json&format=text');
let http = new signalR.HttpConnection(`http://${document.location.host}/hubs`, { transport: transportType });
let connection = new signalR.HubConnection(http);
connection.on('Send', msg => {
addLine('message-list', msg);
});
@ -96,7 +97,7 @@ connection.onClosed = e => {
}
click('connect', event => {
connection.start(transportType)
connection.start()
.then(() => {
isConnected = true;
addLine('message-list', 'Connected successfully', 'green');

View File

@ -22,7 +22,7 @@
document.getElementById('transportName').innerHTML = signalR.TransportType[transportType];
let url = `http://${document.location.host}/chat`
let connection = new signalR.Connection(url);
let connection = new signalR.HttpConnection(url, { transport: transportType });
connection.onDataReceived = data => {
let child = document.createElement('li');
@ -36,7 +36,7 @@
event.preventDefault();
});
connection.start(transportType).then(() => {
connection.start().then(() => {
console.log("Opened");
}, () => {
console.log("Error opening connection");

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
@ -53,7 +53,8 @@
});
click('connectButton', function () {
connection = new signalR.HubConnection(url, 'formatType=json&format=text');
let http = new signalR.HttpConnection(url, { transport: transportType });
connection = new signalR.HubConnection(http);
connection.onClosed = function () {
channelButton.disabled = true;
@ -64,7 +65,7 @@
addLine('resultsList', 'disconnected', 'green');
};
connection.start(transportType)
connection.start()
.then(function () {
channelButton.disabled = false;
observableButton.disabled = false;