Server.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Abstractions;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Net.Sockets;
  8. using BO.ProcessServer.Business.StatisticCounters;
  9. using BO.ProcessServer.Business.Workers;
  10. using BO.ProcessServer.Business.Workers.Contexts;
  11. using BO.ProcessServer.Options;
  12. using Connector.PS;
  13. using Quadarax.Foundation.Core.IO;
  14. using Quadarax.Foundation.Core.Logging;
  15. using Quadarax.Foundation.Core.Object;
  16. namespace BO.ProcessServer.Business
  17. {
  18. internal class Server : DisposableObject
  19. {
  20. #region *** Private fields ***
  21. private Configuration _configuration;
  22. private IFileSystem _fileSystem;
  23. private IList<ServerProcess> _processes;
  24. protected ILog Log { get; }
  25. protected Statistics Statistics { get; }
  26. private Pool _pool;
  27. private PullDocumentsWorker _wkPull;
  28. private RetentionWorker _wkRetention;
  29. private ProcessingDocumentsWorker _wkProcessing;
  30. private Connection _connection;
  31. #endregion
  32. #region *** Public properties ***
  33. public bool IsRunning { get; private set; }
  34. #endregion
  35. #region *** Constructors ***
  36. public Server(Configuration serverConfiguration, IFileSystem fileSystem, ILogger logger)
  37. {
  38. _configuration = serverConfiguration ?? throw new ArgumentNullException(nameof(serverConfiguration));
  39. _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem));
  40. if (logger == null)
  41. throw new ArgumentNullException(nameof(logger));
  42. Log = logger.GetLogger(typeof(Server));
  43. Statistics = new Statistics();
  44. _processes = new List<ServerProcess>();
  45. _connection = new Connection(_configuration.ApiBaseUrl, _configuration.ApiTimeout,
  46. _configuration.System.Identification, IPAddress.Parse(_configuration.System.PreferredInterface),
  47. _configuration.System.PoolPullDocuments);
  48. _pool = new Pool(_configuration, _fileSystem, logger);
  49. _wkPull = new PullDocumentsWorker(_connection, _configuration.System.PoolPullInterval, fileSystem, Statistics, _pool, logger);
  50. _wkRetention = new RetentionWorker(new CfgCtx(_configuration, Statistics, _pool));
  51. _wkProcessing = new ProcessingDocumentsWorker(_configuration, _processes, _connection, fileSystem, Statistics, _pool, logger);
  52. }
  53. #endregion
  54. #region *** Public operations ***
  55. public void Start()
  56. {
  57. if (IsRunning)
  58. {
  59. LogWarn($"Instance '{_configuration.System.Identification}' already running. Start skipped.");
  60. return;
  61. }
  62. LogDebug($"Starting instance '{_configuration.System.Identification}' ...");
  63. ValidateConfiguration();
  64. _wkPull.Start();
  65. _wkRetention.Start();
  66. _wkProcessing.Start();
  67. Statistics.GetCounter<TimespanCounter>(Statistics.CNT_PS_ONLINE_DUR).Start();
  68. IsRunning = true;
  69. LogInfo( $"Instance '{_configuration.System.Identification}' STARTED.");
  70. }
  71. public void Stop()
  72. {
  73. if (!IsRunning)
  74. {
  75. LogWarn($"Instance '{_configuration.System.Identification}' already stopped. Stop skipped.");
  76. return;
  77. }
  78. LogDebug($"Stopping instance '{_configuration.System.Identification}' ...");
  79. StopAll();
  80. Statistics.GetCounter<TimespanCounter>(Statistics.CNT_PS_ONLINE_DUR).Stop();
  81. IsRunning = false;
  82. LogInfo( $"Instance '{_configuration.System.Identification}' STOPPED.");
  83. }
  84. #endregion
  85. #region *** Overrides ***
  86. protected override void OnDisposing()
  87. {
  88. if (IsRunning)
  89. StopAll(true);
  90. _wkPull?.Dispose();
  91. _wkRetention?.Dispose();
  92. _wkProcessing?.Dispose();
  93. _connection?.Dispose();
  94. _pool?.Dispose();
  95. LogDebug($"Instance '{_configuration.System.Identification}' disposed.");
  96. _configuration = null;
  97. _fileSystem = null;
  98. _wkPull=null;
  99. _wkRetention=null;
  100. _wkProcessing = null;
  101. _connection=null;
  102. _pool = null;
  103. }
  104. #endregion
  105. #region *** Private Operations ***
  106. public void LogDebug(string message)
  107. {
  108. LogRaw(LogSeverityEnum.Debug, message);
  109. }
  110. public void LogInfo(string message)
  111. {
  112. LogRaw(LogSeverityEnum.Info, message);
  113. }
  114. public void LogWarn(string message)
  115. {
  116. LogRaw(LogSeverityEnum.Warn, message);
  117. }
  118. public void LogRaw(LogSeverityEnum severity, string message)
  119. {
  120. Log.Log(severity, message);
  121. }
  122. private void ValidateConfiguration()
  123. {
  124. if (string.IsNullOrEmpty(_configuration.System.Identification))
  125. throw new ArgumentNullException(nameof(_configuration.System.Identification),
  126. "Mandatory process server identification.");
  127. if (string.IsNullOrEmpty(_configuration.System.PreferredInterface))
  128. _configuration.System.PreferredInterface = "auto";
  129. var host = Dns.GetHostEntry(Dns.GetHostName());
  130. if (_configuration.System.PreferredInterface.Trim().ToLower() == "auto")
  131. {
  132. _configuration.System.PreferredInterface = host.AddressList.FirstOrDefault(x =>
  133. x.AddressFamily == AddressFamily.InterNetwork ||
  134. x.AddressFamily == AddressFamily.InterNetworkV6)
  135. ?.ToString();
  136. }
  137. if (!host.AddressList.Any(x =>
  138. (x.AddressFamily == AddressFamily.InterNetwork ||
  139. x.AddressFamily == AddressFamily.InterNetworkV6) && x.ToString().ToLower() ==
  140. _configuration.System.PreferredInterface.Trim().ToLower()))
  141. throw new ArgumentNullException(nameof(_configuration.System.PreferredInterface),
  142. "Mandatory preferred interface (or auto) for server identification.");
  143. // Pool directories structure
  144. EnsureDirectory(_configuration.System.PoolPathBase);
  145. EnsureDirectory(_fileSystem.Path.Combine(_configuration.System.PoolPathBase, _configuration.System.PoolPathDone));
  146. EnsureDirectory(_fileSystem.Path.Combine(_configuration.System.PoolPathBase, _configuration.System.PoolPathFail));
  147. EnsureDirectory(_fileSystem.Path.Combine(_configuration.System.PoolPathBase, _configuration.System.PoolPathPending));
  148. EnsureDirectory(_fileSystem.Path.Combine(_configuration.System.PoolPathBase, _configuration.System.PoolPathWorking));
  149. // Scenario structure
  150. EnsureDirectory(_configuration.System.ScenarioPathBase);
  151. if (_fileSystem.Directory.GetFiles(TranslatePath(_configuration.System.ScenarioPathBase), "*.*").Length == 0)
  152. LogWarn($"Scenario directory '{TranslatePath(_configuration.System.ScenarioPathBase)}' is empty.");
  153. LogInfo("Configuration validated.");
  154. }
  155. private string EnsureDirectory(string path)
  156. {
  157. var dir = FileUtils.EnsurePathEndsWithDirSeparator(_fileSystem, TranslatePath(path));
  158. if (!_fileSystem.Directory.Exists(dir))
  159. {
  160. _fileSystem.Directory.CreateDirectory(dir);
  161. LogDebug($"Directory '{dir}' created.");
  162. }
  163. if (!_fileSystem.Directory.Exists(dir))
  164. throw new FileNotFoundException($"Directory '{dir}' not found!");
  165. return dir;
  166. }
  167. private string TranslatePath(string path)
  168. {
  169. if (string.IsNullOrEmpty(path))
  170. return path;
  171. return path.Replace("{CD}", _fileSystem.Directory.GetCurrentDirectory());
  172. }
  173. private void StopAll(bool silently = false)
  174. {
  175. _wkPull.Stop(silently);
  176. _wkRetention.Stop(silently);
  177. _wkProcessing.Stop(silently);
  178. foreach (var process in _processes)
  179. process.Stop(silently);
  180. foreach (var process in _processes)
  181. process.Dispose();
  182. _processes.Clear();
  183. }
  184. #endregion
  185. }
  186. }