github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/gossip/election/adapter.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package election
     8  
     9  import (
    10  	"bytes"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/hyperledger/fabric/gossip/common"
    15  	"github.com/hyperledger/fabric/gossip/discovery"
    16  	"github.com/hyperledger/fabric/gossip/util"
    17  	proto "github.com/hyperledger/fabric/protos/gossip"
    18  	"github.com/op/go-logging"
    19  )
    20  
    21  type msgImpl struct {
    22  	msg *proto.GossipMessage
    23  }
    24  
    25  func (mi *msgImpl) SenderID() peerID {
    26  	return mi.msg.GetLeadershipMsg().PkiId
    27  }
    28  
    29  func (mi *msgImpl) IsProposal() bool {
    30  	return !mi.IsDeclaration()
    31  }
    32  
    33  func (mi *msgImpl) IsDeclaration() bool {
    34  	return mi.msg.GetLeadershipMsg().IsDeclaration
    35  }
    36  
    37  type peerImpl struct {
    38  	member discovery.NetworkMember
    39  }
    40  
    41  func (pi *peerImpl) ID() peerID {
    42  	return peerID(pi.member.PKIid)
    43  }
    44  
    45  type gossip interface {
    46  	// Peers returns the NetworkMembers considered alive
    47  	Peers() []discovery.NetworkMember
    48  
    49  	// Accept returns a dedicated read-only channel for messages sent by other nodes that match a certain predicate.
    50  	// If passThrough is false, the messages are processed by the gossip layer beforehand.
    51  	// If passThrough is true, the gossip layer doesn't intervene and the messages
    52  	// can be used to send a reply back to the sender
    53  	Accept(acceptor common.MessageAcceptor, passThrough bool) (<-chan *proto.GossipMessage, <-chan proto.ReceivedMessage)
    54  
    55  	// Gossip sends a message to other peers to the network
    56  	Gossip(msg *proto.GossipMessage)
    57  }
    58  
    59  type adapterImpl struct {
    60  	gossip    gossip
    61  	selfPKIid common.PKIidType
    62  
    63  	incTime uint64
    64  	seqNum  uint64
    65  
    66  	channel common.ChainID
    67  
    68  	logger *logging.Logger
    69  
    70  	doneCh   chan struct{}
    71  	stopOnce *sync.Once
    72  }
    73  
    74  // NewAdapter creates new leader election adapter
    75  func NewAdapter(gossip gossip, pkiid common.PKIidType, channel common.ChainID) LeaderElectionAdapter {
    76  	return &adapterImpl{
    77  		gossip:    gossip,
    78  		selfPKIid: pkiid,
    79  
    80  		incTime: uint64(time.Now().UnixNano()),
    81  		seqNum:  uint64(0),
    82  
    83  		channel: channel,
    84  
    85  		logger: util.GetLogger(util.LoggingElectionModule, ""),
    86  
    87  		doneCh:   make(chan struct{}),
    88  		stopOnce: &sync.Once{},
    89  	}
    90  }
    91  
    92  func (ai *adapterImpl) Gossip(msg Msg) {
    93  	ai.gossip.Gossip(msg.(*msgImpl).msg)
    94  }
    95  
    96  func (ai *adapterImpl) Accept() <-chan Msg {
    97  	adapterCh, _ := ai.gossip.Accept(func(message interface{}) bool {
    98  		// Get only leadership org and channel messages
    99  		return message.(*proto.GossipMessage).Tag == proto.GossipMessage_CHAN_AND_ORG &&
   100  			message.(*proto.GossipMessage).IsLeadershipMsg() &&
   101  			bytes.Equal(message.(*proto.GossipMessage).Channel, ai.channel)
   102  	}, false)
   103  
   104  	msgCh := make(chan Msg)
   105  
   106  	go func(inCh <-chan *proto.GossipMessage, outCh chan Msg, stopCh chan struct{}) {
   107  		for {
   108  			select {
   109  			case <-stopCh:
   110  				return
   111  			case gossipMsg, ok := <-inCh:
   112  				if ok {
   113  					outCh <- &msgImpl{gossipMsg}
   114  				} else {
   115  					return
   116  				}
   117  			}
   118  		}
   119  	}(adapterCh, msgCh, ai.doneCh)
   120  	return msgCh
   121  }
   122  
   123  func (ai *adapterImpl) CreateMessage(isDeclaration bool) Msg {
   124  	ai.seqNum++
   125  	seqNum := ai.seqNum
   126  
   127  	leadershipMsg := &proto.LeadershipMessage{
   128  		PkiId:         ai.selfPKIid,
   129  		IsDeclaration: isDeclaration,
   130  		Timestamp: &proto.PeerTime{
   131  			IncNum: ai.incTime,
   132  			SeqNum: seqNum,
   133  		},
   134  	}
   135  
   136  	msg := &proto.GossipMessage{
   137  		Nonce:   0,
   138  		Tag:     proto.GossipMessage_CHAN_AND_ORG,
   139  		Content: &proto.GossipMessage_LeadershipMsg{LeadershipMsg: leadershipMsg},
   140  		Channel: ai.channel,
   141  	}
   142  	return &msgImpl{msg}
   143  }
   144  
   145  func (ai *adapterImpl) Peers() []Peer {
   146  	peers := ai.gossip.Peers()
   147  
   148  	var res []Peer
   149  	for _, peer := range peers {
   150  		res = append(res, &peerImpl{peer})
   151  	}
   152  
   153  	return res
   154  }
   155  
   156  func (ai *adapterImpl) Stop() {
   157  	stopFunc := func() {
   158  		close(ai.doneCh)
   159  	}
   160  	ai.stopOnce.Do(stopFunc)
   161  }