Exemplo n.º 1
0
// recvFromAPI handles a new command received from front-end
func (n *node) recvFromAPI(c *cmd) {

	if n.verbose {
		log.Printf("[%s] Received a %q command from API", n.name, c.cmd)
	}

	switch c.cmd {
	case cmdUUID:
		n.replies <- &reply{cmd: cmdUUID, payload: n.identity()}

	case cmdName:
		n.replies <- &reply{cmd: cmdName, payload: n.name}

	case cmdSetName:
		n.name = c.payload.(string)

	case cmdSetHeader:
		n.headers[c.key] = c.payload.(string)

	case cmdSetVerbose:
		n.verbose = c.payload.(bool)
		// n.reactor.SetVerbose(n.verbose)

	case cmdSetPort:
		n.beaconPort = c.payload.(int)

	case cmdSetInterval:
		// Set beacon interval
		n.interval = c.payload.(time.Duration)

	case cmdSetIface:
		n.beacon.SetInterface(c.payload.(string))

	case cmdSetEndpoint:
		err := n.gossipStart()
		if err != nil {
			// Signal the caller and send back the error if any
			n.replies <- &reply{cmd: cmdSetEndpoint, err: err}
			break
		}

		endpoint := c.payload.(string)
		n.endpoint, _, err = bind(n.inbox, endpoint)
		if err != nil {
			n.replies <- &reply{cmd: cmdSetEndpoint, err: err}
			break
		}
		n.bound = true
		n.beaconPort = 0

		n.replies <- &reply{cmd: cmdSetEndpoint}

	case cmdGossipBind:
		err := n.gossipStart()
		if err != nil {
			n.replies <- &reply{cmd: cmdGossipBind, err: err}
			break
		}

		endpoint := c.payload.(string)
		err = n.gossip.SendCmd("BIND", endpoint, 5*time.Second)
		n.replies <- &reply{cmd: cmdGossipBind, err: err}

	case cmdGossipPort:
		err := n.gossip.SendCmd("PORT", nil, 5*time.Second)
		if err != nil {
			n.replies <- &reply{cmd: cmdGossipPort, err: err}
			break
		}
		port, err := n.gossip.RecvResp(5 * time.Second)
		if err != nil {
			n.replies <- &reply{cmd: cmdGossipPort, err: err}
			break
		}
		n.replies <- &reply{cmd: cmdGossipPort, payload: strconv.FormatUint(uint64(port.(uint16)), 10)}

	case cmdGossipConnect:
		err := n.gossipStart()
		if err != nil {
			n.replies <- &reply{cmd: cmdGossipConnect, err: err}
			break
		}

		endpoint := c.payload.(string)
		err = n.gossip.SendCmd("CONNECT", endpoint, 5*time.Second)
		n.replies <- &reply{cmd: cmdGossipConnect, err: err}

	case cmdStart:
		// Add the ping ticker just right before start so that it reads the latest
		// value of loopInterval
		n.reactor.AddChannelTime(time.Tick(loopInterval), 1, func(interface{}) error {
			n.ping()
			return nil
		})

		err := n.start()
		// Signal the caller and send back the error if any
		n.replies <- &reply{cmd: cmdStart, err: err}

	case cmdStop, cmdTerm:
		if n.terminated != nil {
			close(n.terminated)
		}

		// Wait and send the signal in a separate go routine
		// because closing terminated channel
		go func() {
			n.wg.Wait()
			// Signal the caller
			n.replies <- &reply{}
		}()

	case cmdWhisper:
		// Get peer to send message to
		peer, ok := n.peers[c.key]

		// Send frame on out to peer's mailbox, drop message
		// if peer doesn't exist (may have been destroyed)
		if ok {
			m := msg.NewWhisper()
			m.Content = c.payload.([]byte)
			peer.send(m)
		}

	case cmdShout:
		group := c.key
		// Get group to send message to
		if g, ok := n.peerGroups[group]; ok {
			m := msg.NewShout()
			m.Group = group
			m.Content = c.payload.([]byte)
			g.send(m)
		}

	case cmdJoin:
		group := c.key
		if _, ok := n.ownGroups[group]; !ok {

			// Only send if we're not already in group
			n.ownGroups[group] = newGroup(group)
			m := msg.NewJoin()
			m.Group = group

			// Update status before sending command
			n.status++
			m.Status = n.status

			for _, peer := range n.peers {
				cloned := msg.Clone(m)
				peer.send(cloned)
			}
		}

	case cmdLeave:
		group := c.key
		if _, ok := n.ownGroups[group]; ok {
			// Only send if we are actually in group
			m := msg.NewLeave()
			m.Group = group

			// Update status before sending command
			n.status++
			m.Status = n.status

			for _, peer := range n.peers {
				cloned := msg.Clone(m)
				peer.send(cloned)
			}
			delete(n.ownGroups, group)
		}

	case cmdDump:
		// TODO: implement DUMP

	case cmdAddr:
		if n.beaconPort > 0 {
			n.replies <- &reply{cmd: cmdAddr, payload: n.beacon.Addr()}
		} else {
			u, err := url.Parse(n.endpoint)
			if err != nil {
				n.replies <- &reply{cmd: cmdHeader, err: err}
				return
			}
			ip, _, err := net.SplitHostPort(u.Host)
			if err != nil {
				n.replies <- &reply{cmd: cmdHeader, err: err}
				return
			}

			n.replies <- &reply{cmd: cmdAddr, payload: ip}
		}

	case cmdHeader:
		header, ok := n.headers[c.key]

		var err error
		if !ok {
			err = errors.New("Header doesn't exist")
		}

		n.replies <- &reply{cmd: cmdHeader, err: err, payload: header}

	case cmdHeaders:
		n.replies <- &reply{cmd: cmdHeader, payload: n.headers}

	default:
		log.Printf("Invalid command %q %#v", c.cmd, c)
	}
}
Exemplo n.º 2
0
// Send sends message to all peers in group
func (g *group) send(m msg.Transit) {
	for _, peer := range g.peers {
		cloned := msg.Clone(m)
		peer.send(cloned)
	}
}