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); } } } }); }
/// <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);
/// <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);
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); } }