1/*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19// Package main implements a simple gRPC server that demonstrates how to use gRPC-Go libraries
20// to perform unary, client streaming, server streaming and full duplex RPCs.
21//
22// It implements the route guide service whose definition can be found in routeguide/route_guide.proto.
23package main
24
25import (
26	"context"
27	"encoding/json"
28	"flag"
29	"fmt"
30	"io"
31	"io/ioutil"
32	"log"
33	"math"
34	"net"
35	"sync"
36	"time"
37
38	"google.golang.org/grpc"
39
40	"google.golang.org/grpc/credentials"
41	"google.golang.org/grpc/testdata"
42
43	"github.com/golang/protobuf/proto"
44
45	pb "google.golang.org/grpc/examples/route_guide/routeguide"
46)
47
48var (
49	tls        = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP")
50	certFile   = flag.String("cert_file", "", "The TLS cert file")
51	keyFile    = flag.String("key_file", "", "The TLS key file")
52	jsonDBFile = flag.String("json_db_file", "", "A json file containing a list of features")
53	port       = flag.Int("port", 10000, "The server port")
54)
55
56type routeGuideServer struct {
57	pb.UnimplementedRouteGuideServer
58	savedFeatures []*pb.Feature // read-only after initialized
59
60	mu         sync.Mutex // protects routeNotes
61	routeNotes map[string][]*pb.RouteNote
62}
63
64// GetFeature returns the feature at the given point.
65func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
66	for _, feature := range s.savedFeatures {
67		if proto.Equal(feature.Location, point) {
68			return feature, nil
69		}
70	}
71	// No feature was found, return an unnamed feature
72	return &pb.Feature{Location: point}, nil
73}
74
75// ListFeatures lists all features contained within the given bounding Rectangle.
76func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error {
77	for _, feature := range s.savedFeatures {
78		if inRange(feature.Location, rect) {
79			if err := stream.Send(feature); err != nil {
80				return err
81			}
82		}
83	}
84	return nil
85}
86
87// RecordRoute records a route composited of a sequence of points.
88//
89// It gets a stream of points, and responds with statistics about the "trip":
90// number of points,  number of known features visited, total distance traveled, and
91// total time spent.
92func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) error {
93	var pointCount, featureCount, distance int32
94	var lastPoint *pb.Point
95	startTime := time.Now()
96	for {
97		point, err := stream.Recv()
98		if err == io.EOF {
99			endTime := time.Now()
100			return stream.SendAndClose(&pb.RouteSummary{
101				PointCount:   pointCount,
102				FeatureCount: featureCount,
103				Distance:     distance,
104				ElapsedTime:  int32(endTime.Sub(startTime).Seconds()),
105			})
106		}
107		if err != nil {
108			return err
109		}
110		pointCount++
111		for _, feature := range s.savedFeatures {
112			if proto.Equal(feature.Location, point) {
113				featureCount++
114			}
115		}
116		if lastPoint != nil {
117			distance += calcDistance(lastPoint, point)
118		}
119		lastPoint = point
120	}
121}
122
123// RouteChat receives a stream of message/location pairs, and responds with a stream of all
124// previous messages at each of those locations.
125func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {
126	for {
127		in, err := stream.Recv()
128		if err == io.EOF {
129			return nil
130		}
131		if err != nil {
132			return err
133		}
134		key := serialize(in.Location)
135
136		s.mu.Lock()
137		s.routeNotes[key] = append(s.routeNotes[key], in)
138		// Note: this copy prevents blocking other clients while serving this one.
139		// We don't need to do a deep copy, because elements in the slice are
140		// insert-only and never modified.
141		rn := make([]*pb.RouteNote, len(s.routeNotes[key]))
142		copy(rn, s.routeNotes[key])
143		s.mu.Unlock()
144
145		for _, note := range rn {
146			if err := stream.Send(note); err != nil {
147				return err
148			}
149		}
150	}
151}
152
153// loadFeatures loads features from a JSON file.
154func (s *routeGuideServer) loadFeatures(filePath string) {
155	var data []byte
156	if filePath != "" {
157		var err error
158		data, err = ioutil.ReadFile(filePath)
159		if err != nil {
160			log.Fatalf("Failed to load default features: %v", err)
161		}
162	} else {
163		data = exampleData
164	}
165	if err := json.Unmarshal(data, &s.savedFeatures); err != nil {
166		log.Fatalf("Failed to load default features: %v", err)
167	}
168}
169
170func toRadians(num float64) float64 {
171	return num * math.Pi / float64(180)
172}
173
174// calcDistance calculates the distance between two points using the "haversine" formula.
175// The formula is based on http://mathforum.org/library/drmath/view/51879.html.
176func calcDistance(p1 *pb.Point, p2 *pb.Point) int32 {
177	const CordFactor float64 = 1e7
178	const R = float64(6371000) // earth radius in metres
179	lat1 := toRadians(float64(p1.Latitude) / CordFactor)
180	lat2 := toRadians(float64(p2.Latitude) / CordFactor)
181	lng1 := toRadians(float64(p1.Longitude) / CordFactor)
182	lng2 := toRadians(float64(p2.Longitude) / CordFactor)
183	dlat := lat2 - lat1
184	dlng := lng2 - lng1
185
186	a := math.Sin(dlat/2)*math.Sin(dlat/2) +
187		math.Cos(lat1)*math.Cos(lat2)*
188			math.Sin(dlng/2)*math.Sin(dlng/2)
189	c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
190
191	distance := R * c
192	return int32(distance)
193}
194
195func inRange(point *pb.Point, rect *pb.Rectangle) bool {
196	left := math.Min(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
197	right := math.Max(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
198	top := math.Max(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))
199	bottom := math.Min(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))
200
201	if float64(point.Longitude) >= left &&
202		float64(point.Longitude) <= right &&
203		float64(point.Latitude) >= bottom &&
204		float64(point.Latitude) <= top {
205		return true
206	}
207	return false
208}
209
210func serialize(point *pb.Point) string {
211	return fmt.Sprintf("%d %d", point.Latitude, point.Longitude)
212}
213
214func newServer() *routeGuideServer {
215	s := &routeGuideServer{routeNotes: make(map[string][]*pb.RouteNote)}
216	s.loadFeatures(*jsonDBFile)
217	return s
218}
219
220func main() {
221	flag.Parse()
222	lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
223	if err != nil {
224		log.Fatalf("failed to listen: %v", err)
225	}
226	var opts []grpc.ServerOption
227	if *tls {
228		if *certFile == "" {
229			*certFile = testdata.Path("server1.pem")
230		}
231		if *keyFile == "" {
232			*keyFile = testdata.Path("server1.key")
233		}
234		creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)
235		if err != nil {
236			log.Fatalf("Failed to generate credentials %v", err)
237		}
238		opts = []grpc.ServerOption{grpc.Creds(creds)}
239	}
240	grpcServer := grpc.NewServer(opts...)
241	pb.RegisterRouteGuideServer(grpcServer, newServer())
242	grpcServer.Serve(lis)
243}
244
245// exampleData is a copy of testdata/route_guide_db.json. It's to avoid
246// specifying file path with `go run`.
247var exampleData = []byte(`[{
248    "location": {
249        "latitude": 407838351,
250        "longitude": -746143763
251    },
252    "name": "Patriots Path, Mendham, NJ 07945, USA"
253}, {
254    "location": {
255        "latitude": 408122808,
256        "longitude": -743999179
257    },
258    "name": "101 New Jersey 10, Whippany, NJ 07981, USA"
259}, {
260    "location": {
261        "latitude": 413628156,
262        "longitude": -749015468
263    },
264    "name": "U.S. 6, Shohola, PA 18458, USA"
265}, {
266    "location": {
267        "latitude": 419999544,
268        "longitude": -740371136
269    },
270    "name": "5 Conners Road, Kingston, NY 12401, USA"
271}, {
272    "location": {
273        "latitude": 414008389,
274        "longitude": -743951297
275    },
276    "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
277}, {
278    "location": {
279        "latitude": 419611318,
280        "longitude": -746524769
281    },
282    "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
283}, {
284    "location": {
285        "latitude": 406109563,
286        "longitude": -742186778
287    },
288    "name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
289}, {
290    "location": {
291        "latitude": 416802456,
292        "longitude": -742370183
293    },
294    "name": "352 South Mountain Road, Wallkill, NY 12589, USA"
295}, {
296    "location": {
297        "latitude": 412950425,
298        "longitude": -741077389
299    },
300    "name": "Bailey Turn Road, Harriman, NY 10926, USA"
301}, {
302    "location": {
303        "latitude": 412144655,
304        "longitude": -743949739
305    },
306    "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
307}, {
308    "location": {
309        "latitude": 415736605,
310        "longitude": -742847522
311    },
312    "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
313}, {
314    "location": {
315        "latitude": 413843930,
316        "longitude": -740501726
317    },
318    "name": "162 Merrill Road, Highland Mills, NY 10930, USA"
319}, {
320    "location": {
321        "latitude": 410873075,
322        "longitude": -744459023
323    },
324    "name": "Clinton Road, West Milford, NJ 07480, USA"
325}, {
326    "location": {
327        "latitude": 412346009,
328        "longitude": -744026814
329    },
330    "name": "16 Old Brook Lane, Warwick, NY 10990, USA"
331}, {
332    "location": {
333        "latitude": 402948455,
334        "longitude": -747903913
335    },
336    "name": "3 Drake Lane, Pennington, NJ 08534, USA"
337}, {
338    "location": {
339        "latitude": 406337092,
340        "longitude": -740122226
341    },
342    "name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
343}, {
344    "location": {
345        "latitude": 406421967,
346        "longitude": -747727624
347    },
348    "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
349}, {
350    "location": {
351        "latitude": 416318082,
352        "longitude": -749677716
353    },
354    "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
355}, {
356    "location": {
357        "latitude": 415301720,
358        "longitude": -748416257
359    },
360    "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
361}, {
362    "location": {
363        "latitude": 402647019,
364        "longitude": -747071791
365    },
366    "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
367}, {
368    "location": {
369        "latitude": 412567807,
370        "longitude": -741058078
371    },
372    "name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
373}, {
374    "location": {
375        "latitude": 416855156,
376        "longitude": -744420597
377    },
378    "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
379}, {
380    "location": {
381        "latitude": 404663628,
382        "longitude": -744820157
383    },
384    "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
385}, {
386    "location": {
387        "latitude": 407113723,
388        "longitude": -749746483
389    },
390    "name": ""
391}, {
392    "location": {
393        "latitude": 402133926,
394        "longitude": -743613249
395    },
396    "name": ""
397}, {
398    "location": {
399        "latitude": 400273442,
400        "longitude": -741220915
401    },
402    "name": ""
403}, {
404    "location": {
405        "latitude": 411236786,
406        "longitude": -744070769
407    },
408    "name": ""
409}, {
410    "location": {
411        "latitude": 411633782,
412        "longitude": -746784970
413    },
414    "name": "211-225 Plains Road, Augusta, NJ 07822, USA"
415}, {
416    "location": {
417        "latitude": 415830701,
418        "longitude": -742952812
419    },
420    "name": ""
421}, {
422    "location": {
423        "latitude": 413447164,
424        "longitude": -748712898
425    },
426    "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
427}, {
428    "location": {
429        "latitude": 405047245,
430        "longitude": -749800722
431    },
432    "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
433}, {
434    "location": {
435        "latitude": 418858923,
436        "longitude": -746156790
437    },
438    "name": ""
439}, {
440    "location": {
441        "latitude": 417951888,
442        "longitude": -748484944
443    },
444    "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
445}, {
446    "location": {
447        "latitude": 407033786,
448        "longitude": -743977337
449    },
450    "name": "26 East 3rd Street, New Providence, NJ 07974, USA"
451}, {
452    "location": {
453        "latitude": 417548014,
454        "longitude": -740075041
455    },
456    "name": ""
457}, {
458    "location": {
459        "latitude": 410395868,
460        "longitude": -744972325
461    },
462    "name": ""
463}, {
464    "location": {
465        "latitude": 404615353,
466        "longitude": -745129803
467    },
468    "name": ""
469}, {
470    "location": {
471        "latitude": 406589790,
472        "longitude": -743560121
473    },
474    "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
475}, {
476    "location": {
477        "latitude": 414653148,
478        "longitude": -740477477
479    },
480    "name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
481}, {
482    "location": {
483        "latitude": 405957808,
484        "longitude": -743255336
485    },
486    "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
487}, {
488    "location": {
489        "latitude": 411733589,
490        "longitude": -741648093
491    },
492    "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
493}, {
494    "location": {
495        "latitude": 412676291,
496        "longitude": -742606606
497    },
498    "name": "1270 Lakes Road, Monroe, NY 10950, USA"
499}, {
500    "location": {
501        "latitude": 409224445,
502        "longitude": -748286738
503    },
504    "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
505}, {
506    "location": {
507        "latitude": 406523420,
508        "longitude": -742135517
509    },
510    "name": "652 Garden Street, Elizabeth, NJ 07202, USA"
511}, {
512    "location": {
513        "latitude": 401827388,
514        "longitude": -740294537
515    },
516    "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
517}, {
518    "location": {
519        "latitude": 410564152,
520        "longitude": -743685054
521    },
522    "name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
523}, {
524    "location": {
525        "latitude": 408472324,
526        "longitude": -740726046
527    },
528    "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
529}, {
530    "location": {
531        "latitude": 412452168,
532        "longitude": -740214052
533    },
534    "name": "5 White Oak Lane, Stony Point, NY 10980, USA"
535}, {
536    "location": {
537        "latitude": 409146138,
538        "longitude": -746188906
539    },
540    "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
541}, {
542    "location": {
543        "latitude": 404701380,
544        "longitude": -744781745
545    },
546    "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
547}, {
548    "location": {
549        "latitude": 409642566,
550        "longitude": -746017679
551    },
552    "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
553}, {
554    "location": {
555        "latitude": 408031728,
556        "longitude": -748645385
557    },
558    "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
559}, {
560    "location": {
561        "latitude": 413700272,
562        "longitude": -742135189
563    },
564    "name": "367 Prospect Road, Chester, NY 10918, USA"
565}, {
566    "location": {
567        "latitude": 404310607,
568        "longitude": -740282632
569    },
570    "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
571}, {
572    "location": {
573        "latitude": 409319800,
574        "longitude": -746201391
575    },
576    "name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
577}, {
578    "location": {
579        "latitude": 406685311,
580        "longitude": -742108603
581    },
582    "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
583}, {
584    "location": {
585        "latitude": 419018117,
586        "longitude": -749142781
587    },
588    "name": "43 Dreher Road, Roscoe, NY 12776, USA"
589}, {
590    "location": {
591        "latitude": 412856162,
592        "longitude": -745148837
593    },
594    "name": "Swan Street, Pine Island, NY 10969, USA"
595}, {
596    "location": {
597        "latitude": 416560744,
598        "longitude": -746721964
599    },
600    "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
601}, {
602    "location": {
603        "latitude": 405314270,
604        "longitude": -749836354
605    },
606    "name": ""
607}, {
608    "location": {
609        "latitude": 414219548,
610        "longitude": -743327440
611    },
612    "name": ""
613}, {
614    "location": {
615        "latitude": 415534177,
616        "longitude": -742900616
617    },
618    "name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
619}, {
620    "location": {
621        "latitude": 406898530,
622        "longitude": -749127080
623    },
624    "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
625}, {
626    "location": {
627        "latitude": 407586880,
628        "longitude": -741670168
629    },
630    "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
631}, {
632    "location": {
633        "latitude": 400106455,
634        "longitude": -742870190
635    },
636    "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
637}, {
638    "location": {
639        "latitude": 400066188,
640        "longitude": -746793294
641    },
642    "name": ""
643}, {
644    "location": {
645        "latitude": 418803880,
646        "longitude": -744102673
647    },
648    "name": "40 Mountain Road, Napanoch, NY 12458, USA"
649}, {
650    "location": {
651        "latitude": 414204288,
652        "longitude": -747895140
653    },
654    "name": ""
655}, {
656    "location": {
657        "latitude": 414777405,
658        "longitude": -740615601
659    },
660    "name": ""
661}, {
662    "location": {
663        "latitude": 415464475,
664        "longitude": -747175374
665    },
666    "name": "48 North Road, Forestburgh, NY 12777, USA"
667}, {
668    "location": {
669        "latitude": 404062378,
670        "longitude": -746376177
671    },
672    "name": ""
673}, {
674    "location": {
675        "latitude": 405688272,
676        "longitude": -749285130
677    },
678    "name": ""
679}, {
680    "location": {
681        "latitude": 400342070,
682        "longitude": -748788996
683    },
684    "name": ""
685}, {
686    "location": {
687        "latitude": 401809022,
688        "longitude": -744157964
689    },
690    "name": ""
691}, {
692    "location": {
693        "latitude": 404226644,
694        "longitude": -740517141
695    },
696    "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
697}, {
698    "location": {
699        "latitude": 410322033,
700        "longitude": -747871659
701    },
702    "name": ""
703}, {
704    "location": {
705        "latitude": 407100674,
706        "longitude": -747742727
707    },
708    "name": ""
709}, {
710    "location": {
711        "latitude": 418811433,
712        "longitude": -741718005
713    },
714    "name": "213 Bush Road, Stone Ridge, NY 12484, USA"
715}, {
716    "location": {
717        "latitude": 415034302,
718        "longitude": -743850945
719    },
720    "name": ""
721}, {
722    "location": {
723        "latitude": 411349992,
724        "longitude": -743694161
725    },
726    "name": ""
727}, {
728    "location": {
729        "latitude": 404839914,
730        "longitude": -744759616
731    },
732    "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
733}, {
734    "location": {
735        "latitude": 414638017,
736        "longitude": -745957854
737    },
738    "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
739}, {
740    "location": {
741        "latitude": 412127800,
742        "longitude": -740173578
743    },
744    "name": ""
745}, {
746    "location": {
747        "latitude": 401263460,
748        "longitude": -747964303
749    },
750    "name": ""
751}, {
752    "location": {
753        "latitude": 412843391,
754        "longitude": -749086026
755    },
756    "name": ""
757}, {
758    "location": {
759        "latitude": 418512773,
760        "longitude": -743067823
761    },
762    "name": ""
763}, {
764    "location": {
765        "latitude": 404318328,
766        "longitude": -740835638
767    },
768    "name": "42-102 Main Street, Belford, NJ 07718, USA"
769}, {
770    "location": {
771        "latitude": 419020746,
772        "longitude": -741172328
773    },
774    "name": ""
775}, {
776    "location": {
777        "latitude": 404080723,
778        "longitude": -746119569
779    },
780    "name": ""
781}, {
782    "location": {
783        "latitude": 401012643,
784        "longitude": -744035134
785    },
786    "name": ""
787}, {
788    "location": {
789        "latitude": 404306372,
790        "longitude": -741079661
791    },
792    "name": ""
793}, {
794    "location": {
795        "latitude": 403966326,
796        "longitude": -748519297
797    },
798    "name": ""
799}, {
800    "location": {
801        "latitude": 405002031,
802        "longitude": -748407866
803    },
804    "name": ""
805}, {
806    "location": {
807        "latitude": 409532885,
808        "longitude": -742200683
809    },
810    "name": ""
811}, {
812    "location": {
813        "latitude": 416851321,
814        "longitude": -742674555
815    },
816    "name": ""
817}, {
818    "location": {
819        "latitude": 406411633,
820        "longitude": -741722051
821    },
822    "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
823}, {
824    "location": {
825        "latitude": 413069058,
826        "longitude": -744597778
827    },
828    "name": "261 Van Sickle Road, Goshen, NY 10924, USA"
829}, {
830    "location": {
831        "latitude": 418465462,
832        "longitude": -746859398
833    },
834    "name": ""
835}, {
836    "location": {
837        "latitude": 411733222,
838        "longitude": -744228360
839    },
840    "name": ""
841}, {
842    "location": {
843        "latitude": 410248224,
844        "longitude": -747127767
845    },
846    "name": "3 Hasta Way, Newton, NJ 07860, USA"
847}]`)
848