1
wtt
2024-08-16 e03677790c63aba9379b84c976d172c3dcd0127a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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();
            }
        }
    }
}