Winify – Blame information for rev 21

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;
1 office 12 using ClientWebSocket = System.Net.WebSockets.Managed.ClientWebSocket;
13  
14 namespace Winify.Gotify
15 {
16 public class GotifyConnection : IDisposable
17 {
18 #region Public Events & Delegates
19  
20 public event EventHandler<GotifyNotificationEventArgs> GotifyNotification;
21  
22 #endregion
23  
24 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
25  
26 private CancellationToken _cancellationToken;
27  
28 private CancellationTokenSource _cancellationTokenSource;
29  
30 private HttpClient _httpClient;
31  
32 private Task _runTask;
33  
34 private ClientWebSocket _webSocketClient;
35  
36 #endregion
37  
38 #region Constructors, Destructors and Finalizers
39  
40 public void Dispose()
41 {
42 if (_cancellationTokenSource != null)
43 {
44 _cancellationTokenSource.Dispose();
45 _cancellationTokenSource = null;
46 }
47  
48 if (_webSocketClient != null)
49 {
50 _webSocketClient.Dispose();
51 _webSocketClient = null;
52 }
53  
54 if (_httpClient != null)
55 {
56 _httpClient.Dispose();
57 _httpClient = null;
58 }
59 }
60  
61 #endregion
62  
63 #region Public Methods
64  
12 office 65 public void Start(string username, string password, string url)
1 office 66 {
12 office 67 if (!Uri.TryCreate(url, UriKind.Absolute, out var httpUri))
1 office 68 {
69 return;
70 }
71  
12 office 72 // Build the web sockets URI.
73 var webSocketsUriBuilder = new UriBuilder(httpUri);
74 webSocketsUriBuilder.Scheme = "ws";
75 webSocketsUriBuilder.Path = $"{webSocketsUriBuilder.Path}/stream";
76 var webSocketsUri = webSocketsUriBuilder.Uri;
1 office 77  
78 _cancellationTokenSource = new CancellationTokenSource();
79 _cancellationToken = _cancellationTokenSource.Token;
80  
12 office 81 _httpClient = new HttpClient();
18 office 82  
1 office 83 var auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
18 office 84  
1 office 85 _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
86  
12 office 87 _runTask = Run(webSocketsUri, httpUri, username, password, _cancellationToken);
1 office 88 }
89  
90 public void Stop()
91 {
92 if (_cancellationTokenSource != null)
93 {
94 _cancellationTokenSource.Cancel();
95 }
96 }
97  
98 #endregion
99  
100 #region Private Methods
101  
12 office 102 private async Task Run(Uri webSocketsUri, Uri httpUri, string username, string password,
103 CancellationToken cancellationToken)
1 office 104 {
105 try
106 {
107 do
108 {
109 try
110 {
21 office 111 using (_webSocketClient = new ClientWebSocket())
112 {
113 var auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
18 office 114  
21 office 115 _webSocketClient.Options.SetRequestHeader("Authorization", $"Basic {auth}");
18 office 116  
21 office 117 await _webSocketClient.ConnectAsync(webSocketsUri, cancellationToken);
1 office 118  
21 office 119 do
1 office 120 {
21 office 121 var payload = new ArraySegment<byte>(new byte[1024]);
1 office 122  
21 office 123 var result = await _webSocketClient.ReceiveAsync(payload, cancellationToken);
1 office 124  
21 office 125 if (result.Count == 0)
126 {
127 continue;
128 }
1 office 129  
21 office 130 if (payload.Array == null || payload.Count == 0)
131 {
132 continue;
133 }
1 office 134  
21 office 135 var message = Encoding.UTF8.GetString(payload.Array, 0, payload.Count);
12 office 136  
21 office 137 var gotifyNotification = JsonConvert.DeserializeObject<GotifyNotification>(message);
138 if (gotifyNotification == null)
1 office 139 {
140 continue;
141 }
142  
21 office 143 if (!Uri.TryCreate($"{httpUri}/application", UriKind.Absolute, out var applicationUri))
12 office 144 {
145 continue;
146 }
3 office 147  
21 office 148 var applications = await _httpClient.GetStringAsync(applicationUri);
12 office 149  
21 office 150 var gotifyApplications =
151 JsonConvert.DeserializeObject<GotifyApplication[]>(applications);
152 if (gotifyApplications == null)
3 office 153 {
154 continue;
155 }
156  
21 office 157 foreach (var application in gotifyApplications)
1 office 158 {
21 office 159 if (application.Id != gotifyNotification.AppId)
160 {
161 continue;
162 }
1 office 163  
21 office 164 if (!Uri.TryCreate($"{httpUri}/{application.Image}", UriKind.Absolute,
165 out var applicationImageUri))
166 {
167 continue;
168 }
169  
170 var imageBytes = await _httpClient.GetByteArrayAsync(applicationImageUri);
171  
172 if (imageBytes == null || imageBytes.Length == 0)
173 {
174 continue;
175 }
176  
177 using (var memoryStream = new MemoryStream(imageBytes))
178 {
179 var image = Image.FromStream(memoryStream);
180  
181 GotifyNotification?.Invoke(this,
182 new GotifyNotificationEventArgs(gotifyNotification, image));
183 }
184  
185  
186 break;
1 office 187 }
188  
21 office 189 Log.Debug($"Notification message received: {gotifyNotification.Message}");
190 } while (!cancellationToken.IsCancellationRequested);
1 office 191  
21 office 192 await _webSocketClient.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
193 CancellationToken.None);
194 }
1 office 195  
21 office 196 _webSocketClient = null;
1 office 197 }
12 office 198 catch (Exception ex) when (ex is WebSocketException || ex is HttpRequestException)
1 office 199 {
18 office 200 Log.Warning($"Unable to connect to gotify server: {ex.Message}");
12 office 201  
1 office 202 // Reconnect
203 if (_webSocketClient != null)
204 {
205 _webSocketClient.Abort();
206 _webSocketClient.Dispose();
207 _webSocketClient = null;
208 }
209  
210 await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
211 }
212 } while (!cancellationToken.IsCancellationRequested);
213 }
214 catch (Exception ex) when (ex is OperationCanceledException || ex is ObjectDisposedException)
215 {
216 }
217 catch (Exception ex)
218 {
18 office 219 Log.Warning(ex, "Failure running connection loop.");
1 office 220 }
221 }
222  
223 #endregion
224 }
225 }