| using System; | 
| using System.Threading; | 
| using Top.Api; | 
| using WebSocketSharp; | 
|   | 
| namespace Taobao.Top.Link.Channel.WebSocket | 
| { | 
|     /// <summary>simple websocket client helper | 
|     /// </summary> | 
|     public static class WebSocketClient | 
|     { | 
|         /// <summary>connect to uri via websocket | 
|         /// </summary> | 
|         /// <param name="uri">remote address</param> | 
|         /// <param name="timeout">timeout in milliseconds</param> | 
|         /// <returns></returns> | 
|         public static IClientChannel Connect(Uri uri, int timeout) | 
|         { | 
|             return Connect(Log.Instance, uri, timeout); | 
|         } | 
|         /// <summary>connect to uri via websocket | 
|         /// </summary> | 
|         /// <param name="loggerFactory">loggerFactory</param> | 
|         /// <param name="uri">remote address</param> | 
|         /// <param name="timeout">timeout in milliseconds</param> | 
|         /// <returns></returns> | 
|         public static IClientChannel Connect(ITopLogger logger, Uri uri, int timeout) | 
|         { | 
|             //log first | 
|             var log = logger; | 
|   | 
|             var h = new WaitHandle(); | 
|             var onOpen = new EventHandler((o, e) => h.Set()); | 
|             var onError = new EventHandler<ErrorEventArgs>((o, e) => h.Set(e.Message)); | 
|   | 
|             var socket = new WebSocketSharp.WebSocket(uri.ToString()); | 
|             var channel = new WebSocketClientChannel(socket) { Uri = uri }; | 
|             socket.OnOpen += onOpen; | 
|             socket.OnError += onError; | 
|   | 
|             socket.Connect(); | 
|   | 
|             if (!h.WaitOne(timeout, false)) | 
|                 throw new LinkException("connect timeout"); | 
|             if (h.IsError) | 
|                 throw new LinkException(h.Error); | 
|   | 
|             socket.OnOpen -= onOpen; | 
|             socket.OnError -= onError; | 
|   | 
|             socket.OnError += (o, e) => On(log | 
|                 , channel.OnError | 
|                 , new ChannelContext(new LinkException(e.Message))); | 
|             socket.OnClose += (o, e) => On(log | 
|                 , channel.OnClosed | 
|                 , new ChannelClosedEventArgs(e.Reason)); | 
|             socket.OnMessage += (o, e) => On(log | 
|                 , channel.OnMessage | 
|                 , new ChannelContext(e.RawData, channel)); | 
|             return channel; | 
|         } | 
|   | 
|         private static void On<T>(ITopLogger log, EventHandler<T> eventHandler, T args) where T : EventArgs | 
|         { | 
|             try | 
|             { | 
|                 if (eventHandler != null) | 
|                     eventHandler(null, args); | 
|             } | 
|             catch (Exception e) | 
|             { | 
|                 //here is global on error | 
|                 log.Error(e.StackTrace); | 
|                 //TODO:close channel here? | 
|             } | 
|         } | 
|   | 
|         class WaitHandle : EventWaitHandle | 
|         { | 
|             public bool IsError { get; private set; } | 
|             public string Error { get; private set; } | 
|             public WaitHandle() : base(false, EventResetMode.AutoReset) { } | 
|             public void Set(string error) | 
|             { | 
|                 this.IsError = true; | 
|                 this.Error = error; | 
|                 this.Set(); | 
|             } | 
|         } | 
|     } | 
| } |