influxdb/messaging/handler.go

118 lines
2.7 KiB
Go
Raw Normal View History

2014-10-21 02:42:03 +00:00
package messaging
2014-10-02 02:49:21 +00:00
import (
2014-10-24 00:54:12 +00:00
"io/ioutil"
2014-10-02 02:49:21 +00:00
"net/http"
2014-10-24 00:54:12 +00:00
"strconv"
2014-10-02 02:49:21 +00:00
"strings"
"github.com/influxdb/influxdb/raft"
)
2014-10-17 04:11:28 +00:00
// Handler represents an HTTP handler by the broker.
type Handler struct {
raftHandler *raft.HTTPHandler
broker *Broker
2014-10-02 02:49:21 +00:00
}
2014-10-17 04:11:28 +00:00
// NewHandler returns a new instance of Handler.
func NewHandler(b *Broker) *Handler {
return &Handler{
raftHandler: raft.NewHTTPHandler(b.log),
2014-10-03 03:13:42 +00:00
broker: b,
2014-10-02 02:49:21 +00:00
}
}
2014-11-13 05:32:42 +00:00
// Broker returns the broker on the handler.
func (h *Handler) Broker() *Broker { return h.broker }
2014-10-02 02:49:21 +00:00
// ServeHTTP serves an HTTP request.
2014-10-17 04:11:28 +00:00
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
2014-10-02 02:49:21 +00:00
// Delegate raft requests to its own handler.
if strings.HasPrefix(r.URL.Path, "/raft") {
2014-10-17 04:11:28 +00:00
h.raftHandler.ServeHTTP(w, r)
2014-10-02 02:49:21 +00:00
return
}
2014-10-03 03:13:42 +00:00
// Route all InfluxDB broker requests.
2014-10-02 02:49:21 +00:00
switch r.URL.Path {
2014-11-13 05:32:42 +00:00
case "/messages":
2014-10-24 00:54:12 +00:00
if r.Method == "GET" {
h.stream(w, r)
2014-11-13 05:32:42 +00:00
} else if r.Method == "POST" {
2014-10-24 00:54:12 +00:00
h.publish(w, r)
} else {
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
}
2014-11-13 05:32:42 +00:00
default:
http.NotFound(w, r)
2014-10-02 02:49:21 +00:00
}
}
2014-10-17 04:11:28 +00:00
// connects the requestor as the replica's writer.
2014-10-24 00:54:12 +00:00
func (h *Handler) stream(w http.ResponseWriter, r *http.Request) {
2014-10-17 04:11:28 +00:00
// Retrieve the replica name.
name := r.URL.Query().Get("name")
if name == "" {
2014-10-24 00:54:12 +00:00
h.error(w, ErrReplicaNameRequired, http.StatusBadRequest)
2014-10-17 04:11:28 +00:00
return
}
// Find the replica on the broker.
replica := h.broker.Replica(name)
if replica == nil {
2014-10-24 00:54:12 +00:00
h.error(w, ErrReplicaNotFound, http.StatusNotFound)
2014-10-17 04:11:28 +00:00
return
}
// Connect the response writer to the replica.
// This will block until the replica is closed or a new writer connects.
_, _ = replica.WriteTo(w)
}
2014-10-24 00:54:12 +00:00
// publishes a message to the broker.
func (h *Handler) publish(w http.ResponseWriter, r *http.Request) {
m := &Message{}
// Read the message type.
if n, err := strconv.ParseUint(r.URL.Query().Get("type"), 10, 16); err != nil {
h.error(w, ErrMessageTypeRequired, http.StatusBadRequest)
return
} else {
m.Type = MessageType(n)
}
// Read the topic ID.
if n, err := strconv.ParseUint(r.URL.Query().Get("topicID"), 10, 32); err != nil {
h.error(w, ErrTopicRequired, http.StatusBadRequest)
return
} else {
m.TopicID = uint64(n)
2014-10-24 00:54:12 +00:00
}
// Read the request body.
data, err := ioutil.ReadAll(r.Body)
if err != nil {
h.error(w, err, http.StatusInternalServerError)
return
}
m.Data = data
// Publish message to the broker.
index, err := h.broker.Publish(m)
if err != nil {
h.error(w, err, http.StatusInternalServerError)
return
}
// Return index.
w.Header().Set("X-Broker-Index", strconv.FormatUint(index, 10))
}
// error writes an error to the client and sets the status code.
func (h *Handler) error(w http.ResponseWriter, err error, code int) {
s := err.Error()
w.Header().Set("X-Broker-Error", s)
http.Error(w, s, code)
}