Skip to content

Commit

Permalink
Implement start of WebSocket support
Browse files Browse the repository at this point in the history
  • Loading branch information
karashiiro committed Apr 13, 2022
1 parent d3e7568 commit fe45df7
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 9 deletions.
66 changes: 66 additions & 0 deletions src/Universalis.Application/Controllers/V2/WebSocketController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Microsoft.AspNetCore.Mvc;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Universalis.Application.Realtime;
using Universalis.Application.Swagger;
using Universalis.Application.Views.V2.Realtime;

namespace Universalis.Application.Controllers.V2;

[ApiController]
[ApiVersion("1")]
[ApiVersion("2")]
[Route("api")]
public class WebSocketController : ControllerBase
{
private readonly ISocketProcessor _socketProcessor;

public WebSocketController(ISocketProcessor socketProcessor)
{
_socketProcessor = socketProcessor;
}

/// <summary>
/// Connect to the WebSocket endpoint of the API. Requires a valid WebSocket client.
/// </summary>
[HttpGet]
[MapToApiVersion("1")]
[Route("ws")]
[ApiTag("WebSocket")]
public Task<IActionResult> Get(CancellationToken cancellationToken = default)
{
return GetV2(cancellationToken);
}

/// <summary>
/// Connect to the WebSocket endpoint of the API. Requires a valid WebSocket client.
/// </summary>
[HttpGet]
[MapToApiVersion("2")]
[Route("v{version:apiVersion}/ws")]
[ApiTag("WebSocket")]
public async Task<IActionResult> GetV2(CancellationToken cancellationToken = default)
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(
new WebSocketAcceptContext { DangerousEnableCompression = true });
var socketFinished = new TaskCompletionSource<WebSocketCompletionResult>();

_ = _socketProcessor.AddSocket(webSocket, socketFinished);

var result = await socketFinished.Task;

return Ok(new WebSocketCompletionView
{
Error = result.Error,
Reason = result.Reason,
});
}
else
{
return BadRequest();
}
}
}
9 changes: 9 additions & 0 deletions src/Universalis.Application/Realtime/ISocketProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Net.WebSockets;
using System.Threading.Tasks;

namespace Universalis.Application.Realtime;

public interface ISocketProcessor
{
Task AddSocket(WebSocket ws, TaskCompletionSource<WebSocketCompletionResult> cs);
}
18 changes: 18 additions & 0 deletions src/Universalis.Application/Realtime/SocketProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Net.WebSockets;
using System.Threading.Tasks;

namespace Universalis.Application.Realtime;

public class SocketProcessor : ISocketProcessor
{
public Task AddSocket(WebSocket ws, TaskCompletionSource<WebSocketCompletionResult> cs)
{
cs.SetResult(new WebSocketCompletionResult
{
Error = false,
Reason = "",
});

return Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Universalis.Application.Realtime;

public class WebSocketCompletionResult
{
public bool Error { get; init; }

public string Reason { get; init; }
}
14 changes: 9 additions & 5 deletions src/Universalis.Application/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@
using System.Linq;
using System.Reflection;
using System.Xml.XPath;
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
using Microsoft.AspNetCore.StaticFiles.Infrastructure;
using Microsoft.Extensions.FileProviders;
using Universalis.Alerts;
using Universalis.Application.Caching;
using Universalis.Application.ExceptionFilters;
using Universalis.Application.Realtime;
using Universalis.Application.Swagger;
using Universalis.Application.Uploads.Behaviors;
using Universalis.Application.Views.V1;
Expand All @@ -28,7 +26,6 @@
using Universalis.GameData;
using Universalis.Mogboard;
using Universalis.Mogboard.WebUI;
using Universalis.Mogboard.WebUI.Pages;

namespace Universalis.Application;

Expand All @@ -53,6 +50,8 @@ public void ConfigureServices(IServiceCollection services)
var cacheSize = int.Parse(Configuration["MarketCurrentDataCacheSize"]);
services.AddSingleton<ICache<CurrentlyShownQuery, CurrentlyShownView>>(new MemoryCache<CurrentlyShownQuery, CurrentlyShownView>(cacheSize));

services.AddSingleton<ISocketProcessor, SocketProcessor>();

services
.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
Expand Down Expand Up @@ -172,7 +171,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

options.DocumentTitle = "Universalis Documentation";
});


app.UseWebSockets(new WebSocketOptions
{
KeepAliveInterval = TimeSpan.FromMinutes(2),
});

app.UseStaticFiles();

app.UseRouting();
Expand Down
4 changes: 0 additions & 4 deletions src/Universalis.Application/Universalis.Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,4 @@
<ProjectReference Include="..\Universalis.Mogboard\Universalis.Mogboard.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="Views\V1\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Text.Json.Serialization;

namespace Universalis.Application.Views.V2.Realtime;

public class WebSocketCompletionView
{
/// <summary>
/// Whether or not the WebSocket completed in an error state.
/// </summary>
[JsonPropertyName("error")]
public bool Error { get; set; }

/// <summary>
/// The reason for the WebSocket completion.
/// </summary>
[JsonPropertyName("reason")]
public string Reason { get; set; }
}

0 comments on commit fe45df7

Please sign in to comment.