using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.ServiceProcess; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; using Comal.Classes; using Comal.Stores; using InABox.Client.IPC; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.Database; using InABox.Database.SQLite; using InABox.DynamicGrid; using InABox.IPC; using InABox.Wpf.Editors; using InABox.WPF; using PRSClasses; using PRSServer.Forms; using PRSServer.Forms.DatabaseLicense; using RestSharp; using Method = RestSharp.Method; namespace PRSServer { class ServerStartupSettings : BaseObject, ILocalConfigurationSettings { public List StartServers { get; set; } = new(); } public class ServerGrid : DynamicGrid { private Task? _monitor; private ConcurrentBag _services = new(); private Button _channelButton; private Button _statusButton; public ServerGrid() { Options.AddRange(DynamicGridOption.AddRows, DynamicGridOption.EditRows, DynamicGridOption.DeleteRows, DynamicGridOption.ShowHelp); 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); } private BitmapImage secureImage = Properties.Resources.secure.AsBitmapImage(); private BitmapImage insecureImage = Properties.Resources.insecure.AsBitmapImage(); private BitmapImage? SecureImage(CoreRow? row) { if(row is null) { return secureImage; } else { var key = row.Get(x => x.Key); if(SecureConnections.TryGetValue(key, out var secure)) { return secure ? secureImage : insecureImage; } else { return null; } } } private FrameworkElement? SecureToolTip(DynamicActionColumn column, CoreRow? row) { if(row is null) { return column.TextToolTip("Connection Security"); } else { var key = row.Get(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; } } } private DynamicMenuStatus ServerMenuStatus(CoreRow arg) { if (arg == null) return DynamicMenuStatus.Hidden; var type = arg.Get(x => x.Type); var service = GetService(arg.Get(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; } private void CreateServerMenu(DynamicMenuColumn column, CoreRow? row) { if (row == null) return; var status = ServerMenuStatus(row); if (status == DynamicMenuStatus.Hidden) return; var type = row.Get(x => x.Type); var key = row.Get(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)) { 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) { return _services.FirstOrDefault(x => string.Equals(x.ServiceName, key)); } protected override void ShowHelp(string slug) { base.ShowHelp("Server_Configuration"); } public void BeforeUpdate() { var sections = PRSService.GetConfiguration().LoadAll(); RefreshServices(sections); var closed = new List(); foreach (var service in _services) { if(service.Status == ServiceControllerStatus.Running) { service.Stop(); closed.Add(service.ServiceName); } } var config = PRSService.GetConfiguration(); var startupSettings = config.Load(); startupSettings.StartServers = closed; config.Save(startupSettings); } #region Grid Handling private void RefreshServices(Dictionary sections) { Interlocked.Exchange( ref _services, new ConcurrentBag( ServiceController.GetServices().Where(x => sections.ContainsKey(x.ServiceName)) ) ); } private Dictionary SecureConnections { get; set; } = new Dictionary(); private HashSet LoadingInfos = new HashSet(); protected override void Reload(Filters criteria, Columns columns, ref SortOrder? sort, Action action) { var table = new CoreTable(); table.LoadColumns(typeof(Server)); var sections = PRSService.GetConfiguration().LoadAll(); RefreshServices(sections); var startupConfig = PRSService.GetConfiguration(); 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); } if (table.Rows.Any(x => x.Get(x => x.Type) == ServerType.Certificate)) { foreach (var row in table.Rows.Where(x => x.Get(x => x.Type) == ServerType.Web)) { var key = row.Get(x => x.Key); var props = row.ToObject().Properties as WebServerProperties; if (props != null) { Task.Run(() => { bool IsHTTPs = false; var client = new HttpClient { BaseAddress = new Uri($"https://127.0.0.1:{props.ListenPort}") }; try { client.GetAsync("/").Wait(); SecureConnections[key] = true; } catch (Exception e) { System.Console.WriteLine(e); throw; } // try // { // client.GetAsync("operations").Wait(); // URL = $"https://{url}"; // isHTTPS = true; // } // catch (Exception) // { // URL = $"http://{url}"; // isHTTPS = false; // } // } // return URL; }); } } foreach (var row in table.Rows.Where(x => x.Get(x => x.Type) == ServerType.Database)) { var key = row.Get(x => x.Key); var service = GetService(key); if (service is not null && service.Status == ServiceControllerStatus.Running) { if (!LoadingInfos.Contains(key)) { LoadingInfos.Add(key); Task.Run(() => { while (true) { var client = IPCClientFactory.GetClient(DatabaseServerProperties.GetPipeName(key)); var response = client.Send(IPCMessage.Info(new InfoRequest()), 10_000).GetResponse(); if (response.Status != StatusCode.Error) { SecureConnections[key] = response.Info.IsHTTPS; break; } else { SecureConnections.Remove(key); var service = GetService(key); if (service is null || service.Status != ServiceControllerStatus.Running) break; } } Dispatcher.Invoke(() => { InvalidateRow(row); }); LoadingInfos.Remove(key); }); } } else { if(SecureConnections.TryGetValue(key, out var info)) { SecureConnections.Remove(key); } } } } action(table, null); _monitor ??= Task.Run(() => { while (true) { try { var bRefresh = false; foreach (var service in _services) { var oldstatus = service.Status; service.Refresh(); bRefresh = bRefresh || service.Status != oldstatus; /*if ((oldstatus != ServiceControllerStatus.Stopped) && (service.Status == ServiceControllerStatus.Stopped)) Dispatcher.Invoke(() => StopConsole(service.ServiceName));*/ } if (bRefresh) Dispatcher.Invoke(() => { Refresh(false, true); }); } catch (Exception e) { } Task.Delay(500).Wait(); } }); } // protected override void SelectItems(CoreRow[] rows) // { // base.SelectItems(rows); // if (rows != null && rows.Length == 1) // { // var type = rows.First().Get(x => x.Type); // DatabaseLicense.Visibility = Equals(type, ServerType.Database) ? Visibility.Visible : Visibility.Collapsed; // DatabaseCustomFields.Visibility = Equals(type, ServerType.Database) ? Visibility.Visible : Visibility.Collapsed; // DatabaseScripts.Visibility = Equals(type, ServerType.Database) ? Visibility.Visible : Visibility.Collapsed; // // EditWebSettings.Visibility = Equals(type, ServerType.Web) ? Visibility.Visible : Visibility.Collapsed; // // ScheduledScripts.Visibility = type == ServerType.Schedule ? Visibility.Visible : Visibility.Collapsed; // } // else // { // EditWebSettings.Visibility = Visibility.Collapsed; // DatabaseLicense.Visibility = Visibility.Collapsed; // DatabaseCustomFields.Visibility = Visibility.Collapsed; // DatabaseScripts.Visibility = Visibility.Collapsed; // ScheduledScripts.Visibility = Visibility.Collapsed; // } // } protected override Server LoadItem(CoreRow row) { var key = row.Get(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); } }; parent.Items.Add(menu); } 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(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(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; 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)) { server.Name = server.Properties.Name; SaveItem(server); Refresh(false, true); } } 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); } protected override bool CanDeleteItems(params CoreRow[] rows) { var bOK = true; foreach (var row in rows) { var service = GetService(row.Get(x => x.Key)); if (service != null && service.Status != ServiceControllerStatus.Stopped) bOK = false; } return bOK; } protected override void DeleteItems(params CoreRow[] rows) { foreach (var row in rows) { var key = row.Get(x => x.Key); Interlocked.Exchange( ref _services, new ConcurrentBag( _services.Where(x => !string.Equals(x.ServiceName, key)) ) ); PRSService.GetConfiguration(key).Delete(); var serverType = row.Get(x => x.Type); if (serverType == ServerType.Certificate) { if (File.Exists(CertificateEngine.CertificateFile)) { File.Delete(CertificateEngine.CertificateFile); } } PRSServiceInstaller.UninstallService(key); } } protected override void DefineLookups(ILookupEditorControl sender, Server[] items) { if(sender.EditorDefinition is ComboLookupEditor lookup && lookup.Type == typeof(DatabaseServerLookupGenerator)) { base.DefineLookups(sender, Data.Rows.Select(x => x.ToObject()).ToArray()); } else { base.DefineLookups(sender, items); } } #endregion #region Server Configuration private bool EditUpdateChannel_Click(Button arg1, CoreRow[] arg2) { var settings = new LocalConfiguration().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 }; if (propertyEditor.ShowDialog() == true) { settings.FromEditable(editable); new LocalConfiguration().Save(settings); } return false; } private BaseEditor? PropertyEditor_OnDefineEditor(object item, DynamicGridColumn column) { if (string.Equals(column.ColumnName, "Elevated")) return new NullEditor(); 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; string? password = null; if (!string.IsNullOrWhiteSpace(username)) { var passwordEditor = new PasswordDialog(string.Format("Enter password for {0}", username)); if(passwordEditor.ShowDialog() == true) { password = passwordEditor.Password; } else { password = null; } } else { username = 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) { var pages = new DynamicEditorPages(); if (type == typeof(DatabaseServerProperties)) { pages.Add(new SMSProviderGrid(!enabled)); } 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); if(type == typeof(DatabaseServerProperties)) { propertyEditor.OnSaveItem += (o, e) => { propertyEditor.UnloadEditorPages(false); propertyEditor.UnloadEditorPages(true); }; } propertyEditor.ReadOnly = !enabled; propertyEditor.OnDefineLookups += sender => DefineLookups(sender, new Server[] { }); propertyEditor.Items = new BaseObject[] { item }; return propertyEditor.ShowDialog() == true; } #endregion #region Service Start / Stop Actions private readonly Dictionary _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 service = GetService(arg.Get(c => c.Key)); var 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(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(c => c.Key); var service = GetService(arg.Get(c => c.Key)); if (service != null) { Task? task; if (service.Status == ServiceControllerStatus.Running) { task = Task.Run(() => { service.Stop(); }); //StopConsole(key); } else if (service.Status == ServiceControllerStatus.Stopped) { task = Task.Run(() => { service.Start(); }); StartConsole(arg,key); } else if (service.Status == ServiceControllerStatus.Paused) { task = Task.Run(() => { service.Continue(); }); } else { MessageBox.Show(string.Format("Invalid Service State ({0})", service.Status.ToString())); return false; } task?.ContinueWith((e) => { if (e.Exception?.InnerException is { } inner) { 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(x => x.Key)); Refresh(false, true); } }, TaskScheduler.FromCurrentSynchronizationContext()); return true; } MessageBox.Show("Cannot find Service - is it installed?"); return false; } public void StopAll() { foreach (var service in _services.ToArray()) if (service.Status == ServiceControllerStatus.Running) Task.Run(() => { service.Stop(); }); } #endregion #region Server Type Images private readonly Dictionary _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(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(c => c.Type).ToString(), arg2.Get(c => c.Key) )); } #endregion #region Console Functions private BitmapImage? ConsoleImage(CoreRow? arg) { if (arg == null) return Properties.Resources.target.AsBitmapImage(); var service = GetService(arg.Get(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(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> _consoles = new Dictionary>(); private void StartConsole(CoreRow arg, string key) { if (_consoles.ContainsKey(key)) return; var name = arg.Get(c => c.Name); var console = new Console(key, string.Format("{0} - {1}", key, name)); var window = Window.GetWindow(this); int i = 0; while (_consoles.Any(x => x.Value.Item2 == i)) i++; _consoles[key] = new Tuple(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 StopConsole(String key) { if (!_consoles.ContainsKey(key)) return; Console console = _consoles[key].Item1; console.Close(); } #endregion #region Individual Server Buttons // 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 }; try { var res = cli.Execute(req); if (res.StatusCode != HttpStatusCode.OK || res.ErrorException != null) return false; return true; } catch (Exception e) { } return false; } // 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; /// /// Configures a server for the duration of an action /// /// /// /// /// /// /// /// If blocking is set to false, then currentServerUsers must be decreased by one manually once the /// task finishes /// private void ConfigureServer( CoreRow row, Func hostaddress, Func portnumber, Action action, bool blocking = true ) where TProperties : ServerProperties { try { if (row == null) throw new Exception("No Row Selected!"); 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 url = hostaddress(props); var port = portnumber(props); using (new WaitCursor()) { if (!IsDatabaseServerRunning(url, port)) throw new Exception("Database Server is not available!"); } if (action != null) { if (currentServerUsers == 0) { if (currentServerURL != url || currentServerPort != port) { ConfigurationCache.ClearAll(ConfigurationCacheType.Global); ConfigurationCache.ClearAll(ConfigurationCacheType.User); } 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(); } 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( CoreRow row, Func hostPipeName, Action action, bool blocking = true ) where TProperties : ServerProperties { try { if (row == null) throw new Exception("No Row Selected!"); 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 pipeName = DatabaseServerProperties.GetPipeName(hostPipeName(props)); if (action != null) { if (currentServerUsers == 0) { if (currentServerName != pipeName) { 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()) { if (!Client.Ping()) { 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--; } } } 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); if (server == null) throw new Exception("Unable to load Server!"); var properties = server.Properties as DatabaseServerProperties; if (properties == null) 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) => { 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; PurchaseOrderStore.AutoIncrementPrefix = properties.PurchaseOrderPrefix; JobStore.AutoIncrementPrefix = properties.JobPrefix; }); } action(); } catch(Exception e) { Logger.Send(LogType.Error, "", CoreUtils.FormatException(e)); MessageBox.Show(e.Message); } } private bool UpdateDatabaseLicense(CoreRow selectedrow) { ConfigureIPCServer( selectedrow, //x => "http://127.0.0.1", //x => x.Port, x => selectedrow.Get(x => x.Key), () => { new LicenseRenewalForm().ShowDialog(); } ); return false; } private bool ManageDeletions(CoreRow row) { ConfigureLocalDatabase(row, () => { new DeletionsWindow().ShowDialog(); }); return false; } private bool EditCustomFields(CoreRow selectedrow) { ConfigureIPCServer( selectedrow, //x => "http://127.0.0.1", //x => x.Port, x => selectedrow.Get(x => x.Key), () => { new MasterList(typeof(CustomProperty), "Class", null, true).ShowDialog(); } ); return false; } private bool EditDatabaseScripts(CoreRow selectedrow) { ConfigureIPCServer( selectedrow, //x => "http://127.0.0.1", //x => x.Port, x => selectedrow.Get(x => x.Key), () => { new MasterList(typeof(Script), "Section", null, true).ShowDialog(); } ); return false; } private bool EditScheduledScripts(CoreRow selectedrow) { ConfigureIPCServer( selectedrow, x => x.Server, () => { new MasterList(typeof(ScheduledScript), "", null, true, typeof(ScheduledScriptsGrid)).ShowDialog(); } ); return false; } private bool EditWebTemplates(CoreRow selectedRow) { ConfigureIPCServer( selectedRow, x => x.Server, () => { var window = new MasterList(typeof(WebTemplate), "DataModel", "", true); window.Closed += (e, args) => { currentServerUsers--; }; window.Show(); }, false ); return false; } private bool EditWebStyles(CoreRow selectedRow) { ConfigureIPCServer( selectedRow, x => x.Server, () => { var window = new MasterList(typeof(WebStyle), "Code", "", true); window.Closed += (e, args) => { currentServerUsers--; }; window.Show(); }, false ); return false; } private bool EditWebDocuments(CoreRow selectedRow) { ConfigureIPCServer( selectedRow, x => x.Server, () => { var window = new MasterList(typeof(WebDocument), "Code", "", true); window.Closed += (e, args) => { currentServerUsers--; }; window.Show(); }, false ); return false; } private bool PRSMobileSettings(CoreRow selectedrow) { ConfigureIPCServer( selectedrow, x => x.Server, () => { var editor = new DynamicEditorForm(typeof(WebSettings)); var settings = new GlobalConfiguration().Load(); editor.Items = new[] { settings }; if (editor.ShowDialog() == true) new GlobalConfiguration().Save(settings); } ); return false; } private bool ShowServiceStatus(Button arg1, CoreRow[] arg2) { List domains = new List(); var certservers = Data.Rows.Where(row => row.Get(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()); } if (!domains.Any()) domains.Add("localhost"); var servers = Data.Rows.Where(row => row.Get(c=>c.Type) != ServerType.Certificate) .Select(row => LoadItem(row)); var statusgrid = new ServiceStatus(domains, servers); statusgrid.ShowDialog(); return false; } #endregion } }