using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using WebSocket = WebSocketSharp.WebSocket;
using CsharpHttpHelper;
using WebSocketSharp;
namespace Api.Framework
{
///
/// 通知客户端
///
public class NoticeSocketClient
{
///
/// 发送Ack模式通知数据
///
public class AckNoticeData : EventArgs
{
///
/// ID
///
public string Id { get; set; }
///
/// 命令ID
///
public string CommonId { get; set; }
///
/// 信号道
///
public string Channel { get; set; }
///
/// 数据
///
public string Data { get; set; }
///
/// 生成时间
///
public DateTime CreateDateTime { get; set; }
///
/// 标记被删除
///
public bool IsRemove { get; set; }
///
/// 重试
///
public bool IsRetry { get; set; }
}
///
/// 构造函数
///
///
///
public NoticeSocketClient(string host, params string[] channel)
{
this._host = host;
this._channels = channel.ToArray();
}
private readonly string[] _channels;
private readonly string _host;
///
/// 连接对象
///
private WebSocket _websocket;
///
/// 连接状态
///
public bool IsConnected => (_websocket != null && _websocket.IsAlive);
private string ClientId { get; set; } = Guid.NewGuid().ToString("N");
///
/// 连接
///
public void Connect()
{
if (IsConnected)
{
_websocket.OnOpen -= _websocket_OnOpen;
_websocket.OnMessage -= _websocket_OnMessage;
_websocket?.Close();
}
_websocket = new WebSocket($"ws://{this._host}/api/push?id={ClientId}");
_websocket.OnOpen += _websocket_OnOpen;
_websocket.OnError += _websocket_OnError;
_websocket.OnClose += _websocket_OnClose;
_websocket.OnMessage += _websocket_OnMessage;
_websocket.Connect();
_pingId = Guid.NewGuid().ToString("N");
_thread = new Thread(Ping)
{
IsBackground = true
};
_thread.Start();
}
///
/// 连接断开
///
///
///
private void _websocket_OnClose(object sender, CloseEventArgs e)
{
//断开自动重连
this.Connect();
}
///
/// 出现连接错误
///
///
///
private void _websocket_OnError(object sender, ErrorEventArgs e)
{
//断开自动重连
this.Connect();
}
///
/// 收到消息事件
///
public event EventHandler OnMessageEvent;
///
/// 连接成功事件
///
public event EventHandler OnConnectedEvent;
private void _websocket_OnMessage(object sender, WebSocketSharp.MessageEventArgs e)
{
try
{
var index = e.Data.IndexOf("\u0000", StringComparison.Ordinal);
if (index <= -1)
{
return;
}
var commonId = e.Data.Substring(0, index);
if (commonId != "notice") return;
var body = e.Data.Substring(index + 1);
var data = JsonConvert.DeserializeObject(body);
if (data == null || string.IsNullOrEmpty(data.Id)) return;
this._websocket.Send("notice_ack\u0000" + data.Id);
OnMessageEvent?.Invoke(this, data);
}
catch (Exception ex)
{
Console.WriteLine($"即时通讯API接收异常:{ex.Message}");
}
}
private Thread _thread;
private void _websocket_OnOpen(object sender, System.EventArgs e)
{
try
{
foreach (var v in this._channels)
{
this._websocket.Send($"subchannel\u0000{v}");//订阅通道
}
this.OnConnectedEvent?.Invoke(this, EventArgs.Empty);
}
catch (Exception ex)
{
Console.WriteLine($"即时通讯API连接异常:{ex.Message}");
}
}
private int PingFailureCount { get; set; }
private string _pingId = Guid.NewGuid().ToString();
private void Ping()
{
var id = Guid.NewGuid().ToString();
_pingId = id;
while (_pingId == id)
{
Thread.Sleep(1000 * 10);
try
{
//测试ping是否正常
try
{
if (_websocket == null)
{
continue;
}
if (_websocket.ReadyState == WebSocketState.Open)
{
_websocket.Send("\u0001\u0002");
this.PingFailureCount = 0;
}
else
{
this.PingFailureCount = this.PingFailureCount + 1;
}
}
catch
{
// ignored
this.PingFailureCount = this.PingFailureCount + 1;
}
finally
{
if (this.PingFailureCount > 5)
{
Console.WriteLine("心跳异常连接断开");
_websocket?.Close();
}
}
}
catch (Exception e)
{
Console.WriteLine($"即时通讯API Ping异常:{e.Message}");
}
}
// ReSharper disable once FunctionNeverReturns
}
///
/// 获取数据
///
///
///
public string GetData(string key)
{
var http = new HttpHelper();
var html = http.GetHtml($"http://{this._host}/api/TransferData/Get?key={key}&rd={DateTime.Now.Ticks}").Html;
var rest = JObject.Parse(html);
//if (!(rest["Ok"] ?? false).Value() throw new Exception(html);
//return (rest["Data"] ?? string.Empty).Value();
//EventClient.OnEvent($"获取淘客域名数据", $"{html}");
if (!(rest["Ok"] ?? false).Value())
throw new Exception(html);
return (rest["Data"] ?? string.Empty).Value();
}
}
}