using System;
using System.Threading;
using Top.Api;
using WebSocketSharp;
namespace Taobao.Top.Link.Channel.WebSocket
{
/// simple websocket client helper
///
public static class WebSocketClient
{
/// connect to uri via websocket
///
/// remote address
/// timeout in milliseconds
///
public static IClientChannel Connect(Uri uri, int timeout)
{
return Connect(Log.Instance, uri, timeout);
}
/// connect to uri via websocket
///
/// loggerFactory
/// remote address
/// timeout in milliseconds
///
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((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(ITopLogger log, EventHandler 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();
}
}
}
}