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);
Example #6
0
        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);
            }
        }