Winify – Rev 1

Subversion Repositories:
Rev:
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using ClientWebSocket = System.Net.WebSockets.Managed.ClientWebSocket;

namespace Winify.Gotify
{
    public class GotifyConnection : IDisposable
    {
        #region Public Events & Delegates

        public event EventHandler<GotifyNotificationEventArgs> GotifyNotification;

        #endregion

        #region Private Delegates, Events, Enums, Properties, Indexers and Fields

        private CancellationToken _cancellationToken;

        private CancellationTokenSource _cancellationTokenSource;

        private HttpClient _httpClient;

        private Task _runTask;

        private ClientWebSocket _webSocketClient;

        #endregion

        #region Constructors, Destructors and Finalizers

        public void Dispose()
        {
            if (_cancellationTokenSource != null)
            {
                _cancellationTokenSource.Dispose();
                _cancellationTokenSource = null;
            }

            if (_webSocketClient != null)
            {
                _webSocketClient.Dispose();
                _webSocketClient = null;
            }

            if (_httpClient != null)
            {
                _httpClient.Dispose();
                _httpClient = null;
            }
        }

        #endregion

        #region Public Methods

        public void Start(string username, string password, string host, string port)
        {
            if (!Uri.TryCreate($"ws://{host}:{port}/stream", UriKind.RelativeOrAbsolute, out var webSocketsUri))
            {
                return;
            }

            if (!Uri.TryCreate($"http://{host}:{port}/", UriKind.RelativeOrAbsolute, out var httpUri))
            {
                return;
            }

            _cancellationTokenSource = new CancellationTokenSource();
            _cancellationToken = _cancellationTokenSource.Token;

            var httpClientHandler = new HttpClientHandler
            {
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
            };

            _httpClient = new HttpClient(httpClientHandler)
            {
                BaseAddress = httpUri
            };
            var auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);

            _runTask = Run(webSocketsUri, username, password, _cancellationToken);
        }

        public void Stop()
        {
            if (_cancellationTokenSource != null)
            {
                _cancellationTokenSource.Cancel();
            }
        }

        #endregion

        #region Private Methods

        private async Task Run(Uri uri, string username, string password, CancellationToken cancellationToken)
        {
            try
            {
                do
                {
                    try
                    {
                        _webSocketClient = new ClientWebSocket();
                        var auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
                        _webSocketClient.Options.SetRequestHeader("Authorization", $"Basic {auth}");

                        await _webSocketClient.ConnectAsync(uri, cancellationToken);

                        do
                        {
                            var payload = new ArraySegment<byte>(new byte[1024]);

                            await _webSocketClient.ReceiveAsync(payload, cancellationToken);

                            if (payload.Array == null || payload.Count == 0)
                            {
                                continue;
                            }

                            var message = Encoding.UTF8.GetString(payload.Array, 0, payload.Count);

                            var gotifyNotification = JsonConvert.DeserializeObject<GotifyNotification>(message);
                            if (gotifyNotification == null)
                            {
                                continue;
                            }

                            var applications = await _httpClient.GetStringAsync("application");

                            var gotifyApplications = JsonConvert.DeserializeObject<GotifyApplication[]>(applications);
                            if (gotifyApplications == null)
                            {
                                continue;
                            }

                            foreach (var application in gotifyApplications)
                            {
                                if (application.Id != gotifyNotification.AppId)
                                {
                                    continue;
                                }

                                var imageBytes = await _httpClient.GetByteArrayAsync(application.Image);
                                using (var memoryStream = new MemoryStream(imageBytes))
                                {
                                    var image = Image.FromStream(memoryStream);

                                    if (GotifyNotification != null)
                                    {
                                        GotifyNotification.Invoke(this,
                                            new GotifyNotificationEventArgs(gotifyNotification, image));
                                    }
                                }


                                break;
                            }

                            Debug.WriteLine($"{gotifyNotification.Message}");
                        } while (!cancellationToken.IsCancellationRequested);

                        await _webSocketClient.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
                            CancellationToken.None);
                    }
                    catch (WebSocketException)
                    {
                        // Reconnect
                        if (_webSocketClient != null)
                        {
                            _webSocketClient.Abort();
                            _webSocketClient.Dispose();
                            _webSocketClient = null;
                        }

                        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
                    }
                } while (!cancellationToken.IsCancellationRequested);
            }
            catch (Exception ex) when (ex is OperationCanceledException || ex is ObjectDisposedException)
            {
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"Exception: {ex}");
            }
        }

        #endregion
    }
}

Generated by GNU Enscript 1.6.5.90.