< Summary - Combined Code Coverage

Information
Class: Program
Assembly: NLightning.Daemon
File(s): /home/runner/work/NLightning/NLightning/src/NLightning.Daemon/Program.cs
Tag: 57_24045730253
Line coverage
0%
Covered lines: 0
Uncovered lines: 89
Coverable lines: 89
Total lines: 197
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 28
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
<Main>$()0%600240%
ReportDaemonStatus()0%2040%

File(s)

/home/runner/work/NLightning/NLightning/src/NLightning.Daemon/Program.cs

#LineLine coverage
 1using MessagePack;
 2using Microsoft.Extensions.Configuration;
 3using Microsoft.Extensions.Hosting;
 4using Microsoft.Extensions.Logging;
 5using Microsoft.Extensions.Options;
 6using NBitcoin;
 7using NLightning.Daemon.Contracts.Helpers;
 8using NLightning.Daemon.Contracts.Utilities;
 9using NLightning.Daemon.Extensions;
 10using NLightning.Daemon.Utilities;
 11using NLightning.Domain.Node.Options;
 12using NLightning.Domain.Protocol.ValueObjects;
 13using NLightning.Infrastructure.Bitcoin.Managers;
 14using NLightning.Infrastructure.Bitcoin.Options;
 15using NLightning.Infrastructure.Bitcoin.Wallet;
 16using NLightning.Transport.Ipc.MessagePack;
 17using Serilog;
 18
 19try
 20{
 21    // Bootstrap logger for startup messages
 022    Log.Logger = new LoggerConfiguration()
 023                .WriteTo.Console()
 024                .CreateBootstrapLogger();
 25
 026    AppDomain.CurrentDomain.UnhandledException += (_, e) =>
 027    {
 028        var exception = (Exception)e.ExceptionObject;
 029        Log.Logger.Error("An unhandled exception occurred: {exception}", exception);
 030    };
 31
 32    // Read the configuration file to check for daemon setting
 033    var (initialConfig, network, configPath) = NodeConfigurationExtensions.ReadInitialConfiguration(args);
 34
 35    // Get PID file path
 036    var pidFilePath = DaemonUtils.GetPidFilePath(configPath);
 37
 38    // Check for the stop command
 039    if (DaemonUtils.IsStopRequested(args))
 40    {
 041        var stopped = DaemonUtils.StopDaemon(pidFilePath, Log.Logger);
 042        return stopped ? 0 : 1;
 43    }
 44
 45    // Check for status command
 046    if (DaemonUtils.IsStatusRequested(args))
 47    {
 048        ReportDaemonStatus(pidFilePath);
 049        return 0;
 50    }
 51
 52    // Check if help is requested
 053    if (CommandLineHelper.IsHelpRequested(args))
 54    {
 055        DaemonUtils.ShowUsage();
 056        return 0;
 57    }
 58
 059    string? password = null;
 60
 61    // Try to get password from args or prompt
 062    if (args.Contains("--password"))
 63    {
 064        var idx = Array.IndexOf(args, "--password");
 065        if (idx >= 0 && idx + 1 < args.Length)
 066            password = args[idx + 1];
 67    }
 68
 069    if (string.IsNullOrWhiteSpace(password))
 70    {
 071        password = ConsoleUtils.ReadPassword("Enter password for key encryption: ");
 72    }
 73
 074    if (string.IsNullOrWhiteSpace(password))
 75    {
 076        Log.Error("Password cannot be empty.");
 077        return 1;
 78    }
 79
 80    SecureKeyManager keyManager;
 081    var keyFilePath = SecureKeyManager.GetKeyFilePath(configPath);
 082    if (!File.Exists(keyFilePath))
 83    {
 84        // Get current Block Height for key birth
 85        try
 86        {
 87            // Create the logger for the wallet service using Serilog
 088            var loggerFactory = LoggerFactory.Create(b => b.AddSerilog(Log.Logger, dispose: false));
 089            var walletLogger = loggerFactory.CreateLogger<BitcoinChainService>();
 90
 91            // Bind options from initialConfig
 092            var bitcoinOptions = initialConfig.GetSection("Bitcoin").Get<BitcoinOptions>()
 093                              ?? throw new InvalidOperationException(
 094                                     "Bitcoin configuration section is missing or invalid.");
 095            var nodeOptions = initialConfig.GetSection("Node").Get<NodeOptions>()
 096                           ?? throw new InvalidOperationException("Node configuration section is missing or invalid.");
 97
 98            // Instantiate the service
 099            var bitcoinChainService = new BitcoinChainService(Options.Create(bitcoinOptions), walletLogger,
 0100                                                              Options.Create(nodeOptions)
 0101            );
 102
 0103            var heightOfBirth = await bitcoinChainService.GetCurrentBlockHeightAsync();
 104
 105            // Creates new key
 0106            var key = new Key();
 0107            keyManager = new SecureKeyManager(key.ToBytes(), new BitcoinNetwork(network), keyFilePath, heightOfBirth);
 0108            keyManager.SaveToFile(password);
 0109            Console.WriteLine($"New key created and saved to {keyFilePath}");
 0110        }
 0111        catch (Exception e)
 112        {
 0113            Log.Logger.Error(e, "An error occurred while creating new key.");
 0114            return 1;
 115        }
 116    }
 117    else
 118    {
 119        // Load the existing key
 0120        keyManager = SecureKeyManager.FromFilePath(keyFilePath, new BitcoinNetwork(network), password);
 0121        Console.WriteLine($"Loaded key from {keyFilePath}");
 122    }
 123
 124    // Start as a daemon if requested
 0125    if (DaemonUtils.StartDaemonIfRequested(args, initialConfig, pidFilePath, Log.Logger))
 126    {
 127        // The parent process exits immediately after starting the daemon
 0128        return 0;
 129    }
 130
 131    // Register the default formatter for MessagePackSerializer
 0132    MessagePackSerializer.DefaultOptions = NLightningMessagePackOptions.Options;
 133
 0134    Log.Information("Starting NLTG...");
 135
 136    // Create and run host
 0137    var host = Host.CreateDefaultBuilder(args)
 0138                   .ConfigureNltg(initialConfig)
 0139                   .ConfigureNltgServices(keyManager, configPath)
 0140                   .Build();
 141
 142    // Run migrations if configured
 0143    await host.MigrateDatabaseIfConfiguredAsync();
 144
 145    // Run the host
 0146    await host.RunAsync();
 147
 0148    return 0;
 149}
 150catch (Exception e)
 151{
 0152    Log.Fatal(e, "Application terminated unexpectedly");
 0153    return 1;
 154}
 155finally
 156{
 0157    Log.CloseAndFlush();
 158}
 159
 160static void ReportDaemonStatus(string pidFilePath)
 161{
 162    try
 163    {
 0164        if (!File.Exists(pidFilePath))
 165        {
 0166            Console.WriteLine("NLTG daemon is not running");
 0167            return;
 168        }
 169
 0170        var pidText = File.ReadAllText(pidFilePath).Trim();
 0171        if (!int.TryParse(pidText, out var pid))
 172        {
 0173            Console.WriteLine("Invalid PID in file, daemon may not be running");
 0174            return;
 175        }
 176
 177        try
 178        {
 0179            var process = System.Diagnostics.Process.GetProcessById(pid);
 0180            var runTime = DateTime.Now - process.StartTime;
 181
 0182            Console.WriteLine("NLTG daemon is running");
 0183            Console.WriteLine($"PID: {pid}");
 0184            Console.WriteLine($"Started: {process.StartTime}");
 0185            Console.WriteLine($"Uptime: {runTime.Days}d {runTime.Hours}h {runTime.Minutes}m");
 0186            Console.WriteLine($"Memory: {process.WorkingSet64 / (1024 * 1024)} MB");
 0187        }
 0188        catch (ArgumentException)
 189        {
 0190            Console.WriteLine("NLTG daemon is not running (stale PID file)");
 0191        }
 0192    }
 0193    catch (Exception e)
 194    {
 0195        Console.WriteLine($"Error checking daemon status: {e.Message}");
 0196    }
 0197}

Methods/Properties

<Main>$()
ReportDaemonStatus()