#region Copyright notice and license
// Copyright 2015, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Threading;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core
{
///
/// Options for calls made by client.
///
public struct CallOptions
{
Metadata headers;
DateTime? deadline;
CancellationToken cancellationToken;
WriteOptions writeOptions;
ContextPropagationToken propagationToken;
CallCredentials credentials;
CallFlags flags;
///
/// Creates a new instance of CallOptions struct.
///
/// Headers to be sent with the call.
/// Deadline for the call to finish. null means no deadline.
/// Can be used to request cancellation of the call.
/// Write options that will be used for this call.
/// Context propagation token obtained from .
/// Credentials to use for this call.
public CallOptions(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken),
WriteOptions writeOptions = null, ContextPropagationToken propagationToken = null, CallCredentials credentials = null)
{
this.headers = headers;
this.deadline = deadline;
this.cancellationToken = cancellationToken;
this.writeOptions = writeOptions;
this.propagationToken = propagationToken;
this.credentials = credentials;
this.flags = default(CallFlags);
}
///
/// Headers to send at the beginning of the call.
///
public Metadata Headers
{
get { return headers; }
}
///
/// Call deadline.
///
public DateTime? Deadline
{
get { return deadline; }
}
///
/// Token that can be used for cancelling the call on the client side.
/// Cancelling the token will request cancellation
/// of the remote call. Best effort will be made to deliver the cancellation
/// notification to the server and interaction of the call with the server side
/// will be terminated. Unless the call finishes before the cancellation could
/// happen (there is an inherent race),
/// the call will finish with StatusCode.Cancelled status.
///
public CancellationToken CancellationToken
{
get { return cancellationToken; }
}
///
/// Write options that will be used for this call.
///
public WriteOptions WriteOptions
{
get { return this.writeOptions; }
}
///
/// Token for propagating parent call context.
///
public ContextPropagationToken PropagationToken
{
get { return this.propagationToken; }
}
///
/// Credentials to use for this call.
///
public CallCredentials Credentials
{
get { return this.credentials; }
}
///
/// If true and and channel is in ChannelState.TransientFailure, the call will attempt waiting for the channel to recover
/// instead of failing immediately (which is the default "FailFast" semantics).
/// Note: experimental API that can change or be removed without any prior notice.
///
public bool IsWaitForReady
{
get { return (this.flags & CallFlags.WaitForReady) == CallFlags.WaitForReady; }
}
///
/// Flags to use for this call.
///
internal CallFlags Flags
{
get { return this.flags; }
}
///
/// Returns new instance of with
/// Headers set to the value provided. Values of all other fields are preserved.
///
/// The headers.
public CallOptions WithHeaders(Metadata headers)
{
var newOptions = this;
newOptions.headers = headers;
return newOptions;
}
///
/// Returns new instance of with
/// Deadline set to the value provided. Values of all other fields are preserved.
///
/// The deadline.
public CallOptions WithDeadline(DateTime deadline)
{
var newOptions = this;
newOptions.deadline = deadline;
return newOptions;
}
///
/// Returns new instance of with
/// CancellationToken set to the value provided. Values of all other fields are preserved.
///
/// The cancellation token.
public CallOptions WithCancellationToken(CancellationToken cancellationToken)
{
var newOptions = this;
newOptions.cancellationToken = cancellationToken;
return newOptions;
}
///
/// Returns new instance of with
/// WriteOptions set to the value provided. Values of all other fields are preserved.
///
/// The write options.
public CallOptions WithWriteOptions(WriteOptions writeOptions)
{
var newOptions = this;
newOptions.writeOptions = writeOptions;
return newOptions;
}
///
/// Returns new instance of with
/// PropagationToken set to the value provided. Values of all other fields are preserved.
///
/// The context propagation token.
public CallOptions WithPropagationToken(ContextPropagationToken propagationToken)
{
var newOptions = this;
newOptions.propagationToken = propagationToken;
return newOptions;
}
///
/// Returns new instance of with
/// Credentials set to the value provided. Values of all other fields are preserved.
///
/// The call credentials.
public CallOptions WithCredentials(CallCredentials credentials)
{
var newOptions = this;
newOptions.credentials = credentials;
return newOptions;
}
///
/// Returns new instance of with "WaitForReady" semantics enabled/disabled.
/// .
/// Note: experimental API that can change or be removed without any prior notice.
///
public CallOptions WithWaitForReady(bool waitForReady = true)
{
if (waitForReady)
{
return WithFlags(this.flags | CallFlags.WaitForReady);
}
return WithFlags(this.flags & ~CallFlags.WaitForReady);
}
///
/// Returns new instance of with
/// Flags set to the value provided. Values of all other fields are preserved.
///
/// The call flags.
internal CallOptions WithFlags(CallFlags flags)
{
var newOptions = this;
newOptions.flags = flags;
return newOptions;
}
///
/// Returns a new instance of with
/// all previously unset values set to their defaults and deadline and cancellation
/// token propagated when appropriate.
///
internal CallOptions Normalize()
{
var newOptions = this;
if (propagationToken != null)
{
if (propagationToken.Options.IsPropagateDeadline)
{
GrpcPreconditions.CheckArgument(!newOptions.deadline.HasValue,
"Cannot propagate deadline from parent call. The deadline has already been set explicitly.");
newOptions.deadline = propagationToken.ParentDeadline;
}
if (propagationToken.Options.IsPropagateCancellation)
{
GrpcPreconditions.CheckArgument(!newOptions.cancellationToken.CanBeCanceled,
"Cannot propagate cancellation token from parent call. The cancellation token has already been set to a non-default value.");
newOptions.cancellationToken = propagationToken.ParentCancellationToken;
}
}
newOptions.headers = newOptions.headers ?? Metadata.Empty;
newOptions.deadline = newOptions.deadline ?? DateTime.MaxValue;
return newOptions;
}
}
}