hermes-common-library/Common/WebSocketClient.cs

92 lines
3.2 KiB
C#

using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
using CommonSocketLibrary.Abstract;
using Serilog;
namespace CommonSocketLibrary.Common
{
public abstract class WebSocketClient : SocketClient<WebSocketMessage>
{
protected IDictionary<int, IWebSocketHandler> _handlers;
private readonly MessageTypeManager<IWebSocketHandler> _messageTypeManager;
public WebSocketClient(
IEnumerable<IWebSocketHandler> handlers,
MessageTypeManager<IWebSocketHandler> typeManager,
JsonSerializerOptions serializerOptions,
ILogger logger
) : base(logger, serializerOptions)
{
_handlers = handlers.ToDictionary(h => h.OperationCode, h => h);
_messageTypeManager = typeManager;
}
protected WebSocketMessage GenerateMessage<T>(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<T>(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<byte>(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}]");
}
}
}
}