Winify – Blame information for rev 35

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Drawing;
3 using System.IO;
4 using System.Net.Http;
5 using System.Net.Http.Headers;
6 using System.Net.WebSockets;
7 using System.Text;
8 using System.Threading;
9 using System.Threading.Tasks;
10 using Newtonsoft.Json;
18 office 11 using Serilog;
24 office 12 using Servers;
1 office 13 using ClientWebSocket = System.Net.WebSockets.Managed.ClientWebSocket;
14  
15 namespace Winify.Gotify
16 {
17 public class GotifyConnection : IDisposable
18 {
19 #region Public Events & Delegates
20  
21 public event EventHandler<GotifyNotificationEventArgs> GotifyNotification;
22  
23 #endregion
24  
25 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
26  
25 office 27 private readonly Server _server;
28  
1 office 29 private CancellationToken _cancellationToken;
30  
31 private CancellationTokenSource _cancellationTokenSource;
32  
33 private Task _runTask;
34  
25 office 35 #endregion
1 office 36  
25 office 37 #region Constructors, Destructors and Finalizers
24 office 38  
39 public GotifyConnection(Server server)
40 {
41 _server = server;
42 }
43  
1 office 44 public void Dispose()
45 {
46 if (_cancellationTokenSource != null)
47 {
48 _cancellationTokenSource.Dispose();
49 _cancellationTokenSource = null;
50 }
51 }
52  
53 #endregion
54  
55 #region Public Methods
56  
25 office 57 public void Start()
1 office 58 {
28 office 59 if (!Uri.TryCreate(_server.Url, UriKind.Absolute, out var httpUri)) return;
1 office 60  
12 office 61 // Build the web sockets URI.
62 var webSocketsUriBuilder = new UriBuilder(httpUri);
63 webSocketsUriBuilder.Scheme = "ws";
28 office 64 webSocketsUriBuilder.Path = Path.Combine($"{webSocketsUriBuilder.Path}", "stream");
12 office 65 var webSocketsUri = webSocketsUriBuilder.Uri;
1 office 66  
67 _cancellationTokenSource = new CancellationTokenSource();
68 _cancellationToken = _cancellationTokenSource.Token;
69  
25 office 70 _runTask = Run(webSocketsUri, httpUri, _server.Username, _server.Password, _cancellationToken);
1 office 71 }
72  
73 public void Stop()
74 {
28 office 75 if (_cancellationTokenSource != null) _cancellationTokenSource.Cancel();
1 office 76 }
77  
78 #endregion
79  
80 #region Private Methods
81  
12 office 82 private async Task Run(Uri webSocketsUri, Uri httpUri, string username, string password,
28 office 83 CancellationToken cancellationToken)
1 office 84 {
85 try
86 {
87 do
88 {
89 try
90 {
25 office 91 using (var webSocketClient = new ClientWebSocket())
21 office 92 {
93 var auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
18 office 94  
25 office 95 webSocketClient.Options.SetRequestHeader("Authorization", $"Basic {auth}");
18 office 96  
25 office 97 await webSocketClient.ConnectAsync(webSocketsUri, cancellationToken);
1 office 98  
21 office 99 do
1 office 100 {
21 office 101 var payload = new ArraySegment<byte>(new byte[1024]);
1 office 102  
25 office 103 var result = await webSocketClient.ReceiveAsync(payload, cancellationToken);
1 office 104  
28 office 105 if (result.Count == 0) continue;
1 office 106  
28 office 107 if (payload.Array == null || payload.Count == 0) continue;
1 office 108  
21 office 109 var message = Encoding.UTF8.GetString(payload.Array, 0, payload.Count);
12 office 110  
28 office 111 var gotifyNotification = JsonConvert.DeserializeObject<GotifyNotification>(message);
112  
113 if (gotifyNotification == null)
1 office 114 {
25 office 115 Log.Warning($"Could not deserialize gotify notification: {message}");
116  
1 office 117 continue;
118 }
119  
24 office 120 gotifyNotification.Server = _server;
121  
28 office 122 if (!Uri.TryCreate(Path.Combine($"{httpUri}", "application"), UriKind.Absolute,
123 out var applicationUri))
35 office 124 {
12 office 125 continue;
35 office 126 }
3 office 127  
25 office 128 var image = await RetrieveGotifyApplicationImage(gotifyNotification.AppId, httpUri,
129 applicationUri, auth, cancellationToken);
12 office 130  
25 office 131 GotifyNotification?.Invoke(this,
132 new GotifyNotificationEventArgs(gotifyNotification, image));
3 office 133  
21 office 134 Log.Debug($"Notification message received: {gotifyNotification.Message}");
135 } while (!cancellationToken.IsCancellationRequested);
136 }
1 office 137 }
12 office 138 catch (Exception ex) when (ex is WebSocketException || ex is HttpRequestException)
1 office 139 {
25 office 140 // Reconnect
18 office 141 Log.Warning($"Unable to connect to gotify server: {ex.Message}");
12 office 142  
1 office 143 await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
144 }
145 } while (!cancellationToken.IsCancellationRequested);
146 }
147 catch (Exception ex) when (ex is OperationCanceledException || ex is ObjectDisposedException)
148 {
149 }
150 catch (Exception ex)
151 {
18 office 152 Log.Warning(ex, "Failure running connection loop.");
1 office 153 }
154 }
155  
25 office 156 private static async Task<Image> RetrieveGotifyApplicationImage(int appId, Uri httpUri, Uri applicationUri,
28 office 157 string auth,
158 CancellationToken cancellationToken)
25 office 159 {
160 using (var httpClient = new HttpClient())
161 {
162 httpClient.DefaultRequestHeaders.Authorization =
163 new AuthenticationHeaderValue("Basic", auth);
164  
165 var applicationResponse = await httpClient.GetAsync(applicationUri, cancellationToken);
166  
167 var applications = await applicationResponse.Content.ReadAsStringAsync();
168  
169 var gotifyApplications =
170 JsonConvert.DeserializeObject<GotifyApplication[]>(applications);
171  
28 office 172 if (gotifyApplications == null) return null;
25 office 173  
174 foreach (var application in gotifyApplications)
175 {
28 office 176 if (application.Id != appId) continue;
25 office 177  
28 office 178 if (!Uri.TryCreate(Path.Combine($"{httpUri}", $"{application.Image}"), UriKind.Absolute,
179 out var applicationImageUri))
25 office 180 continue;
181  
182 var imageResponse = await httpClient.GetAsync(applicationImageUri, cancellationToken);
183  
184 using (var memoryStream = new MemoryStream())
185 {
186 await imageResponse.Content.CopyToAsync(memoryStream);
187  
188 return Image.FromStream(memoryStream);
189 }
190 }
191 }
192  
193 return null;
194 }
195  
1 office 196 #endregion
197 }
198 }