using MediaBrowser.Common.Net; using MediaBrowser.Model.Logging; using System; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using WebSocketMessageType = MediaBrowser.Model.Net.WebSocketMessageType; using WebSocketState = MediaBrowser.Model.Net.WebSocketState; namespace MediaBrowser.Server.Implementations.HttpServer { /// /// Class NativeWebSocket /// public class NativeWebSocket : IWebSocket { /// /// The logger /// private readonly ILogger _logger; /// /// Gets or sets the web socket. /// /// The web socket. private System.Net.WebSockets.WebSocket WebSocket { get; set; } /// /// Initializes a new instance of the class. /// /// The socket. /// The logger. /// socket public NativeWebSocket(System.Net.WebSockets.WebSocket socket, ILogger logger) { if (socket == null) { throw new ArgumentNullException("socket"); } if (logger == null) { throw new ArgumentNullException("logger"); } _logger = logger; WebSocket = socket; Receive(); } /// /// Gets or sets the state. /// /// The state. public WebSocketState State { get { WebSocketState commonState; if (!Enum.TryParse(WebSocket.State.ToString(), true, out commonState)) { _logger.Warn("Unrecognized WebSocketState: {0}", WebSocket.State.ToString()); } return commonState; } } /// /// Receives this instance. /// private async void Receive() { while (true) { byte[] bytes; try { bytes = await ReceiveBytesAsync(CancellationToken.None).ConfigureAwait(false); } catch (WebSocketException ex) { _logger.ErrorException("Error receiving web socket message", ex); break; } if (OnReceiveDelegate != null) { OnReceiveDelegate(bytes); } } } /// /// Receives the async. /// /// The cancellation token. /// Task{WebSocketMessageInfo}. /// Connection closed private async Task ReceiveBytesAsync(CancellationToken cancellationToken) { var bytes = new byte[4096]; var buffer = new ArraySegment(bytes); var result = await WebSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false); if (result.CloseStatus.HasValue) { throw new WebSocketException("Connection closed"); } return buffer.Array; } /// /// Sends the async. /// /// The bytes. /// The type. /// if set to true [end of message]. /// The cancellation token. /// Task. public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken) { System.Net.WebSockets.WebSocketMessageType nativeType; if (!Enum.TryParse(type.ToString(), true, out nativeType)) { _logger.Warn("Unrecognized WebSocketMessageType: {0}", type.ToString()); } return WebSocket.SendAsync(new ArraySegment(bytes), nativeType, true, cancellationToken); } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { Dispose(true); } /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { if (dispose) { WebSocket.Dispose(); } } /// /// Gets or sets the receive action. /// /// The receive action. public Action OnReceiveDelegate { get; set; } } }