github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/gossip/comm/ack.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package comm
     8  
     9  import (
    10  	"github.com/hechain20/hechain/gossip/common"
    11  	"github.com/hechain20/hechain/gossip/protoext"
    12  	"github.com/hechain20/hechain/gossip/util"
    13  )
    14  
    15  type (
    16  	sendFunc func(peer *RemotePeer, msg *protoext.SignedGossipMessage)
    17  	waitFunc func(*RemotePeer) error
    18  )
    19  
    20  type ackSendOperation struct {
    21  	snd        sendFunc
    22  	waitForAck waitFunc
    23  }
    24  
    25  func newAckSendOperation(snd sendFunc, waitForAck waitFunc) *ackSendOperation {
    26  	return &ackSendOperation{
    27  		snd:        snd,
    28  		waitForAck: waitForAck,
    29  	}
    30  }
    31  
    32  func (aso *ackSendOperation) send(msg *protoext.SignedGossipMessage, minAckNum int, peers ...*RemotePeer) []SendResult {
    33  	successAcks := 0
    34  	results := []SendResult{}
    35  
    36  	acks := make(chan SendResult, len(peers))
    37  	// Send to all peers the message
    38  	for _, p := range peers {
    39  		go func(p *RemotePeer) {
    40  			// Send the message to 'p'
    41  			aso.snd(p, msg)
    42  			// Wait for an ack from 'p', or get an error if timed out
    43  			err := aso.waitForAck(p)
    44  			acks <- SendResult{
    45  				RemotePeer: *p,
    46  				error:      err,
    47  			}
    48  		}(p)
    49  	}
    50  	for {
    51  		ack := <-acks
    52  		results = append(results, SendResult{
    53  			error:      ack.error,
    54  			RemotePeer: ack.RemotePeer,
    55  		})
    56  		if ack.error == nil {
    57  			successAcks++
    58  		}
    59  		if successAcks == minAckNum || len(results) == len(peers) {
    60  			break
    61  		}
    62  	}
    63  	return results
    64  }
    65  
    66  func interceptAcks(nextHandler handler, remotePeerID common.PKIidType, pubSub *util.PubSub) func(*protoext.SignedGossipMessage) {
    67  	return func(m *protoext.SignedGossipMessage) {
    68  		if protoext.IsAck(m.GossipMessage) {
    69  			topic := topicForAck(m.Nonce, remotePeerID)
    70  			pubSub.Publish(topic, m.GetAck())
    71  			return
    72  		}
    73  		nextHandler(m)
    74  	}
    75  }