server.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. //go:generate protoc -I ../routeguide --go_out=plugins=grpc:../routeguide ../routeguide/route_guide.proto
  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.
  23. package main
  24. import (
  25. "context"
  26. "encoding/json"
  27. "flag"
  28. "fmt"
  29. "io"
  30. "io/ioutil"
  31. "log"
  32. "math"
  33. "net"
  34. "sync"
  35. "time"
  36. "google.golang.org/grpc"
  37. "google.golang.org/grpc/credentials"
  38. "google.golang.org/grpc/testdata"
  39. "github.com/golang/protobuf/proto"
  40. pb "google.golang.org/grpc/examples/route_guide/routeguide"
  41. )
  42. var (
  43. tls = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP")
  44. certFile = flag.String("cert_file", "", "The TLS cert file")
  45. keyFile = flag.String("key_file", "", "The TLS key file")
  46. jsonDBFile = flag.String("json_db_file", "testdata/route_guide_db.json", "A json file containing a list of features")
  47. port = flag.Int("port", 10000, "The server port")
  48. )
  49. type routeGuideServer struct {
  50. savedFeatures []*pb.Feature // read-only after initialized
  51. mu sync.Mutex // protects routeNotes
  52. routeNotes map[string][]*pb.RouteNote
  53. }
  54. // GetFeature returns the feature at the given point.
  55. func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
  56. for _, feature := range s.savedFeatures {
  57. if proto.Equal(feature.Location, point) {
  58. return feature, nil
  59. }
  60. }
  61. // No feature was found, return an unnamed feature
  62. return &pb.Feature{Location: point}, nil
  63. }
  64. // ListFeatures lists all features contained within the given bounding Rectangle.
  65. func (s *routeGuideServer) ListFeatures(rect *pb.Rectangle, stream pb.RouteGuide_ListFeaturesServer) error {
  66. for _, feature := range s.savedFeatures {
  67. if inRange(feature.Location, rect) {
  68. if err := stream.Send(feature); err != nil {
  69. return err
  70. }
  71. }
  72. }
  73. return nil
  74. }
  75. // RecordRoute records a route composited of a sequence of points.
  76. //
  77. // It gets a stream of points, and responds with statistics about the "trip":
  78. // number of points, number of known features visited, total distance traveled, and
  79. // total time spent.
  80. func (s *routeGuideServer) RecordRoute(stream pb.RouteGuide_RecordRouteServer) error {
  81. var pointCount, featureCount, distance int32
  82. var lastPoint *pb.Point
  83. startTime := time.Now()
  84. for {
  85. point, err := stream.Recv()
  86. if err == io.EOF {
  87. endTime := time.Now()
  88. return stream.SendAndClose(&pb.RouteSummary{
  89. PointCount: pointCount,
  90. FeatureCount: featureCount,
  91. Distance: distance,
  92. ElapsedTime: int32(endTime.Sub(startTime).Seconds()),
  93. })
  94. }
  95. if err != nil {
  96. return err
  97. }
  98. pointCount++
  99. for _, feature := range s.savedFeatures {
  100. if proto.Equal(feature.Location, point) {
  101. featureCount++
  102. }
  103. }
  104. if lastPoint != nil {
  105. distance += calcDistance(lastPoint, point)
  106. }
  107. lastPoint = point
  108. }
  109. }
  110. // RouteChat receives a stream of message/location pairs, and responds with a stream of all
  111. // previous messages at each of those locations.
  112. func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error {
  113. for {
  114. in, err := stream.Recv()
  115. if err == io.EOF {
  116. return nil
  117. }
  118. if err != nil {
  119. return err
  120. }
  121. key := serialize(in.Location)
  122. s.mu.Lock()
  123. s.routeNotes[key] = append(s.routeNotes[key], in)
  124. // Note: this copy prevents blocking other clients while serving this one.
  125. // We don't need to do a deep copy, because elements in the slice are
  126. // insert-only and never modified.
  127. rn := make([]*pb.RouteNote, len(s.routeNotes[key]))
  128. copy(rn, s.routeNotes[key])
  129. s.mu.Unlock()
  130. for _, note := range rn {
  131. if err := stream.Send(note); err != nil {
  132. return err
  133. }
  134. }
  135. }
  136. }
  137. // loadFeatures loads features from a JSON file.
  138. func (s *routeGuideServer) loadFeatures(filePath string) {
  139. file, err := ioutil.ReadFile(filePath)
  140. if err != nil {
  141. log.Fatalf("Failed to load default features: %v", err)
  142. }
  143. if err := json.Unmarshal(file, &s.savedFeatures); err != nil {
  144. log.Fatalf("Failed to load default features: %v", err)
  145. }
  146. }
  147. func toRadians(num float64) float64 {
  148. return num * math.Pi / float64(180)
  149. }
  150. // calcDistance calculates the distance between two points using the "haversine" formula.
  151. // The formula is based on http://mathforum.org/library/drmath/view/51879.html.
  152. func calcDistance(p1 *pb.Point, p2 *pb.Point) int32 {
  153. const CordFactor float64 = 1e7
  154. const R float64 = float64(6371000) // earth radius in metres
  155. lat1 := toRadians(float64(p1.Latitude) / CordFactor)
  156. lat2 := toRadians(float64(p2.Latitude) / CordFactor)
  157. lng1 := toRadians(float64(p1.Longitude) / CordFactor)
  158. lng2 := toRadians(float64(p2.Longitude) / CordFactor)
  159. dlat := lat2 - lat1
  160. dlng := lng2 - lng1
  161. a := math.Sin(dlat/2)*math.Sin(dlat/2) +
  162. math.Cos(lat1)*math.Cos(lat2)*
  163. math.Sin(dlng/2)*math.Sin(dlng/2)
  164. c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a))
  165. distance := R * c
  166. return int32(distance)
  167. }
  168. func inRange(point *pb.Point, rect *pb.Rectangle) bool {
  169. left := math.Min(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
  170. right := math.Max(float64(rect.Lo.Longitude), float64(rect.Hi.Longitude))
  171. top := math.Max(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))
  172. bottom := math.Min(float64(rect.Lo.Latitude), float64(rect.Hi.Latitude))
  173. if float64(point.Longitude) >= left &&
  174. float64(point.Longitude) <= right &&
  175. float64(point.Latitude) >= bottom &&
  176. float64(point.Latitude) <= top {
  177. return true
  178. }
  179. return false
  180. }
  181. func serialize(point *pb.Point) string {
  182. return fmt.Sprintf("%d %d", point.Latitude, point.Longitude)
  183. }
  184. func newServer() *routeGuideServer {
  185. s := &routeGuideServer{routeNotes: make(map[string][]*pb.RouteNote)}
  186. s.loadFeatures(*jsonDBFile)
  187. return s
  188. }
  189. func main() {
  190. flag.Parse()
  191. lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", *port))
  192. if err != nil {
  193. log.Fatalf("failed to listen: %v", err)
  194. }
  195. var opts []grpc.ServerOption
  196. if *tls {
  197. if *certFile == "" {
  198. *certFile = testdata.Path("server1.pem")
  199. }
  200. if *keyFile == "" {
  201. *keyFile = testdata.Path("server1.key")
  202. }
  203. creds, err := credentials.NewServerTLSFromFile(*certFile, *keyFile)
  204. if err != nil {
  205. log.Fatalf("Failed to generate credentials %v", err)
  206. }
  207. opts = []grpc.ServerOption{grpc.Creds(creds)}
  208. }
  209. grpcServer := grpc.NewServer(opts...)
  210. pb.RegisterRouteGuideServer(grpcServer, newServer())
  211. grpcServer.Serve(lis)
  212. }