Winify – Blame information for rev 28

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;
4 using System.Configuration;
19 office 5 using System.Diagnostics;
4 office 6 using System.IO;
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;
11 using AutoUpdaterDotNET;
18 office 12 using Serilog;
15 office 13 using Servers;
24 office 14 using ToastNotifications;
1 office 15 using Winify.Gotify;
8 office 16 using Winify.Servers.Serialization;
25 office 17 using Winify.Settings;
15 office 18 using Winify.Utilities;
1 office 19  
20 namespace Winify
21 {
22 public partial class Form1 : Form
23 {
24 #region Private Delegates, Events, Enums, Properties, Indexers and Fields
25  
24 office 26 private readonly TaskScheduler _uiTaskScheduler;
14 office 27  
1 office 28 private AboutForm _aboutForm;
29  
25 office 30 private ConcurrentBag<GotifyConnection> _gotifyConnections;
1 office 31  
32 private SettingsForm _settingsForm;
33  
34 #endregion
35  
36 #region Constructors, Destructors and Finalizers
37  
19 office 38 public Form1(Mutex mutex)
1 office 39 {
40 InitializeComponent();
41  
18 office 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  
1 office 48 // Upgrade settings if required.
49 if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile)
25 office 50 if (Properties.Settings.Default.UpdateRequired)
19 office 51 {
25 office 52 Properties.Settings.Default.Upgrade();
53 Properties.Settings.Default.Reload();
19 office 54  
25 office 55 Properties.Settings.Default.UpdateRequired = false;
56 Properties.Settings.Default.Save();
19 office 57  
58 mutex.ReleaseMutex();
59 Process.Start(Application.ExecutablePath);
60 Environment.Exit(0);
61 }
1 office 62  
63 // Bind to settings changed event.
25 office 64 Properties.Settings.Default.SettingsLoaded += Default_SettingsLoaded;
65 Properties.Settings.Default.SettingsSaving += Default_SettingsSaving;
66 Properties.Settings.Default.PropertyChanged += Default_PropertyChanged;
1 office 67  
25 office 68 // Store UI thread context.
24 office 69 _uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
11 office 70  
14 office 71 LoadServers().ContinueWith(async task =>
4 office 72 {
14 office 73 var restoredServers = await task;
4 office 74  
25 office 75 _gotifyConnections = new ConcurrentBag<GotifyConnection>();
76  
7 office 77 foreach (var server in restoredServers.Server)
78 {
25 office 79 var gotifyConnection = new GotifyConnection(server);
80 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification;
81 gotifyConnection.Start();
82 _gotifyConnections.Add(gotifyConnection);
7 office 83 }
4 office 84 });
15 office 85  
19 office 86 // Start application update.
87 AutoUpdater.Start("http://winify.grimore.org/update/winify.xml");
1 office 88 }
89  
90 /// <summary>
91 /// Clean up any resources being used.
92 /// </summary>
93 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
94 protected override void Dispose(bool disposing)
95 {
96 if (disposing && components != null)
97 {
25 office 98 Properties.Settings.Default.SettingsLoaded -= Default_SettingsLoaded;
99 Properties.Settings.Default.SettingsSaving -= Default_SettingsSaving;
100 Properties.Settings.Default.PropertyChanged -= Default_PropertyChanged;
7 office 101  
1 office 102 components.Dispose();
103 }
104  
105 base.Dispose(disposing);
106 }
107  
108 #endregion
109  
110 #region Event Handlers
111  
25 office 112 private static void Default_PropertyChanged(object sender, PropertyChangedEventArgs e)
21 office 113 {
25 office 114 Properties.Settings.Default.Save();
21 office 115 }
116  
25 office 117 private static void Default_SettingsSaving(object sender, CancelEventArgs e)
21 office 118 {
119 }
120  
25 office 121 private static void Default_SettingsLoaded(object sender, SettingsLoadedEventArgs e)
15 office 122 {
123 }
124  
25 office 125 private async void SettingsToolStripMenuItem_Click(object sender, EventArgs e)
11 office 126 {
28 office 127 if (_settingsForm != null) return;
25 office 128  
129 var servers = await LoadServers();
130 var announcements = await LoadAnnouncements();
131  
132 _settingsForm = new SettingsForm(servers, announcements);
133 _settingsForm.Save += SettingsForm_Save;
134 _settingsForm.Closing += SettingsForm_Closing;
135 _settingsForm.Show();
136 }
137  
138 private async void SettingsForm_Save(object sender, SettingsSavedEventArgs e)
139 {
140 // Save the servers.
141 await Task.WhenAll(SaveServers(e.Servers), SaveAnnouncements(e.Announcements));
142  
143 // Update connections to gotify servers.
144 while (_gotifyConnections.TryTake(out var gotifyConnection))
145 {
146 gotifyConnection.GotifyNotification -= GotifyConnection_GotifyNotification;
147 gotifyConnection.Stop();
148 gotifyConnection.Dispose();
149 gotifyConnection = null;
150 }
151  
152 foreach (var server in e.Servers.Server)
153 {
154 var gotifyConnection = new GotifyConnection(server);
155 gotifyConnection.GotifyNotification += GotifyConnection_GotifyNotification;
156 gotifyConnection.Start();
157 _gotifyConnections.Add(gotifyConnection);
158 }
159 }
160  
161 private void GotifyConnection_GotifyNotification(object sender, GotifyNotificationEventArgs e)
162 {
163 Task.Factory.StartNew(async () =>
164 {
165 var announcements = await LoadAnnouncements();
166  
167 foreach (var announcement in announcements.Announcement)
24 office 168 if (announcement.AppId == e.Notification.AppId)
169 {
25 office 170 var configuredNotification = new Notification(
171 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})",
172 e.Notification.Message, announcement.LingerTime, e.Image,
173 FormAnimator.AnimationMethod.Slide,
24 office 174 FormAnimator.AnimationDirection.Up);
175  
176 configuredNotification.Show();
177  
178 return;
179 }
180  
25 office 181 var notification = new Notification(
182 $"{e.Notification.Title} ({e.Notification.Server.Name}/{e.Notification.AppId})",
24 office 183 e.Notification.Message, 5000, e.Image, FormAnimator.AnimationMethod.Slide,
184 FormAnimator.AnimationDirection.Up);
185  
186 notification.Show();
25 office 187 }, CancellationToken.None, TaskCreationOptions.LongRunning, _uiTaskScheduler);
11 office 188 }
189  
1 office 190 private void SettingsForm_Closing(object sender, CancelEventArgs e)
191 {
28 office 192 if (_settingsForm == null) return;
6 office 193  
25 office 194 _settingsForm.Save -= SettingsForm_Save;
1 office 195 _settingsForm.Closing -= SettingsForm_Closing;
196 _settingsForm.Dispose();
197 _settingsForm = null;
198 }
199  
200 private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
201 {
28 office 202 if (_aboutForm != null) return;
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 {
28 office 211 if (_aboutForm == null) return;
1 office 212  
213 _aboutForm.Closing -= AboutForm_Closing;
214 _aboutForm.Dispose();
215 _aboutForm = null;
216 }
217  
218 private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
219 {
17 office 220 Close();
221  
222 Environment.Exit(0);
1 office 223 }
224  
9 office 225 private void UpdateToolStripMenuItem_Click(object sender, EventArgs e)
226 {
227 AutoUpdater.Start("http://winify.grimore.org/update/winify.xml");
228 }
229  
1 office 230 #endregion
4 office 231  
232 #region Private Methods
233  
25 office 234 private static async Task SaveAnnouncements(Announcements.Announcements announcements)
21 office 235 {
25 office 236 switch (await ServersSerialization.Serialize(announcements, Constants.AnnouncementsFile, "Announcements",
28 office 237 "<!ATTLIST Announcements xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>"))
21 office 238 {
239 case SerializationFailure serializationFailure:
240 Log.Warning(serializationFailure.Exception, "Unable to serialize announcements.");
241 break;
242 }
243 }
244  
25 office 245 private static async Task SaveServers(global::Servers.Servers servers)
21 office 246 {
247 // Encrypt password for all servers.
248 var deviceId = Miscellaneous.GetMachineGuid();
249 var @protected = new global::Servers.Servers
250 {
251 Server = new BindingListWithCollectionChanged<Server>()
252 };
25 office 253 foreach (var server in servers.Server)
21 office 254 {
255 var encrypted = AES.Encrypt(Encoding.UTF8.GetBytes(server.Password), deviceId);
256 var armored = Convert.ToBase64String(encrypted);
257  
258 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, armored));
259 }
260  
261 switch (await ServersSerialization.Serialize(@protected, Constants.ServersFile, "Servers",
28 office 262 "<!ATTLIST Servers xmlns:xsi CDATA #IMPLIED xsi:noNamespaceSchemaLocation CDATA #IMPLIED>"))
21 office 263 {
264 case SerializationFailure serializationFailure:
265 Log.Warning(serializationFailure.Exception, "Unable to serialize servers.");
266 break;
267 }
268 }
269  
15 office 270 private static async Task<Announcements.Announcements> LoadAnnouncements()
271 {
272 if (!Directory.Exists(Constants.UserApplicationDirectory))
273 Directory.CreateDirectory(Constants.UserApplicationDirectory);
274  
275 var deserializationResult =
25 office 276 await ServersSerialization.Deserialize<Announcements.Announcements>(Constants.AnnouncementsFile,
15 office 277 "urn:winify-announcements-schema", "Announcements.xsd");
278  
279 switch (deserializationResult)
280 {
281 case SerializationSuccess<Announcements.Announcements> serializationSuccess:
282 return serializationSuccess.Result;
21 office 283 case SerializationFailure serializationFailure:
284 Log.Warning(serializationFailure.Exception, "Unable to load announcements.");
285 return new Announcements.Announcements();
15 office 286 default:
287 return new Announcements.Announcements();
288 }
289 }
290  
8 office 291 private static async Task<global::Servers.Servers> LoadServers()
4 office 292 {
293 if (!Directory.Exists(Constants.UserApplicationDirectory))
294 Directory.CreateDirectory(Constants.UserApplicationDirectory);
295  
15 office 296 var deserializationResult =
297 await ServersSerialization.Deserialize<global::Servers.Servers>(Constants.ServersFile,
298 "urn:winify-servers-schema", "Servers.xsd");
4 office 299  
300 switch (deserializationResult)
301 {
15 office 302 case SerializationSuccess<global::Servers.Servers> serializationSuccess:
303 // Decrypt password.
304 var deviceId = Miscellaneous.GetMachineGuid();
305 var @protected = new global::Servers.Servers
306 {
307 Server = new BindingListWithCollectionChanged<Server>()
308 };
309 foreach (var server in serializationSuccess.Result.Server)
310 {
311 var unarmored = Convert.FromBase64String(server.Password);
312 var decrypted = Encoding.UTF8.GetString(AES.Decrypt(unarmored, deviceId));
4 office 313  
15 office 314 @protected.Server.Add(new Server(server.Name, server.Url, server.Username, decrypted));
315 }
316  
317 return @protected;
318  
21 office 319 case SerializationFailure serializationFailure:
320 Log.Warning(serializationFailure.Exception, "Unable to load servers.");
321 return new global::Servers.Servers();
322  
4 office 323 default:
8 office 324 return new global::Servers.Servers();
4 office 325 }
326 }
327  
328 #endregion
1 office 329 }
330 }