Winify – Blame information for rev 39

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