using System.Collections.Concurrent;
|
using System.Net.Sockets;
|
using WIDESEAWCS_QuartzJob;
|
using WIDESEAWCS_Tasks.SocketServer;
|
|
namespace WIDESEAWCS_Tasks
|
{
|
/// <summary>
|
/// 机械手客户端连接管理器 - 负责TCP客户端连接管理和事件订阅
|
/// </summary>
|
public class RobotClientManager
|
{
|
private readonly TcpSocketServer _tcpSocket;
|
private readonly RobotStateManager _stateManager;
|
|
// 跟踪已经启动 HandleClientAsync 的客户端
|
private static readonly ConcurrentDictionary<string, bool> _handleClientStarted = new();
|
private static int _eventSubscribedFlag;
|
|
public event EventHandler<RobotSocketState>? OnClientDisconnected;
|
|
public RobotClientManager(TcpSocketServer tcpSocket, RobotStateManager stateManager)
|
{
|
_tcpSocket = tcpSocket;
|
_stateManager = stateManager;
|
}
|
|
/// <summary>
|
/// 确保客户端已连接并订阅消息事件
|
/// </summary>
|
/// <param name="ipAddress">设备IP地址</param>
|
/// <param name="robotCrane">机器人设备信息</param>
|
/// <returns>客户端是否可用(已连接且消息处理已启动)</returns>
|
public bool EnsureClientSubscribed(string ipAddress, RobotCraneDevice robotCrane)
|
{
|
// 检查是否有该客户端连接
|
var clientIds = _tcpSocket.GetClientIds();
|
bool isClientConnected = clientIds.Contains(ipAddress);
|
|
if (!isClientConnected)
|
{
|
// 客户端未连接,清理 HandleClientAsync 状态
|
_handleClientStarted.TryRemove(ipAddress, out _);
|
return false;
|
}
|
|
// 订阅一次 robot 事件(全局一次)- message事件由RobotJob订阅
|
if (System.Threading.Interlocked.CompareExchange(ref _eventSubscribedFlag, 1, 0) == 0)
|
{
|
_tcpSocket.RobotReceived += OnRobotReceived;
|
Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 机器人TCP断开事件已订阅");
|
}
|
|
// 获取TcpClient
|
TcpClient? tcpClient = null;
|
_tcpSocket._clients.TryGetValue(ipAddress, out tcpClient);
|
|
if (tcpClient == null)
|
{
|
// isClientConnected为true但无法获取tcpClient,列表可能不同步
|
_handleClientStarted.TryRemove(ipAddress, out _);
|
return false;
|
}
|
|
// 检查是否已经为这个客户端启动过 HandleClientAsync
|
bool alreadyStarted = _handleClientStarted.TryGetValue(ipAddress, out _);
|
|
if (!alreadyStarted)
|
{
|
Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 启动客户端消息处理: {ipAddress}");
|
|
// 重新获取最新的 state 对象
|
var latestStateForSubscribe = _stateManager.GetState(ipAddress);
|
if (latestStateForSubscribe != null)
|
{
|
// 标记为已启动
|
_handleClientStarted[ipAddress] = true;
|
|
_ = _tcpSocket.HandleClientAsync(tcpClient, robotCrane.IPAddress, _tcpSocket._cts.Token, latestStateForSubscribe)
|
.ContinueWith(t =>
|
{
|
if (t.IsFaulted)
|
{
|
Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] HandleClientAsync error: {t.Exception?.GetBaseException().Message}");
|
// 发生错误时,移除启动标志,允许下次重试
|
_handleClientStarted.TryRemove(ipAddress, out _);
|
}
|
}, TaskContinuationOptions.OnlyOnFaulted);
|
|
// 更新 IsEventSubscribed 状态
|
_stateManager.TryUpdateStateSafely(ipAddress, s =>
|
{
|
s.IsEventSubscribed = true;
|
return s;
|
});
|
}
|
}
|
|
return true;
|
}
|
|
/// <summary>
|
/// 事件:客户端断开连接时触发
|
/// </summary>
|
private Task<string?> OnRobotReceived(string clientId)
|
{
|
// 客户端断开连接,清理 HandleClientAsync 启动标志
|
_handleClientStarted.TryRemove(clientId, out _);
|
|
_stateManager.TryUpdateStateSafely(clientId, state =>
|
{
|
state.IsEventSubscribed = false;
|
state.CurrentAction = "";
|
state.OperStatus = "";
|
state.RobotArmObject = 0;
|
state.RobotControlMode = 0;
|
state.RobotRunMode = 0;
|
return state;
|
});
|
|
// 触发断开连接事件
|
OnClientDisconnected?.Invoke(this, _stateManager.GetState(clientId) ?? new RobotSocketState { IPAddress = clientId });
|
|
return Task.FromResult<string?>(null);
|
}
|
|
/// <summary>
|
/// 检查客户端是否已连接
|
/// </summary>
|
public bool IsClientConnected(string ipAddress)
|
{
|
var clientIds = _tcpSocket.GetClientIds();
|
return clientIds.Contains(ipAddress);
|
}
|
|
/// <summary>
|
/// 发送消息到客户端
|
/// </summary>
|
public async Task<bool> SendToClientAsync(string ipAddress, string message)
|
{
|
return await _tcpSocket.SendToClientAsync(ipAddress, message);
|
}
|
|
/// <summary>
|
/// 获取TcpSocketServer引用(用于RobotJob直接访问)
|
/// </summary>
|
public TcpSocketServer TcpSocket => _tcpSocket;
|
}
|
}
|