aboutsummaryrefslogtreecommitdiffhomepage
path: root/examples/csharp
diff options
context:
space:
mode:
authorGravatar Jan Tattermusch <jtattermusch@google.com>2015-08-31 10:27:27 -0700
committerGravatar Jan Tattermusch <jtattermusch@google.com>2015-09-02 12:59:00 -0700
commit121c4d1221f6b6f32288cb5ee9bca3e221a9c4d3 (patch)
treecbed8aef9162ca4d09cfed6d5c6e98235d519fad /examples/csharp
parent97eaec1cdc28174f1f5bd2bd74aba19f0869d75e (diff)
polishing route_guide example
Diffstat (limited to 'examples/csharp')
-rw-r--r--examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs61
-rw-r--r--examples/csharp/route_guide/RouteGuideClient/Program.cs86
-rw-r--r--examples/csharp/route_guide/RouteGuideServer/Program.cs14
-rw-r--r--examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs127
4 files changed, 145 insertions, 143 deletions
diff --git a/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs
index 1e07872488..21a0be43d2 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
{
+ /// <summary>
+ /// Utility methods for the route guide example.
+ /// </summary>
public static class RouteGuideUtil
{
public const string DefaultFeaturesFile = "route_guide_db.json";
@@ -18,22 +21,64 @@ namespace Examples
/// <summary>
/// Indicates whether the given feature exists (i.e. has a valid name).
/// </summary>
- 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;
}
/// <summary>
+ /// Calculate the distance between two points using the "haversine" formula.
+ /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
+ /// </summary>
+ /// <param name="start">the starting point</param>
+ /// <param name="end">the end point</param>
+ /// <returns>the distance between the points in meters</returns>
+ 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;
+ }
+
+ /// <summary>
+ /// Returns <c>true</c> if rectangular area contains given point.
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
/// Parses features from a JSON file.
/// </summary>
public static List<Feature> ParseFeatures(string filename)
@@ -41,13 +86,13 @@ namespace Examples
var features = new List<Feature>();
var jsonFeatures = JsonConvert.DeserializeObject<List<JsonFeature>>(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 2f1d631cce..4ddb526585 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<RouteNote> { NewNote("First message", 0, 0), NewNote("Second message", 0, 1), NewNote("Third message", 1, 0), NewNote("Fourth message", 1, 1) };
+ var requests = new List<RouteNote>
+ {
+ 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 68efce9f4a..0a4d73f391 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 1de37e3869..65355631ec 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
{
/// <summary>
@@ -14,8 +16,8 @@ namespace Examples
public class RouteGuideImpl : RouteGuide.IRouteGuide
{
readonly List<Feature> features;
- private readonly ConcurrentDictionary<Point, List<RouteNote>> routeNotes =
- new ConcurrentDictionary<Point, List<RouteNote>>();
+ readonly object myLock = new object();
+ readonly Dictionary<Point, List<RouteNote>> routeNotes = new Dictionary<Point, List<RouteNote>>();
public RouteGuideImpl(List<Feature> 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.
/// </summary>
- public Task<Feature> GetFeature(Grpc.Core.ServerCallContext context, Point request)
+ public Task<Feature> GetFeature(Point request, Grpc.Core.ServerCallContext context)
{
return Task.FromResult(CheckFeature(request));
}
@@ -34,34 +36,17 @@ namespace Examples
/// <summary>
/// Gets all features contained within the given bounding rectangle.
/// </summary>
- public async Task ListFeatures(Grpc.Core.ServerCallContext context, Rectangle request, Grpc.Core.IServerStreamWriter<Feature> responseStream)
+ public async Task ListFeatures(Rectangle request, Grpc.Core.IServerStreamWriter<Feature> 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);
}
/// <summary>
/// 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.
/// </summary>
- public async Task<RouteSummary> RecordRoute(Grpc.Core.ServerCallContext context, Grpc.Core.IAsyncStreamReader<Point> requestStream)
+ public async Task<RouteSummary> RecordRoute(Grpc.Core.IAsyncStreamReader<Point> 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)
+ };
}
/// <summary>
/// Receives a stream of message/location pairs, and responds with a stream of all previous
/// messages at each of those locations.
/// </summary>
- public async Task RouteChat(Grpc.Core.ServerCallContext context, Grpc.Core.IAsyncStreamReader<RouteNote> requestStream, Grpc.Core.IServerStreamWriter<RouteNote> responseStream)
+ public async Task RouteChat(Grpc.Core.IAsyncStreamReader<RouteNote> requestStream, Grpc.Core.IServerStreamWriter<RouteNote> responseStream, Grpc.Core.ServerCallContext context)
{
while (await requestStream.MoveNext())
{
var note = requestStream.Current;
- List<RouteNote> notes = GetOrCreateNotes(note.Location);
-
- List<RouteNote> prevNotes;
- lock (notes)
- {
- prevNotes = new List<RouteNote>(notes);
- }
-
+ List<RouteNote> prevNotes = AddNoteForLocation(note.Location, note);
foreach (var prevNote in prevNotes)
{
await responseStream.WriteAsync(prevNote);
- }
-
- lock (notes)
- {
- notes.Add(note);
}
}
}
-
/// <summary>
- /// 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).
/// </summary>
- private List<RouteNote> GetOrCreateNotes(Point location)
+ private List<RouteNote> AddNoteForLocation(Point location, RouteNote note)
{
- List<RouteNote> notes = new List<RouteNote>();
- routeNotes.TryAdd(location, notes);
- return routeNotes[location];
+ lock (myLock)
+ {
+ List<RouteNote> notes;
+ if (!routeNotes.TryGetValue(location, out notes)) {
+ notes = new List<RouteNote>();
+ routeNotes.Add(location, notes);
+ }
+ var preexistingNotes = new List<RouteNote>(notes);
+ notes.Add(note);
+ return preexistingNotes;
+ }
}
/// <summary>
@@ -138,47 +123,13 @@ namespace Examples
/// <returns>The feature object at the point Note that an empty name indicates no feature.</returns>
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();
- }
-
- /// <summary>
- /// Calculate the distance between two points using the "haversine" formula.
- /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
- /// </summary>
- /// <param name="start">the starting point</param>
- /// <param name="end">the end point</param>
- /// <returns>the distance between the points in meters</returns>
- 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;
}
}
}