github.com/turingchain2020/turingchain@v1.1.21/system/p2p/dht/protocol/broadcast/broadcastv1.go (about)

     1  // Copyright Turing Corp. 2018 All Rights Reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package broadcast
     6  
     7  import (
     8  	"context"
     9  	"sync/atomic"
    10  
    11  	prototypes "github.com/turingchain2020/turingchain/system/p2p/dht/protocol"
    12  	"github.com/turingchain2020/turingchain/types"
    13  	core "github.com/libp2p/go-libp2p-core"
    14  	"github.com/libp2p/go-libp2p-core/peer"
    15  )
    16  
    17  // Handle 处理请求
    18  func (p *broadcastProtocol) handleStreamBroadcastV1(stream core.Stream) {
    19  
    20  	pid := stream.Conn().RemotePeer()
    21  	sPid := pid.Pretty()
    22  	peerAddr := stream.Conn().RemoteMultiaddr().String()
    23  	var data types.MessageBroadCast
    24  	err := prototypes.ReadStream(&data, stream)
    25  	if err != nil {
    26  		log.Error("Handle", "pid", pid.Pretty(), "addr", peerAddr, "err", err)
    27  		return
    28  	}
    29  	_ = p.handleReceive(data.Message, sPid, peerAddr, broadcastV1)
    30  	sendNonBlocking(p.peerV1, pid)
    31  }
    32  
    33  // 增加广播节点, 每个节点分配一个协程处理广播逻辑
    34  func (p *broadcastProtocol) addBroadcastPeer(id peer.ID) {
    35  	// 广播节点加入保护, 避免被连接管理误删除
    36  	pCtx, pCancel := context.WithCancel(p.Ctx)
    37  	p.broadcastPeers[id] = pCancel
    38  	atomic.AddInt32(&p.peerV1Num, 1)
    39  	p.Host.ConnManager().Protect(id, broadcastTag)
    40  	go p.broadcastV1(pCtx, id)
    41  }
    42  
    43  // 移除广播节点
    44  func (p *broadcastProtocol) removeBroadcastPeer(id peer.ID) {
    45  	p.Host.ConnManager().Unprotect(id, broadcastTag)
    46  	delete(p.broadcastPeers, id)
    47  	atomic.AddInt32(&p.peerV1Num, -1)
    48  }
    49  
    50  // 兼容处理老版本的广播
    51  func (p *broadcastProtocol) manageBroadcastV1Peer() {
    52  
    53  	for {
    54  
    55  		select {
    56  		case pid := <-p.peerV1:
    57  			// 老版本限制广播广播数量
    58  			if len(p.broadcastPeers) >= p.p2pCfg.MaxBroadcastPeers {
    59  				break
    60  			}
    61  			_, ok := p.broadcastPeers[pid]
    62  			// 已经存在
    63  			if ok {
    64  				break
    65  			}
    66  			p.addBroadcastPeer(pid)
    67  
    68  		case pid := <-p.exitPeer:
    69  			p.removeBroadcastPeer(pid)
    70  		case pid := <-p.errPeer:
    71  			//错误节点减少tag值, 这样在内部连接超额时会优先断开
    72  			p.Host.ConnManager().UpsertTag(pid, broadcastTag, func(oldVal int) int { return oldVal - 1 })
    73  		case <-p.Ctx.Done():
    74  			return
    75  
    76  		}
    77  	}
    78  }
    79  
    80  //TODO 老版本广播后期全网升级后,可以移除
    81  func (p *broadcastProtocol) broadcastV1(peerCtx context.Context, pid peer.ID) {
    82  
    83  	var stream core.Stream
    84  	var err error
    85  	outgoing := p.ps.Sub(bcTopic)
    86  	sPid := pid.String()
    87  	log.Debug("broadcastV1Start", "pid", sPid)
    88  	defer func() {
    89  		p.ps.Unsub(outgoing)
    90  		sendNonBlocking(p.exitPeer, pid)
    91  		if stream != nil {
    92  			_ = stream.Reset()
    93  		}
    94  		if err != nil {
    95  			sendNonBlocking(p.errPeer, pid)
    96  		}
    97  		log.Debug("broadcastV1End", "pid", sPid)
    98  	}()
    99  
   100  	for {
   101  		select {
   102  		case data := <-outgoing:
   103  			sendData, doSend := p.handleSend(data, sPid)
   104  			if !doSend {
   105  				break //ignore send
   106  			}
   107  			//包装一层MessageBroadCast
   108  			broadData := &types.MessageBroadCast{
   109  				Message: sendData}
   110  
   111  			stream, err = p.Host.NewStream(p.Ctx, pid, broadcastV1)
   112  			if err != nil {
   113  				log.Error("broadcastV1", "pid", sPid, "NewStreamErr", err)
   114  				return
   115  			}
   116  
   117  			err = prototypes.WriteStream(broadData, stream)
   118  			if err != nil {
   119  				log.Error("broadcastV1", "pid", sPid, "WriteStream err", err)
   120  				return
   121  			}
   122  			prototypes.CloseStream(stream)
   123  
   124  		case <-peerCtx.Done():
   125  			return
   126  
   127  		}
   128  	}
   129  
   130  }
   131  
   132  // 相关协程退出时有顺序依赖,统一使用非阻塞模式
   133  func sendNonBlocking(ch chan peer.ID, id peer.ID) {
   134  	select {
   135  	case ch <- id:
   136  	default:
   137  	}
   138  }