Korero – Rev 1

Subversion Repositories:
Rev:
using System;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Korero.Chat;
using Korero.Communication;
using Korero.Database;
using Korero.Economy;
using Korero.Friendship;
using Korero.Heartbeat;
using Korero.Inventory;
using Korero.Land;
using Korero.Notifications;
using Korero.Properties;
using Korero.Teleport;
using Korero.Utilities;
using NetSparkleUpdater.Enums;
using NetSparkleUpdater.Interfaces;
using NetSparkleUpdater.SignatureVerifiers;
using NetSparkleUpdater;
using NetSparkleUpdater.UI.WinForms;
using Serilog;
using System.Reflection;

namespace Korero
{
    public partial class MainForm : Form
    {
        #region Public Enums, Properties and Fields

        public ChatForm ChatForm { get; set; }

        public MessageDatabase MessageDatabase { get; set; }

        public MqttCommunication MqttCommunication { get; set; }

        #endregion

        #region Private Delegates, Events, Enums, Properties, Indexers and Fields

        private readonly Task _autoAwayTask;

        private readonly CancellationTokenSource _cancellationTokenSource;

        private readonly Task _mqttCommunicationTask;

        private readonly NotificationManager _notificationManager;

        private AboutForm _aboutForm;

        private EconomyForm _economyForm;

        private FriendshipForm _friendsForm;

        private HeartbeatForm _heartbeatForm;

        private InventoryForm _inventoryForm;

        private LandForm _mapForm;

        private SettingsForm _settingsForm;

        private TeleportForm _teleportForm;
        private readonly SparkleUpdater _sparkle;

        #endregion

        #region Constructors, Destructors and Finalizers

        public MainForm(Mutex mutex)
        {
            InitializeComponent();

            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.File(Path.Combine(Constants.UserApplicationDirectory, "Logs", $"{Constants.AssemblyName}.log"),
                    rollingInterval: RollingInterval.Day)
                .CreateLogger();

            // Upgrade settings if required.
            if (!ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).HasFile)
            {
                if (Settings.Default.UpdateRequired)
                {
                    Settings.Default.Upgrade();
                    Settings.Default.Reload();

                    Settings.Default.UpdateRequired = false;
                    Settings.Default.Save();

                    mutex.ReleaseMutex();
                    Process.Start(Application.ExecutablePath);
                    Environment.Exit(0);
                }
            }

            // Bind to settings changed event.
            Settings.Default.SettingsLoaded += Default_SettingsLoaded;
            Settings.Default.SettingsSaving += Default_SettingsSaving;
            Settings.Default.PropertyChanged += Default_PropertyChanged;

            _cancellationTokenSource = new CancellationTokenSource();

            _notificationManager = new NotificationManager(TaskScheduler.FromCurrentSynchronizationContext());

            MqttCommunication = new MqttCommunication();
            MqttCommunication.NotificationReceived += MqttCommunication_NotificationReceived;
            MqttCommunication.Connected += MqttCommunication_Connected;
            MqttCommunication.Disconnected += MqttCommunication_Disconnected;

            MessageDatabase = new MessageDatabase();
            _mqttCommunicationTask = MqttCommunication.Start();

            _autoAwayTask = AutoAway(_cancellationTokenSource.Token);

            // Start application update.
            var manifestModuleName = Assembly.GetEntryAssembly().ManifestModule.FullyQualifiedName;
            var icon = Icon.ExtractAssociatedIcon(manifestModuleName);

            _sparkle = new SparkleUpdater("https://korero.grimore.org/update/appcast.xml",
                new Ed25519Checker(SecurityMode.Strict, "LonrgxVjSF0GnY4hzwlRJnLkaxnDn2ikdmOifILzLJY="))
            {
                UIFactory = new UIFactory(icon),
                RelaunchAfterUpdate = true,
                SecurityProtocolType = SecurityProtocolType.Tls12
            };
            _sparkle.StartLoop(true, true);
        }

        #endregion

        #region Event Handlers

        private void MqttCommunication_Disconnected(object sender, MqttDisconnectedEventArgs e)
        {
            _notificationManager.ShowNotification("Korero: Connection", "Disconnected from the MQTT broker.",
                Settings.Default.ToasterTimeout);
        }

        private void MqttCommunication_Connected(object sender, MqttConnectedEventArgs e)
        {
            _notificationManager.ShowNotification("Korero: Connection",
                "Connection to the MQTT broker succeeded.",
                Settings.Default.ToasterTimeout);
        }

        private async void MqttCommunication_NotificationReceived(object sender, MqttNotificationEventArgs e)
        {
            // Add message to database.
            switch (e.Notification["notification"])
            {
                case "group":
                    var databaseGroupMessage = new DatabaseMessageGroup(e.Notification["firstname"],
                        e.Notification["lastname"], e.Notification["message"], e.Notification["group"], DateTime.Now);
                    await MessageDatabase.SaveGroupMessage(databaseGroupMessage);
                    await MessageDatabase.MarkConversationSeen($"{databaseGroupMessage.Group}", false);

                    _notificationManager.ShowNotification("Korero: Group Message",
                        $"{e.Notification["firstname"]} {e.Notification["lastname"]} says {e.Notification["message"]}",
                        Resources.comm,
                        Settings.Default.ToasterTimeout, ShowChatForm);

                    break;
                case "message":
                    var databaseMessage = new DatabaseMessage(e.Notification["firstname"], e.Notification["lastname"],
                        e.Notification["message"], DateTime.Now);
                    await MessageDatabase.SaveMessage(databaseMessage);
                    await MessageDatabase.MarkConversationSeen(
                        $"{databaseMessage.FirstName} {databaseMessage.LastName}", false);

                    _notificationManager.ShowNotification("Korero: Instant Message",
                        $"{e.Notification["firstname"]} {e.Notification["lastname"]} says {e.Notification["message"]}",
                        Resources.comm,
                        Settings.Default.ToasterTimeout, ShowChatForm);
                    break;
            }

            switch (e.Notification["notification"])
            {
                case "balance":
                    _notificationManager.ShowNotification("Korero: Balance Update",
                        $"The current balance has changed and is now: {e.Notification["balance"]}", Resources.money,
                        Settings.Default.ToasterTimeout);
                    break;
            }
        }

        private static void Default_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            Settings.Default.Save();
        }

        private static void Default_SettingsSaving(object sender, CancelEventArgs e)
        {
        }

        private static void Default_SettingsLoaded(object sender, SettingsLoadedEventArgs e)
        {
        }

        private void QuitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();

            Environment.Exit(0);
        }

        private void AboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_aboutForm != null)
            {
                return;
            }

            _aboutForm = new AboutForm();
            _aboutForm.Closing += AboutForm_Closing;
            _aboutForm.Show();
        }

        private void AboutForm_Closing(object sender, CancelEventArgs e)
        {
            if (_aboutForm == null)
            {
                return;
            }

            _aboutForm.Closing -= AboutForm_Closing;
            _aboutForm.Dispose();
            _aboutForm = null;
        }

        private void SettingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_settingsForm != null)
            {
                return;
            }

            _settingsForm = new SettingsForm(MqttCommunication);
            _settingsForm.Closing += SettingsForm_Closing;
            _settingsForm.Show();
        }

        private void SettingsForm_Closing(object sender, CancelEventArgs e)
        {
            if (_settingsForm == null)
            {
                return;
            }

            _settingsForm.Closing -= SettingsForm_Closing;
            _settingsForm.Dispose();
            _settingsForm = null;
        }

        private void ChatForm_Closing(object sender, CancelEventArgs e)
        {
            if (ChatForm == null)
            {
                return;
            }

            ChatForm.Closing -= ChatForm_Closing;
            ChatForm.Dispose();
            ChatForm = null;
        }

        private void ChatToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowChatForm();
        }

        private void MapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_mapForm != null)
            {
                return;
            }

            _mapForm = new LandForm(this, MqttCommunication);
            _mapForm.Closing += MapForm_Closing;
            _mapForm.Show();
        }

        private void MapForm_Closing(object sender, CancelEventArgs e)
        {
            if (_mapForm == null)
            {
                return;
            }

            _mapForm.Closing -= MapForm_Closing;
            _mapForm.Dispose();
            _mapForm = null;
        }

        private void TeleportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_teleportForm != null)
            {
                return;
            }

            _teleportForm = new TeleportForm(this, MqttCommunication);
            _teleportForm.Closing += TeleportForm_Closing;
            _teleportForm.Show();
        }

        private void TeleportForm_Closing(object sender, CancelEventArgs e)
        {
            if (_teleportForm == null)
            {
                return;
            }

            _teleportForm.Closing -= TeleportForm_Closing;
            _teleportForm.Dispose();
            _teleportForm = null;
        }

        private void FriendsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_friendsForm != null)
            {
                return;
            }

            _friendsForm = new FriendshipForm(this, MqttCommunication);
            _friendsForm.Closing += FriendsForm_Closing;
            _friendsForm.Show();
        }

        private void FriendsForm_Closing(object sender, CancelEventArgs e)
        {
            if (_friendsForm == null)
            {
                return;
            }

            _friendsForm.Closing -= FriendsForm_Closing;
            _friendsForm.Dispose();
            _friendsForm = null;
        }

        private void EconomyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_economyForm != null)
            {
                return;
            }

            _economyForm = new EconomyForm(this, MqttCommunication);
            _economyForm.Closing += EconomyForm_Closing;
            _economyForm.Show();
        }

        private void EconomyForm_Closing(object sender, CancelEventArgs e)
        {
            if (_economyForm == null)
            {
                return;
            }

            _economyForm.Closing -= EconomyForm_Closing;
            _economyForm.Dispose();
            _economyForm = null;
        }

        private void InventoryToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_inventoryForm != null)
            {
                return;
            }

            _inventoryForm = new InventoryForm(this, MqttCommunication);
            _inventoryForm.Closing += InventoryForm_Closing;
            _inventoryForm.Show();
        }

        private void InventoryForm_Closing(object sender, CancelEventArgs e)
        {
            if (_inventoryForm == null)
            {
                return;
            }

            _inventoryForm.Closing -= InventoryForm_Closing;
            _inventoryForm.Dispose();
            _inventoryForm = null;
        }

        private async void UpdateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Manually check for updates, this will not show a ui
            var result = await _sparkle.CheckForUpdatesQuietly();
            var updates = result.Updates;
            if (result.Status == UpdateStatus.UpdateAvailable)
            {
                // if update(s) are found, then we have to trigger the UI to show it gracefully
                _sparkle.ShowUpdateNeededUI();
                return;
            }

            MessageBox.Show("No updates available at this time.", "Korero", MessageBoxButtons.OK,
                MessageBoxIcon.Asterisk,
                MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly, false);
        }

        private void HeartbeatToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (_heartbeatForm != null)
            {
                return;
            }

            _heartbeatForm = new HeartbeatForm(this, MqttCommunication);
            _heartbeatForm.Closing += HeartbeatForm_Closing;
            _heartbeatForm.Show();
        }

        private void HeartbeatForm_Closing(object sender, CancelEventArgs e)
        {
            if (_heartbeatForm == null)
            {
                return;
            }

            _heartbeatForm.Closing -= HeartbeatForm_Closing;
            _heartbeatForm.Dispose();
            _heartbeatForm = null;
        }

        #endregion

        #region Public Methods

        public async Task AutoAway(CancellationToken cancellationToken)
        {
            try
            {
                do
                {
                    await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);

                    if (!Settings.Default.AutoAwayEnabled)
                    {
                        continue;
                    }

                    if (Miscellaneous.GetIdleTime() < TimeSpan.FromMinutes((int) Settings.Default.AutoAwayMinutes))
                    {
                        continue;
                    }

                    Settings.Default.CurrentStatus = Resources.Away;
                } while (cancellationToken.IsCancellationRequested);
            }
            catch (Exception ex) when (ex is ObjectDisposedException || ex is OperationCanceledException)
            {
            }
            catch (Exception ex)
            {
                Log.Warning(ex, "Error while setting auto-away.");
            }
        }

        #endregion

        #region Private Methods

        private void ShowChatForm()
        {
            if (ChatForm != null)
            {
                return;
            }

            ChatForm = new ChatForm(this, MqttCommunication);
            ChatForm.Closing += ChatForm_Closing;
            ChatForm.Show();
        }

        #endregion
    }
}

Generated by GNU Enscript 1.6.5.90.