Moved to google.golang.org/genproto/googleapis/api/annotations

Fixes #52
This commit is contained in:
Valerio Gheri
2017-03-31 18:01:58 +02:00
parent 024c5a4e4e
commit c40779224f
2037 changed files with 831329 additions and 1854 deletions

View File

@@ -0,0 +1,26 @@
package tracking
import (
"context"
"github.com/go-kit/kit/endpoint"
)
type trackCargoRequest struct {
ID string
}
type trackCargoResponse struct {
Cargo *Cargo `json:"cargo,omitempty"`
Err error `json:"error,omitempty"`
}
func (r trackCargoResponse) error() error { return r.Err }
func makeTrackCargoEndpoint(ts Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req := request.(trackCargoRequest)
c, err := ts.Track(req.ID)
return trackCargoResponse{Cargo: &c, Err: err}, nil
}
}

View File

@@ -0,0 +1,31 @@
package tracking
import (
"time"
"github.com/go-kit/kit/metrics"
)
type instrumentingService struct {
requestCount metrics.Counter
requestLatency metrics.Histogram
Service
}
// NewInstrumentingService returns an instance of an instrumenting Service.
func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service {
return &instrumentingService{
requestCount: counter,
requestLatency: latency,
Service: s,
}
}
func (s *instrumentingService) Track(id string) (Cargo, error) {
defer func(begin time.Time) {
s.requestCount.With("method", "track").Add(1)
s.requestLatency.With("method", "track").Observe(time.Since(begin).Seconds())
}(time.Now())
return s.Service.Track(id)
}

View File

@@ -0,0 +1,24 @@
package tracking
import (
"time"
"github.com/go-kit/kit/log"
)
type loggingService struct {
logger log.Logger
Service
}
// NewLoggingService returns a new instance of a logging Service.
func NewLoggingService(logger log.Logger, s Service) Service {
return &loggingService{logger, s}
}
func (s *loggingService) Track(id string) (c Cargo, err error) {
defer func(begin time.Time) {
s.logger.Log("method", "track", "tracking_id", id, "took", time.Since(begin), "err", err)
}(time.Now())
return s.Service.Track(id)
}

View File

@@ -0,0 +1,163 @@
// Package tracking provides the use-case of tracking a cargo. Used by views
// facing the end-user.
package tracking
import (
"errors"
"fmt"
"strings"
"time"
"github.com/go-kit/kit/examples/shipping/cargo"
)
// ErrInvalidArgument is returned when one or more arguments are invalid.
var ErrInvalidArgument = errors.New("invalid argument")
// Service is the interface that provides the basic Track method.
type Service interface {
// Track returns a cargo matching a tracking ID.
Track(id string) (Cargo, error)
}
type service struct {
cargos cargo.Repository
handlingEvents cargo.HandlingEventRepository
}
func (s *service) Track(id string) (Cargo, error) {
if id == "" {
return Cargo{}, ErrInvalidArgument
}
c, err := s.cargos.Find(cargo.TrackingID(id))
if err != nil {
return Cargo{}, err
}
return assemble(c, s.handlingEvents), nil
}
// NewService returns a new instance of the default Service.
func NewService(cargos cargo.Repository, events cargo.HandlingEventRepository) Service {
return &service{
cargos: cargos,
handlingEvents: events,
}
}
// Cargo is a read model for tracking views.
type Cargo struct {
TrackingID string `json:"tracking_id"`
StatusText string `json:"status_text"`
Origin string `json:"origin"`
Destination string `json:"destination"`
ETA time.Time `json:"eta"`
NextExpectedActivity string `json:"next_expected_activity"`
ArrivalDeadline time.Time `json:"arrival_deadline"`
Events []Event `json:"events"`
}
// Leg is a read model for booking views.
type Leg struct {
VoyageNumber string `json:"voyage_number"`
From string `json:"from"`
To string `json:"to"`
LoadTime time.Time `json:"load_time"`
UnloadTime time.Time `json:"unload_time"`
}
// Event is a read model for tracking views.
type Event struct {
Description string `json:"description"`
Expected bool `json:"expected"`
}
func assemble(c *cargo.Cargo, events cargo.HandlingEventRepository) Cargo {
return Cargo{
TrackingID: string(c.TrackingID),
Origin: string(c.Origin),
Destination: string(c.RouteSpecification.Destination),
ETA: c.Delivery.ETA,
NextExpectedActivity: nextExpectedActivity(c),
ArrivalDeadline: c.RouteSpecification.ArrivalDeadline,
StatusText: assembleStatusText(c),
Events: assembleEvents(c, events),
}
}
func assembleLegs(c cargo.Cargo) []Leg {
var legs []Leg
for _, l := range c.Itinerary.Legs {
legs = append(legs, Leg{
VoyageNumber: string(l.VoyageNumber),
From: string(l.LoadLocation),
To: string(l.UnloadLocation),
LoadTime: l.LoadTime,
UnloadTime: l.UnloadTime,
})
}
return legs
}
func nextExpectedActivity(c *cargo.Cargo) string {
a := c.Delivery.NextExpectedActivity
prefix := "Next expected activity is to"
switch a.Type {
case cargo.Load:
return fmt.Sprintf("%s %s cargo onto voyage %s in %s.", prefix, strings.ToLower(a.Type.String()), a.VoyageNumber, a.Location)
case cargo.Unload:
return fmt.Sprintf("%s %s cargo off of voyage %s in %s.", prefix, strings.ToLower(a.Type.String()), a.VoyageNumber, a.Location)
case cargo.NotHandled:
return "There are currently no expected activities for this cargo."
}
return fmt.Sprintf("%s %s cargo in %s.", prefix, strings.ToLower(a.Type.String()), a.Location)
}
func assembleStatusText(c *cargo.Cargo) string {
switch c.Delivery.TransportStatus {
case cargo.NotReceived:
return "Not received"
case cargo.InPort:
return fmt.Sprintf("In port %s", c.Delivery.LastKnownLocation)
case cargo.OnboardCarrier:
return fmt.Sprintf("Onboard voyage %s", c.Delivery.CurrentVoyage)
case cargo.Claimed:
return "Claimed"
default:
return "Unknown"
}
}
func assembleEvents(c *cargo.Cargo, handlingEvents cargo.HandlingEventRepository) []Event {
h := handlingEvents.QueryHandlingHistory(c.TrackingID)
var events []Event
for _, e := range h.HandlingEvents {
var description string
switch e.Activity.Type {
case cargo.NotHandled:
description = "Cargo has not yet been received."
case cargo.Receive:
description = fmt.Sprintf("Received in %s, at %s", e.Activity.Location, time.Now().Format(time.RFC3339))
case cargo.Load:
description = fmt.Sprintf("Loaded onto voyage %s in %s, at %s.", e.Activity.VoyageNumber, e.Activity.Location, time.Now().Format(time.RFC3339))
case cargo.Unload:
description = fmt.Sprintf("Unloaded off voyage %s in %s, at %s.", e.Activity.VoyageNumber, e.Activity.Location, time.Now().Format(time.RFC3339))
case cargo.Claim:
description = fmt.Sprintf("Claimed in %s, at %s.", e.Activity.Location, time.Now().Format(time.RFC3339))
case cargo.Customs:
description = fmt.Sprintf("Cleared customs in %s, at %s.", e.Activity.Location, time.Now().Format(time.RFC3339))
default:
description = "[Unknown status]"
}
events = append(events, Event{
Description: description,
Expected: c.Itinerary.IsExpected(e),
})
}
return events
}

View File

@@ -0,0 +1,74 @@
package tracking
import (
"context"
"encoding/json"
"errors"
"net/http"
"github.com/gorilla/mux"
kitlog "github.com/go-kit/kit/log"
kithttp "github.com/go-kit/kit/transport/http"
"github.com/go-kit/kit/examples/shipping/cargo"
)
// MakeHandler returns a handler for the tracking service.
func MakeHandler(ts Service, logger kitlog.Logger) http.Handler {
r := mux.NewRouter()
opts := []kithttp.ServerOption{
kithttp.ServerErrorLogger(logger),
kithttp.ServerErrorEncoder(encodeError),
}
trackCargoHandler := kithttp.NewServer(
makeTrackCargoEndpoint(ts),
decodeTrackCargoRequest,
encodeResponse,
opts...,
)
r.Handle("/tracking/v1/cargos/{id}", trackCargoHandler).Methods("GET")
return r
}
func decodeTrackCargoRequest(_ context.Context, r *http.Request) (interface{}, error) {
vars := mux.Vars(r)
id, ok := vars["id"]
if !ok {
return nil, errors.New("bad route")
}
return trackCargoRequest{ID: id}, nil
}
func encodeResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
if e, ok := response.(errorer); ok && e.error() != nil {
encodeError(ctx, e.error(), w)
return nil
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
return json.NewEncoder(w).Encode(response)
}
type errorer interface {
error() error
}
// encode errors from business-logic
func encodeError(_ context.Context, err error, w http.ResponseWriter) {
switch err {
case cargo.ErrUnknown:
w.WriteHeader(http.StatusNotFound)
case ErrInvalidArgument:
w.WriteHeader(http.StatusBadRequest)
default:
w.WriteHeader(http.StatusInternalServerError)
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(map[string]interface{}{
"error": err.Error(),
})
}