using System; using System.IO; using System.Net; using System.Reflection; using ZeroLevel.Logging; using ZeroLevel.Network; namespace ZeroLevel { public static class Bootstrap { public interface IServiceExecution { IServiceExecution Run(); IServiceExecution WaitForStatus(ZeroServiceStatus status); IServiceExecution WaitForStatus(ZeroServiceStatus status, TimeSpan period); IServiceExecution WaitWhileStatus(ZeroServiceStatus status); IServiceExecution WaitWhileStatus(ZeroServiceStatus status, TimeSpan period); IServiceExecution Stop(); IZeroService Service { get; } ZeroServiceStatus Status { get; } } public class BootstrapFluent : IServiceExecution { private readonly IZeroService _service; public IZeroService Service { get { return _service; } } public BootstrapFluent(IZeroService service) { if (service == null) { throw new ArgumentNullException(nameof(service)); } _service = service; } public BootstrapFluent UseDiscovery() { _service?.UseDiscovery(); return this; } public BootstrapFluent UseDiscovery(string url) { _service?.UseDiscovery(url); return this; } public BootstrapFluent UseDiscovery(IPEndPoint endpoint) { _service?.UseDiscovery(endpoint); return this; } public BootstrapFluent ReadServiceInfo() { _service?.ReadServiceInfo(); return this; } public BootstrapFluent ReadServiceInfo(IConfigurationSet config) { _service?.ReadServiceInfo(config); return this; } public BootstrapFluent EnableConsoleLog(LogLevel level = LogLevel.FullStandart) { Log.AddConsoleLogger(level); return this; } public ZeroServiceStatus Status { get { return _service.Status; } } public IServiceExecution Run() { try { _service?.Start(); } catch (Exception ex) { Log.Error(ex, $"[Bootstrap] Service {_service?.Name} run error"); return null; } return this; } public IServiceExecution Stop() { try { _service?.Stop(); } catch (Exception ex) { Log.Error(ex, $"[Bootstrap] Service {_service?.Name} dispose error"); } return this; } public IServiceExecution WaitForStatus(ZeroServiceStatus status) { _service.WaitForStatus(status); return this; } public IServiceExecution WaitForStatus(ZeroServiceStatus status, TimeSpan period) { _service.WaitForStatus(status, period); return this; } public IServiceExecution WaitWhileStatus(ZeroServiceStatus status) { _service.WaitWhileStatus(status); return this; } public IServiceExecution WaitWhileStatus(ZeroServiceStatus status, TimeSpan period) { _service.WaitWhileStatus(status, period); return this; } } static Bootstrap() { // Tricks for minimize config changes for dependency resolve //AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; } private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) { try { Log.Info($"[Bootstrap] Resolve assembly '{args.Name}' {args.Name}"); string name = args.Name.Split(',')[0]; if (name.EndsWith(".resources")) return null; foreach (string file in Directory. GetFiles(Path.Combine(Configuration.BaseDirectory), "*.dll", SearchOption.TopDirectoryOnly)) { if (file.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0) { Log.Info($"[Bootstrap] Resolve assembly '{args.Name}' found '{file}'"); return Assembly.LoadFile(file); } } } catch (Exception ex) { Log.Error(ex, $"[Bootstrap] Fault load assembly '{args.Name}'"); } return null; } public static BootstrapFluent Startup(string[] args, Func preStartConfiguration = null, Func postStartConfiguration = null) where T : IZeroService { var service = Initialize(args, null, preStartConfiguration, postStartConfiguration); return new BootstrapFluent(service); } public static BootstrapFluent Startup(string[] args, Func configuration, Func preStartConfiguration = null, Func postStartConfiguration = null) where T : IZeroService { var service = Initialize(args, configuration?.Invoke(), preStartConfiguration, postStartConfiguration); return new BootstrapFluent(service); } private static IZeroService Initialize(string[] args, IConfigurationSet configurationSet, Func preStartConfiguration = null, Func postStartConfiguration = null) where T : IZeroService { IZeroService service = null; IConfigurationSet config = Configuration.DefaultSet; config.CreateSection("commandline", Configuration.ReadFromCommandLine(args)); if (configurationSet != null) { config.Merge(configurationSet); } Log.CreateLoggingFromConfiguration(Configuration.DefaultSet); if (preStartConfiguration != null) { try { if (preStartConfiguration() == false) { Log.SystemInfo("[Bootstrap] Service start canceled, because custom preconfig return false"); return null; } } catch (Exception ex) { Log.SystemError(ex, "[Bootstrap] Service start canceled, preconfig faulted"); return null; } } try { service = Activator.CreateInstance(); } catch (Exception ex) { Log.SystemError(ex, "[Bootstrap] Service start canceled, service constructor call fault"); } if (postStartConfiguration != null) { try { if (postStartConfiguration() == false) { Log.SystemInfo("[Bootstrap] Service start canceled, because custom postconfig return false"); return null; } } catch (Exception ex) { Log.SystemError(ex, "[Bootstrap] Service start canceled, postconfig faulted"); return null; } } return service; } public static IExchange CreateExchange() => new Exchange(null); public static void Shutdown() { try { Sheduller.Dispose(); } catch (Exception ex) { Log.Error(ex, "[Bootstrap] Dispose default sheduller error"); } try { Log.Dispose(); } catch (Exception ex) { Log.Error(ex, "[Bootstrap] Dispose log error"); } try { Injector.Default.Dispose(); Injector.Dispose(); } catch (Exception ex) { Log.Error(ex, "[Bootstrap] Dispose DI containers error"); } } } }