Explorar o código

Added re-try connection loop and App restart; also, RPC is now turn-offable by conditional compilation variable RPC

Kenric Nugteren hai 1 ano
pai
achega
012987c093

+ 13 - 2
prs.desktop/App.xaml.cs

@@ -37,8 +37,9 @@ namespace PRSDesktop
         public static String EmployeeName = "";
         public static String EmployeeName = "";
         public static String EmployeeEmail = "";
         public static String EmployeeEmail = "";
 
 
-        public static string Profile = "";
-        public static bool IsClosing = false;
+        public static string Profile { get; set; } = "";
+        public static bool IsClosing { get; set; } = false;
+        public static bool ShouldRestart { get; set; } = false;
 
 
         /*/ Guid to ensure that only one instance of PRS is running
         /*/ Guid to ensure that only one instance of PRS is running
         public static Guid AppGuid = Guid.Parse("237E8828-7F5A-4298-B311-CF0FC27882EC");
         public static Guid AppGuid = Guid.Parse("237E8828-7F5A-4298-B311-CF0FC27882EC");
@@ -282,9 +283,19 @@ namespace PRSDesktop
             StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
             StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
         }
         }
 
 
+        private static IEnumerable<string> GetRestartArguments()
+        {
+            // Skip the first one, because that is the location.
+            return Environment.GetCommandLineArgs().Skip(1);
+        }
+
         protected override void OnExit(ExitEventArgs e)
         protected override void OnExit(ExitEventArgs e)
         {
         {
             base.OnExit(e);
             base.OnExit(e);
+            if (ShouldRestart)
+            {
+                Process.Start(Path.ChangeExtension(ResourceAssembly.Location, ".exe"), GetRestartArguments());
+            }
             //AppMutex.ReleaseMutex();
             //AppMutex.ReleaseMutex();
         }
         }
 
 

+ 32 - 0
prs.desktop/Forms/ConnectionFailed.xaml

@@ -0,0 +1,32 @@
+<Window x:Class="PRSDesktop.Forms.ConnectionFailed"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:PRSDesktop.Forms"
+        mc:Ignorable="d"
+        Title="Connection Failed" Height="172" Width="395">
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="*"/>
+            <RowDefinition Height="Auto"/>
+        </Grid.RowDefinitions>
+        <TextBlock Text="PRS was unable to connect to the database server; this may be due to the server being down right now, or the database settings (such as URL or port number) may be incorrect. Would you like to try to connect again or open the database configuration screen?"
+                   TextWrapping="Wrap" Padding="5"/>
+        <DockPanel Grid.Row="1" LastChildFill="False">
+            <Button Content="Open Database Configuration"
+                    Padding="5" Margin="5"
+                    DockPanel.Dock="Right"
+                    Name="ConfigurationButton"
+                    Click="ConfigurationButton_Click"/>
+            <Button Content="Re-try Connection"
+                    Padding="5" Margin="5,5,0,5"
+                    DockPanel.Dock="Right"
+                    Name="RetryButton"
+                    Click="RetryButton_Click"/>
+            <Button Content="Quit" Padding="5" Margin="5"
+                    Name="QuitButton"
+                    Click="QuitButton_Click"/>
+        </DockPanel>
+    </Grid>
+</Window>

+ 54 - 0
prs.desktop/Forms/ConnectionFailed.xaml.cs

@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace PRSDesktop.Forms
+{
+    public enum ConnectionFailedWindowResult
+    {
+        RetryConnection,
+        OpenDatabaseConfiguration,
+        Quit
+    }
+
+    /// <summary>
+    /// Interaction logic for ConnectionFailed.xaml
+    /// </summary>
+    public partial class ConnectionFailed : Window
+    {
+        public ConnectionFailedWindowResult Result { get; set; } = ConnectionFailedWindowResult.Quit;
+
+        public ConnectionFailed()
+        {
+            InitializeComponent();
+        }
+
+        private void ConfigurationButton_Click(object sender, RoutedEventArgs e)
+        {
+            Result = ConnectionFailedWindowResult.OpenDatabaseConfiguration;
+            Close();
+        }
+
+        private void RetryButton_Click(object sender, RoutedEventArgs e)
+        {
+            Result = ConnectionFailedWindowResult.RetryConnection;
+            Close();
+        }
+
+        private void QuitButton_Click(object sender, RoutedEventArgs e)
+        {
+            Result = ConnectionFailedWindowResult.Quit;
+            Close();
+        }
+    }
+}

+ 155 - 54
prs.desktop/MainWindow.xaml.cs

@@ -155,6 +155,7 @@ namespace PRSDesktop
             HotKeyManager.RegisterHotKey(Key.F4, ToggleRecordingAudio);
             HotKeyManager.RegisterHotKey(Key.F4, ToggleRecordingAudio);
 
 
             var settings = App.DatabaseSettings;
             var settings = App.DatabaseSettings;
+            bool dbConnected;
             DatabaseType = settings.DatabaseType;
             DatabaseType = settings.DatabaseType;
             switch (DatabaseType)
             switch (DatabaseType)
             {
             {
@@ -162,32 +163,58 @@ namespace PRSDesktop
                     ClientFactory.SetClientType(typeof(LocalClient<>), Platform.Wpf, CoreUtils.GetVersion());
                     ClientFactory.SetClientType(typeof(LocalClient<>), Platform.Wpf, CoreUtils.GetVersion());
                     DbFactory.ColorScheme = App.DatabaseSettings.ColorScheme;
                     DbFactory.ColorScheme = App.DatabaseSettings.ColorScheme;
                     DbFactory.Logo = App.DatabaseSettings.Logo;
                     DbFactory.Logo = App.DatabaseSettings.Logo;
+                    dbConnected = true;
                     break;
                     break;
                 
                 
-                case DatabaseType.Networked:                    
+                case DatabaseType.Networked:
+#if RPC
                     //new RPC stuff (temporary disabled - for enabling when RPC is ready)
                     //new RPC stuff (temporary disabled - for enabling when RPC is ready)
-                    /*_transport = new RpcClientSocketTransport(App.DatabaseSettings.URLs);
+                    _transport = new RpcClientSocketTransport(App.DatabaseSettings.URLs);
                     _transport.OnClose += TransportConnectionLost;
                     _transport.OnClose += TransportConnectionLost;
-                    _transport.Connect();
-                    ClientFactory.SetClientType(typeof(RpcClient<>), Platform.Wpf, CoreUtils.GetVersion(), _transport );*/
-
+                    dbConnected = _transport.Connect();
+                    ClientFactory.SetClientType(typeof(RpcClient<>), Platform.Wpf, CoreUtils.GetVersion(), _transport );
+#else
                     var url = RestClient<User>.Ping(App.DatabaseSettings.URLs, out DatabaseInfo info);
                     var url = RestClient<User>.Ping(App.DatabaseSettings.URLs, out DatabaseInfo info);
                     ClientFactory.SetClientType(typeof(RestClient<>), Platform.Wpf, CoreUtils.GetVersion(), url, true);
                     ClientFactory.SetClientType(typeof(RestClient<>), Platform.Wpf, CoreUtils.GetVersion(), url, true);
+                    dbConnected = true;
+#endif
                     break;
                     break;
                 
                 
                 case DatabaseType.Local:
                 case DatabaseType.Local:
+#if RPC
                     //new RPC stuff (temporary disabled - for enabling when RPC is ready)
                     //new RPC stuff (temporary disabled - for enabling when RPC is ready)
-                    //var pipename = DatabaseServerProperties.GetPipeName(App.DatabaseSettings.LocalServerName);
-                    //_transport = new RpcClientPipeTransport(pipename);
-                    //_transport.OnClose += TransportConnectionLost;
-                    //_transport.Connect();
-                    //ClientFactory.SetClientType(typeof(RpcClient<>), Platform.Wpf, CoreUtils.GetVersion(),
-                    //    _transport );
+                    var pipename = DatabaseServerProperties.GetPipeName(App.DatabaseSettings.LocalServerName, true);
+                    _transport = new RpcClientPipeTransport(pipename);
+                    _transport.OnClose += TransportConnectionLost;
+                    dbConnected = _transport.Connect();
+                    ClientFactory.SetClientType(typeof(RpcClient<>), Platform.Wpf, CoreUtils.GetVersion(), _transport );
+#else
+                    ClientFactory.SetClientType(typeof(IPCClient<>), Platform.Wpf, CoreUtils.GetVersion(),
+                        DatabaseServerProperties.GetPipeName(App.DatabaseSettings.LocalServerName, false));
+                    dbConnected = true;
+#endif
+                    break;
+                default:
+                    throw new Exception($"Invalid database type {DatabaseType}");
+            }
 
 
+            InitializeComponent();
 
 
-                    ClientFactory.SetClientType(typeof(IPCClient<>), Platform.Wpf, CoreUtils.GetVersion(), 
-                           DatabaseServerProperties.GetPipeName(App.DatabaseSettings.LocalServerName,false));
-                    break;
+            if (!dbConnected)
+            {
+                switch (DoConnectionFailed())
+                {
+                    case ConnectionFailedResult.Quit:
+                        Close();
+                        return;
+                    case ConnectionFailedResult.Restart:
+                        App.ShouldRestart = true;
+                        Close();
+                        return;
+                    case ConnectionFailedResult.Ok:
+                        // Do nothing
+                        break;
+                }
             }
             }
 
 
             ThemeManager.BaseColor = Colors.CornflowerBlue;
             ThemeManager.BaseColor = Colors.CornflowerBlue;
@@ -206,8 +233,6 @@ namespace PRSDesktop
             {
             {
             }
             }
 
 
-            InitializeComponent();
-
             VideoRecordingStatus.Source = PRSDesktop.Resources.videorecording.AsGrayScale().AsBitmapImage();
             VideoRecordingStatus.Source = PRSDesktop.Resources.videorecording.AsGrayScale().AsBitmapImage();
             AudioRecordingStatus.Source = PRSDesktop.Resources.audiorecording.AsGrayScale().AsBitmapImage();
             AudioRecordingStatus.Source = PRSDesktop.Resources.audiorecording.AsGrayScale().AsBitmapImage();
             SecondaryWindowStatus.Source = PRSDesktop.Resources.target.AsGrayScale().AsBitmapImage();
             SecondaryWindowStatus.Source = PRSDesktop.Resources.target.AsGrayScale().AsBitmapImage();
@@ -217,7 +242,6 @@ namespace PRSDesktop
             CheckForUpdates();
             CheckForUpdates();
 
 
             Exception? startupException = null;
             Exception? startupException = null;
-            //Exception? loginException = null;
             ValidationStatus? loginStatus = null;
             ValidationStatus? loginStatus = null;
 
 
             Progress.ShowModal("Loading PRS", progress =>
             Progress.ShowModal("Loading PRS", progress =>
@@ -277,45 +301,10 @@ namespace PRSDesktop
                         );
                         );
                     }
                     }
                 }
                 }
-
-                /*if (startupException == null && App.DatabaseSettings.Autologin)
-                {
-                    progress.Report("Logging in...");
-                    if (App.DatabaseSettings.LoginType == LoginType.UserID)
-                    {
-                        ValidationResult? result;
-                        try
-                        {
-                            result = ClientFactory.Validate(App.DatabaseSettings.UserID, App.DatabaseSettings.Password);
-                        }
-                        catch(Exception e)
-                        {
-                            Logger.Send(LogType.Error, ClientFactory.UserID, $"Error connecting to server: {CoreUtils.FormatException(e)}");
-                            loginException = new Exception("Error connecting to server.\nPlease check the server URL and port number.");
-                            result = null;
-                        }
-                        loginStatus = result;
-                        if (result == ValidationResult.INVALID)
-                        {
-                            loginException = new Exception("Unable to Login with User ID: " + App.DatabaseSettings.UserID);
-                        }
-                    }
-                    if(loginStatus == ValidationResult.VALID)
-                    {
-                        LoadCurrentEmployee();
-                        if(!CheckTimesheetBypass(false))
-                        {
-                            loginException = new Exception("You must clock on before logging in to PRS!");
-                            loginStatus = null;
-                        }
-                    }
-                }*/
             });
             });
 
 
             if (startupException != null)
             if (startupException != null)
                 MessageBox.Show(startupException.Message);
                 MessageBox.Show(startupException.Message);
-            //else if (loginException != null)
-            //    MessageBox.Show(loginException.Message);
 
 
             if (DoLogin(App.DatabaseSettings.Autologin) == ValidationStatus.VALID)
             if (DoLogin(App.DatabaseSettings.Autologin) == ValidationStatus.VALID)
             {
             {
@@ -341,6 +330,89 @@ namespace PRSDesktop
             });
             });
         }
         }
 
 
+        /// <summary>
+        /// Reconnect to the server.
+        /// </summary>
+        /// <returns><see langword="true"/> if connection was successful.</returns>
+        private bool Reconnect()
+        {
+            if(_transport != null)
+            {
+                return _transport.Connect();
+            }
+            Logger.Send(LogType.Error, ClientFactory.UserID, "Trying to reconnect without a transport set.");
+            return true; // Returning true so we don't get stuck in infinite loops in exceptional circumstances.
+        }
+
+        private enum ConnectionFailedResult
+        {
+            Quit,
+            Restart,
+            Ok
+        }
+
+        /// <summary>
+        /// To be called when initial connection to the server has failed; asks the user if they want to retry,
+        /// change the database settings, or simply quit PRS.
+        /// </summary>
+        /// <returns>The action to take next.</returns>
+        /// <exception cref="Exception"></exception>
+        private ConnectionFailedResult DoConnectionFailed()
+        {
+            bool connected = false;
+            while (!connected)
+            {
+                var connectionFailedWindow = new ConnectionFailed();
+                connectionFailedWindow.ShowDialog();
+
+                var reconnect = false;
+                switch (connectionFailedWindow.Result)
+                {
+                    case ConnectionFailedWindowResult.OpenDatabaseConfiguration:
+                        var result = ShowDatabaseConfiguration();
+                        switch (result)
+                        {
+                            case DatabaseConfigurationResult.RestartRequired:
+                                var shouldRestart = MessageBox.Show(
+                                    "A restart is required to apply these changes. Do you wish to restart now?",
+                                    "Restart?",
+                                    MessageBoxButton.YesNo);
+                                if (shouldRestart == MessageBoxResult.Yes)
+                                {
+                                    return ConnectionFailedResult.Restart;
+                                }
+                                else
+                                {
+                                    reconnect = true;
+                                }
+                                break;
+                            case DatabaseConfigurationResult.RestartNotRequired:
+                                reconnect = true;
+                                break;
+                            case DatabaseConfigurationResult.Cancel:
+                                reconnect = true;
+                                break;
+                            default:
+                                throw new Exception($"Invalid enum result {result}");
+                        }
+                        break;
+                    case ConnectionFailedWindowResult.RetryConnection:
+                        reconnect = true;
+                        break;
+                    case ConnectionFailedWindowResult.Quit:
+                        return ConnectionFailedResult.Quit;
+                    default:
+                        throw new Exception($"Invalid enum result {connectionFailedWindow.Result}");
+                }
+                if (!reconnect)
+                {
+                    return ConnectionFailedResult.Quit;
+                }
+                connected = Reconnect();
+            }
+            return ConnectionFailedResult.Ok;
+        }
+
         private void TransportConnectionLost(IRpcTransport transport, RpcTransportCloseArgs e)
         private void TransportConnectionLost(IRpcTransport transport, RpcTransportCloseArgs e)
         {
         {
             if ((transport is IRpcClientTransport client))
             if ((transport is IRpcClientTransport client))
@@ -4036,20 +4108,49 @@ namespace PRSDesktop
 
 
         #region Backstage Functions
         #region Backstage Functions
 
 
-        private void DatabaseSettings_OnClick(object sender, RoutedEventArgs e)
+        private enum DatabaseConfigurationResult
         {
         {
+            RestartRequired,
+            RestartNotRequired,
+            Cancel
+        }
+        
+        private DatabaseConfigurationResult ShowDatabaseConfiguration()
+        {
+            DatabaseConfigurationResult result;
             var config = new DataBaseConfiguration();
             var config = new DataBaseConfiguration();
             if (config.ShowDialog() == true)
             if (config.ShowDialog() == true)
             {
             {
                 var newsettings = new LocalConfiguration<DatabaseSettings>(App.Profile).Load();
                 var newsettings = new LocalConfiguration<DatabaseSettings>(App.Profile).Load();
                 if (newsettings.RestartRequired(App.DatabaseSettings))
                 if (newsettings.RestartRequired(App.DatabaseSettings))
-                    MessageBox.Show("Please restart the application to apply these changes!");
+                {
+                    result = DatabaseConfigurationResult.RestartRequired;
+                }
+                else
+                {
+                    result = DatabaseConfigurationResult.RestartNotRequired;
+                }
                 if ((newsettings.DatabaseType == DatabaseType.Standalone) && (newsettings.ColorScheme != App.DatabaseSettings.ColorScheme))
                 if ((newsettings.DatabaseType == DatabaseType.Standalone) && (newsettings.ColorScheme != App.DatabaseSettings.ColorScheme))
                 {
                 {
                     App.DatabaseSettings.ColorScheme = newsettings.ColorScheme;
                     App.DatabaseSettings.ColorScheme = newsettings.ColorScheme;
                     ApplyColorScheme();
                     ApplyColorScheme();
                 }
                 }
             }
             }
+            else
+            {
+                result = DatabaseConfigurationResult.Cancel;
+            }
+            return result;
+        }
+
+        private void DatabaseSettings_OnClick(object sender, RoutedEventArgs e)
+        {
+            switch (ShowDatabaseConfiguration())
+            {
+                case DatabaseConfigurationResult.RestartRequired:
+                    MessageBox.Show("Please restart the application to apply these changes!");
+                    break;
+            }
         }
         }
 
 
         private void CompanyInformation_OnClick(object sender, RoutedEventArgs e)
         private void CompanyInformation_OnClick(object sender, RoutedEventArgs e)