// checkMessage checks peer message sequence func (p *peer) checkMessage(t msg.Transit) bool { p.wantSequence++ valid := p.wantSequence == t.Sequence() if !valid { p.wantSequence-- } return valid }
// send sends message to peer func (p *peer) send(t msg.Transit) (err error) { if p.connected { p.sentSequence++ t.SetSequence(p.sentSequence) err = t.Send(p.mailbox) if err != nil { p.disconnect() } } return }
// recvFromPeer handles messages coming from other peers func (n *node) recvFromPeer(transit msg.Transit) { if transit == nil { // Invalid transit return } routingID := transit.RoutingID() if len(routingID) < 1 { // Invalid routing id, ignore the peer return } // Router socket tells us the identity of this peer // Identity must be [1] followed by 16-byte UUID, ignore the [1] identity := fmt.Sprintf("%X", routingID[1:]) peer := n.peers[identity] if n.verbose { for i, str := range strings.Split(transit.String(), "\n") { if len(str) <= 0 { continue } if i == 0 && peer != nil { log.Printf("[%s] %s %s", n.name, peer.name, str) } else { log.Printf("[%s] %s", n.name, str) } } } switch m := transit.(type) { case *msg.Hello: // On HELLO we may create the peer if it's unknown // On other cmds the peer must already exist if peer != nil { // Remove fake peers if peer.ready { n.removePeer(peer) } else if n.endpoint == peer.endpoint { // We ignore HELLO, if peer has same endpoint as current node return } } var err error peer, err = n.requirePeer(identity, m.Endpoint) if err == nil { peer.ready = true } else if n.verbose { log.Printf("[%s] %s", n.name, err) } } // Ignore command if peer isn't ready if peer == nil || !peer.ready { if peer != nil { n.removePeer(peer) } return } if !peer.checkMessage(transit) { log.Printf("[%s] lost messages from %s", n.name, identity) return } // Now process each command switch m := transit.(type) { case *msg.Hello: // Store properties from HELLO command into peer peer.name = m.Name peer.status = m.Status event := &Event{ eventType: EventEnter, sender: peer.identity, name: peer.name, address: strings.SplitN(strings.TrimPrefix(m.Endpoint, "tcp://"), ":", 2)[0], headers: make(map[string]string), } // Store peer headers for future reference for key, val := range m.Headers { peer.headers[key] = val event.headers[key] = val } select { case n.events <- event: default: if n.verbose { log.Printf("[%s] Dropping event: %s", n.name, EventEnter) } } // Join peer to listed groups for _, group := range m.Groups { n.joinPeerGroup(peer, group) } // TODO(armen): If peer is a ZRE/LOG collector, connect to it case *msg.Whisper: // Pass up to caller API as WHISPER event select { case n.events <- &Event{eventType: EventWhisper, sender: identity, name: peer.name, msg: m.Content}: default: if n.verbose { log.Printf("[%s] Dropping event: %s", n.name, EventWhisper) } } case *msg.Shout: // Pass up to caller as SHOUT event select { case n.events <- &Event{eventType: EventShout, sender: identity, name: peer.name, group: m.Group, msg: m.Content}: default: if n.verbose { log.Printf("[%s] Dropping event: %s", n.name, EventShout) } } case *msg.Ping: ping := msg.NewPingOk() peer.send(ping) case *msg.Join: n.joinPeerGroup(peer, m.Group) if m.Status != peer.status { panic(fmt.Sprintf("[%X] message status isn't equal to peer status, %d != %d", n.uuid, m.Status, peer.status)) } case *msg.Leave: n.leavePeerGroup(peer, m.Group) if m.Status != peer.status { panic(fmt.Sprintf("[%X] message status isn't equal to peer status, %d != %d", n.uuid, m.Status, peer.status)) } } // Activity from peer resets peer timers peer.refresh() }