Winify

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 58  →  ?path2? @ 59
/trunk/Winify/Gotify/GotifyConnection.cs
@@ -4,7 +4,6 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
@@ -15,8 +14,6 @@
using Servers;
using WebSocketSharp;
using WebSocketSharp.Net;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
using Configuration = Configuration.Configuration;
using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;
using NetworkCredential = System.Net.NetworkCredential;
 
@@ -46,7 +43,8 @@
 
private readonly Uri _httpUri;
private WebSocket _webSocketSharp;
private readonly global::Configuration.Configuration _configuration;
private readonly Configuration.Configuration _configuration;
private Task _initTask;
 
#endregion
 
@@ -54,16 +52,15 @@
 
private GotifyConnection()
{
 
}
 
public GotifyConnection(Server server, global::Configuration.Configuration configuration) : this()
public GotifyConnection(Server server, Configuration.Configuration configuration) : this()
{
_server = server;
_configuration = configuration;
 
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var httpClientHandler = new HttpClientHandler()
var httpClientHandler = new HttpClientHandler
{
// mono does not implement this
//SslProtocols = SslProtocols.Tls12
@@ -71,23 +68,17 @@
 
_httpClient = new HttpClient(httpClientHandler);
if (_configuration.IgnoreSelfSignedCertificates)
{
httpClientHandler.ServerCertificateCustomValidationCallback =
(httpRequestMessage, cert, cetChain, policyErrors) => true;
}
 
if (_configuration.Proxy.Enable)
{
httpClientHandler.Proxy = new WebProxy(_configuration.Proxy.Url, false, new string[] { },
new NetworkCredential(_configuration.Proxy.Username, _configuration.Proxy.Password));
}
 
_httpClient = new HttpClient(httpClientHandler);
if (!string.IsNullOrEmpty(_server.Username) && !string.IsNullOrEmpty(_server.Password))
{
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.Default.GetBytes($"{_server.Username}:{_server.Password}")));
}
 
if (!Uri.TryCreate(_server.Url, UriKind.Absolute, out _httpUri))
{
@@ -113,7 +104,8 @@
}
catch (ArgumentException exception)
{
Log.Error($"No WebSockets URL could be built from the provided URL {_server.Url} due to {exception.Message}");
Log.Error(
$"No WebSockets URL could be built from the provided URL {_server.Url} due to {exception.Message}");
}
 
_webSocketsUri = webSocketsUriBuilder.Uri;
@@ -157,6 +149,11 @@
 
Connect();
 
if (_configuration.RetrievePastNotificationHours != 0)
{
_initTask = RetrievePastMessages(_cancellationToken);
}
 
_runTask = Run(_cancellationToken);
}
 
@@ -166,20 +163,15 @@
_webSocketSharp.SslConfiguration = new ClientSslConfiguration(_webSocketsUri.Host,
new X509CertificateCollection(new X509Certificate[] { }), SslProtocols.Tls12, false);
if (_configuration.Proxy.Enable)
{
_webSocketSharp.SetProxy(_configuration.Proxy.Url, _configuration.Proxy.Username, _configuration.Proxy.Password);
}
_webSocketSharp.SetProxy(_configuration.Proxy.Url, _configuration.Proxy.Username,
_configuration.Proxy.Password);
 
if (!string.IsNullOrEmpty(_server.Username) && !string.IsNullOrEmpty(_server.Password))
{
_webSocketSharp.SetCredentials(_server.Username, _server.Password, true);
}
 
if (_configuration.IgnoreSelfSignedCertificates)
{
_webSocketSharp.SslConfiguration.ServerCertificateValidationCallback +=
(sender, certificate, chain, errors) => true;
}
 
_webSocketSharp.Log.Output = (logData, s) =>
{
@@ -190,13 +182,14 @@
_webSocketSharp.OnError += WebSocketSharp_OnError;
_webSocketSharp.OnOpen += WebSocketSharp_OnOpen;
_webSocketSharp.OnClose += WebSocketSharp_OnClose;
 
_webSocketSharp.ConnectAsync();
}
 
private void WebSocketSharp_OnClose(object sender, CloseEventArgs e)
{
Log.Information($"WebSockets connection to server {_webSocketsUri.AbsoluteUri} closed with reason {e.Reason}");
Log.Information(
$"WebSockets connection to server {_webSocketsUri.AbsoluteUri} closed with reason {e.Reason}");
}
 
private void WebSocketSharp_OnOpen(object sender, EventArgs e)
@@ -206,7 +199,9 @@
 
private async void WebSocketSharp_OnError(object sender, ErrorEventArgs e)
{
Log.Error($"Connection to WebSockets server {_webSocketsUri.AbsoluteUri} terminated unexpectedly with message {e.Message}", e.Exception);
Log.Error(
$"Connection to WebSockets server {_webSocketsUri.AbsoluteUri} terminated unexpectedly with message {e.Message}",
e.Exception);
 
if (_cancellationToken.IsCancellationRequested)
{
@@ -224,17 +219,17 @@
{
if (e.RawData.Length == 0)
{
Log.Warning($"Empty message received from server");
Log.Warning("Empty message received from server");
return;
}
 
var message = Encoding.UTF8.GetString(e.RawData, 0, e.RawData.Length);
 
GotifyNotification gotifyNotification;
GotifyMessage gotifyNotification;
 
try
{
gotifyNotification = JsonConvert.DeserializeObject<GotifyNotification>(message);
{
gotifyNotification = JsonConvert.DeserializeObject<GotifyMessage>(message);
}
catch (JsonSerializationException exception)
{
@@ -251,15 +246,21 @@
 
gotifyNotification.Server = _server;
 
if (!Uri.TryCreate(Path.Combine($"{_httpUri}", "application"), UriKind.Absolute,
out var applicationUri))
var applicationUriBuilder = new UriBuilder(_httpUri);
try
{
Log.Warning($"Could not build an URI to an application");
applicationUriBuilder.Path = Path.Combine(applicationUriBuilder.Path, "application");
}
catch (ArgumentException exception)
{
Log.Warning("Could not build an URI to an application");
 
return;
}
 
using (var imageStream =
await RetrieveGotifyApplicationImage(gotifyNotification.AppId, applicationUri, _cancellationToken))
await RetrieveGotifyApplicationImage(gotifyNotification.AppId, applicationUriBuilder.Uri,
_cancellationToken))
{
if (imageStream == null)
{
@@ -278,7 +279,9 @@
 
public void Stop()
{
if (_cancellationTokenSource != null) _cancellationTokenSource.Cancel();
if (_cancellationTokenSource == null) return;
 
_cancellationTokenSource.Cancel();
}
 
#endregion
@@ -285,6 +288,79 @@
 
#region Private Methods
 
private async Task RetrievePastMessages(CancellationToken cancellationToken)
{
var messageUriBuilder = new UriBuilder(_httpUri);
foreach (var application in await RetrieveGotifyApplications(cancellationToken))
{
try
{
messageUriBuilder.Path = Path.Combine(messageUriBuilder.Path, "application", $"{application.Id}",
"message");
}
catch (ArgumentException exception)
{
Log.Error($"No application URL could be built for {_server.Url} due to {exception.Message}");
 
continue;
}
 
var messagesResponse = await _httpClient.GetAsync(messageUriBuilder.Uri, cancellationToken);
 
 
var messages = await messagesResponse.Content.ReadAsStringAsync();
 
GotifyMessageQuery gotifyMessageQuery;
try
{
gotifyMessageQuery =
JsonConvert.DeserializeObject<GotifyMessageQuery>(messages);
}
catch (JsonSerializationException exception)
{
Log.Warning($"Could not deserialize the message response: {exception.Message}");
 
continue;
}
 
var applicationUriBuilder = new UriBuilder(_httpUri);
try
{
applicationUriBuilder.Path = Path.Combine(applicationUriBuilder.Path, "application");
}
catch (ArgumentException exception)
{
Log.Warning($"Could not build an URI to an application: {exception}");
 
return;
}
 
foreach (var message in gotifyMessageQuery.Messages)
{
if (message.Date < DateTime.Now - TimeSpan.FromHours(_configuration.RetrievePastNotificationHours))
continue;
 
message.Server = _server;
 
using (var imageStream =
await RetrieveGotifyApplicationImage(message.AppId, applicationUriBuilder.Uri,
_cancellationToken))
{
if (imageStream == null)
{
Log.Warning("Could not find any application image for notification");
return;
}
 
var image = Image.FromStream(imageStream);
 
GotifyNotification?.Invoke(this,
new GotifyNotificationEventArgs(message, image));
}
}
}
}
 
private async Task Run(CancellationToken cancellationToken)
{
try
@@ -294,7 +370,8 @@
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
} while (!cancellationToken.IsCancellationRequested);
}
catch (Exception exception) when (exception is OperationCanceledException || exception is ObjectDisposedException)
catch (Exception exception) when (exception is OperationCanceledException ||
exception is ObjectDisposedException)
{
}
catch (Exception exception)
@@ -303,6 +380,38 @@
}
}
 
private async Task<GotifyApplication[]> RetrieveGotifyApplications(CancellationToken cancellationToken)
{
var applicationsUriBuilder = new UriBuilder(_httpUri);
try
{
applicationsUriBuilder.Path = Path.Combine(applicationsUriBuilder.Path, "application");
}
catch (ArgumentException exception)
{
Log.Error($"No application URL could be built for {_server.Url} due to {exception}");
}
 
var applicationsResponse = await _httpClient.GetAsync(applicationsUriBuilder.Uri, cancellationToken);
 
var applications = await applicationsResponse.Content.ReadAsStringAsync();
 
GotifyApplication[] gotifyApplications;
try
{
gotifyApplications =
JsonConvert.DeserializeObject<GotifyApplication[]>(applications);
}
catch (JsonSerializationException exception)
{
Log.Warning($"Could not deserialize the list of applications from the server: {exception}");
 
return null;
}
 
return gotifyApplications;
}
 
private async Task<Stream> RetrieveGotifyApplicationImage(int appId, Uri applicationUri,
CancellationToken cancellationToken)
{