Winify – Blame information for rev 12

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
2 using System.Diagnostics;
3 using System.Drawing;
4 using System.IO;
5 using System.Net.Http;
6 using System.Net.Http.Headers;
7 using System.Net.WebSockets;
8 using System.Text;
9 using System.Threading;
10 using System.Threading.Tasks;
11 using Newtonsoft.Json;
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();
1 office 82 var auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
83 _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", auth);
84  
12 office 85 _runTask = Run(webSocketsUri, httpUri, username, password, _cancellationToken);
1 office 86 }
87  
88 public void Stop()
89 {
90 if (_cancellationTokenSource != null)
91 {
92 _cancellationTokenSource.Cancel();
93 }
94 }
95  
96 #endregion
97  
98 #region Private Methods
99  
12 office 100 private async Task Run(Uri webSocketsUri, Uri httpUri, string username, string password,
101 CancellationToken cancellationToken)
1 office 102 {
103 try
104 {
105 do
106 {
107 try
108 {
109 _webSocketClient = new ClientWebSocket();
110 var auth = Convert.ToBase64String(Encoding.Default.GetBytes($"{username}:{password}"));
111 _webSocketClient.Options.SetRequestHeader("Authorization", $"Basic {auth}");
112  
12 office 113 await _webSocketClient.ConnectAsync(webSocketsUri, cancellationToken);
1 office 114  
115 do
116 {
117 var payload = new ArraySegment<byte>(new byte[1024]);
118  
119 await _webSocketClient.ReceiveAsync(payload, cancellationToken);
120  
121 if (payload.Array == null || payload.Count == 0)
122 {
123 continue;
124 }
125  
126 var message = Encoding.UTF8.GetString(payload.Array, 0, payload.Count);
127  
128 var gotifyNotification = JsonConvert.DeserializeObject<GotifyNotification>(message);
129 if (gotifyNotification == null)
130 {
131 continue;
132 }
133  
12 office 134 if (!Uri.TryCreate($"{httpUri}/application", UriKind.Absolute, out var applicationUri))
135 {
136 continue;
137 }
1 office 138  
12 office 139 var applications = await _httpClient.GetStringAsync(applicationUri);
140  
1 office 141 var gotifyApplications = JsonConvert.DeserializeObject<GotifyApplication[]>(applications);
142 if (gotifyApplications == null)
143 {
144 continue;
145 }
146  
147 foreach (var application in gotifyApplications)
148 {
149 if (application.Id != gotifyNotification.AppId)
150 {
151 continue;
152 }
153  
12 office 154 if (!Uri.TryCreate($"{httpUri}/{application.Image}", UriKind.Absolute,
155 out var applicationImageUri))
156 {
157 continue;
158 }
3 office 159  
12 office 160 var imageBytes = await _httpClient.GetByteArrayAsync(applicationImageUri);
161  
3 office 162 if (imageBytes == null || imageBytes.Length == 0)
163 {
164 continue;
165 }
166  
1 office 167 using (var memoryStream = new MemoryStream(imageBytes))
168 {
169 var image = Image.FromStream(memoryStream);
170  
12 office 171 GotifyNotification?.Invoke(this,
172 new GotifyNotificationEventArgs(gotifyNotification, image));
1 office 173 }
174  
175  
176 break;
177 }
178  
179 Debug.WriteLine($"{gotifyNotification.Message}");
180 } while (!cancellationToken.IsCancellationRequested);
181  
182 await _webSocketClient.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
183 CancellationToken.None);
184 }
12 office 185 catch (Exception ex) when (ex is WebSocketException || ex is HttpRequestException)
1 office 186 {
12 office 187 Debug.WriteLine($"Unable to connect to gotify server: {ex.Message}");
188  
1 office 189 // Reconnect
190 if (_webSocketClient != null)
191 {
192 _webSocketClient.Abort();
193 _webSocketClient.Dispose();
194 _webSocketClient = null;
195 }
196  
197 await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
198 }
199 } while (!cancellationToken.IsCancellationRequested);
200 }
201 catch (Exception ex) when (ex is OperationCanceledException || ex is ObjectDisposedException)
202 {
203 }
204 catch (Exception ex)
205 {
206 Debug.WriteLine($"Exception: {ex}");
207 }
208 }
209  
210 #endregion
211 }
212 }