private async Task HandleAfterSocketAsync (WebSocket nativeSocket, MariBaseWebSocketService service, HttpContext context) { using var socket = new MariWebSocket(nativeSocket, service.Cts.Token, service); _logger.LogDebug($"The new WebSocket has the Id: {socket.Id}"); service.AddClient(socket); await service.OnOpenAsync(socket, context) .Try(_logger, service, socket, false); try { await ReadAsync(socket, service, context); } catch (Exception ex) { if (ex is TaskCanceledException) { return; } await service.OnDisconnectedAsync(socket, WebSocketCloseStatus.ProtocolError, ex.Message) .Try(_logger, service, socket, false); if (socket.WebSocket.State.Equals(WebSocketState.Open)) { await socket.WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closed by remote", service.Cts.Token) .Try(_logger, service, socket, false); } } nativeSocket.Dispose(); }
internal MariWebSocket(WebSocket webSocket, CancellationToken token, MariBaseWebSocketService service) { Id = Guid.NewGuid().ToString(); WebSocket = webSocket; _token = token; _service = service; }
private static async Task HandleExceptionFromTryAsync<T> (Exception ex, ILogger<T> logger, MariBaseWebSocketService service, MariWebSocket socket, bool cancel) { await service.OnErrorAsync(ex, socket); if (cancel) throw ex; else if (logger.HasContent()) logger.LogError(ex, ex.Message); }
private async Task ReadAsync (MariWebSocket socket, MariBaseWebSocketService service, HttpContext context) { while (socket.WebSocket.State == WebSocketState.Open) { var buffer = new byte[service.BufferLength]; var result = await socket.WebSocket.ReceiveAsync(buffer, service.Cts.Token) .Try(_logger, service, socket); if (result.HasNoContent()) { continue; } await ReadMessageAsync(result, buffer, service, socket, context); } }
private async Task HandleBeforeSocketAsync(HttpContext context, MariBaseWebSocketService service) { if (service.HasNoContent()) { _logger.LogInformation($"No WebSocketService found for the request path:" + $" \"{context.Request.Path}\"."); context.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } if (service.IsDisposed) { _logger.LogError(new ObjectDisposedException(nameof(service)), "The server cannot use that service because he's disposed."); context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable; return; } _logger.LogDebug("Trying authorize the request..."); if (!await service.AuthorizeAsync(context).Try(_logger, service, default)) { _logger.LogInformation("The WebSocketService returned unauthorized for that request."); context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; return; } _logger.LogInformation("Authorized the request by the WebSocketService."); _logger.LogTrace($"Accepting the WebSocket request for " + $"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort}."); var nativeSocket = await context.WebSockets.AcceptWebSocketAsync() .Try(_logger, service, default); _logger.LogInformation("Successfully accepted the WebSocket request."); await HandleAfterSocketAsync(nativeSocket, service, context); }
private async Task ReadMessageAsync (WebSocketReceiveResult result, byte[] buffer, MariBaseWebSocketService service, MariWebSocket socket, HttpContext context) { if (!result.EndOfMessage) { return; } _logger.LogTrace($"Incoming WebSocket message from " + $"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort}."); _logger.LogDebug($"Received WebSocket message from client's id: {socket.Id}"); if (result.MessageType.Equals(WebSocketMessageType.Text)) { await service.OnMessageAsync(socket, Encoding.UTF8.GetString(buffer)) .Try(_logger, service, socket, false); } else if (result.MessageType.Equals(WebSocketMessageType.Close)) { _logger.LogTrace($"Incoming WebSocket disconnect from " + $"{context.Connection.RemoteIpAddress}:{context.Connection.RemotePort}."); _logger.LogDebug($"WebSocket with id {socket.Id} disconnected."); await service.OnDisconnectedAsync( socket, result.CloseStatus.Value, Encoding.UTF8.GetString(buffer)) .Try(_logger, service, socket, false); service.RemoveClient(socket); await socket.WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closed by remote", service.Cts.Token) .Try(_logger, service, socket, false); socket.Dispose(); } }
/// <summary> /// Try await the task and calls /// <see cref="MariBaseWebSocketService"/>#OnErroAsync /// if a exception throws. /// </summary> /// <typeparam name="T">The <see cref="ILogger"/> type.</typeparam> /// <param name="task">The <see cref="Task"/> that will await.</param> /// <param name="logger">The ASP.NET Core <see cref="ILogger"/> for the Middleware.</param> /// <param name="service">The Socketservice.</param> /// <param name="socket">The <see cref="MariWebSocket"/>.</param> /// <param name="cancel">A Boolen indicates if that Method will throw the exception or not.</param> /// <returns></returns> internal static async Task Try<T> (this Task task, ILogger<T> logger, MariBaseWebSocketService service, MariWebSocket socket, bool cancel = true) { await task .TryAsync((ex) => HandleExceptionFromTryAsync(ex, logger, service, socket, cancel)); }