💥 Rename Pusher to Ring
This commit is contained in:
		
							
								
								
									
										122
									
								
								DysonNetwork.Ring/Connection/WebSocketController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								DysonNetwork.Ring/Connection/WebSocketController.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,122 @@ | ||||
| using System.Net.WebSockets; | ||||
| using DysonNetwork.Shared.Proto; | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.AspNetCore.Mvc; | ||||
| using Swashbuckle.AspNetCore.Annotations; | ||||
|  | ||||
| namespace DysonNetwork.Ring.Connection; | ||||
|  | ||||
| [ApiController] | ||||
| public class WebSocketController(WebSocketService ws, ILogger<WebSocketContext> logger) : ControllerBase | ||||
| { | ||||
|     [Route("/ws")] | ||||
|     [Authorize] | ||||
|     [SwaggerIgnore] | ||||
|     public async Task TheGateway() | ||||
|     { | ||||
|         HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue); | ||||
|         HttpContext.Items.TryGetValue("CurrentSession", out var currentSessionValue); | ||||
|         if (currentUserValue is not Account currentUser || | ||||
|             currentSessionValue is not AuthSession currentSession) | ||||
|         { | ||||
|             HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         var accountId = currentUser.Id!; | ||||
|         var deviceId = currentSession.Challenge?.DeviceId ?? Guid.NewGuid().ToString(); | ||||
|  | ||||
|         if (string.IsNullOrEmpty(deviceId)) | ||||
|         { | ||||
|             HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest; | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(new WebSocketAcceptContext | ||||
|             { KeepAliveInterval = TimeSpan.FromSeconds(60) }); | ||||
|         var cts = new CancellationTokenSource(); | ||||
|         var connectionKey = (accountId, deviceId); | ||||
|  | ||||
|         if (!ws.TryAdd(connectionKey, webSocket, cts)) | ||||
|         { | ||||
|             await webSocket.SendAsync( | ||||
|                 new ArraySegment<byte>(new WebSocketPacket | ||||
|                 { | ||||
|                     Type = "error.dupe", | ||||
|                     ErrorMessage = "Too many connections from the same device and account." | ||||
|                 }.ToBytes()), | ||||
|                 WebSocketMessageType.Binary, | ||||
|                 true, | ||||
|                 CancellationToken.None | ||||
|             ); | ||||
|             await webSocket.CloseAsync( | ||||
|                 WebSocketCloseStatus.PolicyViolation, | ||||
|                 "Too many connections from the same device and account.", | ||||
|                 CancellationToken.None | ||||
|             ); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         logger.LogDebug( | ||||
|             $"Connection established with user @{currentUser.Name}#{currentUser.Id} and device #{deviceId}"); | ||||
|  | ||||
|         try | ||||
|         { | ||||
|             await _ConnectionEventLoop(deviceId, currentUser, webSocket, cts.Token); | ||||
|         } | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             logger.LogError(ex, | ||||
|                 "WebSocket disconnected with user @{UserName}#{UserId} and device #{DeviceId} unexpectedly", | ||||
|                 currentUser.Name, | ||||
|                 currentUser.Id, | ||||
|                 deviceId | ||||
|             ); | ||||
|         } | ||||
|         finally | ||||
|         { | ||||
|             ws.Disconnect(connectionKey); | ||||
|             logger.LogDebug( | ||||
|                 $"Connection disconnected with user @{currentUser.Name}#{currentUser.Id} and device #{deviceId}" | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private async Task _ConnectionEventLoop( | ||||
|         string deviceId, | ||||
|         Account currentUser, | ||||
|         WebSocket webSocket, | ||||
|         CancellationToken cancellationToken | ||||
|     ) | ||||
|     { | ||||
|         var connectionKey = (AccountId: currentUser.Id, DeviceId: deviceId); | ||||
|  | ||||
|         var buffer = new byte[1024 * 4]; | ||||
|         try | ||||
|         { | ||||
|             while (true) | ||||
|             { | ||||
|                 var receiveResult = await webSocket.ReceiveAsync( | ||||
|                     new ArraySegment<byte>(buffer), | ||||
|                     cancellationToken | ||||
|                 ); | ||||
|  | ||||
|                 if (receiveResult.CloseStatus.HasValue) | ||||
|                     break; | ||||
|  | ||||
|                 var packet = WebSocketPacket.FromBytes(buffer[..receiveResult.Count]); | ||||
|                 await ws.HandlePacket(currentUser, connectionKey.DeviceId, packet, webSocket); | ||||
|             } | ||||
|         } | ||||
|         catch (OperationCanceledException) | ||||
|         { | ||||
|             if ( | ||||
|                 webSocket.State != WebSocketState.Closed | ||||
|                 && webSocket.State != WebSocketState.Aborted | ||||
|             ) | ||||
|             { | ||||
|                 ws.Disconnect(connectionKey); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user