using System; using System.Net.WebSockets; using System.Text; using System.Threading; using System.Threading.Tasks; using Emby.Server.Implementations.Net; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.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 WebSocket WebSocket { get; set; } private TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private bool _disposed = false; public SharpWebSocket(WebSocket socket, ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); WebSocket = socket ?? throw new ArgumentNullException(nameof(socket)); } public Task StartReceive() { return _taskCompletionSource.Task; } private void OnSocketError(object sender, SocketHttpListener.ErrorEventArgs e) { _logger.LogError("Error in SharpWebSocket: {Message}", e.Message ?? string.Empty); // Closed?.Invoke(this, EventArgs.Empty); } private void OnSocketClose(object sender, SocketHttpListener.CloseEventArgs e) { _taskCompletionSource.TrySetResult(true); Closed?.Invoke(this, EventArgs.Empty); } private void OnSocketMessage(SocketHttpListener.MessageEventArgs e) { if (OnReceiveBytes != null) { OnReceiveBytes(e.RawData); } } public Task ConnectAsServerAsync() { return Task.CompletedTask; } /// /// Gets or sets the state. /// /// The state. public WebSocketState State => WebSocket.State; /// /// 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(new ArraySegment(bytes), WebSocketMessageType.Binary, endOfMessage, cancellationToken); } /// /// 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(new ArraySegment(Encoding.UTF8.GetBytes(text)), WebSocketMessageType.Text, endOfMessage, cancellationToken); } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// 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 (_disposed) { return; } if (dispose) { _cancellationTokenSource.Cancel(); // TODO // WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "bye", CancellationToken.None).GetAwaiter().GetResult(); } _disposed = true; } /// /// Gets or sets the receive action. /// /// The receive action. public Action OnReceiveBytes { get; set; } } }