github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/underlay/internal/readSubscription.go (about)

     1  package internal
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  
     9  	"github.com/libp2p/go-libp2p/core/peer"
    10  
    11  	"github.com/rs/zerolog"
    12  
    13  	"github.com/onflow/flow-go/network/message"
    14  	"github.com/onflow/flow-go/network/p2p"
    15  	validator "github.com/onflow/flow-go/network/validator/pubsub"
    16  	"github.com/onflow/flow-go/utils/logging"
    17  )
    18  
    19  // ReadSubscriptionCallBackFunction the callback called when a new message is received on the read subscription
    20  type ReadSubscriptionCallBackFunction func(msg *message.Message, peerID peer.ID)
    21  
    22  // ReadSubscription reads the messages coming in on the subscription and calls the given callback until
    23  // the context of the subscription is cancelled.
    24  type ReadSubscription struct {
    25  	log      zerolog.Logger
    26  	sub      p2p.Subscription
    27  	callback ReadSubscriptionCallBackFunction
    28  }
    29  
    30  // NewReadSubscription reads the messages coming in on the subscription
    31  func NewReadSubscription(sub p2p.Subscription, callback ReadSubscriptionCallBackFunction, log zerolog.Logger) *ReadSubscription {
    32  	r := ReadSubscription{
    33  		log:      log.With().Str("channel", sub.Topic()).Logger(),
    34  		sub:      sub,
    35  		callback: callback,
    36  	}
    37  
    38  	return &r
    39  }
    40  
    41  // ReceiveLoop must be run in a goroutine. It continuously receives
    42  // messages for the topic and calls the callback synchronously
    43  func (r *ReadSubscription) ReceiveLoop(ctx context.Context) {
    44  	defer r.log.Debug().Msg("exiting receive routine")
    45  
    46  	for {
    47  		// read the next message from libp2p's subscription (blocking call)
    48  		rawMsg, err := r.sub.Next(ctx)
    49  
    50  		if err != nil {
    51  			// network may have cancelled the context
    52  			if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
    53  				return
    54  			}
    55  
    56  			// subscription may have just been cancelled if node is being stopped or the topic has been unsubscribed,
    57  			// don't log error in that case
    58  			// (https://github.com/ipsn/go-ipfs/blob/master/gxlibs/github.com/libp2p/go-libp2p-pubsub/pubsub.go#L435)
    59  			if strings.Contains(err.Error(), "subscription cancelled") {
    60  				return
    61  			}
    62  
    63  			// log any other error
    64  			r.log.Err(err).Msg("failed to read subscription message")
    65  
    66  			return
    67  		}
    68  
    69  		validatorData, ok := rawMsg.ValidatorData.(validator.TopicValidatorData)
    70  		if !ok {
    71  			r.log.Error().
    72  				Str("raw_msg", rawMsg.String()).
    73  				Bool(logging.KeySuspicious, true).
    74  				Str("received_validator_data_type", fmt.Sprintf("%T", rawMsg.ValidatorData)).
    75  				Msg("[BUG] validator data missing!")
    76  			return
    77  		}
    78  
    79  		// call the callback
    80  		r.callback(validatorData.Message, validatorData.From)
    81  	}
    82  }