using System.Net.WebSockets; using System.Text; using System.Text.Json; using CommonSocketLibrary.Abstract; using Serilog; namespace CommonSocketLibrary.Common { public abstract class WebSocketClient : SocketClient { protected IDictionary _handlers; private readonly MessageTypeManager _messageTypeManager; public WebSocketClient( IEnumerable handlers, MessageTypeManager typeManager, JsonSerializerOptions serializerOptions, ILogger logger ) : base(logger, serializerOptions) { _handlers = handlers.ToDictionary(h => h.OperationCode, h => h); _messageTypeManager = typeManager; } protected WebSocketMessage GenerateMessage(int opcode, T data) { return new WebSocketMessage() { OpCode = opcode, Data = data }; } protected override async Task OnResponseReceived(WebSocketMessage? message) { if (message == null) return; string content = message.Data?.ToString() ?? string.Empty; _logger.Verbose("RX #" + message.OpCode + ": " + content); var type = _messageTypeManager.GetMessageTypeByCode(message.OpCode); if (type == null) { return; } var data = JsonSerializer.Deserialize(content, type, _options); if (!_handlers.TryGetValue(message.OpCode, out IWebSocketHandler? handler) || handler == null) { return; } await handler.Execute(this, data); } public async Task Send(int opcode, T data) { if (_socket == null) return; try { var message = GenerateMessage(opcode, data); var content = JsonSerializer.Serialize(message, _options); var bytes = Encoding.UTF8.GetBytes(content); var array = new ArraySegment(bytes); var total = bytes.Length; var current = 0; while (current < total) { var size = Encoding.UTF8.GetBytes(content.Substring(current), array); await _socket!.SendAsync(array, WebSocketMessageType.Text, current + size >= total, _cts!.Token); current += size; } _logger.Verbose("TX #" + opcode + ": " + content); } catch (Exception e) { if (_socket.State.ToString().Contains("Close") || _socket.State == WebSocketState.Aborted) { await DisconnectAsync(new SocketDisconnectionEventArgs(_socket.CloseStatus.ToString()!, _socket.CloseStatusDescription ?? string.Empty)); _logger.Warning($"Socket state on closing = {_socket.State} | {_socket.CloseStatus?.ToString()} | {_socket.CloseStatusDescription}"); } _logger.Error(e, $"Failed to send a websocket message [op code: {opcode}]"); } } } }