package routing import ( "context" "encoding/json" "net/http" "net/url" "time" "github.com/go-kit/kit/circuitbreaker" "github.com/go-kit/kit/endpoint" kithttp "github.com/go-kit/kit/transport/http" "github.com/go-kit/kit/examples/shipping/cargo" "github.com/go-kit/kit/examples/shipping/location" "github.com/go-kit/kit/examples/shipping/voyage" ) type proxyService struct { context.Context FetchRoutesEndpoint endpoint.Endpoint Service } func (s proxyService) FetchRoutesForSpecification(rs cargo.RouteSpecification) []cargo.Itinerary { response, err := s.FetchRoutesEndpoint(s.Context, fetchRoutesRequest{ From: string(rs.Origin), To: string(rs.Destination), }) if err != nil { return []cargo.Itinerary{} } resp := response.(fetchRoutesResponse) var itineraries []cargo.Itinerary for _, r := range resp.Paths { var legs []cargo.Leg for _, e := range r.Edges { legs = append(legs, cargo.Leg{ VoyageNumber: voyage.Number(e.Voyage), LoadLocation: location.UNLocode(e.Origin), UnloadLocation: location.UNLocode(e.Destination), LoadTime: e.Departure, UnloadTime: e.Arrival, }) } itineraries = append(itineraries, cargo.Itinerary{Legs: legs}) } return itineraries } // ServiceMiddleware defines a middleware for a routing service. type ServiceMiddleware func(Service) Service // NewProxyingMiddleware returns a new instance of a proxying middleware. func NewProxyingMiddleware(ctx context.Context, proxyURL string) ServiceMiddleware { return func(next Service) Service { var e endpoint.Endpoint e = makeFetchRoutesEndpoint(ctx, proxyURL) e = circuitbreaker.Hystrix("fetch-routes")(e) return proxyService{ctx, e, next} } } type fetchRoutesRequest struct { From string To string } type fetchRoutesResponse struct { Paths []struct { Edges []struct { Origin string `json:"origin"` Destination string `json:"destination"` Voyage string `json:"voyage"` Departure time.Time `json:"departure"` Arrival time.Time `json:"arrival"` } `json:"edges"` } `json:"paths"` } func makeFetchRoutesEndpoint(ctx context.Context, instance string) endpoint.Endpoint { u, err := url.Parse(instance) if err != nil { panic(err) } if u.Path == "" { u.Path = "/paths" } return kithttp.NewClient( "GET", u, encodeFetchRoutesRequest, decodeFetchRoutesResponse, ).Endpoint() } func decodeFetchRoutesResponse(_ context.Context, resp *http.Response) (interface{}, error) { var response fetchRoutesResponse if err := json.NewDecoder(resp.Body).Decode(&response); err != nil { return nil, err } return response, nil } func encodeFetchRoutesRequest(_ context.Context, r *http.Request, request interface{}) error { req := request.(fetchRoutesRequest) vals := r.URL.Query() vals.Add("from", req.From) vals.Add("to", req.To) r.URL.RawQuery = vals.Encode() return nil }