Winify – Diff between revs 39 and 44

Subversion Repositories:
Rev:
Show entire fileRegard whitespace
Rev 39 Rev 44
Line 1... Line 1...
1 using System; 1 using System;
2 using System.Drawing; 2 using System.Drawing;
3 using System.IO; 3 using System.IO;
4 using System.Net.Http; 4 using System.Net.Http;
5 using System.Net.Http.Headers; 5 using System.Net.Http.Headers;
6 using System.Net.WebSockets; -  
7 using System.Text; 6 using System.Text;
8 using System.Threading; 7 using System.Threading;
9 using System.Threading.Tasks; 8 using System.Threading.Tasks;
10 using Newtonsoft.Json; 9 using Newtonsoft.Json;
11 using Serilog; 10 using Serilog;
12 using Servers; 11 using Servers;
-   12 using WebSocketSharp;
-   13 using Configuration = Configuration.Configuration;
13 using ClientWebSocket = System.Net.WebSockets.Managed.ClientWebSocket; 14 using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;
Line 14... Line 15...
14   15  
15 namespace Winify.Gotify 16 namespace Winify.Gotify
16 { 17 {
17 public class GotifyConnection : IDisposable 18 public class GotifyConnection : IDisposable
Line 32... Line 33...
32   33  
Line 33... Line 34...
33 private Task _runTask; 34 private Task _runTask;
Line 34... Line -...
34   -  
35 private HttpClient _httpClient; -  
36   35  
Line 37... Line 36...
37 private readonly string _auth; 36 private HttpClient _httpClient;
-   37  
-   38 private readonly Uri _webSocketsUri;
Line 38... Line 39...
38   39  
Line 39... Line 40...
39 private readonly Uri _webSocketsUri; 40 private readonly Uri _httpUri;
Line 40... Line 41...
40   41 private WebSocket _webSocketSharp;
41 private readonly Uri _httpUri; 42 private readonly global::Configuration.Configuration _configuration;
42   -  
-   43  
43 #endregion 44 #endregion
Line 44... Line 45...
44   45  
45 #region Constructors, Destructors and Finalizers 46 #region Constructors, Destructors and Finalizers
46   47  
-   48 private GotifyConnection()
-   49 {
-   50  
-   51 }
-   52  
-   53 public GotifyConnection(Server server, global::Configuration.Configuration configuration) : this()
-   54 {
-   55 _server = server;
-   56 _configuration = configuration;
Line 47... Line 57...
47 public GotifyConnection() 57  
-   58 var httpClientHandler = new HttpClientHandler();
48 { 59 _httpClient = new HttpClient(httpClientHandler);
-   60 if (_configuration.IgnoreSelfSignedCertificates)
49 _httpClient = new HttpClient(); 61 {
-   62 httpClientHandler.ServerCertificateCustomValidationCallback =
-   63 HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
-   64 }
Line 50... Line 65...
50 } 65  
51   66 _httpClient = new HttpClient(httpClientHandler)
52 public GotifyConnection(Server server) : this() 67 {
53 { 68 DefaultRequestHeaders =
-   69 {
-   70 Authorization = new AuthenticationHeaderValue("Basic",
-   71 Convert.ToBase64String(Encoding.Default.GetBytes($"{_server.Username}:{_server.Password}")))
54 _server = server; 72 }
-   73 };
-   74  
-   75 if (Uri.TryCreate(_server.Url, UriKind.Absolute, out _httpUri))
-   76 {
-   77 // Build the web sockets URI.
-   78 var webSocketsUriBuilder = new UriBuilder(_httpUri);
55   79 switch (webSocketsUriBuilder.Scheme.ToUpperInvariant())
56 _auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{_server.Username}:{_server.Password}")); 80 {
57 _httpClient.DefaultRequestHeaders.Authorization = 81 case "HTTP":
58 new AuthenticationHeaderValue("Basic", _auth); 82 webSocketsUriBuilder.Scheme = "ws";
Line 73... Line 97...
73 { 97 {
74 _cancellationTokenSource.Dispose(); 98 _cancellationTokenSource.Dispose();
75 _cancellationTokenSource = null; 99 _cancellationTokenSource = null;
76 } 100 }
Line -... Line 101...
-   101  
-   102 _webSocketSharp.Close();
-   103 _webSocketSharp = null;
77   104  
78 _httpClient.Dispose(); 105 _httpClient.Dispose();
79 _httpClient = null; 106 _httpClient = null;
Line 80... Line 107...
80 } 107 }
Line 86... Line 113...
86 public void Start() 113 public void Start()
87 { 114 {
88 _cancellationTokenSource = new CancellationTokenSource(); 115 _cancellationTokenSource = new CancellationTokenSource();
89 _cancellationToken = _cancellationTokenSource.Token; 116 _cancellationToken = _cancellationTokenSource.Token;
Line -... Line 117...
-   117  
-   118 Connect();
90   119  
91 _runTask = Run(_cancellationToken); 120 _runTask = Run(_cancellationToken);
Line 92... Line 121...
92 } 121 }
93   122  
-   123 private void Connect()
-   124 {
94 public void Stop() 125 _webSocketSharp = new WebSocket(_webSocketsUri.AbsoluteUri);
95 { 126 _webSocketSharp.SetCredentials(_server.Username, _server.Password, true);
-   127 if (_configuration.IgnoreSelfSignedCertificates)
96 if (_cancellationTokenSource != null) 128 {
97 { 129 _webSocketSharp.SslConfiguration.ServerCertificateValidationCallback +=
98 _cancellationTokenSource.Cancel(); -  
99 } -  
100 } -  
Line -... Line 130...
-   130 (sender, certificate, chain, errors) => true;
-   131 }
-   132  
-   133 _webSocketSharp.OnMessage += WebSocketSharp_OnMessage;
101   134 _webSocketSharp.OnError += WebSocketSharp_OnError;
-   135 _webSocketSharp.OnOpen += WebSocketSharp_OnOpen;
Line 102... Line 136...
102 #endregion 136 _webSocketSharp.OnClose += WebSocketSharp_OnClose;
103   137 _webSocketSharp.ConnectAsync();
104 #region Private Methods 138 }
105   139  
-   140 private void WebSocketSharp_OnClose(object sender, CloseEventArgs e)
106 private async Task Run(CancellationToken cancellationToken) 141 {
107 { 142 Log.Information($"Connection to server closed with reason: {e.Reason}");
-   143 }
108 try 144  
-   145 private void WebSocketSharp_OnOpen(object sender, EventArgs e)
-   146 {
109 { 147 Log.Information("Connection to server is now open.");
110 do 148 }
111 { 149  
-   150 private async void WebSocketSharp_OnError(object sender, ErrorEventArgs e)
112 try 151 {
-   152 if (_cancellationToken.IsCancellationRequested)
Line 113... Line 153...
113 { 153 {
-   154 Stop();
Line -... Line 155...
-   155 return;
-   156 }
-   157  
-   158 await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken);
-   159 Log.Information("Reconnecting to websocket server.");
114 using (var webSocketClient = new ClientWebSocket()) 160  
115 { 161 Connect();
116 webSocketClient.Options.SetRequestHeader("Authorization", $"Basic {_auth}"); 162 }
-   163  
-   164 private async void WebSocketSharp_OnMessage(object sender, MessageEventArgs e)
-   165 {
-   166 if (e.RawData.Length == 0)
Line 117... Line 167...
117   167 {
Line 118... Line 168...
118 await webSocketClient.ConnectAsync(_webSocketsUri, cancellationToken); 168 Log.Warning($"Empty message received from server.");
119   169 return;
120 do 170 }
121 { 171  
122 var payload = new ArraySegment<byte>(new byte[1024]); -  
123   172 var message = Encoding.UTF8.GetString(e.RawData, 0, e.RawData.Length);
124 var result = await webSocketClient.ReceiveAsync(payload, cancellationToken); 173  
-   174 GotifyNotification gotifyNotification;
125   175  
126 if (result.Count == 0) 176 try
Line 127... Line -...
127 { -  
128 continue; -  
129 } -  
130   -  
131 if (payload.Array == null || payload.Count == 0) 177 {
132 { 178 gotifyNotification = JsonConvert.DeserializeObject<GotifyNotification>(message);
133 continue; 179 }
Line 134... Line 180...
134 } 180 catch (JsonSerializationException exception)
135   181 {
Line 136... Line 182...
136 var message = Encoding.UTF8.GetString(payload.Array, 0, payload.Count); 182 Log.Warning($"Could not deserialize notification: {exception.Message}");
Line 137... Line 183...
137   183 return;
138 var gotifyNotification = JsonConvert.DeserializeObject<GotifyNotification>(message); 184 }
139   185  
-   186 if (gotifyNotification == null)
-   187 {
-   188 Log.Warning($"Could not deserialize gotify notification: {message}");
-   189  
-   190 return;
-   191 }
-   192  
140 if (gotifyNotification == null) 193 gotifyNotification.Server = _server;
-   194  
-   195 if (!Uri.TryCreate(Path.Combine($"{_httpUri}", "application"), UriKind.Absolute,
-   196 out var applicationUri))
141 { 197 {
Line 142... Line -...
142 Log.Warning($"Could not deserialize gotify notification: {message}"); -  
143   198 Log.Warning($"Could not build an URI to an application.");
Line 144... Line 199...
144 continue; 199 return;
145 } 200 }
-   201  
Line 146... Line 202...
146   202 using (var imageStream =
147 gotifyNotification.Server = _server; -  
148   -  
149 if (!Uri.TryCreate(Path.Combine($"{_httpUri}", "application"), UriKind.Absolute, 203 await RetrieveGotifyApplicationImage(gotifyNotification.AppId, applicationUri, _cancellationToken))
-   204 {
150 out var applicationUri)) 205 if (imageStream == null)
151 { 206 {
-   207 Log.Warning("Could not find any application image for notification.");
-   208 return;
-   209 }
152 continue; 210  
-   211 var image = Image.FromStream(imageStream);
153 } 212  
Line -... Line 213...
-   213 GotifyNotification?.Invoke(this,
-   214 new GotifyNotificationEventArgs(gotifyNotification, image));
-   215 }
-   216  
-   217 Log.Debug($"Notification message received: {gotifyNotification.Message}");
-   218 }
154   219  
155 var image = await RetrieveGotifyApplicationImage(gotifyNotification.AppId, -  
156 applicationUri, cancellationToken); 220 public void Stop()
157   221 {
158 GotifyNotification?.Invoke(this, 222 if (_cancellationTokenSource != null) _cancellationTokenSource.Cancel();
159 new GotifyNotificationEventArgs(gotifyNotification, image)); 223 }
160   224  
161 Log.Debug($"Notification message received: {gotifyNotification.Message}"); 225 #endregion
162 } while (!cancellationToken.IsCancellationRequested); 226  
163 } 227 #region Private Methods
164 } 228  
165 catch (Exception ex) when (ex is WebSocketException || ex is HttpRequestException) 229 private async Task Run(CancellationToken cancellationToken)
Line 166... Line 230...
166 { 230 {
167 // Reconnect 231 try
168 Log.Warning($"Unable to connect to gotify server: {ex.Message}"); 232 {
169   233 do
Line 170... Line 234...
170 await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); 234 {
Line -... Line 235...
-   235 await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
-   236 } while (!cancellationToken.IsCancellationRequested);
-   237 }
171 } 238 catch (Exception exception) when (exception is OperationCanceledException || exception is ObjectDisposedException)
172 } while (!cancellationToken.IsCancellationRequested); 239 {
173 } 240 }
174 catch (Exception ex) when (ex is OperationCanceledException || ex is ObjectDisposedException) 241 catch (Exception exception)
175 { 242 {
-   243 Log.Warning(exception, "Failure running connection loop.");
-   244 }
176 } 245 }
177 catch (Exception ex) 246  
Line 178... Line 247...
178 { 247 private async Task<Stream> RetrieveGotifyApplicationImage(int appId, Uri applicationUri,
179 Log.Warning(ex, "Failure running connection loop."); 248 CancellationToken cancellationToken)
180 } 249 {
181 } -  
182   -  
183 private async Task<Image> RetrieveGotifyApplicationImage(int appId, Uri applicationUri, -  
Line 184... Line 250...
184 CancellationToken cancellationToken) 250 var applicationResponse = await _httpClient.GetAsync(applicationUri, cancellationToken);
185 { 251  
186 var applicationResponse = await _httpClient.GetAsync(applicationUri, cancellationToken); 252 var applications = await applicationResponse.Content.ReadAsStringAsync();
-   253  
187   254 GotifyApplication[] gotifyApplications;
188 var applications = await applicationResponse.Content.ReadAsStringAsync(); 255 try
Line 189... Line 256...
189   256 {
Line 190... Line 257...
190 var gotifyApplications = 257 gotifyApplications =
191 JsonConvert.DeserializeObject<GotifyApplication[]>(applications); -  
-   258 JsonConvert.DeserializeObject<GotifyApplication[]>(applications);
192   259 }
Line 193... Line 260...
193 if (gotifyApplications == null) 260 catch (JsonSerializationException exception)
194 { -  
195 return null; 261 {
Line 196... Line 262...
196 } 262 Log.Warning($"Could not deserialize the list of applications from the server: {exception.Message}");
197   263