Example #1
0
// JSONMiddleware provides a JSONContextEndpoint hook wrapped around all requests.
// In this implementation, we're using it to provide application logging and to check errors
// and provide generic responses.
func (s *RPCService) JSONMiddleware(j server.JSONContextEndpoint) server.JSONContextEndpoint {
	return func(ctx context.Context, r *http.Request) (int, interface{}, error) {
		status, res, err := j(ctx, r)
		if err != nil {
			server.LogWithFields(r).WithFields(logrus.Fields{
				"error": err,
			}).Error("problems with serving request")
			return http.StatusServiceUnavailable, nil, &jsonErr{"sorry, this service is unavailable"}
		}

		server.LogWithFields(r).Info("success!")
		return status, res, nil
	}
}
Example #2
0
File: cats.go Project: strogo/gizmo
func (s *SimpleService) GetCats(w http.ResponseWriter, r *http.Request) {
	res, err := s.client.SemanticConceptSearch("des", "cats")
	if err != nil {
		server.LogWithFields(r).WithFields(logrus.Fields{
			"error": err,
		}).Error("unable to perform semantic search")
		http.Error(w, "unable to perform cat search", http.StatusServiceUnavailable)
		return
	}

	w.Header().Add("Content-Type", "text/html; charset=utf-8")
	err = catsTemplate.Execute(w, &catList{res})
	if err != nil {
		server.LogWithFields(r).WithFields(logrus.Fields{
			"error": err,
		}).Error("unable to execute cats template")
		http.Error(w, "unable to perform cat search", http.StatusServiceUnavailable)
	}
}
Example #3
0
// Put is a JSONEndpoint for adding a new saved item to a user's list.
func (s *SavedItemsService) Put(r *http.Request) (int, interface{}, error) {
	// gather the inputs from the request
	id := context.Get(r, userIDKey).(uint64)
	url := r.URL.Query().Get("url")

	// do work and respond
	err := s.repo.Put(id, url)
	if err != nil {
		return http.StatusInternalServerError, nil, err
	}

	server.LogWithFields(r).Info("successfully saved item")
	return http.StatusCreated, jsonResponse{"successfully saved item"}, nil
}
Example #4
0
// CreateStream is a JSON endpoint for creating a new topic in Kafka.
func (s *StreamService) CreateStream(r *http.Request) (int, interface{}, error) {
	id := time.Now().Unix()
	topic := topicName(id)
	err := createTopic(topic)
	if err != nil {
		return http.StatusInternalServerError, nil, jsonErr{err}
	}

	server.LogWithFields(r).WithField("topic", topic).Info("created new topic")

	return http.StatusOK, struct {
		Status   string `json:"status"`
		StreamID int64  `json:"stream_id"`
	}{"success!", id}, nil
}
Example #5
0
// JSONMiddleware provides a hook to add service-wide middleware for how JSONEndpoints
// should behave. In this example, we’re using the hook to check for a header to
// identify and authorize the user. This method helps satisfy the server.JSONService interface.
func (s *SavedItemsService) JSONMiddleware(j server.JSONEndpoint) server.JSONEndpoint {
	return func(r *http.Request) (code int, res interface{}, err error) {

		// wrap our endpoint with an auth check
		j = authCheck(j)

		// call the endpoint
		code, res, err = j(r)

		// if the endpoint returns an unexpected error, return a generic message
		// and log it.
		if err != nil && code != http.StatusUnauthorized {
			// LogWithFields will add all the request context values
			// to the structured log entry along some other request info
			server.LogWithFields(r).WithField("error", err).Error("unexpected service error")
			return http.StatusServiceUnavailable, nil, ServiceUnavailableErr
		}

		return code, res, err
	}
}
Example #6
0
// Stream will init a new pubsub.KafkaPublisher and pubsub.KafkaSubscriber
// then upgrade the current request to a websocket connection. Any messages
// consumed from Kafka will be published to the web socket and vice versa.
func (s *StreamService) Stream(w http.ResponseWriter, r *http.Request) {
	cfg := *s.cfg
	cfg.Topic = topicName(web.GetInt64Var(r, "stream_id"))
	server.LogWithFields(r).WithField("topic", cfg.Topic).Info("new stream req")

	sub, err := pubsub.NewKafkaSubscriber(&cfg, zeroOffset, discardOffset)
	if err != nil {
		server.LogWithFields(r).WithField("error", err).Error("unable to create sub")
		http.Error(w, "unable to create subscriber: "+err.Error(), http.StatusBadRequest)
		return
	}
	defer func() {
		if err := sub.Stop(); err != nil {
			server.LogWithFields(r).WithField("error", err).Error("unable to stop sub")
		}
	}()

	var pub *pubsub.KafkaPublisher
	pub, err = pubsub.NewKafkaPublisher(&cfg)
	if err != nil {
		server.LogWithFields(r).WithField("error", err).Error("unable to create pub")
		http.Error(w, "unable to create publisher: "+err.Error(), http.StatusBadRequest)
		return
	}
	defer func() {
		if err := pub.Stop(); err != nil {
			server.LogWithFields(r).WithField("error", err).Error("unable to stop pub")
		}
	}()
	var ws *websocket.Conn
	ws, err = upgrader.Upgrade(w, r, nil)
	if err != nil {
		server.LogWithFields(r).WithField("error", err).Error("unable to create websocket")
		http.Error(w, "unable to create websocket: "+err.Error(), http.StatusBadRequest)
		return
	}
	defer func() {
		if err := ws.Close(); err != nil {
			server.LogWithFields(r).WithField("error", err).Error("unable to close ws")
		}
	}()

	// start consumer, emit to ws
	noopTicker := time.NewTicker(time.Second * 5)
	subscriberDone := make(chan bool, 1)
	stopSubscriber := make(chan bool, 1)
	go func() {
		defer func() { subscriberDone <- true }()
		var (
			payload []byte
			msgs    = sub.Start()
		)
		for {
			select {
			case msg := <-msgs:
				payload = msg.Message()
				err = ws.SetWriteDeadline(time.Now().Add(time.Second * 30))
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to write deadline")
				}
				err = ws.WriteMessage(websocket.TextMessage, payload)
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to write ws message")
				}
				err = msg.Done()
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to mark gizmo message as done")
				}
			case <-noopTicker.C:
				err = ws.SetWriteDeadline(time.Now().Add(time.Second * 30))
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to write deadline")
				}
				if err := ws.WriteMessage(websocket.PingMessage, []byte("ping")); err != nil {
					server.LogWithFields(r).WithField("error", err).Error("error writing ws message")
					return
				}
			case <-stopSubscriber:
				return
			}
		}
	}()

	// start producer, emit to kafka
	producerDone := make(chan bool, 1)
	go func() {
		defer func() {
			producerDone <- true
			stopSubscriber <- true
			server.LogWithFields(r).WithField("topic", cfg.Topic).Info("closing stream req")
		}()
		var (
			messageType int
			payload     []byte
			err         error
			read        io.Reader
		)
		for {
			messageType, read, err = ws.NextReader()
			if err != nil {
				if err != io.EOF {
					server.LogWithFields(r).WithField("error", err).Error("error reading message")
				}
				return
			}

			switch messageType {
			case websocket.TextMessage:
				payload, err = ioutil.ReadAll(read)
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to read payload")
					return
				}
				err = pub.PublishRaw(cfg.Topic, payload)
				if err != nil {
					server.LogWithFields(r).WithField("error", err).Error("unable to publish payload")
					return
				}
			case websocket.PingMessage, websocket.PongMessage, websocket.BinaryMessage:
				server.LogWithFields(r).Info("discarding message type: ", messageType)
			case websocket.CloseMessage:
				server.LogWithFields(r).Info("closing websocket")
				return
			}
		}
	}()

	<-subscriberDone
	<-producerDone
	noopTicker.Stop()
	server.LogWithFields(r).WithField("topic", cfg.Topic).Info("leaving stream req")
}