github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/network/simulation/events.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package simulation 18 19 import ( 20 "context" 21 "sync" 22 23 "github.com/FusionFoundation/efsn/p2p/discover" 24 25 "github.com/FusionFoundation/efsn/p2p" 26 ) 27 28 // PeerEvent is the type of the channel returned by Simulation.PeerEvents. 29 type PeerEvent struct { 30 // NodeID is the ID of node that the event is caught on. 31 NodeID discover.NodeID 32 // Event is the event that is caught. 33 Event *p2p.PeerEvent 34 // Error is the error that may have happened during event watching. 35 Error error 36 } 37 38 // PeerEventsFilter defines a filter on PeerEvents to exclude messages with 39 // defined properties. Use PeerEventsFilter methods to set required options. 40 type PeerEventsFilter struct { 41 t *p2p.PeerEventType 42 protocol *string 43 msgCode *uint64 44 } 45 46 // NewPeerEventsFilter returns a new PeerEventsFilter instance. 47 func NewPeerEventsFilter() *PeerEventsFilter { 48 return &PeerEventsFilter{} 49 } 50 51 // Type sets the filter to only one peer event type. 52 func (f *PeerEventsFilter) Type(t p2p.PeerEventType) *PeerEventsFilter { 53 f.t = &t 54 return f 55 } 56 57 // Protocol sets the filter to only one message protocol. 58 func (f *PeerEventsFilter) Protocol(p string) *PeerEventsFilter { 59 f.protocol = &p 60 return f 61 } 62 63 // MsgCode sets the filter to only one msg code. 64 func (f *PeerEventsFilter) MsgCode(c uint64) *PeerEventsFilter { 65 f.msgCode = &c 66 return f 67 } 68 69 // PeerEvents returns a channel of events that are captured by admin peerEvents 70 // subscription nodes with provided NodeIDs. Additional filters can be set to ignore 71 // events that are not relevant. 72 func (s *Simulation) PeerEvents(ctx context.Context, ids []discover.NodeID, filters ...*PeerEventsFilter) <-chan PeerEvent { 73 eventC := make(chan PeerEvent) 74 75 // wait group to make sure all subscriptions to admin peerEvents are established 76 // before this function returns. 77 var subsWG sync.WaitGroup 78 for _, id := range ids { 79 s.shutdownWG.Add(1) 80 subsWG.Add(1) 81 go func(id discover.NodeID) { 82 defer s.shutdownWG.Done() 83 84 client, err := s.Net.GetNode(id).Client() 85 if err != nil { 86 subsWG.Done() 87 eventC <- PeerEvent{NodeID: id, Error: err} 88 return 89 } 90 events := make(chan *p2p.PeerEvent) 91 sub, err := client.Subscribe(ctx, "admin", events, "peerEvents") 92 if err != nil { 93 subsWG.Done() 94 eventC <- PeerEvent{NodeID: id, Error: err} 95 return 96 } 97 defer sub.Unsubscribe() 98 99 subsWG.Done() 100 101 for { 102 select { 103 case <-ctx.Done(): 104 if err := ctx.Err(); err != nil { 105 select { 106 case eventC <- PeerEvent{NodeID: id, Error: err}: 107 case <-s.Done(): 108 } 109 } 110 return 111 case <-s.Done(): 112 return 113 case e := <-events: 114 match := len(filters) == 0 // if there are no filters match all events 115 for _, f := range filters { 116 if f.t != nil && *f.t != e.Type { 117 continue 118 } 119 if f.protocol != nil && *f.protocol != e.Protocol { 120 continue 121 } 122 if f.msgCode != nil && e.MsgCode != nil && *f.msgCode != *e.MsgCode { 123 continue 124 } 125 // all filter parameters matched, break the loop 126 match = true 127 break 128 } 129 if match { 130 select { 131 case eventC <- PeerEvent{NodeID: id, Event: e}: 132 case <-ctx.Done(): 133 if err := ctx.Err(); err != nil { 134 select { 135 case eventC <- PeerEvent{NodeID: id, Error: err}: 136 case <-s.Done(): 137 } 138 } 139 return 140 case <-s.Done(): 141 return 142 } 143 } 144 case err := <-sub.Err(): 145 if err != nil { 146 select { 147 case eventC <- PeerEvent{NodeID: id, Error: err}: 148 case <-ctx.Done(): 149 if err := ctx.Err(); err != nil { 150 select { 151 case eventC <- PeerEvent{NodeID: id, Error: err}: 152 case <-s.Done(): 153 } 154 } 155 return 156 case <-s.Done(): 157 return 158 } 159 } 160 } 161 } 162 }(id) 163 } 164 165 // wait all subscriptions 166 subsWG.Wait() 167 return eventC 168 }