/// <summary> /// Gets the information of the connection /// </summary> /// <param name="websocket"></param> /// <param name="session"></param> /// <returns></returns> public static string GetConnectionInfo(this ManagedWebSocket websocket, Session session = null) { session = session ?? websocket.Get <Session>("Session"); return($"- Account: {websocket.Get("AccountInfo", "Visitor")} - Session ID: {session?.SessionID ?? "Unknown"} - Device ID: {session?.DeviceID ?? "Unknown"} - Origin: {(websocket.Headers.TryGetValue("Origin", out var origin) ? origin : session?.AppOrigin ?? "Unknown")}" + "\r\n" + $"- App: {session?.AppName ?? "Unknown"} @ {session?.AppPlatform ?? "Unknown"} [{session?.AppAgent ?? "Unknown"}]" + "\r\n" + $"- Connection IP: {session?.IP ?? "Unknown"} - Location: {websocket.Get("LocationInfo", "Unknown")} - WebSocket: {websocket.ID} @ {websocket.RemoteEndPoint}"); }
public bool VerifyClient(ManagedWebSocket socket) { var address = (socket.RemoteEndPoint as IPEndPoint).Address.ToString(); // Console.WriteLine($"REQUEST FROM {address}, {(socket. ? "" : "not ")}secure, Origin: {socket.Context.Origin}"); if (connections.Count > Settings.listenerMaxConnections) { Console.WriteLine("listenerMaxConnections reached, dropping new connections"); return(false); } var acceptedOrigins = Settings.listenerAcceptedOrigins; if (acceptedOrigins.Count > 0 && acceptedOrigins.Contains(socket.RequestUri.ToString())) { Console.WriteLine($"listenerAcceptedOrigins doesn't contain {socket.RequestUri.ToString()}"); return(false); } if (Settings.listenerForbiddenIPs.Contains(address)) { Console.WriteLine($"listenerForbiddenIPs contains {address}, dropping connection"); return(false); } if (Settings.listenerMaxConnectionsPerIP > 0) { var count = ConnectionCountForIP(address); if (count != 0 && count >= Settings.listenerMaxConnectionsPerIP) { Console.WriteLine($"listenerMaxConnectionsPerIP reached for '{address}', dropping its new connections"); return(false); } } Console.WriteLine("client verification passed"); return(true); }
/// <summary> /// Prepares the information of the connection /// </summary> /// <param name="websocket"></param> /// <param name="correlationID"></param> /// <param name="session"></param> /// <param name="cancellationToken"></param> /// <param name="logger"></param> /// <returns></returns> public static async Task PrepareConnectionInfoAsync(this ManagedWebSocket websocket, string correlationID = null, Session session = null, CancellationToken cancellationToken = default, Microsoft.Extensions.Logging.ILogger logger = null) { correlationID = correlationID ?? UtilityService.NewUUID; session = session ?? websocket.Get <Session>("Session"); var account = "Visitor"; if (!string.IsNullOrWhiteSpace(session?.User?.ID)) { try { var json = await Router.GetService("Users").ProcessRequestAsync(new RequestInfo(session, "Users", "Profile", "GET") { CorrelationID = correlationID }, cancellationToken).ConfigureAwait(false); account = $"{json?.Get<string>("Name") ?? "Unknown"} ({session.User.ID})"; } catch (Exception ex) { account = $"Unknown ({session.User.ID})"; logger?.LogError($"Error occurred while fetching an account profile => {ex.Message}", ex); } } websocket.Set("AccountInfo", account); websocket.Set("LocationInfo", session != null ? await session.GetLocationAsync(correlationID, cancellationToken).ConfigureAwait(false) : "Unknown"); }
// ctor. // Š¢Š¾Š»ŃŠŗŠ¾ Listener Š¼Š¾Š¶ŠµŃ ŃŠ¾Š·Š“Š°ŃŃ ŃŃŠ¾Ń ŠŗŠ»Š°ŃŃ. internal ServerSideConnection(ManagedWebSocket clientConnection, ServiceProvider serviceProvider, VRpcListener listener) : base(clientConnection, isServer: true, serviceProvider, listener.InvokeActions) { Listener = listener; // ŠŠ·Š½Š°ŃŠ°Š»ŃŠ½ŃŠ¹ Š½Šµ Š°Š²ŃŠ¾ŃŠøŠ·Š¾Š²Š°Š½Š½ŃŠ¹ ŠæŠ¾Š»ŃŠ·Š¾Š²Š°ŃŠµŠ»Ń. _user = CreateUnauthorizedUser(); }
public Connection(Listener listener, ManagedWebSocket webSocket) : base(listener) { WebSocket = webSocket; RemoteAddress = (webSocket.RemoteEndPoint as IPEndPoint).Address; ConnectionTime = DateTime.Now; //lastActivityTime = DateTime.Now; lastChatTime = DateTime.Now; }
public INetworkingClient GetClient(ManagedWebSocket webSocket) { if (!webSocket.Extra.TryGetValue(ClientExtra, out var playerObject) || !(playerObject is INetworkingClient client)) { return(null); } return(client); }
public void OnDisconnection(ManagedWebSocket ws) { Connection connection = ws.Get <Connection>("agar"); Console.WriteLine($"DISCONNECTION FROM {connection.RemoteAddress}"); connection.OnSocketClose(0, null); connections.Remove(connection); globalChat.Remove(connection); }
public static WebSocket CreateServerWebSocket(Stream stream, string subProtocol, TimeSpan keepAliveInterval, int receiveBufferSize) { return(ManagedWebSocket.CreateFromConnectedStream( stream, isServer: true, subprotocol: subProtocol, keepAliveInterval: keepAliveInterval, receiveBufferSize: receiveBufferSize)); }
public INetworkingClient GetClient(ManagedWebSocket managedWebSocket) { if (managedWebSocket.Extra.TryGetValue("client", out var clientObj) && clientObj is INetworkingClient client) { return(client); } return(null); }
public void OnData(ManagedWebSocket ws, WebSocketReceiveResult res, byte[] data) { Connection connection = ws.Get <Connection>("agar"); if (res.MessageType != WebSocketMessageType.Binary) { connection.CloseSocket(1003, "Invalid message type"); } connection.OnSocketMessage(data); }
public void OnConnect(ManagedWebSocket managedWebSocket) { lock (this) { WebSocket = managedWebSocket; if (dimension != 0) { entityStreamer.UpdateClientDimension(this, dimension); } } }
public Task <bool> Verify(INetworkingClientPool networkingClientPool, ManagedWebSocket webSocket, string token, out INetworkingClient client) { if (!networkingClientPool.TryGet(token, out client)) { return(Task.FromResult(false)); } //TODO: check if already has websocket ect. client.WebSocket webSocket.Extra[ClientExtra] = client; return(Task.FromResult(true)); }
public void OnConnection(ManagedWebSocket client) { if (!VerifyClient(client)) { client.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.InternalServerError, "Connection rejected", CancellationToken.None); } var newConnection = new Connection(this, client); client.Set("agar", newConnection); Console.WriteLine($"CONNECTION FROM {newConnection.RemoteAddress}"); connections.Add(newConnection); }
public void OnConnectionBroken(ManagedWebSocket webSocket) { if (!webSocket.Extra.Remove(ClientExtra, out var playerObject) || !(playerObject is INetworkingClient client)) { return; } lock (client) { client.WebSocket = null; } }
public void OnConnect(ManagedWebSocket managedWebSocket) { lock (this) { WebSocket = managedWebSocket; if (dimension != 0) { entityStreamer.UpdateClientDimension(this, dimension); } if (PositionOverride != null) { entityStreamer.UpdateClientPositionOverride(this, PositionOverride); } } }
static async Task WhenConnectionIsBrokenAsync(this ManagedWebSocket websocket) { // prepare websocket.SetStatus("Disconnected"); websocket.Remove("Session", out Session session); var correlationID = UtilityService.NewUUID; // remove the updater if (websocket.Remove("Updater", out IDisposable updater)) { try { updater?.Dispose(); } catch (Exception ex) { await Global.WriteLogsAsync(RTU.Logger, "Http.InternalAPIs", $"Error occurred while disposing updater: {session?.ToJson()?.ToString(Global.IsDebugResultsEnabled ? Formatting.Indented : Formatting.None)}", ex, Global.ServiceName, LogLevel.Error, correlationID).ConfigureAwait(false); } } // remove the communicator if (websocket.Remove("Communicator", out IDisposable communicator)) { try { communicator?.Dispose(); } catch (Exception ex) { await Global.WriteLogsAsync(RTU.Logger, "Http.InternalAPIs", $"Error occurred while disposing communicator: {session?.ToJson()?.ToString(Global.IsDebugResultsEnabled ? Formatting.Indented : Formatting.None)}", ex, Global.ServiceName, LogLevel.Error, correlationID).ConfigureAwait(false); } } // update the session state await Task.WhenAll( session != null?session.SendSessionStateAsync(false, correlationID) : Task.CompletedTask, Global.IsVisitLogEnabled?Global.WriteLogsAsync(RTU.Logger, "Http.Visits", $"The real-time updater (RTU) is stopped" + "\r\n" + websocket.GetConnectionInfo(session) + "\r\n" + $"- Served times: {websocket.Timestamp.GetElapsedTimes()}", null, Global.ServiceName, LogLevel.Information, correlationID) : Task.CompletedTask ).ConfigureAwait(false); }
public static ManagedWebSocket CreateClientWebSocket(Stream innerStream, string subProtocol, int receiveBufferSize, int sendBufferSize, TimeSpan keepAliveInterval, bool useZeroMaskingKey, ArraySegment <byte> internalBuffer) { if (innerStream == null) { throw new ArgumentNullException(nameof(innerStream)); } if (!innerStream.CanRead || !innerStream.CanWrite) { throw new ArgumentException(!innerStream.CanRead ? SR.NotReadableStream : SR.NotWriteableStream, nameof(innerStream)); } if (subProtocol != null) { WebSocketValidate.ValidateSubprotocol(subProtocol); } if (keepAliveInterval != Timeout.InfiniteTimeSpan && keepAliveInterval < TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(keepAliveInterval), keepAliveInterval, SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, 0)); } if (receiveBufferSize <= 0 || sendBufferSize <= 0) { throw new ArgumentOutOfRangeException( receiveBufferSize <= 0 ? nameof(receiveBufferSize) : nameof(sendBufferSize), receiveBufferSize <= 0 ? receiveBufferSize : sendBufferSize, SR.Format(SR.net_WebSockets_ArgumentOutOfRange_TooSmall, 0)); } return(ManagedWebSocket.CreateFromConnectedStream( innerStream, false, subProtocol, keepAliveInterval, receiveBufferSize, internalBuffer)); }
public Task <bool> Verify(INetworkingClientPool networkingClientPool, ManagedWebSocket managedWebSocket, string token, out INetworkingClient client) { if (networkingClientPool.TryGet(token, out client)) { //managedWebSocket.Extra.TryAdd("client", client); /*if (client.WebSocket != managedWebSocket) * { * webSocket.CloseWebSocket(client.WebSocket); * } * * client.WebSocket = managedWebSocket;*/ //return Task.FromResult(true); networkingClientPool.Remove(client); //TODO: maybe try to reuse clients later when client can send if it was a reconnect or new connection in auth event } client = AltNetworking.CreateClient(token); client.WebSocket = managedWebSocket; //TODO: maybe do that automatically, but we would lost freedom managedWebSocket.Extra.TryAdd("client", client); return(Task.FromResult(true)); }
public void OnConnectionEstablished(ManagedWebSocket managedWebSocket) { }
public void OnError(ManagedWebSocket webSocket, Exception exception) { Console.WriteLine(exception); }
public void OnMessage(ManagedWebSocket managedWebSocket, WebSocketReceiveResult result, byte[] data) { Task.Run(async() => { var clientEvent = ClientEvent.Parser.ParseFrom(data); if (clientEvent == null) { return; } var authEvent = clientEvent.Auth; var streamIn = clientEvent.StreamIn; var streamOut = clientEvent.StreamOut; if (authEvent != null) { var token = authEvent.Token; if (token == null) { return; } var verified = await authenticationProvider.Verify(networkingClientPool, managedWebSocket, token, out var client); if (!verified) { return; } client.OnConnect(managedWebSocket); var sendEvent = new ServerEvent(); var currSendEvent = new EntitySendEvent(); lock (AltNetworking.Module.EntityPool.Entities) { foreach (var entity in AltNetworking.Module.EntityPool.Entities) { if (entity.Value.StreamingType == StreamingType.DataStreaming) { var streamedEntity = entity.Value.StreamedEntity.Clone(); streamedEntity.Data.Clear(); currSendEvent.Entities.Add(streamedEntity); } else { currSendEvent.Entities.Add(entity.Value.StreamedEntity); } } } sendEvent.Send = currSendEvent; await managedWebSocket.SendAsync(sendEvent.ToByteArray(), true); } else if (streamIn != null) { var client = authenticationProvider.GetClient(managedWebSocket); if (client == null) { return; } var entityId = streamIn.EntityId; if (AltNetworking.Module.EntityPool.TryGet(entityId, out var entity)) { if (!authenticationProvider.VerifyPosition(client, entity, true)) { return; } EntityStreamInHandler?.Invoke(entity, client); entity.ClientStreamedIn(client); var changedKeys = entity.Snapshot.CompareWithClient(client); if (changedKeys != null) { var multipleDataChangeEvent = new EntityMultipleDataChangeEvent { Id = entityId }; foreach (var changedKey in changedKeys) { if (entity.StreamedEntity.Data.TryGetValue(changedKey, out var mValue)) { multipleDataChangeEvent.Data[changedKey] = mValue; } else // data got deleted probably { multipleDataChangeEvent.Data[changedKey] = new MValue { NullValue = false }; } } var serverEvent = new ServerEvent { MultipleDataChange = multipleDataChangeEvent }; await managedWebSocket.SendAsync(serverEvent.ToByteArray(), true); } } } else if (streamOut != null) { var client = authenticationProvider.GetClient(managedWebSocket); if (client == null) { return; } var entityId = streamOut.EntityId; if (AltNetworking.Module.EntityPool.TryGet(entityId, out var entity)) { if (!authenticationProvider.VerifyPosition(client, entity, false)) { return; } if (entity.ClientStreamedOut(client)) { EntityStreamOutHandler?.Invoke(entity, client); } } } }); }
static async Task WhenConnectionIsEstablishedAsync(this ManagedWebSocket websocket) { // update status websocket.SetStatus("Initializing"); var correlationID = UtilityService.NewUUID; // prepare session try { var query = websocket.RequestUri.ParseQuery(); var session = Global.GetSession(websocket.Headers, query, $"{(websocket.RemoteEndPoint as IPEndPoint).Address}"); // update session identity session.SessionID = query.TryGetValue("x-session-id", out var sessionID) ? sessionID.Url64Decode() : ""; if (string.IsNullOrWhiteSpace(session.SessionID)) { throw new InvalidRequestException("Session identity is not found"); } // update device identity session.DeviceID = query.TryGetValue("x-device-id", out var deviceID) ? deviceID.Url64Decode() : ""; if (string.IsNullOrWhiteSpace(session.DeviceID)) { throw new InvalidRequestException("Device identity is not found"); } // update session websocket.Set("Session", session); await websocket.PrepareConnectionInfoAsync(correlationID, session, Global.CancellationTokenSource.Token, RTU.Logger).ConfigureAwait(false); // wait for few times before connecting to API Gateway Router because RxNET needs that if (query.ContainsKey("x-restart")) { await Task.WhenAll( websocket.SendAsync(new UpdateMessage { Type = "Knock" }), Task.Delay(345, Global.CancellationTokenSource.Token) ).ConfigureAwait(false); } } catch (Exception ex) { await RTU.WebSocket.CloseWebSocketAsync(websocket, ex is InvalidRequestException?WebSocketCloseStatus.InvalidPayloadData : WebSocketCloseStatus.InternalServerError, ex is InvalidRequestException?$"Request is invalid => {ex.Message}" : ex.Message).ConfigureAwait(false); return; } // subscribe an updater to push messages to client device websocket.Set("Updater", Services.Router.IncomingChannel.RealmProxy.Services .GetSubject <UpdateMessage>("messages.update") .Subscribe( async message => await websocket.PushAsync(message).ConfigureAwait(false), async exception => await Global.WriteLogsAsync(RTU.Logger, "Http.InternalAPIs", $"Error occurred while fetching an updating message => {exception.Message}", exception).ConfigureAwait(false) ) ); // subscribe a communicator to update related information websocket.Set("Communicator", Services.Router.IncomingChannel.RealmProxy.Services .GetSubject <CommunicateMessage>("messages.services.apigateway") .Subscribe( async message => await websocket.CommunicateAsync(message).ConfigureAwait(false), async exception => await Global.WriteLogsAsync(RTU.Logger, "Http.InternalAPIs", $"Error occurred while fetching an inter-communicating message => {exception.Message}", exception).ConfigureAwait(false) ) ); // update status websocket.SetStatus("Connected"); if (Global.IsVisitLogEnabled) { await Global.WriteLogsAsync(RTU.Logger, "Http.Visits", $"The real-time updater (RTU) is started" + "\r\n" + websocket.GetConnectionInfo() + "\r\n" + $"- Status: {websocket.GetStatus()}", null, Global.ServiceName, LogLevel.Information, correlationID).ConfigureAwait(false); } }
static async Task WhenMessageIsReceivedAsync(this ManagedWebSocket websocket, WebSocketReceiveResult result, byte[] data) { // receive continuous messages object message; if (!result.EndOfMessage) { websocket.Extra["Message"] = websocket.Extra.TryGetValue("Message", out message) ? (message as byte[]).Concat(data) : data; return; } // last message or single small message var stopwatch = Stopwatch.StartNew(); var correlationID = UtilityService.NewUUID; if (websocket.Extra.TryGetValue("Message", out message)) { message = (message as byte[]).Concat(data); websocket.Extra.Remove("Message"); } else { message = data; } // check message var requestMsg = result.MessageType.Equals(WebSocketMessageType.Text) ? (message as byte[]).GetString() : null; if (string.IsNullOrWhiteSpace(requestMsg)) { return; } // wait for the initializing process is completed while ("Initializing".IsEquals(websocket.GetStatus())) { await Task.Delay(UtilityService.GetRandomNumber(123, 456), Global.CancellationTokenSource.Token).ConfigureAwait(false); } // check session var session = websocket.Get <Session>("Session"); if (session == null) { await Task.WhenAll ( Global.WriteLogsAsync(RTU.Logger, "Http.InternalAPIs", $"No session is attached - Request: {requestMsg}", null, Global.ServiceName, LogLevel.Critical, correlationID), RTU.WebSocket.CloseWebSocketAsync(websocket, WebSocketCloseStatus.PolicyViolation, "No session") ).ConfigureAwait(false); return; } // prepare var requestObj = requestMsg.ToExpandoObject(); var serviceName = requestObj.Get("ServiceName", ""); var objectName = requestObj.Get("ObjectName", ""); var verb = requestObj.Get("Verb", "GET").ToUpper(); var query = new Dictionary <string, string>(requestObj.Get("Query", new Dictionary <string, string>()), StringComparer.OrdinalIgnoreCase); query.TryGetValue("object-identity", out var objectIdentity); // visit logs if (Global.IsVisitLogEnabled) { await Global.WriteLogsAsync(RTU.Logger, "Http.Visits", $"Request starting {verb} " + $"/{serviceName}{(string.IsNullOrWhiteSpace(objectName) ? "" : $"/{objectName}")}{(string.IsNullOrWhiteSpace(objectIdentity) ? "" : $"/{objectIdentity}")}".ToLower() + (query.TryGetValue("x-request", out var xrequest) ? $"?x-request={xrequest}" : "") + " HTTPWS/1.1" + " \r\n" +
/// <summary> /// Sends an update message /// </summary> /// <param name="websocket"></param> /// <param name="message"></param> /// <param name="cancellationToken"></param> /// <param name="toJsonPreCompleted"></param> /// <returns></returns> public static Task SendAsync(this ManagedWebSocket websocket, UpdateMessage message, CancellationToken cancellationToken = default, Action <JToken> toJsonPreCompleted = null) => websocket.SendAsync(message?.ToJson(toJsonPreCompleted), cancellationToken);
public void OnConnectionBroken(ManagedWebSocket managedWebSocket) { //TODO: remove after 5min without life signal from client pool managedWebSocket.Extra.Remove("client"); }
/// <summary> /// Sends the message /// </summary> /// <param name="websocket"></param> /// <param name="message"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static Task SendAsync(this ManagedWebSocket websocket, JToken message, CancellationToken cancellationToken = default) => websocket.SendAsync(message?.ToString(Formatting.None), cancellationToken);
/// <summary> /// Sends the messages /// </summary> /// <param name="websocket"></param> /// <param name="messages"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static Task SendAsync(this ManagedWebSocket websocket, IEnumerable <JToken> messages, CancellationToken cancellationToken = default) => websocket.SendAsync(messages?.Where(message => message != null).Select(message => message.ToString(Formatting.None)), cancellationToken);
/// <summary> /// Sends the messages /// </summary> /// <param name="websocket"></param> /// <param name="messages"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static Task SendAsync(this ManagedWebSocket websocket, IEnumerable <string> messages, CancellationToken cancellationToken = default) => (messages ?? new List <string>()).Where(message => !string.IsNullOrWhiteSpace(message)).ForEachAsync((message, token) => websocket.SendAsync(message, token), cancellationToken, true, false);
public void OnConnectionEstablished(ManagedWebSocket webSocket) { // we don't care about websockets that are just here, maybe timeout them after 5sec without authentication }
public void OnConnectionBroken(ManagedWebSocket webSocket) { webSocket.Extra.Remove(ClientExtra); }