commit
fccea1f70e
145 changed files with 3432 additions and 2674 deletions
@ -0,0 +1,131 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <grpc/grpc_security.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
#include <grpc++/channel_arguments.h> |
||||||
|
#include <grpc++/config.h> |
||||||
|
#include <grpc++/credentials.h> |
||||||
|
#include "src/cpp/client/channel.h" |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
|
||||||
|
class SecureCredentials GRPC_FINAL : public Credentials { |
||||||
|
public: |
||||||
|
explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {} |
||||||
|
~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); } |
||||||
|
grpc_credentials* GetRawCreds() { return c_creds_; } |
||||||
|
|
||||||
|
std::shared_ptr<grpc::ChannelInterface> CreateChannel( |
||||||
|
const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE { |
||||||
|
grpc_channel_args channel_args; |
||||||
|
args.SetChannelArgs(&channel_args); |
||||||
|
return std::shared_ptr<ChannelInterface>(new Channel( |
||||||
|
target, |
||||||
|
grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args))); |
||||||
|
} |
||||||
|
|
||||||
|
SecureCredentials* AsSecureCredentials() { return this; } |
||||||
|
|
||||||
|
private: |
||||||
|
grpc_credentials* const c_creds_; |
||||||
|
}; |
||||||
|
|
||||||
|
namespace { |
||||||
|
std::unique_ptr<Credentials> WrapCredentials(grpc_credentials* creds) { |
||||||
|
return creds == nullptr |
||||||
|
? nullptr |
||||||
|
: std::unique_ptr<Credentials>(new SecureCredentials(creds)); |
||||||
|
} |
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::unique_ptr<Credentials> GoogleDefaultCredentials() { |
||||||
|
return WrapCredentials(grpc_google_default_credentials_create()); |
||||||
|
} |
||||||
|
|
||||||
|
// Builds SSL Credentials given SSL specific options
|
||||||
|
std::unique_ptr<Credentials> SslCredentials( |
||||||
|
const SslCredentialsOptions& options) { |
||||||
|
grpc_ssl_pem_key_cert_pair pem_key_cert_pair = { |
||||||
|
options.pem_private_key.c_str(), options.pem_cert_chain.c_str()}; |
||||||
|
|
||||||
|
grpc_credentials* c_creds = grpc_ssl_credentials_create( |
||||||
|
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(), |
||||||
|
options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair); |
||||||
|
return WrapCredentials(c_creds); |
||||||
|
} |
||||||
|
|
||||||
|
// Builds credentials for use when running in GCE
|
||||||
|
std::unique_ptr<Credentials> ComputeEngineCredentials() { |
||||||
|
return WrapCredentials(grpc_compute_engine_credentials_create()); |
||||||
|
} |
||||||
|
|
||||||
|
// Builds service account credentials.
|
||||||
|
std::unique_ptr<Credentials> ServiceAccountCredentials( |
||||||
|
const grpc::string& json_key, const grpc::string& scope, |
||||||
|
std::chrono::seconds token_lifetime) { |
||||||
|
gpr_timespec lifetime = gpr_time_from_seconds( |
||||||
|
token_lifetime.count() > 0 ? token_lifetime.count() : 0); |
||||||
|
return WrapCredentials(grpc_service_account_credentials_create( |
||||||
|
json_key.c_str(), scope.c_str(), lifetime)); |
||||||
|
} |
||||||
|
|
||||||
|
// Builds IAM credentials.
|
||||||
|
std::unique_ptr<Credentials> IAMCredentials( |
||||||
|
const grpc::string& authorization_token, |
||||||
|
const grpc::string& authority_selector) { |
||||||
|
return WrapCredentials(grpc_iam_credentials_create( |
||||||
|
authorization_token.c_str(), authority_selector.c_str())); |
||||||
|
} |
||||||
|
|
||||||
|
// Combines two credentials objects into a composite credentials.
|
||||||
|
std::unique_ptr<Credentials> CompositeCredentials( |
||||||
|
const std::unique_ptr<Credentials>& creds1, |
||||||
|
const std::unique_ptr<Credentials>& creds2) { |
||||||
|
// Note that we are not saving unique_ptrs to the two credentials
|
||||||
|
// passed in here. This is OK because the underlying C objects (i.e.,
|
||||||
|
// creds1 and creds2) into grpc_composite_credentials_create will see their
|
||||||
|
// refcounts incremented.
|
||||||
|
SecureCredentials* s1 = creds1->AsSecureCredentials(); |
||||||
|
SecureCredentials* s2 = creds2->AsSecureCredentials(); |
||||||
|
if (s1 && s2) { |
||||||
|
return WrapCredentials(grpc_composite_credentials_create( |
||||||
|
s1->GetRawCreds(), s2->GetRawCreds())); |
||||||
|
} |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc
|
@ -0,0 +1,71 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <grpc/grpc_security.h> |
||||||
|
|
||||||
|
#include <grpc++/server_credentials.h> |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
|
||||||
|
namespace { |
||||||
|
class SecureServerCredentials GRPC_FINAL : public ServerCredentials { |
||||||
|
public: |
||||||
|
explicit SecureServerCredentials(grpc_server_credentials* creds) : creds_(creds) {} |
||||||
|
~SecureServerCredentials() GRPC_OVERRIDE { |
||||||
|
grpc_server_credentials_release(creds_); |
||||||
|
} |
||||||
|
|
||||||
|
int AddPortToServer(const grpc::string& addr, |
||||||
|
grpc_server* server) GRPC_OVERRIDE { |
||||||
|
return grpc_server_add_secure_http2_port(server, addr.c_str(), creds_); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
grpc_server_credentials* const creds_; |
||||||
|
}; |
||||||
|
} // namespace
|
||||||
|
|
||||||
|
std::shared_ptr<ServerCredentials> SslServerCredentials( |
||||||
|
const SslServerCredentialsOptions &options) { |
||||||
|
std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs; |
||||||
|
for (const auto &key_cert_pair : options.pem_key_cert_pairs) { |
||||||
|
pem_key_cert_pairs.push_back( |
||||||
|
{key_cert_pair.private_key.c_str(), key_cert_pair.cert_chain.c_str()}); |
||||||
|
} |
||||||
|
grpc_server_credentials *c_creds = grpc_ssl_server_credentials_create( |
||||||
|
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(), |
||||||
|
&pem_key_cert_pairs[0], pem_key_cert_pairs.size()); |
||||||
|
return std::shared_ptr<ServerCredentials>(new SecureServerCredentials(c_creds)); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc
|
@ -0,0 +1,407 @@ |
|||||||
|
#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.Diagnostics; |
||||||
|
using System.Runtime.CompilerServices; |
||||||
|
using System.Runtime.InteropServices; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Grpc.Core.Internal; |
||||||
|
using Grpc.Core.Utils; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Base for handling both client side and server side calls. |
||||||
|
/// Handles native call lifecycle and provides convenience methods. |
||||||
|
/// </summary> |
||||||
|
internal abstract class AsyncCallBase<TWrite, TRead> |
||||||
|
{ |
||||||
|
readonly Func<TWrite, byte[]> serializer; |
||||||
|
readonly Func<byte[], TRead> deserializer; |
||||||
|
|
||||||
|
protected readonly CompletionCallbackDelegate sendFinishedHandler; |
||||||
|
protected readonly CompletionCallbackDelegate readFinishedHandler; |
||||||
|
protected readonly CompletionCallbackDelegate halfclosedHandler; |
||||||
|
|
||||||
|
protected readonly object myLock = new object(); |
||||||
|
|
||||||
|
protected GCHandle gchandle; |
||||||
|
protected CallSafeHandle call; |
||||||
|
protected bool disposed; |
||||||
|
|
||||||
|
protected bool started; |
||||||
|
protected bool errorOccured; |
||||||
|
protected bool cancelRequested; |
||||||
|
|
||||||
|
protected AsyncCompletionDelegate sendCompletionDelegate; // Completion of a pending send or sendclose if not null. |
||||||
|
protected bool readPending; // True if there is a read in progress. |
||||||
|
protected bool readingDone; |
||||||
|
protected bool halfcloseRequested; |
||||||
|
protected bool halfclosed; |
||||||
|
protected bool finished; // True if close has been received from the peer. |
||||||
|
|
||||||
|
// Streaming reads will be delivered to this observer. For a call that only does unary read it may remain null. |
||||||
|
protected IObserver<TRead> readObserver; |
||||||
|
|
||||||
|
public AsyncCallBase(Func<TWrite, byte[]> serializer, Func<byte[], TRead> deserializer) |
||||||
|
{ |
||||||
|
this.serializer = Preconditions.CheckNotNull(serializer); |
||||||
|
this.deserializer = Preconditions.CheckNotNull(deserializer); |
||||||
|
|
||||||
|
this.sendFinishedHandler = CreateBatchCompletionCallback(HandleSendFinished); |
||||||
|
this.readFinishedHandler = CreateBatchCompletionCallback(HandleReadFinished); |
||||||
|
this.halfclosedHandler = CreateBatchCompletionCallback(HandleHalfclosed); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Requests cancelling the call. |
||||||
|
/// </summary> |
||||||
|
public void Cancel() |
||||||
|
{ |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
Preconditions.CheckState(started); |
||||||
|
cancelRequested = true; |
||||||
|
|
||||||
|
if (!disposed) |
||||||
|
{ |
||||||
|
call.Cancel(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Requests cancelling the call with given status. |
||||||
|
/// </summary> |
||||||
|
public void CancelWithStatus(Status status) |
||||||
|
{ |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
Preconditions.CheckState(started); |
||||||
|
cancelRequested = true; |
||||||
|
|
||||||
|
if (!disposed) |
||||||
|
{ |
||||||
|
call.CancelWithStatus(status); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void InitializeInternal(CallSafeHandle call) |
||||||
|
{ |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
// Make sure this object and the delegated held by it will not be garbage collected |
||||||
|
// before we release this handle. |
||||||
|
gchandle = GCHandle.Alloc(this); |
||||||
|
this.call = call; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Initiates sending a message. Only once send operation can be active at a time. |
||||||
|
/// completionDelegate is invoked upon completion. |
||||||
|
/// </summary> |
||||||
|
protected void StartSendMessageInternal(TWrite msg, AsyncCompletionDelegate completionDelegate) |
||||||
|
{ |
||||||
|
byte[] payload = UnsafeSerialize(msg); |
||||||
|
|
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); |
||||||
|
CheckSendingAllowed(); |
||||||
|
|
||||||
|
call.StartSendMessage(payload, sendFinishedHandler); |
||||||
|
sendCompletionDelegate = completionDelegate; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Requests receiving a next message. |
||||||
|
/// </summary> |
||||||
|
protected void StartReceiveMessage() |
||||||
|
{ |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
Preconditions.CheckState(started); |
||||||
|
Preconditions.CheckState(!disposed); |
||||||
|
Preconditions.CheckState(!errorOccured); |
||||||
|
|
||||||
|
Preconditions.CheckState(!readingDone); |
||||||
|
Preconditions.CheckState(!readPending); |
||||||
|
|
||||||
|
call.StartReceiveMessage(readFinishedHandler); |
||||||
|
readPending = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Default behavior just completes the read observer, but more sofisticated behavior might be required |
||||||
|
/// by subclasses. |
||||||
|
/// </summary> |
||||||
|
protected virtual void CompleteReadObserver() |
||||||
|
{ |
||||||
|
FireReadObserverOnCompleted(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// If there are no more pending actions and no new actions can be started, releases |
||||||
|
/// the underlying native resources. |
||||||
|
/// </summary> |
||||||
|
protected bool ReleaseResourcesIfPossible() |
||||||
|
{ |
||||||
|
if (!disposed && call != null) |
||||||
|
{ |
||||||
|
if (halfclosed && readingDone && finished) |
||||||
|
{ |
||||||
|
ReleaseResources(); |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private void ReleaseResources() |
||||||
|
{ |
||||||
|
if (call != null) |
||||||
|
{ |
||||||
|
call.Dispose(); |
||||||
|
} |
||||||
|
gchandle.Free(); |
||||||
|
disposed = true; |
||||||
|
} |
||||||
|
|
||||||
|
protected void CheckSendingAllowed() |
||||||
|
{ |
||||||
|
Preconditions.CheckState(started); |
||||||
|
Preconditions.CheckState(!disposed); |
||||||
|
Preconditions.CheckState(!errorOccured); |
||||||
|
|
||||||
|
Preconditions.CheckState(!halfcloseRequested, "Already halfclosed."); |
||||||
|
Preconditions.CheckState(sendCompletionDelegate == null, "Only one write can be pending at a time"); |
||||||
|
} |
||||||
|
|
||||||
|
protected byte[] UnsafeSerialize(TWrite msg) |
||||||
|
{ |
||||||
|
return serializer(msg); |
||||||
|
} |
||||||
|
|
||||||
|
protected bool TrySerialize(TWrite msg, out byte[] payload) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
payload = serializer(msg); |
||||||
|
return true; |
||||||
|
} |
||||||
|
catch(Exception) |
||||||
|
{ |
||||||
|
Console.WriteLine("Exception occured while trying to serialize message"); |
||||||
|
payload = null; |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected bool TryDeserialize(byte[] payload, out TRead msg) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
msg = deserializer(payload); |
||||||
|
return true; |
||||||
|
} |
||||||
|
catch(Exception) |
||||||
|
{ |
||||||
|
Console.WriteLine("Exception occured while trying to deserialize message"); |
||||||
|
msg = default(TRead); |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void FireReadObserverOnNext(TRead value) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
readObserver.OnNext(value); |
||||||
|
} |
||||||
|
catch(Exception e) |
||||||
|
{ |
||||||
|
Console.WriteLine("Exception occured while invoking readObserver.OnNext: " + e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void FireReadObserverOnCompleted() |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
readObserver.OnCompleted(); |
||||||
|
} |
||||||
|
catch(Exception e) |
||||||
|
{ |
||||||
|
Console.WriteLine("Exception occured while invoking readObserver.OnCompleted: " + e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void FireReadObserverOnError(Exception error) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
readObserver.OnError(error); |
||||||
|
} |
||||||
|
catch(Exception e) |
||||||
|
{ |
||||||
|
Console.WriteLine("Exception occured while invoking readObserver.OnError: " + e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void FireCompletion(AsyncCompletionDelegate completionDelegate, Exception error) |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
completionDelegate(error); |
||||||
|
} |
||||||
|
catch(Exception e) |
||||||
|
{ |
||||||
|
Console.WriteLine("Exception occured while invoking completion delegate: " + e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Creates completion callback delegate that wraps the batch completion handler in a try catch block to |
||||||
|
/// prevent propagating exceptions accross managed/unmanaged boundary. |
||||||
|
/// </summary> |
||||||
|
protected CompletionCallbackDelegate CreateBatchCompletionCallback(Action<bool, BatchContextSafeHandleNotOwned> handler) |
||||||
|
{ |
||||||
|
return new CompletionCallbackDelegate( (error, batchContextPtr) => { |
||||||
|
try |
||||||
|
{ |
||||||
|
var ctx = new BatchContextSafeHandleNotOwned(batchContextPtr); |
||||||
|
bool wasError = (error != GRPCOpError.GRPC_OP_OK); |
||||||
|
handler(wasError, ctx); |
||||||
|
} |
||||||
|
catch(Exception e) |
||||||
|
{ |
||||||
|
Console.WriteLine("Caught exception in a native handler: " + e); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Handles send completion. |
||||||
|
/// </summary> |
||||||
|
private void HandleSendFinished(bool wasError, BatchContextSafeHandleNotOwned ctx) |
||||||
|
{ |
||||||
|
AsyncCompletionDelegate origCompletionDelegate = null; |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
origCompletionDelegate = sendCompletionDelegate; |
||||||
|
sendCompletionDelegate = null; |
||||||
|
|
||||||
|
ReleaseResourcesIfPossible(); |
||||||
|
} |
||||||
|
|
||||||
|
if (wasError) |
||||||
|
{ |
||||||
|
FireCompletion(origCompletionDelegate, new OperationFailedException("Send failed")); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
FireCompletion(origCompletionDelegate, null); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Handles halfclose completion. |
||||||
|
/// </summary> |
||||||
|
private void HandleHalfclosed(bool wasError, BatchContextSafeHandleNotOwned ctx) |
||||||
|
{ |
||||||
|
AsyncCompletionDelegate origCompletionDelegate = null; |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
halfclosed = true; |
||||||
|
origCompletionDelegate = sendCompletionDelegate; |
||||||
|
sendCompletionDelegate = null; |
||||||
|
|
||||||
|
ReleaseResourcesIfPossible(); |
||||||
|
} |
||||||
|
|
||||||
|
if (wasError) |
||||||
|
{ |
||||||
|
FireCompletion(origCompletionDelegate, new OperationFailedException("Halfclose failed")); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
FireCompletion(origCompletionDelegate, null); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Handles streaming read completion. |
||||||
|
/// </summary> |
||||||
|
private void HandleReadFinished(bool wasError, BatchContextSafeHandleNotOwned ctx) |
||||||
|
{ |
||||||
|
var payload = ctx.GetReceivedMessage(); |
||||||
|
|
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
readPending = false; |
||||||
|
if (payload == null) |
||||||
|
{ |
||||||
|
readingDone = true; |
||||||
|
} |
||||||
|
|
||||||
|
ReleaseResourcesIfPossible(); |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: handle the case when error occured... |
||||||
|
|
||||||
|
if (payload != null) |
||||||
|
{ |
||||||
|
// TODO: handle deserialization error |
||||||
|
TRead msg; |
||||||
|
TryDeserialize(payload, out msg); |
||||||
|
|
||||||
|
FireReadObserverOnNext(msg); |
||||||
|
|
||||||
|
// Start a new read. The current one has already been delivered, |
||||||
|
// so correct ordering of reads is assured. |
||||||
|
StartReceiveMessage(); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
CompleteReadObserver(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,125 @@ |
|||||||
|
#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.Diagnostics; |
||||||
|
using System.Runtime.CompilerServices; |
||||||
|
using System.Runtime.InteropServices; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Grpc.Core.Internal; |
||||||
|
using Grpc.Core.Utils; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Handles server side native call lifecycle. |
||||||
|
/// </summary> |
||||||
|
internal class AsyncCallServer<TRequest, TResponse> : AsyncCallBase<TResponse, TRequest> |
||||||
|
{ |
||||||
|
readonly CompletionCallbackDelegate finishedServersideHandler; |
||||||
|
readonly TaskCompletionSource<object> finishedServersideTcs = new TaskCompletionSource<object>(); |
||||||
|
|
||||||
|
public AsyncCallServer(Func<TResponse, byte[]> serializer, Func<byte[], TRequest> deserializer) : base(serializer, deserializer) |
||||||
|
{ |
||||||
|
this.finishedServersideHandler = CreateBatchCompletionCallback(HandleFinishedServerside); |
||||||
|
} |
||||||
|
|
||||||
|
public void Initialize(CallSafeHandle call) |
||||||
|
{ |
||||||
|
InitializeInternal(call); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Starts a server side call. Currently, all server side calls are implemented as duplex |
||||||
|
/// streaming call and they are adapted to the appropriate streaming arity. |
||||||
|
/// </summary> |
||||||
|
public Task ServerSideCallAsync(IObserver<TRequest> readObserver) |
||||||
|
{ |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
Preconditions.CheckNotNull(call); |
||||||
|
|
||||||
|
started = true; |
||||||
|
this.readObserver = readObserver; |
||||||
|
|
||||||
|
call.StartServerSide(finishedServersideHandler); |
||||||
|
StartReceiveMessage(); |
||||||
|
return finishedServersideTcs.Task; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Sends a streaming response. Only one pending send action is allowed at any given time. |
||||||
|
/// completionDelegate is called when the operation finishes. |
||||||
|
/// </summary> |
||||||
|
public void StartSendMessage(TResponse msg, AsyncCompletionDelegate completionDelegate) |
||||||
|
{ |
||||||
|
StartSendMessageInternal(msg, completionDelegate); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Sends call result status, also indicating server is done with streaming responses. |
||||||
|
/// Only one pending send action is allowed at any given time. |
||||||
|
/// completionDelegate is called when the operation finishes. |
||||||
|
/// </summary> |
||||||
|
public void StartSendStatusFromServer(Status status, AsyncCompletionDelegate completionDelegate) |
||||||
|
{ |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
Preconditions.CheckNotNull(completionDelegate, "Completion delegate cannot be null"); |
||||||
|
CheckSendingAllowed(); |
||||||
|
|
||||||
|
call.StartSendStatusFromServer(status, halfclosedHandler); |
||||||
|
halfcloseRequested = true; |
||||||
|
sendCompletionDelegate = completionDelegate; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Handles the server side close completion. |
||||||
|
/// </summary> |
||||||
|
private void HandleFinishedServerside(bool wasError, BatchContextSafeHandleNotOwned ctx) |
||||||
|
{ |
||||||
|
lock (myLock) |
||||||
|
{ |
||||||
|
finished = true; |
||||||
|
|
||||||
|
ReleaseResourcesIfPossible(); |
||||||
|
} |
||||||
|
// TODO: handle error ... |
||||||
|
|
||||||
|
finishedServersideTcs.SetResult(null); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
#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.Diagnostics; |
||||||
|
using System.Runtime.CompilerServices; |
||||||
|
using System.Runtime.InteropServices; |
||||||
|
using System.Threading; |
||||||
|
using System.Threading.Tasks; |
||||||
|
using Grpc.Core.Internal; |
||||||
|
using Grpc.Core.Utils; |
||||||
|
|
||||||
|
namespace Grpc.Core.Internal |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// If error != null, there's been an error or operation has been cancelled. |
||||||
|
/// </summary> |
||||||
|
internal delegate void AsyncCompletionDelegate(Exception error); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Helper for transforming AsyncCompletionDelegate into full-fledged Task. |
||||||
|
/// </summary> |
||||||
|
internal class AsyncCompletionTaskSource |
||||||
|
{ |
||||||
|
readonly TaskCompletionSource<object> tcs = new TaskCompletionSource<object>(); |
||||||
|
readonly AsyncCompletionDelegate completionDelegate; |
||||||
|
|
||||||
|
public AsyncCompletionTaskSource() |
||||||
|
{ |
||||||
|
completionDelegate = new AsyncCompletionDelegate(HandleCompletion); |
||||||
|
} |
||||||
|
|
||||||
|
public Task Task |
||||||
|
{ |
||||||
|
get |
||||||
|
{ |
||||||
|
return tcs.Task; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public AsyncCompletionDelegate CompletionDelegate |
||||||
|
{ |
||||||
|
get |
||||||
|
{ |
||||||
|
return completionDelegate; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void HandleCompletion(Exception error) |
||||||
|
{ |
||||||
|
if (error == null) |
||||||
|
{ |
||||||
|
tcs.SetResult(null); |
||||||
|
return; |
||||||
|
} |
||||||
|
if (error is OperationCanceledException) |
||||||
|
{ |
||||||
|
tcs.SetCanceled(); |
||||||
|
return; |
||||||
|
} |
||||||
|
tcs.SetException(error); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
#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; |
||||||
|
|
||||||
|
namespace Grpc.Core |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Thrown when gRPC operation fails. |
||||||
|
/// </summary> |
||||||
|
public class OperationFailedException : Exception |
||||||
|
{ |
||||||
|
public OperationFailedException(string message) : base(message) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,113 @@ |
|||||||
|
#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.Tasks; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Collections.Concurrent; |
||||||
|
using System.Diagnostics; |
||||||
|
|
||||||
|
namespace Grpc.Core.Utils |
||||||
|
{ |
||||||
|
public static class Preconditions |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Throws ArgumentException if condition is false. |
||||||
|
/// </summary> |
||||||
|
public static void CheckArgument(bool condition) |
||||||
|
{ |
||||||
|
if (!condition) |
||||||
|
{ |
||||||
|
throw new ArgumentException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Throws ArgumentException with given message if condition is false. |
||||||
|
/// </summary> |
||||||
|
public static void CheckArgument(bool condition, string errorMessage) |
||||||
|
{ |
||||||
|
if (!condition) |
||||||
|
{ |
||||||
|
throw new ArgumentException(errorMessage); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Throws NullReferenceException if reference is null. |
||||||
|
/// </summary> |
||||||
|
public static T CheckNotNull<T> (T reference) |
||||||
|
{ |
||||||
|
if (reference == null) |
||||||
|
{ |
||||||
|
throw new NullReferenceException(); |
||||||
|
} |
||||||
|
return reference; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Throws NullReferenceException with given message if reference is null. |
||||||
|
/// </summary> |
||||||
|
public static T CheckNotNull<T> (T reference, string errorMessage) |
||||||
|
{ |
||||||
|
if (reference == null) |
||||||
|
{ |
||||||
|
throw new NullReferenceException(errorMessage); |
||||||
|
} |
||||||
|
return reference; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Throws InvalidOperationException if condition is false. |
||||||
|
/// </summary> |
||||||
|
public static void CheckState(bool condition) |
||||||
|
{ |
||||||
|
if (!condition) |
||||||
|
{ |
||||||
|
throw new InvalidOperationException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Throws InvalidOperationException with given message if condition is false. |
||||||
|
/// </summary> |
||||||
|
public static void CheckState(bool condition, string errorMessage) |
||||||
|
{ |
||||||
|
if (!condition) |
||||||
|
{ |
||||||
|
throw new InvalidOperationException(errorMessage); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,94 @@ |
|||||||
|
/* |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
'use strict'; |
||||||
|
|
||||||
|
var assert = require('assert'); |
||||||
|
var grpc = require('bindings')('grpc.node'); |
||||||
|
|
||||||
|
describe('server', function() { |
||||||
|
describe('constructor', function() { |
||||||
|
it('should work with no arguments', function() { |
||||||
|
assert.doesNotThrow(function() { |
||||||
|
new grpc.Server(); |
||||||
|
}); |
||||||
|
}); |
||||||
|
it('should work with an empty list argument', function() { |
||||||
|
assert.doesNotThrow(function() { |
||||||
|
new grpc.Server([]); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
describe('addHttp2Port', function() { |
||||||
|
var server; |
||||||
|
before(function() { |
||||||
|
server = new grpc.Server(); |
||||||
|
}); |
||||||
|
it('should bind to an unused port', function() { |
||||||
|
var port; |
||||||
|
assert.doesNotThrow(function() { |
||||||
|
port = server.addHttp2Port('0.0.0.0:0'); |
||||||
|
}); |
||||||
|
assert(port > 0); |
||||||
|
}); |
||||||
|
}); |
||||||
|
describe('addSecureHttp2Port', function() { |
||||||
|
var server; |
||||||
|
before(function() { |
||||||
|
server = new grpc.Server(); |
||||||
|
}); |
||||||
|
it('should bind to an unused port with fake credentials', function() { |
||||||
|
var port; |
||||||
|
var creds = grpc.ServerCredentials.createFake(); |
||||||
|
assert.doesNotThrow(function() { |
||||||
|
port = server.addSecureHttp2Port('0.0.0.0:0', creds); |
||||||
|
}); |
||||||
|
assert(port > 0); |
||||||
|
}); |
||||||
|
}); |
||||||
|
describe('listen', function() { |
||||||
|
var server; |
||||||
|
before(function() { |
||||||
|
server = new grpc.Server(); |
||||||
|
server.addHttp2Port('0.0.0.0:0'); |
||||||
|
}); |
||||||
|
after(function() { |
||||||
|
server.shutdown(); |
||||||
|
}); |
||||||
|
it('should listen without error', function() { |
||||||
|
assert.doesNotThrow(function() { |
||||||
|
server.start(); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
@ -0,0 +1,56 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
"""Insecure client-server interoperability as a unit test.""" |
||||||
|
|
||||||
|
import unittest |
||||||
|
|
||||||
|
from grpc.early_adopter import implementations |
||||||
|
|
||||||
|
from interop import _interop_test_case |
||||||
|
from interop import methods |
||||||
|
|
||||||
|
|
||||||
|
class InsecureInteropTest( |
||||||
|
_interop_test_case.InteropTestCase, |
||||||
|
unittest.TestCase): |
||||||
|
|
||||||
|
def setUp(self): |
||||||
|
self.server = implementations.insecure_server(methods.SERVER_METHODS, 0) |
||||||
|
self.server.start() |
||||||
|
port = self.server.port() |
||||||
|
self.stub = implementations.insecure_stub( |
||||||
|
methods.CLIENT_METHODS, 'localhost', port) |
||||||
|
|
||||||
|
def tearDown(self): |
||||||
|
self.server.stop() |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
unittest.main() |
@ -0,0 +1,55 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
"""Common code for unit tests of the interoperability test code.""" |
||||||
|
|
||||||
|
from interop import methods |
||||||
|
|
||||||
|
|
||||||
|
class InteropTestCase(object): |
||||||
|
"""Unit test methods. |
||||||
|
|
||||||
|
This class must be mixed in with unittest.TestCase and a class that defines |
||||||
|
setUp and tearDown methods that manage a stub attribute. |
||||||
|
""" |
||||||
|
|
||||||
|
def testEmptyUnary(self): |
||||||
|
methods.TestCase.EMPTY_UNARY.test_interoperability(self.stub) |
||||||
|
|
||||||
|
def testLargeUnary(self): |
||||||
|
methods.TestCase.LARGE_UNARY.test_interoperability(self.stub) |
||||||
|
|
||||||
|
def testServerStreaming(self): |
||||||
|
methods.TestCase.SERVER_STREAMING.test_interoperability(self.stub) |
||||||
|
|
||||||
|
def testClientStreaming(self): |
||||||
|
methods.TestCase.CLIENT_STREAMING.test_interoperability(self.stub) |
||||||
|
|
||||||
|
def testPingPong(self): |
||||||
|
methods.TestCase.PING_PONG.test_interoperability(self.stub) |
@ -0,0 +1,63 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
"""Secure client-server interoperability as a unit test.""" |
||||||
|
|
||||||
|
import unittest |
||||||
|
|
||||||
|
from grpc.early_adopter import implementations |
||||||
|
|
||||||
|
from interop import _interop_test_case |
||||||
|
from interop import methods |
||||||
|
from interop import resources |
||||||
|
|
||||||
|
_SERVER_HOST_OVERRIDE = 'foo.test.google.fr' |
||||||
|
|
||||||
|
|
||||||
|
class SecureInteropTest( |
||||||
|
_interop_test_case.InteropTestCase, |
||||||
|
unittest.TestCase): |
||||||
|
|
||||||
|
def setUp(self): |
||||||
|
self.server = implementations.secure_server( |
||||||
|
methods.SERVER_METHODS, 0, resources.private_key(), |
||||||
|
resources.certificate_chain()) |
||||||
|
self.server.start() |
||||||
|
port = self.server.port() |
||||||
|
self.stub = implementations.secure_stub( |
||||||
|
methods.CLIENT_METHODS, 'localhost', port, |
||||||
|
resources.test_root_certificates(), None, None, |
||||||
|
server_host_override=_SERVER_HOST_OVERRIDE) |
||||||
|
|
||||||
|
def tearDown(self): |
||||||
|
self.server.stop() |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
unittest.main() |
@ -1,179 +0,0 @@ |
|||||||
# 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. |
|
||||||
|
|
||||||
"""Utilities for assembling RPC framework values.""" |
|
||||||
|
|
||||||
import collections |
|
||||||
|
|
||||||
from grpc.framework.assembly import interfaces |
|
||||||
from grpc.framework.common import cardinality |
|
||||||
from grpc.framework.common import style |
|
||||||
from grpc.framework.face import interfaces as face_interfaces |
|
||||||
from grpc.framework.foundation import stream |
|
||||||
|
|
||||||
|
|
||||||
class _MethodImplementation( |
|
||||||
interfaces.MethodImplementation, |
|
||||||
collections.namedtuple( |
|
||||||
'_MethodImplementation', |
|
||||||
['cardinality', 'style', 'unary_unary_inline', 'unary_stream_inline', |
|
||||||
'stream_unary_inline', 'stream_stream_inline', 'unary_unary_event', |
|
||||||
'unary_stream_event', 'stream_unary_event', 'stream_stream_event',])): |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
def unary_unary_inline(behavior): |
|
||||||
"""Creates an interfaces.MethodImplementation for the given behavior. |
|
||||||
|
|
||||||
Args: |
|
||||||
behavior: The implementation of a unary-unary RPC method as a callable value |
|
||||||
that takes a request value and a face_interfaces.RpcContext object and |
|
||||||
returns a response value. |
|
||||||
|
|
||||||
Returns: |
|
||||||
An interfaces.MethodImplementation derived from the given behavior. |
|
||||||
""" |
|
||||||
return _MethodImplementation( |
|
||||||
cardinality.Cardinality.UNARY_UNARY, style.Service.INLINE, behavior, |
|
||||||
None, None, None, None, None, None, None) |
|
||||||
|
|
||||||
|
|
||||||
def unary_stream_inline(behavior): |
|
||||||
"""Creates an interfaces.MethodImplementation for the given behavior. |
|
||||||
|
|
||||||
Args: |
|
||||||
behavior: The implementation of a unary-stream RPC method as a callable |
|
||||||
value that takes a request value and a face_interfaces.RpcContext object |
|
||||||
and returns an iterator of response values. |
|
||||||
|
|
||||||
Returns: |
|
||||||
An interfaces.MethodImplementation derived from the given behavior. |
|
||||||
""" |
|
||||||
return _MethodImplementation( |
|
||||||
cardinality.Cardinality.UNARY_STREAM, style.Service.INLINE, None, |
|
||||||
behavior, None, None, None, None, None, None) |
|
||||||
|
|
||||||
|
|
||||||
def stream_unary_inline(behavior): |
|
||||||
"""Creates an interfaces.MethodImplementation for the given behavior. |
|
||||||
|
|
||||||
Args: |
|
||||||
behavior: The implementation of a stream-unary RPC method as a callable |
|
||||||
value that takes an iterator of request values and a |
|
||||||
face_interfaces.RpcContext object and returns a response value. |
|
||||||
|
|
||||||
Returns: |
|
||||||
An interfaces.MethodImplementation derived from the given behavior. |
|
||||||
""" |
|
||||||
return _MethodImplementation( |
|
||||||
cardinality.Cardinality.STREAM_UNARY, style.Service.INLINE, None, None, |
|
||||||
behavior, None, None, None, None, None) |
|
||||||
|
|
||||||
|
|
||||||
def stream_stream_inline(behavior): |
|
||||||
"""Creates an interfaces.MethodImplementation for the given behavior. |
|
||||||
|
|
||||||
Args: |
|
||||||
behavior: The implementation of a stream-stream RPC method as a callable |
|
||||||
value that takes an iterator of request values and a |
|
||||||
face_interfaces.RpcContext object and returns an iterator of response |
|
||||||
values. |
|
||||||
|
|
||||||
Returns: |
|
||||||
An interfaces.MethodImplementation derived from the given behavior. |
|
||||||
""" |
|
||||||
return _MethodImplementation( |
|
||||||
cardinality.Cardinality.STREAM_STREAM, style.Service.INLINE, None, None, |
|
||||||
None, behavior, None, None, None, None) |
|
||||||
|
|
||||||
|
|
||||||
def unary_unary_event(behavior): |
|
||||||
"""Creates an interfaces.MethodImplementation for the given behavior. |
|
||||||
|
|
||||||
Args: |
|
||||||
behavior: The implementation of a unary-unary RPC method as a callable |
|
||||||
value that takes a request value, a response callback to which to pass |
|
||||||
the response value of the RPC, and a face_interfaces.RpcContext. |
|
||||||
|
|
||||||
Returns: |
|
||||||
An interfaces.MethodImplementation derived from the given behavior. |
|
||||||
""" |
|
||||||
return _MethodImplementation( |
|
||||||
cardinality.Cardinality.UNARY_UNARY, style.Service.EVENT, None, None, |
|
||||||
None, None, behavior, None, None, None) |
|
||||||
|
|
||||||
|
|
||||||
def unary_stream_event(behavior): |
|
||||||
"""Creates an interfaces.MethodImplementation for the given behavior. |
|
||||||
|
|
||||||
Args: |
|
||||||
behavior: The implementation of a unary-stream RPC method as a callable |
|
||||||
value that takes a request value, a stream.Consumer to which to pass the |
|
||||||
the response values of the RPC, and a face_interfaces.RpcContext. |
|
||||||
|
|
||||||
Returns: |
|
||||||
An interfaces.MethodImplementation derived from the given behavior. |
|
||||||
""" |
|
||||||
return _MethodImplementation( |
|
||||||
cardinality.Cardinality.UNARY_STREAM, style.Service.EVENT, None, None, |
|
||||||
None, None, None, behavior, None, None) |
|
||||||
|
|
||||||
|
|
||||||
def stream_unary_event(behavior): |
|
||||||
"""Creates an interfaces.MethodImplementation for the given behavior. |
|
||||||
|
|
||||||
Args: |
|
||||||
behavior: The implementation of a stream-unary RPC method as a callable |
|
||||||
value that takes a response callback to which to pass the response value |
|
||||||
of the RPC and a face_interfaces.RpcContext and returns a stream.Consumer |
|
||||||
to which the request values of the RPC should be passed. |
|
||||||
|
|
||||||
Returns: |
|
||||||
An interfaces.MethodImplementation derived from the given behavior. |
|
||||||
""" |
|
||||||
return _MethodImplementation( |
|
||||||
cardinality.Cardinality.STREAM_UNARY, style.Service.EVENT, None, None, |
|
||||||
None, None, None, None, behavior, None) |
|
||||||
|
|
||||||
|
|
||||||
def stream_stream_event(behavior): |
|
||||||
"""Creates an interfaces.MethodImplementation for the given behavior. |
|
||||||
|
|
||||||
Args: |
|
||||||
behavior: The implementation of a stream-stream RPC method as a callable |
|
||||||
value that takes a stream.Consumer to which to pass the response values |
|
||||||
of the RPC and a face_interfaces.RpcContext and returns a stream.Consumer |
|
||||||
to which the request values of the RPC should be passed. |
|
||||||
|
|
||||||
Returns: |
|
||||||
An interfaces.MethodImplementation derived from the given behavior. |
|
||||||
""" |
|
||||||
return _MethodImplementation( |
|
||||||
cardinality.Cardinality.STREAM_STREAM, style.Service.EVENT, None, None, |
|
||||||
None, None, None, None, None, behavior) |
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue