Prechádzať zdrojové kódy

Moved Console class to InABox.Wpf

Kenric Nugteren 1 rok pred
rodič
commit
75c3e2efd5

+ 0 - 113
prs.desktop/Forms/Console.xaml

@@ -1,113 +0,0 @@
-<wpf:ThemableWindow x:Class="PRSDesktop.Console"
-        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"
-		xmlns:wpf="clr-namespace:InABox.Wpf;assembly=InABox.Wpf"
-        mc:Ignorable="d"
-        Title="Console" Height="450" Width="800" Loaded="Window_Loaded" Closing="Window_Closing">
-    <Window.Resources>
-
-        <Style TargetType="ItemsControl" x:Key="LogViewerStyle">
-
-            <Setter Property="Template">
-                <Setter.Value>
-                    <ControlTemplate>
-                        <ScrollViewer CanContentScroll="True">
-                            <ItemsPresenter />
-                        </ScrollViewer>
-                    </ControlTemplate>
-                </Setter.Value>
-            </Setter>
-
-            <Setter Property="ItemsPanel">
-                <Setter.Value>
-                    <ItemsPanelTemplate>
-                        <VirtualizingStackPanel IsItemsHost="True" />
-                    </ItemsPanelTemplate>
-                </Setter.Value>
-            </Setter>
-        </Style>
-
-        <DataTemplate DataType="{x:Type local:LogEntry}">
-            <Grid IsSharedSizeScope="True">
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition SharedSizeGroup="Date" Width="120" />
-                    <ColumnDefinition SharedSizeGroup="Type" Width="60" />
-                    <ColumnDefinition SharedSizeGroup="User" Width="120" />
-                    <ColumnDefinition />
-                </Grid.ColumnDefinitions>
-
-                <TextBlock Text="{Binding DateTime}" Grid.Column="0" FontFamily="Courier New"
-                           Margin="5,0,5,0" />
-
-                <TextBlock Text="{Binding Type}" Grid.Column="1" FontFamily="Courier New"
-                           Margin="5,0,5,0" />
-
-                <TextBlock Text="{Binding User}" Grid.Column="2" FontFamily="Courier New"
-                           Margin="0,0,2,0" />
-
-                <TextBlock Text="{Binding Message}" Grid.Column="3" FontFamily="Courier New"
-                           TextWrapping="Wrap" />
-            </Grid>
-        </DataTemplate>
-
-        <DataTemplate DataType="{x:Type local:CollapsibleLogEntry}">
-            <Grid IsSharedSizeScope="True">
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition SharedSizeGroup="Date" Width="120" />
-                    <ColumnDefinition SharedSizeGroup="Type" Width="60" />
-                    <ColumnDefinition SharedSizeGroup="User" Width="120" />
-                    <ColumnDefinition />
-                </Grid.ColumnDefinitions>
-
-                <Grid.RowDefinitions>
-                    <RowDefinition Height="Auto" />
-                    <RowDefinition />
-                </Grid.RowDefinitions>
-
-                <TextBlock Text="{Binding DateTime}" Grid.Column="0" FontFamily="Courier New"
-                           Margin="5,0,5,0" />
-
-                <TextBlock Text="{Binding Type}" Grid.Column="1" FontFamily="Courier New"
-                           Margin="5,0,5,0" />
-
-                <TextBlock Text="{Binding User}" Grid.Column="2" FontFamily="Courier New"
-                           Margin="0,0,2,0" />
-
-                <TextBlock Text="{Binding Message}" Grid.Column="3" FontFamily="Courier New"
-                           TextWrapping="Wrap" />
-
-                <ToggleButton x:Name="Expander" Grid.Row="1" Grid.Column="0"
-                              VerticalAlignment="Top" Content="+" HorizontalAlignment="Right" />
-
-                <ItemsControl ItemsSource="{Binding Contents}" Style="{StaticResource LogViewerStyle}"
-                              Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"
-                              x:Name="Contents" Visibility="Collapsed" />
-
-            </Grid>
-            <DataTemplate.Triggers>
-                <Trigger SourceName="Expander" Property="IsChecked" Value="True">
-                    <Setter TargetName="Contents" Property="Visibility" Value="Visible" />
-                    <Setter TargetName="Expander" Property="Content" Value="-" />
-                </Trigger>
-            </DataTemplate.Triggers>
-        </DataTemplate>
-
-    </Window.Resources>
-    <Grid>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="*" />
-        </Grid.RowDefinitions>
-        <DockPanel Grid.Row="0" Margin="5,5,5,0">
-            <Label Content="Search" VerticalContentAlignment="Center" />
-            <TextBox x:Name="Search" Margin="5,0,0,0" DockPanel.Dock="Left" Background="LightYellow"
-                     VerticalContentAlignment="Center" TextChanged="Search_TextChanged" />
-        </DockPanel>
-        <Border BorderBrush="Gray" Grid.Row="1" BorderThickness="0.75" Margin="5" Padding="2" Background="LightYellow">
-            <ItemsControl x:Name="Log" ItemsSource="{Binding}" Style="{StaticResource LogViewerStyle}" />
-        </Border>
-    </Grid>
-</wpf:ThemableWindow>

+ 0 - 156
prs.desktop/Forms/Console.xaml.cs

@@ -1,156 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using H.Pipes;
-using InABox.Logging;
-using InABox.Wpf;
-
-namespace PRSDesktop
-{
-    public class PropertyChangedBase : INotifyPropertyChanged
-    {
-        public event PropertyChangedEventHandler? PropertyChanged;
-
-        protected virtual void OnPropertyChanged(string propertyName)
-        {
-            Application.Current.Dispatcher.BeginInvoke((Action)(() =>
-            {
-                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
-            }));
-        }
-    }
-
-    public class LogEntry : PropertyChangedBase
-    {
-        public string DateTime { get; set; } = "";
-
-        public string Type { get; set; } = "";
-
-        public string User { get; set; } = "";
-
-        public string Message { get; set; } = "";
-    }
-
-    public class CollapsibleLogEntry : LogEntry
-    {
-        public List<LogEntry> Contents { get; set; }
-    }
-
-    public static class ItemsControlExtensions
-    {
-        public static void ScrollIntoView(
-            this ItemsControl control,
-            object item)
-        {
-            var framework =
-                control.ItemContainerGenerator.ContainerFromItem(item)
-                    as FrameworkElement;
-            if (framework == null) return;
-            framework.BringIntoView();
-        }
-
-        public static void ScrollIntoView(this ItemsControl control)
-        {
-            var count = control.Items.Count;
-            if (count == 0) return;
-            var item = control.Items[count - 1];
-            control.ScrollIntoView(item);
-        }
-    }
-
-    /// <summary>
-    ///     Interaction logic for Console.xaml
-    /// </summary>
-    public partial class Console : ThemableWindow
-    {
-        //private PipeClient<string> _client;
-        public CollectionViewSource _filtered;
-
-        private readonly ObservableCollection<LogEntry> _logentries;
-
-        private EventLogger logger;
-
-        public Console()
-        {
-            InitializeComponent();
-
-            _logentries = new ObservableCollection<LogEntry>();
-            _filtered = new CollectionViewSource();
-            _filtered.Source = _logentries;
-            _filtered.Filter += (sender, args) =>
-            {
-                args.Accepted = string.IsNullOrWhiteSpace(Search.Text)
-                                || ((LogEntry)args.Item).DateTime.Contains(Search.Text)
-                                || ((LogEntry)args.Item).Type.Contains(Search.Text)
-                                || ((LogEntry)args.Item).User.Contains(Search.Text)
-                                || ((LogEntry)args.Item).Message.Contains(Search.Text);
-            };
-            DataContext = _filtered;
-        }
-
-        private void Window_Loaded(object sender, RoutedEventArgs e)
-        {
-            /*_client = new PipeClient<string>("PRSDesktop");
-            _client.Connected += _client_Connected;
-            _client.ExceptionOccurred += _client_ExceptionOccurred;
-            _client.MessageReceived += (o, args) =>
-            {
-                var m = args.Message;
-                var datetime = m.Length > 32 ? m.Substring(0, 12) : string.Format("{0:HH:mm:ss.fff}", DateTime.Now);
-                var type = m.Length > 32 ? m.Substring(13, 6) : "INFO";
-                var user = m.Length > 32 ? m.Substring(20, 12) : "";
-                var msg = m.Length > 32 ? m.Substring(33) : m;
-
-                if (string.Equals(type?.Trim(), "INFO") || string.Equals(type?.Trim(), "ERROR"))
-                {
-                    var logentry = new LogEntry
-                    {
-                        DateTime = datetime,
-                        Type = type,
-                        User = user,
-                        Message = msg
-                    };
-                    Dispatcher.BeginInvoke((Action)(() => { _logentries.Insert(0, logentry); }));
-                }
-            };
-            _client.ConnectAsync();*/
-            logger = new EventLogger(OnLog);
-            MainLogger.AddLogger(logger);
-        }
-
-        private void OnLog(string message)
-        {
-            var datetime = message.Length > 32 ? message.Substring(0, 12) : string.Format("{0:HH:mm:ss.fff}", DateTime.Now);
-            var type = message.Length > 32 ? message.Substring(13, 6) : "INFO";
-            var user = message.Length > 32 ? message.Substring(20, 12) : "";
-            var msg = message.Length > 32 ? message.Substring(33) : message;
-
-            if (string.Equals(type.Trim(), "INFO") || string.Equals(type.Trim(), "ERROR"))
-            {
-                var logentry = new LogEntry
-                {
-                    DateTime = datetime,
-                    Type = type,
-                    User = user,
-                    Message = msg
-                };
-                Dispatcher.BeginInvoke(() => _logentries.Insert(0, logentry));
-            }
-        }
-
-        private void Window_Closing(object sender, CancelEventArgs e)
-        {
-            //_client.DisconnectAsync();
-            MainLogger.RemoveLogger(logger);
-        }
-
-        private void Search_TextChanged(object sender, TextChangedEventArgs e)
-        {
-            _filtered.View.Refresh();
-        }
-    }
-}

+ 50 - 0
prs.desktop/Forms/DesktopConsole.cs

@@ -0,0 +1,50 @@
+using InABox.Core;
+using InABox.Logging;
+using InABox.Wpf.Console;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Console = InABox.Wpf.Console.Console;
+
+namespace PRSDesktop;
+
+public class DesktopConsole : Console
+{
+    private EventLogger? logger;
+
+    public DesktopConsole(string description): base(description)
+    {
+    }
+
+    protected override void OnLoaded()
+    {
+        base.OnLoaded();
+
+        logger = new EventLogger(OnLog);
+        MainLogger.AddLogger(logger);
+    }
+
+    private void OnLog(string message)
+    {
+        Dispatcher.BeginInvoke(() =>
+        {
+            ConsoleControl.LoadLogEntry(message);
+        });
+    }
+
+    protected override void OnClosing()
+    {
+        base.OnClosing();
+        if(logger is not null)
+        {
+            MainLogger.RemoveLogger(logger);
+        }
+    }
+
+    protected override string GetLogDirectory()
+    {
+        return CoreUtils.GetPath();
+    }
+}

+ 3 - 2
prs.desktop/MainWindow.xaml.cs

@@ -34,6 +34,7 @@ using InABox.Core.Reports;
 using InABox.IPC;
 using InABox.Rpc;
 using InABox.Scripting;
+using InABox.Wpf.Console;
 using InABox.WPF;
 using NAudio.Wave;
 using PRS.Shared;
@@ -83,7 +84,7 @@ namespace PRSDesktop
         private MemoryStream? _audioStream;
         private readonly Dictionary<DateTime, Stream> _bitmaps = new();
 
-        private Console? _console;
+        private DesktopConsole? _console;
         private Dictionary<DateTime, Tuple<Rectangle, string>> _notes = new();
 
 
@@ -2340,7 +2341,7 @@ namespace PRSDesktop
         {
             if (_console is null)
             {
-                _console = new Console();
+                _console = new DesktopConsole("Console");
                 _console.Closing += (o, args) => _console = null;
             }
 

+ 1 - 1
prs.server/App.xaml.cs

@@ -83,7 +83,7 @@ namespace PRSServer
                 }
                 else if (args[1].StartsWith("/service="))
                 {
-                    var c = new Console(args[1].Split('=').Last(), args[1].Split('=').Last(), false);
+                    var c = new ServerConsole(args[1].Split('=').Last(), args[1].Split('=').Last(), false);
                     c.ShowDialog();
                     Shutdown(0);
                 }

+ 0 - 9
prs.server/Forms/Console/CollapsibleLogEntry.cs

@@ -1,9 +0,0 @@
-using System.Collections.Generic;
-
-namespace PRSServer
-{
-    public class CollapsibleLogEntry : LogEntry
-    {
-        public List<LogEntry> Contents { get; set; }
-    }
-}

+ 0 - 144
prs.server/Forms/Console/Console.xaml

@@ -1,144 +0,0 @@
-<wpf:ThemableWindow x:Class="PRSServer.Console"
-        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:PRSServer"
-		xmlns:wpf="clr-namespace:InABox.Wpf;assembly=InABox.Wpf"
-        mc:Ignorable="d"
-        Title="Console" Height="800" Width="1200" Closing="Window_Closing" Loaded="Console_Loaded">
-    <Window.Resources>
-
-        <Style TargetType="ItemsControl" x:Key="LogViewerStyle">
-
-            <Setter Property="Template">
-                <Setter.Value>
-                    <ControlTemplate>
-                        <ScrollViewer CanContentScroll="True">
-                            <ItemsPresenter />
-                        </ScrollViewer>
-                    </ControlTemplate>
-                </Setter.Value>
-            </Setter>
-
-            <Setter Property="ItemsPanel">
-                <Setter.Value>
-                    <ItemsPanelTemplate>
-                        <VirtualizingStackPanel IsItemsHost="True" />
-                    </ItemsPanelTemplate>
-                </Setter.Value>
-            </Setter>
-        </Style>
-
-        <DataTemplate DataType="{x:Type local:LogEntry}">
-            <Grid IsSharedSizeScope="True">
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition SharedSizeGroup="Date" Width="120" />
-                    <ColumnDefinition SharedSizeGroup="Type" Width="60" />
-                    <ColumnDefinition SharedSizeGroup="User" Width="120" />
-                    <ColumnDefinition />
-                </Grid.ColumnDefinitions>
-
-                <TextBlock Text="{Binding DateTime}" Grid.Column="0" FontFamily="Courier New"
-                           Margin="5,0,5,0" />
-
-                <TextBlock Text="{Binding Type}" Grid.Column="1" FontFamily="Courier New"
-                           Margin="5,0,5,0" />
-
-                <TextBlock Text="{Binding User}" Grid.Column="2" FontFamily="Courier New"
-                           Margin="0,0,2,0" />
-
-                <TextBlock Text="{Binding Message}" Grid.Column="3" FontFamily="Courier New"
-                           TextWrapping="Wrap" />
-            </Grid>
-        </DataTemplate>
-
-        <DataTemplate DataType="{x:Type local:CollapsibleLogEntry}">
-            <Grid IsSharedSizeScope="True">
-                <Grid.ColumnDefinitions>
-                    <ColumnDefinition SharedSizeGroup="Date" Width="120" />
-                    <ColumnDefinition SharedSizeGroup="Type" Width="60" />
-                    <ColumnDefinition SharedSizeGroup="User" Width="120" />
-                    <ColumnDefinition />
-                </Grid.ColumnDefinitions>
-
-                <Grid.RowDefinitions>
-                    <RowDefinition Height="Auto" />
-                    <RowDefinition />
-                </Grid.RowDefinitions>
-
-                <TextBlock Text="{Binding DateTime}" Grid.Column="0" FontFamily="Courier New"
-                           Margin="5,0,5,0" />
-
-                <TextBlock Text="{Binding Type}" Grid.Column="1" FontFamily="Courier New"
-                           Margin="5,0,5,0" />
-
-                <TextBlock Text="{Binding User}" Grid.Column="2" FontFamily="Courier New"
-                           Margin="0,0,2,0" />
-
-                <TextBlock Text="{Binding Message}" Grid.Column="3" FontFamily="Courier New"
-                           TextWrapping="Wrap" />
-
-                <ToggleButton x:Name="Expander" Grid.Row="1" Grid.Column="0"
-                              VerticalAlignment="Top" Content="+" HorizontalAlignment="Right" />
-
-                <ItemsControl ItemsSource="{Binding Contents}" Style="{StaticResource LogViewerStyle}"
-                              Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"
-                              x:Name="Contents" Visibility="Collapsed" />
-
-            </Grid>
-            <DataTemplate.Triggers>
-                <Trigger SourceName="Expander" Property="IsChecked" Value="True">
-                    <Setter TargetName="Contents" Property="Visibility" Value="Visible" />
-                    <Setter TargetName="Expander" Property="Content" Value="-" />
-                </Trigger>
-            </DataTemplate.Triggers>
-        </DataTemplate>
-
-    </Window.Resources>
-    <Grid>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto" />
-            <RowDefinition Height="*" />
-            <RowDefinition Height="Auto" />
-        </Grid.RowDefinitions>
-        <Grid>
-            <Grid.RowDefinitions>
-                <RowDefinition Height="Auto" />
-            </Grid.RowDefinitions>
-            <Grid.ColumnDefinitions>
-                <ColumnDefinition Width="Auto" />
-                <ColumnDefinition />
-                <ColumnDefinition Width="Auto" />
-                <ColumnDefinition Width="Auto" />
-                <ColumnDefinition Width="Auto" />
-            </Grid.ColumnDefinitions>
-            <Label Content="Search" VerticalContentAlignment="Center" HorizontalAlignment="Left" />
-            <TextBox x:Name="Search" Margin="5,0,0,0" DockPanel.Dock="Right" Background="LightYellow"
-                     VerticalContentAlignment="Center" PreviewKeyDown="Search_KeyDown" TextChanged="Search_TextChanged"
-                     HorizontalAlignment="Stretch" Grid.Column="1" />
-            <CheckBox x:Name="UseRegEx" Content="Use Regular Expressions" HorizontalAlignment="Right"
-                      VerticalAlignment="Center" Visibility="Visible" Margin="5,0,5,0" Grid.Column="2"
-                      Checked="UseRegEx_Checked" Unchecked="UseRegEx_Unchecked" />
-            <CheckBox x:Name="ShowImportant" Content="Show only Important" HorizontalAlignment="Right"
-                      VerticalAlignment="Center" Visibility="Visible" Margin="5,0,5,0" Grid.Column="3"
-                      Checked="ShowImportant_Checked" Unchecked="ShowImportant_Unchecked"/>
-            <Button x:Name="LoadLog" Grid.Column="4" Content="Load Log File" Padding="4,1,4,1" Margin="5,5,5,5"
-                    Click="LoadLog_Click" />
-            <Button x:Name="CloseLog" Grid.Column="4" Content="Close Log File" Padding="4,1,4,1" Margin="5,5,5,5"
-                    Click="CloseLog_Click" Visibility="Collapsed" />
-        </Grid>
-        <Border x:Name="LogBorder" BorderBrush="Gray" Grid.Row="1" BorderThickness="0.75" Margin="5" Padding="2" Background="WhiteSmoke">
-            <ItemsControl x:Name="Log" ItemsSource="{Binding}" Style="{StaticResource LogViewerStyle}">
-                <ItemsControl.Template>
-                    <ControlTemplate>
-                        <ScrollViewer CanContentScroll="True">
-                            <ItemsPresenter />
-                        </ScrollViewer>
-                    </ControlTemplate>
-                </ItemsControl.Template>
-            </ItemsControl>
-        </Border>
-        <Label x:Name="Error" Content="" Grid.Row="2" HorizontalAlignment="Right" Visibility="Collapsed" />
-    </Grid>
-</wpf:ThemableWindow>

+ 0 - 341
prs.server/Forms/Console/Console.xaml.cs

@@ -1,341 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.IO;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using System.Timers;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Threading;
-using H.Pipes;
-using InABox.Logging;
-using InABox.Wpf;
-using Microsoft.Win32;
-
-namespace PRSServer
-{
-    public static class ItemsControlExtensions
-    {
-        public static void ScrollIntoView(
-            this ItemsControl control,
-            object item)
-        {
-            var framework =
-                control.ItemContainerGenerator.ContainerFromItem(item)
-                    as FrameworkElement;
-            if (framework == null) return;
-            framework.BringIntoView();
-        }
-
-        public static void ScrollIntoView(this ItemsControl control)
-        {
-            var count = control.Items.Count;
-            if (count == 0) return;
-            var item = control.Items[count - 1];
-            control.ScrollIntoView(item);
-        }
-    }
-
-    /// <summary>
-    ///     Interaction logic for Console.xaml
-    /// </summary>
-    public partial class Console : ThemableWindow
-    {
-        private PipeClient<string> _client;
-        public CollectionViewSource _filtered;
-
-        private readonly ObservableCollection<LogEntry> _logentries;
-
-        private readonly bool _monitoronly = true;
-
-        private PRSService _service;
-        public string ServiceName { get; private set; }
-
-        private readonly string description;
-        private readonly TimeSpan regexTimeOut = TimeSpan.FromMilliseconds(100);
-
-        private Timer? RefreshTimer;
-
-        private Regex? searchRegex;
-
-        public Console(string servicename, string description, bool monitoronly = true)
-        {
-            ServiceName = servicename;
-            _monitoronly = monitoronly;
-
-            InitializeComponent();
-
-            _logentries = new ObservableCollection<LogEntry>();
-            _filtered = new CollectionViewSource();
-            _filtered.Source = _logentries;
-            _filtered.Filter += (sender, args) =>
-            {
-                var logEntry = (LogEntry)args.Item;
-                if (ShowImportant.IsChecked == true && !IsImportant(logEntry))
-                {
-                    args.Accepted = false;
-                    return;
-                }
-
-                if (UseRegEx.IsChecked == true && searchRegex != null)
-                    args.Accepted = string.IsNullOrWhiteSpace(Search.Text)
-                                    || searchRegex.IsMatch(logEntry.DateTime)
-                                    || searchRegex.IsMatch(logEntry.Type)
-                                    || searchRegex.IsMatch(logEntry.User)
-                                    || searchRegex.IsMatch(logEntry.Message);
-                else
-                    args.Accepted = string.IsNullOrWhiteSpace(Search.Text)
-                                    || logEntry.DateTime.Contains(Search.Text)
-                                    || logEntry.Type.Contains(Search.Text)
-                                    || logEntry.User.Contains(Search.Text)
-                                    || logEntry.Message.Contains(Search.Text);
-            };
-            DataContext = _filtered;
-
-
-            Title = description;
-            this.description = description;
-        }
-
-        private bool IsImportant(LogEntry entry)
-        {
-            return entry.Type == "IMPTNT";
-        }
-
-        private LogEntry ParseLogMessage(string logLine)
-        {
-            var datetime = logLine.Length > 32 ? logLine.Substring(0, 12) : string.Format("{0:HH:mm:ss.fff}", DateTime.Now);
-            var type = logLine.Length > 32 ? logLine.Substring(13, 6).Trim() : "INFO";
-            var user = logLine.Length > 32 ? logLine.Substring(20, 12) : "";
-            var msg = logLine.Length > 32 ? logLine.Substring(33) : logLine;
-
-            return new LogEntry
-            {
-                DateTime = datetime,
-                Type = type,
-                User = user,
-                Message = msg
-            };
-        }
-
-        private void Console_Loaded(object sender, RoutedEventArgs e)
-        {
-            _client = new PipeClient<string>(ServiceName, ".");
-            _client.MessageReceived += (o, args) =>
-            {
-                var m = args.Message;
-
-                var logEntry = ParseLogMessage(args.Message ?? "");
-                var logType = logEntry.Type;
-                if (logType == "INFO" || logType == "ERROR" || logType == "IMPTNT")
-                    Dispatcher.BeginInvoke((Action)(() => { _logentries.Insert(0, logEntry); }));
-            };
-            _client.Connected += (o, args) =>
-            {
-                Dispatcher.Invoke(() => LogBorder.Background = new SolidColorBrush(Colors.LightYellow));
-            };
-            _client.Disconnected += (o, args) =>
-            {
-                Dispatcher.Invoke(() => LogBorder.Background = new SolidColorBrush(Colors.WhiteSmoke));
-
-                if (RefreshTimer == null)
-                {
-                    RefreshTimer = new Timer(1000);
-                    RefreshTimer.Elapsed += RefreshTimer_Elapsed;
-                }
-                RefreshTimer.Start();
-            };
-            _client.ExceptionOccurred += (o, args) =>
-            {
-                
-            };
-            if (!_client.IsConnecting)
-            {
-                _client.ConnectAsync();
-            }
-
-            if (!_monitoronly)
-            {
-                var timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 3) };
-                timer.Tick += (o, args) =>
-                {
-                    timer.IsEnabled = false;
-                    _service = new PRSService(ServiceName, null);
-                    _service.Run(ServiceName);
-                };
-                timer.IsEnabled = true;
-            }
-        }
-
-        private void RefreshTimer_Elapsed(object? sender, ElapsedEventArgs e)
-        {
-            if(!_client.IsConnected)
-            {
-                if (!_client.IsConnecting)
-                {
-                    _client.ConnectAsync();
-                }
-            }
-            else
-            {
-                RefreshTimer?.Stop();
-            }
-        }
-
-        private void Window_Closing(object sender, CancelEventArgs e)
-        {
-            if (_monitoronly)
-            {
-                _client.DisposeAsync().AsTask().Wait();
-                RefreshTimer?.Stop();
-            }
-            else
-                _service?.Halt();
-        }
-
-        private void Search_KeyDown(object sender, KeyEventArgs e)
-        {
-            if (e.Key == Key.Enter && UseRegEx.IsChecked == true)
-            {
-                try
-                {
-                    searchRegex = new Regex(Search.Text, RegexOptions.Compiled, regexTimeOut);
-                }
-                catch (ArgumentException)
-                {
-                    searchRegex = null;
-                }
-
-                _filtered.View.Refresh();
-                SetSearchStyleNormal();
-            }
-        }
-
-        private void SetSearchStyleChanged()
-        {
-            Search.Background = Brushes.White;
-        }
-
-        private void SetSearchStyleNormal()
-        {
-            Search.Background = Brushes.LightYellow;
-        }
-
-        private void Search_TextChanged(object sender, TextChangedEventArgs e)
-        {
-            if (UseRegEx.IsChecked != true)
-            {
-                _filtered.View.Refresh();
-            }
-            else
-            {
-                if (string.IsNullOrWhiteSpace(Search.Text))
-                {
-                    searchRegex = null;
-                    _filtered.View.Refresh();
-                    SetSearchStyleNormal();
-                }
-                else
-                {
-                    SetSearchStyleChanged();
-                }
-            }
-        }
-
-        private void UseRegEx_Checked(object sender, RoutedEventArgs e)
-        {
-            try
-            {
-                searchRegex = new Regex(Search.Text, RegexOptions.Compiled, regexTimeOut);
-            }
-            catch (ArgumentException ex)
-            {
-                searchRegex = null;
-            }
-
-            _filtered.View.Refresh();
-        }
-
-        private void UseRegEx_Unchecked(object sender, RoutedEventArgs e)
-        {
-            searchRegex = null;
-            _filtered.View.Refresh();
-
-            SetSearchStyleNormal();
-        }
-
-        private void SetErrorMessage(string? error)
-        {
-            if (string.IsNullOrWhiteSpace(error))
-            {
-                Error.Content = "";
-                Error.Visibility = Visibility.Collapsed;
-            }
-            else
-            {
-                Error.Content = error;
-                Error.Visibility = Visibility.Visible;
-            }
-        }
-
-        private void LoadLog_Click(object sender, RoutedEventArgs e)
-        {
-            var dialog = new OpenFileDialog();
-            dialog.InitialDirectory = DatabaseEngine.GetPath(ServiceName);
-            if (dialog.ShowDialog() == true)
-            {
-                var logEntries = new List<LogEntry>();
-
-                var numberSkipped = 0;
-
-                var lines = File.ReadLines(dialog.FileName);
-                foreach (var line in lines)
-                {
-                    var logEntry = ParseLogMessage(line ?? "");
-                    var logType = logEntry.Type;
-                    if (logType == "ERROR" || logType == "INFO" || logType == "IMPTNT")
-                        logEntries.Add(logEntry);
-                    else if (string.IsNullOrWhiteSpace(logType)) numberSkipped++;
-                }
-
-                if (numberSkipped > 0)
-                {
-                    if (logEntries.Count == 0)
-                        SetErrorMessage("File does not contain valid log information!");
-                    else
-                        SetErrorMessage(string.Format("Skipped {0} lines that did not contain valid log information", numberSkipped));
-                }
-
-                Title = dialog.FileName;
-
-                _filtered.Source = logEntries;
-                LoadLog.Visibility = Visibility.Collapsed;
-                CloseLog.Visibility = Visibility.Visible;
-            }
-        }
-
-        private void CloseLog_Click(object sender, RoutedEventArgs e)
-        {
-            _filtered.Source = _logentries;
-            CloseLog.Visibility = Visibility.Collapsed;
-            LoadLog.Visibility = Visibility.Visible;
-
-            Title = description;
-        }
-
-        private void ShowImportant_Checked(object sender, RoutedEventArgs e)
-        {
-            _filtered.View.Refresh();
-        }
-
-        private void ShowImportant_Unchecked(object sender, RoutedEventArgs e)
-        {
-            _filtered.View.Refresh();
-        }
-    }
-}

+ 0 - 13
prs.server/Forms/Console/LogEntry.cs

@@ -1,13 +0,0 @@
-namespace PRSServer
-{
-    public class LogEntry : PropertyChangedBase
-    {
-        public string DateTime { get; set; }
-
-        public string Type { get; set; }
-
-        public string User { get; set; }
-
-        public string Message { get; set; }
-    }
-}

+ 0 - 21
prs.server/Forms/Console/PropertyChangedBase.cs

@@ -1,21 +0,0 @@
-using System;
-using System.ComponentModel;
-using System.Windows;
-
-namespace PRSServer
-{
-    public class PropertyChangedBase : INotifyPropertyChanged
-    {
-        public event PropertyChangedEventHandler PropertyChanged;
-
-        protected virtual void OnPropertyChanged(string propertyName)
-        {
-            Application.Current.Dispatcher.BeginInvoke((Action)(() =>
-            {
-                var handler = PropertyChanged;
-                if (handler != null)
-                    handler(this, new PropertyChangedEventArgs(propertyName));
-            }));
-        }
-    }
-}

+ 117 - 0
prs.server/Forms/Console/ServerConsole.cs

@@ -0,0 +1,117 @@
+using H.Pipes;
+using InABox.Wpf.Console;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Timers;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Threading;
+using Console = InABox.Wpf.Console.Console;
+
+namespace PRSServer;
+
+public class ServerConsole : Console
+{
+    private PipeClient<string>? _client;
+
+    private PRSService? _service;
+
+    private readonly bool _monitoronly = true;
+
+    public string ServiceName { get; private set; }
+
+    private Timer? RefreshTimer;
+
+    public ServerConsole(string servicename, string description, bool monitoronly = true): base(description)
+    {
+        ServiceName = servicename;
+        _monitoronly = monitoronly;
+    }
+
+    protected override void OnLoaded()
+    {
+        base.OnLoaded();
+
+        _client = new PipeClient<string>(ServiceName, ".");
+        _client.MessageReceived += (o, args) =>
+        {
+            Dispatcher.BeginInvoke(() =>
+            {
+                ConsoleControl.LoadLogEntry(args.Message ?? "");
+            });
+        };
+        _client.Connected += (o, args) =>
+        {
+            ConsoleControl.Enabled = true;
+        };
+        _client.Disconnected += (o, args) =>
+        {
+            ConsoleControl.Enabled = false;
+
+            if (RefreshTimer == null)
+            {
+                RefreshTimer = new Timer(1000);
+                RefreshTimer.Elapsed += RefreshTimer_Elapsed;
+            }
+            RefreshTimer.Start();
+        };
+        _client.ExceptionOccurred += (o, args) =>
+        {
+
+        };
+        if (!_client.IsConnecting)
+        {
+            _client.ConnectAsync();
+        }
+
+        if (!_monitoronly)
+        {
+            var timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 3) };
+            timer.Tick += (o, args) =>
+            {
+                timer.IsEnabled = false;
+                _service = new PRSService(ServiceName, null);
+                _service.Run(ServiceName);
+            };
+            timer.IsEnabled = true;
+        }
+    }
+
+    private void RefreshTimer_Elapsed(object? sender, ElapsedEventArgs e)
+    {
+        if (_client is null) return;
+
+        if (!_client.IsConnected)
+        {
+            if (!_client.IsConnecting)
+            {
+                _client.ConnectAsync();
+            }
+        }
+        else
+        {
+            RefreshTimer?.Stop();
+        }
+    }
+
+    protected override void OnClosing()
+    {
+        base.OnClosing();
+
+        if (_monitoronly)
+        {
+            _client?.DisposeAsync().AsTask().Wait();
+            RefreshTimer?.Stop();
+        }
+        else
+            _service?.Halt();
+    }
+
+    protected override string GetLogDirectory()
+    {
+        return DatabaseEngine.GetPath(ServiceName);
+    }
+}

+ 1044 - 1043
prs.server/Forms/ServerGrid.cs

@@ -24,1272 +24,1273 @@ using InABox.DynamicGrid;
 using InABox.IPC;
 using InABox.Rpc;
 using InABox.Wpf.Editors;
+using InABox.Wpf.Console;
 using InABox.WPF;
 using PRSClasses;
 using PRSServer.Forms;
 using PRSServer.Forms.DatabaseLicense;
 using RestSharp;
 using Method = RestSharp.Method;
+using Console = InABox.Wpf.Console.Console;
 
-namespace PRSServer
+namespace PRSServer;
+
+class ServerStartupSettings : BaseObject, ILocalConfigurationSettings
 {
-    class ServerStartupSettings : BaseObject, ILocalConfigurationSettings
-    {
-        public List<string> StartServers { get; set; } = new();
-    }
+    public List<string> StartServers { get; set; } = new();
+}
 
-    public class ServerGrid : DynamicGrid<Server>
-    {
-        private Task? _monitor;
+public class ServerGrid : DynamicGrid<Server>
+{
+    private Task? _monitor;
+
+    private ConcurrentBag<ServiceController> _services = new();
+    
+    private Button _channelButton;
+
+    private Button _statusButton;
+
+    private CancellationTokenSource cancel = new CancellationTokenSource();
 
-        private ConcurrentBag<ServiceController> _services = new();
+    public ServerGrid()
+    {
+        ActionColumns.Add(new DynamicImageColumn(TypeImage) 
+            { Position = DynamicActionColumnPosition.Start, ToolTip = TypeToolTip });
+        
+        ActionColumns.Add(new DynamicImageColumn(SecureImage)
+            {  Position = DynamicActionColumnPosition.Start, ToolTip = SecureToolTip });
         
-        private Button _channelButton;
+        ActionColumns.Add(new DynamicImageColumn(StateImage, StateAction)
+            { Position = DynamicActionColumnPosition.End, ToolTip = StateToolTip });
 
-        private Button _statusButton;
+        ActionColumns.Add(new DynamicMenuColumn(CreateServerMenu,ServerMenuStatus)
+            { Position = DynamicActionColumnPosition.End, ToolTip = MenuToolTip });
+        
+        RowHeight = 40;
+        FontSize = 14;
 
-        private CancellationTokenSource cancel = new CancellationTokenSource();
+        _channelButton = AddButton("", Properties.Resources.autoupdate.AsBitmapImage(), "Change Update Channel", EditUpdateChannel_Click);
+        _statusButton = AddButton("", Properties.Resources.secure.AsBitmapImage(), "Check Service Status", ShowServiceStatus);
 
-        public ServerGrid()
-        {
-            ActionColumns.Add(new DynamicImageColumn(TypeImage) 
-                { Position = DynamicActionColumnPosition.Start, ToolTip = TypeToolTip });
-            
-            ActionColumns.Add(new DynamicImageColumn(SecureImage)
-                {  Position = DynamicActionColumnPosition.Start, ToolTip = SecureToolTip });
-            
-            ActionColumns.Add(new DynamicImageColumn(StateImage, StateAction)
-                { Position = DynamicActionColumnPosition.End, ToolTip = StateToolTip });
-
-            ActionColumns.Add(new DynamicMenuColumn(CreateServerMenu,ServerMenuStatus)
-                { Position = DynamicActionColumnPosition.End, ToolTip = MenuToolTip });
-            
-            RowHeight = 40;
-            FontSize = 14;
-
-            _channelButton = AddButton("", Properties.Resources.autoupdate.AsBitmapImage(), "Change Update Channel", EditUpdateChannel_Click);
-            _statusButton = AddButton("", Properties.Resources.secure.AsBitmapImage(), "Check Service Status", ShowServiceStatus);
+    }
 
-        }
+    protected override void Init()
+    {
+    }
+    protected override void DoReconfigure(FluentList<DynamicGridOption> options)
+    {
+        options.AddRange(DynamicGridOption.AddRows, DynamicGridOption.EditRows, DynamicGridOption.DeleteRows, DynamicGridOption.ShowHelp);
+    }
 
-        protected override void Init()
-        {
-        }
-        protected override void DoReconfigure(FluentList<DynamicGridOption> options)
+    private BitmapImage secureImage = Properties.Resources.secure.AsBitmapImage();
+    private BitmapImage insecureImage = Properties.Resources.insecure.AsBitmapImage();
+    private BitmapImage? SecureImage(CoreRow? row)
+    {
+        if(row is null)
         {
-            options.AddRange(DynamicGridOption.AddRows, DynamicGridOption.EditRows, DynamicGridOption.DeleteRows, DynamicGridOption.ShowHelp);
+            return secureImage;
         }
-
-        private BitmapImage secureImage = Properties.Resources.secure.AsBitmapImage();
-        private BitmapImage insecureImage = Properties.Resources.insecure.AsBitmapImage();
-        private BitmapImage? SecureImage(CoreRow? row)
+        else
         {
-            if(row is null)
+            var key = row.Get<Server, string>(x => x.Key);
+            if(_secureConnections.TryGetValue(key, out var secure))
             {
-                return secureImage;
+                return secure
+                    ? secureImage
+                    : insecureImage;
             }
             else
             {
-                var key = row.Get<Server, string>(x => x.Key);
-                if(_secureConnections.TryGetValue(key, out var secure))
-                {
-                    return secure
-                        ? secureImage
-                        : insecureImage;
-                }
-                else
-                {
-                    return null;
-                }
+                return null;
             }
         }
+    }
 
-        private FrameworkElement? SecureToolTip(DynamicActionColumn column, CoreRow? row)
+    private FrameworkElement? SecureToolTip(DynamicActionColumn column, CoreRow? row)
+    {
+        if(row is null)
+        {
+            return column.TextToolTip("Connection Security");
+        }
+        else
         {
-            if(row is null)
+            var key = row.Get<Server, string>(x => x.Key);
+            if (_secureConnections.TryGetValue(key, out var secure))
             {
-                return column.TextToolTip("Connection Security");
+                return secure
+                    ? column.TextToolTip("Secure (HTTPS) Connection")
+                    : column.TextToolTip("Insecure (HTTP) Connection");
             }
             else
             {
-                var key = row.Get<Server, string>(x => x.Key);
-                if (_secureConnections.TryGetValue(key, out var secure))
-                {
-                    return secure
-                        ? column.TextToolTip("Secure (HTTPS) Connection")
-                        : column.TextToolTip("Insecure (HTTP) Connection");
-                }
-                else
-                {
-                    return null;
-                }
+                return null;
             }
         }
+    }
 
-        private DynamicMenuStatus ServerMenuStatus(CoreRow arg)
+    private DynamicMenuStatus ServerMenuStatus(CoreRow arg)
+    {
+        if (arg == null)
+            return DynamicMenuStatus.Hidden;
+        var type = arg.Get<Server, ServerType>(x => x.Type);
+        var service = GetService(arg.Get<Server, string>(c => c.Key));
+        var running = service?.Status == ServiceControllerStatus.Running;
+        if ((type == ServerType.Database) || (type == ServerType.Web) || (type == ServerType.Schedule))
         {
-            if (arg == null)
-                return DynamicMenuStatus.Hidden;
-            var type = arg.Get<Server, ServerType>(x => x.Type);
-            var service = GetService(arg.Get<Server, string>(c => c.Key));
-            var running = service?.Status == ServiceControllerStatus.Running;
-            if ((type == ServerType.Database) || (type == ServerType.Web) || (type == ServerType.Schedule))
-            {
-                return running
-                    ? DynamicMenuStatus.Enabled
-                    : DynamicMenuStatus.Disabled;
-            }
             return running
                 ? DynamicMenuStatus.Enabled
-                : DynamicMenuStatus.Hidden;
+                : DynamicMenuStatus.Disabled;
         }
+        return running
+            ? DynamicMenuStatus.Enabled
+            : DynamicMenuStatus.Hidden;
+    }
 
-        private void CreateServerMenu(DynamicMenuColumn column, CoreRow? row)
+    private void CreateServerMenu(DynamicMenuColumn column, CoreRow? row)
+    {
+        if (row == null)
+            return;
+        var status = ServerMenuStatus(row);
+        if (status == DynamicMenuStatus.Hidden)
+            return;
+        var type = row.Get<Server, ServerType>(x => x.Type);
+        var key = row.Get<Server, String>(x => x.Key);
+
+        column.AddItem(
+            "View Console",
+            Properties.Resources.target,
+            (row) => StartConsole(row, key),
+            null,
+            status == DynamicMenuStatus.Enabled && !_consoles.ContainsKey(key)
+        );
+
+        if (type.Equals(ServerType.Database))
         {
-            if (row == null)
-                return;
-            var status = ServerMenuStatus(row);
-            if (status == DynamicMenuStatus.Hidden)
-                return;
-            var type = row.Get<Server, ServerType>(x => x.Type);
-            var key = row.Get<Server, String>(x => x.Key);
-
+            column.AddSeparator();
             column.AddItem(
-                "View Console",
-                Properties.Resources.target,
-                (row) => StartConsole(row, key),
-                null,
-                status == DynamicMenuStatus.Enabled && !_consoles.ContainsKey(key)
+                "Custom Fields",
+                Properties.Resources.service,
+                (row) => EditCustomFields(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
+            );
+            column.AddItem(
+                "Database Scripts", 
+                Properties.Resources.script, 
+                (row) => EditDatabaseScripts(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
+            );
+            column.AddSeparator();
+            column.AddItem(
+                "Update License", 
+                Properties.Resources.key,
+                (row) => UpdateDatabaseLicense(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
+            );
+            column.AddSeparator();
+            column.AddItem(
+                "Manage Deletions", 
+                Properties.Resources.delete,
+                (row) => ManageDeletions(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
             );
-
-            if (type.Equals(ServerType.Database))
-            {
-                column.AddSeparator();
-                column.AddItem(
-                    "Custom Fields",
-                    Properties.Resources.service,
-                    (row) => EditCustomFields(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-                column.AddItem(
-                    "Database Scripts", 
-                    Properties.Resources.script, 
-                    (row) => EditDatabaseScripts(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-                column.AddSeparator();
-                column.AddItem(
-                    "Update License", 
-                    Properties.Resources.key,
-                    (row) => UpdateDatabaseLicense(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-                column.AddSeparator();
-                column.AddItem(
-                    "Manage Deletions", 
-                    Properties.Resources.delete,
-                    (row) => ManageDeletions(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-            }
-            else if (type.Equals(ServerType.Web))
-            {
-                column.AddSeparator();
-                column.AddItem(
-                    "Edit Templates", 
-                    Properties.Resources.script,
-                    (row) => EditWebTemplates(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-                column.AddItem(
-                    "Edit Styles", 
-                    Properties.Resources.css,
-                    (row) => EditWebStyles(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-                column.AddItem(
-                    "Edit Documents", 
-                    Properties.Resources.pdf,
-                    (row) => EditWebDocuments(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-                column.AddSeparator();
-                column.AddItem(
-                    "PRS Mobile Settings",
-                    Properties.Resources.web,
-                    (row) => PRSMobileSettings(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-            }
-            else if (type.Equals(ServerType.Schedule))
-            {
-                column.AddSeparator();
-                column.AddItem(
-                    "Scheduled Scripts", 
-                    Properties.Resources.script,
-                    (row) => EditScheduledScripts(row), 
-                    null, 
-                    status == DynamicMenuStatus.Enabled
-                );
-            }
-
-
         }
-
-        private ServiceController? GetService(string key)
+        else if (type.Equals(ServerType.Web))
         {
-            return _services.FirstOrDefault(x => string.Equals(x.ServiceName, key));
+            column.AddSeparator();
+            column.AddItem(
+                "Edit Templates", 
+                Properties.Resources.script,
+                (row) => EditWebTemplates(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
+            );
+            column.AddItem(
+                "Edit Styles", 
+                Properties.Resources.css,
+                (row) => EditWebStyles(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
+            );
+            column.AddItem(
+                "Edit Documents", 
+                Properties.Resources.pdf,
+                (row) => EditWebDocuments(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
+            );
+            column.AddSeparator();
+            column.AddItem(
+                "PRS Mobile Settings",
+                Properties.Resources.web,
+                (row) => PRSMobileSettings(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
+            );
         }
-
-        protected override void ShowHelp(string slug)
+        else if (type.Equals(ServerType.Schedule))
         {
-            base.ShowHelp("Server_Configuration");
+            column.AddSeparator();
+            column.AddItem(
+                "Scheduled Scripts", 
+                Properties.Resources.script,
+                (row) => EditScheduledScripts(row), 
+                null, 
+                status == DynamicMenuStatus.Enabled
+            );
         }
 
-        public void BeforeUpdate()
-        {
-            var sections = PRSService.GetConfiguration().LoadAll();
-            RefreshServices(sections);
 
-            var closed = new List<string>();
-            foreach (var service in _services)
-            {
-                if(service.Status == ServiceControllerStatus.Running)
-                {
-                    service.Stop();
-                    closed.Add(service.ServiceName);
-                }
-            }
+    }
 
-            var config = PRSService.GetConfiguration<ServerStartupSettings>();
-            var startupSettings = config.Load();
-            startupSettings.StartServers = closed;
-            config.Save(startupSettings);
-        }
+    private ServiceController? GetService(string key)
+    {
+        return _services.FirstOrDefault(x => string.Equals(x.ServiceName, key));
+    }
+
+    protected override void ShowHelp(string slug)
+    {
+        base.ShowHelp("Server_Configuration");
+    }
 
-        #region Grid Handling
+    public void BeforeUpdate()
+    {
+        var sections = PRSService.GetConfiguration().LoadAll();
+        RefreshServices(sections);
 
-        private void RefreshServices(Dictionary<string, ServerSettings> sections)
+        var closed = new List<string>();
+        foreach (var service in _services)
         {
-            Interlocked.Exchange(
-                ref _services,
-                new ConcurrentBag<ServiceController>(
-                    ServiceController.GetServices().Where(x => sections.ContainsKey(x.ServiceName))
-                )
-            );
+            if(service.Status == ServiceControllerStatus.Running)
+            {
+                service.Stop();
+                closed.Add(service.ServiceName);
+            }
         }
 
-        private Dictionary<String, ServiceControllerStatus> _serviceStatuses = new Dictionary<string, ServiceControllerStatus>();
-        private Dictionary<string, bool> _secureConnections = new Dictionary<string, bool>();
-        private Dictionary<String,RpcClientPipeTransport> _pipemonitors = new Dictionary<string, RpcClientPipeTransport>();
-        private Dictionary<String,HttpClient> _webmonitors = new Dictionary<string, HttpClient>();
+        var config = PRSService.GetConfiguration<ServerStartupSettings>();
+        var startupSettings = config.Load();
+        startupSettings.StartServers = closed;
+        config.Save(startupSettings);
+    }
 
-        protected override void Reload(Filters<Server> criteria, Columns<Server> columns, ref SortOrder<Server>? sort,
-            Action<CoreTable?, Exception?> action)
-        {
+    #region Grid Handling
 
-            var table = new CoreTable();
-            table.LoadColumns(typeof(Server));
+    private void RefreshServices(Dictionary<string, ServerSettings> sections)
+    {
+        Interlocked.Exchange(
+            ref _services,
+            new ConcurrentBag<ServiceController>(
+                ServiceController.GetServices().Where(x => sections.ContainsKey(x.ServiceName))
+            )
+        );
+    }
 
-            var sections = PRSService.GetConfiguration().LoadAll();
+    private Dictionary<String, ServiceControllerStatus> _serviceStatuses = new Dictionary<string, ServiceControllerStatus>();
+    private Dictionary<string, bool> _secureConnections = new Dictionary<string, bool>();
+    private Dictionary<String,RpcClientPipeTransport> _pipemonitors = new Dictionary<string, RpcClientPipeTransport>();
+    private Dictionary<String,HttpClient> _webmonitors = new Dictionary<string, HttpClient>();
 
-            RefreshServices(sections);
+    protected override void Reload(Filters<Server> criteria, Columns<Server> columns, ref SortOrder<Server>? sort,
+        Action<CoreTable?, Exception?> action)
+    {
 
-            var startupConfig = PRSService.GetConfiguration<ServerStartupSettings>();
-            var startupSettings = startupConfig.Load();
-            foreach (var startup in startupSettings.StartServers)
-            {
-                _services.FirstOrDefault(x => x.ServiceName == startup)?.Start();
-            }
-            startupSettings.StartServers.Clear();
-            startupConfig.Save(startupSettings);
+        var table = new CoreTable();
+        table.LoadColumns(typeof(Server));
 
-            foreach (var section in sections.OrderBy(x => x.Value.Type))
-            {
-                var server = section.Value.CreateServer(section.Key);
-                var service = _services.FirstOrDefault(x => string.Equals(x.ServiceName, section.Key));
-                var row = table.NewRow();
-                table.LoadRow(row, server);
-                table.Rows.Add(row);
-            }
-            
-            action(table, null);
+        var sections = PRSService.GetConfiguration().LoadAll();
+
+        RefreshServices(sections);
+
+        var startupConfig = PRSService.GetConfiguration<ServerStartupSettings>();
+        var startupSettings = startupConfig.Load();
+        foreach (var startup in startupSettings.StartServers)
+        {
+            _services.FirstOrDefault(x => x.ServiceName == startup)?.Start();
+        }
+        startupSettings.StartServers.Clear();
+        startupConfig.Save(startupSettings);
+
+        foreach (var section in sections.OrderBy(x => x.Value.Type))
+        {
+            var server = section.Value.CreateServer(section.Key);
+            var service = _services.FirstOrDefault(x => string.Equals(x.ServiceName, section.Key));
+            var row = table.NewRow();
+            table.LoadRow(row, server);
+            table.Rows.Add(row);
+        }
+        
+        action(table, null);
 
-            _monitor ??= Task.Run(
-                () =>
+        _monitor ??= Task.Run(
+            () =>
+            {
+                while (!cancel.Token.IsCancellationRequested)
                 {
-                    while (!cancel.Token.IsCancellationRequested)
+                    bool testcertificates = false;
+                    var certrow = table.Rows.FirstOrDefault(x => x.Get<Server, ServerType>(x => x.Type) == ServerType.Certificate);
+                    if (certrow != null)
                     {
-                        bool testcertificates = false;
-                        var certrow = table.Rows.FirstOrDefault(x => x.Get<Server, ServerType>(x => x.Type) == ServerType.Certificate);
-                        if (certrow != null)
-                        {
-                            var key = certrow.Get<Server, string>(x => x.Key);
-                            var certservice = GetService(key);
-                            certservice.Refresh();
-                            if (certservice.Status == ServiceControllerStatus.Running)
-                                testcertificates = true;
-                        }
+                        var key = certrow.Get<Server, string>(x => x.Key);
+                        var certservice = GetService(key);
+                        certservice.Refresh();
+                        if (certservice.Status == ServiceControllerStatus.Running)
+                            testcertificates = true;
+                    }
 
-                        foreach (var row in table.Rows)
+                    foreach (var row in table.Rows)
+                    {
+                        bool bRefresh = false;
+                        var key = row.Get<Server, string>(x => x.Key);
+                        
+                        var service = GetService(key);
+                        _serviceStatuses.TryGetValue(key, out var oldstatus);
+                        service.Refresh();
+                        _serviceStatuses[key] = service.Status;
+                        if (_serviceStatuses[key] != oldstatus)
+                            bRefresh = true;
+
+                        if (testcertificates && (_serviceStatuses[key] == ServiceControllerStatus.Running))
                         {
-                            bool bRefresh = false;
-                            var key = row.Get<Server, string>(x => x.Key);
-                            
-                            var service = GetService(key);
-                            _serviceStatuses.TryGetValue(key, out var oldstatus);
-                            service.Refresh();
-                            _serviceStatuses[key] = service.Status;
-                            if (_serviceStatuses[key] != oldstatus)
-                                bRefresh = true;
-
-                            if (testcertificates && (_serviceStatuses[key] == ServiceControllerStatus.Running))
+                            var type = row.Get<Server, ServerType>(x => x.Type);
+                            if (type == ServerType.Database)
                             {
-                                var type = row.Get<Server, ServerType>(x => x.Type);
-                                if (type == ServerType.Database)
-                                {
-                                    _secureConnections.TryGetValue(key, out bool oldsecure);
-                                    if (!_pipemonitors.TryGetValue(key, out RpcClientPipeTransport client))
-                                    {
-                                        client = new RpcClientPipeTransport(DatabaseServerProperties.GetPipeName(key, true));
-                                        client.Connect();
-                                        _pipemonitors[key] = client;
-                                    }
-                                    
-                                    var info = client.IsConnected()
-                                        ? client.Send<RpcInfoCommand, RpcInfoParameters, RpcInfoResult>(new RpcInfoParameters()).Info
-                                        : null;
-                                    _secureConnections[key] = info?.IsHTTPS ?? false;
-                                    
-                                    bRefresh = bRefresh || (_secureConnections[key] != oldsecure);
-                                }
-                                else if (type == ServerType.Web)
+                                _secureConnections.TryGetValue(key, out bool oldsecure);
+                                if (!_pipemonitors.TryGetValue(key, out RpcClientPipeTransport client))
                                 {
-                                    var props = row.ToObject<Server>().Properties as WebServerProperties;
-                                    _secureConnections.TryGetValue(key, out bool oldsecure);
-                                    if (!_webmonitors.TryGetValue(key, out HttpClient client))
-                                    {
-                                        client = new HttpClient { BaseAddress = new Uri($"https://127.0.0.1:{props.ListenPort}") };
-                                        _webmonitors[key] = client;
-                                    }
-                                    try
-                                    {
-                                        client.GetAsync("/").Wait();
-                                        _secureConnections[key] = true;
-                                    }
-                                    catch (Exception e)
-                                    {
-                                        _secureConnections[key] = false;
-                                    }         
-                                    bRefresh = bRefresh || (_secureConnections[key] != oldsecure);
+                                    client = new RpcClientPipeTransport(DatabaseServerProperties.GetPipeName(key, true));
+                                    client.Connect();
+                                    _pipemonitors[key] = client;
                                 }
+                                
+                                var info = client.IsConnected()
+                                    ? client.Send<RpcInfoCommand, RpcInfoParameters, RpcInfoResult>(new RpcInfoParameters()).Info
+                                    : null;
+                                _secureConnections[key] = info?.IsHTTPS ?? false;
+                                
+                                bRefresh = bRefresh || (_secureConnections[key] != oldsecure);
                             }
-                            else
+                            else if (type == ServerType.Web)
                             {
-                                bRefresh = bRefresh || _secureConnections.ContainsKey(key);
-                                _secureConnections.Remove(key);
+                                var props = row.ToObject<Server>().Properties as WebServerProperties;
+                                _secureConnections.TryGetValue(key, out bool oldsecure);
+                                if (!_webmonitors.TryGetValue(key, out HttpClient client))
+                                {
+                                    client = new HttpClient { BaseAddress = new Uri($"https://127.0.0.1:{props.ListenPort}") };
+                                    _webmonitors[key] = client;
+                                }
+                                try
+                                {
+                                    client.GetAsync("/").Wait();
+                                    _secureConnections[key] = true;
+                                }
+                                catch (Exception e)
+                                {
+                                    _secureConnections[key] = false;
+                                }         
+                                bRefresh = bRefresh || (_secureConnections[key] != oldsecure);
                             }
-                            if (bRefresh)
-                                Dispatcher.Invoke(() =>
-                                {                                    
-                                    if (testcertificates && (ActionColumns[1].Position != DynamicActionColumnPosition.Start))
-                                        ActionColumns[1].Position = DynamicActionColumnPosition.Start;
-                                    else if (!testcertificates && (ActionColumns[1].Position != DynamicActionColumnPosition.Hidden))
-                                        ActionColumns[1].Position = DynamicActionColumnPosition.Hidden;
-                                    Refresh(true, false);
-                                    InvalidateRow(row);
-                                });
                         }
-                        
-                        Task.Delay(TimeSpan.FromSeconds(1)).Wait();
+                        else
+                        {
+                            bRefresh = bRefresh || _secureConnections.ContainsKey(key);
+                            _secureConnections.Remove(key);
+                        }
+                        if (bRefresh)
+                            Dispatcher.Invoke(() =>
+                            {                                    
+                                if (testcertificates && (ActionColumns[1].Position != DynamicActionColumnPosition.Start))
+                                    ActionColumns[1].Position = DynamicActionColumnPosition.Start;
+                                else if (!testcertificates && (ActionColumns[1].Position != DynamicActionColumnPosition.Hidden))
+                                    ActionColumns[1].Position = DynamicActionColumnPosition.Hidden;
+                                Refresh(true, false);
+                                InvalidateRow(row);
+                            });
                     }
-                },
-                cancel.Token
-            );
-        }
-        
-        protected override Server LoadItem(CoreRow row)
-        {
-            var key = row.Get<Server, string>(x => x.Key);
-            var settings = PRSService.GetConfiguration(key).Load();
-            return settings.CreateServer(key);
-        }
-
-        private string CreateKey(ServerType type)
-        {
-            var services = ServiceController.GetServices();
-            var key = string.Format("PRS{0}", type.ToString());
-            var i = 1;
-            while (services.Any(x => string.Equals(key, x.ServiceName)))
-                key = string.Format("PRS{0}_{1}", type.ToString(), i++);
-            return key;
-        }
-
-        private void CreateMenu(ContextMenu parent, string header, ServerType server, Type properties)
-        {
-            var menu = new MenuItem();
-            menu.Header = header;
-            menu.Tag = properties;
-            menu.Icon = new Image() { Source = _typeimages[server] };
-            menu.IsCheckable = false;
-            menu.Click += (o, e) =>
-            {
-                var itemtype = ((o as MenuItem)?.Tag as Type)!;
-                var props = (Activator.CreateInstance(itemtype) as ServerProperties)!;
-                if (EditProperties(properties, props, true))
-                {
-                    var server = CreateItem();
-                    server.Key = CreateKey(props.Type());
-                    server.Type = props.Type();
-                    server.Properties = props;
-                    SaveItem(server);
-                    Refresh(false, true);
+                    
+                    Task.Delay(TimeSpan.FromSeconds(1)).Wait();
                 }
-            };
-            parent.Items.Add(menu);
-        }
+            },
+            cancel.Token
+        );
+    }
+    
+    protected override Server LoadItem(CoreRow row)
+    {
+        var key = row.Get<Server, string>(x => x.Key);
+        var settings = PRSService.GetConfiguration(key).Load();
+        return settings.CreateServer(key);
+    }
 
-        protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
-        {
-            var menu = new ContextMenu();
-            CreateMenu(menu, "Database", ServerType.Database, typeof(DatabaseServerProperties));
-            CreateMenu(menu, "GPS Connector", ServerType.GPS, typeof(GPSServerProperties));
-            if (!Data.Rows.Any(r => r.Get<Server, ServerType>(c => c.Type) == ServerType.AutoDiscovery))
-                CreateMenu(menu, "Auto Discovery", ServerType.AutoDiscovery, typeof(AutoDiscoveryServerProperties));
-            CreateMenu(menu, "Scheduler", ServerType.Schedule, typeof(ScheduleServerProperties));
-            CreateMenu(menu, "Web Service", ServerType.Web, typeof(WebServerProperties));
-            if (!Data.Rows.Any(r => r.Get<Server, ServerType>(c => c.Type) == ServerType.Certificate))
-                CreateMenu(menu, "HTTPS Certificate Engine", ServerType.Certificate, typeof(CertificateEngineProperties));
-            menu.IsOpen = true;
-        }
+    private string CreateKey(ServerType type)
+    {
+        var services = ServiceController.GetServices();
+        var key = string.Format("PRS{0}", type.ToString());
+        var i = 1;
+        while (services.Any(x => string.Equals(key, x.ServiceName)))
+            key = string.Format("PRS{0}_{1}", type.ToString(), i++);
+        return key;
+    }
 
-        protected override void DoEdit()
+    private void CreateMenu(ContextMenu parent, string header, ServerType server, Type properties)
+    {
+        var menu = new MenuItem();
+        menu.Header = header;
+        menu.Tag = properties;
+        menu.Icon = new Image() { Source = _typeimages[server] };
+        menu.IsCheckable = false;
+        menu.Click += (o, e) =>
         {
-            if (!SelectedRows.Any())
-                return;
-
-            var server = LoadItem(SelectedRows.First());
-
-            var service = GetService(server.Key);
-            var enabled = service == null || service.Status == ServiceControllerStatus.Stopped;
-
-            if (EditProperties(server.Properties.GetType(), server.Properties, enabled))
+            var itemtype = ((o as MenuItem)?.Tag as Type)!;
+            var props = (Activator.CreateInstance(itemtype) as ServerProperties)!;
+            if (EditProperties(properties, props, true))
             {
-                server.Name = server.Properties.Name;
+                var server = CreateItem();
+                server.Key = CreateKey(props.Type());
+                server.Type = props.Type();
+                server.Properties = props;
                 SaveItem(server);
                 Refresh(false, true);
             }
-        }
+        };
+        parent.Items.Add(menu);
+    }
 
-        public override void SaveItem(Server item)
-        {
-            var settings = new ServerSettings();
-            settings.Type = item.Type;
-            settings.Properties = Serialization.Serialize(item.Properties, false);
+    protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
+    {
+        var menu = new ContextMenu();
+        CreateMenu(menu, "Database", ServerType.Database, typeof(DatabaseServerProperties));
+        CreateMenu(menu, "GPS Connector", ServerType.GPS, typeof(GPSServerProperties));
+        if (!Data.Rows.Any(r => r.Get<Server, ServerType>(c => c.Type) == ServerType.AutoDiscovery))
+            CreateMenu(menu, "Auto Discovery", ServerType.AutoDiscovery, typeof(AutoDiscoveryServerProperties));
+        CreateMenu(menu, "Scheduler", ServerType.Schedule, typeof(ScheduleServerProperties));
+        CreateMenu(menu, "Web Service", ServerType.Web, typeof(WebServerProperties));
+        if (!Data.Rows.Any(r => r.Get<Server, ServerType>(c => c.Type) == ServerType.Certificate))
+            CreateMenu(menu, "HTTPS Certificate Engine", ServerType.Certificate, typeof(CertificateEngineProperties));
+        menu.IsOpen = true;
+    }
+
+    protected override void DoEdit()
+    {
+        if (!SelectedRows.Any())
+            return;
 
-            PRSService.GetConfiguration(item.Key).Save(settings);
+        var server = LoadItem(SelectedRows.First());
 
-            ReconfigureService(item);
-        }
+        var service = GetService(server.Key);
+        var enabled = service == null || service.Status == ServiceControllerStatus.Stopped;
 
-        private bool isServiceChanged(Server server, ServiceController? service, string newDisplayName)
+        if (EditProperties(server.Properties.GetType(), server.Properties, enabled))
         {
-            return newDisplayName != service?.DisplayName || (server.Properties.HasOriginalValue(x => x.Username) && server.Properties.GetOriginalValue(x => x.Username) != server.Properties.Username);
+            server.Name = server.Properties.Name;
+            SaveItem(server);
+            Refresh(false, true);
         }
+    }
 
-        protected override bool CanDeleteItems(params CoreRow[] rows)
-        {
-            var bOK = true;
-            foreach (var row in rows)
-            {
-                var service = GetService(row.Get<Server, string>(x => x.Key));
-                if (service != null && service.Status != ServiceControllerStatus.Stopped)
-                    bOK = false;
-            }
+    public override void SaveItem(Server item)
+    {
+        var settings = new ServerSettings();
+        settings.Type = item.Type;
+        settings.Properties = Serialization.Serialize(item.Properties, false);
+
+        PRSService.GetConfiguration(item.Key).Save(settings);
+
+        ReconfigureService(item);
+    }
+
+    private bool isServiceChanged(Server server, ServiceController? service, string newDisplayName)
+    {
+        return newDisplayName != service?.DisplayName || (server.Properties.HasOriginalValue(x => x.Username) && server.Properties.GetOriginalValue(x => x.Username) != server.Properties.Username);
+    }
 
-            return bOK;
+    protected override bool CanDeleteItems(params CoreRow[] rows)
+    {
+        var bOK = true;
+        foreach (var row in rows)
+        {
+            var service = GetService(row.Get<Server, string>(x => x.Key));
+            if (service != null && service.Status != ServiceControllerStatus.Stopped)
+                bOK = false;
         }
 
-        protected override void DeleteItems(params CoreRow[] rows)
+        return bOK;
+    }
+
+    protected override void DeleteItems(params CoreRow[] rows)
+    {
+        foreach (var row in rows)
         {
-            foreach (var row in rows)
-            {
-                var key = row.Get<Server, string>(x => x.Key);
+            var key = row.Get<Server, string>(x => x.Key);
 
-                Interlocked.Exchange(
-                    ref _services,
-                    new ConcurrentBag<ServiceController>(
-                        _services.Where(x => !string.Equals(x.ServiceName, key))
-                    )
-                );
+            Interlocked.Exchange(
+                ref _services,
+                new ConcurrentBag<ServiceController>(
+                    _services.Where(x => !string.Equals(x.ServiceName, key))
+                )
+            );
 
-                PRSService.GetConfiguration(key).Delete();
+            PRSService.GetConfiguration(key).Delete();
 
-                var serverType = row.Get<Server, ServerType>(x => x.Type);
-                if (serverType == ServerType.Certificate)
+            var serverType = row.Get<Server, ServerType>(x => x.Type);
+            if (serverType == ServerType.Certificate)
+            {
+                if (File.Exists(CertificateEngine.CertificateFile))
                 {
-                    if (File.Exists(CertificateEngine.CertificateFile))
-                    {
-                        File.Delete(CertificateEngine.CertificateFile);
-                    }
+                    File.Delete(CertificateEngine.CertificateFile);
                 }
-
-                PRSServiceInstaller.UninstallService(key);
             }
+
+            PRSServiceInstaller.UninstallService(key);
         }
+    }
 
-        protected override void DefineLookups(ILookupEditorControl sender, Server[] items, bool async = true)
+    protected override void DefineLookups(ILookupEditorControl sender, Server[] items, bool async = true)
+    {
+        if(sender.EditorDefinition is ComboLookupEditor lookup && lookup.Type == typeof(DatabaseServerLookupGenerator))
         {
-            if(sender.EditorDefinition is ComboLookupEditor lookup && lookup.Type == typeof(DatabaseServerLookupGenerator))
-            {
-                base.DefineLookups(sender, Data.Rows.Select(x => x.ToObject<Server>()).ToArray());
-            }
-            else
-            {
-                base.DefineLookups(sender, items, async);
-            }
+            base.DefineLookups(sender, Data.Rows.Select(x => x.ToObject<Server>()).ToArray());
+        }
+        else
+        {
+            base.DefineLookups(sender, items, async);
         }
+    }
 
-        #endregion
+    #endregion
 
-        #region Server Configuration
+    #region Server Configuration
 
-        private bool EditUpdateChannel_Click(Button arg1, CoreRow[] arg2)
+    private bool EditUpdateChannel_Click(Button arg1, CoreRow[] arg2)
+    {
+        var settings = new LocalConfiguration<AutoUpdateSettings>().Load();
+        var editable = settings.ToEditable();
+        var buttons = new DynamicEditorButtons()
         {
-            var settings = new LocalConfiguration<AutoUpdateSettings>().Load();
-            var editable = settings.ToEditable();
-            var buttons = new DynamicEditorButtons()
-            {
-                new DynamicEditorButton(
-                    "",
-                    Properties.Resources.help.AsBitmapImage(),
-                    null,
-                    (o, e) => base.ShowHelp("Automatic_Updates"))
-
-            };
-            var propertyEditor = new DynamicEditorForm(typeof(EditableAutoUpdateSettings), null, buttons);
-            propertyEditor.OnDefineEditor += PropertyEditor_OnDefineEditor;
-            propertyEditor.OnDefineLookups += sender => DefineLookups(sender, new Server[] { });
-            propertyEditor.Items = new BaseObject[] { editable };
+            new DynamicEditorButton(
+                "",
+                Properties.Resources.help.AsBitmapImage(),
+                null,
+                (o, e) => base.ShowHelp("Automatic_Updates"))
 
-            if (propertyEditor.ShowDialog() == true)
-            {
-                settings.FromEditable(editable);
-                new LocalConfiguration<AutoUpdateSettings>().Save(settings);
-            }
+        };
+        var propertyEditor = new DynamicEditorForm(typeof(EditableAutoUpdateSettings), null, buttons);
+        propertyEditor.OnDefineEditor += PropertyEditor_OnDefineEditor;
+        propertyEditor.OnDefineLookups += sender => DefineLookups(sender, new Server[] { });
+        propertyEditor.Items = new BaseObject[] { editable };
 
-            return false;
+        if (propertyEditor.ShowDialog() == true)
+        {
+            settings.FromEditable(editable);
+            new LocalConfiguration<AutoUpdateSettings>().Save(settings);
         }
 
-        private BaseEditor? PropertyEditor_OnDefineEditor(object item, DynamicGridColumn column)
-        {
-            if (string.Equals(column.ColumnName, "Elevated"))
-                return new NullEditor();
+        return false;
+    }
 
-            var result = GetEditor(item, column);
-            if (result != null)
-                result = result.CloneEditor();
-            return result;
-        }
+    private BaseEditor? PropertyEditor_OnDefineEditor(object item, DynamicGridColumn column)
+    {
+        if (string.Equals(column.ColumnName, "Elevated"))
+            return new NullEditor();
 
-        private void ReconfigureService(Server item)
-        {
-            var service = GetService(item.Key);
-            var newDisplayName = "PRS - " + item.Properties.Name;
-            string? username = item.Properties.Username;
+        var result = GetEditor(item, column);
+        if (result != null)
+            result = result.CloneEditor();
+        return result;
+    }
+
+    private void ReconfigureService(Server item)
+    {
+        var service = GetService(item.Key);
+        var newDisplayName = "PRS - " + item.Properties.Name;
+        string? username = item.Properties.Username;
 
-            if (!isServiceChanged(item, service, newDisplayName)) return;
+        if (!isServiceChanged(item, service, newDisplayName)) return;
 
-            string? password = null;
-            if (!string.IsNullOrWhiteSpace(username))
+        string? password = null;
+        if (!string.IsNullOrWhiteSpace(username))
+        {
+            var passwordEditor = new PasswordDialog(string.Format("Enter password for {0}", username));
+            if(passwordEditor.ShowDialog() == true)
             {
-                var passwordEditor = new PasswordDialog(string.Format("Enter password for {0}", username));
-                if(passwordEditor.ShowDialog() == true)
-                {
-                    password = passwordEditor.Password;
-                }
-                else
-                {
-                    password = null;
-                }
+                password = passwordEditor.Password;
             }
             else
             {
-                username = null;
+                password = null;
             }
-
-            if (service == null)
-                try
-                {
-                    using (new WaitCursor())
-                    {
-                        PRSServiceInstaller.InstallService(
-                            item.Key,
-                            item.Properties.Name,
-                            newDisplayName,
-                            username,
-                            password
-                        );
-                    }
-                }
-                catch (Exception e)
-                {
-                    MessageBox.Show(string.Format("Error Installing {0}: {1}", item.Key, e.Message));
-                }
-            else
-                try
-                {
-                    using (new WaitCursor())
-                    {
-                        PRSServiceInstaller.ChangeService(
-                            item.Key,
-                            item.Properties.Name,
-                            newDisplayName,
-                            username,
-                            password
-                        );
-                    }
-                }
-                catch (Exception e)
-                {
-                    MessageBox.Show(string.Format("Error Configuring {0}: {1}", item.Key, e.Message));
-                }
         }
-
-        public bool EditProperties(Type type, ServerProperties item, bool enabled)
+        else
         {
-            var pages = new DynamicEditorPages();
+            username = null;
+        }
 
-            if (type == typeof(DatabaseServerProperties))
+        if (service == null)
+            try
             {
-                pages.Add(new SMSProviderGrid());
-            }
-
-            var buttons = new DynamicEditorButtons();
-            buttons.Add(
-                "",
-                Properties.Resources.help.AsBitmapImage(),
-                item,
-                (f, i) =>
+                using (new WaitCursor())
                 {
-                    Process.Start(new ProcessStartInfo("https://prsdigital.com.au/wiki/index.php/" + type.Name.SplitCamelCase().Replace(" ", "_"))
-                        { UseShellExecute = true });
+                    PRSServiceInstaller.InstallService(
+                        item.Key,
+                        item.Properties.Name,
+                        newDisplayName,
+                        username,
+                        password
+                    );
                 }
-            );
-            var propertyEditor = new DynamicEditorForm(type, pages, buttons);
-
-            if(type == typeof(DatabaseServerProperties))
+            }
+            catch (Exception e)
+            {
+                MessageBox.Show(string.Format("Error Installing {0}: {1}", item.Key, e.Message));
+            }
+        else
+            try
             {
-                propertyEditor.OnSaveItem += (o, e) =>
+                using (new WaitCursor())
                 {
-                    propertyEditor.UnloadEditorPages(false);
-                    propertyEditor.UnloadEditorPages(true);
-                };
+                    PRSServiceInstaller.ChangeService(
+                        item.Key,
+                        item.Properties.Name,
+                        newDisplayName,
+                        username,
+                        password
+                    );
+                }
             }
+            catch (Exception e)
+            {
+                MessageBox.Show(string.Format("Error Configuring {0}: {1}", item.Key, e.Message));
+            }
+    }
 
-            propertyEditor.ReadOnly = !enabled;
+    public bool EditProperties(Type type, ServerProperties item, bool enabled)
+    {
+        var pages = new DynamicEditorPages();
 
-            propertyEditor.OnDefineLookups += sender => DefineLookups(sender, new Server[] { });
-            propertyEditor.Items = new BaseObject[] { item };
+        if (type == typeof(DatabaseServerProperties))
+        {
+            pages.Add(new SMSProviderGrid());
+        }
+
+        var buttons = new DynamicEditorButtons();
+        buttons.Add(
+            "",
+            Properties.Resources.help.AsBitmapImage(),
+            item,
+            (f, i) =>
+            {
+                Process.Start(new ProcessStartInfo("https://prsdigital.com.au/wiki/index.php/" + type.Name.SplitCamelCase().Replace(" ", "_"))
+                    { UseShellExecute = true });
+            }
+        );
+        var propertyEditor = new DynamicEditorForm(type, pages, buttons);
 
-            return propertyEditor.ShowDialog() == true;
+        if(type == typeof(DatabaseServerProperties))
+        {
+            propertyEditor.OnSaveItem += (o, e) =>
+            {
+                propertyEditor.UnloadEditorPages(false);
+                propertyEditor.UnloadEditorPages(true);
+            };
         }
 
-        #endregion
+        propertyEditor.ReadOnly = !enabled;
 
-        #region Service Start / Stop Actions
+        propertyEditor.OnDefineLookups += sender => DefineLookups(sender, new Server[] { });
+        propertyEditor.Items = new BaseObject[] { item };
 
-        private readonly Dictionary<int, BitmapImage> _stateimages = new()
-        {
-            { 0, Properties.Resources.warning.AsBitmapImage() },
-            { (int)ServiceControllerStatus.Stopped, Properties.Resources.pause.AsBitmapImage() },
-            { (int)ServiceControllerStatus.StartPending, Properties.Resources.working.AsBitmapImage() },
-            { (int)ServiceControllerStatus.StopPending, Properties.Resources.working.AsBitmapImage() },
-            { (int)ServiceControllerStatus.Running, Properties.Resources.tick.AsBitmapImage() },
-            { (int)ServiceControllerStatus.ContinuePending, Properties.Resources.working.AsBitmapImage() },
-            { (int)ServiceControllerStatus.PausePending, Properties.Resources.working.AsBitmapImage() },
-            { (int)ServiceControllerStatus.Paused, Properties.Resources.pause.AsBitmapImage() }
-        };
+        return propertyEditor.ShowDialog() == true;
+    }
 
-        private BitmapImage StateImage(CoreRow? arg)
-        {
-            if (arg == null)
-                return Properties.Resources.tick.AsBitmapImage();
-            var key = arg.Get<Server, string>(c => c.Key);
-            var service = GetService(key);
-            int state = service != null ? (int)service.Status : 0; 
-            return _stateimages[state];
-        }
+    #endregion
 
-        private FrameworkElement? StateToolTip(DynamicActionColumn arg1, CoreRow? arg2)
-        {
-            if (arg2 == null)
-                return null;
-            var service = GetService(arg2.Get<Server, string>(c => c.Key));
-            return arg1.TextToolTip(service != null ? "Current State: " + service.Status : "Not Installed");
-        }
-        
-        private FrameworkElement? MenuToolTip(DynamicActionColumn arg1, CoreRow? arg2)
-        {
-            return arg2 != null ? arg1.TextToolTip("Server Options") : null;
-        }
+    #region Service Start / Stop Actions
 
-        private bool StateAction(CoreRow? arg)
+    private readonly Dictionary<int, BitmapImage> _stateimages = new()
+    {
+        { 0, Properties.Resources.warning.AsBitmapImage() },
+        { (int)ServiceControllerStatus.Stopped, Properties.Resources.pause.AsBitmapImage() },
+        { (int)ServiceControllerStatus.StartPending, Properties.Resources.working.AsBitmapImage() },
+        { (int)ServiceControllerStatus.StopPending, Properties.Resources.working.AsBitmapImage() },
+        { (int)ServiceControllerStatus.Running, Properties.Resources.tick.AsBitmapImage() },
+        { (int)ServiceControllerStatus.ContinuePending, Properties.Resources.working.AsBitmapImage() },
+        { (int)ServiceControllerStatus.PausePending, Properties.Resources.working.AsBitmapImage() },
+        { (int)ServiceControllerStatus.Paused, Properties.Resources.pause.AsBitmapImage() }
+    };
+
+    private BitmapImage StateImage(CoreRow? arg)
+    {
+        if (arg == null)
+            return Properties.Resources.tick.AsBitmapImage();
+        var key = arg.Get<Server, string>(c => c.Key);
+        var service = GetService(key);
+        int state = service != null ? (int)service.Status : 0; 
+        return _stateimages[state];
+    }
+
+    private FrameworkElement? StateToolTip(DynamicActionColumn arg1, CoreRow? arg2)
+    {
+        if (arg2 == null)
+            return null;
+        var service = GetService(arg2.Get<Server, string>(c => c.Key));
+        return arg1.TextToolTip(service != null ? "Current State: " + service.Status : "Not Installed");
+    }
+    
+    private FrameworkElement? MenuToolTip(DynamicActionColumn arg1, CoreRow? arg2)
+    {
+        return arg2 != null ? arg1.TextToolTip("Server Options") : null;
+    }
+
+    private bool StateAction(CoreRow? arg)
+    {
+        if (arg == null)
+            return false;
+        var key = arg.Get<Server, string>(c => c.Key);
+        var service = GetService(arg.Get<Server, string>(c => c.Key));
+        if (service != null)
         {
-            if (arg == null)
-                return false;
-            var key = arg.Get<Server, string>(c => c.Key);
-            var service = GetService(arg.Get<Server, string>(c => c.Key));
-            if (service != null)
+            Task? task;
+            if (service.Status == ServiceControllerStatus.Running)
             {
-                Task? task;
-                if (service.Status == ServiceControllerStatus.Running)
-                {
-                    task = Task.Run(
-                        () =>
-                        {
-                            service.Stop();
-                            Dispatcher.Invoke(()=> Refresh(false, false));
-                        });
-                    //StopConsole(key);
-                }
-                else if (service.Status == ServiceControllerStatus.Stopped)
-                {
-                    task = Task.Run(
-                        () => 
-                        {
-                            service.Start();
-                            Dispatcher.Invoke(()=> Refresh(false, false));
-                        });
-                    StartConsole(arg,key);
-                }
-                else if (service.Status == ServiceControllerStatus.Paused)
-                {
-                    task = Task.Run(() =>
+                task = Task.Run(
+                    () =>
                     {
-                        service.Continue();
+                        service.Stop();
                         Dispatcher.Invoke(()=> Refresh(false, false));
                     });
-                }
-                else
+                //StopConsole(key);
+            }
+            else if (service.Status == ServiceControllerStatus.Stopped)
+            {
+                task = Task.Run(
+                    () => 
+                    {
+                        service.Start();
+                        Dispatcher.Invoke(()=> Refresh(false, false));
+                    });
+                StartConsole(arg,key);
+            }
+            else if (service.Status == ServiceControllerStatus.Paused)
+            {
+                task = Task.Run(() =>
                 {
-                    MessageBox.Show(string.Format("Invalid Service State ({0})", service.Status.ToString()));
-                    return false;
-                }
-                task?.ContinueWith((e) =>
+                    service.Continue();
+                    Dispatcher.Invoke(()=> Refresh(false, false));
+                });
+            }
+            else
+            {
+                MessageBox.Show(string.Format("Invalid Service State ({0})", service.Status.ToString()));
+                return false;
+            }
+            task?.ContinueWith((e) =>
+            {
+                if (e.Exception?.InnerException is { } inner)
                 {
-                    if (e.Exception?.InnerException is { } inner)
+                    if(inner.InnerException != null)
                     {
-                        if(inner.InnerException != null)
-                        {
-                            MessageBox.Show(String.Format("Error while running service:\n{0}", inner.InnerException.Message));
-                        }
-                        else
-                        {
-                            MessageBox.Show(String.Format("Error while running service:\n{0}", inner.Message));
-                        }
-                        PRSServiceInstaller.UninstallService(arg.Get<Server, string>(x => x.Key));
-                        Refresh(false, true);
+                        MessageBox.Show(String.Format("Error while running service:\n{0}", inner.InnerException.Message));
                     }
-                }, TaskScheduler.FromCurrentSynchronizationContext());
-
-                return true;
-            }
+                    else
+                    {
+                        MessageBox.Show(String.Format("Error while running service:\n{0}", inner.Message));
+                    }
+                    PRSServiceInstaller.UninstallService(arg.Get<Server, string>(x => x.Key));
+                    Refresh(false, true);
+                }
+            }, TaskScheduler.FromCurrentSynchronizationContext());
 
-            MessageBox.Show("Cannot find Service - is it installed?");
-            return false;
+            return true;
         }
 
-        public void StopAll()
-        {
-            foreach (var service in _services.ToArray())
-                if (service.Status == ServiceControllerStatus.Running)
-                    Task.Run(() => { service.Stop(); });
-        }
+        MessageBox.Show("Cannot find Service - is it installed?");
+        return false;
+    }
 
-        #endregion
+    public void StopAll()
+    {
+        foreach (var service in _services.ToArray())
+            if (service.Status == ServiceControllerStatus.Running)
+                Task.Run(() => { service.Stop(); });
+    }
 
-        #region Server Type Images
+    #endregion
 
-        private readonly Dictionary<ServerType, BitmapImage> _typeimages = new()
-        {
-            { ServerType.Database, Properties.Resources.database.AsBitmapImage() },
-            { ServerType.GPS, Properties.Resources.gps.AsBitmapImage() },
-            { ServerType.AutoDiscovery, Properties.Resources.autodiscover.AsBitmapImage() },
-            { ServerType.Schedule, Properties.Resources.schedule.AsBitmapImage() },
-            { ServerType.Web, Properties.Resources.web.AsBitmapImage() },
-            { ServerType.Certificate, Properties.Resources.certificate.AsBitmapImage() }
-        };
+    #region Server Type Images
 
-        private BitmapImage TypeImage(CoreRow? arg)
-        {
-            if (arg == null)
-                return Properties.Resources.help.AsBitmapImage();
-            var type = arg.Get<Server, ServerType>(c => c.Type);
-            return _typeimages[type];
-        }
-        
-        private FrameworkElement? TypeToolTip(DynamicActionColumn arg1, CoreRow? arg2)
-        {
-            if (arg2 == null)
-                return null;
-            return arg1.TextToolTip(string.Format("{0} Service\nName: {1}",
-                arg2.Get<Server, ServerType>(c => c.Type).ToString(),
-                arg2.Get<Server, string>(c => c.Key)
-            ));
-        }
-
-        #endregion
+    private readonly Dictionary<ServerType, BitmapImage> _typeimages = new()
+    {
+        { ServerType.Database, Properties.Resources.database.AsBitmapImage() },
+        { ServerType.GPS, Properties.Resources.gps.AsBitmapImage() },
+        { ServerType.AutoDiscovery, Properties.Resources.autodiscover.AsBitmapImage() },
+        { ServerType.Schedule, Properties.Resources.schedule.AsBitmapImage() },
+        { ServerType.Web, Properties.Resources.web.AsBitmapImage() },
+        { ServerType.Certificate, Properties.Resources.certificate.AsBitmapImage() }
+    };
+
+    private BitmapImage TypeImage(CoreRow? arg)
+    {
+        if (arg == null)
+            return Properties.Resources.help.AsBitmapImage();
+        var type = arg.Get<Server, ServerType>(c => c.Type);
+        return _typeimages[type];
+    }
+    
+    private FrameworkElement? TypeToolTip(DynamicActionColumn arg1, CoreRow? arg2)
+    {
+        if (arg2 == null)
+            return null;
+        return arg1.TextToolTip(string.Format("{0} Service\nName: {1}",
+            arg2.Get<Server, ServerType>(c => c.Type).ToString(),
+            arg2.Get<Server, string>(c => c.Key)
+        ));
+    }
 
-        #region Console Functions
+    #endregion
 
-        private BitmapImage? ConsoleImage(CoreRow? arg)
-        {
-            if (arg == null)
-                return Properties.Resources.target.AsBitmapImage();
-            var service = GetService(arg.Get<Server, string>(c => c.Key));
-            var state = service != null ? (int)service.Status : 0;
-            if (state == (int)ServiceControllerStatus.StartPending || state == (int)ServiceControllerStatus.Running)
-                return Properties.Resources.target.AsBitmapImage();
-            return null;
-        }
+    #region Console Functions
 
-        private bool ConsoleAction(CoreRow? arg)
-        {
-            if (arg == null)
-                return false;
-            var key = arg.Get<Server, string>(c => c.Key);
-            var service = GetService(key);
-            var state = service != null ? (int)service.Status : 0;
-            if (state == (int)ServiceControllerStatus.StartPending || state == (int)ServiceControllerStatus.Running)
-                StartConsole(arg, key);
+    private BitmapImage? ConsoleImage(CoreRow? arg)
+    {
+        if (arg == null)
+            return Properties.Resources.target.AsBitmapImage();
+        var service = GetService(arg.Get<Server, string>(c => c.Key));
+        var state = service != null ? (int)service.Status : 0;
+        if (state == (int)ServiceControllerStatus.StartPending || state == (int)ServiceControllerStatus.Running)
+            return Properties.Resources.target.AsBitmapImage();
+        return null;
+    }
 
+    private bool ConsoleAction(CoreRow? arg)
+    {
+        if (arg == null)
             return false;
-        }
+        var key = arg.Get<Server, string>(c => c.Key);
+        var service = GetService(key);
+        var state = service != null ? (int)service.Status : 0;
+        if (state == (int)ServiceControllerStatus.StartPending || state == (int)ServiceControllerStatus.Running)
+            StartConsole(arg, key);
+
+        return false;
+    }
 
-        private Dictionary<String, Tuple<Console,int>> _consoles = new Dictionary<string, Tuple<Console,int>>();
+    private Dictionary<String, Tuple<ServerConsole, int>> _consoles = new Dictionary<string, Tuple<ServerConsole, int>>();
 
-        private void StartConsole(CoreRow arg, string key)
-        {
-            if (_consoles.ContainsKey(key))
-                return;
-            
-            var name = arg.Get<Server, string>(c => c.Name);
-            var console = new Console(key, $"{key} - {name}");
-            var window = Window.GetWindow(this);
-
-            int i = 0;
-            while (_consoles.Any(x => x.Value.Item2 == i))
-                i++;
-            
-            _consoles[key] = new Tuple<Console, int>(console, i);
-            
-            console.Top = window.Top + (i * 50);
-            console.Left = window.Left + window.Width + 2 + (i*50);
-            console.Height = window.Height;
-            console.Closing += (o, e) =>
-            {
-                Console c = o as Console;
-                if (_consoles.ContainsKey(c.ServiceName))
-                    _consoles.Remove(c.ServiceName);
-            };
-            console.Show();
-            
-        }
+    private void StartConsole(CoreRow arg, string key)
+    {
+        if (_consoles.ContainsKey(key))
+            return;
+        
+        var name = arg.Get<Server, string>(c => c.Name);
+        var console = new ServerConsole(key, $"{key} - {name}");
+        var window = Window.GetWindow(this);
 
-        private void StopConsole(String key)
+        int i = 0;
+        while (_consoles.Any(x => x.Value.Item2 == i))
+            i++;
+        
+        _consoles[key] = new Tuple<ServerConsole, int>(console, i);
+        
+        console.Top = window.Top + (i * 50);
+        console.Left = window.Left + window.Width + 2 + (i*50);
+        console.Height = window.Height;
+        console.Closing += (o, e) =>
         {
-            if (!_consoles.ContainsKey(key))
-                return;
-            Console console = _consoles[key].Item1;
-            console.Close();
-        }
+            var c = o as ServerConsole;
+            if (_consoles.ContainsKey(c.ServiceName))
+                _consoles.Remove(c.ServiceName);
+        };
+        console.Show();
+        
+    }
 
-        #endregion
+    private void StopConsole(String key)
+    {
+        if (!_consoles.ContainsKey(key))
+            return;
+        var console = _consoles[key].Item1;
+        console.Close();
+    }
 
-        #region Individual Server Buttons
+    #endregion
 
-        // Check if a database server is running at the given url and port
-        private bool IsDatabaseServerRunning(string url, int port)
-        {
-            var uri = new Uri(string.Format("{0}:{1}", url, port));
-            var cli = new RestClient(uri);
-            var req = new RestRequest("/classes", Method.Get) { Timeout = 20000 };
+    #region Individual Server Buttons
 
-            try
-            {
-                var res = cli.Execute(req);
-                if (res.StatusCode != HttpStatusCode.OK || res.ErrorException != null)
-                    return false;
-                return true;
-            }
-            catch (Exception e)
-            {
-            }
+    // Check if a database server is running at the given url and port
+    private bool IsDatabaseServerRunning(string url, int port)
+    {
+        var uri = new Uri(string.Format("{0}:{1}", url, port));
+        var cli = new RestClient(uri);
+        var req = new RestRequest("/classes", Method.Get) { Timeout = 20000 };
 
-            return false;
+        try
+        {
+            var res = cli.Execute(req);
+            if (res.StatusCode != HttpStatusCode.OK || res.ErrorException != null)
+                return false;
+            return true;
         }
-
-        // The following variables keep track of whether a database is currently being used, since if two people try to access two different databases,
-        // terrible things will ensue.
-        private int currentServerUsers;
-        private string? currentServerURL;
-        private int? currentServerPort;
-
-        /// <summary>
-        ///     Configures a server for the duration of an action
-        /// </summary>
-        /// <typeparam name="TProperties"></typeparam>
-        /// <param name="row"></param>
-        /// <param name="hostaddress"></param>
-        /// <param name="portnumber"></param>
-        /// <param name="action"></param>
-        /// <param name="blocking">
-        ///     If blocking is set to false, then currentServerUsers must be decreased by one manually once the
-        ///     task finishes
-        /// </param>
-        private void ConfigureServer<TProperties>(
-            CoreRow row,
-            Func<TProperties, string> hostaddress,
-            Func<TProperties, int> portnumber,
-            Action action,
-            bool blocking = true
-        ) where TProperties : ServerProperties
+        catch (Exception e)
         {
-            try
-            {
-                if (row == null)
-                    throw new Exception("No Row Selected!");
+        }
 
-                var server = LoadItem(row);
-                if (server == null)
-                    throw new Exception("Unable to load Server!");
+        return false;
+    }
 
-                var props = server.Properties as TProperties;
-                if (props == null)
-                    throw new Exception("Unable to Load Properties!");
+    // The following variables keep track of whether a database is currently being used, since if two people try to access two different databases,
+    // terrible things will ensue.
+    private int currentServerUsers;
+    private string? currentServerURL;
+    private int? currentServerPort;
+
+    /// <summary>
+    ///     Configures a server for the duration of an action
+    /// </summary>
+    /// <typeparam name="TProperties"></typeparam>
+    /// <param name="row"></param>
+    /// <param name="hostaddress"></param>
+    /// <param name="portnumber"></param>
+    /// <param name="action"></param>
+    /// <param name="blocking">
+    ///     If blocking is set to false, then currentServerUsers must be decreased by one manually once the
+    ///     task finishes
+    /// </param>
+    private void ConfigureServer<TProperties>(
+        CoreRow row,
+        Func<TProperties, string> hostaddress,
+        Func<TProperties, int> portnumber,
+        Action action,
+        bool blocking = true
+    ) where TProperties : ServerProperties
+    {
+        try
+        {
+            if (row == null)
+                throw new Exception("No Row Selected!");
 
-                var url = hostaddress(props);
-                var port = portnumber(props);
+            var server = LoadItem(row);
+            if (server == null)
+                throw new Exception("Unable to load Server!");
 
-                using (new WaitCursor())
-                {
-                    if (!IsDatabaseServerRunning(url, port))
-                        throw new Exception("Database Server is not available!");
-                }
+            var props = server.Properties as TProperties;
+            if (props == null)
+                throw new Exception("Unable to Load Properties!");
 
-                if (action != null)
-                {
-                    if (currentServerUsers == 0)
-                    {
-                        if (currentServerURL != url || currentServerPort != port)
-                        {
-                            ConfigurationCache.ClearAll(ConfigurationCacheType.Global);
-                            ConfigurationCache.ClearAll(ConfigurationCacheType.User);
-                        }
+            var url = hostaddress(props);
+            var port = portnumber(props);
 
-                        currentServerURL = url;
-                        currentServerPort = port;
-                        currentServerName = null;
-                        ClientFactory.SetClientType(typeof(RestClient<>), Platform.Server, CoreUtils.GetVersion(), url, port, true);
+            using (new WaitCursor())
+            {
+                if (!IsDatabaseServerRunning(url, port))
+                    throw new Exception("Database Server is not available!");
+            }
 
-                        // override the need to provide credentials when configuring the database
-                        ClientFactory.SetBypass();
-                    }
-                    else
+            if (action != null)
+            {
+                if (currentServerUsers == 0)
+                {
+                    if (currentServerURL != url || currentServerPort != port)
                     {
-                        if (url != currentServerURL || port != currentServerPort)
-                            throw new Exception(string.Format("A different Database Server ({0}:{1}) is currently in use!", currentServerURL,
-                                currentServerPort));
+                        ConfigurationCache.ClearAll(ConfigurationCacheType.Global);
+                        ConfigurationCache.ClearAll(ConfigurationCacheType.User);
                     }
 
-                    currentServerUsers++;
-                    action();
-                    if (blocking) currentServerUsers--;
+                    currentServerURL = url;
+                    currentServerPort = port;
+                    currentServerName = null;
+                    ClientFactory.SetClientType(typeof(RestClient<>), Platform.Server, CoreUtils.GetVersion(), url, port, true);
+
+                    // override the need to provide credentials when configuring the database
+                    ClientFactory.SetBypass();
                 }
-            }
-            catch (Exception e)
-            {
-                Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
-                MessageBox.Show(e.Message);
+                else
+                {
+                    if (url != currentServerURL || port != currentServerPort)
+                        throw new Exception(string.Format("A different Database Server ({0}:{1}) is currently in use!", currentServerURL,
+                            currentServerPort));
+                }
+
+                currentServerUsers++;
+                action();
+                if (blocking) currentServerUsers--;
             }
         }
+        catch (Exception e)
+        {
+            Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
+            MessageBox.Show(e.Message);
+        }
+    }
 
-        private string? currentServerName;
-        private void ConfigureIPCServer<TProperties>(
-            CoreRow row,
-            Func<TProperties, string> hostPipeName,
-            Action action,
-            bool blocking = true
-        ) where TProperties : ServerProperties
+    private string? currentServerName;
+    private void ConfigureIPCServer<TProperties>(
+        CoreRow row,
+        Func<TProperties, string> hostPipeName,
+        Action action,
+        bool blocking = true
+    ) where TProperties : ServerProperties
+    {
+        try
         {
-            try
-            {
-                if (row == null)
-                    throw new Exception("No Row Selected!");
+            if (row == null)
+                throw new Exception("No Row Selected!");
 
-                var server = LoadItem(row);
-                if (server == null)
-                    throw new Exception("Unable to load Server!");
+            var server = LoadItem(row);
+            if (server == null)
+                throw new Exception("Unable to load Server!");
 
-                var props = server.Properties as TProperties;
-                if (props == null)
-                    throw new Exception("Unable to Load Properties!");
+            var props = server.Properties as TProperties;
+            if (props == null)
+                throw new Exception("Unable to Load Properties!");
 
-                var pipeName = DatabaseServerProperties.GetPipeName(hostPipeName(props), false);
+            var pipeName = DatabaseServerProperties.GetPipeName(hostPipeName(props), false);
 
-                if (action != null)
+            if (action != null)
+            {
+                if (currentServerUsers == 0)
                 {
-                    if (currentServerUsers == 0)
+                    if (currentServerName != pipeName)
                     {
-                        if (currentServerName != pipeName)
-                        {
-                            ConfigurationCache.ClearAll(ConfigurationCacheType.Global);
-                            ConfigurationCache.ClearAll(ConfigurationCacheType.User);
-                        }
+                        ConfigurationCache.ClearAll(ConfigurationCacheType.Global);
+                        ConfigurationCache.ClearAll(ConfigurationCacheType.User);
+                    }
 
-                        currentServerPort = null;
-                        currentServerURL = null;
-                        currentServerName = pipeName;
-                        ClientFactory.SetClientType(typeof(IPCClient<>), Platform.Server, CoreUtils.GetVersion(), pipeName);
-                        using (new WaitCursor())
+                    currentServerPort = null;
+                    currentServerURL = null;
+                    currentServerName = pipeName;
+                    ClientFactory.SetClientType(typeof(IPCClient<>), Platform.Server, CoreUtils.GetVersion(), pipeName);
+                    using (new WaitCursor())
+                    {
+                        if (!Client.Ping())
                         {
-                            if (!Client.Ping())
-                            {
-                                ClientFactory.ClearClientType();
-                                throw new Exception("Database Server is not available!");
-                            }
+                            ClientFactory.ClearClientType();
+                            throw new Exception("Database Server is not available!");
                         }
-
-                        // override the need to provide credentials when configuring the database
-                        ClientFactory.SetBypass();
-                    }
-                    else
-                    {
-                        if (pipeName != currentServerName)
-                            throw new Exception(string.Format("A different Database Server ({0}) is currently in use!", currentServerName));
                     }
 
-                    currentServerUsers++;
-                    try
-                    {
-                        action();
-                    }
-                    finally
-                    {
-                        if (blocking) currentServerUsers--;
-                    }
+                    // override the need to provide credentials when configuring the database
+                    ClientFactory.SetBypass();
                 }
-            }
-            catch (Exception e)
-            {
-                Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
-                MessageBox.Show(e.Message);
-            }
-        }
-
-        private void ConfigureLocalDatabase(
-            CoreRow row,
-            Action action
-        )
-        {
-            try
-            {
-                if (row == null)
-                    throw new Exception("No Row Selected!");
-
-                var server = LoadItem(row) ?? throw new Exception("Unable to load Server!");
-                if (server.Properties is not DatabaseServerProperties properties)
-                    throw new Exception("Unable to Load Properties!");
-
-                if (!DbFactory.IsProviderSet || DbFactory.Provider is not SQLiteProvider sql || sql.URL != properties.FileName)
+                else
                 {
-                    ClientFactory.SetClientType(typeof(LocalClient<>), Platform.Server, CoreUtils.GetVersion());
-                    Progress.ShowModal("Configuring database", (progress) =>
-                    {
-                        DbFactory.Stores = CoreUtils.TypeList(
-                            AppDomain.CurrentDomain.GetAssemblies(),
-                            myType =>
-                                myType.IsClass
-                                && !myType.IsAbstract
-                                && !myType.IsGenericType
-                                && myType.GetInterfaces().Contains(typeof(IStore))
-                        ).ToArray();
-
-                        DbFactory.Provider = new SQLiteProvider(properties.FileName);
-                        DbFactory.Start();
-
-                        StoreUtils.GoogleAPIKey = properties.GoogleAPIKey;
-                        PurchaseOrder.PONumberPrefix = properties.PurchaseOrderPrefix;
-                        Job.JobNumberPrefix = properties.JobPrefix;
-                    });
+                    if (pipeName != currentServerName)
+                        throw new Exception(string.Format("A different Database Server ({0}) is currently in use!", currentServerName));
                 }
 
-                action();
-            }
-            catch(Exception e)
-            {
-                Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
-                MessageBox.Show(e.Message);
-            }
-        }
-        
-        private bool UpdateDatabaseLicense(CoreRow selectedrow)
-        {
-            ConfigureIPCServer<DatabaseServerProperties>(
-                selectedrow,
-                //x => "http://127.0.0.1",
-                //x => x.Port,
-                x => selectedrow.Get<Server, string>(x => x.Key),
-                () =>
+                currentServerUsers++;
+                try
                 {
-                    new LicenseRenewalForm().ShowDialog();
+                    action();
                 }
-            );
-            return false;
-        }
-
-        private bool ManageDeletions(CoreRow row)
-        {
-            ConfigureLocalDatabase(row, () =>
-            {
-                new DeletionsWindow().ShowDialog();
-            });
-            return false;
-        }
-        
-        private bool EditCustomFields(CoreRow selectedrow)
-        {
-            ConfigureIPCServer<DatabaseServerProperties>(
-                selectedrow,
-                //x => "http://127.0.0.1",
-                //x => x.Port,
-                x => selectedrow.Get<Server, string>(x => x.Key),
-                () => { new MasterList(typeof(CustomProperty), "Class", null, true).ShowDialog(); }
-            );
-            return false;
-        }
-        
-        private bool EditDatabaseScripts(CoreRow selectedrow)
-        {
-            ConfigureIPCServer<DatabaseServerProperties>(
-                selectedrow,
-                //x => "http://127.0.0.1",
-                //x => x.Port,
-                x => selectedrow.Get<Server, string>(x => x.Key),
-                () => { new MasterList(typeof(Script), "Section", null, true).ShowDialog(); }
-            );
-            return false;
+                finally
+                {
+                    if (blocking) currentServerUsers--;
+                }
+            }
         }
-        
-        private bool EditScheduledScripts(CoreRow selectedrow)
+        catch (Exception e)
         {
-            ConfigureIPCServer<ScheduleServerProperties>(
-                selectedrow,
-                x => x.Server,
-                () => { new MasterList(typeof(ScheduledScript), "", null, true, typeof(ScheduledScriptsGrid)).ShowDialog(); }
-            );
-            return false;
+            Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
+            MessageBox.Show(e.Message);
         }
+    }
 
-        private bool EditWebTemplates(CoreRow selectedRow)
+    private void ConfigureLocalDatabase(
+        CoreRow row,
+        Action action
+    )
+    {
+        try
         {
-            ConfigureIPCServer<WebServerProperties>(
-                selectedRow,
-                x => x.Server,
-                () =>
-                {
-                    var window = new MasterList(typeof(WebTemplate), "DataModel", "", true);
-                    window.Closed += (e, args) => { currentServerUsers--; };
-                    window.Show();
-                },
-                false
-            );
-            return false;
-        }
+            if (row == null)
+                throw new Exception("No Row Selected!");
 
-        private bool EditWebStyles(CoreRow selectedRow)
-        {
-            ConfigureIPCServer<WebServerProperties>(
-                selectedRow,
-                x => x.Server,
-                () =>
+            var server = LoadItem(row) ?? throw new Exception("Unable to load Server!");
+            if (server.Properties is not DatabaseServerProperties properties)
+                throw new Exception("Unable to Load Properties!");
+
+            if (!DbFactory.IsProviderSet || DbFactory.Provider is not SQLiteProvider sql || sql.URL != properties.FileName)
+            {
+                ClientFactory.SetClientType(typeof(LocalClient<>), Platform.Server, CoreUtils.GetVersion());
+                Progress.ShowModal("Configuring database", (progress) =>
                 {
-                    var window = new MasterList(typeof(WebStyle), "Code", "", true);
-                    window.Closed += (e, args) => { currentServerUsers--; };
-                    window.Show();
-                },
-                false
-            );
-            return false;
-        }
+                    DbFactory.Stores = CoreUtils.TypeList(
+                        AppDomain.CurrentDomain.GetAssemblies(),
+                        myType =>
+                            myType.IsClass
+                            && !myType.IsAbstract
+                            && !myType.IsGenericType
+                            && myType.GetInterfaces().Contains(typeof(IStore))
+                    ).ToArray();
+
+                    DbFactory.Provider = new SQLiteProvider(properties.FileName);
+                    DbFactory.Start();
+
+                    StoreUtils.GoogleAPIKey = properties.GoogleAPIKey;
+                    PurchaseOrder.PONumberPrefix = properties.PurchaseOrderPrefix;
+                    Job.JobNumberPrefix = properties.JobPrefix;
+                });
+            }
 
-        private bool EditWebDocuments(CoreRow selectedRow)
+            action();
+        }
+        catch(Exception e)
         {
-            ConfigureIPCServer<WebServerProperties>(
-                selectedRow,
-                x => x.Server,
-                () =>
-                {
-                    var window = new MasterList(typeof(WebDocument), "Code", "", true);
-                    window.Closed += (e, args) => { currentServerUsers--; };
-                    window.Show();
-                },
-                false
-            );
-            return false;
+            Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
+            MessageBox.Show(e.Message);
         }
+    }
+    
+    private bool UpdateDatabaseLicense(CoreRow selectedrow)
+    {
+        ConfigureIPCServer<DatabaseServerProperties>(
+            selectedrow,
+            //x => "http://127.0.0.1",
+            //x => x.Port,
+            x => selectedrow.Get<Server, string>(x => x.Key),
+            () =>
+            {
+                new LicenseRenewalForm().ShowDialog();
+            }
+        );
+        return false;
+    }
 
-        private bool PRSMobileSettings(CoreRow selectedrow)
+    private bool ManageDeletions(CoreRow row)
+    {
+        ConfigureLocalDatabase(row, () =>
         {
-            ConfigureIPCServer<WebServerProperties>(
-                selectedrow,
-                x => x.Server,
-                () =>
-                {
-                    var editor = new DynamicEditorForm(typeof(WebSettings));
-                    var settings = new GlobalConfiguration<WebSettings>().Load();
+            new DeletionsWindow().ShowDialog();
+        });
+        return false;
+    }
+    
+    private bool EditCustomFields(CoreRow selectedrow)
+    {
+        ConfigureIPCServer<DatabaseServerProperties>(
+            selectedrow,
+            //x => "http://127.0.0.1",
+            //x => x.Port,
+            x => selectedrow.Get<Server, string>(x => x.Key),
+            () => { new MasterList(typeof(CustomProperty), "Class", null, true).ShowDialog(); }
+        );
+        return false;
+    }
+    
+    private bool EditDatabaseScripts(CoreRow selectedrow)
+    {
+        ConfigureIPCServer<DatabaseServerProperties>(
+            selectedrow,
+            //x => "http://127.0.0.1",
+            //x => x.Port,
+            x => selectedrow.Get<Server, string>(x => x.Key),
+            () => { new MasterList(typeof(Script), "Section", null, true).ShowDialog(); }
+        );
+        return false;
+    }
+    
+    private bool EditScheduledScripts(CoreRow selectedrow)
+    {
+        ConfigureIPCServer<ScheduleServerProperties>(
+            selectedrow,
+            x => x.Server,
+            () => { new MasterList(typeof(ScheduledScript), "", null, true, typeof(ScheduledScriptsGrid)).ShowDialog(); }
+        );
+        return false;
+    }
 
-                    editor.Items = new[] { settings };
+    private bool EditWebTemplates(CoreRow selectedRow)
+    {
+        ConfigureIPCServer<WebServerProperties>(
+            selectedRow,
+            x => x.Server,
+            () =>
+            {
+                var window = new MasterList(typeof(WebTemplate), "DataModel", "", true);
+                window.Closed += (e, args) => { currentServerUsers--; };
+                window.Show();
+            },
+            false
+        );
+        return false;
+    }
 
-                    if (editor.ShowDialog() == true) new GlobalConfiguration<WebSettings>().Save(settings);
-                }
-            );
-            return false;
-        }
-        
-        private bool ShowServiceStatus(Button arg1, CoreRow[] arg2)
-        {
-            List<String> domains = new List<String>();
-            var certservers = Data.Rows.Where(row => row.Get<Server,ServerType>(c=>c.Type) == ServerType.Certificate)
-                .Select(row => LoadItem(row));;
-            foreach (var certserver in certservers)
+    private bool EditWebStyles(CoreRow selectedRow)
+    {
+        ConfigureIPCServer<WebServerProperties>(
+            selectedRow,
+            x => x.Server,
+            () =>
             {
-                var certprops = certserver.Properties as CertificateEngineProperties;
-                if (certprops != null)
-                    domains.AddRange(certprops.ParseDomainNames());
-            }
+                var window = new MasterList(typeof(WebStyle), "Code", "", true);
+                window.Closed += (e, args) => { currentServerUsers--; };
+                window.Show();
+            },
+            false
+        );
+        return false;
+    }
 
-            if (!domains.Any())
-                domains.Add("localhost");
+    private bool EditWebDocuments(CoreRow selectedRow)
+    {
+        ConfigureIPCServer<WebServerProperties>(
+            selectedRow,
+            x => x.Server,
+            () =>
+            {
+                var window = new MasterList(typeof(WebDocument), "Code", "", true);
+                window.Closed += (e, args) => { currentServerUsers--; };
+                window.Show();
+            },
+            false
+        );
+        return false;
+    }
 
-            var servers = Data.Rows.Where(row => row.Get<Server,ServerType>(c=>c.Type) != ServerType.Certificate)
-                .Select(row => LoadItem(row));
+    private bool PRSMobileSettings(CoreRow selectedrow)
+    {
+        ConfigureIPCServer<WebServerProperties>(
+            selectedrow,
+            x => x.Server,
+            () =>
+            {
+                var editor = new DynamicEditorForm(typeof(WebSettings));
+                var settings = new GlobalConfiguration<WebSettings>().Load();
 
-            var statusgrid = new ServiceStatus(domains, servers);
-            statusgrid.ShowDialog();
+                editor.Items = new[] { settings };
 
-            return false;
+                if (editor.ShowDialog() == true) new GlobalConfiguration<WebSettings>().Save(settings);
+            }
+        );
+        return false;
+    }
+    
+    private bool ShowServiceStatus(Button arg1, CoreRow[] arg2)
+    {
+        List<String> domains = new List<String>();
+        var certservers = Data.Rows.Where(row => row.Get<Server,ServerType>(c=>c.Type) == ServerType.Certificate)
+            .Select(row => LoadItem(row));;
+        foreach (var certserver in certservers)
+        {
+            var certprops = certserver.Properties as CertificateEngineProperties;
+            if (certprops != null)
+                domains.AddRange(certprops.ParseDomainNames());
         }
 
-        #endregion
+        if (!domains.Any())
+            domains.Add("localhost");
+
+        var servers = Data.Rows.Where(row => row.Get<Server,ServerType>(c=>c.Type) != ServerType.Certificate)
+            .Select(row => LoadItem(row));
+
+        var statusgrid = new ServiceStatus(domains, servers);
+        statusgrid.ShowDialog();
+
+        return false;
     }
+
+    #endregion
 }

+ 116 - 120
prs.server/Services/PRSService.cs

@@ -11,161 +11,157 @@ using InABox.Core;
 using InABox.Logging;
 using InABox.IPC;
 
-namespace PRSServer
+namespace PRSServer;
+
+public class PRSService : ServiceBase
 {
+    private IEngine? _engine;
     
 
+    private string _servicename;
 
-    public class PRSService : ServiceBase
-    {
-        private IEngine? _engine;
-        
-
-        private string _servicename;
-
-        private Thread? _thread;
-        //private CancellationTokenSource Source = new();
+    private Thread? _thread;
+    //private CancellationTokenSource Source = new();
 
-        // TODO: Is this necessary?
-        private App app;
+    // TODO: Is this necessary?
+    private App? app;
 
-        public PRSService(string serviceName, App app)
-        {
-            this.app = app;
+    public PRSService(string serviceName, App? app)
+    {
+        this.app = app;
 
-            CanPauseAndContinue = false;
-            CanShutdown = true;
+        CanPauseAndContinue = false;
+        CanShutdown = true;
 
-            if (string.IsNullOrWhiteSpace(serviceName))
-                _servicename = GetServiceName();
-            else
-                _servicename = serviceName;
-            ServiceName = _servicename;
-        }
+        if (string.IsNullOrWhiteSpace(serviceName))
+            _servicename = GetServiceName();
+        else
+            _servicename = serviceName;
+        ServiceName = _servicename;
+    }
 
-        private string GetServiceName()
+    private string GetServiceName()
+    {
+        if (string.IsNullOrWhiteSpace(_servicename))
         {
-            if (string.IsNullOrWhiteSpace(_servicename))
-            {
-                var processId = Process.GetCurrentProcess().Id;
-                var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Service where ProcessId = " + processId);
-                var collection = searcher.Get();
-                var services = collection.Cast<ManagementBaseObject>();
-                _servicename = services.Any() ? (string)services.First()["Name"] : "";
-                Logger.Send(LogType.Information, "", string.Format("Service Name is [{0}]", _servicename));
-            }
-
-            return _servicename;
+            var processId = Process.GetCurrentProcess().Id;
+            var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Service where ProcessId = " + processId);
+            var collection = searcher.Get();
+            var services = collection.Cast<ManagementBaseObject>();
+            _servicename = services.Any() ? (string)services.First()["Name"] : "";
+            Logger.Send(LogType.Information, "", string.Format("Service Name is [{0}]", _servicename));
         }
 
-        public static LocalConfiguration<T> GetConfiguration<T>(string section = "")
-            where T : ILocalConfigurationSettings, new()
+        return _servicename;
+    }
+
+    public static LocalConfiguration<T> GetConfiguration<T>(string section = "")
+        where T : ILocalConfigurationSettings, new()
+    {
+        // TODO : Remove the fallback location
+        var configuration = new LocalConfiguration<T>(CoreUtils.GetCommonAppData(), section);
+        if (!File.Exists(configuration.GetFileName()))
         {
-            // TODO : Remove the fallback location
-            var configuration = new LocalConfiguration<T>(CoreUtils.GetCommonAppData(), section);
-            if (!File.Exists(configuration.GetFileName()))
+            var oldsettings = new LocalConfiguration<T>(
+                Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location),
+                ""
+            );
+            if (File.Exists(oldsettings.GetFileName()))
             {
-                var oldsettings = new LocalConfiguration<T>(
-                    Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location),
-                    ""
-                );
-                if (File.Exists(oldsettings.GetFileName()))
-                {
-                    // Transition old data to new location
-                    var settings = oldsettings.LoadAll();
-                    configuration.SaveAll(settings);
-                    File.Delete(oldsettings.GetFileName());
-                }
+                // Transition old data to new location
+                var settings = oldsettings.LoadAll();
+                configuration.SaveAll(settings);
+                File.Delete(oldsettings.GetFileName());
             }
-            return configuration;
         }
+        return configuration;
+    }
 
-        public static LocalConfiguration<ServerSettings> GetConfiguration(string section = "") => GetConfiguration<ServerSettings>(section);
+    public static LocalConfiguration<ServerSettings> GetConfiguration(string section = "") => GetConfiguration<ServerSettings>(section);
 
-        public void Run(string servicename)
-        {
-            _servicename = servicename;
-            OnStart(new string[] { });
-        }
+    public void Run(string servicename)
+    {
+        _servicename = servicename;
+        OnStart(new string[] { });
+    }
 
-        public void Halt()
-        {
-            OnStop();
-        }
+    public void Halt()
+    {
+        OnStop();
+    }
+
+    protected override void OnStart(string[] args)
+    {
+        Logger.OnLog += MainLogger.Send;
+        //InABox.Logging.NamedPipeLogger.Start(CoreUtils.GetPath());
 
-        protected override void OnStart(string[] args)
+        var svcname = GetServiceName();
+        
+        var settings = GetConfiguration(svcname).Load();
+        if (settings != null)
         {
-            Logger.OnLog += MainLogger.Send;
-            //InABox.Logging.NamedPipeLogger.Start(CoreUtils.GetPath());
+            var server = settings.CreateServer(svcname);
 
-            var svcname = GetServiceName();
-            
-            var settings = GetConfiguration(svcname).Load();
-            if (settings != null)
-            {
-                var server = settings.CreateServer(svcname);
+            if (settings.Type == ServerType.Database)
+                _engine = new DatabaseEngine();
 
-                if (settings.Type == ServerType.Database)
-                    _engine = new DatabaseEngine();
+            else if (settings.Type == ServerType.GPS)
+                _engine = new GPSEngine();
 
-                else if (settings.Type == ServerType.GPS)
-                    _engine = new GPSEngine();
+            else if (settings.Type == ServerType.AutoDiscovery)
+                _engine = new AutoDiscoveryEngine();
 
-                else if (settings.Type == ServerType.AutoDiscovery)
-                    _engine = new AutoDiscoveryEngine();
+            else if (settings.Type == ServerType.Schedule)
+                _engine = new ScheduleEngine();
 
-                else if (settings.Type == ServerType.Schedule)
-                    _engine = new ScheduleEngine();
+            else if (settings.Type == ServerType.Web)
+                _engine = new WebEngine();
 
-                else if (settings.Type == ServerType.Web)
-                    _engine = new WebEngine();
+            else if (settings.Type == ServerType.Certificate)
+                _engine = new CertificateEngine();
 
-                else if (settings.Type == ServerType.Certificate)
-                    _engine = new CertificateEngine();
 
+            if (_engine != null)
+            {
+                _engine.ServiceName = svcname;
+                _engine.Version = CoreUtils.GetVersion();
+                _engine.Configure(server);
 
-                if (_engine != null)
+                /*_task = Task.Run(() =>
                 {
-                    _engine.ServiceName = svcname;
-                    _engine.Version = CoreUtils.GetVersion();
-                    _engine.Configure(server);
-
-                    /*_task = Task.Run(() =>
-                    {
-                        _engine.Run();
-                    }, Source.Token);*/
-
-                    _thread = new Thread(() => { _engine.Run(); });
-                    _thread.IsBackground = true;
-                    _thread.Start();
-                }
+                    _engine.Run();
+                }, Source.Token);*/
+
+                _thread = new Thread(() => { _engine.Run(); });
+                _thread.IsBackground = true;
+                _thread.Start();
             }
         }
+    }
 
-        protected override void OnStop()
-        {
-            Logger.Send(LogType.Information, "", "Shutting down Service: " + _servicename);
+    protected override void OnStop()
+    {
+        Logger.Send(LogType.Information, "", "Shutting down Service: " + _servicename);
 
-            _engine?.Stop();
-            /*var timer = new Timer { Interval = 1000 };
-            timer.Elapsed += (o, e) =>
+        _engine?.Stop();
+        /*var timer = new Timer { Interval = 1000 };
+        timer.Elapsed += (o, e) =>
+        {
+            try
             {
-                try
-                {
-                    Logger.Send(LogType.Information, "", "Terminating Process..");
-                    MainLogger.Stop();
-                    Environment.Exit(0);
-                }
-                catch (Exception err)
-                {
-                    Logger.Send(LogType.Error, "", "Exception while killing process: " + err.Message);
-                }
-            };
-            timer.AutoReset = false;
-            timer.Enabled = true;*/
-
-            Logger.Send(LogType.Information, "", "Terminating Process..");
-            MainLogger.Stop();
-        }
+                Logger.Send(LogType.Information, "", "Terminating Process..");
+                MainLogger.Stop();
+                Environment.Exit(0);
+            }
+            catch (Exception err)
+            {
+                Logger.Send(LogType.Error, "", "Exception while killing process: " + err.Message);
+            }
+        };
+        timer.AutoReset = false;
+        timer.Enabled = true;*/
+
+        Logger.Send(LogType.Information, "", "Terminating Process..");
+        MainLogger.Stop();
     }
 }