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" +