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