diff --git a/Client/Components/App.razor b/Client/Components/App.razor index 5dac545..3fde3ff 100644 --- a/Client/Components/App.razor +++ b/Client/Components/App.razor @@ -1,4 +1,7 @@ - +@using Microsoft.Extensions.Configuration +@inject IConfiguration Configuration + + @@ -19,6 +22,44 @@ + \ No newline at end of file diff --git a/Client/Components/Pages/Home.razor b/Client/Components/Pages/Home.razor index cfa1177..d07d89c 100644 --- a/Client/Components/Pages/Home.razor +++ b/Client/Components/Pages/Home.razor @@ -7,6 +7,7 @@ Replay viewer

Replay browser for Space Station 14

+

There is currently 1 user here.



diff --git a/Client/Components/Pages/Search.razor b/Client/Components/Pages/Search.razor index aaf70d9..7091a38 100644 --- a/Client/Components/Pages/Search.razor +++ b/Client/Components/Pages/Search.razor @@ -8,6 +8,7 @@ Replay viewer

Replay browser for Space Station 14

+

There is currently 1 user here.

Search for replays by using the search bar below

Back to main page
diff --git a/Server/Api/DataController.cs b/Server/Api/DataController.cs index 09c750f..6734c71 100644 --- a/Server/Api/DataController.cs +++ b/Server/Api/DataController.cs @@ -1,6 +1,11 @@ -using Microsoft.AspNetCore.Cors; +using System.Collections.Concurrent; +using System.Net.WebSockets; +using System.Text; +using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using Serilog; +using Shared; namespace Server.Api; @@ -13,10 +18,13 @@ namespace Server.Api; public class DataController : ControllerBase { private readonly ReplayDbContext _context; - + public static readonly Dictionary ConnectedUsers = new(); + private Timer _timer; + public DataController(ReplayDbContext context) { _context = context; + _timer = new Timer(CheckInactiveConnections, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); } /// @@ -39,4 +47,55 @@ [FromQuery] string username return Ok(completions); } + + [Route("/ws")] + public async Task Connect() + { + if (HttpContext.WebSockets.IsWebSocketRequest) + { + var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(); + var userId = Guid.NewGuid(); + ConnectedUsers.Add(userId, webSocket); + Log.Information("User connected with ID {UserId}", userId); + await Echo(webSocket, userId); + } + else + { + HttpContext.Response.StatusCode = 400; + } + } + + private async Task Echo(WebSocket webSocket, Guid userId) + { + var buffer = new byte[1024 * 4]; + var result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + + while (!result.CloseStatus.HasValue) + { + result = await webSocket.ReceiveAsync(new ArraySegment(buffer), CancellationToken.None); + + if (Encoding.UTF8.GetString(buffer).Contains("count")) + { + var count = ConnectedUsers.Count; + var countBytes = Encoding.UTF8.GetBytes(count.ToString()); + await webSocket.SendAsync(new ArraySegment(countBytes), WebSocketMessageType.Text, true, CancellationToken.None); + } + + buffer = new byte[1024 * 4]; + } + + ConnectedUsers.Remove(userId, out _); + await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None); + } + + private void CheckInactiveConnections(object state) + { + foreach (var user in ConnectedUsers) + { + if (user.Value.State == WebSocketState.Open) continue; + + ConnectedUsers.Remove(user.Key, out _); + Log.Information("User disconnected with ID {UserId}", user.Key); + } + } } \ No newline at end of file diff --git a/Server/Program.cs b/Server/Program.cs index 791b89e..e6b6bf6 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -66,6 +66,13 @@ builder.Services.AddMvc(); var app = builder.Build(); + + var webSocketOptions = new WebSocketOptions() + { + KeepAliveInterval = TimeSpan.FromSeconds(10), + }; + + app.UseWebSockets(webSocketOptions); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment())