Files
CatLink/Relay/ActiveClient.cs
2026-01-18 17:59:01 +08:00

106 lines
3.1 KiB
C#

using System.Net.Sockets;
using System.Text;
using CatLink.Models;
using Microsoft.Extensions.Logging;
namespace CatLink.Relay
{
public class ActiveClient
{
private readonly ILogger<ActiveClient> _logger;
private readonly Socket _socket;
private readonly StreamReader _reader;
private readonly StreamWriter _writer;
private readonly object _writeLock = new();
private readonly Thread _thread;
private readonly Action<ActiveClient, Msg> _messageHandler;
private readonly Action<ActiveClient> _disconnectHandler;
public string ClientKey { get; }
public uint StubIp { get; }
public Dictionary<int, uint> TcpStreams { get; } = new();
public HashSet<int> PendingStreams { get; } = new();
public long LastHeartbeat { get; set; }
public ActiveClient(
string clientKey,
uint stubIp,
Socket socket,
Action<ActiveClient, Msg> messageHandler,
Action<ActiveClient> disconnectHandler,
ILogger<ActiveClient> logger)
{
ClientKey = clientKey;
StubIp = stubIp;
_socket = socket;
_messageHandler = messageHandler;
_disconnectHandler = disconnectHandler;
_logger = logger;
var stream = new NetworkStream(socket);
_reader = new StreamReader(stream, Encoding.UTF8);
_writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
LastHeartbeat = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
_thread = new Thread(HandleMessages)
{
IsBackground = true
};
_thread.Start();
}
private void HandleMessages()
{
try
{
while (_socket.Connected)
{
var line = _reader.ReadLine();
if (line == null) break;
var msg = Msg.FromString(line);
_messageHandler(this, msg);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error handling messages for client {ClientKey}", ClientKey);
}
finally
{
_disconnectHandler(this);
}
}
public void Send(Msg msg)
{
lock (_writeLock)
{
try
{
_writer.WriteLine(msg.ToString());
}
catch (Exception ex)
{
_logger.LogError(ex, "Error sending message to client {ClientKey}", ClientKey);
Disconnect();
}
}
}
public void Disconnect()
{
try
{
_socket.Close();
_reader.Dispose();
_writer.Dispose();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error disconnecting client {ClientKey}", ClientKey);
}
}
}
}