Winify – Blame information for rev 43

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System;
25 office 2 using System.Collections.Concurrent;
1 office 3 using System.ComponentModel;
30 office 4 using System.Drawing;
4 office 5 using System.IO;
30 office 6 using System.Reflection;
15 office 7 using System.Text;
19 office 8 using System.Threading;
4 office 9 using System.Threading.Tasks;
1 office 10 using System.Windows.Forms;
30 office 11 using NetSparkleUpdater;
12 using NetSparkleUpdater.Enums;
13 using NetSparkleUpdater.SignatureVerifiers;
14 using NetSparkleUpdater.UI.WinForms;
18 office 15 using Serilog;
15 office 16 using Servers;
29 office 17 using Toasts;
1 office 18 using Winify.Gotify;
25 office 19 using Winify.Settings;
15 office 20 using Winify.Utilities;
30 office 21 using Winify.Utilities.Serialization;
1 office 22  
23 namespace Winify
24 {
30 office 25 public partial class MainForm : Form
1 office 26 {
30 office 27 #region Public Enums, Properties and Fields
28  
29 public Configuration.Configuration Configuration { get; set; }
30  
31 public ScheduledContinuation ChangedConfigurationContinuation { get; set; }
32  
43 office 33 public bool MemorySinkEnabled { get; set; }
34  
30 office 35 #endregion
36  
1 office 37 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
38  
39 private AboutForm _aboutForm;
40  
25 office 41 private ConcurrentBag<GotifyConnection> _gotifyConnections;
1 office 42  
43 private SettingsForm _settingsForm;
44  
30 office 45 private readonly SparkleUpdater _sparkle;
46  
47 private readonly CancellationTokenSource _cancellationTokenSource;
48  
49 private readonly CancellationToken _cancellationToken;
50  
43 office 51 private LogViewForm _logViewForm;
52  
53 private readonly LogMemorySink _memorySink;
54  
1 office 55 #endregion
56  
57 #region Constructors, Destructors and Finalizers
58  
30 office 59 public MainForm()
1 office 60 {
30 office 61 _cancellationTokenSource = new CancellationTokenSource();
62 _cancellationToken = _cancellationTokenSource.Token;
63  
64 ChangedConfigurationContinuation = new ScheduledContinuation();
65 }
66  
67 public MainForm(Mutex mutex) : this()
68 {
1 office 69 InitializeComponent();
70  
43 office 71 _memorySink = new LogMemorySink();
18 office 72 Log.Logger = new LoggerConfiguration()
73 .MinimumLevel.Debug()
43 office 74 .WriteTo.Conditional(condition => MemorySinkEnabled, configureSink => configureSink.Sink(_memorySink))
18 office 75 .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"),
76 rollingInterval: RollingInterval.Day)
77 .CreateLogger();
78  
30 office 79 // Start application update.
80 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName;
81 var icon = Icon.ExtractAssociatedIcon(manifestModuleName);
19 office 82  
30 office 83 _sparkle = new SparkleUpdater("https://winify.grimore.org/update/appcast.xml",
84 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY="))
4 office 85 {
30 office 86 UIFactory = new UIFactory(icon),
87 RelaunchAfterUpdate = true
88 };
89 _sparkle.StartLoop(true, true);
1 office 90 }
91  
92 /// <summary>
93 /// Clean up any resources being used.
94 /// </summary>
95 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
96 protected override void Dispose(bool disposing)
97 {
30 office 98 if (disposing && components != null) components.Dispose();
7 office 99  
1 office 100 base.Dispose(disposing);
101 }
102  
103 #endregion
104  
105 #region Event Handlers
106  
30 office 107 private async void MainForm_Load(object sender, EventArgs e)
21 office 108 {
30 office 109 Configuration = await LoadConfiguration();
21 office 110  
30 office 111 var servers = await LoadServers();
112 _gotifyConnections = new ConcurrentBag<GotifyConnection>();
113 foreach (var server in servers.Server)
114 {
115 var gotifyConnection = new GotifyConnection(server);
116 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification;
117 gotifyConnection.Start();
118 _gotifyConnections.Add(gotifyConnection);
119 }
21 office 120 }
121  
25 office 122 private async void SettingsToolStripMenuItem_Click(object sender, EventArgs e)
11 office 123 {
30 office 124 if (_settingsForm == null)
125 {
126 var servers = await LoadServers();
127 var announcements = await LoadAnnouncements();
25 office 128  
30 office 129 _settingsForm = new SettingsForm(this, servers, announcements, _cancellationToken);
130 _settingsForm.Save += SettingsForm_Save;
131 _settingsForm.Closing += SettingsForm_Closing;
132 _settingsForm.Show();
133 }
25 office 134 }
135  
136 private async void SettingsForm_Save(object sender, SettingsSavedEventArgs e)
137 {
138 // Save the servers.
139 await Task.WhenAll(SaveServers(e.Servers), SaveAnnouncements(e.Announcements));
140  
141 // Update connections to gotify servers.
142 while (_gotifyConnections.TryTake(out var gotifyConnection))
143 {
144 gotifyConnection.GotifyNotification -= GotifyConnection_GotifyNotification;
145 gotifyConnection.Stop();
146 gotifyConnection.Dispose();
147 gotifyConnection = null;
148 }
149  
150 foreach (var server in e.Servers.Server)
151 {
152 var gotifyConnection = new GotifyConnection(server);
153 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification;
154 gotifyConnection.Start();
155 _gotifyConnections.Add(gotifyConnection);
156 }
157 }
158  
30 office 159 private async void GotifyConnection_GotifyNotification(object sender, GotifyNotificationEventArgs e)
25 office 160 {
30 office 161 var announcements = await LoadAnnouncements();
25 office 162  
30 office 163 foreach (var announcement in announcements.Announcement)
40 office 164 {
30 office 165 if (announcement.AppId == e.Notification.AppId)
166 {
167 var configuredNotification = new ToastForm(
168 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})",
169 e.Notification.Message, announcement.LingerTime, e.Image);
24 office 170  
30 office 171 configuredNotification.Show();
24 office 172  
30 office 173 return;
174 }
40 office 175 }
24 office 176  
30 office 177 var notification = new ToastForm(
178 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})",
179 e.Notification.Message, 5000, e.Image);
24 office 180  
30 office 181 notification.Show();
11 office 182 }
183  
1 office 184 private void SettingsForm_Closing(object sender, CancelEventArgs e)
185 {
42 office 186 if (_settingsForm == null)
187 {
188 return;
189 }
6 office 190  
25 office 191 _settingsForm.Save -= SettingsForm_Save;
1 office 192 _settingsForm.Closing -= SettingsForm_Closing;
193 _settingsForm.Dispose();
194 _settingsForm = null;
195 }
196  
197 private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
198 {
42 office 199 if (_aboutForm != null)
200 {
201 return;
202 }
1 office 203  
204 _aboutForm = new AboutForm();
205 _aboutForm.Closing += AboutForm_Closing;
206 _aboutForm.Show();
207 }
208  
209 private void AboutForm_Closing(object sender, CancelEventArgs e)
210 {
42 office 211 if (_aboutForm == null)
212 {
213 return;
214 }
1 office 215  
216 _aboutForm.Closing -= AboutForm_Closing;
217 _aboutForm.Dispose();
218 _aboutForm = null;
219 }
220  
221 private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
222 {
17 office 223 Close();
30 office 224 }
17 office 225  
30 office 226 private async void UpdateToolStripMenuItem_Click(object sender, EventArgs e)
227 {
228 // Manually check for updates, this will not show a ui
229 var result = await _sparkle.CheckForUpdatesQuietly();
230 if (result.Status == UpdateStatus.UpdateAvailable)
231 {
232 // if update(s) are found, then we have to trigger the UI to show it gracefully
233 _sparkle.ShowUpdateNeededUI();
234 return;
235 }
236  
237 MessageBox.Show("No updates available at this time.", "Horizon", MessageBoxButtons.OK,
238 MessageBoxIcon.Asterisk,
239 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false);
1 office 240 }
241  
30 office 242 #endregion
243  
244 #region Public Methods
245  
246 public async Task SaveConfiguration()
9 office 247 {
30 office 248 if (!Directory.Exists(Constants.UserApplicationDirectory))
249 Directory.CreateDirectory(Constants.UserApplicationDirectory);
250  
251 switch (await Serialization.Serialize(Configuration, Constants.ConfigurationFile, "Configuration",
252 "<!ATTLIST Configuration xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
253 CancellationToken.None))
254 {
255 case SerializationSuccess<Configuration.Configuration> _:
256 Log.Information("Serialized configuration.");
257 break;
258 case SerializationFailure serializationFailure:
259 Log.Warning(serializationFailure.Exception.Message, "Failed to serialize configuration.");
260 break;
261 }
9 office 262 }
263  
30 office 264 public static async Task<Configuration.Configuration> LoadConfiguration()
265 {
266 if (!Directory.Exists(Constants.UserApplicationDirectory))
267 Directory.CreateDirectory(Constants.UserApplicationDirectory);
268  
269 var deserializationResult =
270 await Serialization.Deserialize<Configuration.Configuration>(Constants.ConfigurationFile,
271 Constants.ConfigurationNamespace, Constants.ConfigurationXsd, CancellationToken.None);
272  
273 switch (deserializationResult)
274 {
275 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
276 return serializationSuccess.Result;
277 case SerializationFailure serializationFailure:
278 Log.Warning(serializationFailure.Exception, "Failed to load configuration.");
279 return new Configuration.Configuration();
280 default:
281 return new Configuration.Configuration();
282 }
283 }
284  
1 office 285 #endregion
4 office 286  
287 #region Private Methods
288  
25 office 289 private static async Task SaveAnnouncements(Announcements.Announcements announcements)
21 office 290 {
30 office 291 switch (await Serialization.Serialize(announcements, Constants.AnnouncementsFile, "Announcements",
292 "<!ATTLIST Announcements xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
293 CancellationToken.None))
21 office 294 {
295 case SerializationFailure serializationFailure:
296 Log.Warning(serializationFailure.Exception, "Unable to serialize announcements.");
297 break;
298 }
299 }
300  
30 office 301 private static async Task SaveServers(Servers.Servers servers)
21 office 302 {
303 // Encrypt password for all servers.
304 var deviceId = Miscellaneous.GetMachineGuid();
30 office 305 var @protected = new Servers.Servers
21 office 306 {
307 Server = new BindingListWithCollectionChanged<Server>()
308 };
43 office 309  
25 office 310 foreach (var server in servers.Server)
21 office 311 {
41 office 312 var password = Encoding.UTF8.GetBytes(server.Password);
313 var encrypted = await AES.Encrypt(password, deviceId);
21 office 314 var armored = Convert.ToBase64String(encrypted);
315  
316 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, armored));
317 }
318  
30 office 319 switch (await Serialization.Serialize(@protected, Constants.ServersFile, "Servers",
320 "<!ATTLIST Servers xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
321 CancellationToken.None))
21 office 322 {
323 case SerializationFailure serializationFailure:
324 Log.Warning(serializationFailure.Exception, "Unable to serialize servers.");
325 break;
326 }
327 }
328  
15 office 329 private static async Task<Announcements.Announcements> LoadAnnouncements()
330 {
331 if (!Directory.Exists(Constants.UserApplicationDirectory))
332 Directory.CreateDirectory(Constants.UserApplicationDirectory);
333  
334 var deserializationResult =
30 office 335 await Serialization.Deserialize<Announcements.Announcements>(Constants.AnnouncementsFile,
336 "urn:winify-announcements-schema", "Announcements.xsd", CancellationToken.None);
15 office 337  
338 switch (deserializationResult)
339 {
340 case SerializationSuccess<Announcements.Announcements> serializationSuccess:
341 return serializationSuccess.Result;
21 office 342 case SerializationFailure serializationFailure:
343 Log.Warning(serializationFailure.Exception, "Unable to load announcements.");
344 return new Announcements.Announcements();
15 office 345 default:
346 return new Announcements.Announcements();
347 }
348 }
349  
30 office 350 private static async Task<Servers.Servers> LoadServers()
4 office 351 {
352 if (!Directory.Exists(Constants.UserApplicationDirectory))
353 Directory.CreateDirectory(Constants.UserApplicationDirectory);
354  
15 office 355 var deserializationResult =
30 office 356 await Serialization.Deserialize<Servers.Servers>(Constants.ServersFile,
357 "urn:winify-servers-schema", "Servers.xsd", CancellationToken.None);
4 office 358  
359 switch (deserializationResult)
360 {
30 office 361 case SerializationSuccess<Servers.Servers> serializationSuccess:
15 office 362 // Decrypt password.
363 var deviceId = Miscellaneous.GetMachineGuid();
30 office 364 var @protected = new Servers.Servers
15 office 365 {
366 Server = new BindingListWithCollectionChanged<Server>()
367 };
368 foreach (var server in serializationSuccess.Result.Server)
369 {
370 var unarmored = Convert.FromBase64String(server.Password);
41 office 371 var result = await AES.Decrypt(unarmored, deviceId);
372 var decrypted = Encoding.UTF8.GetString(result);
4 office 373  
15 office 374 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, decrypted));
375 }
376  
377 return @protected;
378  
21 office 379 case SerializationFailure serializationFailure:
380 Log.Warning(serializationFailure.Exception, "Unable to load servers.");
30 office 381 return new Servers.Servers();
21 office 382  
4 office 383 default:
30 office 384 return new Servers.Servers();
4 office 385 }
386 }
387  
388 #endregion
43 office 389  
390 private void LogViewToolStripMenuItem_Click(object sender, EventArgs e)
391 {
392 if (_logViewForm != null)
393 {
394 return;
395 }
396  
397 _logViewForm = new LogViewForm(this, _memorySink, _cancellationToken);
398 _logViewForm.Closing += LogViewForm_Closing;
399 _logViewForm.Show();
400 }
401  
402 private void LogViewForm_Closing(object sender, CancelEventArgs e)
403 {
404 if (_logViewForm == null)
405 {
406 return;
407 }
408  
409 _logViewForm.Closing -= LogViewForm_Closing;
410 _logViewForm.Close();
411 _logViewForm = null;
412 }
1 office 413 }
414 }