aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs
blob: c8ab58ca40b1089f3236b5ff806fe024b5debfb9 (plain)
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using Alchemy.Classes;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Logging;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MediaBrowser.Networking.WebSocket
{
    /// <summary>
    /// Class AlchemyWebSocket
    /// </summary>
    public class AlchemyWebSocket : IWebSocket
    {
        /// <summary>
        /// The logger
        /// </summary>
        private readonly ILogger _logger;

        /// <summary>
        /// Gets or sets the web socket.
        /// </summary>
        /// <value>The web socket.</value>
        private UserContext UserContext { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="AlchemyWebSocket" /> class.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="logger">The logger.</param>
        /// <exception cref="System.ArgumentNullException">context</exception>
        public AlchemyWebSocket(UserContext context, ILogger logger)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            _logger = logger;
            UserContext = context;

            context.SetOnDisconnect(OnDisconnected);
            context.SetOnReceive(OnReceive);

            _logger.Info("Client connected from {0}", context.ClientAddress);
        }

        /// <summary>
        /// The _disconnected
        /// </summary>
        private bool _disconnected = false;
        /// <summary>
        /// Gets or sets the state.
        /// </summary>
        /// <value>The state.</value>
        public WebSocketState State
        {
            get { return _disconnected ? WebSocketState.Closed : WebSocketState.Open; }
        }

        /// <summary>
        /// Called when [disconnected].
        /// </summary>
        /// <param name="context">The context.</param>
        private void OnDisconnected(UserContext context)
        {
            _disconnected = true;
        }

        /// <summary>
        /// Called when [receive].
        /// </summary>
        /// <param name="context">The context.</param>
        private void OnReceive(UserContext context)
        {
            if (OnReceiveDelegate != null)
            {
                var json = context.DataFrame.ToString();

                if (!string.IsNullOrWhiteSpace(json))
                {
                    try
                    {
                        var bytes = Encoding.UTF8.GetBytes(json);

                        OnReceiveDelegate(bytes);
                    }
                    catch (Exception ex)
                    {
                        _logger.ErrorException("Error processing web socket message", ex);
                    }
                }
            }
        }
        
        /// <summary>
        /// Sends the async.
        /// </summary>
        /// <param name="bytes">The bytes.</param>
        /// <param name="type">The type.</param>
        /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Task.</returns>
        public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken)
        {
            return Task.Run(() => UserContext.Send(bytes));
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources.
        /// </summary>
        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool dispose)
        {
        }

        /// <summary>
        /// Gets or sets the receive action.
        /// </summary>
        /// <value>The receive action.</value>
        public Action<byte[]> OnReceiveDelegate { get; set; }
    }
}