Winify – Diff between revs 29 and 30

Subversion Repositories:
Rev:
Show entire fileIgnore whitespace
Rev 29 Rev 30
Line 1... Line 1...
1 using System; 1 using System;
2 using System.Collections.Concurrent; 2 using System.Collections.Concurrent;
3 using System.ComponentModel; 3 using System.ComponentModel;
4 using System.Configuration; -  
5 using System.Diagnostics; 4 using System.Drawing;
6 using System.IO; 5 using System.IO;
-   6 using System.Reflection;
7 using System.Text; 7 using System.Text;
8 using System.Threading; 8 using System.Threading;
9 using System.Threading.Tasks; 9 using System.Threading.Tasks;
10 using System.Windows.Forms; 10 using System.Windows.Forms;
-   11 using NetSparkleUpdater;
11 using AutoUpdaterDotNET; 12 using NetSparkleUpdater.Enums;
-   13 using NetSparkleUpdater.SignatureVerifiers;
-   14 using NetSparkleUpdater.UI.WinForms;
12 using Serilog; 15 using Serilog;
13 using Servers; 16 using Servers;
14 using Toasts; 17 using Toasts;
15 using Winify.Gotify; 18 using Winify.Gotify;
16 using Winify.Servers.Serialization; -  
17 using Winify.Settings; 19 using Winify.Settings;
18 using Winify.Utilities; 20 using Winify.Utilities;
-   21 using Winify.Utilities.Serialization;
Line 19... Line 22...
19   22  
20 namespace Winify 23 namespace Winify
21 { 24 {
22 public partial class Form1 : Form 25 public partial class MainForm : Form
23 { 26 {
-   27 #region Public Enums, Properties and Fields
-   28  
-   29 public Configuration.Configuration Configuration { get; set; }
-   30  
Line -... Line 31...
-   31 public ScheduledContinuation ChangedConfigurationContinuation { get; set; }
-   32  
24 #region Private Delegates, Events, Enums, Properties, Indexers and Fields 33 #endregion
Line 25... Line 34...
25   34  
Line 26... Line 35...
26 private readonly TaskScheduler _uiTaskScheduler; 35 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
Line 27... Line 36...
27   36  
Line -... Line 37...
-   37 private AboutForm _aboutForm;
-   38  
-   39 private ConcurrentBag<GotifyConnection> _gotifyConnections;
-   40  
-   41 private SettingsForm _settingsForm;
-   42  
28 private AboutForm _aboutForm; 43 private readonly SparkleUpdater _sparkle;
Line 29... Line 44...
29   44  
Line -... Line 45...
-   45 private readonly CancellationTokenSource _cancellationTokenSource;
-   46  
-   47 private readonly CancellationToken _cancellationToken;
-   48  
-   49 #endregion
-   50  
-   51 #region Constructors, Destructors and Finalizers
-   52  
30 private ConcurrentBag<GotifyConnection> _gotifyConnections; 53 public MainForm()
31   54 {
32 private SettingsForm _settingsForm; 55 _cancellationTokenSource = new CancellationTokenSource();
Line 33... Line 56...
33   56 _cancellationToken = _cancellationTokenSource.Token;
34 #endregion 57  
35   58 ChangedConfigurationContinuation = new ScheduledContinuation();
36 #region Constructors, Destructors and Finalizers 59 }
37   60  
Line 38... Line 61...
38 public Form1(Mutex mutex) 61 public MainForm(Mutex mutex) : this()
39 { 62 {
40 InitializeComponent(); -  
41   -  
42 Log.Logger = new LoggerConfiguration() -  
43 .MinimumLevel.Debug() -  
44 .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"), -  
45 rollingInterval: RollingInterval.Day) -  
46 .CreateLogger(); -  
47   -  
48 // Upgrade settings if required. -  
49 if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile) 63 InitializeComponent();
50 if (Properties.Settings.Default.UpdateRequired) -  
51 { -  
52 Properties.Settings.Default.Upgrade(); -  
53 Properties.Settings.Default.Reload(); -  
54   -  
55 Properties.Settings.Default.UpdateRequired = false; -  
56 Properties.Settings.Default.Save(); -  
57   -  
58 mutex.ReleaseMutex(); -  
59 Process.Start(Application.ExecutablePath); -  
Line 60... Line 64...
60 Environment.Exit(0); 64  
-   65 Log.Logger = new LoggerConfiguration()
61 } 66 .MinimumLevel.Debug()
62   67 .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"),
63 // Bind to settings changed event. -  
64 Properties.Settings.Default.SettingsLoaded += Default_SettingsLoaded; -  
65 Properties.Settings.Default.SettingsSaving += Default_SettingsSaving; -  
66 Properties.Settings.Default.PropertyChanged += Default_PropertyChanged; -  
67   -  
68 // Store UI thread context. -  
69 _uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(); -  
70   68 rollingInterval: RollingInterval.Day)
71 LoadServers().ContinueWith(async task => -  
72 { -  
73 var restoredServers = await task; 69 .CreateLogger();
74   -  
75 _gotifyConnections = new ConcurrentBag<GotifyConnection>(); 70  
76   -  
77 foreach (var server in restoredServers.Server) 71 // Start application update.
Line 78... Line 72...
78 { 72 var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName;
79 var gotifyConnection = new GotifyConnection(server); 73 var icon = Icon.ExtractAssociatedIcon(manifestModuleName);
80 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification; 74  
81 gotifyConnection.Start(); 75 _sparkle = new SparkleUpdater("https://winify.grimore.org/update/appcast.xml",
82 _gotifyConnections.Add(gotifyConnection); 76 new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY="))
83 } 77 {
84 }); 78 UIFactory = new UIFactory(icon),
85   -  
86 // Start application update. -  
87 AutoUpdater.Start("http://winify.grimore.org/update/winify.xml"); -  
88 } -  
89   -  
90 /// <summary> -  
91 /// Clean up any resources being used. -  
Line 92... Line 79...
92 /// </summary> 79 RelaunchAfterUpdate = true
93 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 80 };
Line 94... Line 81...
94 protected override void Dispose(bool disposing) 81 _sparkle.StartLoop(true, true);
Line 95... Line 82...
95 { 82 }
Line 96... Line 83...
96 if (disposing && components != null) 83  
97 { 84 /// <summary>
98 Properties.Settings.Default.SettingsLoaded -= Default_SettingsLoaded; 85 /// Clean up any resources being used.
99 Properties.Settings.Default.SettingsSaving -= Default_SettingsSaving; -  
Line -... Line 86...
-   86 /// </summary>
100 Properties.Settings.Default.PropertyChanged -= Default_PropertyChanged; 87 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-   88 protected override void Dispose(bool disposing)
101   89 {
-   90 if (disposing && components != null) components.Dispose();
-   91  
102 components.Dispose(); 92 base.Dispose(disposing);
103 } -  
104   93 }
105 base.Dispose(disposing); 94  
106 } 95 #endregion
Line 107... Line 96...
107   96  
108 #endregion 97 #region Event Handlers
109   98  
110 #region Event Handlers 99 private async void MainForm_Load(object sender, EventArgs e)
111   100 {
112 private static void Default_PropertyChanged(object sender, PropertyChangedEventArgs e) 101 Configuration = await LoadConfiguration();
Line 113... Line 102...
113 { 102  
114 Properties.Settings.Default.Save(); 103 var servers = await LoadServers();
115 } 104 _gotifyConnections = new ConcurrentBag<GotifyConnection>();
116   105 foreach (var server in servers.Server)
-   106 {
117 private static void Default_SettingsSaving(object sender, CancelEventArgs e) 107 var gotifyConnection = new GotifyConnection(server);
Line 118... Line 108...
118 { 108 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification;
119 } 109 gotifyConnection.Start();
120   110 _gotifyConnections.Add(gotifyConnection);
Line 156... Line 146...
156 gotifyConnection.Start(); 146 gotifyConnection.Start();
157 _gotifyConnections.Add(gotifyConnection); 147 _gotifyConnections.Add(gotifyConnection);
158 } 148 }
159 } 149 }
Line 160... Line 150...
160   150  
161 private void GotifyConnection_GotifyNotification(object sender, GotifyNotificationEventArgs e) 151 private async void GotifyConnection_GotifyNotification(object sender, GotifyNotificationEventArgs e)
162 { -  
163 Task.Factory.StartNew(async () => -  
164 { 152 {
Line 165... Line 153...
165 var announcements = await LoadAnnouncements(); 153 var announcements = await LoadAnnouncements();
166   154  
167 foreach (var announcement in announcements.Announcement) 155 foreach (var announcement in announcements.Announcement)
168 if (announcement.AppId == e.Notification.AppId) 156 if (announcement.AppId == e.Notification.AppId)
169 { 157 {
170 var configuredNotification = new ToastForm( 158 var configuredNotification = new ToastForm(
Line 171... Line 159...
171 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})", 159 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})",
Line 172... Line 160...
172 e.Notification.Message, announcement.LingerTime, e.Image); 160 e.Notification.Message, announcement.LingerTime, e.Image);
173   161  
Line 174... Line 162...
174 configuredNotification.Show(); 162 configuredNotification.Show();
175   163  
176 return; 164 return;
Line 177... Line 165...
177 } 165 }
178   -  
179 var notification = new ToastForm( 166  
Line 180... Line 167...
180 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})", 167 var notification = new ToastForm(
181 e.Notification.Message, 5000, e.Image); 168 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})",
182   169 e.Notification.Message, 5000, e.Image);
Line 213... Line 200...
213 } 200 }
Line 214... Line 201...
214   201  
215 private void QuitToolStripMenuItem_Click(object sender, EventArgs e) 202 private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
216 { 203 {
-   204 Close();
-   205 }
-   206  
-   207 private async void UpdateToolStripMenuItem_Click(object sender, EventArgs e)
-   208 {
-   209 // Manually check for updates, this will not show a ui
-   210 var result = await _sparkle.CheckForUpdatesQuietly();
-   211 if (result.Status == UpdateStatus.UpdateAvailable)
-   212 {
-   213 // if update(s) are found, then we have to trigger the UI to show it gracefully
-   214 _sparkle.ShowUpdateNeededUI();
-   215 return;
-   216 }
-   217  
-   218 MessageBox.Show("No updates available at this time.", "Horizon", MessageBoxButtons.OK,
-   219 MessageBoxIcon.Asterisk,
-   220 MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false);
-   221 }
-   222  
Line -... Line 223...
-   223 #endregion
-   224  
-   225 #region Public Methods
-   226  
-   227 public async Task SaveConfiguration()
-   228 {
-   229 if (!Directory.Exists(Constants.UserApplicationDirectory))
-   230 Directory.CreateDirectory(Constants.UserApplicationDirectory);
-   231  
-   232 switch (await Serialization.Serialize(Configuration, Constants.ConfigurationFile, "Configuration",
-   233 "<!ATTLIST Configuration xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
-   234 CancellationToken.None))
-   235 {
-   236 case SerializationSuccess<Configuration.Configuration> _:
-   237 Log.Information("Serialized configuration.");
-   238 break;
217 Close(); 239 case SerializationFailure serializationFailure:
-   240 Log.Warning(serializationFailure.Exception.Message, "Failed to serialize configuration.");
218   241 break;
Line 219... Line 242...
219 Environment.Exit(0); 242 }
220 } 243 }
-   244  
221   245 public static async Task<Configuration.Configuration> LoadConfiguration()
-   246 {
-   247 if (!Directory.Exists(Constants.UserApplicationDirectory))
-   248 Directory.CreateDirectory(Constants.UserApplicationDirectory);
-   249  
-   250 var deserializationResult =
-   251 await Serialization.Deserialize<Configuration.Configuration>(Constants.ConfigurationFile,
-   252 Constants.ConfigurationNamespace, Constants.ConfigurationXsd, CancellationToken.None);
-   253  
-   254 switch (deserializationResult)
-   255 {
-   256 case SerializationSuccess<Configuration.Configuration> serializationSuccess:
-   257 return serializationSuccess.Result;
-   258 case SerializationFailure serializationFailure:
-   259 Log.Warning(serializationFailure.Exception, "Failed to load configuration.");
-   260 return new Configuration.Configuration();
222 private void UpdateToolStripMenuItem_Click(object sender, EventArgs e) 261 default:
Line 223... Line 262...
223 { 262 return new Configuration.Configuration();
Line 224... Line 263...
224 AutoUpdater.Start("http://winify.grimore.org/update/winify.xml"); 263 }
Line 225... Line 264...
225 } 264 }
226   265  
227 #endregion 266 #endregion
228   267  
-   268 #region Private Methods
229 #region Private Methods 269  
230   270 private static async Task SaveAnnouncements(Announcements.Announcements announcements)
231 private static async Task SaveAnnouncements(Announcements.Announcements announcements) 271 {
232 { 272 switch (await Serialization.Serialize(announcements, Constants.AnnouncementsFile, "Announcements",
233 switch (await ServersSerialization.Serialize(announcements, Constants.AnnouncementsFile, "Announcements", 273 "<!ATTLIST Announcements xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
234 "<!ATTLIST Announcements xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>")) 274 CancellationToken.None))
Line 235... Line 275...
235 { 275 {
236 case SerializationFailure serializationFailure: 276 case SerializationFailure serializationFailure:
237 Log.Warning(serializationFailure.Exception, "Unable to serialize announcements."); 277 Log.Warning(serializationFailure.Exception, "Unable to serialize announcements.");
238 break; 278 break;
239 } 279 }
240 } 280 }
241   281  
242 private static async Task SaveServers(global::Servers.Servers servers) 282 private static async Task SaveServers(Servers.Servers servers)
243 { 283 {
244 // Encrypt password for all servers. 284 // Encrypt password for all servers.
Line 253... Line 293...
253 var armored = Convert.ToBase64String(encrypted); 293 var armored = Convert.ToBase64String(encrypted);
Line 254... Line 294...
254   294  
255 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, armored)); 295 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, armored));
Line 256... Line 296...
256 } 296 }
257   297  
-   298 switch (await Serialization.Serialize(@protected, Constants.ServersFile, "Servers",
258 switch (await ServersSerialization.Serialize(@protected, Constants.ServersFile, "Servers", 299 "<!ATTLIST Servers xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>",
259 "<!ATTLIST Servers xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>")) 300 CancellationToken.None))
260 { 301 {
261 case SerializationFailure serializationFailure: 302 case SerializationFailure serializationFailure:
262 Log.Warning(serializationFailure.Exception, "Unable to serialize servers."); 303 Log.Warning(serializationFailure.Exception, "Unable to serialize servers.");
Line 268... Line 309...
268 { 309 {
269 if (!Directory.Exists(Constants.UserApplicationDirectory)) 310 if (!Directory.Exists(Constants.UserApplicationDirectory))
270 Directory.CreateDirectory(Constants.UserApplicationDirectory); 311 Directory.CreateDirectory(Constants.UserApplicationDirectory);
Line 271... Line 312...
271   312  
272 var deserializationResult = 313 var deserializationResult =
273 await ServersSerialization.Deserialize<Announcements.Announcements>(Constants.AnnouncementsFile, 314 await Serialization.Deserialize<Announcements.Announcements>(Constants.AnnouncementsFile,
Line 274... Line 315...
274 "urn:winify-announcements-schema", "Announcements.xsd"); 315 "urn:winify-announcements-schema", "Announcements.xsd", CancellationToken.None);
275   316  
276 switch (deserializationResult) 317 switch (deserializationResult)
277 { 318 {
Line 283... Line 324...
283 default: 324 default:
284 return new Announcements.Announcements(); 325 return new Announcements.Announcements();
285 } 326 }
286 } 327 }
Line 287... Line 328...
287   328  
288 private static async Task<global::Servers.Servers> LoadServers() 329 private static async Task<Servers.Servers> LoadServers()
289 { 330 {
290 if (!Directory.Exists(Constants.UserApplicationDirectory)) 331 if (!Directory.Exists(Constants.UserApplicationDirectory))
Line 291... Line 332...
291 Directory.CreateDirectory(Constants.UserApplicationDirectory); 332 Directory.CreateDirectory(Constants.UserApplicationDirectory);
292   333  
293 var deserializationResult = 334 var deserializationResult =
Line 294... Line 335...
294 await ServersSerialization.Deserialize<global::Servers.Servers>(Constants.ServersFile, 335 await Serialization.Deserialize<Servers.Servers>(Constants.ServersFile,
295 "urn:winify-servers-schema", "Servers.xsd"); 336 "urn:winify-servers-schema", "Servers.xsd", CancellationToken.None);
296   337  
297 switch (deserializationResult) 338 switch (deserializationResult)
298 { 339 {
299 case SerializationSuccess<global::Servers.Servers> serializationSuccess: 340 case SerializationSuccess<Servers.Servers> serializationSuccess:
300 // Decrypt password. 341 // Decrypt password.
301 var deviceId = Miscellaneous.GetMachineGuid(); 342 var deviceId = Miscellaneous.GetMachineGuid();
302 var @protected = new global::Servers.Servers 343 var @protected = new Servers.Servers
303 { 344 {
304 Server = new BindingListWithCollectionChanged<Server>() 345 Server = new BindingListWithCollectionChanged<Server>()
Line 313... Line 354...
313   354  
Line 314... Line 355...
314 return @protected; 355 return @protected;
315   356  
316 case SerializationFailure serializationFailure: 357 case SerializationFailure serializationFailure:
Line 317... Line 358...
317 Log.Warning(serializationFailure.Exception, "Unable to load servers."); 358 Log.Warning(serializationFailure.Exception, "Unable to load servers.");
318 return new global::Servers.Servers(); 359 return new Servers.Servers();
319   360  
320 default: 361 default:
Line 321... Line 362...
321 return new global::Servers.Servers(); 362 return new Servers.Servers();
322 } 363 }