ServerGrid.cs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Reflection;
  9. using System.Security.Policy;
  10. using System.ServiceProcess;
  11. using System.Threading;
  12. using System.Threading.Tasks;
  13. using System.Windows;
  14. using System.Windows.Controls;
  15. using System.Windows.Media.Imaging;
  16. using Comal.Classes;
  17. using Comal.Stores;
  18. using H.Pipes.Extensions;
  19. using InABox.Client.IPC;
  20. using InABox.Clients;
  21. using InABox.Configuration;
  22. using InABox.Core;
  23. using InABox.Database;
  24. using InABox.Database.SQLite;
  25. using InABox.DeviceIdentifier;
  26. using InABox.DynamicGrid;
  27. using InABox.Scripting;
  28. using InABox.Wpf.Editors;
  29. using InABox.WPF;
  30. using PRSClasses;
  31. using PRSServer.Forms;
  32. using PRSServer.Forms.DatabaseLicense;
  33. using RestSharp;
  34. using Method = RestSharp.Method;
  35. namespace PRSServer
  36. {
  37. class ServerStartupSettings : BaseObject, LocalConfigurationSettings
  38. {
  39. public List<string> StartServers { get; set; } = new();
  40. }
  41. public class ServerGrid : DynamicGrid<Server>
  42. {
  43. private Task? _monitor;
  44. private ConcurrentBag<ServiceController> _services = new();
  45. private Button _channelButton;
  46. public ServerGrid()
  47. {
  48. Options.AddRange(DynamicGridOption.AddRows, DynamicGridOption.EditRows, DynamicGridOption.DeleteRows, DynamicGridOption.ShowHelp);
  49. ActionColumns.Add(new DynamicImageColumn(TypeImage)
  50. { Position = DynamicActionColumnPosition.Start, ToolTip = TypeToolTip });
  51. ActionColumns.Add(new DynamicImageColumn(StateImage, StateAction)
  52. { Position = DynamicActionColumnPosition.End, ToolTip = StateToolTip });
  53. //ActionColumns.Add(new DynamicImageColumn(ConsoleImage, ConsoleAction)
  54. // { Position = DynamicActionColumnPosition.End, ToolTip = StateToolTip });
  55. ActionColumns.Add(new DynamicMenuColumn(CreateServerMenu,ServerMenuStatus)
  56. { Position = DynamicActionColumnPosition.End, ToolTip = MenuToolTip });
  57. RowHeight = 40;
  58. FontSize = 14;
  59. _channelButton = AddButton("", Properties.Resources.autoupdate.AsBitmapImage(), "Change Update Channel", EditUpdateChannel_Click);
  60. }
  61. private DynamicMenuStatus ServerMenuStatus(CoreRow arg)
  62. {
  63. if (arg == null)
  64. return DynamicMenuStatus.Hidden;
  65. var type = arg.Get<Server, ServerType>(x => x.Type);
  66. var service = GetService(arg.Get<Server, string>(c => c.Key));
  67. var running = service?.Status == ServiceControllerStatus.Running;
  68. if ((type == ServerType.Database) || (type == ServerType.Web) || (type == ServerType.Schedule))
  69. {
  70. return running
  71. ? DynamicMenuStatus.Enabled
  72. : DynamicMenuStatus.Disabled;
  73. }
  74. return running
  75. ? DynamicMenuStatus.Enabled
  76. : DynamicMenuStatus.Hidden;
  77. }
  78. private void CreateServerMenu(DynamicMenuColumn column, CoreRow? row)
  79. {
  80. if (row == null)
  81. return;
  82. var status = ServerMenuStatus(row);
  83. if (status == DynamicMenuStatus.Hidden)
  84. return;
  85. var type = row.Get<Server, ServerType>(x => x.Type);
  86. var key = row.Get<Server, String>(x => x.Key);
  87. column.AddItem(
  88. "View Console",
  89. Properties.Resources.target,
  90. (row) => StartConsole(row, key),
  91. null,
  92. status == DynamicMenuStatus.Enabled && !_consoles.ContainsKey(key)
  93. );
  94. if (type.Equals(ServerType.Database))
  95. {
  96. column.AddSeparator();
  97. column.AddItem(
  98. "Custom Fields",
  99. Properties.Resources.service,
  100. (row) => EditCustomFields(row),
  101. null,
  102. status == DynamicMenuStatus.Enabled
  103. );
  104. column.AddItem(
  105. "Database Scripts",
  106. Properties.Resources.script,
  107. (row) => EditDatabaseScripts(row),
  108. null,
  109. status == DynamicMenuStatus.Enabled
  110. );
  111. column.AddSeparator();
  112. column.AddItem(
  113. "Update License",
  114. Properties.Resources.key,
  115. (row) => UpdateDatabaseLicense(row),
  116. null,
  117. status == DynamicMenuStatus.Enabled
  118. );
  119. column.AddSeparator();
  120. column.AddItem(
  121. "Manage Deletions",
  122. Properties.Resources.delete,
  123. (row) => ManageDeletions(row),
  124. null,
  125. status == DynamicMenuStatus.Enabled
  126. );
  127. }
  128. else if (type.Equals(ServerType.Web))
  129. {
  130. column.AddSeparator();
  131. column.AddItem(
  132. "Edit Templates",
  133. Properties.Resources.script,
  134. (row) => EditWebTemplates(row),
  135. null,
  136. status == DynamicMenuStatus.Enabled
  137. );
  138. column.AddItem(
  139. "Edit Styles",
  140. Properties.Resources.css,
  141. (row) => EditWebStyles(row),
  142. null,
  143. status == DynamicMenuStatus.Enabled
  144. );
  145. column.AddItem(
  146. "Edit Documents",
  147. Properties.Resources.pdf,
  148. (row) => EditWebDocuments(row),
  149. null,
  150. status == DynamicMenuStatus.Enabled
  151. );
  152. column.AddSeparator();
  153. column.AddItem(
  154. "PRS Mobile Settings",
  155. Properties.Resources.web,
  156. (row) => PRSMobileSettings(row),
  157. null,
  158. status == DynamicMenuStatus.Enabled
  159. );
  160. }
  161. else if (type.Equals(ServerType.Schedule))
  162. {
  163. column.AddSeparator();
  164. column.AddItem(
  165. "Scheduled Scripts",
  166. Properties.Resources.script,
  167. (row) => EditScheduledScripts(row),
  168. null,
  169. status == DynamicMenuStatus.Enabled
  170. );
  171. }
  172. }
  173. private ServiceController? GetService(string key)
  174. {
  175. return _services.FirstOrDefault(x => string.Equals(x.ServiceName, key));
  176. }
  177. protected override void ShowHelp(string slug)
  178. {
  179. base.ShowHelp("Server_Configuration");
  180. }
  181. public void BeforeUpdate()
  182. {
  183. var sections = PRSService.GetConfiguration().LoadAll();
  184. RefreshServices(sections);
  185. var closed = new List<string>();
  186. foreach (var service in _services)
  187. {
  188. if(service.Status == ServiceControllerStatus.Running)
  189. {
  190. service.Stop();
  191. closed.Add(service.ServiceName);
  192. }
  193. }
  194. var config = PRSService.GetConfiguration<ServerStartupSettings>();
  195. var startupSettings = config.Load();
  196. startupSettings.StartServers = closed;
  197. config.Save(startupSettings);
  198. }
  199. #region Grid Handling
  200. private void RefreshServices(Dictionary<string, ServerSettings> sections)
  201. {
  202. Interlocked.Exchange(
  203. ref _services,
  204. new ConcurrentBag<ServiceController>(
  205. ServiceController.GetServices().Where(x => sections.ContainsKey(x.ServiceName))
  206. )
  207. );
  208. }
  209. protected override void Reload(Filters<Server> criteria, Columns<Server> columns, ref SortOrder<Server>? sort,
  210. Action<CoreTable?, Exception?> action)
  211. {
  212. var table = new CoreTable();
  213. table.LoadColumns(typeof(Server));
  214. var sections = PRSService.GetConfiguration().LoadAll();
  215. RefreshServices(sections);
  216. var startupConfig = PRSService.GetConfiguration<ServerStartupSettings>();
  217. var startupSettings = startupConfig.Load();
  218. foreach (var startup in startupSettings.StartServers)
  219. {
  220. _services.FirstOrDefault(x => x.ServiceName == startup)?.Start();
  221. }
  222. startupSettings.StartServers.Clear();
  223. startupConfig.Save(startupSettings);
  224. foreach (var section in sections.OrderBy(x => x.Value.Type))
  225. {
  226. var server = section.Value.CreateServer(section.Key);
  227. var service = _services.FirstOrDefault(x => string.Equals(x.ServiceName, section.Key));
  228. var row = table.NewRow();
  229. table.LoadRow(row, server);
  230. table.Rows.Add(row);
  231. }
  232. action(table, null);
  233. if (_monitor == null)
  234. _monitor = Task.Run(() =>
  235. {
  236. while (true)
  237. {
  238. try
  239. {
  240. var bRefresh = false;
  241. foreach (var service in _services)
  242. {
  243. var oldstatus = service.Status;
  244. service.Refresh();
  245. bRefresh = bRefresh || service.Status != oldstatus;
  246. /*if ((oldstatus != ServiceControllerStatus.Stopped) && (service.Status == ServiceControllerStatus.Stopped))
  247. Dispatcher.Invoke(() => StopConsole(service.ServiceName));*/
  248. }
  249. if (bRefresh)
  250. Dispatcher.Invoke(() => { Refresh(false, true); });
  251. }
  252. catch (Exception e)
  253. {
  254. }
  255. Task.Delay(500).Wait();
  256. }
  257. });
  258. }
  259. // protected override void SelectItems(CoreRow[] rows)
  260. // {
  261. // base.SelectItems(rows);
  262. // if (rows != null && rows.Length == 1)
  263. // {
  264. // var type = rows.First().Get<Server, ServerType>(x => x.Type);
  265. // DatabaseLicense.Visibility = Equals(type, ServerType.Database) ? Visibility.Visible : Visibility.Collapsed;
  266. // DatabaseCustomFields.Visibility = Equals(type, ServerType.Database) ? Visibility.Visible : Visibility.Collapsed;
  267. // DatabaseScripts.Visibility = Equals(type, ServerType.Database) ? Visibility.Visible : Visibility.Collapsed;
  268. //
  269. // EditWebSettings.Visibility = Equals(type, ServerType.Web) ? Visibility.Visible : Visibility.Collapsed;
  270. //
  271. // ScheduledScripts.Visibility = type == ServerType.Schedule ? Visibility.Visible : Visibility.Collapsed;
  272. // }
  273. // else
  274. // {
  275. // EditWebSettings.Visibility = Visibility.Collapsed;
  276. // DatabaseLicense.Visibility = Visibility.Collapsed;
  277. // DatabaseCustomFields.Visibility = Visibility.Collapsed;
  278. // DatabaseScripts.Visibility = Visibility.Collapsed;
  279. // ScheduledScripts.Visibility = Visibility.Collapsed;
  280. // }
  281. // }
  282. protected override Server LoadItem(CoreRow row)
  283. {
  284. var key = row.Get<Server, string>(x => x.Key);
  285. var settings = PRSService.GetConfiguration(key).Load();
  286. return settings.CreateServer(key);
  287. }
  288. private string CreateKey(ServerType type)
  289. {
  290. var services = ServiceController.GetServices();
  291. var key = string.Format("PRS{0}", type.ToString());
  292. var i = 1;
  293. while (services.Any(x => string.Equals(key, x.ServiceName)))
  294. key = string.Format("PRS{0}_{1}", type.ToString(), i++);
  295. return key;
  296. }
  297. private void CreateMenu(ContextMenu parent, string header, ServerType server, Type properties)
  298. {
  299. var menu = new MenuItem();
  300. menu.Header = header;
  301. menu.Tag = properties;
  302. menu.Icon = new Image() { Source = _typeimages[server] };
  303. menu.IsCheckable = false;
  304. menu.Click += (o, e) =>
  305. {
  306. var itemtype = ((o as MenuItem)?.Tag as Type)!;
  307. var props = (Activator.CreateInstance(itemtype) as ServerProperties)!;
  308. if (EditProperties(properties, props, true))
  309. {
  310. var server = CreateItem();
  311. server.Key = CreateKey(props.Type());
  312. server.Type = props.Type();
  313. server.Properties = props;
  314. SaveItem(server);
  315. Refresh(false, true);
  316. }
  317. };
  318. parent.Items.Add(menu);
  319. }
  320. protected override void DoAdd(bool OpenEditorOnDirectEdit = false)
  321. {
  322. var menu = new ContextMenu();
  323. CreateMenu(menu, "Database", ServerType.Database, typeof(DatabaseServerProperties));
  324. CreateMenu(menu, "GPS Connector", ServerType.GPS, typeof(GPSServerProperties));
  325. if (!Data.Rows.Any(r => r.Get<Server, ServerType>(c => c.Type) == ServerType.AutoDiscovery))
  326. CreateMenu(menu, "Auto Discovery", ServerType.AutoDiscovery, typeof(AutoDiscoveryServerProperties));
  327. CreateMenu(menu, "Scheduler", ServerType.Schedule, typeof(ScheduleServerProperties));
  328. CreateMenu(menu, "Web Service", ServerType.Web, typeof(WebServerProperties));
  329. if (!Data.Rows.Any(r => r.Get<Server, ServerType>(c => c.Type) == ServerType.Certificate))
  330. CreateMenu(menu, "HTTPS Certificate Engine", ServerType.Certificate, typeof(CertificateEngineProperties));
  331. menu.IsOpen = true;
  332. }
  333. protected override void DoEdit()
  334. {
  335. if (!SelectedRows.Any())
  336. return;
  337. var server = LoadItem(SelectedRows.First());
  338. var service = GetService(server.Key);
  339. var enabled = service == null || service.Status == ServiceControllerStatus.Stopped;
  340. if (EditProperties(server.Properties.GetType(), server.Properties, enabled))
  341. {
  342. server.Name = server.Properties.Name;
  343. SaveItem(server);
  344. Refresh(false, true);
  345. }
  346. }
  347. public override void SaveItem(Server item)
  348. {
  349. var settings = new ServerSettings();
  350. settings.Type = item.Type;
  351. settings.Properties = Serialization.Serialize(item.Properties, false);
  352. PRSService.GetConfiguration(item.Key).Save(settings);
  353. ReconfigureService(item);
  354. }
  355. private bool isServiceChanged(Server server, ServiceController? service, string newDisplayName)
  356. {
  357. return newDisplayName != service?.DisplayName || (server.Properties.HasOriginalValue(x => x.Username) && server.Properties.GetOriginalValue(x => x.Username) != server.Properties.Username);
  358. }
  359. protected override bool CanDeleteItems(params CoreRow[] rows)
  360. {
  361. var bOK = true;
  362. foreach (var row in rows)
  363. {
  364. var service = GetService(row.Get<Server, string>(x => x.Key));
  365. if (service != null && service.Status != ServiceControllerStatus.Stopped)
  366. bOK = false;
  367. }
  368. return bOK;
  369. }
  370. protected override void DeleteItems(params CoreRow[] rows)
  371. {
  372. foreach (var row in rows)
  373. {
  374. var key = row.Get<Server, string>(x => x.Key);
  375. Interlocked.Exchange(
  376. ref _services,
  377. new ConcurrentBag<ServiceController>(
  378. _services.Where(x => !string.Equals(x.ServiceName, key))
  379. )
  380. );
  381. PRSService.GetConfiguration(key).Delete();
  382. var serverType = row.Get<Server, ServerType>(x => x.Type);
  383. if (serverType == ServerType.Certificate)
  384. {
  385. if (File.Exists(CertificateEngine.CertificateFile))
  386. {
  387. File.Delete(CertificateEngine.CertificateFile);
  388. }
  389. }
  390. PRSServiceInstaller.UninstallService(key);
  391. }
  392. }
  393. protected override void DefineLookups(ILookupEditorControl sender, Server[] items)
  394. {
  395. if(sender.EditorDefinition is ComboLookupEditor lookup && lookup.Type == typeof(DatabaseServerLookupGenerator))
  396. {
  397. base.DefineLookups(sender, Data.Rows.Select(x => x.ToObject<Server>()).ToArray());
  398. }
  399. else
  400. {
  401. base.DefineLookups(sender, items);
  402. }
  403. }
  404. #endregion
  405. #region Server Configuration
  406. private bool EditUpdateChannel_Click(Button arg1, CoreRow[] arg2)
  407. {
  408. var settings = new LocalConfiguration<AutoUpdateSettings>().Load();
  409. var editable = settings.ToEditable();
  410. var buttons = new DynamicEditorButtons()
  411. {
  412. new DynamicEditorButton(
  413. "",
  414. Properties.Resources.help.AsBitmapImage(),
  415. null,
  416. (o, e) => base.ShowHelp("Automatic_Updates"))
  417. };
  418. var propertyEditor = new DynamicEditorForm(typeof(EditableAutoUpdateSettings), null, buttons);
  419. propertyEditor.OnDefineEditor += PropertyEditor_OnDefineEditor;
  420. propertyEditor.OnDefineLookups += sender => DefineLookups(sender, new Server[] { });
  421. propertyEditor.Items = new BaseObject[] { editable };
  422. if (propertyEditor.ShowDialog() == true)
  423. {
  424. settings.FromEditable(editable);
  425. new LocalConfiguration<AutoUpdateSettings>().Save(settings);
  426. }
  427. return false;
  428. }
  429. private BaseEditor? PropertyEditor_OnDefineEditor(object item, DynamicGridColumn column)
  430. {
  431. if (string.Equals(column.ColumnName, "Elevated"))
  432. return new NullEditor();
  433. var result = GetEditor(item, column);
  434. if (result != null)
  435. result = result.CloneEditor();
  436. return result;
  437. }
  438. private void ReconfigureService(Server item)
  439. {
  440. var service = GetService(item.Key);
  441. var newDisplayName = "PRS - " + item.Properties.Name;
  442. string? username = item.Properties.Username;
  443. if (!isServiceChanged(item, service, newDisplayName)) return;
  444. string? password = null;
  445. if (!string.IsNullOrWhiteSpace(username))
  446. {
  447. var passwordEditor = new PasswordDialog(string.Format("Enter password for {0}", username));
  448. if(passwordEditor.ShowDialog() == true)
  449. {
  450. password = passwordEditor.Password;
  451. }
  452. else
  453. {
  454. password = null;
  455. }
  456. }
  457. else
  458. {
  459. username = null;
  460. }
  461. if (service == null)
  462. try
  463. {
  464. using (new WaitCursor())
  465. {
  466. PRSServiceInstaller.InstallService(
  467. item.Key,
  468. item.Properties.Name,
  469. newDisplayName,
  470. username,
  471. password
  472. );
  473. }
  474. }
  475. catch (Exception e)
  476. {
  477. MessageBox.Show(string.Format("Error Installing {0}: {1}", item.Key, e.Message));
  478. }
  479. else
  480. try
  481. {
  482. using (new WaitCursor())
  483. {
  484. PRSServiceInstaller.ChangeService(
  485. item.Key,
  486. item.Properties.Name,
  487. newDisplayName,
  488. username,
  489. password
  490. );
  491. }
  492. }
  493. catch (Exception e)
  494. {
  495. MessageBox.Show(string.Format("Error Configuring {0}: {1}", item.Key, e.Message));
  496. }
  497. }
  498. public bool EditProperties(Type type, ServerProperties item, bool enabled)
  499. {
  500. var pages = new DynamicEditorPages();
  501. if (type == typeof(DatabaseServerProperties))
  502. {
  503. pages.Add(new SMSProviderGrid(!enabled));
  504. }
  505. var buttons = new DynamicEditorButtons();
  506. buttons.Add(
  507. "",
  508. Properties.Resources.help.AsBitmapImage(),
  509. item,
  510. (f, i) =>
  511. {
  512. Process.Start(new ProcessStartInfo("https://prsdigital.com.au/wiki/index.php/" + type.Name.SplitCamelCase().Replace(" ", "_"))
  513. { UseShellExecute = true });
  514. }
  515. );
  516. var propertyEditor = new DynamicEditorForm(type, pages, buttons);
  517. if(type == typeof(DatabaseServerProperties))
  518. {
  519. propertyEditor.OnSaveItem += (o, e) =>
  520. {
  521. propertyEditor.UnloadEditorPages(false);
  522. propertyEditor.UnloadEditorPages(true);
  523. };
  524. }
  525. propertyEditor.ReadOnly = !enabled;
  526. propertyEditor.OnDefineLookups += sender => DefineLookups(sender, new Server[] { });
  527. propertyEditor.Items = new BaseObject[] { item };
  528. return propertyEditor.ShowDialog() == true;
  529. }
  530. #endregion
  531. #region Service Start / Stop Actions
  532. private readonly Dictionary<int, BitmapImage> _stateimages = new()
  533. {
  534. { 0, Properties.Resources.warning.AsBitmapImage() },
  535. { (int)ServiceControllerStatus.Stopped, Properties.Resources.pause.AsBitmapImage() },
  536. { (int)ServiceControllerStatus.StartPending, Properties.Resources.working.AsBitmapImage() },
  537. { (int)ServiceControllerStatus.StopPending, Properties.Resources.working.AsBitmapImage() },
  538. { (int)ServiceControllerStatus.Running, Properties.Resources.tick.AsBitmapImage() },
  539. { (int)ServiceControllerStatus.ContinuePending, Properties.Resources.working.AsBitmapImage() },
  540. { (int)ServiceControllerStatus.PausePending, Properties.Resources.working.AsBitmapImage() },
  541. { (int)ServiceControllerStatus.Paused, Properties.Resources.pause.AsBitmapImage() }
  542. };
  543. private BitmapImage StateImage(CoreRow? arg)
  544. {
  545. if (arg == null)
  546. return Properties.Resources.tick.AsBitmapImage();
  547. var service = GetService(arg.Get<Server, string>(c => c.Key));
  548. var state = service != null ? (int)service.Status : 0;
  549. return _stateimages[state];
  550. }
  551. private FrameworkElement? StateToolTip(DynamicActionColumn arg1, CoreRow? arg2)
  552. {
  553. if (arg2 == null)
  554. return null;
  555. var service = GetService(arg2.Get<Server, string>(c => c.Key));
  556. return arg1.TextToolTip(service != null ? "Current State: " + service.Status : "Not Installed");
  557. }
  558. private FrameworkElement? MenuToolTip(DynamicActionColumn arg1, CoreRow? arg2)
  559. {
  560. return arg2 != null ? arg1.TextToolTip("Server Options") : null;
  561. }
  562. private bool StateAction(CoreRow? arg)
  563. {
  564. if (arg == null)
  565. return false;
  566. var key = arg.Get<Server, string>(c => c.Key);
  567. var service = GetService(arg.Get<Server, string>(c => c.Key));
  568. if (service != null)
  569. {
  570. Task? task;
  571. if (service.Status == ServiceControllerStatus.Running)
  572. {
  573. task = Task.Run(() => { service.Stop(); });
  574. //StopConsole(key);
  575. }
  576. else if (service.Status == ServiceControllerStatus.Stopped)
  577. {
  578. task = Task.Run(() => {
  579. service.Start();
  580. });
  581. StartConsole(arg,key);
  582. }
  583. else if (service.Status == ServiceControllerStatus.Paused)
  584. {
  585. task = Task.Run(() => { service.Continue(); });
  586. }
  587. else
  588. {
  589. MessageBox.Show(string.Format("Invalid Service State ({0})", service.Status.ToString()));
  590. return false;
  591. }
  592. task?.ContinueWith((e) =>
  593. {
  594. if (e.Exception?.InnerException is { } inner)
  595. {
  596. if(inner.InnerException != null)
  597. {
  598. MessageBox.Show(String.Format("Error while running service:\n{0}", inner.InnerException.Message));
  599. }
  600. else
  601. {
  602. MessageBox.Show(String.Format("Error while running service:\n{0}", inner.Message));
  603. }
  604. PRSServiceInstaller.UninstallService(arg.Get<Server, string>(x => x.Key));
  605. Refresh(false, true);
  606. }
  607. }, TaskScheduler.FromCurrentSynchronizationContext());
  608. return true;
  609. }
  610. MessageBox.Show("Cannot find Service - is it installed?");
  611. return false;
  612. }
  613. public void StopAll()
  614. {
  615. foreach (var service in _services.ToArray())
  616. if (service.Status == ServiceControllerStatus.Running)
  617. Task.Run(() => { service.Stop(); });
  618. }
  619. #endregion
  620. #region Server Type Images
  621. private readonly Dictionary<ServerType, BitmapImage> _typeimages = new()
  622. {
  623. { ServerType.Database, Properties.Resources.database.AsBitmapImage() },
  624. { ServerType.GPS, Properties.Resources.gps.AsBitmapImage() },
  625. { ServerType.AutoDiscovery, Properties.Resources.autodiscover.AsBitmapImage() },
  626. { ServerType.Schedule, Properties.Resources.schedule.AsBitmapImage() },
  627. { ServerType.Web, Properties.Resources.web.AsBitmapImage() },
  628. { ServerType.Certificate, Properties.Resources.certificate.AsBitmapImage() }
  629. };
  630. private BitmapImage TypeImage(CoreRow? arg)
  631. {
  632. if (arg == null)
  633. return Properties.Resources.help.AsBitmapImage();
  634. var type = arg.Get<Server, ServerType>(c => c.Type);
  635. return _typeimages[type];
  636. }
  637. private FrameworkElement? TypeToolTip(DynamicActionColumn arg1, CoreRow? arg2)
  638. {
  639. if (arg2 == null)
  640. return null;
  641. return arg1.TextToolTip(string.Format("{0} Service\nName: {1}",
  642. arg2.Get<Server, ServerType>(c => c.Type).ToString(),
  643. arg2.Get<Server, string>(c => c.Key)
  644. ));
  645. }
  646. #endregion
  647. #region Console Functions
  648. private BitmapImage? ConsoleImage(CoreRow? arg)
  649. {
  650. if (arg == null)
  651. return Properties.Resources.target.AsBitmapImage();
  652. var service = GetService(arg.Get<Server, string>(c => c.Key));
  653. var state = service != null ? (int)service.Status : 0;
  654. if (state == (int)ServiceControllerStatus.StartPending || state == (int)ServiceControllerStatus.Running)
  655. return Properties.Resources.target.AsBitmapImage();
  656. return null;
  657. }
  658. private bool ConsoleAction(CoreRow? arg)
  659. {
  660. if (arg == null)
  661. return false;
  662. var key = arg.Get<Server, string>(c => c.Key);
  663. var service = GetService(key);
  664. var state = service != null ? (int)service.Status : 0;
  665. if (state == (int)ServiceControllerStatus.StartPending || state == (int)ServiceControllerStatus.Running)
  666. StartConsole(arg, key);
  667. return false;
  668. }
  669. private Dictionary<String, Tuple<Console,int>> _consoles = new Dictionary<string, Tuple<Console,int>>();
  670. private void StartConsole(CoreRow arg, string key)
  671. {
  672. if (_consoles.ContainsKey(key))
  673. return;
  674. var name = arg.Get<Server, string>(c => c.Name);
  675. var console = new Console(key, string.Format("{0} - {1}", key, name));
  676. var window = Window.GetWindow(this);
  677. int i = 0;
  678. while (_consoles.Any(x => x.Value.Item2 == i))
  679. i++;
  680. _consoles[key] = new Tuple<Console, int>(console, i);
  681. console.Top = window.Top + (i * 50);
  682. console.Left = window.Left + window.Width + 2 + (i*50);
  683. console.Height = window.Height;
  684. console.Closing += (o, e) =>
  685. {
  686. Console c = o as Console;
  687. if (_consoles.ContainsKey(c.ServiceName))
  688. _consoles.Remove(c.ServiceName);
  689. };
  690. console.Show();
  691. }
  692. private void StopConsole(String key)
  693. {
  694. if (!_consoles.ContainsKey(key))
  695. return;
  696. Console console = _consoles[key].Item1;
  697. console.Close();
  698. }
  699. #endregion
  700. #region Individual Server Buttons
  701. // Check if a database server is running at the given url and port
  702. private bool IsDatabaseServerRunning(string url, int port)
  703. {
  704. var uri = new Uri(string.Format("{0}:{1}", url, port));
  705. var cli = new RestClient(uri);
  706. var req = new RestRequest("/classes", Method.GET) { Timeout = 20000 };
  707. try
  708. {
  709. var res = cli.Execute(req);
  710. if (res.StatusCode != HttpStatusCode.OK || res.ErrorException != null)
  711. return false;
  712. return true;
  713. }
  714. catch (Exception e)
  715. {
  716. }
  717. return false;
  718. }
  719. // The following variables keep track of whether a database is currently being used, since if two people try to access two different databases,
  720. // terrible things will ensue.
  721. private int currentServerUsers;
  722. private string? currentServerURL;
  723. private int? currentServerPort;
  724. /// <summary>
  725. /// Configures a server for the duration of an action
  726. /// </summary>
  727. /// <typeparam name="TProperties"></typeparam>
  728. /// <param name="row"></param>
  729. /// <param name="hostaddress"></param>
  730. /// <param name="portnumber"></param>
  731. /// <param name="action"></param>
  732. /// <param name="blocking">
  733. /// If blocking is set to false, then currentServerUsers must be decreased by one manually once the
  734. /// task finishes
  735. /// </param>
  736. private void ConfigureServer<TProperties>(
  737. CoreRow row,
  738. Func<TProperties, string> hostaddress,
  739. Func<TProperties, int> portnumber,
  740. Action action,
  741. bool blocking = true
  742. ) where TProperties : ServerProperties
  743. {
  744. try
  745. {
  746. if (row == null)
  747. throw new Exception("No Row Selected!");
  748. var server = LoadItem(row);
  749. if (server == null)
  750. throw new Exception("Unable to load Server!");
  751. var props = server.Properties as TProperties;
  752. if (props == null)
  753. throw new Exception("Unable to Load Properties!");
  754. var url = hostaddress(props);
  755. var port = portnumber(props);
  756. using (new WaitCursor())
  757. {
  758. if (!IsDatabaseServerRunning(url, port))
  759. throw new Exception("Database Server is not available!");
  760. }
  761. if (action != null)
  762. {
  763. if (currentServerUsers == 0)
  764. {
  765. if (currentServerURL != url || currentServerPort != port)
  766. {
  767. ConfigurationCache.ClearAll(ConfigurationCacheType.Global);
  768. ConfigurationCache.ClearAll(ConfigurationCacheType.User);
  769. }
  770. currentServerURL = url;
  771. currentServerPort = port;
  772. currentServerName = null;
  773. ClientFactory.SetClientType(typeof(JsonClient<>), "PRSServer", CoreUtils.GetVersion(), url, port, true);
  774. // override the need to provide credentials when configuring the database
  775. ClientFactory.SetBypass();
  776. }
  777. else
  778. {
  779. if (url != currentServerURL || port != currentServerPort)
  780. throw new Exception(string.Format("A different Database Server ({0}:{1}) is currently in use!", currentServerURL,
  781. currentServerPort));
  782. }
  783. currentServerUsers++;
  784. action();
  785. if (blocking) currentServerUsers--;
  786. }
  787. }
  788. catch (Exception e)
  789. {
  790. Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
  791. MessageBox.Show(e.Message);
  792. }
  793. }
  794. private string? currentServerName;
  795. private void ConfigureIPCServer<TProperties>(
  796. CoreRow row,
  797. Func<TProperties, string> hostPipeName,
  798. Action action,
  799. bool blocking = true
  800. ) where TProperties : ServerProperties
  801. {
  802. try
  803. {
  804. if (row == null)
  805. throw new Exception("No Row Selected!");
  806. var server = LoadItem(row);
  807. if (server == null)
  808. throw new Exception("Unable to load Server!");
  809. var props = server.Properties as TProperties;
  810. if (props == null)
  811. throw new Exception("Unable to Load Properties!");
  812. var pipeName = DatabaseServerProperties.GetPipeName(hostPipeName(props));
  813. if (action != null)
  814. {
  815. if (currentServerUsers == 0)
  816. {
  817. if (currentServerName != pipeName)
  818. {
  819. ConfigurationCache.ClearAll(ConfigurationCacheType.Global);
  820. ConfigurationCache.ClearAll(ConfigurationCacheType.User);
  821. }
  822. currentServerPort = null;
  823. currentServerURL = null;
  824. currentServerName = pipeName;
  825. ClientFactory.SetClientType(typeof(PipeIPCClient<>), "PRSServer", CoreUtils.GetVersion(), pipeName);
  826. using (new WaitCursor())
  827. {
  828. if (!Client.Ping())
  829. {
  830. ClientFactory.ClearClientType();
  831. throw new Exception("Database Server is not available!");
  832. }
  833. }
  834. // override the need to provide credentials when configuring the database
  835. ClientFactory.SetBypass();
  836. }
  837. else
  838. {
  839. if (pipeName != currentServerName)
  840. throw new Exception(string.Format("A different Database Server ({0}) is currently in use!", currentServerName));
  841. }
  842. currentServerUsers++;
  843. try
  844. {
  845. action();
  846. }
  847. finally
  848. {
  849. if (blocking) currentServerUsers--;
  850. }
  851. }
  852. }
  853. catch (Exception e)
  854. {
  855. Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
  856. MessageBox.Show(e.Message);
  857. }
  858. }
  859. private void ConfigureLocalDatabase(
  860. CoreRow row,
  861. Action action
  862. )
  863. {
  864. try
  865. {
  866. if (row == null)
  867. throw new Exception("No Row Selected!");
  868. var server = LoadItem(row);
  869. if (server == null)
  870. throw new Exception("Unable to load Server!");
  871. var properties = server.Properties as DatabaseServerProperties;
  872. if (properties == null)
  873. throw new Exception("Unable to Load Properties!");
  874. if (!DbFactory.IsProviderSet || DbFactory.Provider is not SQLiteProvider sql || sql.URL != properties.FileName)
  875. {
  876. ClientFactory.SetClientType(typeof(LocalClient<>), "PRSServer", CoreUtils.GetVersion(), "");
  877. Progress.ShowModal("Configuring database", (progress) =>
  878. {
  879. DbFactory.Stores = CoreUtils.TypeList(
  880. AppDomain.CurrentDomain.GetAssemblies(),
  881. myType =>
  882. myType.IsClass
  883. && !myType.IsAbstract
  884. && !myType.IsGenericType
  885. && myType.GetInterfaces().Contains(typeof(IStore))
  886. ).ToArray();
  887. DbFactory.Provider = new SQLiteProvider(properties.FileName);
  888. var deviceid = DeviceID.Value(properties.Port.ToString(), null);
  889. DbFactory.Start(deviceid);
  890. StoreUtils.GoogleAPIKey = properties.GoogleAPIKey;
  891. PurchaseOrderStore.AutoIncrementPrefix = properties.PurchaseOrderPrefix;
  892. JobStore.AutoIncrementPrefix = properties.JobPrefix;
  893. });
  894. }
  895. action();
  896. }
  897. catch(Exception e)
  898. {
  899. Logger.Send(LogType.Error, "", CoreUtils.FormatException(e));
  900. MessageBox.Show(e.Message);
  901. }
  902. }
  903. private bool UpdateDatabaseLicense(CoreRow selectedrow)
  904. {
  905. ConfigureIPCServer<DatabaseServerProperties>(
  906. selectedrow,
  907. //x => "http://127.0.0.1",
  908. //x => x.Port,
  909. x => selectedrow.Get<Server, string>(x => x.Key),
  910. () =>
  911. {
  912. new LicenseRenewalForm().ShowDialog();
  913. }
  914. );
  915. return false;
  916. }
  917. private bool ManageDeletions(CoreRow row)
  918. {
  919. ConfigureLocalDatabase(row, () =>
  920. {
  921. new DeletionsWindow().ShowDialog();
  922. });
  923. return false;
  924. }
  925. private bool EditCustomFields(CoreRow selectedrow)
  926. {
  927. ConfigureIPCServer<DatabaseServerProperties>(
  928. selectedrow,
  929. //x => "http://127.0.0.1",
  930. //x => x.Port,
  931. x => selectedrow.Get<Server, string>(x => x.Key),
  932. () => { new MasterList(typeof(CustomProperty), "Class", null, true).ShowDialog(); }
  933. );
  934. return false;
  935. }
  936. private bool EditDatabaseScripts(CoreRow selectedrow)
  937. {
  938. ConfigureIPCServer<DatabaseServerProperties>(
  939. selectedrow,
  940. //x => "http://127.0.0.1",
  941. //x => x.Port,
  942. x => selectedrow.Get<Server, string>(x => x.Key),
  943. () => { new MasterList(typeof(Script), "Section", null, true).ShowDialog(); }
  944. );
  945. return false;
  946. }
  947. private bool EditScheduledScripts(CoreRow selectedrow)
  948. {
  949. ConfigureIPCServer<ScheduleServerProperties>(
  950. selectedrow,
  951. x => x.Server,
  952. () => { new MasterList(typeof(ScheduledScript), "", null, true, typeof(ScheduledScriptsGrid)).ShowDialog(); }
  953. );
  954. return false;
  955. }
  956. private bool EditWebTemplates(CoreRow selectedRow)
  957. {
  958. ConfigureIPCServer<WebServerProperties>(
  959. selectedRow,
  960. x => x.Server,
  961. () =>
  962. {
  963. var window = new MasterList(typeof(WebTemplate), "DataModel", "", true);
  964. window.Closed += (e, args) => { currentServerUsers--; };
  965. window.Show();
  966. },
  967. false
  968. );
  969. return false;
  970. }
  971. private bool EditWebStyles(CoreRow selectedRow)
  972. {
  973. ConfigureIPCServer<WebServerProperties>(
  974. selectedRow,
  975. x => x.Server,
  976. () =>
  977. {
  978. var window = new MasterList(typeof(WebStyle), "Code", "", true);
  979. window.Closed += (e, args) => { currentServerUsers--; };
  980. window.Show();
  981. },
  982. false
  983. );
  984. return false;
  985. }
  986. private bool EditWebDocuments(CoreRow selectedRow)
  987. {
  988. ConfigureIPCServer<WebServerProperties>(
  989. selectedRow,
  990. x => x.Server,
  991. () =>
  992. {
  993. var window = new MasterList(typeof(WebDocument), "Code", "", true);
  994. window.Closed += (e, args) => { currentServerUsers--; };
  995. window.Show();
  996. },
  997. false
  998. );
  999. return false;
  1000. }
  1001. private bool PRSMobileSettings(CoreRow selectedrow)
  1002. {
  1003. ConfigureIPCServer<WebServerProperties>(
  1004. selectedrow,
  1005. x => x.Server,
  1006. () =>
  1007. {
  1008. var editor = new DynamicEditorForm(typeof(WebSettings));
  1009. var settings = new GlobalConfiguration<WebSettings>().Load();
  1010. editor.Items = new[] { settings };
  1011. if (editor.ShowDialog() == true) new GlobalConfiguration<WebSettings>().Save(settings);
  1012. }
  1013. );
  1014. return false;
  1015. }
  1016. #endregion
  1017. }
  1018. }