Skip to content
Snippets Groups Projects
Commit 998eb9bc authored by Jan Tattermusch's avatar Jan Tattermusch
Browse files

populate server context

parent 5bbd8186
No related branches found
No related tags found
No related merge requests found
......@@ -182,6 +182,19 @@ namespace Grpc.Core.Tests
}).Wait();
}
[Test]
public void AsyncUnaryCall_EchoMetadata()
{
var metadata = new Metadata
{
new Metadata.Entry("asciiHeader", "abcdefg"),
new Metadata.Entry("binaryHeader-bin", new byte[] { 1, 2, 3, 0, 0xff } ),
};
var call = new Call<string, string>(ServiceName, EchoMethod, channel, metadata);
var result = Calls.AsyncUnaryCall(call, "ABC", CancellationToken.None).Result;
Assert.AreEqual("ABC", result);
}
[Test]
public void UnaryCall_DisposedChannel()
{
......@@ -216,10 +229,17 @@ namespace Grpc.Core.Tests
private static async Task<string> EchoHandler(ServerCallContext context, string request)
{
foreach (Metadata.Entry metadataEntry in context.RequestHeaders)
{
Console.WriteLine("Echoing header " + metadataEntry.Key + " as trailer");
context.ResponseTrailers.Add(metadataEntry);
}
if (request == "THROW")
{
throw new Exception("This was thrown on purpose by a test");
}
return request;
}
......
......@@ -58,6 +58,19 @@ namespace Grpc.Core.Internal.Tests
Assert.AreEqual(Timespec.NativeSize, Marshal.SizeOf(typeof(Timespec)));
}
[Test]
public void ToDateTime()
{
Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
new Timespec(IntPtr.Zero, 0).ToDateTime());
Assert.AreEqual(new DateTime(1970, 1, 1, 0, 0, 10, DateTimeKind.Utc).AddTicks(50),
new Timespec(new IntPtr(10), 5000).ToDateTime());
Assert.AreEqual(new DateTime(2015, 7, 21, 4, 21, 48, DateTimeKind.Utc),
new Timespec(new IntPtr(1437452508), 0).ToDateTime());
}
[Test]
public void Add()
{
......
......@@ -34,6 +34,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
......@@ -70,15 +71,16 @@ namespace Grpc.Core.Internal
var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status = Status.DefaultSuccess;
Status status;
try
{
Preconditions.CheckArgument(await requestStream.MoveNext());
var request = requestStream.Current;
// TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated.
Preconditions.CheckArgument(!await requestStream.MoveNext());
var context = new ServerCallContext(); // TODO(jtattermusch): initialize the context
var context = HandlerUtils.NewContext(newRpc);
var result = await handler(context, request);
status = context.Status;
await responseStream.WriteAsync(result);
}
catch (Exception e)
......@@ -123,7 +125,7 @@ namespace Grpc.Core.Internal
var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
Status status = Status.DefaultSuccess;
Status status;
try
{
Preconditions.CheckArgument(await requestStream.MoveNext());
......@@ -131,8 +133,9 @@ namespace Grpc.Core.Internal
// TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated.
Preconditions.CheckArgument(!await requestStream.MoveNext());
var context = new ServerCallContext(); // TODO(jtattermusch): initialize the context
var context = HandlerUtils.NewContext(newRpc);
await handler(context, request, responseStream);
status = context.Status;
}
catch (Exception e)
{
......@@ -176,12 +179,13 @@ namespace Grpc.Core.Internal
var finishedTask = asyncCall.ServerSideCallAsync();
var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
var context = new ServerCallContext(); // TODO(jtattermusch): initialize the context
var context = HandlerUtils.NewContext(newRpc);
Status status = Status.DefaultSuccess;
Status status;
try
{
var result = await handler(context, requestStream);
status = context.Status;
try
{
await responseStream.WriteAsync(result);
......@@ -233,12 +237,13 @@ namespace Grpc.Core.Internal
var finishedTask = asyncCall.ServerSideCallAsync();
var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall);
var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall);
var context = new ServerCallContext(); // TODO(jtattermusch): initialize the context
var context = HandlerUtils.NewContext(newRpc);
Status status = Status.DefaultSuccess;
Status status;
try
{
await handler(context, requestStream, responseStream);
status = context.Status;
}
catch (Exception e)
{
......@@ -284,5 +289,12 @@ namespace Grpc.Core.Internal
// TODO(jtattermusch): what is the right status code here?
return new Status(StatusCode.Unknown, "Exception was thrown by handler.");
}
public static ServerCallContext NewContext(ServerRpcNew newRpc)
{
return new ServerCallContext(
newRpc.Method, newRpc.Host, newRpc.Deadline.ToDateTime(),
newRpc.RequestMetadata, CancellationToken.None);
}
}
}
......@@ -43,6 +43,8 @@ namespace Grpc.Core.Internal
const int NanosPerSecond = 1000 * 1000 * 1000;
const int NanosPerTick = 100;
static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
[DllImport("grpc_csharp_ext.dll")]
static extern Timespec gprsharp_now();
......@@ -52,6 +54,13 @@ namespace Grpc.Core.Internal
[DllImport("grpc_csharp_ext.dll")]
static extern int gprsharp_sizeof_timespec();
public Timespec(IntPtr tv_sec, int tv_nsec)
{
this.tv_sec = tv_sec;
this.tv_nsec = tv_nsec;
this.clock_type = GPRClockType.Realtime;
}
// NOTE: on linux 64bit sizeof(gpr_timespec) = 16, on windows 32bit sizeof(gpr_timespec) = 8
// so IntPtr seems to have the right size to work on both.
public System.IntPtr tv_sec;
......@@ -76,6 +85,11 @@ namespace Grpc.Core.Internal
return gprsharp_now();
}
}
public DateTime ToDateTime()
{
return UnixEpoch.AddTicks(tv_sec.ToInt64() * (NanosPerSecond / NanosPerTick) + tv_nsec / NanosPerTick);
}
internal static int NativeSize
{
......
......@@ -220,6 +220,12 @@ namespace Grpc.Core
return value;
}
}
public override string ToString()
{
return string.Format("[Entry: key={0}, value={1}]", Key, Value);
}
}
}
}
......@@ -33,6 +33,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace Grpc.Core
......@@ -42,14 +43,94 @@ namespace Grpc.Core
/// </summary>
public sealed class ServerCallContext
{
// TODO(jtattermusch): add cancellationToken
// TODO(jtattermusch): expose method to send initial metadata back to client
// TODO(jtattermusch): add deadline info
// TODO(jtattermusch): allow setting status and trailing metadata to send after handler completes.
// TODO(jtattermusch): expose initial metadata sent by client for reading
private readonly string method;
private readonly string host;
private readonly DateTime deadline;
private readonly Metadata requestHeaders;
private readonly CancellationToken cancellationToken;
// TODO(jtattermusch): expose method to send initial metadata back to client
private Status status = Status.DefaultSuccess;
private readonly Metadata responseTrailers = new Metadata();
// TODO(jtattermusch): allow setting status and trailing metadata to send after handler completes.
public ServerCallContext(string method, string host, DateTime deadline, Metadata requestHeaders, CancellationToken cancellationToken)
{
this.method = method;
this.host = host;
this.deadline = deadline;
this.requestHeaders = requestHeaders;
this.cancellationToken = cancellationToken;
}
/// <summary> Name of method called in this RPC. </summary>
public string Method
{
get
{
return this.method;
}
}
/// <summary> Name of host called in this RPC. </summary>
public string Host
{
get
{
return this.host;
}
}
/// <summary> Deadline for this RPC. </summary>
public DateTime Deadline
{
get
{
return this.deadline;
}
}
/// <summary> Initial metadata sent by client. </summary>
public Metadata RequestHeaders
{
get
{
return this.requestHeaders;
}
}
// TODO(jtattermusch): support signalling cancellation.
/// <summary> Cancellation token signals when call is cancelled. </summary>
public CancellationToken CancellationToken
{
get
{
return this.cancellationToken;
}
}
/// <summary> Trailers to send back to client after RPC finishes.</summary>
public Metadata ResponseTrailers
{
get
{
return this.responseTrailers;
}
}
/// <summary> Status to send back to client after RPC finishes.</summary>
public Status Status
{
get
{
return this.status;
}
set
{
status = value;
}
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment