< Summary - Combined Code Coverage

Information
Class: NLightning.Infrastructure.Protocol.Services.PingPongService
Assembly: NLightning.Infrastructure
File(s): /home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/Protocol/Services/PingPongService.cs
Tag: 30_15166811759
Line coverage
0%
Covered lines: 0
Uncovered lines: 30
Coverable lines: 30
Total lines: 93
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 16
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%
StartPingAsync()0%110100%
HandlePong(...)0%4260%

File(s)

/home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/Protocol/Services/PingPongService.cs

#LineLine coverage
 1using Microsoft.Extensions.Options;
 2
 3namespace NLightning.Infrastructure.Protocol.Services;
 4
 5using Domain.Exceptions;
 6using Domain.Factories;
 7using Domain.Node.Options;
 8using Domain.Protocol.Messages;
 9using Domain.Protocol.Messages.Interfaces;
 10using Domain.Protocol.Services;
 11
 12/// <summary>
 13/// Service for managing the ping pong protocol.
 14/// </summary>
 15/// <remarks>
 16/// This class is used to manage the ping pong protocol.
 17/// </remarks>
 18internal class PingPongService : IPingPongService
 19{
 20    private readonly IMessageFactory _messageFactory;
 21    private readonly NodeOptions _nodeOptions;
 022    private readonly Random _random = new();
 23
 024    private TaskCompletionSource<bool> _pongReceivedTaskSource = new();
 25    private PingMessage _pingMessage;
 26
 27    /// <inheritdoc />
 28    public event EventHandler<IMessage>? PingMessageReadyEvent;
 29
 30    /// <inheritdoc />
 31    public event EventHandler<Exception>? DisconnectEvent;
 32
 033    public PingPongService(IMessageFactory messageFactory, IOptions<NodeOptions> nodeOptions)
 34    {
 035        _messageFactory = messageFactory;
 036        _nodeOptions = nodeOptions.Value;
 037        _pingMessage = (PingMessage)messageFactory.CreatePingMessage();
 038    }
 39
 40    /// <inheritdoc />
 41    /// <remarks>
 42    /// Ping messages are sent to the peer at random intervals ranging from 30 seconds to 5 minutes.
 43    /// If a pong message is not received within the network timeout, DisconnectEvent is raised.
 44    /// </remarks>
 45    public async Task StartPingAsync(CancellationToken cancellationToken)
 46    {
 47        // Send the first ping message
 048        while (!cancellationToken.IsCancellationRequested)
 49        {
 050            PingMessageReadyEvent?.Invoke(this, _pingMessage);
 51
 052            using var pongTimeoutTokenSource = CancellationTokenSource
 053                .CreateLinkedTokenSource(cancellationToken,
 054                                         new CancellationTokenSource(_nodeOptions.NetworkTimeout).Token);
 55
 056            var task = await Task.WhenAny(_pongReceivedTaskSource.Task, Task.Delay(-1, pongTimeoutTokenSource.Token));
 057            if (task.IsFaulted)
 58            {
 059                DisconnectEvent?
 060                    .Invoke(this, new ConnectionException("Pong message not received within network timeout."));
 061                return;
 62            }
 63
 064            if (task.IsCanceled)
 65            {
 066                continue;
 67            }
 68
 069            await Task.Delay(_random.Next(30_000, 300_000), cancellationToken);
 70
 071            _pongReceivedTaskSource = new TaskCompletionSource<bool>();
 072            _pingMessage = (PingMessage)_messageFactory.CreatePingMessage();
 073        }
 074    }
 75
 76    /// <inheritdoc />
 77    /// <remarks>
 78    /// Handles a pong message.
 79    /// If the pong message has a different length than the ping message, DisconnectEvent is raised.
 80    /// </remarks>
 81    public void HandlePong(IMessage message)
 82    {
 83        // if the pong message has a different length than the ping message, disconnect
 084        if (message is not PongMessage pongMessage ||
 085            pongMessage.Payload.BytesLength != _pingMessage.Payload.NumPongBytes)
 86        {
 087            DisconnectEvent?.Invoke(this, new Exception("Pong message has different length than ping message."));
 088            return;
 89        }
 90
 091        _pongReceivedTaskSource.TrySetResult(true);
 092    }
 93}