// remoteExec sends an encoded command to the remote leader. func (s *Store) remoteExec(b []byte) error { // Retrieve the current known leader. leader := s.raft.Leader() if leader == "" { return errors.New("no leader") } // Create a connection to the leader. conn, err := net.DialTimeout("tcp", leader, 10*time.Second) if err != nil { return err } defer conn.Close() // Write a marker byte for exec messages. _, err = conn.Write([]byte{MuxExecHeader}) if err != nil { return err } // Write a marker message. _, err = conn.Write([]byte(ExecMagic)) if err != nil { return err } // Write command size & bytes. if err := binary.Write(conn, binary.BigEndian, uint64(len(b))); err != nil { return fmt.Errorf("write command size: %s", err) } else if _, err := conn.Write(b); err != nil { return fmt.Errorf("write command: %s", err) } // Read response bytes. var sz uint64 if err := binary.Read(conn, binary.BigEndian, &sz); err != nil { return fmt.Errorf("read response size: %s", err) } buf := make([]byte, sz) if _, err := io.ReadFull(conn, buf); err != nil { return fmt.Errorf("read response: %s", err) } // Unmarshal response. var resp internal.Response if err := proto.Unmarshal(buf, &resp); err != nil { return fmt.Errorf("unmarshal response: %s", err) } else if !resp.GetOK() { return fmt.Errorf("exec failed: %s", resp.GetError()) } // Wait for local FSM to sync to index. if err := s.sync(resp.GetIndex(), 5*time.Second); err != nil { return fmt.Errorf("sync: %s", err) } return nil }