Exemple #1
0
func (s *Server) subscribe(w http.ResponseWriter, r *http.Request) {
	if _, ok := w.(http.Flusher); !ok {
		http.Error(w, "streaming unsupported", http.StatusInternalServerError)
		return
	}

	rd, err := s.newReader(w, r)
	if rd != nil {
		defer rd.Close()
	}
	if err != nil {
		handleError(w, r, err)
		return
	}
	_, err = io.Copy(newWriteFlusher(w), rd)

	netErr, ok := err.(net.Error)
	if ok && netErr.Timeout() {
		util.CountWithData("server.sub.read.timeout", 1, "msg=%q request_id=%q", err, r.Header.Get("Request-Id"))
		return
	}

	if err != nil {
		rollbar.Error(rollbar.ERR, fmt.Errorf("unhandled error: %#v", err))
	}
	util.CountWithData("server.sub.read.finish", 1, "msg=%q request_id=%q", err, r.Header.Get("Request-Id"))
}
Exemple #2
0
func storeOutput(channel string, requestURI string) {
	if buf, err := broker.Get(channel); err == nil {
		if err := storage.Put(requestURI, bytes.NewBuffer(buf)); err != nil {
			util.CountWithData("server.storeOutput.put.error", 1, "err=%s", err.Error())
		}
	} else {
		util.CountWithData("server.storeOutput.get.error", 1, "err=%s", err.Error())
	}
}
Exemple #3
0
func (s *Server) publish(w http.ResponseWriter, r *http.Request) {
	if !util.StringInSlice(r.TransferEncoding, "chunked") {
		http.Error(w, "A chunked Transfer-Encoding header is required.", http.StatusBadRequest)
		return
	}

	writer, err := broker.NewWriter(key(r))
	if err != nil {
		handleError(w, r, err)
		return
	}

	body := bufio.NewReader(r.Body)
	defer r.Body.Close()

	wl, err := broker.Len(writer)
	if err != nil {
		handleError(w, r, err)
		return
	}
	if wl > 0 {
		_, err = body.Discard(int(wl))
		if err != nil {
			handleError(w, r, err)
			return
		}
	}

	_, err = io.Copy(writer, body)

	if err == io.ErrUnexpectedEOF {
		util.CountWithData("server.pub.read.eoferror", 1, "msg=%q request_id=%q", err, r.Header.Get("Request-Id"))
		return
	}

	netErr, ok := err.(net.Error)
	if ok && netErr.Timeout() {
		util.CountWithData("server.pub.read.timeout", 1, "msg=%q request_id=%q", err, r.Header.Get("Request-Id"))
		handleError(w, r, netErr)
		return
	}

	if err != nil {
		log.Printf("%#v", err)
		http.Error(w, "Unhandled error, please try again.", http.StatusInternalServerError)
		rollbar.Error(rollbar.ERR, fmt.Errorf("unhandled error: %#v", err))
		return
	}

	util.CountWithData("server.pub.read.end", 1, "request_id=%q", r.Header.Get("Request-Id"))
	writer.Close()
	// Asynchronously upload the output to our defined storage backend.
	go storeOutput(key(r), requestURI(r), s.StorageBaseURL)
}
Exemple #4
0
func mkstream(w http.ResponseWriter, _ *http.Request) {
	registrar := broker.NewRedisRegistrar()
	uuid, err := util.NewUUID()
	if err != nil {
		http.Error(w, "Unable to create stream. Please try again.", http.StatusServiceUnavailable)
		rollbar.Error(rollbar.ERR, fmt.Errorf("unable to create new uuid for stream: %#v", err))
		util.CountWithData("mkstream.create.fail", 1, "error=%s", err)
		return
	}

	if err := registrar.Register(uuid); err != nil {
		http.Error(w, "Unable to create stream. Please try again.", http.StatusServiceUnavailable)
		rollbar.Error(rollbar.ERR, fmt.Errorf("unable to register stream: %#v", err))
		util.CountWithData("mkstream.create.fail", 1, "error=%s", err)
		return
	}

	util.Count("mkstream.create.success")
	io.WriteString(w, string(uuid))
}
Exemple #5
0
func (s *Server) createStream(w http.ResponseWriter, r *http.Request) {
	registrar := broker.NewRedisRegistrar()

	if err := registrar.Register(key(r)); err != nil {
		http.Error(w, "Unable to create stream. Please try again.", http.StatusServiceUnavailable)
		rollbar.Error(rollbar.ERR, fmt.Errorf("unable to register stream: %#v", err))
		util.CountWithData("put.create.fail", 1, "error=%s", err)
		return
	}
	util.Count("put.create.success")
	w.WriteHeader(http.StatusCreated)
}
Exemple #6
0
// Register registers the new channel
func (rr *RedisRegistrar) Register(channelName string) (err error) {
	conn := redisPool.Get()
	defer conn.Close()

	channel := channel(channelName)

	_, err = conn.Do("SETEX", channel.id(), redisChannelExpire, make([]byte, 0))
	if err != nil {
		util.CountWithData("RedisRegistrar.Register.error", 1, "error=%s", err)
		return
	}
	return
}
Exemple #7
0
// IsRegistered checks whether a channel name is registered
func (rr *RedisRegistrar) IsRegistered(channelName string) (registered bool) {
	conn := redisPool.Get()
	defer conn.Close()

	channel := channel(channelName)

	exists, err := redis.Bool(conn.Do("EXISTS", channel.id()))
	if err != nil {
		util.CountWithData("RedisRegistrar.IsRegistered.error", 1, "error=%s", err)
		return false
	}

	return exists
}
Exemple #8
0
func pub(w http.ResponseWriter, r *http.Request) {
	if !util.StringSliceUtil(r.TransferEncoding).Contains("chunked") {
		http.Error(w, "A chunked Transfer-Encoding header is required.", http.StatusBadRequest)
		return
	}

	writer, err := broker.NewWriter(key(r))
	if err != nil {
		handleError(w, r, err)
		return
	}
	defer writer.Close()

	body := bufio.NewReader(r.Body)
	defer r.Body.Close()

	done := make(chan struct{})

	go func() {
		for {
			select {
			case <-done:
				// Asynchronously upload the output to our defined storage backend.
				go storeOutput(key(r), requestURI(r))
				return
			case <-time.After(*util.StorageInterval):
				// Asynchronously upload the output to our defined storage backend.
				go storeOutput(key(r), requestURI(r))
			}
		}

	}()

	_, err = io.Copy(writer, body)

	if err == io.ErrUnexpectedEOF {
		util.CountWithData("server.pub.read.eoferror", 1, "msg=\"%v\"", err.Error())
		return
	}

	if err != nil {
		log.Printf("%#v", err)
		http.Error(w, "Unhandled error, please try again.", http.StatusInternalServerError)
		rollbar.Error(rollbar.ERR, fmt.Errorf("unhandled error: %#v", err))
		return
	}

	close(done)
}
Exemple #9
0
func (r *reader) Read(p []byte) (n int, err error) {
	if r.closed { // Don't read from a closed redigo connection
		return 0, io.EOF
	}

	if n, err := r.replay(p); n > 0 || err != nil {
		return n, err
	}

	switch msg := r.psc.Receive().(type) {
	case redis.Message:
	case redis.PMessage:
		return r.read(msg, p)
	case redis.Subscription:
	case error:
		util.CountWithData("RedisBroker.redisSubscribe.ReceiveError", 1, "err=%s", msg)
		err = msg
		return
	}
	return
}
Exemple #10
0
func handleError(w http.ResponseWriter, r *http.Request, err error) {
	switch err {
	case broker.ErrNotRegistered, storage.ErrNoStorage, storage.ErrNotFound:
		message := "Channel is not registered."
		if r.Header.Get("Accept") == "text/ascii; version=feral" {
			message = assets.HttpCatGone
		}

		http.Error(w, message, http.StatusNotFound)

	case storage.ErrRange:
		w.WriteHeader(http.StatusRequestedRangeNotSatisfiable)

	case errNoContent:
		// As indicated in the w3 spec[1] an SSE stream
		// that's already done should return a `204 No Content`
		// [1]: http://www.w3.org/TR/2012/WD-eventsource-20120426/
		w.WriteHeader(http.StatusNoContent)

	default:
		util.CountWithData("server.handleError", 1, "error=%s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
	}
}