Codebase list golang-github-go-kit-kit / 0c8ee06
shipping: Update with upstream changes Marcus Olsson 7 years ago
26 changed file(s) with 375 addition(s) and 265 deletion(s). Raw diff Collapse all Expand all
1515
1616 There are also a few pure domain packages that contain some intricate business-logic. They provide domain objects and services that are used by each application service to provide interesting use-cases for the user.
1717
18 `repository` contains in-memory implementations for the repositories found in the domain packages.
18 `inmem` contains in-memory implementations for the repositories found in the domain packages.
1919
2020 The `routing` package provides a _domain service_ that is used to query an external application for possible routes.
2121
55 "golang.org/x/net/context"
66
77 "github.com/go-kit/kit/endpoint"
8
89 "github.com/go-kit/kit/examples/shipping/cargo"
910 "github.com/go-kit/kit/examples/shipping/location"
1011 )
1515 }
1616
1717 // NewInstrumentingService returns an instance of an instrumenting Service.
18 func NewInstrumentingService(requestCount metrics.Counter, requestLatency metrics.Histogram, s Service) Service {
18 func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service {
1919 return &instrumentingService{
20 requestCount: requestCount,
21 requestLatency: requestLatency,
20 requestCount: counter,
21 requestLatency: latency,
2222 Service: s,
2323 }
2424 }
2525
26 func (s *instrumentingService) BookNewCargo(origin, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error) {
26 func (s *instrumentingService) BookNewCargo(origin, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error) {
2727 defer func(begin time.Time) {
2828 s.requestCount.With("method", "book").Add(1)
2929 s.requestLatency.With("method", "book").Observe(time.Since(begin).Seconds())
3030 }(time.Now())
3131
32 return s.Service.BookNewCargo(origin, destination, arrivalDeadline)
32 return s.Service.BookNewCargo(origin, destination, deadline)
3333 }
3434
3535 func (s *instrumentingService) LoadCargo(id cargo.TrackingID) (c Cargo, err error) {
22 import (
33 "time"
44
5 "github.com/go-kit/kit/log"
6
57 "github.com/go-kit/kit/examples/shipping/cargo"
68 "github.com/go-kit/kit/examples/shipping/location"
7 "github.com/go-kit/kit/log"
89 )
910
1011 type loggingService struct {
1718 return &loggingService{logger, s}
1819 }
1920
20 func (s *loggingService) BookNewCargo(origin location.UNLocode, destination location.UNLocode, arrivalDeadline time.Time) (id cargo.TrackingID, err error) {
21 func (s *loggingService) BookNewCargo(origin location.UNLocode, destination location.UNLocode, deadline time.Time) (id cargo.TrackingID, err error) {
2122 defer func(begin time.Time) {
2223 s.logger.Log(
2324 "method", "book",
2425 "origin", origin,
2526 "destination", destination,
26 "arrival_deadline", arrivalDeadline,
27 "arrival_deadline", deadline,
2728 "took", time.Since(begin),
2829 "err", err,
2930 )
3031 }(time.Now())
31 return s.Service.BookNewCargo(origin, destination, arrivalDeadline)
32 return s.Service.BookNewCargo(origin, destination, deadline)
3233 }
3334
3435 func (s *loggingService) LoadCargo(id cargo.TrackingID) (c Cargo, err error) {
1717 type Service interface {
1818 // BookNewCargo registers a new cargo in the tracking system, not yet
1919 // routed.
20 BookNewCargo(origin location.UNLocode, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error)
20 BookNewCargo(origin location.UNLocode, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error)
2121
2222 // LoadCargo returns a read model of a cargo.
23 LoadCargo(trackingID cargo.TrackingID) (Cargo, error)
23 LoadCargo(id cargo.TrackingID) (Cargo, error)
2424
2525 // RequestPossibleRoutesForCargo requests a list of itineraries describing
2626 // possible routes for this cargo.
27 RequestPossibleRoutesForCargo(trackingID cargo.TrackingID) []cargo.Itinerary
27 RequestPossibleRoutesForCargo(id cargo.TrackingID) []cargo.Itinerary
2828
2929 // AssignCargoToRoute assigns a cargo to the route specified by the
3030 // itinerary.
31 AssignCargoToRoute(trackingID cargo.TrackingID, itinerary cargo.Itinerary) error
31 AssignCargoToRoute(id cargo.TrackingID, itinerary cargo.Itinerary) error
3232
3333 // ChangeDestination changes the destination of a cargo.
34 ChangeDestination(trackingID cargo.TrackingID, unLocode location.UNLocode) error
34 ChangeDestination(id cargo.TrackingID, destination location.UNLocode) error
3535
3636 // Cargos returns a list of all cargos that have been booked.
3737 Cargos() []Cargo
4141 }
4242
4343 type service struct {
44 cargoRepository cargo.Repository
45 locationRepository location.Repository
46 routingService routing.Service
47 handlingEventRepository cargo.HandlingEventRepository
44 cargos cargo.Repository
45 locations location.Repository
46 handlingEvents cargo.HandlingEventRepository
47 routingService routing.Service
4848 }
4949
5050 func (s *service) AssignCargoToRoute(id cargo.TrackingID, itinerary cargo.Itinerary) error {
5252 return ErrInvalidArgument
5353 }
5454
55 c, err := s.cargoRepository.Find(id)
55 c, err := s.cargos.Find(id)
5656 if err != nil {
5757 return err
5858 }
5959
6060 c.AssignToRoute(itinerary)
6161
62 if err := s.cargoRepository.Store(c); err != nil {
63 return err
64 }
65
66 return nil
62 return s.cargos.Store(c)
6763 }
6864
69 func (s *service) BookNewCargo(origin, destination location.UNLocode, arrivalDeadline time.Time) (cargo.TrackingID, error) {
70 if origin == "" || destination == "" || arrivalDeadline.IsZero() {
65 func (s *service) BookNewCargo(origin, destination location.UNLocode, deadline time.Time) (cargo.TrackingID, error) {
66 if origin == "" || destination == "" || deadline.IsZero() {
7167 return "", ErrInvalidArgument
7268 }
7369
7571 rs := cargo.RouteSpecification{
7672 Origin: origin,
7773 Destination: destination,
78 ArrivalDeadline: arrivalDeadline,
74 ArrivalDeadline: deadline,
7975 }
8076
8177 c := cargo.New(id, rs)
8278
83 if err := s.cargoRepository.Store(c); err != nil {
79 if err := s.cargos.Store(c); err != nil {
8480 return "", err
8581 }
8682
8783 return c.TrackingID, nil
8884 }
8985
90 func (s *service) LoadCargo(trackingID cargo.TrackingID) (Cargo, error) {
91 if trackingID == "" {
86 func (s *service) LoadCargo(id cargo.TrackingID) (Cargo, error) {
87 if id == "" {
9288 return Cargo{}, ErrInvalidArgument
9389 }
9490
95 c, err := s.cargoRepository.Find(trackingID)
91 c, err := s.cargos.Find(id)
9692 if err != nil {
9793 return Cargo{}, err
9894 }
9995
100 return assemble(c, s.handlingEventRepository), nil
96 return assemble(c, s.handlingEvents), nil
10197 }
10298
10399 func (s *service) ChangeDestination(id cargo.TrackingID, destination location.UNLocode) error {
105101 return ErrInvalidArgument
106102 }
107103
108 c, err := s.cargoRepository.Find(id)
104 c, err := s.cargos.Find(id)
109105 if err != nil {
110106 return err
111107 }
112108
113 l, err := s.locationRepository.Find(destination)
109 l, err := s.locations.Find(destination)
114110 if err != nil {
115111 return err
116112 }
121117 ArrivalDeadline: c.RouteSpecification.ArrivalDeadline,
122118 })
123119
124 if err := s.cargoRepository.Store(c); err != nil {
120 if err := s.cargos.Store(c); err != nil {
125121 return err
126122 }
127123
133129 return nil
134130 }
135131
136 c, err := s.cargoRepository.Find(id)
132 c, err := s.cargos.Find(id)
137133 if err != nil {
138134 return []cargo.Itinerary{}
139135 }
143139
144140 func (s *service) Cargos() []Cargo {
145141 var result []Cargo
146 for _, c := range s.cargoRepository.FindAll() {
147 result = append(result, assemble(c, s.handlingEventRepository))
142 for _, c := range s.cargos.FindAll() {
143 result = append(result, assemble(c, s.handlingEvents))
148144 }
149145 return result
150146 }
151147
152148 func (s *service) Locations() []Location {
153149 var result []Location
154 for _, v := range s.locationRepository.FindAll() {
150 for _, v := range s.locations.FindAll() {
155151 result = append(result, Location{
156152 UNLocode: string(v.UNLocode),
157153 Name: v.Name,
161157 }
162158
163159 // NewService creates a booking service with necessary dependencies.
164 func NewService(cr cargo.Repository, lr location.Repository, her cargo.HandlingEventRepository, rs routing.Service) Service {
160 func NewService(cargos cargo.Repository, locations location.Repository, events cargo.HandlingEventRepository, rs routing.Service) Service {
165161 return &service{
166 cargoRepository: cr,
167 locationRepository: lr,
168 handlingEventRepository: her,
169 routingService: rs,
162 cargos: cargos,
163 locations: locations,
164 handlingEvents: events,
165 routingService: rs,
170166 }
171167 }
172168
187183 TrackingID string `json:"tracking_id"`
188184 }
189185
190 func assemble(c *cargo.Cargo, her cargo.HandlingEventRepository) Cargo {
186 func assemble(c *cargo.Cargo, events cargo.HandlingEventRepository) Cargo {
191187 return Cargo{
192188 TrackingID: string(c.TrackingID),
193189 Origin: string(c.Origin),
88 "github.com/gorilla/mux"
99 "golang.org/x/net/context"
1010
11 kitlog "github.com/go-kit/kit/log"
12 kithttp "github.com/go-kit/kit/transport/http"
13
1114 "github.com/go-kit/kit/examples/shipping/cargo"
1215 "github.com/go-kit/kit/examples/shipping/location"
13 kitlog "github.com/go-kit/kit/log"
14 kithttp "github.com/go-kit/kit/transport/http"
1516 )
1617
1718 // MakeHandler returns a handler for the booking service.
8081 r.Handle("/booking/v1/cargos/{id}/assign_to_route", assignToRouteHandler).Methods("POST")
8182 r.Handle("/booking/v1/cargos/{id}/change_destination", changeDestinationHandler).Methods("POST")
8283 r.Handle("/booking/v1/locations", listLocationsHandler).Methods("GET")
83 r.Handle("/booking/v1/docs", http.StripPrefix("/booking/v1/docs", http.FileServer(http.Dir("booking/docs"))))
8484
8585 return r
8686 }
5656 // Repository provides access a cargo store.
5757 type Repository interface {
5858 Store(cargo *Cargo) error
59 Find(trackingID TrackingID) (*Cargo, error)
59 Find(id TrackingID) (*Cargo, error)
6060 FindAll() []*Cargo
6161 }
6262
9191 }
9292
9393 // CreateHandlingEvent creates a validated handling event.
94 func (f *HandlingEventFactory) CreateHandlingEvent(registrationTime time.Time, completionTime time.Time, trackingID TrackingID,
94 func (f *HandlingEventFactory) CreateHandlingEvent(registered time.Time, completed time.Time, id TrackingID,
9595 voyageNumber voyage.Number, unLocode location.UNLocode, eventType HandlingEventType) (HandlingEvent, error) {
9696
97 if _, err := f.CargoRepository.Find(trackingID); err != nil {
97 if _, err := f.CargoRepository.Find(id); err != nil {
9898 return HandlingEvent{}, err
9999 }
100100
110110 }
111111
112112 return HandlingEvent{
113 TrackingID: trackingID,
113 TrackingID: id,
114114 Activity: HandlingActivity{
115115 Type: eventType,
116116 Location: unLocode,
55 "golang.org/x/net/context"
66
77 "github.com/go-kit/kit/endpoint"
8
89 "github.com/go-kit/kit/examples/shipping/cargo"
910 "github.com/go-kit/kit/examples/shipping/location"
1011 "github.com/go-kit/kit/examples/shipping/voyage"
1616 }
1717
1818 // NewInstrumentingService returns an instance of an instrumenting Service.
19 func NewInstrumentingService(requestCount metrics.Counter, requestLatency metrics.Histogram, s Service) Service {
19 func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service {
2020 return &instrumentingService{
21 requestCount: requestCount,
22 requestLatency: requestLatency,
21 requestCount: counter,
22 requestLatency: latency,
2323 Service: s,
2424 }
2525 }
2626
27 func (s *instrumentingService) RegisterHandlingEvent(completionTime time.Time, trackingID cargo.TrackingID, voyage voyage.Number,
27 func (s *instrumentingService) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number,
2828 loc location.UNLocode, eventType cargo.HandlingEventType) error {
2929
3030 defer func(begin time.Time) {
3232 s.requestLatency.With("method", "register_incident").Observe(time.Since(begin).Seconds())
3333 }(time.Now())
3434
35 return s.Service.RegisterHandlingEvent(completionTime, trackingID, voyage, loc, eventType)
35 return s.Service.RegisterHandlingEvent(completed, id, voyageNumber, loc, eventType)
3636 }
22 import (
33 "time"
44
5 "github.com/go-kit/kit/log"
6
57 "github.com/go-kit/kit/examples/shipping/cargo"
68 "github.com/go-kit/kit/examples/shipping/location"
79 "github.com/go-kit/kit/examples/shipping/voyage"
8 "github.com/go-kit/kit/log"
910 )
1011
1112 type loggingService struct {
1819 return &loggingService{logger, s}
1920 }
2021
21 func (s *loggingService) RegisterHandlingEvent(completionTime time.Time, trackingID cargo.TrackingID, voyageNumber voyage.Number,
22 func (s *loggingService) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number,
2223 unLocode location.UNLocode, eventType cargo.HandlingEventType) (err error) {
2324 defer func(begin time.Time) {
2425 s.logger.Log(
2526 "method", "register_incident",
26 "tracking_id", trackingID,
27 "tracking_id", id,
2728 "location", unLocode,
2829 "voyage", voyageNumber,
2930 "event_type", eventType,
30 "completion_time", completionTime,
31 "completion_time", completed,
3132 "took", time.Since(begin),
3233 "err", err,
3334 )
3435 }(time.Now())
35 return s.Service.RegisterHandlingEvent(completionTime, trackingID, voyageNumber, unLocode, eventType)
36 return s.Service.RegisterHandlingEvent(completed, id, voyageNumber, unLocode, eventType)
3637 }
2323 type Service interface {
2424 // RegisterHandlingEvent registers a handling event in the system, and
2525 // notifies interested parties that a cargo has been handled.
26 RegisterHandlingEvent(completionTime time.Time, trackingID cargo.TrackingID, voyageNumber voyage.Number,
26 RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number,
2727 unLocode location.UNLocode, eventType cargo.HandlingEventType) error
2828 }
2929
3333 handlingEventHandler EventHandler
3434 }
3535
36 func (s *service) RegisterHandlingEvent(completionTime time.Time, trackingID cargo.TrackingID, voyage voyage.Number,
36 func (s *service) RegisterHandlingEvent(completed time.Time, id cargo.TrackingID, voyageNumber voyage.Number,
3737 loc location.UNLocode, eventType cargo.HandlingEventType) error {
38 if completionTime.IsZero() || trackingID == "" || loc == "" || eventType == cargo.NotHandled {
38 if completed.IsZero() || id == "" || loc == "" || eventType == cargo.NotHandled {
3939 return ErrInvalidArgument
4040 }
4141
42 e, err := s.handlingEventFactory.CreateHandlingEvent(time.Now(), completionTime, trackingID, voyage, loc, eventType)
42 e, err := s.handlingEventFactory.CreateHandlingEvent(time.Now(), completed, id, voyageNumber, loc, eventType)
4343 if err != nil {
4444 return err
4545 }
77 "github.com/gorilla/mux"
88 "golang.org/x/net/context"
99
10 kitlog "github.com/go-kit/kit/log"
11 kithttp "github.com/go-kit/kit/transport/http"
12
1013 "github.com/go-kit/kit/examples/shipping/cargo"
1114 "github.com/go-kit/kit/examples/shipping/location"
1215 "github.com/go-kit/kit/examples/shipping/voyage"
13 kitlog "github.com/go-kit/kit/log"
14 kithttp "github.com/go-kit/kit/transport/http"
1516 )
1617
1718 // MakeHandler returns a handler for the handling service.
0 // Package inmem provides in-memory implementations of all the domain repositories.
1 package inmem
2
3 import (
4 "sync"
5
6 "github.com/go-kit/kit/examples/shipping/cargo"
7 "github.com/go-kit/kit/examples/shipping/location"
8 "github.com/go-kit/kit/examples/shipping/voyage"
9 )
10
11 type cargoRepository struct {
12 mtx sync.RWMutex
13 cargos map[cargo.TrackingID]*cargo.Cargo
14 }
15
16 func (r *cargoRepository) Store(c *cargo.Cargo) error {
17 r.mtx.Lock()
18 defer r.mtx.Unlock()
19 r.cargos[c.TrackingID] = c
20 return nil
21 }
22
23 func (r *cargoRepository) Find(id cargo.TrackingID) (*cargo.Cargo, error) {
24 r.mtx.RLock()
25 defer r.mtx.RUnlock()
26 if val, ok := r.cargos[id]; ok {
27 return val, nil
28 }
29 return nil, cargo.ErrUnknown
30 }
31
32 func (r *cargoRepository) FindAll() []*cargo.Cargo {
33 r.mtx.RLock()
34 defer r.mtx.RUnlock()
35 c := make([]*cargo.Cargo, 0, len(r.cargos))
36 for _, val := range r.cargos {
37 c = append(c, val)
38 }
39 return c
40 }
41
42 // NewCargoRepository returns a new instance of a in-memory cargo repository.
43 func NewCargoRepository() cargo.Repository {
44 return &cargoRepository{
45 cargos: make(map[cargo.TrackingID]*cargo.Cargo),
46 }
47 }
48
49 type locationRepository struct {
50 locations map[location.UNLocode]*location.Location
51 }
52
53 func (r *locationRepository) Find(locode location.UNLocode) (*location.Location, error) {
54 if l, ok := r.locations[locode]; ok {
55 return l, nil
56 }
57 return nil, location.ErrUnknown
58 }
59
60 func (r *locationRepository) FindAll() []*location.Location {
61 l := make([]*location.Location, 0, len(r.locations))
62 for _, val := range r.locations {
63 l = append(l, val)
64 }
65 return l
66 }
67
68 // NewLocationRepository returns a new instance of a in-memory location repository.
69 func NewLocationRepository() location.Repository {
70 r := &locationRepository{
71 locations: make(map[location.UNLocode]*location.Location),
72 }
73
74 r.locations[location.SESTO] = location.Stockholm
75 r.locations[location.AUMEL] = location.Melbourne
76 r.locations[location.CNHKG] = location.Hongkong
77 r.locations[location.JNTKO] = location.Tokyo
78 r.locations[location.NLRTM] = location.Rotterdam
79 r.locations[location.DEHAM] = location.Hamburg
80
81 return r
82 }
83
84 type voyageRepository struct {
85 voyages map[voyage.Number]*voyage.Voyage
86 }
87
88 func (r *voyageRepository) Find(voyageNumber voyage.Number) (*voyage.Voyage, error) {
89 if v, ok := r.voyages[voyageNumber]; ok {
90 return v, nil
91 }
92
93 return nil, voyage.ErrUnknown
94 }
95
96 // NewVoyageRepository returns a new instance of a in-memory voyage repository.
97 func NewVoyageRepository() voyage.Repository {
98 r := &voyageRepository{
99 voyages: make(map[voyage.Number]*voyage.Voyage),
100 }
101
102 r.voyages[voyage.V100.Number] = voyage.V100
103 r.voyages[voyage.V300.Number] = voyage.V300
104 r.voyages[voyage.V400.Number] = voyage.V400
105
106 r.voyages[voyage.V0100S.Number] = voyage.V0100S
107 r.voyages[voyage.V0200T.Number] = voyage.V0200T
108 r.voyages[voyage.V0300A.Number] = voyage.V0300A
109 r.voyages[voyage.V0301S.Number] = voyage.V0301S
110 r.voyages[voyage.V0400S.Number] = voyage.V0400S
111
112 return r
113 }
114
115 type handlingEventRepository struct {
116 mtx sync.RWMutex
117 events map[cargo.TrackingID][]cargo.HandlingEvent
118 }
119
120 func (r *handlingEventRepository) Store(e cargo.HandlingEvent) {
121 r.mtx.Lock()
122 defer r.mtx.Unlock()
123 // Make array if it's the first event with this tracking ID.
124 if _, ok := r.events[e.TrackingID]; !ok {
125 r.events[e.TrackingID] = make([]cargo.HandlingEvent, 0)
126 }
127 r.events[e.TrackingID] = append(r.events[e.TrackingID], e)
128 }
129
130 func (r *handlingEventRepository) QueryHandlingHistory(id cargo.TrackingID) cargo.HandlingHistory {
131 r.mtx.RLock()
132 defer r.mtx.RUnlock()
133 return cargo.HandlingHistory{HandlingEvents: r.events[id]}
134 }
135
136 // NewHandlingEventRepository returns a new instance of a in-memory handling event repository.
137 func NewHandlingEventRepository() cargo.HandlingEventRepository {
138 return &handlingEventRepository{
139 events: make(map[cargo.TrackingID][]cargo.HandlingEvent),
140 }
141 }
1313 // InspectCargo inspects cargo and send relevant notifications to
1414 // interested parties, for example if a cargo has been misdirected, or
1515 // unloaded at the final destination.
16 InspectCargo(trackingID cargo.TrackingID)
16 InspectCargo(id cargo.TrackingID)
1717 }
1818
1919 type service struct {
20 cargoRepository cargo.Repository
21 handlingEventRepository cargo.HandlingEventRepository
22 cargoEventHandler EventHandler
20 cargos cargo.Repository
21 events cargo.HandlingEventRepository
22 handler EventHandler
2323 }
2424
2525 // TODO: Should be transactional
26 func (s *service) InspectCargo(trackingID cargo.TrackingID) {
27 c, err := s.cargoRepository.Find(trackingID)
26 func (s *service) InspectCargo(id cargo.TrackingID) {
27 c, err := s.cargos.Find(id)
2828 if err != nil {
2929 return
3030 }
3131
32 h := s.handlingEventRepository.QueryHandlingHistory(trackingID)
32 h := s.events.QueryHandlingHistory(id)
3333
3434 c.DeriveDeliveryProgress(h)
3535
3636 if c.Delivery.IsMisdirected {
37 s.cargoEventHandler.CargoWasMisdirected(c)
37 s.handler.CargoWasMisdirected(c)
3838 }
3939
4040 if c.Delivery.IsUnloadedAtDestination {
41 s.cargoEventHandler.CargoHasArrived(c)
41 s.handler.CargoHasArrived(c)
4242 }
4343
44 s.cargoRepository.Store(c)
44 s.cargos.Store(c)
4545 }
4646
4747 // NewService creates a inspection service with necessary dependencies.
48 func NewService(cargoRepository cargo.Repository, handlingEventRepository cargo.HandlingEventRepository, eventHandler EventHandler) Service {
49 return &service{cargoRepository, handlingEventRepository, eventHandler}
48 func NewService(cargos cargo.Repository, events cargo.HandlingEventRepository, handler EventHandler) Service {
49 return &service{cargos, events, handler}
5050 }
2121
2222 // Repository provides access a location store.
2323 type Repository interface {
24 Find(locode UNLocode) (Location, error)
25 FindAll() []Location
24 Find(locode UNLocode) (*Location, error)
25 FindAll() []*Location
2626 }
1414
1515 // Sample locations.
1616 var (
17 Stockholm = Location{SESTO, "Stockholm"}
18 Melbourne = Location{AUMEL, "Melbourne"}
19 Hongkong = Location{CNHKG, "Hongkong"}
20 NewYork = Location{USNYC, "New York"}
21 Chicago = Location{USCHI, "Chicago"}
22 Tokyo = Location{JNTKO, "Tokyo"}
23 Hamburg = Location{DEHAM, "Hamburg"}
24 Rotterdam = Location{NLRTM, "Rotterdam"}
25 Helsinki = Location{FIHEL, "Helsinki"}
17 Stockholm = &Location{SESTO, "Stockholm"}
18 Melbourne = &Location{AUMEL, "Melbourne"}
19 Hongkong = &Location{CNHKG, "Hongkong"}
20 NewYork = &Location{USNYC, "New York"}
21 Chicago = &Location{USCHI, "Chicago"}
22 Tokyo = &Location{JNTKO, "Tokyo"}
23 Hamburg = &Location{DEHAM, "Hamburg"}
24 Rotterdam = &Location{NLRTM, "Rotterdam"}
25 Helsinki = &Location{FIHEL, "Helsinki"}
2626 )
1818 "github.com/go-kit/kit/examples/shipping/booking"
1919 "github.com/go-kit/kit/examples/shipping/cargo"
2020 "github.com/go-kit/kit/examples/shipping/handling"
21 "github.com/go-kit/kit/examples/shipping/inmem"
2122 "github.com/go-kit/kit/examples/shipping/inspection"
2223 "github.com/go-kit/kit/examples/shipping/location"
23 "github.com/go-kit/kit/examples/shipping/repository"
2424 "github.com/go-kit/kit/examples/shipping/routing"
2525 "github.com/go-kit/kit/examples/shipping/tracking"
2626 )
4949 logger = log.NewContext(logger).With("ts", log.DefaultTimestampUTC)
5050
5151 var (
52 cargos = repository.NewCargo()
53 locations = repository.NewLocation()
54 voyages = repository.NewVoyage()
55 handlingEvents = repository.NewHandlingEvent()
52 cargos = inmem.NewCargoRepository()
53 locations = inmem.NewLocationRepository()
54 voyages = inmem.NewVoyageRepository()
55 handlingEvents = inmem.NewHandlingEventRepository()
5656 )
5757
5858 // Configure some questionable dependencies.
7373 fieldKeys := []string{"method"}
7474
7575 var rs routing.Service
76 rs = routing.NewProxyingMiddleware(*routingServiceURL, ctx)(rs)
76 rs = routing.NewProxyingMiddleware(ctx, *routingServiceURL)(rs)
7777
7878 var bs booking.Service
7979 bs = booking.NewService(cargos, locations, handlingEvents, rs)
185185 Destination: location.SESTO,
186186 ArrivalDeadline: time.Now().AddDate(0, 0, 7),
187187 })
188 _ = r.Store(test1)
188 if err := r.Store(test1); err != nil {
189 panic(err)
190 }
189191
190192 test2 := cargo.New("ABC123", cargo.RouteSpecification{
191193 Origin: location.SESTO,
192194 Destination: location.CNHKG,
193195 ArrivalDeadline: time.Now().AddDate(0, 0, 14),
194196 })
195 _ = r.Store(test2)
197 if err := r.Store(test2); err != nil {
198 panic(err)
199 }
196200 }
197201
198202 type serializedLogger struct {
0 package mock
1
2 import (
3 "github.com/go-kit/kit/examples/shipping/cargo"
4 "github.com/go-kit/kit/examples/shipping/location"
5 "github.com/go-kit/kit/examples/shipping/voyage"
6 )
7
8 // CargoRepository is a mock cargo repository.
9 type CargoRepository struct {
10 StoreFn func(c *cargo.Cargo) error
11 StoreInvoked bool
12
13 FindFn func(id cargo.TrackingID) (*cargo.Cargo, error)
14 FindInvoked bool
15
16 FindAllFn func() []*cargo.Cargo
17 FindAllInvoked bool
18 }
19
20 // Store calls the StoreFn.
21 func (r *CargoRepository) Store(c *cargo.Cargo) error {
22 r.StoreInvoked = true
23 return r.StoreFn(c)
24 }
25
26 // Find calls the FindFn.
27 func (r *CargoRepository) Find(id cargo.TrackingID) (*cargo.Cargo, error) {
28 r.FindInvoked = true
29 return r.FindFn(id)
30 }
31
32 // FindAll calls the FindAllFn.
33 func (r *CargoRepository) FindAll() []*cargo.Cargo {
34 r.FindAllInvoked = true
35 return r.FindAllFn()
36 }
37
38 // LocationRepository is a mock location repository.
39 type LocationRepository struct {
40 FindFn func(location.UNLocode) (*location.Location, error)
41 FindInvoked bool
42
43 FindAllFn func() []*location.Location
44 FindAllInvoked bool
45 }
46
47 // Find calls the FindFn.
48 func (r *LocationRepository) Find(locode location.UNLocode) (*location.Location, error) {
49 r.FindInvoked = true
50 return r.FindFn(locode)
51 }
52
53 // FindAll calls the FindAllFn.
54 func (r *LocationRepository) FindAll() []*location.Location {
55 r.FindAllInvoked = true
56 return r.FindAllFn()
57 }
58
59 // VoyageRepository is a mock voyage repository.
60 type VoyageRepository struct {
61 FindFn func(voyage.Number) (*voyage.Voyage, error)
62 FindInvoked bool
63 }
64
65 // Find calls the FindFn.
66 func (r *VoyageRepository) Find(number voyage.Number) (*voyage.Voyage, error) {
67 r.FindInvoked = true
68 return r.FindFn(number)
69 }
70
71 // HandlingEventRepository is a mock handling events repository.
72 type HandlingEventRepository struct {
73 StoreFn func(cargo.HandlingEvent)
74 StoreInvoked bool
75
76 QueryHandlingHistoryFn func(cargo.TrackingID) cargo.HandlingHistory
77 QueryHandlingHistoryInvoked bool
78 }
79
80 // Store calls the StoreFn.
81 func (r *HandlingEventRepository) Store(e cargo.HandlingEvent) {
82 r.StoreInvoked = true
83 r.StoreFn(e)
84 }
85
86 // QueryHandlingHistory calls the QueryHandlingHistoryFn.
87 func (r *HandlingEventRepository) QueryHandlingHistory(id cargo.TrackingID) cargo.HandlingHistory {
88 r.QueryHandlingHistoryInvoked = true
89 return r.QueryHandlingHistoryFn(id)
90 }
91
92 // RoutingService provides a mock routing service.
93 type RoutingService struct {
94 FetchRoutesFn func(cargo.RouteSpecification) []cargo.Itinerary
95 FetchRoutesInvoked bool
96 }
97
98 // FetchRoutesForSpecification calls the FetchRoutesFn.
99 func (s *RoutingService) FetchRoutesForSpecification(rs cargo.RouteSpecification) []cargo.Itinerary {
100 s.FetchRoutesInvoked = true
101 return s.FetchRoutesFn(rs)
102 }
+0
-142
examples/shipping/repository/repositories.go less more
0 // Package repository provides implementations of all the domain repositories.
1 package repository
2
3 import (
4 "sync"
5
6 "github.com/go-kit/kit/examples/shipping/cargo"
7 "github.com/go-kit/kit/examples/shipping/location"
8 "github.com/go-kit/kit/examples/shipping/voyage"
9 )
10
11 type cargoRepository struct {
12 mtx sync.RWMutex
13 cargos map[cargo.TrackingID]*cargo.Cargo
14 }
15
16 func (r *cargoRepository) Store(c *cargo.Cargo) error {
17 r.mtx.Lock()
18 defer r.mtx.Unlock()
19 r.cargos[c.TrackingID] = c
20 return nil
21 }
22
23 func (r *cargoRepository) Find(trackingID cargo.TrackingID) (*cargo.Cargo, error) {
24 r.mtx.RLock()
25 defer r.mtx.RUnlock()
26 if val, ok := r.cargos[trackingID]; ok {
27 return val, nil
28 }
29 return nil, cargo.ErrUnknown
30 }
31
32 func (r *cargoRepository) FindAll() []*cargo.Cargo {
33 r.mtx.RLock()
34 defer r.mtx.RUnlock()
35 c := make([]*cargo.Cargo, 0, len(r.cargos))
36 for _, val := range r.cargos {
37 c = append(c, val)
38 }
39 return c
40 }
41
42 // NewCargo returns a new instance of a in-memory cargo repository.
43 func NewCargo() cargo.Repository {
44 return &cargoRepository{
45 cargos: make(map[cargo.TrackingID]*cargo.Cargo),
46 }
47 }
48
49 type locationRepository struct {
50 locations map[location.UNLocode]location.Location
51 }
52
53 func (r *locationRepository) Find(locode location.UNLocode) (location.Location, error) {
54 if l, ok := r.locations[locode]; ok {
55 return l, nil
56 }
57 return location.Location{}, location.ErrUnknown
58 }
59
60 func (r *locationRepository) FindAll() []location.Location {
61 l := make([]location.Location, 0, len(r.locations))
62 for _, val := range r.locations {
63 l = append(l, val)
64 }
65 return l
66 }
67
68 // NewLocation returns a new instance of a in-memory location repository.
69 func NewLocation() location.Repository {
70 r := &locationRepository{
71 locations: make(map[location.UNLocode]location.Location),
72 }
73
74 r.locations[location.SESTO] = location.Stockholm
75 r.locations[location.AUMEL] = location.Melbourne
76 r.locations[location.CNHKG] = location.Hongkong
77 r.locations[location.JNTKO] = location.Tokyo
78 r.locations[location.NLRTM] = location.Rotterdam
79 r.locations[location.DEHAM] = location.Hamburg
80
81 return r
82 }
83
84 type voyageRepository struct {
85 voyages map[voyage.Number]*voyage.Voyage
86 }
87
88 func (r *voyageRepository) Find(voyageNumber voyage.Number) (*voyage.Voyage, error) {
89 if v, ok := r.voyages[voyageNumber]; ok {
90 return v, nil
91 }
92
93 return nil, voyage.ErrUnknown
94 }
95
96 // NewVoyage returns a new instance of a in-memory voyage repository.
97 func NewVoyage() voyage.Repository {
98 r := &voyageRepository{
99 voyages: make(map[voyage.Number]*voyage.Voyage),
100 }
101
102 r.voyages[voyage.V100.Number] = voyage.V100
103 r.voyages[voyage.V300.Number] = voyage.V300
104 r.voyages[voyage.V400.Number] = voyage.V400
105
106 r.voyages[voyage.V0100S.Number] = voyage.V0100S
107 r.voyages[voyage.V0200T.Number] = voyage.V0200T
108 r.voyages[voyage.V0300A.Number] = voyage.V0300A
109 r.voyages[voyage.V0301S.Number] = voyage.V0301S
110 r.voyages[voyage.V0400S.Number] = voyage.V0400S
111
112 return r
113 }
114
115 type handlingEventRepository struct {
116 mtx sync.RWMutex
117 events map[cargo.TrackingID][]cargo.HandlingEvent
118 }
119
120 func (r *handlingEventRepository) Store(e cargo.HandlingEvent) {
121 r.mtx.Lock()
122 defer r.mtx.Unlock()
123 // Make array if it's the first event with this tracking ID.
124 if _, ok := r.events[e.TrackingID]; !ok {
125 r.events[e.TrackingID] = make([]cargo.HandlingEvent, 0)
126 }
127 r.events[e.TrackingID] = append(r.events[e.TrackingID], e)
128 }
129
130 func (r *handlingEventRepository) QueryHandlingHistory(trackingID cargo.TrackingID) cargo.HandlingHistory {
131 r.mtx.RLock()
132 defer r.mtx.RUnlock()
133 return cargo.HandlingHistory{HandlingEvents: r.events[trackingID]}
134 }
135
136 // NewHandlingEvent returns a new instance of a in-memory handling event repository.
137 func NewHandlingEvent() cargo.HandlingEventRepository {
138 return &handlingEventRepository{
139 events: make(map[cargo.TrackingID][]cargo.HandlingEvent),
140 }
141 }
99
1010 "github.com/go-kit/kit/circuitbreaker"
1111 "github.com/go-kit/kit/endpoint"
12 kithttp "github.com/go-kit/kit/transport/http"
13
1214 "github.com/go-kit/kit/examples/shipping/cargo"
1315 "github.com/go-kit/kit/examples/shipping/location"
1416 "github.com/go-kit/kit/examples/shipping/voyage"
15 kithttp "github.com/go-kit/kit/transport/http"
1617 )
1718
1819 type proxyService struct {
5556 type ServiceMiddleware func(Service) Service
5657
5758 // NewProxyingMiddleware returns a new instance of a proxying middleware.
58 func NewProxyingMiddleware(proxyURL string, ctx context.Context) ServiceMiddleware {
59 func NewProxyingMiddleware(ctx context.Context, proxyURL string) ServiceMiddleware {
5960 return func(next Service) Service {
6061 var e endpoint.Endpoint
6162 e = makeFetchRoutesEndpoint(ctx, proxyURL)
1212 }
1313
1414 // NewInstrumentingService returns an instance of an instrumenting Service.
15 func NewInstrumentingService(requestCount metrics.Counter, requestLatency metrics.Histogram, s Service) Service {
15 func NewInstrumentingService(counter metrics.Counter, latency metrics.Histogram, s Service) Service {
1616 return &instrumentingService{
17 requestCount: requestCount,
18 requestLatency: requestLatency,
17 requestCount: counter,
18 requestLatency: latency,
1919 Service: s,
2020 }
2121 }
3636 }
3737
3838 // NewService returns a new instance of the default Service.
39 func NewService(cargos cargo.Repository, handlingEvents cargo.HandlingEventRepository) Service {
39 func NewService(cargos cargo.Repository, events cargo.HandlingEventRepository) Service {
4040 return &service{
4141 cargos: cargos,
42 handlingEvents: handlingEvents,
42 handlingEvents: events,
4343 }
4444 }
4545
7070 Expected bool `json:"expected"`
7171 }
7272
73 func assemble(c *cargo.Cargo, her cargo.HandlingEventRepository) Cargo {
73 func assemble(c *cargo.Cargo, events cargo.HandlingEventRepository) Cargo {
7474 return Cargo{
7575 TrackingID: string(c.TrackingID),
7676 Origin: string(c.Origin),
7979 NextExpectedActivity: nextExpectedActivity(c),
8080 ArrivalDeadline: c.RouteSpecification.ArrivalDeadline,
8181 StatusText: assembleStatusText(c),
82 Events: assembleEvents(c, her),
82 Events: assembleEvents(c, events),
8383 }
8484 }
8585
128128 }
129129 }
130130
131 func assembleEvents(c *cargo.Cargo, r cargo.HandlingEventRepository) []Event {
132 h := r.QueryHandlingHistory(c.TrackingID)
131 func assembleEvents(c *cargo.Cargo, handlingEvents cargo.HandlingEventRepository) []Event {
132 h := handlingEvents.QueryHandlingHistory(c.TrackingID)
133133
134134 var events []Event
135135 for _, e := range h.HandlingEvents {
77 "github.com/gorilla/mux"
88 "golang.org/x/net/context"
99
10 "github.com/go-kit/kit/examples/shipping/cargo"
1110 kitlog "github.com/go-kit/kit/log"
1211 kithttp "github.com/go-kit/kit/transport/http"
12
13 "github.com/go-kit/kit/examples/shipping/cargo"
1314 )
1415
1516 // MakeHandler returns a handler for the tracking service.
55 var (
66 V100 = New("V100", Schedule{
77 []CarrierMovement{
8 {DepartureLocation: location.Hongkong, ArrivalLocation: location.Tokyo},
9 {DepartureLocation: location.Tokyo, ArrivalLocation: location.NewYork},
8 {DepartureLocation: location.CNHKG, ArrivalLocation: location.JNTKO},
9 {DepartureLocation: location.JNTKO, ArrivalLocation: location.USNYC},
1010 },
1111 })
1212
1313 V300 = New("V300", Schedule{
1414 []CarrierMovement{
15 {DepartureLocation: location.Tokyo, ArrivalLocation: location.Rotterdam},
16 {DepartureLocation: location.Rotterdam, ArrivalLocation: location.Hamburg},
17 {DepartureLocation: location.Hamburg, ArrivalLocation: location.Melbourne},
18 {DepartureLocation: location.Melbourne, ArrivalLocation: location.Tokyo},
15 {DepartureLocation: location.JNTKO, ArrivalLocation: location.NLRTM},
16 {DepartureLocation: location.NLRTM, ArrivalLocation: location.DEHAM},
17 {DepartureLocation: location.DEHAM, ArrivalLocation: location.AUMEL},
18 {DepartureLocation: location.AUMEL, ArrivalLocation: location.JNTKO},
1919 },
2020 })
2121
2222 V400 = New("V400", Schedule{
2323 []CarrierMovement{
24 {DepartureLocation: location.Hamburg, ArrivalLocation: location.Stockholm},
25 {DepartureLocation: location.Stockholm, ArrivalLocation: location.Helsinki},
26 {DepartureLocation: location.Helsinki, ArrivalLocation: location.Hamburg},
24 {DepartureLocation: location.DEHAM, ArrivalLocation: location.SESTO},
25 {DepartureLocation: location.SESTO, ArrivalLocation: location.FIHEL},
26 {DepartureLocation: location.FIHEL, ArrivalLocation: location.DEHAM},
2727 },
2828 })
2929 )
2828
2929 // CarrierMovement is a vessel voyage from one location to another.
3030 type CarrierMovement struct {
31 DepartureLocation location.Location
32 ArrivalLocation location.Location
31 DepartureLocation location.UNLocode
32 ArrivalLocation location.UNLocode
3333 DepartureTime time.Time
3434 ArrivalTime time.Time
3535 }