├── public ├── stylesheets │ └── main.css └── index.html ├── .gitignore ├── Dockerfile ├── Makefile ├── internal ├── proto │ ├── geo │ │ ├── geo.proto │ │ └── geo.pb.go │ ├── search │ │ ├── search.proto │ │ └── search.pb.go │ ├── rate │ │ ├── rate.proto │ │ └── rate.pb.go │ └── profile │ │ ├── profile.proto │ │ └── profile.pb.go └── trace │ ├── tracer.go │ └── mux.go ├── profile_test.go ├── data ├── geo.json ├── inventory.json ├── hotels.json └── bindata.go ├── docker-compose.yml ├── LICENSE ├── go.mod ├── cmd └── go-micro-services │ └── main.go ├── profile.go ├── search.go ├── rate.go ├── geo.go ├── frontend.go ├── README.md └── go.sum /public/stylesheets/main.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | margin: 0; 5 | padding: 0; 6 | } 7 | 8 | #map { 9 | height: 100%; 10 | } 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cmd/*/data 2 | cmd/api/api 3 | cmd/auth/auth 4 | cmd/geo/geo 5 | cmd/profile/profile 6 | cmd/rate/rate 7 | cmd/www/www 8 | cmd/search/search 9 | vendor/** 10 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.13.4 2 | COPY . /go/src/github.com/harlow/go-micro-services 3 | WORKDIR /go/src/github.com/harlow/go-micro-services 4 | RUN go install -ldflags="-s -w" ./cmd/... 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: proto data run 2 | 3 | proto: 4 | for f in internal/proto/*/*.proto; do \ 5 | protoc --go_out=plugins=grpc:. $$f; \ 6 | echo compiled: $$f; \ 7 | done 8 | 9 | data: 10 | go-bindata -o data/bindata.go -pkg data data/*.json 11 | 12 | run: 13 | docker-compose build 14 | docker-compose up --remove-orphans 15 | -------------------------------------------------------------------------------- /internal/proto/geo/geo.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package geo; 4 | 5 | service Geo { 6 | // Finds the hotels contained nearby the current lat/lon. 7 | rpc Nearby(Request) returns (Result); 8 | } 9 | 10 | // The latitude and longitude of the current location. 11 | message Request { 12 | float lat = 1; 13 | float lon = 2; 14 | } 15 | 16 | message Result { 17 | repeated string hotelIds = 1; 18 | } 19 | -------------------------------------------------------------------------------- /profile_test.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/harlow/go-micro-services/internal/proto/profile" 7 | ) 8 | 9 | func TestGetProfile(t *testing.T) { 10 | s := &Profile{ 11 | profiles: map[string]*profile.Hotel{ 12 | "1": &profile.Hotel{Id: "1", Name: "Cliff Hotel"}, 13 | }, 14 | } 15 | 16 | got := s.getProfile("1") 17 | 18 | if got.Name != "Cliff Hotel" { 19 | t.Fatalf("get profile error: expected %v, got %v", "Cliff Hotel", got.Name) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /internal/proto/search/search.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package search; 4 | 5 | // Search service returns best hotel chocies for a user. 6 | service Search { 7 | rpc Nearby(NearbyRequest) returns (SearchResult); 8 | // rpc City(CityRequest) returns (SearchResult); 9 | } 10 | 11 | message NearbyRequest { 12 | float lat = 1; 13 | float lon = 2; 14 | string inDate = 3; 15 | string outDate = 4; 16 | } 17 | 18 | // TODO(hw): add city search endpoint 19 | // message CityRequest { 20 | // string city = 1; 21 | // string inDate = 2; 22 | // string outDate = 3; 23 | // } 24 | 25 | message SearchResult { 26 | repeated string hotelIds = 1; 27 | } 28 | -------------------------------------------------------------------------------- /data/geo.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "hotelId": "1", 4 | "lat": 37.7867, 5 | "lon": -122.4112 6 | }, 7 | { 8 | "hotelId": "2", 9 | "lat": 37.7854, 10 | "lon": -122.4005 11 | }, 12 | { 13 | "hotelId": "3", 14 | "lat": 37.7834, 15 | "lon": -122.4071 16 | }, 17 | { 18 | "hotelId": "4", 19 | "lat": 37.7936, 20 | "lon": -122.3930 21 | }, 22 | { 23 | "hotelId": "5", 24 | "lat": 37.7831, 25 | "lon": -122.4181 26 | }, 27 | { 28 | "hotelId": "6", 29 | "lat": 37.7863, 30 | "lon": -122.4015 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /internal/trace/tracer.go: -------------------------------------------------------------------------------- 1 | package trace 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | opentracing "github.com/opentracing/opentracing-go" 8 | "github.com/uber/jaeger-client-go/config" 9 | ) 10 | 11 | // New creates a new Jaeger tracer 12 | func New(serviceName, host string) (opentracing.Tracer, error) { 13 | cfg := config.Configuration{ 14 | Sampler: &config.SamplerConfig{ 15 | Type: "const", 16 | Param: 1, 17 | }, 18 | Reporter: &config.ReporterConfig{ 19 | LogSpans: false, 20 | BufferFlushInterval: 1 * time.Second, 21 | LocalAgentHostPort: host, 22 | }, 23 | } 24 | 25 | tracer, _, err := cfg.New(serviceName) 26 | if err != nil { 27 | return nil, fmt.Errorf("new tracer error: %v", err) 28 | } 29 | return tracer, nil 30 | } 31 | -------------------------------------------------------------------------------- /internal/proto/rate/rate.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package rate; 4 | 5 | service Rate { 6 | // GetRates returns rate codes for hotels for a given date range 7 | rpc GetRates(Request) returns (Result); 8 | } 9 | 10 | message Request { 11 | repeated string hotelIds = 1; 12 | string inDate = 2; 13 | string outDate = 3; 14 | } 15 | 16 | message Result { 17 | repeated RatePlan ratePlans = 1; 18 | } 19 | 20 | message RatePlan { 21 | string hotelId = 1; 22 | string code = 2; 23 | string inDate = 3; 24 | string outDate = 4; 25 | RoomType roomType = 5; 26 | } 27 | 28 | message RoomType { 29 | double bookableRate = 1; 30 | double totalRate = 2; 31 | double totalRateInclusive = 3; 32 | string code = 4; 33 | string currency = 5; 34 | string roomDescription = 6; 35 | } 36 | -------------------------------------------------------------------------------- /internal/proto/profile/profile.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package profile; 4 | 5 | service Profile { 6 | rpc GetProfiles(Request) returns (Result); 7 | } 8 | 9 | message Request { 10 | repeated string hotelIds = 1; 11 | string locale = 2; 12 | } 13 | 14 | message Result { 15 | repeated Hotel hotels = 1; 16 | } 17 | 18 | message Hotel { 19 | string id = 1; 20 | string name = 2; 21 | string phoneNumber = 3; 22 | string description = 4; 23 | Address address = 5; 24 | repeated Image images = 6; 25 | } 26 | 27 | message Address { 28 | string streetNumber = 1; 29 | string streetName = 2; 30 | string city = 3; 31 | string state = 4; 32 | string country = 5; 33 | string postalCode = 6; 34 | float lat = 7; 35 | float lon = 8; 36 | } 37 | 38 | message Image { 39 | string url = 1; 40 | bool default = 2; 41 | } 42 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | frontend: 4 | build: . 5 | entrypoint: go-micro-services frontend 6 | ports: 7 | - "5000:8080" 8 | links: 9 | - jaeger 10 | - search 11 | - profile 12 | depends_on: 13 | - search 14 | - profile 15 | search: 16 | build: . 17 | entrypoint: go-micro-services search 18 | links: 19 | - geo 20 | - rate 21 | - jaeger 22 | profile: 23 | build: . 24 | entrypoint: go-micro-services profile 25 | links: 26 | - geo 27 | - rate 28 | - jaeger 29 | geo: 30 | build: . 31 | entrypoint: go-micro-services geo 32 | links: 33 | - jaeger 34 | rate: 35 | build: . 36 | entrypoint: go-micro-services rate 37 | links: 38 | - jaeger 39 | jaeger: 40 | image: jaegertracing/all-in-one:latest 41 | ports: 42 | - "14269" 43 | - "5778:5778" 44 | - "14268:14268" 45 | - "14267" 46 | - "16686:16686" 47 | - "5775:5775/udp" 48 | - "6831:6831/udp" 49 | - "6832:6832/udp" 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Harlow Ward 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /data/inventory.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "hotelId": "1", 4 | "code": "RACK", 5 | "inDate": "2015-04-09", 6 | "outDate": "2015-04-10", 7 | "roomType": { 8 | "bookableRate": 109.00, 9 | "code": "KNG", 10 | "description": "King sized bed", 11 | "totalRate": 109.00, 12 | "totalRateInclusive": 123.17 13 | } 14 | }, 15 | { 16 | "hotelId": "2", 17 | "code": "RACK", 18 | "inDate": "2015-04-09", 19 | "outDate": "2015-04-10", 20 | "roomType": { 21 | "bookableRate": 139.00, 22 | "code": "QN", 23 | "description": "Queen sized bed", 24 | "totalRate": 139.00, 25 | "totalRateInclusive": 153.09 26 | } 27 | }, 28 | { 29 | "hotelId": "3", 30 | "code": "RACK", 31 | "inDate": "2015-04-09", 32 | "outDate": "2015-04-10", 33 | "roomType": { 34 | "bookableRate": 109.00, 35 | "code": "KNG", 36 | "description": "King sized bed", 37 | "totalRate": 109.00, 38 | "totalRateInclusive": 123.17 39 | } 40 | } 41 | ] 42 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/harlow/go-micro-services 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7 // indirect 7 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect 10 | github.com/golang/protobuf v1.2.0 11 | github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20171214222146-0e7658f8ee99 12 | github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711 13 | github.com/opentracing-contrib/go-stdlib v0.0.0-20180308002341-f6b9967a3c69 14 | github.com/opentracing/opentracing-go v1.0.2 15 | github.com/prometheus/client_golang v0.9.2 // indirect 16 | github.com/stretchr/testify v1.3.0 // indirect 17 | github.com/uber-go/atomic v1.4.0 // indirect 18 | github.com/uber/jaeger-client-go v2.11.2+incompatible 19 | github.com/uber/jaeger-lib v1.4.0 // indirect 20 | go.uber.org/atomic v1.4.0 // indirect 21 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 22 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect 23 | google.golang.org/genproto v0.0.0-20180306020942-df60624c1e9b // indirect 24 | google.golang.org/grpc v1.10.0 25 | ) 26 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Go Microservices Example 6 | 7 | 8 | 9 |
10 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /internal/trace/mux.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Uber Technologies, Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package trace 16 | 17 | import ( 18 | "net/http" 19 | 20 | "github.com/opentracing-contrib/go-stdlib/nethttp" 21 | opentracing "github.com/opentracing/opentracing-go" 22 | ) 23 | 24 | // NewServeMux creates a new TracedServeMux. 25 | func NewServeMux(tracer opentracing.Tracer) *TracedServeMux { 26 | return &TracedServeMux{ 27 | mux: http.NewServeMux(), 28 | tracer: tracer, 29 | } 30 | } 31 | 32 | // TracedServeMux is a wrapper around http.ServeMux that instruments handlers for tracing. 33 | type TracedServeMux struct { 34 | mux *http.ServeMux 35 | tracer opentracing.Tracer 36 | } 37 | 38 | // Handle implements http.ServeMux#Handle 39 | func (tm *TracedServeMux) Handle(pattern string, handler http.Handler) { 40 | middleware := nethttp.Middleware( 41 | tm.tracer, 42 | handler, 43 | nethttp.OperationNameFunc(func(r *http.Request) string { 44 | return "HTTP " + r.Method + " " + pattern 45 | })) 46 | tm.mux.Handle(pattern, middleware) 47 | } 48 | 49 | // ServeHTTP implements http.ServeMux#ServeHTTP 50 | func (tm *TracedServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { 51 | tm.mux.ServeHTTP(w, r) 52 | } 53 | -------------------------------------------------------------------------------- /cmd/go-micro-services/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "os" 8 | 9 | "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc" 10 | services "github.com/harlow/go-micro-services" 11 | "github.com/harlow/go-micro-services/internal/trace" 12 | opentracing "github.com/opentracing/opentracing-go" 13 | "google.golang.org/grpc" 14 | ) 15 | 16 | type server interface { 17 | Run(int) error 18 | } 19 | 20 | func main() { 21 | var ( 22 | port = flag.Int("port", 8080, "The service port") 23 | jaegeraddr = flag.String("jaeger", "jaeger:6831", "Jaeger address") 24 | profileaddr = flag.String("profileaddr", "profile:8080", "Profile service addr") 25 | geoaddr = flag.String("geoaddr", "geo:8080", "Geo server addr") 26 | rateaddr = flag.String("rateaddr", "rate:8080", "Rate server addr") 27 | searchaddr = flag.String("searchaddr", "search:8080", "Search service addr") 28 | ) 29 | flag.Parse() 30 | 31 | t, err := trace.New("search", *jaegeraddr) 32 | if err != nil { 33 | log.Fatalf("trace new error: %v", err) 34 | } 35 | 36 | var srv server 37 | var cmd = os.Args[1] 38 | 39 | switch cmd { 40 | case "geo": 41 | srv = services.NewGeo(t) 42 | case "rate": 43 | srv = services.NewRate(t) 44 | case "profile": 45 | srv = services.NewProfile(t) 46 | case "search": 47 | srv = services.NewSearch( 48 | t, 49 | dial(*geoaddr, t), 50 | dial(*rateaddr, t), 51 | ) 52 | case "frontend": 53 | srv = services.NewFrontend( 54 | t, 55 | dial(*searchaddr, t), 56 | dial(*profileaddr, t), 57 | ) 58 | default: 59 | log.Fatalf("unknown cmd: %s", cmd) 60 | } 61 | 62 | if err := srv.Run(*port); err != nil { 63 | log.Fatalf("run %s error: %v", cmd, err) 64 | } 65 | } 66 | 67 | func dial(addr string, t opentracing.Tracer) *grpc.ClientConn { 68 | opts := []grpc.DialOption{ 69 | grpc.WithInsecure(), 70 | grpc.WithUnaryInterceptor(otgrpc.OpenTracingClientInterceptor(t)), 71 | } 72 | 73 | conn, err := grpc.Dial(addr, opts...) 74 | if err != nil { 75 | panic(fmt.Sprintf("ERROR: dial error: %v", err)) 76 | } 77 | 78 | return conn 79 | } 80 | -------------------------------------------------------------------------------- /profile.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "net" 8 | 9 | "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc" 10 | "github.com/harlow/go-micro-services/data" 11 | "github.com/harlow/go-micro-services/internal/proto/profile" 12 | opentracing "github.com/opentracing/opentracing-go" 13 | "golang.org/x/net/context" 14 | "google.golang.org/grpc" 15 | ) 16 | 17 | // NewProfile returns a new server 18 | func NewProfile(tr opentracing.Tracer) *Profile { 19 | return &Profile{ 20 | tracer: tr, 21 | profiles: loadProfiles("data/hotels.json"), 22 | } 23 | } 24 | 25 | // Profile implements the profile service 26 | type Profile struct { 27 | profiles map[string]*profile.Hotel 28 | tracer opentracing.Tracer 29 | } 30 | 31 | // Run starts the server 32 | func (s *Profile) Run(port int) error { 33 | srv := grpc.NewServer( 34 | grpc.UnaryInterceptor( 35 | otgrpc.OpenTracingServerInterceptor(s.tracer), 36 | ), 37 | ) 38 | profile.RegisterProfileServer(srv, s) 39 | 40 | lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 41 | if err != nil { 42 | log.Fatalf("failed to listen: %v", err) 43 | } 44 | 45 | return srv.Serve(lis) 46 | } 47 | 48 | // GetProfiles returns hotel profiles for requested IDs 49 | func (s *Profile) GetProfiles(ctx context.Context, req *profile.Request) (*profile.Result, error) { 50 | res := new(profile.Result) 51 | for _, id := range req.HotelIds { 52 | res.Hotels = append(res.Hotels, s.getProfile(id)) 53 | } 54 | return res, nil 55 | } 56 | 57 | func (s *Profile) getProfile(id string) *profile.Hotel { 58 | return s.profiles[id] 59 | } 60 | 61 | // loadProfiles loads hotel profiles from a JSON file. 62 | func loadProfiles(path string) map[string]*profile.Hotel { 63 | var ( 64 | file = data.MustAsset(path) 65 | hotels []*profile.Hotel 66 | ) 67 | 68 | if err := json.Unmarshal(file, &hotels); err != nil { 69 | log.Fatalf("Failed to load json: %v", err) 70 | } 71 | 72 | profiles := make(map[string]*profile.Hotel) 73 | for _, hotel := range hotels { 74 | profiles[hotel.Id] = hotel 75 | } 76 | return profiles 77 | } 78 | -------------------------------------------------------------------------------- /search.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net" 7 | 8 | "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc" 9 | "github.com/harlow/go-micro-services/internal/proto/geo" 10 | "github.com/harlow/go-micro-services/internal/proto/rate" 11 | "github.com/harlow/go-micro-services/internal/proto/search" 12 | opentracing "github.com/opentracing/opentracing-go" 13 | context "golang.org/x/net/context" 14 | "google.golang.org/grpc" 15 | ) 16 | 17 | // NewSearch returns a new server 18 | func NewSearch(t opentracing.Tracer, geoconn, rateconn *grpc.ClientConn) *Search { 19 | return &Search{ 20 | geoClient: geo.NewGeoClient(geoconn), 21 | rateClient: rate.NewRateClient(rateconn), 22 | tracer: t, 23 | } 24 | } 25 | 26 | // Search implments the search service 27 | type Search struct { 28 | geoClient geo.GeoClient 29 | rateClient rate.RateClient 30 | tracer opentracing.Tracer 31 | } 32 | 33 | // Run starts the server 34 | func (s *Search) Run(port int) error { 35 | srv := grpc.NewServer( 36 | grpc.UnaryInterceptor( 37 | otgrpc.OpenTracingServerInterceptor(s.tracer), 38 | ), 39 | ) 40 | search.RegisterSearchServer(srv, s) 41 | 42 | lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 43 | if err != nil { 44 | log.Fatalf("failed to listen: %v", err) 45 | } 46 | return srv.Serve(lis) 47 | } 48 | 49 | // Nearby returns ids of nearby hotels ordered by ranking algo 50 | func (s *Search) Nearby(ctx context.Context, req *search.NearbyRequest) (*search.SearchResult, error) { 51 | // find nearby hotels 52 | nearby, err := s.geoClient.Nearby(ctx, &geo.Request{ 53 | Lat: req.Lat, 54 | Lon: req.Lon, 55 | }) 56 | if err != nil { 57 | log.Fatalf("nearby error: %v", err) 58 | } 59 | 60 | // find rates for hotels 61 | rates, err := s.rateClient.GetRates(ctx, &rate.Request{ 62 | HotelIds: nearby.HotelIds, 63 | InDate: req.InDate, 64 | OutDate: req.OutDate, 65 | }) 66 | if err != nil { 67 | log.Fatalf("rates error: %v", err) 68 | } 69 | 70 | // build the response 71 | res := new(search.SearchResult) 72 | for _, ratePlan := range rates.RatePlans { 73 | res.HotelIds = append(res.HotelIds, ratePlan.HotelId) 74 | } 75 | 76 | return res, nil 77 | } 78 | -------------------------------------------------------------------------------- /rate.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "net" 8 | 9 | "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc" 10 | "github.com/harlow/go-micro-services/data" 11 | "github.com/harlow/go-micro-services/internal/proto/rate" 12 | opentracing "github.com/opentracing/opentracing-go" 13 | "golang.org/x/net/context" 14 | "google.golang.org/grpc" 15 | ) 16 | 17 | // NewRate returns a new server 18 | func NewRate(tr opentracing.Tracer) *Rate { 19 | return &Rate{ 20 | tracer: tr, 21 | rateTable: loadRateTable("data/inventory.json"), 22 | } 23 | } 24 | 25 | // Rate implements the rate service 26 | type Rate struct { 27 | rateTable map[stay]*rate.RatePlan 28 | tracer opentracing.Tracer 29 | } 30 | 31 | // Run starts the server 32 | func (s *Rate) Run(port int) error { 33 | srv := grpc.NewServer( 34 | grpc.UnaryInterceptor( 35 | otgrpc.OpenTracingServerInterceptor(s.tracer), 36 | ), 37 | ) 38 | rate.RegisterRateServer(srv, s) 39 | 40 | lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 41 | if err != nil { 42 | log.Fatalf("failed to listen: %v", err) 43 | } 44 | 45 | return srv.Serve(lis) 46 | } 47 | 48 | // GetRates gets rates for hotels for specific date range. 49 | func (s *Rate) GetRates(ctx context.Context, req *rate.Request) (*rate.Result, error) { 50 | res := new(rate.Result) 51 | 52 | for _, hotelID := range req.HotelIds { 53 | stay := stay{ 54 | HotelID: hotelID, 55 | InDate: req.InDate, 56 | OutDate: req.OutDate, 57 | } 58 | if s.rateTable[stay] != nil { 59 | res.RatePlans = append(res.RatePlans, s.rateTable[stay]) 60 | } 61 | } 62 | 63 | return res, nil 64 | } 65 | 66 | // loadRates loads rate codes from JSON file. 67 | func loadRateTable(path string) map[stay]*rate.RatePlan { 68 | file := data.MustAsset(path) 69 | 70 | rates := []*rate.RatePlan{} 71 | if err := json.Unmarshal(file, &rates); err != nil { 72 | log.Fatalf("Failed to load json: %v", err) 73 | } 74 | 75 | rateTable := make(map[stay]*rate.RatePlan) 76 | for _, ratePlan := range rates { 77 | stay := stay{ 78 | HotelID: ratePlan.HotelId, 79 | InDate: ratePlan.InDate, 80 | OutDate: ratePlan.OutDate, 81 | } 82 | rateTable[stay] = ratePlan 83 | } 84 | 85 | return rateTable 86 | } 87 | 88 | type stay struct { 89 | HotelID string 90 | InDate string 91 | OutDate string 92 | } 93 | -------------------------------------------------------------------------------- /geo.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "net" 8 | 9 | "github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc" 10 | "github.com/hailocab/go-geoindex" 11 | "github.com/harlow/go-micro-services/data" 12 | "github.com/harlow/go-micro-services/internal/proto/geo" 13 | opentracing "github.com/opentracing/opentracing-go" 14 | "golang.org/x/net/context" 15 | "google.golang.org/grpc" 16 | ) 17 | 18 | const ( 19 | maxSearchRadius = 10 20 | maxSearchResults = 5 21 | ) 22 | 23 | // point represents a hotels's geo location on map 24 | type point struct { 25 | Pid string `json:"hotelId"` 26 | Plat float64 `json:"lat"` 27 | Plon float64 `json:"lon"` 28 | } 29 | 30 | // Implement Point interface 31 | func (p *point) Lat() float64 { return p.Plat } 32 | func (p *point) Lon() float64 { return p.Plon } 33 | func (p *point) Id() string { return p.Pid } 34 | 35 | // NewGeo returns a new server 36 | func NewGeo(tr opentracing.Tracer) *Geo { 37 | return &Geo{ 38 | tracer: tr, 39 | geoidx: newGeoIndex("data/geo.json"), 40 | } 41 | } 42 | 43 | // Server implements the geo service 44 | type Geo struct { 45 | geoidx *geoindex.ClusteringIndex 46 | tracer opentracing.Tracer 47 | } 48 | 49 | // Run starts the server 50 | func (s *Geo) Run(port int) error { 51 | srv := grpc.NewServer( 52 | grpc.UnaryInterceptor( 53 | otgrpc.OpenTracingServerInterceptor(s.tracer), 54 | ), 55 | ) 56 | geo.RegisterGeoServer(srv, s) 57 | 58 | lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) 59 | if err != nil { 60 | return fmt.Errorf("failed to listen: %v", err) 61 | } 62 | 63 | return srv.Serve(lis) 64 | } 65 | 66 | // Nearby returns all hotels within a given distance. 67 | func (s *Geo) Nearby(ctx context.Context, req *geo.Request) (*geo.Result, error) { 68 | var ( 69 | points = s.getNearbyPoints(ctx, float64(req.Lat), float64(req.Lon)) 70 | res = &geo.Result{} 71 | ) 72 | 73 | for _, p := range points { 74 | res.HotelIds = append(res.HotelIds, p.Id()) 75 | } 76 | 77 | return res, nil 78 | } 79 | 80 | func (s *Geo) getNearbyPoints(ctx context.Context, lat, lon float64) []geoindex.Point { 81 | center := &geoindex.GeoPoint{ 82 | Pid: "", 83 | Plat: lat, 84 | Plon: lon, 85 | } 86 | 87 | return s.geoidx.KNearest( 88 | center, 89 | maxSearchResults, 90 | geoindex.Km(maxSearchRadius), func(p geoindex.Point) bool { 91 | return true 92 | }, 93 | ) 94 | } 95 | 96 | // newGeoIndex returns a geo index with points loaded 97 | func newGeoIndex(path string) *geoindex.ClusteringIndex { 98 | var ( 99 | file = data.MustAsset(path) 100 | points []*point 101 | ) 102 | 103 | // load geo points from json file 104 | if err := json.Unmarshal(file, &points); err != nil { 105 | log.Fatalf("Failed to load hotels: %v", err) 106 | } 107 | 108 | // add points to index 109 | index := geoindex.NewClusteringIndex() 110 | for _, point := range points { 111 | index.Add(point) 112 | } 113 | 114 | return index 115 | } 116 | -------------------------------------------------------------------------------- /frontend.go: -------------------------------------------------------------------------------- 1 | package services 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "net/http" 7 | 8 | "github.com/harlow/go-micro-services/internal/trace" 9 | "github.com/harlow/go-micro-services/internal/proto/profile" 10 | "github.com/harlow/go-micro-services/internal/proto/search" 11 | opentracing "github.com/opentracing/opentracing-go" 12 | "google.golang.org/grpc" 13 | ) 14 | 15 | // NewFrontend returns a new server 16 | func NewFrontend(t opentracing.Tracer, searchconn, profileconn *grpc.ClientConn) *Frontend { 17 | return &Frontend{ 18 | searchClient: search.NewSearchClient(searchconn), 19 | profileClient: profile.NewProfileClient(profileconn), 20 | tracer: t, 21 | } 22 | } 23 | 24 | // Frontend implements frontend service 25 | type Frontend struct { 26 | searchClient search.SearchClient 27 | profileClient profile.ProfileClient 28 | tracer opentracing.Tracer 29 | } 30 | 31 | // Run the server 32 | func (s *Frontend) Run(port int) error { 33 | mux := trace.NewServeMux(s.tracer) 34 | mux.Handle("/", http.FileServer(http.Dir("public"))) 35 | mux.Handle("/hotels", http.HandlerFunc(s.searchHandler)) 36 | 37 | return http.ListenAndServe(fmt.Sprintf(":%d", port), mux) 38 | } 39 | 40 | func (s *Frontend) searchHandler(w http.ResponseWriter, r *http.Request) { 41 | w.Header().Set("Access-Control-Allow-Origin", "*") 42 | ctx := r.Context() 43 | 44 | // in/out dates from query params 45 | inDate, outDate := r.URL.Query().Get("inDate"), r.URL.Query().Get("outDate") 46 | if inDate == "" || outDate == "" { 47 | http.Error(w, "Please specify inDate/outDate params", http.StatusBadRequest) 48 | return 49 | } 50 | 51 | // search for best hotels 52 | // TODO(hw): allow lat/lon from input params 53 | searchResp, err := s.searchClient.Nearby(ctx, &search.NearbyRequest{ 54 | Lat: 37.7749, 55 | Lon: -122.4194, 56 | InDate: inDate, 57 | OutDate: outDate, 58 | }) 59 | if err != nil { 60 | http.Error(w, err.Error(), http.StatusInternalServerError) 61 | return 62 | } 63 | 64 | // grab locale from query params or default to en 65 | locale := r.URL.Query().Get("locale") 66 | if locale == "" { 67 | locale = "en" 68 | } 69 | 70 | // hotel profiles 71 | profileResp, err := s.profileClient.GetProfiles(ctx, &profile.Request{ 72 | HotelIds: searchResp.HotelIds, 73 | Locale: locale, 74 | }) 75 | if err != nil { 76 | http.Error(w, err.Error(), http.StatusInternalServerError) 77 | return 78 | } 79 | 80 | json.NewEncoder(w).Encode(geoJSONResponse(profileResp.Hotels)) 81 | } 82 | 83 | // return a geoJSON response that allows google map to plot points directly on map 84 | // https://developers.google.com/maps/documentation/javascript/datalayer#sample_geojson 85 | func geoJSONResponse(hs []*profile.Hotel) map[string]interface{} { 86 | fs := []interface{}{} 87 | 88 | for _, h := range hs { 89 | fs = append(fs, map[string]interface{}{ 90 | "type": "Feature", 91 | "id": h.Id, 92 | "properties": map[string]string{ 93 | "name": h.Name, 94 | "phone_number": h.PhoneNumber, 95 | }, 96 | "geometry": map[string]interface{}{ 97 | "type": "Point", 98 | "coordinates": []float32{ 99 | h.Address.Lon, 100 | h.Address.Lat, 101 | }, 102 | }, 103 | }) 104 | } 105 | 106 | return map[string]interface{}{ 107 | "type": "FeatureCollection", 108 | "features": fs, 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /data/hotels.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "1", 4 | "name": "Clift Hotel", 5 | "phoneNumber": "(415) 775-4700", 6 | "description": "A 6-minute walk from Union Square and 4 minutes from a Muni Metro station, this luxury hotel designed by Philippe Starck features an artsy furniture collection in the lobby, including work by Salvador Dali.", 7 | "address": { 8 | "streetNumber": "495", 9 | "streetName": "Geary St", 10 | "city": "San Francisco", 11 | "state": "CA", 12 | "country": "United States", 13 | "postalCode": "94102", 14 | "lat": 37.7867, 15 | "lon": -122.4112 16 | } 17 | }, 18 | { 19 | "id": "2", 20 | "name": "W San Francisco", 21 | "phoneNumber": "(415) 777-5300", 22 | "description": "Less than a block from the Yerba Buena Center for the Arts, this trendy hotel is a 12-minute walk from Union Square.", 23 | "address": { 24 | "streetNumber": "181", 25 | "streetName": "3rd St", 26 | "city": "San Francisco", 27 | "state": "CA", 28 | "country": "United States", 29 | "postalCode": "94103", 30 | "lat": 37.7854, 31 | "lon": -122.4005 32 | } 33 | }, 34 | { 35 | "id": "3", 36 | "name": "Hotel Zetta", 37 | "phoneNumber": "(415) 543-8555", 38 | "description": "A 3-minute walk from the Powell Street cable-car turnaround and BART rail station, this hip hotel 9 minutes from Union Square combines high-tech lodging with artsy touches.", 39 | "address": { 40 | "streetNumber": "55", 41 | "streetName": "5th St", 42 | "city": "San Francisco", 43 | "state": "CA", 44 | "country": "United States", 45 | "postalCode": "94103", 46 | "lat": 37.7834, 47 | "lon": -122.4071 48 | } 49 | }, 50 | { 51 | "id": "4", 52 | "name": "Hotel Vitale", 53 | "phoneNumber": "(415) 278-3700", 54 | "description": "This waterfront hotel with Bay Bridge views is 3 blocks from the Financial District and a 4-minute walk from the Ferry Building.", 55 | "address": { 56 | "streetNumber": "8", 57 | "streetName": "Mission St", 58 | "city": "San Francisco", 59 | "state": "CA", 60 | "country": "United States", 61 | "postalCode": "94105", 62 | "lat": 37.7936, 63 | "lon": -122.3930 64 | } 65 | }, 66 | { 67 | "id": "5", 68 | "name": "Phoenix Hotel", 69 | "phoneNumber": "(415) 776-1380", 70 | "description": "Located in the Tenderloin neighborhood, a 10-minute walk from a BART rail station, this retro motor lodge has hosted many rock musicians and other celebrities since the 1950s. It’s a 4-minute walk from the historic Great American Music Hall nightclub.", 71 | "address": { 72 | "streetNumber": "601", 73 | "streetName": "Eddy St", 74 | "city": "San Francisco", 75 | "state": "CA", 76 | "country": "United States", 77 | "postalCode": "94109", 78 | "lat": 37.7831, 79 | "lon": -122.4181 80 | } 81 | }, 82 | { 83 | "id": "6", 84 | "name": "St. Regis San Francisco", 85 | "phoneNumber": "(415) 284-4000", 86 | "description": "St. Regis Museum Tower is a 42-story, 484 ft skyscraper in the South of Market district of San Francisco, California, adjacent to Yerba Buena Gardens, Moscone Center, PacBell Building and the San Francisco Museum of Modern Art.", 87 | "address": { 88 | "streetNumber": "125", 89 | "streetName": "3rd St", 90 | "city": "San Francisco", 91 | "state": "CA", 92 | "country": "United States", 93 | "postalCode": "94109", 94 | "lat": 37.7863, 95 | "lon": -122.4015 96 | } 97 | } 98 | ] 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang Microservices Example 2 | 3 | A demonstration of Golang micro-services that expose a HTTP/JSON frontend and then 4 | leverages [gRPC][1] for inter-service communication. 5 | 6 | 7 | websequence-diagram 8 | 9 | * Services written in Golang 10 | * gRPC for inter-service communication 11 | * Jaeger for request tracing 12 | 13 | The example application plots Hotel locations on a Google map: 14 | 15 | screen shot 2016-11-07 at 9 31 12 pm 16 | 17 | The web page makes an HTTP request to the API Endpoint which in turn spawns a number of RPC requests to the backend services. 18 | 19 | Data for each of the services is stored in JSON flat files under the `data/` directory. In reality each of the services could choose their own specialty datastore. The Geo service for example could use PostGis or any other database specializing in geospacial queries. 20 | 21 | ## Request Tracing 22 | 23 | The [Jaeger Tracing](https://github.com/jaegertracing/jaeger) project is used for tracing inter-service requests. The `tracing` package is used initialize a new service tracer: 24 | 25 | ```go 26 | tracer, err := tracing.Init("serviceName", jaegeraddr) 27 | if err != nil { 28 | fmt.Fprintf(os.Stderr, "%v\n", err) 29 | os.Exit(1) 30 | } 31 | ``` 32 | 33 | jaeger tracing example 34 | 35 | View dashboard: http://localhost:16686/search 36 | 37 | ## Installation 38 | 39 | ### Setup 40 | 41 | Docker is required for running the services https://docs.docker.com/engine/installation. 42 | 43 | Protobuf v3 are required: 44 | 45 | $ brew install protobuf 46 | 47 | Install the protoc-gen libraries: 48 | 49 | $ go get -u github.com/golang/protobuf/{proto,protoc-gen-go} 50 | 51 | Clone the repository: 52 | 53 | $ git clone git@github.com:harlow/go-micro-services.git 54 | 55 | ### Run 56 | 57 | To make the demo as straigforward as possible; [Docker Compose](https://docs.docker.com/compose/) is used to run all the services at once (In a production environment each of the services would be run (and scaled) independently). 58 | 59 | $ make run 60 | 61 | Vist the web page in a browser: 62 | 63 | [http://localhost:5000/](http://localhost:5000/) 64 | 65 | cURL the API endpoint and receive GeoJSON response: 66 | 67 | $ curl "http://localhost:5000/hotels?inDate=2015-04-09&outDate=2015-04-10" 68 | 69 | The JSON response: 70 | 71 | ```json 72 | { 73 | "type": "FeatureCollection", 74 | "features": [{ 75 | "id": "5", 76 | "type": "Feature", 77 | "properties": { 78 | "name": "Phoenix Hotel", 79 | "phone_number": "(415) 776-1380" 80 | }, 81 | "geometry": { 82 | "type": "Point", 83 | "coordinates": [-122.4181, 37.7831] 84 | } 85 | }, { 86 | "id": "3", 87 | "type": "Feature", 88 | "properties": { 89 | "name": "Hotel Zetta", 90 | "phone_number": "(415) 543-8555" 91 | }, 92 | "geometry": { 93 | "type": "Point", 94 | "coordinates": [-122.4071, 37.7834] 95 | } 96 | }] 97 | } 98 | ``` 99 | 100 | ### Protobufs 101 | 102 | If changes are made to the Protocol Buffer files use the Makefile to regenerate: 103 | 104 | $ make proto 105 | 106 | ## Credits 107 | 108 | Thanks to all the [contributors][6]. This codebase was heavily inspired by the following talks and repositories: 109 | 110 | * [Scaling microservices in Go][3] 111 | * [gRPC Example Service][4] 112 | * [go-kit][5] 113 | 114 | [1]: http://www.grpc.io/ 115 | [2]: https://github.com/docker/compose/issues/3560 116 | [3]: https://speakerdeck.com/mattheath/scaling-microservices-in-go-high-load-strategy-2015 117 | [4]: https://github.com/grpc/grpc-go/tree/master/examples/route_guide 118 | [5]: https://github.com/go-kit/kit 119 | [6]: https://github.com/harlow/go-micro-services/graphs/contributors 120 | 121 | > [www.hward.com](http://www.hward.com)  ·  122 | > GitHub [@harlow](https://github.com/harlow)  ·  123 | > Twitter [@comma_ok](https://twitter.com/comma_ok) 124 | -------------------------------------------------------------------------------- /internal/proto/geo/geo.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: services/geo/proto/geo.proto 3 | 4 | /* 5 | Package geo is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | services/geo/proto/geo.proto 9 | 10 | It has these top-level messages: 11 | Request 12 | Result 13 | */ 14 | package geo 15 | 16 | import proto "github.com/golang/protobuf/proto" 17 | import fmt "fmt" 18 | import math "math" 19 | 20 | import ( 21 | context "golang.org/x/net/context" 22 | grpc "google.golang.org/grpc" 23 | ) 24 | 25 | // Reference imports to suppress errors if they are not otherwise used. 26 | var _ = proto.Marshal 27 | var _ = fmt.Errorf 28 | var _ = math.Inf 29 | 30 | // This is a compile-time assertion to ensure that this generated file 31 | // is compatible with the proto package it is being compiled against. 32 | // A compilation error at this line likely means your copy of the 33 | // proto package needs to be updated. 34 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 35 | 36 | // The latitude and longitude of the current location. 37 | type Request struct { 38 | Lat float32 `protobuf:"fixed32,1,opt,name=lat" json:"lat,omitempty"` 39 | Lon float32 `protobuf:"fixed32,2,opt,name=lon" json:"lon,omitempty"` 40 | } 41 | 42 | func (m *Request) Reset() { *m = Request{} } 43 | func (m *Request) String() string { return proto.CompactTextString(m) } 44 | func (*Request) ProtoMessage() {} 45 | func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 46 | 47 | func (m *Request) GetLat() float32 { 48 | if m != nil { 49 | return m.Lat 50 | } 51 | return 0 52 | } 53 | 54 | func (m *Request) GetLon() float32 { 55 | if m != nil { 56 | return m.Lon 57 | } 58 | return 0 59 | } 60 | 61 | type Result struct { 62 | HotelIds []string `protobuf:"bytes,1,rep,name=hotelIds" json:"hotelIds,omitempty"` 63 | } 64 | 65 | func (m *Result) Reset() { *m = Result{} } 66 | func (m *Result) String() string { return proto.CompactTextString(m) } 67 | func (*Result) ProtoMessage() {} 68 | func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 69 | 70 | func (m *Result) GetHotelIds() []string { 71 | if m != nil { 72 | return m.HotelIds 73 | } 74 | return nil 75 | } 76 | 77 | func init() { 78 | proto.RegisterType((*Request)(nil), "geo.Request") 79 | proto.RegisterType((*Result)(nil), "geo.Result") 80 | } 81 | 82 | // Reference imports to suppress errors if they are not otherwise used. 83 | var _ context.Context 84 | var _ grpc.ClientConn 85 | 86 | // This is a compile-time assertion to ensure that this generated file 87 | // is compatible with the grpc package it is being compiled against. 88 | const _ = grpc.SupportPackageIsVersion4 89 | 90 | // Client API for Geo service 91 | 92 | type GeoClient interface { 93 | // Finds the hotels contained nearby the current lat/lon. 94 | Nearby(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) 95 | } 96 | 97 | type geoClient struct { 98 | cc *grpc.ClientConn 99 | } 100 | 101 | func NewGeoClient(cc *grpc.ClientConn) GeoClient { 102 | return &geoClient{cc} 103 | } 104 | 105 | func (c *geoClient) Nearby(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) { 106 | out := new(Result) 107 | err := grpc.Invoke(ctx, "/geo.Geo/Nearby", in, out, c.cc, opts...) 108 | if err != nil { 109 | return nil, err 110 | } 111 | return out, nil 112 | } 113 | 114 | // Server API for Geo service 115 | 116 | type GeoServer interface { 117 | // Finds the hotels contained nearby the current lat/lon. 118 | Nearby(context.Context, *Request) (*Result, error) 119 | } 120 | 121 | func RegisterGeoServer(s *grpc.Server, srv GeoServer) { 122 | s.RegisterService(&_Geo_serviceDesc, srv) 123 | } 124 | 125 | func _Geo_Nearby_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 126 | in := new(Request) 127 | if err := dec(in); err != nil { 128 | return nil, err 129 | } 130 | if interceptor == nil { 131 | return srv.(GeoServer).Nearby(ctx, in) 132 | } 133 | info := &grpc.UnaryServerInfo{ 134 | Server: srv, 135 | FullMethod: "/geo.Geo/Nearby", 136 | } 137 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 138 | return srv.(GeoServer).Nearby(ctx, req.(*Request)) 139 | } 140 | return interceptor(ctx, in, info, handler) 141 | } 142 | 143 | var _Geo_serviceDesc = grpc.ServiceDesc{ 144 | ServiceName: "geo.Geo", 145 | HandlerType: (*GeoServer)(nil), 146 | Methods: []grpc.MethodDesc{ 147 | { 148 | MethodName: "Nearby", 149 | Handler: _Geo_Nearby_Handler, 150 | }, 151 | }, 152 | Streams: []grpc.StreamDesc{}, 153 | Metadata: "services/geo/proto/geo.proto", 154 | } 155 | 156 | func init() { proto.RegisterFile("services/geo/proto/geo.proto", fileDescriptor0) } 157 | 158 | var fileDescriptor0 = []byte{ 159 | // 156 bytes of a gzipped FileDescriptorProto 160 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x29, 0x4e, 0x2d, 0x2a, 161 | 0xcb, 0x4c, 0x4e, 0x2d, 0xd6, 0x4f, 0x4f, 0xcd, 0xd7, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x07, 0xb1, 162 | 0xf4, 0xc0, 0x2c, 0x21, 0xe6, 0xf4, 0xd4, 0x7c, 0x25, 0x5d, 0x2e, 0xf6, 0xa0, 0xd4, 0xc2, 0xd2, 163 | 0xd4, 0xe2, 0x12, 0x21, 0x01, 0x2e, 0xe6, 0x9c, 0xc4, 0x12, 0x09, 0x46, 0x05, 0x46, 0x0d, 0xa6, 164 | 0x20, 0x10, 0x13, 0x2c, 0x92, 0x9f, 0x27, 0xc1, 0x04, 0x15, 0xc9, 0xcf, 0x53, 0x52, 0xe1, 0x62, 165 | 0x0b, 0x4a, 0x2d, 0x2e, 0xcd, 0x29, 0x11, 0x92, 0xe2, 0xe2, 0xc8, 0xc8, 0x2f, 0x49, 0xcd, 0xf1, 166 | 0x4c, 0x29, 0x96, 0x60, 0x54, 0x60, 0xd6, 0xe0, 0x0c, 0x82, 0xf3, 0x8d, 0xb4, 0xb8, 0x98, 0xdd, 167 | 0x53, 0xf3, 0x85, 0x94, 0xb9, 0xd8, 0xfc, 0x52, 0x13, 0x8b, 0x92, 0x2a, 0x85, 0x78, 0xf4, 0x40, 168 | 0xd6, 0x42, 0x2d, 0x92, 0xe2, 0x86, 0xf2, 0x40, 0xe6, 0x24, 0xb1, 0x81, 0x1d, 0x63, 0x0c, 0x08, 169 | 0x00, 0x00, 0xff, 0xff, 0x1f, 0x18, 0x14, 0xc4, 0xac, 0x00, 0x00, 0x00, 170 | } 171 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7 h1:Fv9bK1Q+ly/ROk4aJsVMeuIwPel4bEnD8EPiI91nZMg= 2 | github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= 3 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= 4 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 5 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= 6 | github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= 7 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 9 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 11 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 12 | github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= 13 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 14 | github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20171214222146-0e7658f8ee99 h1:bTRV2bQrg85E7ZeeyQfHX3GyfidLrNzVoyq7epx0bTw= 15 | github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20171214222146-0e7658f8ee99/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= 16 | github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711 h1:Oi8hPOZX0gaM2sPVXse2bMpfOjP47a7O61YuB6Z4sGk= 17 | github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711/go.mod h1:+v2qJ3UZe4q2GfgZO4od004F/cMgJbmPSs7dD/ZMUkY= 18 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 19 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 20 | github.com/opentracing-contrib/go-stdlib v0.0.0-20180308002341-f6b9967a3c69 h1:xwxJZjgtaEhkTCXKdcV9+ZSIUox2tcv0a5oYzy6p4zE= 21 | github.com/opentracing-contrib/go-stdlib v0.0.0-20180308002341-f6b9967a3c69/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w= 22 | github.com/opentracing/opentracing-go v1.0.2 h1:3jA2P6O1F9UOrWVpwrIo17pu01KWvNWg4X946/Y5Zwg= 23 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 24 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 25 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 26 | github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= 27 | github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= 28 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= 29 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 30 | github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= 31 | github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 32 | github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= 33 | github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 34 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 35 | github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= 36 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 37 | github.com/uber-go/atomic v1.4.0 h1:yOuPqEq4ovnhEjpHmfFwsqBXDYbQeT6Nb0bwD6XnD5o= 38 | github.com/uber-go/atomic v1.4.0/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= 39 | github.com/uber/jaeger-client-go v2.11.2+incompatible h1:D2idO5gYBl+40qnsowJaqtwCV6z1rxYy2yhYBh3mVvI= 40 | github.com/uber/jaeger-client-go v2.11.2+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= 41 | github.com/uber/jaeger-lib v1.4.0 h1:FiI99eCazm7u6tdv4Z+9sBXNrC9sHz43kfKIJaCDqCE= 42 | github.com/uber/jaeger-lib v1.4.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= 43 | go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= 44 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 45 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 46 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0= 47 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 48 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= 49 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 50 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 51 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= 52 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 53 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 54 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 55 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 56 | google.golang.org/genproto v0.0.0-20180306020942-df60624c1e9b h1:XeiFoG4FHSBJUL3qKCkMrkwBFRXB+hyQiTPg82JUssI= 57 | google.golang.org/genproto v0.0.0-20180306020942-df60624c1e9b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 58 | google.golang.org/grpc v1.10.0 h1:C9kRCw/lM10n+54FLMKvGRJbhvJ0+7ipOUuWpLS9xIA= 59 | google.golang.org/grpc v1.10.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 60 | -------------------------------------------------------------------------------- /internal/proto/search/search.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: services/search/proto/search.proto 3 | 4 | /* 5 | Package search is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | services/search/proto/search.proto 9 | 10 | It has these top-level messages: 11 | NearbyRequest 12 | SearchResult 13 | */ 14 | package search 15 | 16 | import proto "github.com/golang/protobuf/proto" 17 | import fmt "fmt" 18 | import math "math" 19 | 20 | import ( 21 | context "golang.org/x/net/context" 22 | grpc "google.golang.org/grpc" 23 | ) 24 | 25 | // Reference imports to suppress errors if they are not otherwise used. 26 | var _ = proto.Marshal 27 | var _ = fmt.Errorf 28 | var _ = math.Inf 29 | 30 | // This is a compile-time assertion to ensure that this generated file 31 | // is compatible with the proto package it is being compiled against. 32 | // A compilation error at this line likely means your copy of the 33 | // proto package needs to be updated. 34 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 35 | 36 | type NearbyRequest struct { 37 | Lat float32 `protobuf:"fixed32,1,opt,name=lat" json:"lat,omitempty"` 38 | Lon float32 `protobuf:"fixed32,2,opt,name=lon" json:"lon,omitempty"` 39 | InDate string `protobuf:"bytes,3,opt,name=inDate" json:"inDate,omitempty"` 40 | OutDate string `protobuf:"bytes,4,opt,name=outDate" json:"outDate,omitempty"` 41 | } 42 | 43 | func (m *NearbyRequest) Reset() { *m = NearbyRequest{} } 44 | func (m *NearbyRequest) String() string { return proto.CompactTextString(m) } 45 | func (*NearbyRequest) ProtoMessage() {} 46 | func (*NearbyRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 47 | 48 | func (m *NearbyRequest) GetLat() float32 { 49 | if m != nil { 50 | return m.Lat 51 | } 52 | return 0 53 | } 54 | 55 | func (m *NearbyRequest) GetLon() float32 { 56 | if m != nil { 57 | return m.Lon 58 | } 59 | return 0 60 | } 61 | 62 | func (m *NearbyRequest) GetInDate() string { 63 | if m != nil { 64 | return m.InDate 65 | } 66 | return "" 67 | } 68 | 69 | func (m *NearbyRequest) GetOutDate() string { 70 | if m != nil { 71 | return m.OutDate 72 | } 73 | return "" 74 | } 75 | 76 | type SearchResult struct { 77 | HotelIds []string `protobuf:"bytes,1,rep,name=hotelIds" json:"hotelIds,omitempty"` 78 | } 79 | 80 | func (m *SearchResult) Reset() { *m = SearchResult{} } 81 | func (m *SearchResult) String() string { return proto.CompactTextString(m) } 82 | func (*SearchResult) ProtoMessage() {} 83 | func (*SearchResult) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 84 | 85 | func (m *SearchResult) GetHotelIds() []string { 86 | if m != nil { 87 | return m.HotelIds 88 | } 89 | return nil 90 | } 91 | 92 | func init() { 93 | proto.RegisterType((*NearbyRequest)(nil), "search.NearbyRequest") 94 | proto.RegisterType((*SearchResult)(nil), "search.SearchResult") 95 | } 96 | 97 | // Reference imports to suppress errors if they are not otherwise used. 98 | var _ context.Context 99 | var _ grpc.ClientConn 100 | 101 | // This is a compile-time assertion to ensure that this generated file 102 | // is compatible with the grpc package it is being compiled against. 103 | const _ = grpc.SupportPackageIsVersion4 104 | 105 | // Client API for Search service 106 | 107 | type SearchClient interface { 108 | Nearby(ctx context.Context, in *NearbyRequest, opts ...grpc.CallOption) (*SearchResult, error) 109 | } 110 | 111 | type searchClient struct { 112 | cc *grpc.ClientConn 113 | } 114 | 115 | func NewSearchClient(cc *grpc.ClientConn) SearchClient { 116 | return &searchClient{cc} 117 | } 118 | 119 | func (c *searchClient) Nearby(ctx context.Context, in *NearbyRequest, opts ...grpc.CallOption) (*SearchResult, error) { 120 | out := new(SearchResult) 121 | err := grpc.Invoke(ctx, "/search.Search/Nearby", in, out, c.cc, opts...) 122 | if err != nil { 123 | return nil, err 124 | } 125 | return out, nil 126 | } 127 | 128 | // Server API for Search service 129 | 130 | type SearchServer interface { 131 | Nearby(context.Context, *NearbyRequest) (*SearchResult, error) 132 | } 133 | 134 | func RegisterSearchServer(s *grpc.Server, srv SearchServer) { 135 | s.RegisterService(&_Search_serviceDesc, srv) 136 | } 137 | 138 | func _Search_Nearby_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 139 | in := new(NearbyRequest) 140 | if err := dec(in); err != nil { 141 | return nil, err 142 | } 143 | if interceptor == nil { 144 | return srv.(SearchServer).Nearby(ctx, in) 145 | } 146 | info := &grpc.UnaryServerInfo{ 147 | Server: srv, 148 | FullMethod: "/search.Search/Nearby", 149 | } 150 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 151 | return srv.(SearchServer).Nearby(ctx, req.(*NearbyRequest)) 152 | } 153 | return interceptor(ctx, in, info, handler) 154 | } 155 | 156 | var _Search_serviceDesc = grpc.ServiceDesc{ 157 | ServiceName: "search.Search", 158 | HandlerType: (*SearchServer)(nil), 159 | Methods: []grpc.MethodDesc{ 160 | { 161 | MethodName: "Nearby", 162 | Handler: _Search_Nearby_Handler, 163 | }, 164 | }, 165 | Streams: []grpc.StreamDesc{}, 166 | Metadata: "services/search/proto/search.proto", 167 | } 168 | 169 | func init() { proto.RegisterFile("services/search/proto/search.proto", fileDescriptor0) } 170 | 171 | var fileDescriptor0 = []byte{ 172 | // 193 bytes of a gzipped FileDescriptorProto 173 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x8f, 0xb1, 0x0a, 0xc2, 0x30, 174 | 0x10, 0x86, 0x49, 0x2b, 0xd1, 0x1e, 0x0a, 0x12, 0x54, 0x42, 0xa7, 0xd2, 0xa9, 0x38, 0xb4, 0xa0, 175 | 0x38, 0xbb, 0xb8, 0xb8, 0x38, 0xc4, 0x27, 0x48, 0xeb, 0x41, 0x0b, 0xa5, 0xd1, 0x24, 0x15, 0x7c, 176 | 0x7b, 0x31, 0x4d, 0x45, 0xb7, 0x7c, 0xff, 0x1f, 0xee, 0xbe, 0x83, 0xd4, 0xa0, 0x7e, 0x36, 0x15, 177 | 0x9a, 0xc2, 0xa0, 0xd4, 0x55, 0x5d, 0xdc, 0xb5, 0xb2, 0xca, 0x43, 0xee, 0x80, 0xd1, 0x81, 0x52, 178 | 0x84, 0xc5, 0x05, 0xa5, 0x2e, 0x5f, 0x02, 0x1f, 0x3d, 0x1a, 0xcb, 0x96, 0x10, 0xb6, 0xd2, 0x72, 179 | 0x92, 0x90, 0x2c, 0x10, 0x9f, 0xa7, 0x4b, 0x54, 0xc7, 0x03, 0x9f, 0xa8, 0x8e, 0x6d, 0x80, 0x36, 180 | 0xdd, 0x49, 0x5a, 0xe4, 0x61, 0x42, 0xb2, 0x48, 0x78, 0x62, 0x1c, 0xa6, 0xaa, 0xb7, 0xae, 0x98, 181 | 0xb8, 0x62, 0xc4, 0x74, 0x0b, 0xf3, 0xab, 0x5b, 0x28, 0xd0, 0xf4, 0xad, 0x65, 0x31, 0xcc, 0x6a, 182 | 0x65, 0xb1, 0x3d, 0xdf, 0x0c, 0x27, 0x49, 0x98, 0x45, 0xe2, 0xcb, 0xbb, 0x23, 0xd0, 0xe1, 0x2f, 183 | 0x3b, 0x00, 0x1d, 0xe4, 0xd8, 0x3a, 0xf7, 0xf6, 0x7f, 0xb2, 0xf1, 0x6a, 0x8c, 0x7f, 0x87, 0x97, 184 | 0xd4, 0x9d, 0xb8, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x55, 0xd9, 0x68, 0x1c, 0x08, 0x01, 0x00, 185 | 0x00, 186 | } 187 | -------------------------------------------------------------------------------- /internal/proto/rate/rate.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: services/rate/proto/rate.proto 3 | 4 | /* 5 | Package rate is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | services/rate/proto/rate.proto 9 | 10 | It has these top-level messages: 11 | Request 12 | Result 13 | RatePlan 14 | RoomType 15 | */ 16 | package rate 17 | 18 | import proto "github.com/golang/protobuf/proto" 19 | import fmt "fmt" 20 | import math "math" 21 | 22 | import ( 23 | context "golang.org/x/net/context" 24 | grpc "google.golang.org/grpc" 25 | ) 26 | 27 | // Reference imports to suppress errors if they are not otherwise used. 28 | var _ = proto.Marshal 29 | var _ = fmt.Errorf 30 | var _ = math.Inf 31 | 32 | // This is a compile-time assertion to ensure that this generated file 33 | // is compatible with the proto package it is being compiled against. 34 | // A compilation error at this line likely means your copy of the 35 | // proto package needs to be updated. 36 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 37 | 38 | type Request struct { 39 | HotelIds []string `protobuf:"bytes,1,rep,name=hotelIds" json:"hotelIds,omitempty"` 40 | InDate string `protobuf:"bytes,2,opt,name=inDate" json:"inDate,omitempty"` 41 | OutDate string `protobuf:"bytes,3,opt,name=outDate" json:"outDate,omitempty"` 42 | } 43 | 44 | func (m *Request) Reset() { *m = Request{} } 45 | func (m *Request) String() string { return proto.CompactTextString(m) } 46 | func (*Request) ProtoMessage() {} 47 | func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 48 | 49 | func (m *Request) GetHotelIds() []string { 50 | if m != nil { 51 | return m.HotelIds 52 | } 53 | return nil 54 | } 55 | 56 | func (m *Request) GetInDate() string { 57 | if m != nil { 58 | return m.InDate 59 | } 60 | return "" 61 | } 62 | 63 | func (m *Request) GetOutDate() string { 64 | if m != nil { 65 | return m.OutDate 66 | } 67 | return "" 68 | } 69 | 70 | type Result struct { 71 | RatePlans []*RatePlan `protobuf:"bytes,1,rep,name=ratePlans" json:"ratePlans,omitempty"` 72 | } 73 | 74 | func (m *Result) Reset() { *m = Result{} } 75 | func (m *Result) String() string { return proto.CompactTextString(m) } 76 | func (*Result) ProtoMessage() {} 77 | func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 78 | 79 | func (m *Result) GetRatePlans() []*RatePlan { 80 | if m != nil { 81 | return m.RatePlans 82 | } 83 | return nil 84 | } 85 | 86 | type RatePlan struct { 87 | HotelId string `protobuf:"bytes,1,opt,name=hotelId" json:"hotelId,omitempty"` 88 | Code string `protobuf:"bytes,2,opt,name=code" json:"code,omitempty"` 89 | InDate string `protobuf:"bytes,3,opt,name=inDate" json:"inDate,omitempty"` 90 | OutDate string `protobuf:"bytes,4,opt,name=outDate" json:"outDate,omitempty"` 91 | RoomType *RoomType `protobuf:"bytes,5,opt,name=roomType" json:"roomType,omitempty"` 92 | } 93 | 94 | func (m *RatePlan) Reset() { *m = RatePlan{} } 95 | func (m *RatePlan) String() string { return proto.CompactTextString(m) } 96 | func (*RatePlan) ProtoMessage() {} 97 | func (*RatePlan) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } 98 | 99 | func (m *RatePlan) GetHotelId() string { 100 | if m != nil { 101 | return m.HotelId 102 | } 103 | return "" 104 | } 105 | 106 | func (m *RatePlan) GetCode() string { 107 | if m != nil { 108 | return m.Code 109 | } 110 | return "" 111 | } 112 | 113 | func (m *RatePlan) GetInDate() string { 114 | if m != nil { 115 | return m.InDate 116 | } 117 | return "" 118 | } 119 | 120 | func (m *RatePlan) GetOutDate() string { 121 | if m != nil { 122 | return m.OutDate 123 | } 124 | return "" 125 | } 126 | 127 | func (m *RatePlan) GetRoomType() *RoomType { 128 | if m != nil { 129 | return m.RoomType 130 | } 131 | return nil 132 | } 133 | 134 | type RoomType struct { 135 | BookableRate float64 `protobuf:"fixed64,1,opt,name=bookableRate" json:"bookableRate,omitempty"` 136 | TotalRate float64 `protobuf:"fixed64,2,opt,name=totalRate" json:"totalRate,omitempty"` 137 | TotalRateInclusive float64 `protobuf:"fixed64,3,opt,name=totalRateInclusive" json:"totalRateInclusive,omitempty"` 138 | Code string `protobuf:"bytes,4,opt,name=code" json:"code,omitempty"` 139 | Currency string `protobuf:"bytes,5,opt,name=currency" json:"currency,omitempty"` 140 | RoomDescription string `protobuf:"bytes,6,opt,name=roomDescription" json:"roomDescription,omitempty"` 141 | } 142 | 143 | func (m *RoomType) Reset() { *m = RoomType{} } 144 | func (m *RoomType) String() string { return proto.CompactTextString(m) } 145 | func (*RoomType) ProtoMessage() {} 146 | func (*RoomType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } 147 | 148 | func (m *RoomType) GetBookableRate() float64 { 149 | if m != nil { 150 | return m.BookableRate 151 | } 152 | return 0 153 | } 154 | 155 | func (m *RoomType) GetTotalRate() float64 { 156 | if m != nil { 157 | return m.TotalRate 158 | } 159 | return 0 160 | } 161 | 162 | func (m *RoomType) GetTotalRateInclusive() float64 { 163 | if m != nil { 164 | return m.TotalRateInclusive 165 | } 166 | return 0 167 | } 168 | 169 | func (m *RoomType) GetCode() string { 170 | if m != nil { 171 | return m.Code 172 | } 173 | return "" 174 | } 175 | 176 | func (m *RoomType) GetCurrency() string { 177 | if m != nil { 178 | return m.Currency 179 | } 180 | return "" 181 | } 182 | 183 | func (m *RoomType) GetRoomDescription() string { 184 | if m != nil { 185 | return m.RoomDescription 186 | } 187 | return "" 188 | } 189 | 190 | func init() { 191 | proto.RegisterType((*Request)(nil), "rate.Request") 192 | proto.RegisterType((*Result)(nil), "rate.Result") 193 | proto.RegisterType((*RatePlan)(nil), "rate.RatePlan") 194 | proto.RegisterType((*RoomType)(nil), "rate.RoomType") 195 | } 196 | 197 | // Reference imports to suppress errors if they are not otherwise used. 198 | var _ context.Context 199 | var _ grpc.ClientConn 200 | 201 | // This is a compile-time assertion to ensure that this generated file 202 | // is compatible with the grpc package it is being compiled against. 203 | const _ = grpc.SupportPackageIsVersion4 204 | 205 | // Client API for Rate service 206 | 207 | type RateClient interface { 208 | // GetRates returns rate codes for hotels for a given date range 209 | GetRates(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) 210 | } 211 | 212 | type rateClient struct { 213 | cc *grpc.ClientConn 214 | } 215 | 216 | func NewRateClient(cc *grpc.ClientConn) RateClient { 217 | return &rateClient{cc} 218 | } 219 | 220 | func (c *rateClient) GetRates(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) { 221 | out := new(Result) 222 | err := grpc.Invoke(ctx, "/rate.Rate/GetRates", in, out, c.cc, opts...) 223 | if err != nil { 224 | return nil, err 225 | } 226 | return out, nil 227 | } 228 | 229 | // Server API for Rate service 230 | 231 | type RateServer interface { 232 | // GetRates returns rate codes for hotels for a given date range 233 | GetRates(context.Context, *Request) (*Result, error) 234 | } 235 | 236 | func RegisterRateServer(s *grpc.Server, srv RateServer) { 237 | s.RegisterService(&_Rate_serviceDesc, srv) 238 | } 239 | 240 | func _Rate_GetRates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 241 | in := new(Request) 242 | if err := dec(in); err != nil { 243 | return nil, err 244 | } 245 | if interceptor == nil { 246 | return srv.(RateServer).GetRates(ctx, in) 247 | } 248 | info := &grpc.UnaryServerInfo{ 249 | Server: srv, 250 | FullMethod: "/rate.Rate/GetRates", 251 | } 252 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 253 | return srv.(RateServer).GetRates(ctx, req.(*Request)) 254 | } 255 | return interceptor(ctx, in, info, handler) 256 | } 257 | 258 | var _Rate_serviceDesc = grpc.ServiceDesc{ 259 | ServiceName: "rate.Rate", 260 | HandlerType: (*RateServer)(nil), 261 | Methods: []grpc.MethodDesc{ 262 | { 263 | MethodName: "GetRates", 264 | Handler: _Rate_GetRates_Handler, 265 | }, 266 | }, 267 | Streams: []grpc.StreamDesc{}, 268 | Metadata: "services/rate/proto/rate.proto", 269 | } 270 | 271 | func init() { proto.RegisterFile("services/rate/proto/rate.proto", fileDescriptor0) } 272 | 273 | var fileDescriptor0 = []byte{ 274 | // 327 bytes of a gzipped FileDescriptorProto 275 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xdd, 0x4a, 0xc3, 0x30, 276 | 0x14, 0xc7, 0x89, 0xab, 0x5d, 0x7b, 0x9c, 0x0a, 0xe7, 0x42, 0xca, 0x10, 0x19, 0xbd, 0x71, 0x88, 277 | 0x6c, 0x30, 0xc1, 0x27, 0x18, 0xc8, 0xee, 0xe4, 0x20, 0x78, 0xdd, 0x75, 0x07, 0x2c, 0xd6, 0x66, 278 | 0x26, 0xe9, 0x60, 0x2f, 0xe2, 0xa3, 0xf9, 0x3c, 0x92, 0x34, 0xed, 0x3a, 0xd1, 0xbb, 0xff, 0x47, 279 | 0x38, 0xfd, 0x25, 0x3d, 0x70, 0xa3, 0x59, 0xed, 0x8a, 0x9c, 0xf5, 0x5c, 0x65, 0x86, 0xe7, 0x5b, 280 | 0x25, 0x8d, 0x74, 0x72, 0xe6, 0x24, 0x06, 0x56, 0xa7, 0xaf, 0x30, 0x24, 0xfe, 0xac, 0x59, 0x1b, 281 | 0x1c, 0x43, 0xf4, 0x26, 0x0d, 0x97, 0xab, 0x8d, 0x4e, 0xc4, 0x64, 0x30, 0x8d, 0xa9, 0xf3, 0x78, 282 | 0x05, 0x61, 0x51, 0x2d, 0x33, 0xc3, 0xc9, 0xc9, 0x44, 0x4c, 0x63, 0xf2, 0x0e, 0x13, 0x18, 0xca, 283 | 0xda, 0xb8, 0x62, 0xe0, 0x8a, 0xd6, 0xa6, 0x8f, 0x10, 0x12, 0xeb, 0xba, 0x34, 0x78, 0x0f, 0xb1, 284 | 0xfd, 0xd4, 0x73, 0x99, 0x55, 0xcd, 0xe0, 0xb3, 0xc5, 0xc5, 0xcc, 0x81, 0x90, 0x8f, 0xe9, 0x70, 285 | 0x20, 0xfd, 0x12, 0x10, 0xb5, 0xb9, 0x1d, 0xef, 0x11, 0x12, 0xd1, 0x8c, 0xf7, 0x16, 0x11, 0x82, 286 | 0x5c, 0x6e, 0x5a, 0x1c, 0xa7, 0x7b, 0x90, 0x83, 0xff, 0x20, 0x83, 0x23, 0x48, 0xbc, 0x83, 0x48, 287 | 0x49, 0xf9, 0xf1, 0xb2, 0xdf, 0x72, 0x72, 0x3a, 0x11, 0x3d, 0x32, 0x9f, 0x52, 0xd7, 0xa7, 0xdf, 288 | 0x16, 0xcc, 0x1b, 0x4c, 0x61, 0xb4, 0x96, 0xf2, 0x3d, 0x5b, 0x97, 0x6c, 0x61, 0x1d, 0x9d, 0xa0, 289 | 0xa3, 0x0c, 0xaf, 0x21, 0x36, 0xd2, 0x64, 0x25, 0xb5, 0xcf, 0x26, 0xe8, 0x10, 0xe0, 0x0c, 0xb0, 290 | 0x33, 0xab, 0x2a, 0x2f, 0x6b, 0x5d, 0xec, 0x1a, 0x70, 0x41, 0x7f, 0x34, 0xdd, 0x85, 0x83, 0xde, 291 | 0x85, 0xc7, 0x10, 0xe5, 0xb5, 0x52, 0x5c, 0xe5, 0x7b, 0x87, 0x1f, 0x53, 0xe7, 0x71, 0x0a, 0x97, 292 | 0x16, 0x7d, 0xc9, 0x3a, 0x57, 0xc5, 0xd6, 0x14, 0xb2, 0x4a, 0x42, 0x77, 0xe4, 0x77, 0xbc, 0x98, 293 | 0x43, 0xe0, 0x88, 0x6e, 0x21, 0x7a, 0x62, 0x63, 0xa5, 0xc6, 0x73, 0xff, 0x0c, 0xcd, 0x6a, 0x8c, 294 | 0x47, 0xad, 0xb5, 0x3f, 0x74, 0x1d, 0xba, 0x05, 0x7a, 0xf8, 0x09, 0x00, 0x00, 0xff, 0xff, 0x71, 295 | 0x7f, 0xc7, 0x74, 0x62, 0x02, 0x00, 0x00, 296 | } 297 | -------------------------------------------------------------------------------- /internal/proto/profile/profile.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: services/profile/proto/profile.proto 3 | 4 | /* 5 | Package profile is a generated protocol buffer package. 6 | 7 | It is generated from these files: 8 | services/profile/proto/profile.proto 9 | 10 | It has these top-level messages: 11 | Request 12 | Result 13 | Hotel 14 | Address 15 | Image 16 | */ 17 | package profile 18 | 19 | import proto "github.com/golang/protobuf/proto" 20 | import fmt "fmt" 21 | import math "math" 22 | 23 | import ( 24 | context "golang.org/x/net/context" 25 | grpc "google.golang.org/grpc" 26 | ) 27 | 28 | // Reference imports to suppress errors if they are not otherwise used. 29 | var _ = proto.Marshal 30 | var _ = fmt.Errorf 31 | var _ = math.Inf 32 | 33 | // This is a compile-time assertion to ensure that this generated file 34 | // is compatible with the proto package it is being compiled against. 35 | // A compilation error at this line likely means your copy of the 36 | // proto package needs to be updated. 37 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 38 | 39 | type Request struct { 40 | HotelIds []string `protobuf:"bytes,1,rep,name=hotelIds" json:"hotelIds,omitempty"` 41 | Locale string `protobuf:"bytes,2,opt,name=locale" json:"locale,omitempty"` 42 | } 43 | 44 | func (m *Request) Reset() { *m = Request{} } 45 | func (m *Request) String() string { return proto.CompactTextString(m) } 46 | func (*Request) ProtoMessage() {} 47 | func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } 48 | 49 | func (m *Request) GetHotelIds() []string { 50 | if m != nil { 51 | return m.HotelIds 52 | } 53 | return nil 54 | } 55 | 56 | func (m *Request) GetLocale() string { 57 | if m != nil { 58 | return m.Locale 59 | } 60 | return "" 61 | } 62 | 63 | type Result struct { 64 | Hotels []*Hotel `protobuf:"bytes,1,rep,name=hotels" json:"hotels,omitempty"` 65 | } 66 | 67 | func (m *Result) Reset() { *m = Result{} } 68 | func (m *Result) String() string { return proto.CompactTextString(m) } 69 | func (*Result) ProtoMessage() {} 70 | func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } 71 | 72 | func (m *Result) GetHotels() []*Hotel { 73 | if m != nil { 74 | return m.Hotels 75 | } 76 | return nil 77 | } 78 | 79 | type Hotel struct { 80 | Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"` 81 | Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` 82 | PhoneNumber string `protobuf:"bytes,3,opt,name=phoneNumber" json:"phoneNumber,omitempty"` 83 | Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` 84 | Address *Address `protobuf:"bytes,5,opt,name=address" json:"address,omitempty"` 85 | Images []*Image `protobuf:"bytes,6,rep,name=images" json:"images,omitempty"` 86 | } 87 | 88 | func (m *Hotel) Reset() { *m = Hotel{} } 89 | func (m *Hotel) String() string { return proto.CompactTextString(m) } 90 | func (*Hotel) ProtoMessage() {} 91 | func (*Hotel) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } 92 | 93 | func (m *Hotel) GetId() string { 94 | if m != nil { 95 | return m.Id 96 | } 97 | return "" 98 | } 99 | 100 | func (m *Hotel) GetName() string { 101 | if m != nil { 102 | return m.Name 103 | } 104 | return "" 105 | } 106 | 107 | func (m *Hotel) GetPhoneNumber() string { 108 | if m != nil { 109 | return m.PhoneNumber 110 | } 111 | return "" 112 | } 113 | 114 | func (m *Hotel) GetDescription() string { 115 | if m != nil { 116 | return m.Description 117 | } 118 | return "" 119 | } 120 | 121 | func (m *Hotel) GetAddress() *Address { 122 | if m != nil { 123 | return m.Address 124 | } 125 | return nil 126 | } 127 | 128 | func (m *Hotel) GetImages() []*Image { 129 | if m != nil { 130 | return m.Images 131 | } 132 | return nil 133 | } 134 | 135 | type Address struct { 136 | StreetNumber string `protobuf:"bytes,1,opt,name=streetNumber" json:"streetNumber,omitempty"` 137 | StreetName string `protobuf:"bytes,2,opt,name=streetName" json:"streetName,omitempty"` 138 | City string `protobuf:"bytes,3,opt,name=city" json:"city,omitempty"` 139 | State string `protobuf:"bytes,4,opt,name=state" json:"state,omitempty"` 140 | Country string `protobuf:"bytes,5,opt,name=country" json:"country,omitempty"` 141 | PostalCode string `protobuf:"bytes,6,opt,name=postalCode" json:"postalCode,omitempty"` 142 | Lat float32 `protobuf:"fixed32,7,opt,name=lat" json:"lat,omitempty"` 143 | Lon float32 `protobuf:"fixed32,8,opt,name=lon" json:"lon,omitempty"` 144 | } 145 | 146 | func (m *Address) Reset() { *m = Address{} } 147 | func (m *Address) String() string { return proto.CompactTextString(m) } 148 | func (*Address) ProtoMessage() {} 149 | func (*Address) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } 150 | 151 | func (m *Address) GetStreetNumber() string { 152 | if m != nil { 153 | return m.StreetNumber 154 | } 155 | return "" 156 | } 157 | 158 | func (m *Address) GetStreetName() string { 159 | if m != nil { 160 | return m.StreetName 161 | } 162 | return "" 163 | } 164 | 165 | func (m *Address) GetCity() string { 166 | if m != nil { 167 | return m.City 168 | } 169 | return "" 170 | } 171 | 172 | func (m *Address) GetState() string { 173 | if m != nil { 174 | return m.State 175 | } 176 | return "" 177 | } 178 | 179 | func (m *Address) GetCountry() string { 180 | if m != nil { 181 | return m.Country 182 | } 183 | return "" 184 | } 185 | 186 | func (m *Address) GetPostalCode() string { 187 | if m != nil { 188 | return m.PostalCode 189 | } 190 | return "" 191 | } 192 | 193 | func (m *Address) GetLat() float32 { 194 | if m != nil { 195 | return m.Lat 196 | } 197 | return 0 198 | } 199 | 200 | func (m *Address) GetLon() float32 { 201 | if m != nil { 202 | return m.Lon 203 | } 204 | return 0 205 | } 206 | 207 | type Image struct { 208 | Url string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"` 209 | Default bool `protobuf:"varint,2,opt,name=default" json:"default,omitempty"` 210 | } 211 | 212 | func (m *Image) Reset() { *m = Image{} } 213 | func (m *Image) String() string { return proto.CompactTextString(m) } 214 | func (*Image) ProtoMessage() {} 215 | func (*Image) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } 216 | 217 | func (m *Image) GetUrl() string { 218 | if m != nil { 219 | return m.Url 220 | } 221 | return "" 222 | } 223 | 224 | func (m *Image) GetDefault() bool { 225 | if m != nil { 226 | return m.Default 227 | } 228 | return false 229 | } 230 | 231 | func init() { 232 | proto.RegisterType((*Request)(nil), "profile.Request") 233 | proto.RegisterType((*Result)(nil), "profile.Result") 234 | proto.RegisterType((*Hotel)(nil), "profile.Hotel") 235 | proto.RegisterType((*Address)(nil), "profile.Address") 236 | proto.RegisterType((*Image)(nil), "profile.Image") 237 | } 238 | 239 | // Reference imports to suppress errors if they are not otherwise used. 240 | var _ context.Context 241 | var _ grpc.ClientConn 242 | 243 | // This is a compile-time assertion to ensure that this generated file 244 | // is compatible with the grpc package it is being compiled against. 245 | const _ = grpc.SupportPackageIsVersion4 246 | 247 | // Client API for Profile service 248 | 249 | type ProfileClient interface { 250 | GetProfiles(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) 251 | } 252 | 253 | type profileClient struct { 254 | cc *grpc.ClientConn 255 | } 256 | 257 | func NewProfileClient(cc *grpc.ClientConn) ProfileClient { 258 | return &profileClient{cc} 259 | } 260 | 261 | func (c *profileClient) GetProfiles(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) { 262 | out := new(Result) 263 | err := grpc.Invoke(ctx, "/profile.Profile/GetProfiles", in, out, c.cc, opts...) 264 | if err != nil { 265 | return nil, err 266 | } 267 | return out, nil 268 | } 269 | 270 | // Server API for Profile service 271 | 272 | type ProfileServer interface { 273 | GetProfiles(context.Context, *Request) (*Result, error) 274 | } 275 | 276 | func RegisterProfileServer(s *grpc.Server, srv ProfileServer) { 277 | s.RegisterService(&_Profile_serviceDesc, srv) 278 | } 279 | 280 | func _Profile_GetProfiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 281 | in := new(Request) 282 | if err := dec(in); err != nil { 283 | return nil, err 284 | } 285 | if interceptor == nil { 286 | return srv.(ProfileServer).GetProfiles(ctx, in) 287 | } 288 | info := &grpc.UnaryServerInfo{ 289 | Server: srv, 290 | FullMethod: "/profile.Profile/GetProfiles", 291 | } 292 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 293 | return srv.(ProfileServer).GetProfiles(ctx, req.(*Request)) 294 | } 295 | return interceptor(ctx, in, info, handler) 296 | } 297 | 298 | var _Profile_serviceDesc = grpc.ServiceDesc{ 299 | ServiceName: "profile.Profile", 300 | HandlerType: (*ProfileServer)(nil), 301 | Methods: []grpc.MethodDesc{ 302 | { 303 | MethodName: "GetProfiles", 304 | Handler: _Profile_GetProfiles_Handler, 305 | }, 306 | }, 307 | Streams: []grpc.StreamDesc{}, 308 | Metadata: "services/profile/proto/profile.proto", 309 | } 310 | 311 | func init() { proto.RegisterFile("services/profile/proto/profile.proto", fileDescriptor0) } 312 | 313 | var fileDescriptor0 = []byte{ 314 | // 390 bytes of a gzipped FileDescriptorProto 315 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0xc1, 0x6e, 0xd4, 0x30, 316 | 0x10, 0x86, 0x95, 0x6c, 0x93, 0xec, 0x4e, 0x50, 0xa9, 0x46, 0x08, 0x59, 0x3d, 0xa0, 0x28, 0x42, 317 | 0x28, 0xe2, 0x50, 0xaa, 0xed, 0x11, 0x71, 0x40, 0x1c, 0xa0, 0x17, 0x84, 0xfc, 0x06, 0x6e, 0x3c, 318 | 0xa5, 0x96, 0xbc, 0x71, 0xb0, 0x1d, 0xa4, 0x7d, 0x3e, 0x9e, 0x81, 0xf7, 0x41, 0x76, 0x9c, 0xdd, 319 | 0xd0, 0x53, 0xe6, 0xff, 0x66, 0x9c, 0xdf, 0xbf, 0x35, 0xf0, 0xd6, 0x91, 0xfd, 0xad, 0x7a, 0x72, 320 | 0x1f, 0x46, 0x6b, 0x1e, 0x95, 0xa6, 0xf0, 0xf5, 0x66, 0x51, 0x37, 0x51, 0x61, 0x95, 0x64, 0xfb, 321 | 0x09, 0x2a, 0x4e, 0xbf, 0x26, 0x72, 0x1e, 0xaf, 0x61, 0xfb, 0x64, 0x3c, 0xe9, 0x7b, 0xe9, 0x58, 322 | 0xd6, 0x6c, 0xba, 0x1d, 0x3f, 0x69, 0x7c, 0x0d, 0xa5, 0x36, 0xbd, 0xd0, 0xc4, 0xf2, 0x26, 0xeb, 323 | 0x76, 0x3c, 0xa9, 0xf6, 0x16, 0x4a, 0x4e, 0x6e, 0xd2, 0x1e, 0xdf, 0x41, 0x19, 0xa7, 0xe7, 0xb3, 324 | 0xf5, 0xfe, 0xf2, 0x66, 0x71, 0xfc, 0x16, 0x30, 0x4f, 0xdd, 0xf6, 0x4f, 0x06, 0x45, 0x24, 0x78, 325 | 0x09, 0xb9, 0x92, 0x2c, 0x8b, 0xff, 0xcb, 0x95, 0x44, 0x84, 0x8b, 0x41, 0x1c, 0x16, 0x87, 0x58, 326 | 0x63, 0x03, 0xf5, 0xf8, 0x64, 0x06, 0xfa, 0x3e, 0x1d, 0x1e, 0xc8, 0xb2, 0x4d, 0x6c, 0xad, 0x51, 327 | 0x98, 0x90, 0xe4, 0x7a, 0xab, 0x46, 0xaf, 0xcc, 0xc0, 0x2e, 0xe6, 0x89, 0x15, 0xc2, 0xf7, 0x50, 328 | 0x09, 0x29, 0x2d, 0x39, 0xc7, 0x8a, 0x26, 0xeb, 0xea, 0xfd, 0xd5, 0xe9, 0x6a, 0x9f, 0x67, 0xce, 329 | 0x97, 0x81, 0x90, 0x42, 0x1d, 0xc4, 0x4f, 0x72, 0xac, 0x7c, 0x96, 0xe2, 0x3e, 0x60, 0x9e, 0xba, 330 | 0xed, 0xdf, 0x0c, 0xaa, 0x74, 0x18, 0x5b, 0x78, 0xe1, 0xbc, 0x25, 0xf2, 0xe9, 0x92, 0x73, 0xa2, 331 | 0xff, 0x18, 0xbe, 0x01, 0x48, 0xfa, 0x9c, 0x70, 0x45, 0x42, 0xf6, 0x5e, 0xf9, 0x63, 0x0a, 0x18, 332 | 0x6b, 0x7c, 0x05, 0x85, 0xf3, 0xc2, 0x53, 0xca, 0x34, 0x0b, 0x64, 0x50, 0xf5, 0x66, 0x1a, 0xbc, 333 | 0x3d, 0xc6, 0x34, 0x3b, 0xbe, 0xc8, 0xe0, 0x31, 0x1a, 0xe7, 0x85, 0xfe, 0x62, 0x24, 0xb1, 0x72, 334 | 0xf6, 0x38, 0x13, 0xbc, 0x82, 0x8d, 0x16, 0x9e, 0x55, 0x4d, 0xd6, 0xe5, 0x3c, 0x94, 0x91, 0x98, 335 | 0x81, 0x6d, 0x13, 0x31, 0x43, 0x7b, 0x07, 0x45, 0x0c, 0x1a, 0x5a, 0x93, 0xd5, 0x29, 0x4b, 0x28, 336 | 0x83, 0xb1, 0xa4, 0x47, 0x31, 0x69, 0x1f, 0xef, 0xbf, 0xe5, 0x8b, 0xdc, 0x7f, 0x84, 0xea, 0xc7, 337 | 0xfc, 0x4a, 0x78, 0x0b, 0xf5, 0x57, 0xf2, 0x49, 0x39, 0x3c, 0xbf, 0x74, 0x5a, 0xb2, 0xeb, 0x97, 338 | 0x2b, 0x12, 0xf6, 0xe6, 0xa1, 0x8c, 0x0b, 0x79, 0xf7, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x45, 0xf5, 339 | 0x1c, 0xec, 0xb8, 0x02, 0x00, 0x00, 340 | } 341 | -------------------------------------------------------------------------------- /data/bindata.go: -------------------------------------------------------------------------------- 1 | // Code generated by go-bindata. 2 | // sources: 3 | // data/geo.json 4 | // data/hotels.json 5 | // data/inventory.json 6 | // data/locales.json 7 | // DO NOT EDIT! 8 | 9 | package data 10 | 11 | import ( 12 | "bytes" 13 | "compress/gzip" 14 | "fmt" 15 | "io" 16 | "io/ioutil" 17 | "os" 18 | "path/filepath" 19 | "strings" 20 | "time" 21 | ) 22 | 23 | func bindataRead(data []byte, name string) ([]byte, error) { 24 | gz, err := gzip.NewReader(bytes.NewBuffer(data)) 25 | if err != nil { 26 | return nil, fmt.Errorf("Read %q: %v", name, err) 27 | } 28 | 29 | var buf bytes.Buffer 30 | _, err = io.Copy(&buf, gz) 31 | clErr := gz.Close() 32 | 33 | if err != nil { 34 | return nil, fmt.Errorf("Read %q: %v", name, err) 35 | } 36 | if clErr != nil { 37 | return nil, err 38 | } 39 | 40 | return buf.Bytes(), nil 41 | } 42 | 43 | type asset struct { 44 | bytes []byte 45 | info os.FileInfo 46 | } 47 | 48 | type bindataFileInfo struct { 49 | name string 50 | size int64 51 | mode os.FileMode 52 | modTime time.Time 53 | } 54 | 55 | func (fi bindataFileInfo) Name() string { 56 | return fi.name 57 | } 58 | func (fi bindataFileInfo) Size() int64 { 59 | return fi.size 60 | } 61 | func (fi bindataFileInfo) Mode() os.FileMode { 62 | return fi.mode 63 | } 64 | func (fi bindataFileInfo) ModTime() time.Time { 65 | return fi.modTime 66 | } 67 | func (fi bindataFileInfo) IsDir() bool { 68 | return false 69 | } 70 | func (fi bindataFileInfo) Sys() interface{} { 71 | return nil 72 | } 73 | 74 | var _dataGeoJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8a\xe6\x52\x50\x50\x50\xa8\x06\x93\x20\xa0\x94\x91\x5f\x92\x9a\xe3\x99\xa2\x64\xa5\xa0\x64\xa8\xa4\x83\x10\xcf\x49\x2c\x51\xb2\x52\x30\x36\xd7\x33\xb7\x30\x33\x47\x16\xcf\xcf\x53\xb2\x52\xd0\x35\x34\x32\xd2\x33\x31\x34\x34\x02\x4b\xd4\xea\xe0\x31\xd5\x08\x87\xa9\xa6\x26\x38\x4c\x35\x30\x30\x25\x6c\xaa\x31\x0e\x53\x8d\x71\x9a\x6a\x6e\x48\xd8\x54\x13\xec\xa6\x5a\x1a\x9b\x61\x37\xd5\xd8\xd2\xd8\x80\xb0\xa9\xa6\xb8\xdc\x6a\x88\x2b\x5c\x2d\x88\x70\xab\x19\xae\xd8\x32\xc6\x15\x02\x86\xd0\x70\xe5\x8a\xe5\x02\x04\x00\x00\xff\xff\xc2\xb0\xd9\xce\x07\x02\x00\x00") 75 | 76 | func dataGeoJsonBytes() ([]byte, error) { 77 | return bindataRead( 78 | _dataGeoJson, 79 | "data/geo.json", 80 | ) 81 | } 82 | 83 | func dataGeoJson() (*asset, error) { 84 | bytes, err := dataGeoJsonBytes() 85 | if err != nil { 86 | return nil, err 87 | } 88 | 89 | info := bindataFileInfo{name: "data/geo.json", size: 519, mode: os.FileMode(420), modTime: time.Unix(1502238721, 0)} 90 | a := &asset{bytes: bytes, info: info} 91 | return a, nil 92 | } 93 | 94 | var _dataHotelsJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xd4\x96\xcd\x6e\x23\x45\x10\xc7\xef\xfb\x14\xa5\x9c\x40\xb2\x23\x8f\x67\xc6\x1f\x7b\x4b\xb2\xec\x2e\x12\x46\xd1\x3a\x0b\x02\xc4\xa1\xdc\x5d\xf6\x14\x69\x77\x9b\xea\x9a\xcd\x5a\x68\x25\x5e\x83\xd7\xe3\x49\x50\x8f\x1d\xe2\xc4\xf6\x24\xe4\x14\x72\x88\xac\xae\x9a\xea\x8f\xfa\xe9\x5f\xff\x5f\x5e\x01\x00\xfc\xd1\xfc\x4f\x7f\x27\x6c\x4f\x5e\xc3\x49\x76\xd2\xb9\x5b\xf2\xb8\xa4\xb4\x78\xe1\x78\xae\xf0\x3e\x28\xb9\xdd\xf0\xaa\x0a\x9e\xbe\xaf\x97\x33\x92\x94\xf5\x55\x91\x95\x5f\xc3\x70\x58\x76\x8b\x61\xaf\xb7\x9b\x68\x29\x1a\xe1\x95\x72\xf0\x29\xf1\x0c\x06\xdd\x25\xfb\x5a\x09\x6e\xd0\x5d\xc3\x5c\xc2\x12\x3e\x7a\x0e\x1e\xa6\xbf\xd7\x28\x04\xe8\x2d\x14\xb0\xc9\x89\x9b\x38\xc2\xa4\xf6\x0c\x13\x52\x09\x10\x15\x53\xb1\x0e\x68\xc5\x11\x5c\xfd\xb9\x96\x35\x54\xe9\x7c\x60\x29\xf2\xc2\x93\x85\xd9\x1a\x2e\x2b\x76\xbc\x5a\x11\x4c\x15\xc5\x5c\xc3\x9c\x50\x6b\xa1\x08\xe8\x01\x45\xe3\x1a\xe6\xb5\x78\x4e\x6b\x60\x82\x73\x64\x52\x55\x60\x0f\x5a\x11\xb8\x30\x9b\xad\x3b\xc0\xde\xb8\xda\xb2\x5f\xc0\x4d\x90\xeb\x54\x76\x8a\xee\x13\xda\x20\xf0\x06\x1d\x9f\xee\x5e\x14\xad\x15\x8a\xf1\xe4\xf5\xce\xc3\x36\x81\xa8\x42\xa4\x77\x6f\x55\x8c\xcb\x9d\xef\x76\x53\xb6\x4f\xfe\x8e\x50\xd6\x30\xd5\x87\x59\x86\x75\x9d\xe2\x53\xf4\xf0\x56\xd0\x1b\x8e\x26\xec\x97\x42\xdd\x34\xee\x6c\xef\xfb\x50\x7b\x95\xa6\xc4\x47\xcf\x4a\x36\xbd\x8d\x52\x7c\x98\xb7\x0a\x51\xd1\x5d\x04\xdb\xd4\x19\x17\x59\xaf\xff\x30\xc5\xa1\x9e\xbc\x86\x7c\x78\x3a\x1c\x0d\x86\x0f\x63\x4d\xa7\xbb\x59\xbf\x7f\x5a\x64\x59\xff\xdf\xe0\x97\xe6\xd7\x97\xce\x61\xf8\xfa\x87\xe0\xfb\x11\x8e\xdd\xf5\x18\x80\xc3\x6e\x99\xb7\x02\xf8\x1d\xc5\x08\x5a\x25\x0a\x60\xe6\x82\xd9\x22\x98\x9a\xfe\x13\xc9\x0c\xe1\xbc\x26\x8f\x70\x41\x5e\x49\x60\x1e\xa4\x09\x9d\x89\xc6\x2d\x71\x2a\xe4\xed\x2d\x71\x1c\x01\x21\xeb\xb7\x23\xfd\x3c\x4c\xb2\x51\xd6\x8e\x49\x2e\xf6\x45\x41\x92\xb7\x40\x52\x16\x2d\x90\xf4\x7a\xe5\x13\x21\xc9\x0f\x41\xd2\x68\x13\xfc\x4c\xaa\xf8\x28\x20\x65\x91\x77\x47\x65\x59\xb6\x2a\x54\xbe\xdf\xce\xc4\xc0\x65\xb8\x21\xe7\x60\xda\x34\x01\x0c\xce\x1c\x75\x0d\x0a\x68\x2d\x1e\x25\xd4\xde\x36\xda\x75\x7e\xf6\xe1\x0a\x04\xd9\x3d\x50\xaa\x8a\x57\x5b\x68\xc6\xf7\xd5\xed\x9e\xfa\x99\xb0\x9c\xb1\xa7\x94\xbe\xa8\xba\x4a\xa6\x02\x17\xec\xa2\x91\x20\xd6\x6a\x2b\x5d\x1a\x6a\x53\x51\x7c\x1e\x58\xe5\x23\xf2\x53\x6a\xf5\xbf\xe1\x2a\x6f\xe5\x6a\x98\x3d\x91\xab\xe2\x38\x57\x3f\xb0\xa2\xa3\x47\xc1\xea\x0f\x47\xdd\xbc\x7d\xf4\x5d\x25\x0a\x6e\x50\x49\xe6\x12\xbc\x6e\x61\x68\xba\x7a\x8e\x6b\x38\x17\xb6\x0b\x82\x4f\x4c\x37\x31\xe9\x4a\xbe\x91\xa7\x78\x07\xe0\x5b\xf6\xe9\xdd\xd1\xc1\x1b\x8e\x2a\x6c\xb4\x01\x0e\xa1\x38\x0c\xec\x5b\x12\x59\xc3\x79\xcd\x2e\x8d\xb0\xe7\xc1\x32\x6a\x67\x65\xc2\x31\x36\xf4\xbe\x20\x5e\xf6\xf0\xbe\xe3\x65\x9c\x0f\x8e\xf3\x92\x8f\xf3\xde\x13\x79\x29\x0f\xf1\x72\x59\x05\xf2\xfc\xf9\xc9\x5e\x69\xd0\xcd\xf2\x51\xeb\xa8\x0a\x06\xd3\xc5\xb7\x9e\xe4\x8a\xbc\x25\x71\x81\x3d\x78\xe2\x45\x35\x0b\x52\x85\x60\x3b\x69\x02\xf5\xf6\x09\xc0\xa3\x4a\x24\x8d\x8f\x5a\x06\x0d\xd2\x88\x0b\x41\x85\x11\xaa\x10\xd3\x66\x4b\xf4\x6b\x90\x34\x17\x97\x75\x64\xc3\xe8\x63\x43\x59\xd0\x8a\x04\x0c\x39\x9a\x09\x2b\x53\x84\xc8\xde\x50\x73\xb2\x6c\x5c\xf6\xe2\x29\x7c\xab\x7f\xff\xf9\x57\x3c\xce\x63\xc5\x51\x83\xb0\x81\x77\x42\xa8\x70\xb6\x24\x61\x83\x1e\x26\x69\x23\x78\x8f\xce\x81\xe7\x45\xa5\xc6\xd5\xb3\xe7\xd1\x3a\xe8\x3d\x32\x33\xbf\xb1\xf6\x65\x39\xab\x71\x9b\xb8\x65\x6d\xce\x6a\xf4\x54\x71\x1b\x1c\x82\x75\xaa\xa7\xf0\x81\x16\x1c\xff\xa3\xc3\xea\x8f\x8a\x6e\xd1\x6b\xd5\xb9\xbb\xd2\x93\x3a\x52\xbd\x84\xab\x70\x43\xb2\xb1\x4a\x45\xbf\x9b\x18\x58\x77\xa0\x18\x15\x30\x57\x88\xd7\xeb\x68\x04\x57\x29\x61\x83\xf9\x34\xd4\x5a\x41\x98\xc3\x04\xe5\x9a\x14\xec\xad\xd6\x85\xf9\xfd\xb3\x76\xe0\x02\x1d\xcf\x83\x78\xc6\x0e\xa0\xfd\x0d\x0d\x79\x05\x0d\xf7\x8c\xdc\x3b\x14\x4b\x3e\x76\x60\x12\xa2\x09\x9e\xb6\xce\xae\x03\x97\x68\xce\xd3\x3c\xbf\xd5\xc7\x86\xf2\xe6\x00\xbb\x9b\xdc\xde\x21\x9d\x27\x58\x12\x9f\xac\xe0\x33\x0d\x5d\xff\x91\xc1\xfb\xd2\x0c\x5d\x1b\x9b\x83\xbc\x6d\xf0\x66\x7b\x86\xee\xd5\xaf\xaf\xfe\x09\x00\x00\xff\xff\xd4\xa1\x82\xaf\x76\x0e\x00\x00") 95 | 96 | func dataHotelsJsonBytes() ([]byte, error) { 97 | return bindataRead( 98 | _dataHotelsJson, 99 | "data/hotels.json", 100 | ) 101 | } 102 | 103 | func dataHotelsJson() (*asset, error) { 104 | bytes, err := dataHotelsJsonBytes() 105 | if err != nil { 106 | return nil, err 107 | } 108 | 109 | info := bindataFileInfo{name: "data/hotels.json", size: 3702, mode: os.FileMode(420), modTime: time.Unix(1502238721, 0)} 110 | a := &asset{bytes: bytes, info: info} 111 | return a, nil 112 | } 113 | 114 | var _dataInventoryJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x8a\xe6\x52\x50\x50\x50\xa8\x06\x93\x20\xa0\x94\x91\x5f\x92\x9a\xe3\x99\xa2\x64\xa5\xa0\x64\xa8\xa4\x83\x10\x4f\xce\x4f\x49\x05\x09\x06\x39\x3a\x7b\x23\x8b\x67\xe6\xb9\x24\x96\x80\x65\x8c\x0c\x0c\x4d\x75\x0d\x4c\x74\x0d\x2c\x91\xe5\xf3\x4b\x4b\xd0\x15\x18\x1a\x20\x2b\x28\xca\xcf\xcf\x0d\xa9\x2c\x00\xa9\x40\x38\x43\x41\x41\x29\x29\x3f\x3f\x3b\x31\x29\x27\x35\x08\xa2\xdb\xd0\xc0\x52\xcf\xc0\x40\x07\x59\x05\xcc\x49\xde\x7e\xee\x4a\x28\x12\x29\xa9\xc5\xc9\x45\x99\x05\x25\x99\xf9\x79\x60\xf9\xcc\xbc\x74\x85\xe2\xcc\xaa\xd4\x14\x85\xa4\xd4\x14\x54\xa5\x25\xf9\x25\x89\x39\xb8\xad\x80\x4b\x7b\xe6\x25\xe7\x94\x16\x67\x96\x81\xd5\x19\x19\xeb\x19\x9a\xc3\x95\xd5\x82\x59\xb5\x3a\x78\x42\xd2\x68\x50\x85\xa4\x31\xce\x90\x0c\xf4\xc3\x1b\x90\x81\xa5\xa9\xa9\x79\x44\x85\x24\xa6\x15\xd8\x43\xd2\xd4\x58\xcf\xc0\x92\x94\x90\x34\x1e\x54\x21\x39\xd8\xd3\x24\x57\x2c\x17\x20\x00\x00\xff\xff\x34\xed\xf5\xf8\xe1\x03\x00\x00") 115 | 116 | func dataInventoryJsonBytes() ([]byte, error) { 117 | return bindataRead( 118 | _dataInventoryJson, 119 | "data/inventory.json", 120 | ) 121 | } 122 | 123 | func dataInventoryJson() (*asset, error) { 124 | bytes, err := dataInventoryJsonBytes() 125 | if err != nil { 126 | return nil, err 127 | } 128 | 129 | info := bindataFileInfo{name: "data/inventory.json", size: 993, mode: os.FileMode(420), modTime: time.Unix(1502245313, 0)} 130 | a := &asset{bytes: bytes, info: info} 131 | return a, nil 132 | } 133 | 134 | var _dataLocalesJson = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x4c\x8f\x31\x4b\xf4\x40\x10\x86\xfb\xfb\x15\x2f\xa9\xf3\x7d\x20\x88\x85\x9d\x60\x63\x71\x20\x04\x2b\xb1\x98\xec\x4e\x2e\x43\xe6\x66\xe3\xec\xae\x67\x10\xff\xbb\x6c\xae\xd0\x29\xa6\x78\xde\xe1\x61\xde\xd7\x03\x00\x7c\xed\xbb\x4d\x37\xa7\xc2\xfa\x14\xbb\x7b\x74\x37\x5d\xff\xcb\x35\x05\x52\x6e\x98\xed\x2f\x8f\x9c\x83\xcb\x5a\x24\x59\x0b\x1f\x70\xf7\xef\x2c\x56\x0b\xe3\x42\xba\x60\xf2\x74\xc6\x8b\x49\x32\x0c\xef\x95\x9c\x41\x16\x71\x8b\xeb\x4d\xbe\xe6\x84\x63\x35\xc1\x91\x8b\x27\xe4\x42\x4d\xd6\xa3\xcc\x92\xa1\xf5\xb3\xfa\x86\xfd\x2b\x44\xce\x72\x32\x8e\x18\x37\x3c\xcf\xa2\xb2\xae\x8c\xa1\x90\x87\x05\x13\x53\xa9\xce\x19\x64\x20\x2f\x79\xc3\x54\xdd\xa4\x31\x84\xa4\xca\xa1\x59\x21\x86\x32\x33\x34\x8d\xe3\xd6\x43\x2c\x68\x8d\x62\x27\x5c\x92\x2f\x4d\x3b\x90\x7e\x50\x4c\x8e\x47\x52\xf9\xdf\xed\x3d\xbf\x0f\x6f\x87\x9f\x00\x00\x00\xff\xff\x84\x3e\x09\x90\x28\x01\x00\x00") 135 | 136 | func dataLocalesJsonBytes() ([]byte, error) { 137 | return bindataRead( 138 | _dataLocalesJson, 139 | "data/locales.json", 140 | ) 141 | } 142 | 143 | func dataLocalesJson() (*asset, error) { 144 | bytes, err := dataLocalesJsonBytes() 145 | if err != nil { 146 | return nil, err 147 | } 148 | 149 | info := bindataFileInfo{name: "data/locales.json", size: 296, mode: os.FileMode(420), modTime: time.Unix(1502238721, 0)} 150 | a := &asset{bytes: bytes, info: info} 151 | return a, nil 152 | } 153 | 154 | // Asset loads and returns the asset for the given name. 155 | // It returns an error if the asset could not be found or 156 | // could not be loaded. 157 | func Asset(name string) ([]byte, error) { 158 | cannonicalName := strings.Replace(name, "\\", "/", -1) 159 | if f, ok := _bindata[cannonicalName]; ok { 160 | a, err := f() 161 | if err != nil { 162 | return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) 163 | } 164 | return a.bytes, nil 165 | } 166 | return nil, fmt.Errorf("Asset %s not found", name) 167 | } 168 | 169 | // MustAsset is like Asset but panics when Asset would return an error. 170 | // It simplifies safe initialization of global variables. 171 | func MustAsset(name string) []byte { 172 | a, err := Asset(name) 173 | if err != nil { 174 | panic("asset: Asset(" + name + "): " + err.Error()) 175 | } 176 | 177 | return a 178 | } 179 | 180 | // AssetInfo loads and returns the asset info for the given name. 181 | // It returns an error if the asset could not be found or 182 | // could not be loaded. 183 | func AssetInfo(name string) (os.FileInfo, error) { 184 | cannonicalName := strings.Replace(name, "\\", "/", -1) 185 | if f, ok := _bindata[cannonicalName]; ok { 186 | a, err := f() 187 | if err != nil { 188 | return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) 189 | } 190 | return a.info, nil 191 | } 192 | return nil, fmt.Errorf("AssetInfo %s not found", name) 193 | } 194 | 195 | // AssetNames returns the names of the assets. 196 | func AssetNames() []string { 197 | names := make([]string, 0, len(_bindata)) 198 | for name := range _bindata { 199 | names = append(names, name) 200 | } 201 | return names 202 | } 203 | 204 | // _bindata is a table, holding each asset generator, mapped to its name. 205 | var _bindata = map[string]func() (*asset, error){ 206 | "data/geo.json": dataGeoJson, 207 | "data/hotels.json": dataHotelsJson, 208 | "data/inventory.json": dataInventoryJson, 209 | "data/locales.json": dataLocalesJson, 210 | } 211 | 212 | // AssetDir returns the file names below a certain 213 | // directory embedded in the file by go-bindata. 214 | // For example if you run go-bindata on data/... and data contains the 215 | // following hierarchy: 216 | // data/ 217 | // foo.txt 218 | // img/ 219 | // a.png 220 | // b.png 221 | // then AssetDir("data") would return []string{"foo.txt", "img"} 222 | // AssetDir("data/img") would return []string{"a.png", "b.png"} 223 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error 224 | // AssetDir("") will return []string{"data"}. 225 | func AssetDir(name string) ([]string, error) { 226 | node := _bintree 227 | if len(name) != 0 { 228 | cannonicalName := strings.Replace(name, "\\", "/", -1) 229 | pathList := strings.Split(cannonicalName, "/") 230 | for _, p := range pathList { 231 | node = node.Children[p] 232 | if node == nil { 233 | return nil, fmt.Errorf("Asset %s not found", name) 234 | } 235 | } 236 | } 237 | if node.Func != nil { 238 | return nil, fmt.Errorf("Asset %s not found", name) 239 | } 240 | rv := make([]string, 0, len(node.Children)) 241 | for childName := range node.Children { 242 | rv = append(rv, childName) 243 | } 244 | return rv, nil 245 | } 246 | 247 | type bintree struct { 248 | Func func() (*asset, error) 249 | Children map[string]*bintree 250 | } 251 | var _bintree = &bintree{nil, map[string]*bintree{ 252 | "data": &bintree{nil, map[string]*bintree{ 253 | "geo.json": &bintree{dataGeoJson, map[string]*bintree{}}, 254 | "hotels.json": &bintree{dataHotelsJson, map[string]*bintree{}}, 255 | "inventory.json": &bintree{dataInventoryJson, map[string]*bintree{}}, 256 | "locales.json": &bintree{dataLocalesJson, map[string]*bintree{}}, 257 | }}, 258 | }} 259 | 260 | // RestoreAsset restores an asset under the given directory 261 | func RestoreAsset(dir, name string) error { 262 | data, err := Asset(name) 263 | if err != nil { 264 | return err 265 | } 266 | info, err := AssetInfo(name) 267 | if err != nil { 268 | return err 269 | } 270 | err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) 271 | if err != nil { 272 | return err 273 | } 274 | err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) 275 | if err != nil { 276 | return err 277 | } 278 | err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) 279 | if err != nil { 280 | return err 281 | } 282 | return nil 283 | } 284 | 285 | // RestoreAssets restores an asset under the given directory recursively 286 | func RestoreAssets(dir, name string) error { 287 | children, err := AssetDir(name) 288 | // File 289 | if err != nil { 290 | return RestoreAsset(dir, name) 291 | } 292 | // Dir 293 | for _, child := range children { 294 | err = RestoreAssets(dir, filepath.Join(name, child)) 295 | if err != nil { 296 | return err 297 | } 298 | } 299 | return nil 300 | } 301 | 302 | func _filePath(dir, name string) string { 303 | cannonicalName := strings.Replace(name, "\\", "/", -1) 304 | return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) 305 | } 306 | 307 | --------------------------------------------------------------------------------