diff --git a/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs index 1e07872488e..21a0be43d21 100644 --- a/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs +++ b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs @@ -9,6 +9,9 @@ using System.Threading.Tasks; namespace Examples { + /// + /// Utility methods for the route guide example. + /// public static class RouteGuideUtil { public const string DefaultFeaturesFile = "route_guide_db.json"; @@ -18,21 +21,63 @@ namespace Examples /// /// Indicates whether the given feature exists (i.e. has a valid name). /// - public static bool Exists(Feature feature) + public static bool Exists(this Feature feature) { return feature != null && (feature.Name.Length != 0); } - public static double GetLatitude(Point point) + public static double GetLatitude(this Point point) { return point.Latitude / CoordFactor; } - public static double GetLongitude(Point point) + public static double GetLongitude(this Point point) { return point.Longitude / CoordFactor; } + /// + /// Calculate the distance between two points using the "haversine" formula. + /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. + /// + /// the starting point + /// the end point + /// the distance between the points in meters + public static double GetDistance(this Point start, Point end) + { + double lat1 = start.GetLatitude(); + double lat2 = end.GetLatitude(); + double lon1 = start.GetLongitude(); + double lon2 = end.GetLongitude(); + int r = 6371000; // metres + double phi1 = ToRadians(lat1); + double phi2 = ToRadians(lat2); + double deltaPhi = ToRadians(lat2 - lat1); + double deltaLambda = ToRadians(lon2 - lon1); + + double a = Math.Sin(deltaPhi / 2) * Math.Sin(deltaPhi / 2) + Math.Cos(phi1) * Math.Cos(phi2) * Math.Sin(deltaLambda / 2) * Math.Sin(deltaLambda / 2); + double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); + + return r * c; + } + + /// + /// Returns true if rectangular area contains given point. + /// + public static bool Contains(this Rectangle rectangle, Point point) + { + int left = Math.Min(rectangle.Lo.Longitude, rectangle.Hi.Longitude); + int right = Math.Max(rectangle.Lo.Longitude, rectangle.Hi.Longitude); + int top = Math.Max(rectangle.Lo.Latitude, rectangle.Hi.Latitude); + int bottom = Math.Min(rectangle.Lo.Latitude, rectangle.Hi.Latitude); + return (point.Longitude >= left && point.Longitude <= right && point.Latitude >= bottom && point.Latitude <= top); + } + + private static double ToRadians(double val) + { + return (Math.PI / 180) * val; + } + /// /// Parses features from a JSON file. /// @@ -41,13 +86,13 @@ namespace Examples var features = new List(); var jsonFeatures = JsonConvert.DeserializeObject>(File.ReadAllText(filename)); - foreach(var jsonFeature in jsonFeatures) { - features.Add(Feature.CreateBuilder().SetName(jsonFeature.name).SetLocation( - Point.CreateBuilder() - .SetLongitude(jsonFeature.location.longitude) - .SetLatitude(jsonFeature.location.latitude).Build()).Build()); + features.Add(new Feature + { + Name = jsonFeature.name, + Location = new Point { Longitude = jsonFeature.location.longitude, Latitude = jsonFeature.location.latitude} + }); } return features; } diff --git a/examples/csharp/route_guide/RouteGuideClient/Program.cs b/examples/csharp/route_guide/RouteGuideClient/Program.cs index 2f1d631cce3..4ddb526585f 100644 --- a/examples/csharp/route_guide/RouteGuideClient/Program.cs +++ b/examples/csharp/route_guide/RouteGuideClient/Program.cs @@ -30,27 +30,24 @@ namespace Examples { Log("*** GetFeature: lat={0} lon={1}", lat, lon); - Point request = Point.CreateBuilder().SetLatitude(lat).SetLongitude(lon).Build(); + Point request = new Point { Latitude = lat, Longitude = lon }; Feature feature = client.GetFeature(request); - if (RouteGuideUtil.Exists(feature)) + if (feature.Exists()) { Log("Found feature called \"{0}\" at {1}, {2}", - feature.Name, - RouteGuideUtil.GetLatitude(feature.Location), - RouteGuideUtil.GetLongitude(feature.Location)); + feature.Name, feature.Location.GetLatitude(), feature.Location.GetLongitude()); } else { Log("Found no feature at {0}, {1}", - RouteGuideUtil.GetLatitude(feature.Location), - RouteGuideUtil.GetLongitude(feature.Location)); + feature.Location.GetLatitude(), feature.Location.GetLongitude()); } } catch (RpcException e) { Log("RPC failed " + e); - throw e; + throw; } } @@ -65,18 +62,20 @@ namespace Examples Log("*** ListFeatures: lowLat={0} lowLon={1} hiLat={2} hiLon={3}", lowLat, lowLon, hiLat, hiLon); - Rectangle request = - Rectangle.CreateBuilder() - .SetLo(Point.CreateBuilder().SetLatitude(lowLat).SetLongitude(lowLon).Build()) - .SetHi(Point.CreateBuilder().SetLatitude(hiLat).SetLongitude(hiLon).Build()).Build(); + Rectangle request = new Rectangle + { + Lo = new Point { Latitude = lowLat, Longitude = lowLon }, + Hi = new Point { Latitude = hiLat, Longitude = hiLon } + }; using (var call = client.ListFeatures(request)) { + var responseStream = call.ResponseStream; StringBuilder responseLog = new StringBuilder("Result: "); - while (await call.ResponseStream.MoveNext()) + while (await responseStream.MoveNext()) { - Feature feature = call.ResponseStream.Current; + Feature feature = responseStream.Current; responseLog.Append(feature.ToString()); } Log(responseLog.ToString()); @@ -85,7 +84,7 @@ namespace Examples catch (RpcException e) { Log("RPC failed " + e); - throw e; + throw; } } @@ -107,8 +106,7 @@ namespace Examples { int index = rand.Next(features.Count); Point point = features[index].Location; - Log("Visiting point {0}, {1}", RouteGuideUtil.GetLatitude(point), - RouteGuideUtil.GetLongitude(point)); + Log("Visiting point {0}, {1}", point.GetLatitude(), point.GetLongitude()); await call.RequestStream.WriteAsync(point); @@ -117,7 +115,7 @@ namespace Examples } await call.RequestStream.CompleteAsync(); - RouteSummary summary = await call.Result; + RouteSummary summary = await call.ResponseAsync; Log("Finished trip with {0} points. Passed {1} features. " + "Travelled {2} meters. It took {3} seconds.", summary.PointCount, summary.FeatureCount, summary.Distance, summary.ElapsedTime); @@ -128,7 +126,7 @@ namespace Examples catch (RpcException e) { Log("RPC failed", e); - throw e; + throw; } } @@ -141,8 +139,13 @@ namespace Examples try { Log("*** RouteChat"); - var requests = - new List { NewNote("First message", 0, 0), NewNote("Second message", 0, 1), NewNote("Third message", 1, 0), NewNote("Fourth message", 1, 1) }; + var requests = new List + { + NewNote("First message", 0, 0), + NewNote("Second message", 0, 1), + NewNote("Third message", 1, 0), + NewNote("Fourth message", 0, 0) + }; using (var call = client.RouteChat()) { @@ -172,7 +175,7 @@ namespace Examples catch (RpcException e) { Log("RPC failed", e); - throw e; + throw; } } @@ -188,36 +191,37 @@ namespace Examples private RouteNote NewNote(string message, int lat, int lon) { - return RouteNote.CreateBuilder().SetMessage(message).SetLocation( - Point.CreateBuilder().SetLatitude(lat).SetLongitude(lat).Build()).Build(); + return new RouteNote + { + Message = message, + Location = new Point { Latitude = lat, Longitude = lon } + }; } } static void Main(string[] args) { - GrpcEnvironment.Initialize(); + var channel = new Channel("127.0.0.1:50052", Credentials.Insecure); + var client = new RouteGuideClient(RouteGuide.NewClient(channel)); - using (Channel channel = new Channel("127.0.0.1:50052")) - { - var client = new RouteGuideClient(RouteGuide.NewStub(channel)); - - // Looking for a valid feature - client.GetFeature(409146138, -746188906); + // Looking for a valid feature + client.GetFeature(409146138, -746188906); - // Feature missing. - client.GetFeature(0, 0); + // Feature missing. + client.GetFeature(0, 0); - // Looking for features between 40, -75 and 42, -73. - client.ListFeatures(400000000, -750000000, 420000000, -730000000).Wait(); + // Looking for features between 40, -75 and 42, -73. + client.ListFeatures(400000000, -750000000, 420000000, -730000000).Wait(); - // Record a few randomly selected points from the features file. - client.RecordRoute(RouteGuideUtil.ParseFeatures(RouteGuideUtil.DefaultFeaturesFile), 10).Wait(); + // Record a few randomly selected points from the features file. + client.RecordRoute(RouteGuideUtil.ParseFeatures(RouteGuideUtil.DefaultFeaturesFile), 10).Wait(); - // Send and receive some notes. - client.RouteChat().Wait(); - } + // Send and receive some notes. + client.RouteChat().Wait(); - GrpcEnvironment.Shutdown(); + channel.ShutdownAsync().Wait(); + Console.WriteLine("Press any key to exit..."); + Console.ReadKey(); } } } diff --git a/examples/csharp/route_guide/RouteGuideServer/Program.cs b/examples/csharp/route_guide/RouteGuideServer/Program.cs index 68efce9f4ad..0a4d73f391d 100644 --- a/examples/csharp/route_guide/RouteGuideServer/Program.cs +++ b/examples/csharp/route_guide/RouteGuideServer/Program.cs @@ -11,20 +11,22 @@ namespace Examples { static void Main(string[] args) { + const int Port = 50052; + var features = RouteGuideUtil.ParseFeatures(RouteGuideUtil.DefaultFeaturesFile); - GrpcEnvironment.Initialize(); - Server server = new Server(); - server.AddServiceDefinition(RouteGuide.BindService(new RouteGuideImpl(features))); - int port = server.AddListeningPort("localhost", 50052); + Server server = new Server + { + Services = { RouteGuide.BindService(new RouteGuideImpl(features)) }, + Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) } + }; server.Start(); - Console.WriteLine("RouteGuide server listening on port " + port); + Console.WriteLine("RouteGuide server listening on port " + Port); Console.WriteLine("Press any key to stop the server..."); Console.ReadKey(); server.ShutdownAsync().Wait(); - GrpcEnvironment.Shutdown(); } } } diff --git a/examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs b/examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs index 1de37e38691..65355631ec6 100644 --- a/examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs +++ b/examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Grpc.Core.Utils; + namespace Examples { /// @@ -14,8 +16,8 @@ namespace Examples public class RouteGuideImpl : RouteGuide.IRouteGuide { readonly List features; - private readonly ConcurrentDictionary> routeNotes = - new ConcurrentDictionary>(); + readonly object myLock = new object(); + readonly Dictionary> routeNotes = new Dictionary>(); public RouteGuideImpl(List features) { @@ -26,7 +28,7 @@ namespace Examples /// Gets the feature at the requested point. If no feature at that location /// exists, an unnammed feature is returned at the provided location. /// - public Task GetFeature(Grpc.Core.ServerCallContext context, Point request) + public Task GetFeature(Point request, Grpc.Core.ServerCallContext context) { return Task.FromResult(CheckFeature(request)); } @@ -34,34 +36,17 @@ namespace Examples /// /// Gets all features contained within the given bounding rectangle. /// - public async Task ListFeatures(Grpc.Core.ServerCallContext context, Rectangle request, Grpc.Core.IServerStreamWriter responseStream) + public async Task ListFeatures(Rectangle request, Grpc.Core.IServerStreamWriter responseStream, Grpc.Core.ServerCallContext context) { - int left = Math.Min(request.Lo.Longitude, request.Hi.Longitude); - int right = Math.Max(request.Lo.Longitude, request.Hi.Longitude); - int top = Math.Max(request.Lo.Latitude, request.Hi.Latitude); - int bottom = Math.Min(request.Lo.Latitude, request.Hi.Latitude); - - foreach (var feature in features) - { - if (!RouteGuideUtil.Exists(feature)) - { - continue; - } - - int lat = feature.Location.Latitude; - int lon = feature.Location.Longitude; - if (lon >= left && lon <= right && lat >= bottom && lat <= top) - { - await responseStream.WriteAsync(feature); - } - } + var responses = features.FindAll( (feature) => feature.Exists() && request.Contains(feature.Location) ); + await responseStream.WriteAllAsync(responses); } /// /// Gets a stream of points, and responds with statistics about the "trip": number of points, /// number of known features visited, total distance traveled, and total time spent. /// - public async Task RecordRoute(Grpc.Core.ServerCallContext context, Grpc.Core.IAsyncStreamReader requestStream) + public async Task RecordRoute(Grpc.Core.IAsyncStreamReader requestStream, Grpc.Core.ServerCallContext context) { int pointCount = 0; int featureCount = 0; @@ -74,61 +59,61 @@ namespace Examples { var point = requestStream.Current; pointCount++; - if (RouteGuideUtil.Exists(CheckFeature(point))) + if (CheckFeature(point).Exists()) { featureCount++; } if (previous != null) { - distance += (int) CalcDistance(previous, point); + distance += (int) previous.GetDistance(point); } previous = point; } stopwatch.Stop(); - return RouteSummary.CreateBuilder().SetPointCount(pointCount) - .SetFeatureCount(featureCount).SetDistance(distance) - .SetElapsedTime((int) (stopwatch.ElapsedMilliseconds / 1000)).Build(); + + return new RouteSummary + { + PointCount = pointCount, + FeatureCount = featureCount, + Distance = distance, + ElapsedTime = (int)(stopwatch.ElapsedMilliseconds / 1000) + }; } /// /// Receives a stream of message/location pairs, and responds with a stream of all previous /// messages at each of those locations. /// - public async Task RouteChat(Grpc.Core.ServerCallContext context, Grpc.Core.IAsyncStreamReader requestStream, Grpc.Core.IServerStreamWriter responseStream) + public async Task RouteChat(Grpc.Core.IAsyncStreamReader requestStream, Grpc.Core.IServerStreamWriter responseStream, Grpc.Core.ServerCallContext context) { while (await requestStream.MoveNext()) { var note = requestStream.Current; - List notes = GetOrCreateNotes(note.Location); - - List prevNotes; - lock (notes) - { - prevNotes = new List(notes); - } - + List prevNotes = AddNoteForLocation(note.Location, note); foreach (var prevNote in prevNotes) { await responseStream.WriteAsync(prevNote); - } - - lock (notes) - { - notes.Add(note); } } } - /// - /// Get the notes list for the given location. If missing, create it. + /// Adds a note for location and returns a list of pre-existing notes for that location (not containing the newly added note). /// - private List GetOrCreateNotes(Point location) + private List AddNoteForLocation(Point location, RouteNote note) { - List notes = new List(); - routeNotes.TryAdd(location, notes); - return routeNotes[location]; + lock (myLock) + { + List notes; + if (!routeNotes.TryGetValue(location, out notes)) { + notes = new List(); + routeNotes.Add(location, notes); + } + var preexistingNotes = new List(notes); + notes.Add(note); + return preexistingNotes; + } } /// @@ -138,47 +123,13 @@ namespace Examples /// The feature object at the point Note that an empty name indicates no feature. private Feature CheckFeature(Point location) { - foreach (var feature in features) + var result = features.FirstOrDefault((feature) => feature.Location.Equals(location)); + if (result == null) { - if (feature.Location.Latitude == location.Latitude - && feature.Location.Longitude == location.Longitude) - { - return feature; - } + // No feature was found, return an unnamed feature. + return new Feature { Name = "", Location = location }; } - - // No feature was found, return an unnamed feature. - return Feature.CreateBuilder().SetName("").SetLocation(location).Build(); - } - - /// - /// Calculate the distance between two points using the "haversine" formula. - /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. - /// - /// the starting point - /// the end point - /// the distance between the points in meters - private static double CalcDistance(Point start, Point end) - { - double lat1 = RouteGuideUtil.GetLatitude(start); - double lat2 = RouteGuideUtil.GetLatitude(end); - double lon1 = RouteGuideUtil.GetLongitude(start); - double lon2 = RouteGuideUtil.GetLongitude(end); - int r = 6371000; // metres - double φ1 = ToRadians(lat1); - double φ2 = ToRadians(lat2); - double Δφ = ToRadians(lat2 - lat1); - double Δλ = ToRadians(lon2 - lon1); - - double a = Math.Sin(Δφ / 2) * Math.Sin(Δφ / 2) + Math.Cos(φ1) * Math.Cos(φ2) * Math.Sin(Δλ / 2) * Math.Sin(Δλ / 2); - double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); - - return r * c; - } - - private static double ToRadians(double val) - { - return (Math.PI / 180) * val; + return result; } } }