using Microsoft.AspNetCore.Http.Extensions; using Shogi.Contracts.Socket; using Shogi.Contracts.Types; using System.Buffers; using System.Net.WebSockets; using System.Text.Json; namespace Shogi.UI.Shared; public class ShogiSocket : IDisposable { public event EventHandler? OnCreateGameMessage; private readonly ClientWebSocket socket; private readonly JsonSerializerOptions serializerOptions; private readonly UriBuilder uriBuilder; private readonly CancellationTokenSource cancelToken; private readonly IMemoryOwner memoryOwner; private bool disposedValue; public ShogiSocket(IConfiguration configuration, ClientWebSocket socket, JsonSerializerOptions serializerOptions) { this.socket = socket; this.serializerOptions = serializerOptions; this.uriBuilder = new UriBuilder(configuration["SocketUrl"]); this.cancelToken = new CancellationTokenSource(); this.memoryOwner = MemoryPool.Shared.Rent(1024 * 2); } public async Task OpenAsync(string token) { uriBuilder.Query = new QueryBuilder { { "token", token } }.ToQueryString().Value; await socket.ConnectAsync(this.uriBuilder.Uri, cancelToken.Token); Console.WriteLine("CONNECTED"); Listen(); } private async void Listen() { while (socket.State == WebSocketState.Open && !cancelToken.IsCancellationRequested) { var result = await socket.ReceiveAsync(this.memoryOwner.Memory, cancelToken.Token); var memory = this.memoryOwner.Memory[..result.Count].ToArray(); var action = JsonDocument .Parse(memory[..result.Count]) .RootElement .GetProperty(nameof(ISocketResponse.Action)) .Deserialize(); switch (action) { case SocketAction.SessionCreated: Console.WriteLine("Session created event."); this.OnCreateGameMessage?.Invoke(this, JsonSerializer.Deserialize(memory, this.serializerOptions)!); break; default: break; } } if (!cancelToken.IsCancellationRequested) { throw new InvalidOperationException("Stopped socket listening without cancelling."); } } protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { cancelToken.Cancel(); socket.Dispose(); memoryOwner.Dispose(); } disposedValue = true; } } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method Dispose(disposing: true); GC.SuppressFinalize(this); } }