github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/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/ShyftNetwork/go-empyrean/p2p/enode" 24 "github.com/ShyftNetwork/go-empyrean/p2p/simulations" 25 ) 26 27 // PeerEvent is the type of the channel returned by Simulation.PeerEvents. 28 type PeerEvent struct { 29 // NodeID is the ID of node that the event is caught on. 30 NodeID enode.ID 31 // PeerID is the ID of the peer node that the event is caught on. 32 PeerID enode.ID 33 // Event is the event that is caught. 34 Event *simulations.Event 35 // Error is the error that may have happened during event watching. 36 Error error 37 } 38 39 // PeerEventsFilter defines a filter on PeerEvents to exclude messages with 40 // defined properties. Use PeerEventsFilter methods to set required options. 41 type PeerEventsFilter struct { 42 eventType simulations.EventType 43 44 connUp *bool 45 46 msgReceive *bool 47 protocol *string 48 msgCode *uint64 49 } 50 51 // NewPeerEventsFilter returns a new PeerEventsFilter instance. 52 func NewPeerEventsFilter() *PeerEventsFilter { 53 return &PeerEventsFilter{} 54 } 55 56 // Connect sets the filter to events when two nodes connect. 57 func (f *PeerEventsFilter) Connect() *PeerEventsFilter { 58 f.eventType = simulations.EventTypeConn 59 b := true 60 f.connUp = &b 61 return f 62 } 63 64 // Drop sets the filter to events when two nodes disconnect. 65 func (f *PeerEventsFilter) Drop() *PeerEventsFilter { 66 f.eventType = simulations.EventTypeConn 67 b := false 68 f.connUp = &b 69 return f 70 } 71 72 // ReceivedMessages sets the filter to only messages that are received. 73 func (f *PeerEventsFilter) ReceivedMessages() *PeerEventsFilter { 74 f.eventType = simulations.EventTypeMsg 75 b := true 76 f.msgReceive = &b 77 return f 78 } 79 80 // SentMessages sets the filter to only messages that are sent. 81 func (f *PeerEventsFilter) SentMessages() *PeerEventsFilter { 82 f.eventType = simulations.EventTypeMsg 83 b := false 84 f.msgReceive = &b 85 return f 86 } 87 88 // Protocol sets the filter to only one message protocol. 89 func (f *PeerEventsFilter) Protocol(p string) *PeerEventsFilter { 90 f.eventType = simulations.EventTypeMsg 91 f.protocol = &p 92 return f 93 } 94 95 // MsgCode sets the filter to only one msg code. 96 func (f *PeerEventsFilter) MsgCode(c uint64) *PeerEventsFilter { 97 f.eventType = simulations.EventTypeMsg 98 f.msgCode = &c 99 return f 100 } 101 102 // PeerEvents returns a channel of events that are captured by admin peerEvents 103 // subscription nodes with provided NodeIDs. Additional filters can be set to ignore 104 // events that are not relevant. 105 func (s *Simulation) PeerEvents(ctx context.Context, ids []enode.ID, filters ...*PeerEventsFilter) <-chan PeerEvent { 106 eventC := make(chan PeerEvent) 107 108 // wait group to make sure all subscriptions to admin peerEvents are established 109 // before this function returns. 110 var subsWG sync.WaitGroup 111 for _, id := range ids { 112 s.shutdownWG.Add(1) 113 subsWG.Add(1) 114 go func(id enode.ID) { 115 defer s.shutdownWG.Done() 116 117 events := make(chan *simulations.Event) 118 sub := s.Net.Events().Subscribe(events) 119 defer sub.Unsubscribe() 120 121 subsWG.Done() 122 123 for { 124 select { 125 case <-ctx.Done(): 126 if err := ctx.Err(); err != nil { 127 select { 128 case eventC <- PeerEvent{NodeID: id, Error: err}: 129 case <-s.Done(): 130 } 131 } 132 return 133 case <-s.Done(): 134 return 135 case e := <-events: 136 // ignore control events 137 if e.Control { 138 continue 139 } 140 match := len(filters) == 0 // if there are no filters match all events 141 for _, f := range filters { 142 if f.eventType == simulations.EventTypeConn && e.Conn != nil { 143 if *f.connUp != e.Conn.Up { 144 continue 145 } 146 // all connection filter parameters matched, break the loop 147 match = true 148 break 149 } 150 if f.eventType == simulations.EventTypeMsg && e.Msg != nil { 151 if f.msgReceive != nil && *f.msgReceive != e.Msg.Received { 152 continue 153 } 154 if f.protocol != nil && *f.protocol != e.Msg.Protocol { 155 continue 156 } 157 if f.msgCode != nil && *f.msgCode != e.Msg.Code { 158 continue 159 } 160 // all message filter parameters matched, break the loop 161 match = true 162 break 163 } 164 } 165 var peerID enode.ID 166 switch e.Type { 167 case simulations.EventTypeConn: 168 peerID = e.Conn.One 169 if peerID == id { 170 peerID = e.Conn.Other 171 } 172 case simulations.EventTypeMsg: 173 peerID = e.Msg.One 174 if peerID == id { 175 peerID = e.Msg.Other 176 } 177 } 178 if match { 179 select { 180 case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Event: e}: 181 case <-ctx.Done(): 182 if err := ctx.Err(); err != nil { 183 select { 184 case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Error: err}: 185 case <-s.Done(): 186 } 187 } 188 return 189 case <-s.Done(): 190 return 191 } 192 } 193 case err := <-sub.Err(): 194 if err != nil { 195 select { 196 case eventC <- PeerEvent{NodeID: id, Error: err}: 197 case <-ctx.Done(): 198 if err := ctx.Err(); err != nil { 199 select { 200 case eventC <- PeerEvent{NodeID: id, Error: err}: 201 case <-s.Done(): 202 } 203 } 204 return 205 case <-s.Done(): 206 return 207 } 208 } 209 } 210 } 211 }(id) 212 } 213 214 // wait all subscriptions 215 subsWG.Wait() 216 return eventC 217 }