Winify – Blame information for rev 25

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