|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
using System;
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Text;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
using WebSocket4Net;
|
|
|
|
using CoreAgent.ProtocolClient.Models;
|
|
|
|
|
|
|
|
namespace CoreAgent.ProtocolClient.Managers.WebSocketMgr
|
|
|
|
{
|
|
|
|
public partial class WebSocketMessageManager
|
|
|
|
{
|
|
|
|
#region 公共方法
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 连接到WebSocket服务器
|
|
|
|
/// </summary>
|
|
|
|
public void Connect(string url, bool ssl = false)
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(url))
|
|
|
|
throw new ArgumentException("URL不能为空", nameof(url));
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_logger.LogInformation($"[{_clientName}] 尝试连接: {url}");
|
|
|
|
|
|
|
|
// 构建WebSocket URL
|
|
|
|
var fullUrl = (ssl ? "wss://" : "ws://") + url;
|
|
|
|
|
|
|
|
// 创建WebSocket实例
|
|
|
|
_webSocket = new WebSocket(fullUrl);
|
|
|
|
_webSocket.EnableAutoSendPing = false;
|
|
|
|
|
|
|
|
// 绑定事件处理器
|
|
|
|
_webSocket.Opened += OnSocketOpened!;
|
|
|
|
_webSocket.Closed += OnSocketClosed!;
|
|
|
|
_webSocket.MessageReceived += OnSocketMessageReceived!;
|
|
|
|
_webSocket.Error += OnSocketError!;
|
|
|
|
|
|
|
|
// 打开连接
|
|
|
|
_webSocket.Open();
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
_logger.LogError(ex, $"[{_clientName}] 连接异常: {ex.Message}");
|
|
|
|
ConnectionError?.Invoke(this, $"无法连接到 {url}: {ex.Message}");
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 断开WebSocket连接
|
|
|
|
/// </summary>
|
|
|
|
public void Disconnect()
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
_logger.LogInformation($"[{_clientName}] 断开连接");
|
|
|
|
|
|
|
|
// 停止消息发送定时器
|
|
|
|
StopMessageDeferTimer();
|
|
|
|
|
|
|
|
// 清空消息队列
|
|
|
|
ClearMessageQueue();
|
|
|
|
|
|
|
|
// 关闭WebSocket连接
|
|
|
|
if (_webSocket != null)
|
|
|
|
{
|
|
|
|
_webSocket.Close();
|
|
|
|
_webSocket = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
_logger.LogError(ex, $"[{_clientName}] 断开连接异常: {ex.Message}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 发送消息
|
|
|
|
/// </summary>
|
|
|
|
public long SendMessage(JObject message, Action<JObject>? callback = null, bool errorHandler = false)
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
|
|
|
|
if (message == null)
|
|
|
|
throw new ArgumentNullException(nameof(message));
|
|
|
|
|
|
|
|
// 检查连接状态
|
|
|
|
if (!IsConnected)
|
|
|
|
{
|
|
|
|
_logger.LogWarning($"[{_clientName}] WebSocket未连接,无法发送消息");
|
|
|
|
return -1L;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 使用MessageIdManager生成ID
|
|
|
|
var messageId = _messageIdManager.GenerateGeneralMessageId(message, callback, errorHandler);
|
|
|
|
|
|
|
|
// 添加到消息队列
|
|
|
|
_messageFifo.Add(message);
|
|
|
|
|
|
|
|
// 启动消息发送定时器
|
|
|
|
StartMessageDeferTimer();
|
|
|
|
|
|
|
|
_logger.LogDebug($"[{_clientName}] 消息已加入队列: message_id={messageId}");
|
|
|
|
return messageId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 发送日志获取消息
|
|
|
|
/// </summary>
|
|
|
|
public long SendLogGetMessage(JObject message, Action<JObject> callback)
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
|
|
|
|
if (message == null)
|
|
|
|
throw new ArgumentNullException(nameof(message));
|
|
|
|
|
|
|
|
if (callback == null)
|
|
|
|
throw new ArgumentNullException(nameof(callback));
|
|
|
|
|
|
|
|
// 检查连接状态
|
|
|
|
if (!IsConnected)
|
|
|
|
{
|
|
|
|
_logger.LogWarning($"[{_clientName}] WebSocket未连接,无法发送日志获取消息");
|
|
|
|
return -1L;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 使用MessageIdManager生成LogGet ID
|
|
|
|
var messageId = _messageIdManager.GenerateLogGetMessageId(message, callback);
|
|
|
|
|
|
|
|
// 将消息加入队列并启动定时器
|
|
|
|
_messageFifo.Add(message);
|
|
|
|
StartMessageDeferTimer();
|
|
|
|
|
|
|
|
_logger.LogDebug($"[{_clientName}] 日志获取消息已加入队列: message_id={messageId}");
|
|
|
|
return messageId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 处理接收到的消息
|
|
|
|
/// </summary>
|
|
|
|
public bool HandleReceivedMessage(JObject message, Action<string>? errorHandler = null)
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
|
|
|
|
if (message == null)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// 使用MessageIdManager处理消息响应
|
|
|
|
var handled = _messageIdManager.HandleMessageResponse(message, errorHandler);
|
|
|
|
|
|
|
|
if (handled)
|
|
|
|
{
|
|
|
|
_logger.LogDebug($"[{_clientName}] 消息已处理: message_id={message["message_id"]}");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 处理特定消息类型
|
|
|
|
var name = message["message"]?.ToString();
|
|
|
|
if (!string.IsNullOrEmpty(name))
|
|
|
|
{
|
|
|
|
_logger.LogDebug($"[{_clientName}] 未处理的特定消息类型: {name}");
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
_logger.LogError(ex, $"[{_clientName}] 处理消息异常: {ex.Message}");
|
|
|
|
errorHandler?.Invoke($"消息处理错误: {ex.Message}");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 设置消息处理器
|
|
|
|
/// </summary>
|
|
|
|
public void SetMessageHandler(string[] names, MessageHandler handler)
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
_messageIdManager.SetMessageHandler(names, handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 取消设置消息处理器
|
|
|
|
/// </summary>
|
|
|
|
public void UnsetMessageHandler(string[] names)
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
_messageIdManager.UnsetMessageHandler(names);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 检查是否为当前日志获取消息
|
|
|
|
/// </summary>
|
|
|
|
public bool IsCurrentLogGetMessage(long messageId)
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
return _messageIdManager.IsCurrentLogGetMessage(messageId);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 重置日志获取ID
|
|
|
|
/// </summary>
|
|
|
|
public void ResetLogGetId()
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
_messageIdManager.ResetLogGetId();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// 清理过期的消息处理器
|
|
|
|
/// </summary>
|
|
|
|
public void CleanupExpiredHandlers(int maxAge = 30000)
|
|
|
|
{
|
|
|
|
ThrowIfDisposed();
|
|
|
|
_messageIdManager.CleanupExpiredHandlers(maxAge);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|