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