using Grpc.Core; using MessagePack; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace MagicOnion { /// /// Wrapped AsyncClientStreamingCall. /// public struct ClientStreamingResult : IDisposable { internal readonly TResponse rawValue; internal readonly bool hasRawValue; readonly AsyncClientStreamingCall inner; readonly IClientStreamWriter requestStream; readonly MessagePackSerializerOptions serializerOptions; public ClientStreamingResult(TResponse rawValue) { this.hasRawValue = true; this.rawValue = rawValue; this.inner = null; this.requestStream = null; this.serializerOptions = null; } public ClientStreamingResult(AsyncClientStreamingCall inner, IClientStreamWriter requestStream, MessagePackSerializerOptions serializerOptions) { this.hasRawValue = false; this.rawValue = default(TResponse); this.inner = inner; this.requestStream = requestStream; this.serializerOptions = serializerOptions; } async Task Deserialize() { var bytes = await inner.ResponseAsync.ConfigureAwait(false); return MessagePackSerializer.Deserialize(bytes, serializerOptions); } /// /// Asynchronous call result. /// public Task ResponseAsync { get { if (hasRawValue) { return Task.FromResult(rawValue); } else { return Deserialize(); } } } /// /// Asynchronous access to response headers. /// public Task ResponseHeadersAsync { get { return this.inner.ResponseHeadersAsync; } } /// /// Async stream to send streaming requests. /// public IClientStreamWriter RequestStream { get { return this.requestStream; } } /// /// Allows awaiting this object directly. /// /// public TaskAwaiter GetAwaiter() { return ResponseAsync.GetAwaiter(); } /// /// Gets the call status if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Status GetStatus() { return this.inner.GetStatus(); } /// /// Gets the call trailing metadata if the call has already finished. /// Throws InvalidOperationException otherwise. /// public Metadata GetTrailers() { return this.inner.GetTrailers(); } /// /// Provides means to cleanup after the call. /// If the call has already finished normally (request stream has been completed and call result has been received), doesn't do anything. /// Otherwise, requests cancellation of the call which should terminate all pending async operations associated with the call. /// As a result, all resources being used by the call should be released eventually. /// /// /// Normally, there is no need for you to dispose the call unless you want to utilize the /// "Cancel" semantics of invoking Dispose. /// public void Dispose() { if (this.inner != null) { this.inner.Dispose(); } } } }