Adding transport selection
Fixing serverSentEvents transport Updating the client 'app'
This commit is contained in:
parent
752f329036
commit
ce17f0d19a
|
|
@ -5,7 +5,26 @@
|
||||||
<title></title>
|
<title></title>
|
||||||
<script src="js/signalr-client.js"></script>
|
<script src="js/signalr-client.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
function getParameterByName(name, url) {
|
||||||
|
if (!url) {
|
||||||
|
url = window.location.href;
|
||||||
|
}
|
||||||
|
name = name.replace(/[\[\]]/g, "\\$&");
|
||||||
|
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
|
||||||
|
results = regex.exec(url);
|
||||||
|
if (!results) return null;
|
||||||
|
if (!results[2]) return '';
|
||||||
|
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
var transports = getParameterByName('transport');
|
||||||
|
if (transports != null) {
|
||||||
|
transports = transports.split(',')
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('head1').innerHTML = transports ? transports.join(', ') : "auto (WebSockets)";
|
||||||
|
|
||||||
let connectButton = document.getElementById('connect');
|
let connectButton = document.getElementById('connect');
|
||||||
let connection = new RpcConnection(`http://${document.location.host}/hubs`, 'formatType=json&format=text');
|
let connection = new RpcConnection(`http://${document.location.host}/hubs`, 'formatType=json&format=text');
|
||||||
connection.on('Send', msg => {
|
connection.on('Send', msg => {
|
||||||
|
|
@ -13,7 +32,7 @@
|
||||||
let isConnected = false;
|
let isConnected = false;
|
||||||
|
|
||||||
connectButton.addEventListener('click', () => {
|
connectButton.addEventListener('click', () => {
|
||||||
connection.start()
|
connection.start(transports)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
})
|
})
|
||||||
|
|
@ -51,117 +70,10 @@
|
||||||
child.innerText = line;
|
child.innerText = line;
|
||||||
document.getElementById('messages').appendChild(child);
|
document.getElementById('messages').appendChild(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
function hubConnection(url) {
|
|
||||||
var ws = new WebSocket(url);
|
|
||||||
var id = 0;
|
|
||||||
var calls = {};
|
|
||||||
var methods = {};
|
|
||||||
|
|
||||||
ws.onopen = function () {
|
|
||||||
console.log('Opened!');
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.onmessage = function (event) {
|
|
||||||
|
|
||||||
let response = {};
|
|
||||||
|
|
||||||
if (document.getElementById('formatType').value == 'line') {
|
|
||||||
let parts = event.data.split(',');
|
|
||||||
if (event.data[0] == 'R') {
|
|
||||||
response.Id = parts[0].slice(2);
|
|
||||||
response.Result = parts[1].slice(1);
|
|
||||||
}
|
|
||||||
else if (event.data[0] == 'C') {
|
|
||||||
response.Method = parts[1].slice(1);
|
|
||||||
response.Arguments = parts.slice(2).join();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
response.error = parts[0].slice(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
response = JSON.parse(event.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Response
|
|
||||||
if (response.Id) {
|
|
||||||
var cb = calls[response.Id];
|
|
||||||
|
|
||||||
delete calls[response.Id];
|
|
||||||
|
|
||||||
if (response.Error) {
|
|
||||||
cb.error(response.Error);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cb.success(response.Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Reverse JSON RPC
|
|
||||||
methods[response.Method](response.Arguments);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ws.onclose = function (event) {
|
|
||||||
console.log('Closed!');
|
|
||||||
};
|
|
||||||
|
|
||||||
this.invoke = function (method, args, formatType) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
calls[id] = { success: resolve, error: reject };
|
|
||||||
if (formatType == 'line') {
|
|
||||||
ws.send(`CI${id},M${method},${args.join()}\n`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ws.send(JSON.stringify({ method: method, arguments: args, id: id }));
|
|
||||||
}
|
|
||||||
id++;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.on = function (method, fn) {
|
|
||||||
methods[method] = fn;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
let connectButton = document.getElementById('connect');
|
|
||||||
connectButton.addEventListener('click', () => {
|
|
||||||
run(document.getElementById('formatType').value);
|
|
||||||
connectButton.disabled = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function run(formatType) {
|
|
||||||
var conn = new hubConnection(`ws://${document.location.host}/hubs/ws?formatType=${formatType}`);
|
|
||||||
|
|
||||||
conn.on('Send', function (message) {
|
|
||||||
var child = document.createElement('li');
|
|
||||||
child.innerText = message;
|
|
||||||
document.getElementById('messages').appendChild(child);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('sendmessage').addEventListener('submit', event => {
|
|
||||||
let data = document.getElementById('data').value;
|
|
||||||
|
|
||||||
conn.invoke('SocketsSample.Hubs.Chat.Send', [data], formatType).catch(err => {
|
|
||||||
var child = document.createElement('li');
|
|
||||||
child.style.color = 'red';
|
|
||||||
child.innerText = err;
|
|
||||||
document.getElementById('messages').appendChild(child);
|
|
||||||
});
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>WebSockets</h1>
|
<h1 id="head1"></h1>
|
||||||
<div>
|
<div>
|
||||||
<select id="formatType">
|
<select id="formatType">
|
||||||
<option value="json">json</option>
|
<option value="json">json</option>
|
||||||
|
|
|
||||||
|
|
@ -21,18 +21,21 @@ class Connection {
|
||||||
this.connectionState = ConnectionState.Disconnected;
|
this.connectionState = ConnectionState.Disconnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
start(): Promise<void> {
|
start(transportNames?: string[]): Promise<void> {
|
||||||
if (this.connectionState != ConnectionState.Disconnected) {
|
if (this.connectionState != ConnectionState.Disconnected) {
|
||||||
throw new Error("Cannot start a connection that is not in the 'Disconnected' state");
|
throw new Error("Cannot start a connection that is not in the 'Disconnected' state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let transports = this.filterTransports(transportNames);
|
||||||
|
if (transports.length == 0) {
|
||||||
|
throw new Error("No valid transports requested.");
|
||||||
|
}
|
||||||
|
|
||||||
return new HttpClient().get(`${this.url}/getid?${this.queryString}`)
|
return new HttpClient().get(`${this.url}/getid?${this.queryString}`)
|
||||||
.then(connectionId => {
|
.then(connectionId => {
|
||||||
this.connectionId = connectionId;
|
this.connectionId = connectionId;
|
||||||
return this.tryStartTransport([
|
this.queryString = `id=${connectionId}&${this.connectionId}`;
|
||||||
new WebSocketTransport(),
|
return this.tryStartTransport(transports, 0);
|
||||||
new ServerSentEventsTransport(null),
|
|
||||||
new LongPollingTransport(null)], 0);
|
|
||||||
})
|
})
|
||||||
.then(transport => {
|
.then(transport => {
|
||||||
this.transport = transport;
|
this.transport = transport;
|
||||||
|
|
@ -45,6 +48,30 @@ class Connection {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private filterTransports(transportNames: string[]): ITransport[] {
|
||||||
|
let availableTransports = ['webSockets', 'serverSentEvents', 'longPolling'];
|
||||||
|
transportNames = transportNames || availableTransports;
|
||||||
|
// uniquify
|
||||||
|
transportNames = transportNames.filter((value, index, values) => {
|
||||||
|
return values.indexOf(value) == index;
|
||||||
|
});
|
||||||
|
|
||||||
|
let transports: ITransport[] = [];
|
||||||
|
transportNames.forEach(transportName => {
|
||||||
|
if (transportName === 'webSockets') {
|
||||||
|
transports.push(new WebSocketTransport());
|
||||||
|
}
|
||||||
|
if (transportName === 'serverSentEvents') {
|
||||||
|
transports.push(new ServerSentEventsTransport());
|
||||||
|
}
|
||||||
|
if (transportName === 'longPolling') {
|
||||||
|
transports.push(new LongPollingTransport(null));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return transports;
|
||||||
|
}
|
||||||
|
|
||||||
private tryStartTransport(transports: ITransport[], index: number): Promise<ITransport> {
|
private tryStartTransport(transports: ITransport[], index: number): Promise<ITransport> {
|
||||||
let thisConnection = this;
|
let thisConnection = this;
|
||||||
transports[index].onDataReceived = data => thisConnection.dataReceivedCallback(data);
|
transports[index].onDataReceived = data => thisConnection.dataReceivedCallback(data);
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ class RpcConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start(): Promise<void> {
|
start(transportNames?:string[]): Promise<void> {
|
||||||
return this.connection.start();
|
return this.connection.start(transportNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
stop(): void {
|
stop(): void {
|
||||||
|
|
|
||||||
|
|
@ -6,20 +6,28 @@ class ServerSentEventsTransport implements ITransport {
|
||||||
private url: string;
|
private url: string;
|
||||||
private queryString: string;
|
private queryString: string;
|
||||||
|
|
||||||
constructor(receiveCallback: (data: string) => void) {
|
connect(url: string, queryString: string = ""): Promise<void> {
|
||||||
this.receiveCallback = receiveCallback;
|
if (typeof (EventSource) === "undefined") {
|
||||||
}
|
Promise.reject("EventSource not supported by the browser.")
|
||||||
|
}
|
||||||
|
|
||||||
connect(url: string, queryString: string): Promise<void> {
|
this.queryString = queryString;
|
||||||
this.queryString = queryString || "";
|
this.url = url;
|
||||||
this.url = url || "";
|
|
||||||
let tmp = `${this.url}/sse?${this.queryString}`;
|
let tmp = `${this.url}/sse?${this.queryString}`;
|
||||||
this.eventSource = new EventSource(`${this.url}/sse?${this.queryString}`);
|
try {
|
||||||
this.eventSource.onmessage = e => {
|
this.eventSource = new EventSource(`${this.url}/sse?${this.queryString}`);
|
||||||
this.receiveCallback(e.data);
|
|
||||||
};
|
this.eventSource.onmessage = (e: MessageEvent) => {
|
||||||
|
this.onDataReceived(e.data);
|
||||||
|
};
|
||||||
|
this.eventSource.onerror = (e: Event) => {
|
||||||
|
// todo: handle errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: handle errors
|
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
class WebSocketTransport implements ITransport {
|
class WebSocketTransport implements ITransport {
|
||||||
private webSocket: WebSocket;
|
private webSocket: WebSocket;
|
||||||
|
|
||||||
connect(url: string, queryString: string): Promise<void> {
|
connect(url: string, queryString: string = ""): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
url = url.replace(/^http/, "ws");
|
url = url.replace(/^http/, "ws");
|
||||||
let connectUrl = url + "/ws?" + queryString;
|
let connectUrl = url + "/ws?" + queryString;
|
||||||
|
|
@ -12,7 +12,7 @@ class WebSocketTransport implements ITransport {
|
||||||
};
|
};
|
||||||
|
|
||||||
this.webSocket.onerror = (event: Event) => {
|
this.webSocket.onerror = (event: Event) => {
|
||||||
// TODO: handle when connection was opened successfully
|
// TODO: also handle when connection was opened successfully
|
||||||
reject();
|
reject();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue