Winify

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 82  →  ?path2? @ 83
/trunk/Winify/Gotify/GotifyApplication.cs
@@ -1,25 +1,107 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Winify.Properties;
 
namespace Winify.Gotify
{
public class GotifyApplication
public class GotifyApplication : INotifyPropertyChanged
{
private int _id;
private string _token;
private string _name;
private string _description;
private bool _internal;
private string _image;
 
#region Public Enums, Properties and Fields
 
[JsonProperty(PropertyName = "id")] public int Id { get; set; }
[JsonProperty(PropertyName = "id")]
public int Id
{
get => _id;
set
{
if (value == _id) return;
_id = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "token")] public string Token { get; set; }
[JsonProperty(PropertyName = "token")]
public string Token
{
get => _token;
set
{
if (value == _token) return;
_token = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "name")] public string Name { get; set; }
[JsonProperty(PropertyName = "name")]
public string Name
{
get => _name;
set
{
if (value == _name) return;
_name = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "description")]
public string Description { get; set; }
public string Description
{
get => _description;
set
{
if (value == _description) return;
_description = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "internal")]
public bool Internal { get; set; }
public bool Internal
{
get => _internal;
set
{
if (value == _internal) return;
_internal = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "image")] public string Image { get; set; }
[JsonProperty(PropertyName = "image")]
public string Image
{
get => _image;
set
{
if (value == _image) return;
_image = value;
OnPropertyChanged();
}
}
 
#endregion
 
[UsedImplicitly]
public GotifyApplication()
{
 
}
 
public event PropertyChangedEventHandler PropertyChanged;
 
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
/trunk/Winify/Gotify/GotifyConnection.cs
@@ -58,6 +58,9 @@
private Task _retrievePastMessagesTask;
private static JsonSerializer _jsonSerializer;
private readonly CancellationToken _programCancellationToken;
private CancellationTokenSource _localCancellationTokenSource;
private CancellationToken _localCancellationToken;
 
#endregion
 
@@ -118,10 +121,11 @@
new DataflowLinkOptions { PropagateCompletion = true });
}
 
public GotifyConnection(Server server, Configuration.Configuration configuration) : this()
public GotifyConnection(Server server, Configuration.Configuration configuration, CancellationToken cancellationToken) : this()
{
_server = server;
_configuration = configuration;
_programCancellationToken = cancellationToken;
 
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var httpClientHandler = new HttpClientHandler
@@ -172,10 +176,10 @@
 
public void Dispose()
{
if (_cancellationTokenSource != null)
if (_localCancellationTokenSource != null)
{
_cancellationTokenSource.Dispose();
_cancellationTokenSource = null;
_localCancellationTokenSource.Dispose();
_localCancellationTokenSource = null;
}
 
if (_tplWebSocketsBufferBlockTransformLink != null)
@@ -207,6 +211,32 @@
 
#region Public Methods
 
public async Task Stop()
{
_localCancellationTokenSource.Cancel();
 
if (_heartBeatTask != null)
{
await _heartBeatTask;
}
 
if (_retrievePastMessagesTask != null)
{
await _retrievePastMessagesTask;
}
 
if (_webSocketSharp != null)
{
_webSocketSharp.OnMessage -= WebSocketSharp_OnMessage;
_webSocketSharp.OnError -= WebSocketSharp_OnError;
_webSocketSharp.OnOpen -= WebSocketSharp_OnOpen;
_webSocketSharp.OnClose -= WebSocketSharp_OnClose;
 
_webSocketSharp.Close();
_webSocketSharp = null;
}
}
 
public void Start()
{
if (_webSocketsUri == null || _httpUri == null)
@@ -215,7 +245,11 @@
return;
}
 
_cancellationTokenSource = new CancellationTokenSource();
 
_localCancellationTokenSource = new CancellationTokenSource();
_localCancellationToken = _localCancellationTokenSource.Token;
 
_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(new [] { _programCancellationToken, _localCancellationToken });
_cancellationToken = _cancellationTokenSource.Token;
 
if (_webSocketSharp != null)
@@ -269,14 +303,20 @@
 
private async 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}");
 
await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken);
try
{
await Task.Delay(TimeSpan.FromSeconds(1), _programCancellationToken);
 
Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}");
Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}");
 
await Stop().ContinueWith(task => Start(), CancellationToken.None);
await Stop().ContinueWith(task => Start(), _programCancellationToken);
}
catch (Exception exception)
{
Log.Error(exception, "Error restarting WebSockets connection on connection closed.");
}
}
 
private void WebSocketSharp_OnOpen(object sender, EventArgs e)
@@ -283,18 +323,25 @@
{
Log.Information($"WebSockets connection to server {_webSocketsUri.AbsoluteUri} is now open");
 
_webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnUnresponsiveServer, _cancellationToken);
_webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnServerNotResponding, _cancellationToken);
}
 
private async void OnUnresponsiveServer()
private async void OnServerNotResponding()
{
Log.Warning($"Server {_server.Name} has not responded in a long while...");
 
await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken);
try
{
await Task.Delay(TimeSpan.FromSeconds(1), _programCancellationToken);
 
Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}");
Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}");
 
await Stop().ContinueWith(task => Start(), CancellationToken.None);
await Stop().ContinueWith(task => Start(), _programCancellationToken);
}
catch (Exception exception)
{
Log.Error(exception, "Error restarting WebSockets connection on connection closed.");
}
}
 
private async void WebSocketSharp_OnError(object sender, ErrorEventArgs e)
@@ -303,11 +350,18 @@
$"Connection to WebSockets server {_webSocketsUri.AbsoluteUri} terminated unexpectedly with message {e.Message}",
e.Exception);
 
await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken);
try
{
await Task.Delay(TimeSpan.FromSeconds(1), _programCancellationToken);
 
Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}");
Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}");
 
await Stop().ContinueWith(task => Start(), CancellationToken.None);
await Stop().ContinueWith(task => Start(), _programCancellationToken);
}
catch (Exception exception)
{
Log.Error(exception, "Error restarting WebSockets connection on connection closed.");
}
}
 
private async void WebSocketSharp_OnMessage(object sender, MessageEventArgs e)
@@ -316,7 +370,7 @@
{
Log.Information($"Server {_server.Name} sent PING message");
 
_webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnUnresponsiveServer, _cancellationToken);
_webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnServerNotResponding, _cancellationToken);
return;
}
 
@@ -323,41 +377,6 @@
await _webSocketMessageBufferBlock.SendAsync(new GotifyConnectionData(e.RawData, _server), _cancellationToken);
}
 
public async Task Stop()
{
 
if (_webSocketSharp == null || _cancellationTokenSource == null)
{
return;
}
 
_cancellationTokenSource.Cancel();
 
if (_heartBeatTask != null)
{
await _heartBeatTask;
}
 
if (_retrievePastMessagesTask != null)
{
await _retrievePastMessagesTask;
}
 
if (_webSocketSharp != null)
{
_webSocketSharp.OnMessage -= WebSocketSharp_OnMessage;
_webSocketSharp.OnError -= WebSocketSharp_OnError;
_webSocketSharp.OnOpen -= WebSocketSharp_OnOpen;
_webSocketSharp.OnClose -= WebSocketSharp_OnClose;
 
_webSocketSharp.Close();
_webSocketSharp = null;
}
 
_cancellationTokenSource.Dispose();
_cancellationTokenSource = null;
}
 
#endregion
 
#region Private Methods
@@ -461,7 +480,7 @@
 
Log.Information($"PING response latency for {_server.Name} is {delta}ms");
 
_webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnUnresponsiveServer, _cancellationToken);
_webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnServerNotResponding, _cancellationToken);
 
} while (!cancellationToken.IsCancellationRequested);
}
/trunk/Winify/Gotify/GotifyMessage.cs
@@ -1,6 +1,10 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Newtonsoft.Json;
using Servers;
using Winify.Properties;
 
namespace Winify.Gotify
{
@@ -8,29 +12,129 @@
/// {"id":22,"appid":1,"message":"iot","title":"Arcade
/// Netplay","priority":0,"date":"2022-10-26T14:55:59.050734643+03:00"}
/// </summary>
public class GotifyMessage
public class GotifyMessage : INotifyPropertyChanged
{
private int _id;
private int _appId;
private string _message;
private string _title;
private int _priority;
private DateTime _date;
private GotifyMessageExtras _extras = new GotifyMessageExtras();
private Server _server;
 
#region Public Enums, Properties and Fields
 
[JsonProperty(PropertyName = "id")] public int Id { get; set; }
[JsonProperty(PropertyName = "id")]
public int Id
{
get => _id;
set
{
if (value == _id) return;
_id = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "appid")] public int AppId { get; set; }
[JsonProperty(PropertyName = "appid")]
public int AppId
{
get => _appId;
set
{
if (value == _appId) return;
_appId = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "message")]
public string Message { get; set; }
public string Message
{
get => _message;
set
{
if (value == _message) return;
_message = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "title")] public string Title { get; set; }
[JsonProperty(PropertyName = "title")]
public string Title
{
get => _title;
set
{
if (value == _title) return;
_title = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "priority")]
public int Priority { get; set; }
public int Priority
{
get => _priority;
set
{
if (value == _priority) return;
_priority = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "date")] public DateTime Date { get; set; }
[JsonProperty(PropertyName = "date")]
public DateTime Date
{
get => _date;
set
{
if (value.Equals(_date)) return;
_date = value;
OnPropertyChanged();
}
}
 
[JsonProperty(PropertyName = "extras")]
public GotifyMessageExtras Extras { get; set; }
public GotifyMessageExtras Extras
{
get => _extras;
set
{
if (Equals(value, _extras)) return;
_extras = value;
OnPropertyChanged();
}
}
 
[JsonIgnore] public Server Server { get; set; }
[JsonIgnore]
public Server Server
{
get => _server;
set
{
if (Equals(value, _server)) return;
_server = value;
OnPropertyChanged();
OnPropertyChanged();
}
}
 
#endregion
 
[UsedImplicitly]
public GotifyMessage()
{
 
}
 
public event PropertyChangedEventHandler PropertyChanged;
 
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
/trunk/Winify/Gotify/GotifyMessageExtras.cs
@@ -1,10 +1,38 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Winify.Properties;
 
namespace Winify.Gotify
{
public class GotifyMessageExtras
public class GotifyMessageExtras : INotifyPropertyChanged
{
private GotifyMessageExtrasClientDisplay _gotifyMessageExtrasClientDisplay = new GotifyMessageExtrasClientDisplay();
 
[JsonProperty(PropertyName = "client::display")]
public GotifyMessageExtrasClientDisplay GotifyMessageExtrasClientDisplay { get; set; }
public GotifyMessageExtrasClientDisplay GotifyMessageExtrasClientDisplay
{
get => _gotifyMessageExtrasClientDisplay;
set
{
if (Equals(value, _gotifyMessageExtrasClientDisplay)) return;
_gotifyMessageExtrasClientDisplay = value;
OnPropertyChanged();
}
}
 
[UsedImplicitly]
public GotifyMessageExtras()
{
 
}
 
public event PropertyChangedEventHandler PropertyChanged;
 
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
/trunk/Winify/Gotify/GotifyMessageExtrasClientDisplay.cs
@@ -1,10 +1,23 @@
using Newtonsoft.Json;
using Winify.Properties;
 
namespace Winify.Gotify
{
public class GotifyMessageExtrasClientDisplay
{
private string _contentType = "text/plain";
 
[JsonProperty(PropertyName = "contentType")]
public string ContentType { get; set; }
public string ContentType
{
get => _contentType;
set => _contentType = value;
}
 
[UsedImplicitly]
public GotifyMessageExtrasClientDisplay()
{
 
}
}
}