Winify – Blame information for rev 24

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