// 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) } }
// 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) } }