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 }