< Summary - Combined Code Coverage

Information
Class: NLightning.Application.NLTG.Services.TcpListenerService
Assembly: NLightning.Application.NLTG
File(s): /home/runner/work/nlightning/nlightning/src/NLightning.Application.NLTG/Services/TcpListenerService.cs
Tag: 30_15166811759
Line coverage
0%
Covered lines: 0
Uncovered lines: 63
Coverable lines: 63
Total lines: 133
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 18
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
StartAsync(...)0%4260%
StopAsync()0%4260%
ListenForConnectionsAsync()0%4260%
<ListenForConnectionsAsync()100%210%

File(s)

/home/runner/work/nlightning/nlightning/src/NLightning.Application.NLTG/Services/TcpListenerService.cs

#LineLine coverage
 1using System.Net;
 2using System.Net.Sockets;
 3using Microsoft.Extensions.Logging;
 4using Microsoft.Extensions.Options;
 5
 6namespace NLightning.Application.NLTG.Services;
 7
 8using Domain.Node.Options;
 9using Infrastructure.Node.Interfaces;
 10using Interfaces;
 11
 12public class TcpListenerService : ITcpListenerService
 13{
 14    private readonly ILogger<TcpListenerService> _logger;
 15    private readonly NodeOptions _nodeOptions;
 16    private readonly IPeerManager _peerManager;
 017    private readonly List<TcpListener> _listeners = [];
 18
 19    private CancellationTokenSource? _cts;
 20    private Task? _listeningTask;
 21
 022    public TcpListenerService(ILogger<TcpListenerService> logger, IOptions<NodeOptions> nodeOptions,
 023                              IPeerManager peerManager)
 24    {
 025        _logger = logger;
 026        _nodeOptions = nodeOptions.Value;
 027        _peerManager = peerManager;
 028    }
 29
 30    public Task StartAsync(CancellationToken cancellationToken)
 31    {
 032        _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 33
 034        foreach (var address in _nodeOptions.ListenAddresses)
 35        {
 036            var parts = address.Split(':');
 037            if (parts.Length != 2 || !int.TryParse(parts[1], out var port))
 38            {
 039                _logger.LogWarning("Invalid listen address: {Address}", address);
 040                continue;
 41            }
 42
 043            var ipAddress = IPAddress.Parse(parts[0]);
 044            var listener = new TcpListener(ipAddress, port);
 045            listener.Start();
 046            _listeners.Add(listener);
 47
 048            _logger.LogInformation("Listening for connections on {Address}:{Port}", ipAddress, port);
 49        }
 50
 051        _listeningTask = ListenForConnectionsAsync(_cts.Token);
 52
 053        return Task.CompletedTask;
 54    }
 55
 56    public async Task StopAsync()
 57    {
 058        if (_cts is null)
 59        {
 060            throw new InvalidOperationException("Service is not running");
 61        }
 62
 063        await _cts.CancelAsync();
 64
 065        foreach (var listener in _listeners)
 66        {
 67            try
 68            {
 069                listener.Stop();
 070            }
 071            catch (Exception ex)
 72            {
 073                _logger.LogError(ex, "Error stopping listener");
 074            }
 75        }
 76
 077        _listeners.Clear();
 78
 079        if (_listeningTask is not null)
 80        {
 81            try
 82            {
 083                await _listeningTask;
 084            }
 085            catch (OperationCanceledException)
 86            {
 87                // Expected during cancellation
 088            }
 89        }
 090    }
 91
 92    private async Task ListenForConnectionsAsync(CancellationToken cancellationToken)
 93    {
 94        try
 95        {
 096            while (!cancellationToken.IsCancellationRequested)
 97            {
 098                foreach (var listener in _listeners)
 99                {
 0100                    if (!listener.Pending())
 101                    {
 102                        continue;
 103                    }
 104
 0105                    var tcpClient = await listener.AcceptTcpClientAsync(cancellationToken);
 0106                    _ = Task.Run(async () =>
 0107                    {
 0108                        try
 0109                        {
 0110                            _logger.LogInformation("New peer connection from {RemoteEndPoint}", tcpClient.Client.RemoteE
 0111                            await _peerManager.AcceptPeerAsync(tcpClient);
 0112                        }
 0113                        catch (Exception e)
 0114                        {
 0115                            _logger.LogError(e, "Error accepting peer connection for {RemoteEndPoint}",
 0116                                tcpClient.Client.RemoteEndPoint);
 0117                        }
 0118                    }, cancellationToken);
 0119                }
 120
 0121                await Task.Delay(100, cancellationToken); // Avoid busy-waiting
 122            }
 0123        }
 0124        catch (OperationCanceledException)
 125        {
 0126            _logger.LogInformation("Stopping listener service");
 0127        }
 0128        catch (Exception e)
 129        {
 0130            _logger.LogError(e, "Unhandled exception in listener service");
 0131        }
 0132    }
 133}