| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 | package routingimport (	"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"	shipping "github.com/longjoy/micro-go-course/section19/cargo/model")type proxyService struct {	context.Context	FetchRoutesEndpoint endpoint.Endpoint	shipping.RoutingService}func (s proxyService) FetchRoutesForSpecification(rs shipping.RouteSpecification) []shipping.Itinerary {	response, err := s.FetchRoutesEndpoint(s.Context, fetchRoutesRequest{		From: string(rs.Origin),		To:   string(rs.Destination),	})	if err != nil {		return []shipping.Itinerary{}	}	resp := response.(fetchRoutesResponse)	var itineraries []shipping.Itinerary	for _, r := range resp.Paths {		var legs []shipping.Leg		for _, e := range r.Edges {			legs = append(legs, shipping.Leg{				VoyageNumber:   shipping.VoyageNumber(e.Voyage),				LoadLocation:   shipping.UNLocode(e.Origin),				UnloadLocation: shipping.UNLocode(e.Destination),				LoadTime:       e.Departure,				UnloadTime:     e.Arrival,			})		}		itineraries = append(itineraries, shipping.Itinerary{Legs: legs})	}	return itineraries}// ServiceMiddleware defines a middleware for a routing service.type ServiceMiddleware func(shipping.RoutingService) shipping.RoutingService// NewProxyingMiddleware returns a new instance of a proxying middleware.func NewProxyingMiddleware(ctx context.Context, proxyURL string) ServiceMiddleware {	return func(next shipping.RoutingService) shipping.RoutingService {		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}
 |