Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor the codes for binding services #828

Merged
merged 5 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,25 @@ namespace MagicOnion.Internal
{
internal static class GrpcMethodHelper
{
public sealed class MagicOnionMethod<TRequest, TResponse, TRawRequest, TRawResponse>
{
public Method<TRawRequest, TRawResponse> Method { get; }

public MagicOnionMethod(Method<TRawRequest, TRawResponse> method)
{
Method = method;
}

public TRawRequest ToRawRequest(TRequest obj) => ToRaw<TRequest, TRawRequest>(obj);
public TRawResponse ToRawResponse(TResponse obj) => ToRaw<TResponse, TRawResponse>(obj);
public TRequest FromRawRequest(TRawRequest obj) => FromRaw<TRawRequest, TRequest>(obj);
public TResponse FromRawResponse(TRawResponse obj) => FromRaw<TRawResponse, TResponse>(obj);

static TRaw ToRaw<T, TRaw>(T obj)
{
if (typeof(TRaw) == typeof(Box<T>))
{
return (TRaw)(object)Box.Create(obj);
}
else
{
return DangerousDummyNull.GetObjectOrDummyNull(Unsafe.As<T, TRaw>(ref obj));
}
}

static T FromRaw<TRaw, T>(TRaw obj)
{
if (typeof(TRaw) == typeof(Box<T>))
{
return ((Box<T>)(object)obj!).Value;
}
else
{
return DangerousDummyNull.GetObjectOrDefault<T>(obj!);
}
}
}

public static MagicOnionMethod<Nil, TResponse, Box<Nil>, TRawResponse> CreateMethod<TResponse, TRawResponse>(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TRaw ToRaw<T, TRaw>(T obj)
=> (obj is ValueType)
? (TRaw)(object)Box.Create(obj)
: DangerousDummyNull.GetObjectOrDummyNull(Unsafe.As<T, TRaw>(ref obj));

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T FromRaw<TRaw, T>(TRaw obj)
=> (obj is Box<T> boxed)
? boxed.Value
: DangerousDummyNull.GetObjectOrDefault<T>(obj!);

public static Method<Box<Nil>, TRawResponse> CreateMethod<TResponse, TRawResponse>(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer)
where TRawResponse : class
{
return CreateMethod<TResponse, TRawResponse>(methodType, serviceName, name, null, messageSerializer);
}
public static MagicOnionMethod<Nil, TResponse, Box<Nil>, TRawResponse> CreateMethod<TResponse, TRawResponse>(MethodType methodType, string serviceName, string name, MethodInfo? methodInfo, IMagicOnionSerializer messageSerializer)
public static Method<Box<Nil>, TRawResponse> CreateMethod<TResponse, TRawResponse>(MethodType methodType, string serviceName, string name, MethodInfo? methodInfo, IMagicOnionSerializer messageSerializer)
where TRawResponse : class
{
// WORKAROUND: Prior to MagicOnion 5.0, the request type for the parameter-less method was byte[].
// DynamicClient sends byte[], but GeneratedClient sends Nil, which is incompatible,
Expand All @@ -62,20 +37,24 @@ public static MagicOnionMethod<Nil, TResponse, Box<Nil>, TRawResponse> CreateMet
? CreateBoxedMarshaller<TResponse>(messageSerializer)
: (object)CreateMarshaller<TResponse>(messageSerializer);

return new MagicOnionMethod<Nil, TResponse, Box<Nil>, TRawResponse>(new Method<Box<Nil>, TRawResponse>(
return new Method<Box<Nil>, TRawResponse>(
methodType,
serviceName,
name,
IgnoreNilMarshaller,
(Marshaller<TRawResponse>)responseMarshaller
));
);
}

public static MagicOnionMethod<TRequest, TResponse, TRawRequest, TRawResponse> CreateMethod<TRequest, TResponse, TRawRequest, TRawResponse>(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer)
public static Method<TRawRequest, TRawResponse> CreateMethod<TRequest, TResponse, TRawRequest, TRawResponse>(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer)
where TRawRequest : class
where TRawResponse : class
{
return CreateMethod<TRequest, TResponse, TRawRequest, TRawResponse>(methodType, serviceName, name, null, messageSerializer);
}
public static MagicOnionMethod<TRequest, TResponse, TRawRequest, TRawResponse> CreateMethod<TRequest, TResponse, TRawRequest, TRawResponse>(MethodType methodType, string serviceName, string name, MethodInfo? methodInfo, IMagicOnionSerializer messageSerializer)
public static Method<TRawRequest, TRawResponse> CreateMethod<TRequest, TResponse, TRawRequest, TRawResponse>(MethodType methodType, string serviceName, string name, MethodInfo? methodInfo, IMagicOnionSerializer messageSerializer)
where TRawRequest : class
where TRawResponse : class
{
var isMethodRequestTypeBoxed = typeof(TRequest).IsValueType;
var isMethodResponseTypeBoxed = typeof(TResponse).IsValueType;
Expand All @@ -87,13 +66,13 @@ public static MagicOnionMethod<TRequest, TResponse, TRawRequest, TRawResponse> C
? CreateBoxedMarshaller<TResponse>(messageSerializer)
: (object)CreateMarshaller<TResponse>(messageSerializer);

return new MagicOnionMethod<TRequest, TResponse, TRawRequest, TRawResponse>(new Method<TRawRequest, TRawResponse>(
return new Method<TRawRequest, TRawResponse>(
methodType,
serviceName,
name,
(Marshaller<TRawRequest>)requestMarshaller,
(Marshaller<TRawResponse>)responseMarshaller
));
);
}

// WORKAROUND: Prior to MagicOnion 5.0, the request type for the parameter-less method was byte[].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,16 @@ namespace MagicOnion.Internal
internal class MagicOnionAsyncStreamReader<T, TRaw> : IAsyncStreamReader<T>
{
readonly IAsyncStreamReader<TRaw> inner;
readonly Func<TRaw, T> fromRawMessage;

public MagicOnionAsyncStreamReader(IAsyncStreamReader<TRaw> inner, Func<TRaw, T> fromRawMessage)
public MagicOnionAsyncStreamReader(IAsyncStreamReader<TRaw> inner)
{
this.inner = inner;
this.fromRawMessage = fromRawMessage;
}

public Task<bool> MoveNext(CancellationToken cancellationToken)
=> inner.MoveNext(cancellationToken);

public T Current
=> fromRawMessage(inner.Current);
=> GrpcMethodHelper.FromRaw<TRaw, T>(inner.Current);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@ namespace MagicOnion.Internal
internal class MagicOnionClientStreamWriter<T, TRaw> : IClientStreamWriter<T>
{
readonly IClientStreamWriter<TRaw> inner;
readonly Func<T, TRaw> toRawMessage;

public MagicOnionClientStreamWriter(IClientStreamWriter<TRaw> inner, Func<T, TRaw> toRawMessage)
public MagicOnionClientStreamWriter(IClientStreamWriter<TRaw> inner)
{
this.inner = inner;
this.toRawMessage = toRawMessage;
}

public Task WriteAsync(T message)
=> inner.WriteAsync(toRawMessage(message));
=> inner.WriteAsync(GrpcMethodHelper.ToRaw<T, TRaw>(message));

public WriteOptions? WriteOptions
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@ namespace MagicOnion.Internal
internal class MagicOnionServerStreamWriter<T, TRaw> : IServerStreamWriter<T>
{
readonly IServerStreamWriter<TRaw> inner;
readonly Func<T, TRaw> toRawMessage;

public MagicOnionServerStreamWriter(IServerStreamWriter<TRaw> inner, Func<T, TRaw> toRawMessage)
public MagicOnionServerStreamWriter(IServerStreamWriter<TRaw> inner)
{
this.inner = inner;
this.toRawMessage = toRawMessage;
}

public Task WriteAsync(T message)
=> inner.WriteAsync(toRawMessage(message));
=> inner.WriteAsync(GrpcMethodHelper.ToRaw<T, TRaw>(message));

public WriteOptions? WriteOptions
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,14 @@ public sealed class RawMethodInvoker<TRequest, TResponse, TRawRequest, TRawRespo
where TRawRequest : class
where TRawResponse : class
{
readonly GrpcMethodHelper.MagicOnionMethod<TRequest, TResponse, TRawRequest, TRawResponse> method;
readonly Method<TRawRequest, TRawResponse> method;
readonly Func<RequestContext, ResponseContext> createUnaryResponseContext;

public RawMethodInvoker(MethodType methodType, string serviceName, string name, IMagicOnionSerializer messageSerializer)
{
this.method = GrpcMethodHelper.CreateMethod<TRequest, TResponse, TRawRequest, TRawResponse>(methodType, serviceName, name, messageSerializer);
this.createUnaryResponseContext = context => ResponseContext<TResponse>.Create<TRawResponse>(
context.Client.Options.CallInvoker.AsyncUnaryCall(method.Method, context.Client.Options.Host, context.CallOptions, method.ToRawRequest(((RequestContext<TRequest>)context).Request)),
method.FromRawResponse
context.Client.Options.CallInvoker.AsyncUnaryCall(method, context.Client.Options.Host, context.CallOptions, GrpcMethodHelper.ToRaw<TRequest, TRawRequest>(((RequestContext<TRequest>)context).Request))
);
}

Expand Down Expand Up @@ -87,34 +86,29 @@ public override Task<ServerStreamingResult<TResponse>> InvokeServerStreaming(Mag
=> Task.FromResult(
new ServerStreamingResult<TResponse>(
new AsyncServerStreamingCallWrapper(
client.Options.CallInvoker.AsyncServerStreamingCall(method.Method, client.Options.Host, client.Options.CallOptions, method.ToRawRequest(request)),
method.FromRawResponse)));
client.Options.CallInvoker.AsyncServerStreamingCall(method, client.Options.Host, client.Options.CallOptions, GrpcMethodHelper.ToRaw<TRequest, TRawRequest>(request)))));

public override Task<ClientStreamingResult<TRequest, TResponse>> InvokeClientStreaming(MagicOnionClientBase client, string path)
=> Task.FromResult(
new ClientStreamingResult<TRequest, TResponse>(
new AsyncClientStreamingCallWrapper(
client.Options.CallInvoker.AsyncClientStreamingCall(method.Method, client.Options.Host, client.Options.CallOptions),
method.ToRawRequest, method.FromRawResponse)));
client.Options.CallInvoker.AsyncClientStreamingCall(method, client.Options.Host, client.Options.CallOptions))));

public override Task<DuplexStreamingResult<TRequest, TResponse>> InvokeDuplexStreaming(MagicOnionClientBase client, string path)
=> Task.FromResult(
new DuplexStreamingResult<TRequest, TResponse>(
new AsyncDuplexStreamingCallWrapper(
client.Options.CallInvoker.AsyncDuplexStreamingCall(method.Method, client.Options.Host, client.Options.CallOptions),
method.ToRawRequest, method.FromRawResponse)));
client.Options.CallInvoker.AsyncDuplexStreamingCall(method, client.Options.Host, client.Options.CallOptions))));

class AsyncServerStreamingCallWrapper : IAsyncServerStreamingCallWrapper<TResponse>
{
readonly AsyncServerStreamingCall<TRawResponse> inner;
readonly Func<TRawResponse, TResponse> fromRawResponse;

IAsyncStreamReader<TResponse>? responseStream;

public AsyncServerStreamingCallWrapper(AsyncServerStreamingCall<TRawResponse> inner, Func<TRawResponse, TResponse> fromRawResponse)
public AsyncServerStreamingCallWrapper(AsyncServerStreamingCall<TRawResponse> inner)
{
this.inner = inner;
this.fromRawResponse = fromRawResponse;
}

public Task<Metadata> ResponseHeadersAsync
Expand All @@ -125,7 +119,7 @@ public Metadata GetTrailers()
=> inner.GetTrailers();

public IAsyncStreamReader<TResponse> ResponseStream
=> responseStream ?? (responseStream = new MagicOnionAsyncStreamReader<TResponse, TRawResponse>(inner.ResponseStream, fromRawResponse));
=> responseStream ?? (responseStream = new MagicOnionAsyncStreamReader<TResponse, TRawResponse>(inner.ResponseStream));

public void Dispose()
=> inner.Dispose();
Expand All @@ -134,15 +128,11 @@ public void Dispose()
class AsyncClientStreamingCallWrapper : IAsyncClientStreamingCallWrapper<TRequest, TResponse>
{
readonly AsyncClientStreamingCall<TRawRequest, TRawResponse> inner;
readonly Func<TRequest, TRawRequest> toRawRequest;
readonly Func<TRawResponse, TResponse> fromRawResponse;
IClientStreamWriter<TRequest>? requestStream;

public AsyncClientStreamingCallWrapper(AsyncClientStreamingCall<TRawRequest, TRawResponse> inner, Func<TRequest, TRawRequest> toRawRequest, Func<TRawResponse, TResponse> fromRawResponse)
public AsyncClientStreamingCallWrapper(AsyncClientStreamingCall<TRawRequest, TRawResponse> inner)
{
this.inner = inner;
this.toRawRequest = toRawRequest;
this.fromRawResponse = fromRawResponse;
}

public Task<Metadata> ResponseHeadersAsync
Expand All @@ -153,12 +143,12 @@ public Metadata GetTrailers()
=> inner.GetTrailers();

public IClientStreamWriter<TRequest> RequestStream
=> requestStream ?? (requestStream = new MagicOnionClientStreamWriter<TRequest, TRawRequest>(inner.RequestStream, toRawRequest));
=> requestStream ?? (requestStream = new MagicOnionClientStreamWriter<TRequest, TRawRequest>(inner.RequestStream));
public Task<TResponse> ResponseAsync
=> ResponseAsyncCore();

async Task<TResponse> ResponseAsyncCore()
=> fromRawResponse(await inner.ResponseAsync.ConfigureAwait(false));
=> GrpcMethodHelper.FromRaw<TRawResponse, TResponse>(await inner.ResponseAsync.ConfigureAwait(false));

public void Dispose()
=> inner.Dispose();
Expand All @@ -167,16 +157,12 @@ public void Dispose()
class AsyncDuplexStreamingCallWrapper : IAsyncDuplexStreamingCallWrapper<TRequest, TResponse>
{
readonly AsyncDuplexStreamingCall<TRawRequest, TRawResponse> inner;
readonly Func<TRequest, TRawRequest> toRawRequest;
readonly Func<TRawResponse, TResponse> fromRawResponse;
IClientStreamWriter<TRequest>? requestStream;
IAsyncStreamReader<TResponse>? responseStream;

public AsyncDuplexStreamingCallWrapper(AsyncDuplexStreamingCall<TRawRequest, TRawResponse> inner, Func<TRequest, TRawRequest> toRawRequest, Func<TRawResponse, TResponse> fromRawResponse)
public AsyncDuplexStreamingCallWrapper(AsyncDuplexStreamingCall<TRawRequest, TRawResponse> inner)
{
this.inner = inner;
this.toRawRequest = toRawRequest;
this.fromRawResponse = fromRawResponse;
}

public Task<Metadata> ResponseHeadersAsync
Expand All @@ -187,9 +173,9 @@ public Metadata GetTrailers()
=> inner.GetTrailers();

public IClientStreamWriter<TRequest> RequestStream
=> requestStream ?? (requestStream = new MagicOnionClientStreamWriter<TRequest, TRawRequest>(inner.RequestStream, toRawRequest));
=> requestStream ?? (requestStream = new MagicOnionClientStreamWriter<TRequest, TRawRequest>(inner.RequestStream));
public IAsyncStreamReader<TResponse> ResponseStream
=> responseStream ?? (responseStream = new MagicOnionAsyncStreamReader<TResponse, TRawResponse>(inner.ResponseStream, fromRawResponse));
=> responseStream ?? (responseStream = new MagicOnionAsyncStreamReader<TResponse, TRawResponse>(inner.ResponseStream));

public void Dispose()
=> inner.Dispose();
Expand Down
Loading
Loading