Fixing longpolling

This commit is contained in:
moozzyk 2016-09-30 15:13:21 -07:00
parent 32ed7ca0c4
commit 239b5f815f
5 changed files with 69 additions and 60 deletions

View File

@ -2,10 +2,11 @@
namespace WebApplication95 namespace WebApplication95
{ {
public class ConnectionState public class ConnectionState
{ {
public DateTimeOffset LastSeen { get; set; } public DateTimeOffset LastSeen { get; set; }
public bool Alive { get; set; } = true; public bool Alive { get; set; } = true;
public Connection Connection { get; set; } public Connection Connection { get; set; }
public bool IsReservation { get; set; }
} }
} }

View File

@ -58,6 +58,7 @@ namespace WebApplication95
if (context.Request.Path.StartsWithSegments(path + "/sse")) if (context.Request.Path.StartsWithSegments(path + "/sse"))
{ {
var connectionState = GetOrCreateConnection(context); var connectionState = GetOrCreateConnection(context);
connectionState.IsReservation = false;
var sse = new ServerSentEvents(connectionState); var sse = new ServerSentEvents(connectionState);
var ignore = endpoint.OnConnected(connectionState.Connection); var ignore = endpoint.OnConnected(connectionState.Connection);
@ -73,6 +74,8 @@ namespace WebApplication95
else if (context.Request.Path.StartsWithSegments(path + "/ws")) else if (context.Request.Path.StartsWithSegments(path + "/ws"))
{ {
var connectionState = GetOrCreateConnection(context); var connectionState = GetOrCreateConnection(context);
connectionState.IsReservation = false;
var ws = new WebSockets(connectionState); var ws = new WebSockets(connectionState);
var ignore = endpoint.OnConnected(connectionState.Connection); var ignore = endpoint.OnConnected(connectionState.Connection);
@ -89,18 +92,17 @@ namespace WebApplication95
{ {
var connectionId = context.Request.Query["id"]; var connectionId = context.Request.Query["id"];
ConnectionState connectionState; ConnectionState connectionState;
bool newConnection = false;
if (_manager.AddConnection(connectionId, out connectionState))
{
newConnection = true;
var ignore = endpoint.OnConnected(connectionState.Connection);
if (_manager.AddConnection(connectionId, out connectionState) || connectionState.IsReservation)
{
connectionState.Connection.TransportType = TransportType.LongPolling; connectionState.Connection.TransportType = TransportType.LongPolling;
connectionState.IsReservation = false;
var ignore = endpoint.OnConnected(connectionState.Connection);
} }
var longPolling = new LongPolling(connectionState); var longPolling = new LongPolling(connectionState);
await longPolling.ProcessRequest(newConnection, context); await longPolling.ProcessRequest(context);
_manager.MarkConnectionDead(connectionState.Connection.ConnectionId); _manager.MarkConnectionDead(connectionState.Connection.ConnectionId);
} }
@ -112,6 +114,7 @@ namespace WebApplication95
var connectionId = _manager.GetConnectionId(context); var connectionId = _manager.GetConnectionId(context);
ConnectionState state; ConnectionState state;
_manager.AddConnection(connectionId, out state); _manager.AddConnection(connectionId, out state);
state.IsReservation = true;
context.Response.Headers["X-SignalR-ConnectionId"] = connectionId; context.Response.Headers["X-SignalR-ConnectionId"] = connectionId;
await context.Response.WriteAsync($"{{ \"connectionId\": \"{connectionId}\" }}"); await context.Response.WriteAsync($"{{ \"connectionId\": \"{connectionId}\" }}");
return; return;

View File

@ -37,10 +37,8 @@ namespace WebApplication95
return _lastTask; return _lastTask;
} }
public async Task ProcessRequest(bool newConnection, HttpContext context) public async Task ProcessRequest(HttpContext context)
{ {
context.Response.ContentType = "application/json";
// End the connection if the client goes away // End the connection if the client goes away
context.RequestAborted.Register(state => OnConnectionAborted(state), this); context.RequestAborted.Register(state => OnConnectionAborted(state), this);
@ -48,17 +46,8 @@ namespace WebApplication95
_initTcs.TrySetResult(null); _initTcs.TrySetResult(null);
if (newConnection) // Send queue messages to the connection
{ var ignore = ProcessMessages(context);
// Flush the connection id to the connection
var ignore = Send(default(ArraySegment<byte>));
}
else
{
// Send queue messages to the connection
var ignore = ProcessMessages(context);
}
await _lifetime.Task; await _lifetime.Task;
@ -106,7 +95,7 @@ namespace WebApplication95
var data = ((ArraySegment<byte>)state); var data = ((ArraySegment<byte>)state);
_context.Response.Headers["X-SignalR-ConnectionId"] = _state.Connection.ConnectionId; _context.Response.Headers["X-SignalR-ConnectionId"] = _state.Connection.ConnectionId;
_context.Response.ContentLength = data.Count; _context.Response.ContentLength = data.Count;
await _context.Response.Body.WriteAsync(data.Array, 0, data.Count); await _context.Response.Body.WriteAsync(data.Array, data.Offset, data.Count);
}, },
value); value);

View File

@ -9,19 +9,17 @@
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
var url = '/chat/send?id=' + connectionId; var url = '/chat/send?id=' + connectionId;
xhr.open("POST", url, true); xhr.open("POST", url, true);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.onreadystatechange = function () { xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) { if (xhr.readyState == 4 && xhr.status == 200) {
} }
} }
var data = JSON.stringify(data);
xhr.send(data); xhr.send(data);
} }
function xhr(method, url) { function xhr(method, url) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest(); let xhr = new XMLHttpRequest();
xhr.open(method, url); xhr.open(method, url, true);
xhr.send(); xhr.send();
xhr.onload = () => { xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) { if (xhr.status >= 200 && xhr.status < 300) {

View File

@ -4,57 +4,75 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<title></title> <title></title>
<script> <script>
document.addEventListener('DOMContentLoaded', () => {
var connectionId; function xhr(method, url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(method, url, true);
xhr.send();
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject({
status: xhr.status,
statusText: xhr.statusText
});
}
};
function send() { xhr.onerror = () => {
var body = document.getElementById('data').value; reject({
status: xhr.status,
var xhr = new XMLHttpRequest(); statusText: xhr.statusText
var url = '/chat/send?id=' + connectionId; });
xhr.open("POST", url, true); };
xhr.setRequestHeader('Content-type', 'application/json'); });
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
}
} }
var data = JSON.stringify(body);
xhr.send(data);
}
function send(connectionId, data) {
var xhr = new XMLHttpRequest();
var url = '/chat/send?id=' + connectionId;
xhr.open("POST", url, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
}
}
xhr.send(data);
}
function poll(id) { function poll(connectionId, xhr) {
var xhr = new XMLHttpRequest(); var url = `/chat/poll?id=${connectionId}`;
var url = '/chat/poll' + (id == null ? '' : '?id=' + id); xhr.open("POST", url, true);
xhr.open("POST", url, true); xhr.onreadystatechange = () => {
xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) {
if (xhr.readyState == 4 && xhr.status == 200) {
var json = JSON.parse(xhr.responseText);
var id = json.c;
var data = json.d;
if (data) {
var child = document.createElement('li'); var child = document.createElement('li');
child.innerText = data; child.innerText = xhr.response;
document.getElementById('messages').appendChild(child); document.getElementById('messages').appendChild(child);
poll(connectionId, xhr);
} }
if (!connectionId) {
connectionId = id;
}
poll(id);
} }
xhr.send(null);
} }
xhr.send(null);
}
poll(); xhr('GET', '/chat/getid').then(getidPayload => {
let connectionId = JSON.parse(getidPayload).connectionId;
document.getElementById('sendmessage').addEventListener('click', () => {
let data = document.getElementById('data').value;
send(connectionId, data);
});
poll(connectionId, new XMLHttpRequest());
});
});
</script> </script>
</head> </head>
<body> <body>
<h1>Long Polling</h1> <h1>Long Polling</h1>
<input type="text" id="data" /> <input type="text" id="data" />
<input type="button" value="Send" onclick="send()" /> <input type="button" id="sendmessage" value="Send" />
<ul id="messages"></ul> <ul id="messages"></ul>
</body> </body>