using System; using System.Collections.Generic; using System.Text; using WebSocketSharp; using WebSocketSharp.Frame; namespace Taobao.Top.Link.Channel.WebSocket { /// websocket clientchannel via websocket-sharp impl /// public class WebSocketClientChannel : IClientChannel { private WebSocketSharp.WebSocket _socket; private ResetableTimer _timer; private EventHandler _onMessage; private EventHandler _onError; private EventHandler _onClosed; public EventHandler OnMessage { get { this.DelayPing(); return this._onMessage; } set { this._onMessage = value; } } public EventHandler OnError { get { this.DelayPing(); return this._onError; } set { this._onError = value; } } public EventHandler OnClosed { get { return this._onClosed; } set { this._onClosed = value; } } public Uri Uri { get; set; } public bool IsConnected { get { return this._socket.ReadyState == WsState.OPEN; } } public WebSocketClientChannel(WebSocketSharp.WebSocket socket) { this._socket = socket; this._onClosed += (o, e) => { this.Close(e.Reason); }; } public void Send(byte[] data) { this.CheckChannel(); this._socket.Send(data); } public void Close(string reason) { this._socket.Close(CloseStatusCode.NORMAL, reason); if (this._timer != null) { this._timer.Cancel(); this._timer = null; #if DEBUG Console.WriteLine("TMC: Info@close: " + reason); #endif } } public ResetableTimer HeartbeatTimer { set { this._timer = value; this._timer.Elapsed += (s, e) => { if (this.IsConnected) //websocket-sharp's ping is sync this._socket.Ping(); }; } } private void CheckChannel() { if (!this.IsConnected) { if (this._timer != null) this._timer.Cancel(); throw new LinkException("websocket channel closed"); } this.DelayPing(); } private void DelayPing() { try { if (this._timer != null) this._timer.Delay(); } catch (Exception) { } } } }