|
@ -29,89 +29,100 @@ or more `Channels`. So while sending outgoing messages is typically performed o |
|
|
incoming messages are received on the reactor. |
|
|
incoming messages are received on the reactor. |
|
|
*/ |
|
|
*/ |
|
|
type Switch struct { |
|
|
type Switch struct { |
|
|
reactors []Reactor |
|
|
|
|
|
|
|
|
chainId string |
|
|
|
|
|
reactors map[string]Reactor |
|
|
chDescs []*ChannelDescriptor |
|
|
chDescs []*ChannelDescriptor |
|
|
reactorsByCh map[byte]Reactor |
|
|
reactorsByCh map[byte]Reactor |
|
|
peers *PeerSet |
|
|
peers *PeerSet |
|
|
dialing *CMap |
|
|
dialing *CMap |
|
|
listeners *CMap // listenerName -> chan interface{}
|
|
|
|
|
|
quit chan struct{} |
|
|
|
|
|
started uint32 |
|
|
|
|
|
stopped uint32 |
|
|
|
|
|
chainId string |
|
|
|
|
|
|
|
|
listeners *CMap // listenerName -> chan interface{}
|
|
|
|
|
|
running uint32 // atomic
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var ( |
|
|
var ( |
|
|
ErrSwitchStopped = errors.New("Switch already stopped") |
|
|
|
|
|
ErrSwitchDuplicatePeer = errors.New("Duplicate peer") |
|
|
ErrSwitchDuplicatePeer = errors.New("Duplicate peer") |
|
|
|
|
|
ErrSwitchStopped = errors.New("Switch stopped") |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
const ( |
|
|
const ( |
|
|
peerDialTimeoutSeconds = 3 |
|
|
peerDialTimeoutSeconds = 3 |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
func NewSwitch(reactors []Reactor) *Switch { |
|
|
|
|
|
|
|
|
|
|
|
// Validate the reactors. no two reactors can share the same channel.
|
|
|
|
|
|
chDescs := []*ChannelDescriptor{} |
|
|
|
|
|
reactorsByCh := make(map[byte]Reactor) |
|
|
|
|
|
for _, reactor := range reactors { |
|
|
|
|
|
reactorChannels := reactor.GetChannels() |
|
|
|
|
|
for _, chDesc := range reactorChannels { |
|
|
|
|
|
chId := chDesc.Id |
|
|
|
|
|
if reactorsByCh[chId] != nil { |
|
|
|
|
|
panic(fmt.Sprintf("Channel %X has multiple reactors %v & %v", chId, reactorsByCh[chId], reactor)) |
|
|
|
|
|
} |
|
|
|
|
|
chDescs = append(chDescs, chDesc) |
|
|
|
|
|
reactorsByCh[chId] = reactor |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
func NewSwitch() *Switch { |
|
|
|
|
|
|
|
|
sw := &Switch{ |
|
|
sw := &Switch{ |
|
|
reactors: reactors, |
|
|
|
|
|
chDescs: chDescs, |
|
|
|
|
|
reactorsByCh: reactorsByCh, |
|
|
|
|
|
|
|
|
chainId: "", |
|
|
|
|
|
reactors: make(map[string]Reactor), |
|
|
|
|
|
chDescs: make([]*ChannelDescriptor, 0), |
|
|
|
|
|
reactorsByCh: make(map[byte]Reactor), |
|
|
peers: NewPeerSet(), |
|
|
peers: NewPeerSet(), |
|
|
dialing: NewCMap(), |
|
|
dialing: NewCMap(), |
|
|
listeners: NewCMap(), |
|
|
listeners: NewCMap(), |
|
|
quit: make(chan struct{}), |
|
|
|
|
|
stopped: 0, |
|
|
|
|
|
|
|
|
running: 0, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return sw |
|
|
return sw |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (sw *Switch) Start() { |
|
|
|
|
|
if atomic.CompareAndSwapUint32(&sw.started, 0, 1) { |
|
|
|
|
|
log.Info("Starting Switch") |
|
|
|
|
|
for _, reactor := range sw.reactors { |
|
|
|
|
|
reactor.Start(sw) |
|
|
|
|
|
|
|
|
func (sw *Switch) SetChainId(hash []byte, network string) { |
|
|
|
|
|
sw.chainId = hex.EncodeToString(hash) + "-" + network |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (sw *Switch) AddReactor(name string, reactor Reactor) { |
|
|
|
|
|
// Validate the reactor.
|
|
|
|
|
|
// No two reactors can share the same channel.
|
|
|
|
|
|
reactorChannels := reactor.GetChannels() |
|
|
|
|
|
for _, chDesc := range reactorChannels { |
|
|
|
|
|
chId := chDesc.Id |
|
|
|
|
|
if sw.reactorsByCh[chId] != nil { |
|
|
|
|
|
panic(fmt.Sprintf("Channel %X has multiple reactors %v & %v", chId, sw.reactorsByCh[chId], reactor)) |
|
|
} |
|
|
} |
|
|
|
|
|
sw.chDescs = append(sw.chDescs, chDesc) |
|
|
|
|
|
sw.reactorsByCh[chId] = reactor |
|
|
} |
|
|
} |
|
|
|
|
|
sw.reactors[name] = reactor |
|
|
|
|
|
time.Sleep(1 * time.Second) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (sw *Switch) Stop() { |
|
|
|
|
|
if atomic.CompareAndSwapUint32(&sw.stopped, 0, 1) { |
|
|
|
|
|
log.Info("Stopping Switch") |
|
|
|
|
|
close(sw.quit) |
|
|
|
|
|
// Stop each peer.
|
|
|
|
|
|
for _, peer := range sw.peers.List() { |
|
|
|
|
|
peer.stop() |
|
|
|
|
|
} |
|
|
|
|
|
sw.peers = NewPeerSet() |
|
|
|
|
|
// Stop all reactors.
|
|
|
|
|
|
for _, reactor := range sw.reactors { |
|
|
|
|
|
reactor.Stop() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
func (sw *Switch) StartReactor(name string) { |
|
|
|
|
|
atomic.StoreUint32(&sw.running, 1) |
|
|
|
|
|
sw.reactors[name].Start(sw) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience function
|
|
|
|
|
|
func (sw *Switch) StartAll() { |
|
|
|
|
|
atomic.StoreUint32(&sw.running, 1) |
|
|
|
|
|
for _, reactor := range sw.reactors { |
|
|
|
|
|
reactor.Start(sw) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (sw *Switch) StopReactor(name string) { |
|
|
|
|
|
sw.reactors[name].Stop() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Convenience function
|
|
|
|
|
|
// Not goroutine safe
|
|
|
|
|
|
func (sw *Switch) StopAll() { |
|
|
|
|
|
atomic.StoreUint32(&sw.running, 0) |
|
|
|
|
|
// Stop each peer.
|
|
|
|
|
|
for _, peer := range sw.peers.List() { |
|
|
|
|
|
peer.stop() |
|
|
|
|
|
} |
|
|
|
|
|
sw.peers = NewPeerSet() |
|
|
|
|
|
// Stop all reactors.
|
|
|
|
|
|
for _, reactor := range sw.reactors { |
|
|
|
|
|
reactor.Stop() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (sw *Switch) Reactors() []Reactor { |
|
|
|
|
|
|
|
|
// Not goroutine safe
|
|
|
|
|
|
func (sw *Switch) Reactors() map[string]Reactor { |
|
|
return sw.reactors |
|
|
return sw.reactors |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (sw *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, error) { |
|
|
func (sw *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, error) { |
|
|
if atomic.LoadUint32(&sw.stopped) == 1 { |
|
|
|
|
|
|
|
|
if atomic.LoadUint32(&sw.running) == 0 { |
|
|
return nil, ErrSwitchStopped |
|
|
return nil, ErrSwitchStopped |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -125,12 +136,12 @@ func (sw *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, er |
|
|
return nil, ErrSwitchDuplicatePeer |
|
|
return nil, ErrSwitchDuplicatePeer |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Start the peer
|
|
|
|
|
|
go peer.start() |
|
|
|
|
|
|
|
|
|
|
|
// Notify listeners.
|
|
|
// Notify listeners.
|
|
|
sw.doAddPeer(peer) |
|
|
sw.doAddPeer(peer) |
|
|
|
|
|
|
|
|
|
|
|
// Start the peer
|
|
|
|
|
|
go peer.start() |
|
|
|
|
|
|
|
|
// Send handshake
|
|
|
// Send handshake
|
|
|
msg := &pexHandshakeMessage{ChainId: sw.chainId} |
|
|
msg := &pexHandshakeMessage{ChainId: sw.chainId} |
|
|
peer.Send(PexChannel, msg) |
|
|
peer.Send(PexChannel, msg) |
|
@ -139,7 +150,7 @@ func (sw *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, er |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (sw *Switch) DialPeerWithAddress(addr *NetAddress) (*Peer, error) { |
|
|
func (sw *Switch) DialPeerWithAddress(addr *NetAddress) (*Peer, error) { |
|
|
if atomic.LoadUint32(&sw.stopped) == 1 { |
|
|
|
|
|
|
|
|
if atomic.LoadUint32(&sw.running) == 0 { |
|
|
return nil, ErrSwitchStopped |
|
|
return nil, ErrSwitchStopped |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -168,7 +179,7 @@ func (sw *Switch) IsDialing(addr *NetAddress) bool { |
|
|
// trying to send for defaultSendTimeoutSeconds. Returns a channel
|
|
|
// trying to send for defaultSendTimeoutSeconds. Returns a channel
|
|
|
// which receives success values for each attempted send (false if times out)
|
|
|
// which receives success values for each attempted send (false if times out)
|
|
|
func (sw *Switch) Broadcast(chId byte, msg interface{}) chan bool { |
|
|
func (sw *Switch) Broadcast(chId byte, msg interface{}) chan bool { |
|
|
if atomic.LoadUint32(&sw.stopped) == 1 { |
|
|
|
|
|
|
|
|
if atomic.LoadUint32(&sw.running) == 0 { |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
|
successChan := make(chan bool, len(sw.peers.List())) |
|
|
successChan := make(chan bool, len(sw.peers.List())) |
|
@ -223,16 +234,12 @@ func (sw *Switch) StopPeerGracefully(peer *Peer) { |
|
|
sw.doRemovePeer(peer, nil) |
|
|
sw.doRemovePeer(peer, nil) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (sw *Switch) SetChainId(hash []byte, network string) { |
|
|
|
|
|
sw.chainId = hex.EncodeToString(hash) + "-" + network |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (sw *Switch) IsListening() bool { |
|
|
func (sw *Switch) IsListening() bool { |
|
|
return sw.listeners.Size() > 0 |
|
|
return sw.listeners.Size() > 0 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (sw *Switch) doAddPeer(peer *Peer) { |
|
|
func (sw *Switch) doAddPeer(peer *Peer) { |
|
|
for _, reactor := range sw.reactors { |
|
|
|
|
|
|
|
|
for name, reactor := range sw.reactors { |
|
|
reactor.AddPeer(peer) |
|
|
reactor.AddPeer(peer) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|