Winify – Diff between revs 68 and 80
?pathlinks?
Rev 68 | Rev 80 | |||
---|---|---|---|---|
Line 85... | Line 85... | |||
85 | |
85 | |
|
Line 86... | Line 86... | |||
86 | var gotifyMessage = _jsonSerializer.Deserialize<GotifyMessage>(jsonTextReader) ?? throw new ArgumentNullException(); |
86 | var gotifyMessage = _jsonSerializer.Deserialize<GotifyMessage>(jsonTextReader) ?? throw new ArgumentNullException(); |
|
Line 87... | Line 87... | |||
87 | |
87 | |
|
Line 88... | Line 88... | |||
88 | gotifyMessage.Server = gotifyConnectionData.Server; |
88 | gotifyMessage.Server = gotifyConnectionData.Server; |
|
89 | |
89 | |
|
90 | using var imageStream = await RetrieveGotifyApplicationImage(gotifyMessage.AppId, _cancellationToken); |
90 | using var imageStream = await RetrieveGotifyApplicationImage(gotifyMessage.AppId); |
|
Line 226... | Line 226... | |||
226 | _webSocketSharp = new WebSocket(_webSocketsUri.AbsoluteUri); |
226 | _webSocketSharp = new WebSocket(_webSocketsUri.AbsoluteUri); |
|
227 | _webSocketSharp.EmitOnPing = true; |
227 | _webSocketSharp.EmitOnPing = true; |
|
228 | _webSocketSharp.WaitTime = TimeSpan.FromMinutes(1); |
228 | _webSocketSharp.WaitTime = TimeSpan.FromMinutes(1); |
|
229 | _webSocketSharp.SslConfiguration = new ClientSslConfiguration(_webSocketsUri.Host, |
229 | _webSocketSharp.SslConfiguration = new ClientSslConfiguration(_webSocketsUri.Host, |
|
230 | new X509CertificateCollection(new X509Certificate[] { }), SslProtocols.Tls12, false); |
230 | new X509CertificateCollection(new X509Certificate[] { }), SslProtocols.Tls12, false); |
|
- | 231 | |
||
231 | if (_configuration.Proxy.Enable) |
232 | if (_configuration.Proxy.Enable) |
|
- | 233 | { |
||
- | 234 | if (!string.IsNullOrEmpty(_configuration.Proxy.Url)) |
||
- | 235 | { |
||
232 | _webSocketSharp.SetProxy(_configuration.Proxy.Url, _configuration.Proxy.Username, |
236 | _webSocketSharp.SetProxy(_configuration.Proxy.Url, _configuration.Proxy.Username, _configuration.Proxy.Password); |
|
233 | _configuration.Proxy.Password); |
237 | } |
|
- | 238 | } |
||
Line 234... | Line 239... | |||
234 | |
239 | |
|
- | 240 | if (!string.IsNullOrEmpty(_server.Username) && !string.IsNullOrEmpty(_server.Password)) |
||
235 | if (!string.IsNullOrEmpty(_server.Username) && !string.IsNullOrEmpty(_server.Password)) |
241 | { |
|
- | 242 | _webSocketSharp.SetCredentials(_server.Username, _server.Password, true); |
||
Line 236... | Line 243... | |||
236 | _webSocketSharp.SetCredentials(_server.Username, _server.Password, true); |
243 | } |
|
- | 244 | |
||
237 | |
245 | if (_configuration.IgnoreSelfSignedCertificates) |
|
238 | if (_configuration.IgnoreSelfSignedCertificates) |
246 | { |
|
- | 247 | _webSocketSharp.SslConfiguration.ServerCertificateValidationCallback += |
||
Line 239... | Line 248... | |||
239 | _webSocketSharp.SslConfiguration.ServerCertificateValidationCallback += |
248 | (sender, certificate, chain, errors) => true; |
|
240 | (sender, certificate, chain, errors) => true; |
249 | } |
|
241 | |
250 | |
|
242 | _webSocketSharp.Log.Output = (logData, s) => |
251 | _webSocketSharp.Log.Output = (logData, s) => |
|
Line 256... | Line 265... | |||
256 | { |
265 | { |
|
257 | _retrievePastMessagesTask = RetrievePastMessages(_cancellationToken); |
266 | _retrievePastMessagesTask = RetrievePastMessages(_cancellationToken); |
|
258 | } |
267 | } |
|
259 | } |
268 | } |
|
Line 260... | Line 269... | |||
260 | |
269 | |
|
261 | private void WebSocketSharp_OnClose(object sender, CloseEventArgs e) |
270 | private async void WebSocketSharp_OnClose(object sender, CloseEventArgs e) |
|
262 | { |
271 | { |
|
263 | Log.Information( |
272 | Log.Information( |
|
- | 273 | $"WebSockets connection to server {_webSocketsUri.AbsoluteUri} closed with reason {e.Reason}"); |
||
- | 274 | |
||
- | 275 | await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken); |
||
- | 276 | |
||
- | 277 | Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}"); |
||
- | 278 | |
||
264 | $"WebSockets connection to server {_webSocketsUri.AbsoluteUri} closed with reason {e.Reason}"); |
279 | await Stop().ContinueWith(task => Start(), CancellationToken.None); |
|
Line 265... | Line 280... | |||
265 | } |
280 | } |
|
266 | |
281 | |
|
267 | private void WebSocketSharp_OnOpen(object sender, EventArgs e) |
282 | private void WebSocketSharp_OnOpen(object sender, EventArgs e) |
|
Line 268... | Line 283... | |||
268 | { |
283 | { |
|
269 | Log.Information($"WebSockets connection to server {_webSocketsUri.AbsoluteUri} is now open"); |
284 | Log.Information($"WebSockets connection to server {_webSocketsUri.AbsoluteUri} is now open"); |
|
Line 270... | Line 285... | |||
270 | |
285 | |
|
271 | _webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnUnresponsiveServer, _cancellationToken); |
286 | _webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnUnresponsiveServer, _cancellationToken); |
|
272 | } |
287 | } |
|
- | 288 | |
||
- | 289 | private async void OnUnresponsiveServer() |
||
- | 290 | { |
||
- | 291 | Log.Warning($"Server {_server.Name} has not responded in a long while..."); |
||
- | 292 | |
||
- | 293 | await Task.Delay(TimeSpan.FromSeconds(1), _cancellationToken); |
||
273 | |
294 | |
|
Line 274... | Line 295... | |||
274 | private void OnUnresponsiveServer() |
295 | Log.Information($"Reconnecting to websocket server {_webSocketsUri.AbsoluteUri}"); |
|
275 | { |
296 | |
|
276 | Log.Warning($"Server {_server.Name} has not responded in a long while..."); |
297 | await Stop().ContinueWith(task => Start(), CancellationToken.None); |
|
Line 362... | Line 383... | |||
362 | var gotifyMessageQuery = _jsonSerializer.Deserialize<GotifyMessageQuery>(jsonTextReader) ?? |
383 | var gotifyMessageQuery = _jsonSerializer.Deserialize<GotifyMessageQuery>(jsonTextReader) ?? |
|
363 | throw new ArgumentNullException(); |
384 | throw new ArgumentNullException(); |
|
Line 364... | Line 385... | |||
364 | |
385 | |
|
365 | if (gotifyMessageQuery.Messages == null) |
386 | if (gotifyMessageQuery.Messages == null) |
|
366 | { |
387 | { |
|
Line 367... | Line 388... | |||
367 | Log.Warning("Invalid application messages deserialized deserialized."); |
388 | Log.Warning("Invalid application messages deserialized."); |
|
368 | |
389 | |
|
Line 369... | Line 390... | |||
369 | return; |
390 | return; |
|
370 | } |
391 | } |
|
371 | |
- | ||
372 | foreach (var message in gotifyMessageQuery.Messages) |
392 | |
|
373 | { |
393 | foreach (var message in gotifyMessageQuery.Messages) |
|
374 | if (message.Date < |
394 | { |
|
375 | DateTime.Now - TimeSpan.FromHours(_configuration.RetrievePastNotificationHours)) |
395 | if (message.Date < DateTime.Now - TimeSpan.FromHours(_configuration.RetrievePastNotificationHours)) |
|
Line 376... | Line 396... | |||
376 | { |
396 | { |
|
377 | continue; |
397 | continue; |
|
378 | } |
398 | } |
|
379 | |
399 | |
|
Line 380... | Line 400... | |||
380 | using var imageStream = await RetrieveGotifyApplicationImage(message.AppId, _cancellationToken); |
400 | using var imageStream = await RetrieveGotifyApplicationImage(message.AppId); |
|
381 | if (imageStream == null || imageStream.Length == 0) |
401 | if (imageStream == null || imageStream.Length == 0) |
|
Line 382... | Line 402... | |||
382 | { |
402 | { |
|
383 | Log.Warning("Could not find any application image for notification."); |
403 | Log.Warning("Could not find any application image for notification."); |
|
Line 384... | Line -... | |||
384 | |
- | ||
385 | continue; |
404 | |
|
386 | } |
405 | continue; |
|
387 | |
406 | } |
|
388 | var image = new Bitmap(imageStream); |
407 | |
|
389 | message.Server = gotifyConnectionApplication.Server; |
408 | var image = new Bitmap(imageStream); |
|
390 | |
409 | message.Server = gotifyConnectionApplication.Server; |
|
Line 405... | Line 424... | |||
405 | { |
424 | { |
|
406 | Log.Warning(exception, "Generic failure."); |
425 | Log.Warning(exception, "Generic failure."); |
|
407 | } |
426 | } |
|
408 | }, new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken }); |
427 | }, new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken }); |
|
Line 409... | Line 428... | |||
409 | |
428 | |
|
410 | gotifyApplicationBufferBlock.LinkTo(gotifyApplicationActionBlock, |
429 | using var _1 = gotifyApplicationBufferBlock.LinkTo(gotifyApplicationActionBlock, |
|
Line 411... | Line 430... | |||
411 | new DataflowLinkOptions { PropagateCompletion = true }); |
430 | new DataflowLinkOptions { PropagateCompletion = true }); |
|
412 | |
431 | |
|
413 | var tasks = new ConcurrentBag<Task>(); |
432 | var tasks = new ConcurrentBag<Task>(); |
|
414 | await foreach (var application in RetrieveGotifyApplications(cancellationToken)) |
433 | foreach (var application in await RetrieveGotifyApplications()) |
|
- | 434 | { |
||
415 | { |
435 | var gotifyConnectionApplication = new GotifyConnectionApplication(_server, application); |
|
416 | var gotifyConnectionApplication = new GotifyConnectionApplication(_server, application); |
436 | |
|
Line 417... | Line 437... | |||
417 | tasks.Add(gotifyApplicationBufferBlock.SendAsync(gotifyConnectionApplication, cancellationToken)); |
437 | tasks.Add(gotifyApplicationBufferBlock.SendAsync(gotifyConnectionApplication, cancellationToken)); |
|
418 | } |
438 | } |
|
Line 440... | Line 460... | |||
440 | var delta = _webSocketsClientPingStopWatch.ElapsedMilliseconds; |
460 | var delta = _webSocketsClientPingStopWatch.ElapsedMilliseconds; |
|
Line 441... | Line 461... | |||
441 | |
461 | |
|
Line 442... | Line 462... | |||
442 | Log.Information($"PING response latency for {_server.Name} is {delta}ms"); |
462 | Log.Information($"PING response latency for {_server.Name} is {delta}ms"); |
|
- | 463 | |
||
443 | |
464 | _webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnUnresponsiveServer, _cancellationToken); |
|
444 | _webSocketsServerResponseScheduledContinuation.Schedule(TimeSpan.FromMinutes(1), OnUnresponsiveServer, _cancellationToken); |
465 | |
|
445 | } while (!cancellationToken.IsCancellationRequested); |
466 | } while (!cancellationToken.IsCancellationRequested); |
|
446 | } |
467 | } |
|
447 | catch (Exception exception) when (exception is OperationCanceledException || |
468 | catch (Exception exception) when (exception is OperationCanceledException || |
|
Line 452... | Line 473... | |||
452 | { |
473 | { |
|
453 | Log.Warning(exception, $"Heartbeat for server {_server.Name} has failed."); |
474 | Log.Warning(exception, $"Heartbeat for server {_server.Name} has failed."); |
|
454 | } |
475 | } |
|
455 | } |
476 | } |
|
Line 456... | Line 477... | |||
456 | |
477 | |
|
457 | private async IAsyncEnumerable<GotifyApplication> RetrieveGotifyApplications([EnumeratorCancellation] CancellationToken cancellationToken) |
478 | private async Task<GotifyApplication[]> RetrieveGotifyApplications() |
|
458 | { |
479 | { |
|
459 | if (!Uri.TryCreate(_httpUri, "application", out var combinedUri)) |
480 | if (!Uri.TryCreate(_httpUri, "application", out var combinedUri)) |
|
460 | { |
481 | { |
|
Line 461... | Line 482... | |||
461 | Log.Error($"No application URL could be built for {_server.Url}."); |
482 | Log.Error($"No application URL could be built for {_server.Url}."); |
|
462 | |
483 | |
|
463 | yield break; |
484 | return Array.Empty<GotifyApplication>(); |
|
464 | } |
- | ||
465 | |
485 | } |
|
466 | GotifyApplication[] gotifyApplications; |
486 | |
|
467 | try |
487 | try |
|
468 | { |
488 | { |
|
469 | using var messageStream = await _httpClient.GetStreamAsync(combinedUri); |
489 | using var messageStream = await _httpClient.GetStreamAsync(combinedUri); |
|
Line 470... | Line 490... | |||
470 | using var streamReader = new StreamReader(messageStream); |
490 | using var streamReader = new StreamReader(messageStream); |
|
471 | using var jsonTextReader = new JsonTextReader(streamReader); |
- | ||
472 | |
- | ||
473 | gotifyApplications = _jsonSerializer.Deserialize<GotifyApplication[]>(jsonTextReader); |
- | ||
474 | |
- | ||
475 | if (gotifyApplications == null) |
- | ||
476 | { |
491 | using var jsonTextReader = new JsonTextReader(streamReader); |
|
477 | throw new ArgumentNullException(); |
492 | |
|
478 | } |
493 | return _jsonSerializer.Deserialize<GotifyApplication[]>(jsonTextReader); |
|
479 | } |
494 | } |
|
Line 480... | Line -... | |||
480 | catch (Exception exception) |
- | ||
481 | { |
- | ||
482 | Log.Warning(exception,"Could not deserialize the list of applications from the server."); |
- | ||
483 | |
495 | catch (Exception exception) |
|
484 | yield break; |
- | ||
485 | } |
- | ||
486 | |
496 | { |
|
487 | foreach (var application in gotifyApplications) |
497 | Log.Warning(exception,"Could not deserialize the list of applications from the server."); |
|
Line 488... | Line 498... | |||
488 | { |
498 | |
|
489 | yield return application; |
499 | return Array.Empty<GotifyApplication>(); |
|
- | 500 | } |
||
- | 501 | } |
||
490 | } |
502 | |
|
491 | } |
503 | private async Task<Stream> RetrieveGotifyApplicationImage(int appId) |
|
492 | |
504 | { |
|
493 | private async Task<Stream> RetrieveGotifyApplicationImage(int appId, CancellationToken cancellationToken) |
505 | var memoryStream = new MemoryStream(); |
|
494 | { |
506 | |
|
495 | await foreach (var application in RetrieveGotifyApplications(cancellationToken)) |
507 | foreach (var application in await RetrieveGotifyApplications()) |
|
Line 506... | Line 518... | |||
506 | continue; |
518 | continue; |
|
507 | } |
519 | } |
|
Line 508... | Line 520... | |||
508 | |
520 | |
|
509 | try |
521 | try |
|
510 | { |
522 | { |
|
511 | var imageResponse = await _httpClient.GetStreamAsync(applicationImageUri); |
- | ||
512 | |
- | ||
Line 513... | Line 523... | |||
513 | var memoryStream = new MemoryStream(); |
523 | using var imageResponse = await _httpClient.GetStreamAsync(applicationImageUri); |
|
Line 514... | Line 524... | |||
514 | |
524 | |
|
515 | await imageResponse.CopyToAsync(memoryStream); |
525 | await imageResponse.CopyToAsync(memoryStream); |
|
Line 520... | Line 530... | |||
520 | { |
530 | { |
|
521 | Log.Error(exception,"Could not retrieve application image."); |
531 | Log.Error(exception,"Could not retrieve application image."); |
|
522 | } |
532 | } |
|
523 | } |
533 | } |
|
Line 524... | Line 534... | |||
524 | |
534 | |
|
525 | return new MemoryStream(); |
535 | return memoryStream; |
|
Line 526... | Line 536... | |||
526 | } |
536 | } |
|
Line 527... | Line 537... | |||
527 | |
537 | |