Winify – Diff between revs 54 and 59

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 54 Rev 59
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; 4 using System.Net;
5 using System.Net.Http; 5 using System.Net.Http;
6 using System.Net.Http.Headers; 6 using System.Net.Http.Headers;
7 using System.Net.Security; -  
8 using System.Security.Authentication; 7 using System.Security.Authentication;
9 using System.Security.Cryptography.X509Certificates; 8 using System.Security.Cryptography.X509Certificates;
10 using System.Text; 9 using System.Text;
11 using System.Threading; 10 using System.Threading;
12 using System.Threading.Tasks; 11 using System.Threading.Tasks;
13 using Newtonsoft.Json; 12 using Newtonsoft.Json;
14 using Serilog; 13 using Serilog;
15 using Servers; 14 using Servers;
16 using WebSocketSharp; 15 using WebSocketSharp;
17 using WebSocketSharp.Net; 16 using WebSocketSharp.Net;
18 using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; -  
19 using Configuration = Configuration.Configuration; -  
20 using ErrorEventArgs = WebSocketSharp.ErrorEventArgs; 17 using ErrorEventArgs = WebSocketSharp.ErrorEventArgs;
21 using NetworkCredential = System.Net.NetworkCredential; 18 using NetworkCredential = System.Net.NetworkCredential;
22   19  
23 namespace Winify.Gotify 20 namespace Winify.Gotify
24 { 21 {
25 public class GotifyConnection : IDisposable 22 public class GotifyConnection : IDisposable
26 { 23 {
27 #region Public Events & Delegates 24 #region Public Events & Delegates
28   25  
29 public event EventHandler<GotifyNotificationEventArgs> GotifyNotification; 26 public event EventHandler<GotifyNotificationEventArgs> GotifyNotification;
30   27  
31 #endregion 28 #endregion
32   29  
33 #region Private Delegates, Events, Enums, Properties, Indexers and Fields 30 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
34   31  
35 private readonly Server _server; 32 private readonly Server _server;
36   33  
37 private CancellationToken _cancellationToken; 34 private CancellationToken _cancellationToken;
38   35  
39 private CancellationTokenSource _cancellationTokenSource; 36 private CancellationTokenSource _cancellationTokenSource;
40   37  
41 private Task _runTask; 38 private Task _runTask;
42   39  
43 private HttpClient _httpClient; 40 private HttpClient _httpClient;
44   41  
45 private readonly Uri _webSocketsUri; 42 private readonly Uri _webSocketsUri;
46   43  
47 private readonly Uri _httpUri; 44 private readonly Uri _httpUri;
48 private WebSocket _webSocketSharp; 45 private WebSocket _webSocketSharp;
49 private readonly global::Configuration.Configuration _configuration; 46 private readonly Configuration.Configuration _configuration;
-   47 private Task _initTask;
50   48  
51 #endregion 49 #endregion
52   50  
53 #region Constructors, Destructors and Finalizers 51 #region Constructors, Destructors and Finalizers
54   52  
55 private GotifyConnection() 53 private GotifyConnection()
56 { 54 {
57   -  
58 } 55 }
59   56  
60 public GotifyConnection(Server server, global::Configuration.Configuration configuration) : this() 57 public GotifyConnection(Server server, Configuration.Configuration configuration) : this()
61 { 58 {
62 _server = server; 59 _server = server;
63 _configuration = configuration; 60 _configuration = configuration;
64   61  
65 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; 62 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
66 var httpClientHandler = new HttpClientHandler() 63 var httpClientHandler = new HttpClientHandler
67 { 64 {
68 // mono does not implement this 65 // mono does not implement this
69 //SslProtocols = SslProtocols.Tls12 66 //SslProtocols = SslProtocols.Tls12
70 }; 67 };
71   68  
72 _httpClient = new HttpClient(httpClientHandler); 69 _httpClient = new HttpClient(httpClientHandler);
73 if (_configuration.IgnoreSelfSignedCertificates) 70 if (_configuration.IgnoreSelfSignedCertificates)
74 { -  
75 httpClientHandler.ServerCertificateCustomValidationCallback = 71 httpClientHandler.ServerCertificateCustomValidationCallback =
76 (httpRequestMessage, cert, cetChain, policyErrors) => true; 72 (httpRequestMessage, cert, cetChain, policyErrors) => true;
77 } -  
78   73  
79 if (_configuration.Proxy.Enable) -  
80 { 74 if (_configuration.Proxy.Enable)
81 httpClientHandler.Proxy = new WebProxy(_configuration.Proxy.Url, false, new string[] { }, 75 httpClientHandler.Proxy = new WebProxy(_configuration.Proxy.Url, false, new string[] { },
82 new NetworkCredential(_configuration.Proxy.Username, _configuration.Proxy.Password)); -  
83 } 76 new NetworkCredential(_configuration.Proxy.Username, _configuration.Proxy.Password));
84   77  
85 _httpClient = new HttpClient(httpClientHandler); 78 _httpClient = new HttpClient(httpClientHandler);
86 if (!string.IsNullOrEmpty(_server.Username) && !string.IsNullOrEmpty(_server.Password)) 79 if (!string.IsNullOrEmpty(_server.Username) && !string.IsNullOrEmpty(_server.Password))
87 { -  
88 _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", 80 _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
89 Convert.ToBase64String(Encoding.Default.GetBytes($"{_server.Username}:{_server.Password}"))); 81 Convert.ToBase64String(Encoding.Default.GetBytes($"{_server.Username}:{_server.Password}")));
90 } -  
91   82  
92 if (!Uri.TryCreate(_server.Url, UriKind.Absolute, out _httpUri)) 83 if (!Uri.TryCreate(_server.Url, UriKind.Absolute, out _httpUri))
93 { 84 {
94 Log.Error($"No HTTP URL could be built out of the supplied server URI {_server.Url}"); 85 Log.Error($"No HTTP URL could be built out of the supplied server URI {_server.Url}");
95 return; 86 return;
96 } 87 }
97   88  
98 // Build the web sockets URI. 89 // Build the web sockets URI.
99 var webSocketsUriBuilder = new UriBuilder(_httpUri); 90 var webSocketsUriBuilder = new UriBuilder(_httpUri);
100 switch (webSocketsUriBuilder.Scheme.ToUpperInvariant()) 91 switch (webSocketsUriBuilder.Scheme.ToUpperInvariant())
101 { 92 {
102 case "HTTP": 93 case "HTTP":
103 webSocketsUriBuilder.Scheme = "ws"; 94 webSocketsUriBuilder.Scheme = "ws";
104 break; 95 break;
105 case "HTTPS": 96 case "HTTPS":
106 webSocketsUriBuilder.Scheme = "wss"; 97 webSocketsUriBuilder.Scheme = "wss";
107 break; 98 break;
108 } 99 }
109   100  
110 try 101 try
111 { 102 {
112 webSocketsUriBuilder.Path = Path.Combine(webSocketsUriBuilder.Path, "stream"); 103 webSocketsUriBuilder.Path = Path.Combine(webSocketsUriBuilder.Path, "stream");
113 } 104 }
114 catch (ArgumentException exception) 105 catch (ArgumentException exception)
115 { 106 {
-   107 Log.Error(
116 Log.Error($"No WebSockets URL could be built from the provided URL {_server.Url} due to {exception.Message}"); 108 $"No WebSockets URL could be built from the provided URL {_server.Url} due to {exception.Message}");
117 } 109 }
118   110  
119 _webSocketsUri = webSocketsUriBuilder.Uri; 111 _webSocketsUri = webSocketsUriBuilder.Uri;
120 } 112 }
121   113  
122 public void Dispose() 114 public void Dispose()
123 { 115 {
124 if (_cancellationTokenSource != null) 116 if (_cancellationTokenSource != null)
125 { 117 {
126 _cancellationTokenSource.Dispose(); 118 _cancellationTokenSource.Dispose();
127 _cancellationTokenSource = null; 119 _cancellationTokenSource = null;
128 } 120 }
129   121  
130 if (_webSocketSharp != null) 122 if (_webSocketSharp != null)
131 { 123 {
132 _webSocketSharp.Close(); 124 _webSocketSharp.Close();
133 _webSocketSharp = null; 125 _webSocketSharp = null;
134 } 126 }
135   127  
136 if (_httpClient != null) 128 if (_httpClient != null)
137 { 129 {
138 _httpClient.Dispose(); 130 _httpClient.Dispose();
139 _httpClient = null; 131 _httpClient = null;
140 } 132 }
141 } 133 }
142   134  
143 #endregion 135 #endregion
144   136  
145 #region Public Methods 137 #region Public Methods
146   138  
147 public void Start() 139 public void Start()
148 { 140 {
149 if (_webSocketsUri == null || _httpUri == null) 141 if (_webSocketsUri == null || _httpUri == null)
150 { 142 {
151 Log.Error("Could not start connection to server due to unreadable URLs"); 143 Log.Error("Could not start connection to server due to unreadable URLs");
152 return; 144 return;
153 } 145 }
154   146  
155 _cancellationTokenSource = new CancellationTokenSource(); 147 _cancellationTokenSource = new CancellationTokenSource();
156 _cancellationToken = _cancellationTokenSource.Token; 148 _cancellationToken = _cancellationTokenSource.Token;
157   149  
158 Connect(); 150 Connect();
-   151  
-   152 if (_configuration.RetrievePastNotificationHours != 0)
-   153 {
-   154 _initTask = RetrievePastMessages(_cancellationToken);
-   155 }
159   156  
160 _runTask = Run(_cancellationToken); 157 _runTask = Run(_cancellationToken);
161 } 158 }
162   159  
163 private void Connect() 160 private void Connect()
164 { 161 {
165 _webSocketSharp = new WebSocket(_webSocketsUri.AbsoluteUri); 162 _webSocketSharp = new WebSocket(_webSocketsUri.AbsoluteUri);
166 _webSocketSharp.SslConfiguration = new ClientSslConfiguration(_webSocketsUri.Host, 163 _webSocketSharp.SslConfiguration = new ClientSslConfiguration(_webSocketsUri.Host,
167 new X509CertificateCollection(new X509Certificate[] { }), SslProtocols.Tls12, false); 164 new X509CertificateCollection(new X509Certificate[] { }), SslProtocols.Tls12, false);
168 if (_configuration.Proxy.Enable) 165 if (_configuration.Proxy.Enable)
169 { -  
170 _webSocketSharp.SetProxy(_configuration.Proxy.Url, _configuration.Proxy.Username, _configuration.Proxy.Password); 166 _webSocketSharp.SetProxy(_configuration.Proxy.Url, _configuration.Proxy.Username,
171 } 167 _configuration.Proxy.Password);
172   168  
173 if (!string.IsNullOrEmpty(_server.Username) && !string.IsNullOrEmpty(_server.Password)) -  
174 { 169 if (!string.IsNullOrEmpty(_server.Username) && !string.IsNullOrEmpty(_server.Password))
175 _webSocketSharp.SetCredentials(_server.Username, _server.Password, true); -  
176 } 170 _webSocketSharp.SetCredentials(_server.Username, _server.Password, true);
177   -  
178 if (_configuration.IgnoreSelfSignedCertificates) 171  
179 { 172 if (_configuration.IgnoreSelfSignedCertificates)
180 _webSocketSharp.SslConfiguration.ServerCertificateValidationCallback += -  
181 (sender, certificate, chain, errors) => true; 173 _webSocketSharp.SslConfiguration.ServerCertificateValidationCallback +=
182 } 174 (sender, certificate, chain, errors) => true;
183   175  
184 _webSocketSharp.Log.Output = (logData, s) => 176 _webSocketSharp.Log.Output = (logData, s) =>
185 { 177 {
186 Log.Information($"WebSockets low level logging reported: {logData.Message}"); 178 Log.Information($"WebSockets low level logging reported: {logData.Message}");
187 }; 179 };
188   180  
189 _webSocketSharp.OnMessage += WebSocketSharp_OnMessage; 181 _webSocketSharp.OnMessage += WebSocketSharp_OnMessage;
190 _webSocketSharp.OnError += WebSocketSharp_OnError; 182 _webSocketSharp.OnError += WebSocketSharp_OnError;
191 _webSocketSharp.OnOpen += WebSocketSharp_OnOpen; 183 _webSocketSharp.OnOpen += WebSocketSharp_OnOpen;
192 _webSocketSharp.OnClose += WebSocketSharp_OnClose; 184 _webSocketSharp.OnClose += WebSocketSharp_OnClose;
193 185  
194 _webSocketSharp.ConnectAsync(); 186 _webSocketSharp.ConnectAsync();
195 } 187 }
196   188  
197 private void WebSocketSharp_OnClose(object sender, CloseEventArgs e) 189 private void WebSocketSharp_OnClose(object sender, CloseEventArgs e)
198 { 190 {
-   191 Log.Information(
199 Log.Information($"WebSockets connection to server {_webSocketsUri.AbsoluteUri} closed with reason {e.Reason}"); 192 $"WebSockets connection to server {_webSocketsUri.AbsoluteUri} closed with reason {e.Reason}");
200 } 193 }
201   194  
202 private void WebSocketSharp_OnOpen(object sender, EventArgs e) 195 private void WebSocketSharp_OnOpen(object sender, EventArgs e)
203 { 196 {
204 Log.Information($"WebSockets connection to server {_webSocketsUri.AbsoluteUri} is now open"); 197 Log.Information($"WebSockets connection to server {_webSocketsUri.AbsoluteUri} is now open");
205 } 198 }
206   199  
207 private async void WebSocketSharp_OnError(object sender, ErrorEventArgs e) 200 private async void WebSocketSharp_OnError(object sender, ErrorEventArgs e)
208 { 201 {
-   202 Log.Error(
209 Log.Error($"Connection to WebSockets server {_webSocketsUri.AbsoluteUri} terminated unexpectedly with message {e.Message}", e.Exception); 203 $"Connection to WebSockets server {_webSocketsUri.AbsoluteUri} terminated unexpectedly with message {e.Message}",
-   204 e.Exception);
210   205  
211 if (_cancellationToken.IsCancellationRequested) 206 if (_cancellationToken.IsCancellationRequested)
212 { 207 {
213 Stop(); 208 Stop();
214 return; 209 return;
215 } 210 }
216   211  
217 await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken); 212 await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken);
218 Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}"); 213 Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}");
219   214  
220 Connect(); 215 Connect();
221 } 216 }
222   217  
223 private async void WebSocketSharp_OnMessage(object sender, MessageEventArgs e) 218 private async void WebSocketSharp_OnMessage(object sender, MessageEventArgs e)
224 { 219 {
225 if (e.RawData.Length == 0) 220 if (e.RawData.Length == 0)
226 { 221 {
227 Log.Warning($"Empty message received from server"); 222 Log.Warning("Empty message received from server");
228 return; 223 return;
229 } 224 }
230   225  
231 var message = Encoding.UTF8.GetString(e.RawData, 0, e.RawData.Length); 226 var message = Encoding.UTF8.GetString(e.RawData, 0, e.RawData.Length);
232   227  
233 GotifyNotification gotifyNotification; 228 GotifyMessage gotifyNotification;
234   229  
235 try 230 try
236 { 231 {
237 gotifyNotification = JsonConvert.DeserializeObject<GotifyNotification>(message); 232 gotifyNotification = JsonConvert.DeserializeObject<GotifyMessage>(message);
238 } 233 }
239 catch (JsonSerializationException exception) 234 catch (JsonSerializationException exception)
240 { 235 {
241 Log.Warning($"Could not deserialize notification: {exception.Message}"); 236 Log.Warning($"Could not deserialize notification: {exception.Message}");
242 return; 237 return;
243 } 238 }
244   239  
245 if (gotifyNotification == null) 240 if (gotifyNotification == null)
246 { 241 {
247 Log.Warning($"Could not deserialize gotify notification: {message}"); 242 Log.Warning($"Could not deserialize gotify notification: {message}");
248   243  
249 return; 244 return;
250 } 245 }
251   246  
252 gotifyNotification.Server = _server; 247 gotifyNotification.Server = _server;
253   248  
254 if (!Uri.TryCreate(Path.Combine($"{_httpUri}", "application"), UriKind.Absolute, 249 var applicationUriBuilder = new UriBuilder(_httpUri);
255 out var applicationUri)) 250 try
-   251 {
-   252 applicationUriBuilder.Path = Path.Combine(applicationUriBuilder.Path, "application");
-   253 }
-   254 catch (ArgumentException exception)
256 { 255 {
-   256 Log.Warning("Could not build an URI to an application");
257 Log.Warning($"Could not build an URI to an application"); 257  
258 return; 258 return;
259 } 259 }
260   260  
261 using (var imageStream = 261 using (var imageStream =
262 await RetrieveGotifyApplicationImage(gotifyNotification.AppId, applicationUri, _cancellationToken)) 262 await RetrieveGotifyApplicationImage(gotifyNotification.AppId, applicationUriBuilder.Uri,
-   263 _cancellationToken))
263 { 264 {
264 if (imageStream == null) 265 if (imageStream == null)
265 { 266 {
266 Log.Warning("Could not find any application image for notification"); 267 Log.Warning("Could not find any application image for notification");
267 return; 268 return;
268 } 269 }
269   270  
270 var image = Image.FromStream(imageStream); 271 var image = Image.FromStream(imageStream);
271   272  
272 GotifyNotification?.Invoke(this, 273 GotifyNotification?.Invoke(this,
273 new GotifyNotificationEventArgs(gotifyNotification, image)); 274 new GotifyNotificationEventArgs(gotifyNotification, image));
274 } 275 }
275   276  
276 Log.Debug($"Notification message received: {gotifyNotification.Message}"); 277 Log.Debug($"Notification message received: {gotifyNotification.Message}");
277 } 278 }
278   279  
279 public void Stop() 280 public void Stop()
280 { 281 {
281 if (_cancellationTokenSource != null) _cancellationTokenSource.Cancel(); 282 if (_cancellationTokenSource == null) return;
-   283  
-   284 _cancellationTokenSource.Cancel();
282 } 285 }
283   286  
284 #endregion 287 #endregion
285   288  
286 #region Private Methods 289 #region Private Methods
-   290  
-   291 private async Task RetrievePastMessages(CancellationToken cancellationToken)
-   292 {
-   293 var messageUriBuilder = new UriBuilder(_httpUri);
-   294 foreach (var application in await RetrieveGotifyApplications(cancellationToken))
-   295 {
-   296 try
-   297 {
-   298 messageUriBuilder.Path = Path.Combine(messageUriBuilder.Path, "application", $"{application.Id}",
-   299 "message");
-   300 }
-   301 catch (ArgumentException exception)
-   302 {
-   303 Log.Error($"No application URL could be built for {_server.Url} due to {exception.Message}");
-   304  
-   305 continue;
-   306 }
-   307  
-   308 var messagesResponse = await _httpClient.GetAsync(messageUriBuilder.Uri, cancellationToken);
-   309  
-   310  
-   311 var messages = await messagesResponse.Content.ReadAsStringAsync();
-   312  
-   313 GotifyMessageQuery gotifyMessageQuery;
-   314 try
-   315 {
-   316 gotifyMessageQuery =
-   317 JsonConvert.DeserializeObject<GotifyMessageQuery>(messages);
-   318 }
-   319 catch (JsonSerializationException exception)
-   320 {
-   321 Log.Warning($"Could not deserialize the message response: {exception.Message}");
-   322  
-   323 continue;
-   324 }
-   325  
-   326 var applicationUriBuilder = new UriBuilder(_httpUri);
-   327 try
-   328 {
-   329 applicationUriBuilder.Path = Path.Combine(applicationUriBuilder.Path, "application");
-   330 }
-   331 catch (ArgumentException exception)
-   332 {
-   333 Log.Warning($"Could not build an URI to an application: {exception}");
-   334  
-   335 return;
-   336 }
-   337  
-   338 foreach (var message in gotifyMessageQuery.Messages)
-   339 {
-   340 if (message.Date < DateTime.Now - TimeSpan.FromHours(_configuration.RetrievePastNotificationHours))
-   341 continue;
-   342  
-   343 message.Server = _server;
-   344  
-   345 using (var imageStream =
-   346 await RetrieveGotifyApplicationImage(message.AppId, applicationUriBuilder.Uri,
-   347 _cancellationToken))
-   348 {
-   349 if (imageStream == null)
-   350 {
-   351 Log.Warning("Could not find any application image for notification");
-   352 return;
-   353 }
-   354  
-   355 var image = Image.FromStream(imageStream);
-   356  
-   357 GotifyNotification?.Invoke(this,
-   358 new GotifyNotificationEventArgs(message, image));
-   359 }
-   360 }
-   361 }
-   362 }
287   363  
288 private async Task Run(CancellationToken cancellationToken) 364 private async Task Run(CancellationToken cancellationToken)
289 { 365 {
290 try 366 try
291 { 367 {
292 do 368 do
293 { 369 {
294 await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); 370 await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
295 } while (!cancellationToken.IsCancellationRequested); 371 } while (!cancellationToken.IsCancellationRequested);
296 } 372 }
297 catch (Exception exception) when (exception is OperationCanceledException || exception is ObjectDisposedException) 373 catch (Exception exception) when (exception is OperationCanceledException ||
-   374 exception is ObjectDisposedException)
298 { 375 {
299 } 376 }
300 catch (Exception exception) 377 catch (Exception exception)
301 { 378 {
302 Log.Warning(exception, "Failure running connection loop"); 379 Log.Warning(exception, "Failure running connection loop");
303 } 380 }
304 } 381 }
-   382  
-   383 private async Task<GotifyApplication[]> RetrieveGotifyApplications(CancellationToken cancellationToken)
-   384 {
-   385 var applicationsUriBuilder = new UriBuilder(_httpUri);
-   386 try
-   387 {
-   388 applicationsUriBuilder.Path = Path.Combine(applicationsUriBuilder.Path, "application");
-   389 }
-   390 catch (ArgumentException exception)
-   391 {
-   392 Log.Error($"No application URL could be built for {_server.Url} due to {exception}");
-   393 }
-   394  
-   395 var applicationsResponse = await _httpClient.GetAsync(applicationsUriBuilder.Uri, cancellationToken);
-   396  
-   397 var applications = await applicationsResponse.Content.ReadAsStringAsync();
-   398  
-   399 GotifyApplication[] gotifyApplications;
-   400 try
-   401 {
-   402 gotifyApplications =
-   403 JsonConvert.DeserializeObject<GotifyApplication[]>(applications);
-   404 }
-   405 catch (JsonSerializationException exception)
-   406 {
-   407 Log.Warning($"Could not deserialize the list of applications from the server: {exception}");
-   408  
-   409 return null;
-   410 }
-   411  
-   412 return gotifyApplications;
-   413 }
305   414  
306 private async Task<Stream> RetrieveGotifyApplicationImage(int appId, Uri applicationUri, 415 private async Task<Stream> RetrieveGotifyApplicationImage(int appId, Uri applicationUri,
307 CancellationToken cancellationToken) 416 CancellationToken cancellationToken)
308 { 417 {
309 var applicationResponse = await _httpClient.GetAsync(applicationUri, cancellationToken); 418 var applicationResponse = await _httpClient.GetAsync(applicationUri, cancellationToken);
310   419  
311 var applications = await applicationResponse.Content.ReadAsStringAsync(); 420 var applications = await applicationResponse.Content.ReadAsStringAsync();
312   421  
313 GotifyApplication[] gotifyApplications; 422 GotifyApplication[] gotifyApplications;
314 try 423 try
315 { 424 {
316 gotifyApplications = 425 gotifyApplications =
317 JsonConvert.DeserializeObject<GotifyApplication[]>(applications); 426 JsonConvert.DeserializeObject<GotifyApplication[]>(applications);
318 } 427 }
319 catch (JsonSerializationException exception) 428 catch (JsonSerializationException exception)
320 { 429 {
321 Log.Warning($"Could not deserialize the list of applications from the server: {exception.Message}"); 430 Log.Warning($"Could not deserialize the list of applications from the server: {exception.Message}");
322   431  
323 return null; 432 return null;
324 } 433 }
325   434  
326 foreach (var application in gotifyApplications) 435 foreach (var application in gotifyApplications)
327 { 436 {
328 if (application.Id != appId) continue; 437 if (application.Id != appId) continue;
329   438  
330 if (!Uri.TryCreate(Path.Combine($"{_httpUri}", $"{application.Image}"), UriKind.Absolute, 439 if (!Uri.TryCreate(Path.Combine($"{_httpUri}", $"{application.Image}"), UriKind.Absolute,
331 out var applicationImageUri)) 440 out var applicationImageUri))
332 { 441 {
333 Log.Warning("Could not build URL path to application icon"); 442 Log.Warning("Could not build URL path to application icon");
334 continue; 443 continue;
335 } 444 }
336   445  
337 var imageResponse = await _httpClient.GetAsync(applicationImageUri, cancellationToken); 446 var imageResponse = await _httpClient.GetAsync(applicationImageUri, cancellationToken);
338   447  
339 var memoryStream = new MemoryStream(); 448 var memoryStream = new MemoryStream();
340   449  
341 await imageResponse.Content.CopyToAsync(memoryStream); 450 await imageResponse.Content.CopyToAsync(memoryStream);
342   451  
343 return memoryStream; 452 return memoryStream;
344 } 453 }
345   454  
346 return null; 455 return null;
347 } 456 }
348   457  
349 #endregion 458 #endregion
350 } 459 }
351 } 460 }
352   461  
353
Generated by GNU Enscript 1.6.5.90.
462
Generated by GNU Enscript 1.6.5.90.
354   463  
355   464  
356   465