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(); } } }