using System; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Net; using Microsoft.Extensions.Logging; namespace Jellyfin.SocketSharp { public class SharpWebSocket : IWebSocket { /// /// The logger /// private readonly ILogger _logger; public event EventHandler Closed; /// /// Gets or sets the web socket. /// /// The web socket. private SocketHttpListener.WebSocket WebSocket { get; set; } private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); public SharpWebSocket(SocketHttpListener.WebSocket socket, ILogger logger) { if (socket == null) { throw new ArgumentNullException(nameof(socket)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } _logger = logger; WebSocket = socket; socket.OnMessage += socket_OnMessage; socket.OnClose += socket_OnClose; socket.OnError += socket_OnError; WebSocket.ConnectAsServer(); } public Task StartReceive() { return _taskCompletionSource.Task; } void socket_OnError(object sender, SocketHttpListener.ErrorEventArgs e) { _logger.LogError("Error in SharpWebSocket: {Message}", e.Message ?? string.Empty); //Closed?.Invoke(this, EventArgs.Empty); } void socket_OnClose(object sender, SocketHttpListener.CloseEventArgs e) { _taskCompletionSource.TrySetResult(true); Closed?.Invoke(this, EventArgs.Empty); } void socket_OnMessage(object sender, SocketHttpListener.MessageEventArgs e) { //if (!string.IsNullOrEmpty(e.Data)) //{ // if (OnReceive != null) // { // OnReceive(e.Data); // } // return; //} if (OnReceiveBytes != null) { OnReceiveBytes(e.RawData); } } /// /// Gets or sets the state. /// /// The state. public WebSocketState State => WebSocket.ReadyState; /// /// Sends the async. /// /// The bytes. /// if set to true [end of message]. /// The cancellation token. /// Task. public Task SendAsync(byte[] bytes, bool endOfMessage, CancellationToken cancellationToken) { return WebSocket.SendAsync(bytes); } /// /// Sends the asynchronous. /// /// The text. /// if set to true [end of message]. /// The cancellation token. /// Task. public Task SendAsync(string text, bool endOfMessage, CancellationToken cancellationToken) { return WebSocket.SendAsync(text); } /// /// 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.OnMessage -= socket_OnMessage; WebSocket.OnClose -= socket_OnClose; WebSocket.OnError -= socket_OnError; _cancellationTokenSource.Cancel(); WebSocket.Close(); } } /// /// Gets or sets the receive action. /// /// The receive action. public Action OnReceiveBytes { get; set; } /// /// Gets or sets the on receive. /// /// The on receive. public Action OnReceive { get; set; } } }