< Summary - Combined Code Coverage

Information
Class: Program
Assembly: NLightning.Node
File(s): /home/runner/work/nlightning/nlightning/src/NLightning.Node/Program.cs
Tag: 39_18410846617
Line coverage
0%
Covered lines: 0
Uncovered lines: 91
Coverable lines: 91
Total lines: 194
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.Node/Program.cs

#LineLine coverage
 1using Microsoft.Extensions.Configuration;
 2using Microsoft.Extensions.Hosting;
 3using Microsoft.Extensions.Logging;
 4using Microsoft.Extensions.Options;
 5using NBitcoin;
 6using NLightning.Domain.Node.Options;
 7using NLightning.Domain.Protocol.ValueObjects;
 8using NLightning.Infrastructure.Bitcoin.Managers;
 9using NLightning.Infrastructure.Bitcoin.Options;
 10using NLightning.Infrastructure.Bitcoin.Wallet;
 11using NLightning.Node.Extensions;
 12using NLightning.Node.Helpers;
 13using NLightning.Node.Utilities;
 14using Serilog;
 15
 16try
 17{
 18    // Bootstrap logger for startup messages
 019    Log.Logger = new LoggerConfiguration()
 020                .WriteTo.Console()
 021                .CreateBootstrapLogger();
 22
 023    AppDomain.CurrentDomain.UnhandledException += (_, e) =>
 024    {
 025        var exception = (Exception)e.ExceptionObject;
 026        Log.Logger.Error("An unhandled exception occurred: {exception}", exception);
 027    };
 28
 29    // Get network for the PID file path
 030    var network = CommandLineHelper.GetNetwork(args);
 031    var pidFilePath = DaemonUtils.GetPidFilePath(network);
 32
 33    // Check for the stop command
 034    if (CommandLineHelper.IsStopRequested(args))
 35    {
 036        var stopped = DaemonUtils.StopDaemon(pidFilePath, Log.Logger);
 037        return stopped ? 0 : 1;
 38    }
 39
 40    // Check for status command
 041    if (CommandLineHelper.IsStatusRequested(args))
 42    {
 043        ReportDaemonStatus(pidFilePath);
 044        return 0;
 45    }
 46
 47    // Check if help is requested
 048    if (CommandLineHelper.IsHelpRequested(args))
 49    {
 050        CommandLineHelper.ShowUsage();
 051        return 0;
 52    }
 53
 54    // Read the configuration file to check for daemon setting
 055    var initialConfig = NodeConfigurationExtensions.ReadInitialConfiguration(args);
 56
 057    string? password = null;
 58
 59    // Try to get password from args or prompt
 060    if (args.Contains("--password"))
 61    {
 062        var idx = Array.IndexOf(args, "--password");
 063        if (idx >= 0 && idx + 1 < args.Length)
 064            password = args[idx + 1];
 65    }
 66
 067    if (string.IsNullOrWhiteSpace(password))
 68    {
 069        password = ConsoleUtils.ReadPassword("Enter password for key encryption: ");
 70    }
 71
 072    if (string.IsNullOrWhiteSpace(password))
 73    {
 074        Log.Error("Password cannot be empty.");
 075        return 1;
 76    }
 77
 78    SecureKeyManager keyManager;
 079    var keyFilePath = SecureKeyManager.GetKeyFilePath(network);
 080    if (!File.Exists(keyFilePath))
 81    {
 82        // Get current Block Height for key birth
 83        try
 84        {
 85            // Create logger for the wallet service using Serilog
 086            var loggerFactory = LoggerFactory.Create(b => b.AddSerilog(Log.Logger, dispose: false));
 087            var walletLogger = loggerFactory.CreateLogger<BitcoinWalletService>();
 88
 89            // Bind options from initialConfig
 090            var bitcoinOptions = initialConfig.GetSection("Bitcoin").Get<BitcoinOptions>()
 091                              ?? throw new InvalidOperationException(
 092                                     "Bitcoin configuration section is missing or invalid.");
 093            var nodeOptions = initialConfig.GetSection("Node").Get<NodeOptions>()
 094                           ?? throw new InvalidOperationException("Node configuration section is missing or invalid.");
 95
 96            // Instantiate the service
 097            var bitcoinWalletService = new BitcoinWalletService(
 098                Options.Create(bitcoinOptions),
 099                walletLogger,
 0100                Options.Create(nodeOptions)
 0101            );
 102
 0103            var heightOfBirth = await bitcoinWalletService.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
 0131    Log.Information("Starting NLTG...");
 132
 133    // Create and run host
 0134    var host = Host.CreateDefaultBuilder(args)
 0135                   .ConfigureNltg(initialConfig)
 0136                   .ConfigureNltgServices(keyManager)
 0137                   .Build();
 138
 139    // Run migrations if configured
 0140    await host.MigrateDatabaseIfConfiguredAsync();
 141
 142    // Run the host
 0143    await host.RunAsync();
 144
 0145    return 0;
 146}
 147catch (Exception e)
 148{
 0149    Log.Fatal(e, "Application terminated unexpectedly");
 0150    return 1;
 151}
 152finally
 153{
 0154    Log.CloseAndFlush();
 155}
 156
 157static void ReportDaemonStatus(string pidFilePath)
 158{
 159    try
 160    {
 0161        if (!File.Exists(pidFilePath))
 162        {
 0163            Console.WriteLine("NLTG daemon is not running");
 0164            return;
 165        }
 166
 0167        var pidText = File.ReadAllText(pidFilePath).Trim();
 0168        if (!int.TryParse(pidText, out var pid))
 169        {
 0170            Console.WriteLine("Invalid PID in file, daemon may not be running");
 0171            return;
 172        }
 173
 174        try
 175        {
 0176            var process = System.Diagnostics.Process.GetProcessById(pid);
 0177            var runTime = DateTime.Now - process.StartTime;
 178
 0179            Console.WriteLine("NLTG daemon is running");
 0180            Console.WriteLine($"PID: {pid}");
 0181            Console.WriteLine($"Started: {process.StartTime}");
 0182            Console.WriteLine($"Uptime: {runTime.Days}d {runTime.Hours}h {runTime.Minutes}m");
 0183            Console.WriteLine($"Memory: {process.WorkingSet64 / (1024 * 1024)} MB");
 0184        }
 0185        catch (ArgumentException)
 186        {
 0187            Console.WriteLine("NLTG daemon is not running (stale PID file)");
 0188        }
 0189    }
 0190    catch (Exception e)
 191    {
 0192        Console.WriteLine($"Error checking daemon status: {e.Message}");
 0193    }
 0194}

Methods/Properties

<Main>$()
ReportDaemonStatus()