commit
c3e1c72194
610 changed files with 27586 additions and 11933 deletions
@ -0,0 +1,100 @@ |
||||
[MASTER] |
||||
ignore= |
||||
src/python/grpcio/grpc/beta, |
||||
src/python/grpcio/grpc/framework, |
||||
src/python/grpcio/grpc/framework/common, |
||||
src/python/grpcio/grpc/framework/foundation, |
||||
src/python/grpcio/grpc/framework/interfaces, |
||||
|
||||
[VARIABLES] |
||||
|
||||
# TODO(https://github.com/PyCQA/pylint/issues/1345): How does the inspection |
||||
# not include "unused_" and "ignored_" by default? |
||||
dummy-variables-rgx=^ignored_|^unused_ |
||||
|
||||
[DESIGN] |
||||
|
||||
# NOTE(nathaniel): Not particularly attached to this value; it just seems to |
||||
# be what works for us at the moment (excepting the dead-code-walking Beta |
||||
# API). |
||||
max-args=6 |
||||
|
||||
[MISCELLANEOUS] |
||||
|
||||
# NOTE(nathaniel): We are big fans of "TODO(<issue link>): " and |
||||
# "NOTE(<username or issue link>): ". We do not allow "TODO:", |
||||
# "TODO(<username>):", "FIXME:", or anything else. |
||||
notes=FIXME,XXX |
||||
|
||||
[MESSAGES CONTROL] |
||||
|
||||
disable= |
||||
# -- START OF EXAMPLE-SPECIFIC SUPPRESSIONS -- |
||||
no-self-use, |
||||
unused-argument, |
||||
unused-variable, |
||||
# -- END OF EXAMPLE-SPECIFIC SUPPRESSIONS -- |
||||
|
||||
# TODO(https://github.com/PyCQA/pylint/issues/59#issuecomment-283774279): |
||||
# Enable cyclic-import after a 1.7-or-later pylint release that |
||||
# recognizes our disable=cyclic-import suppressions. |
||||
cyclic-import, |
||||
# TODO(https://github.com/grpc/grpc/issues/8622): Enable this after the |
||||
# Beta API is removed. |
||||
duplicate-code, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Doesn't seem to |
||||
# understand enum and concurrent.futures; look into this later with the |
||||
# latest pylint version. |
||||
import-error, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Enable this one. |
||||
# Should take a little configuration but not much. |
||||
invalid-name, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): This doesn't seem to |
||||
# work for now? Try with a later pylint? |
||||
locally-disabled, |
||||
# NOTE(nathaniel): What even is this? *Enabling* an inspection results |
||||
# in a warning? How does that encourage more analysis and coverage? |
||||
locally-enabled, |
||||
# NOTE(nathaniel): We don't write doc strings for most private code |
||||
# elements. |
||||
missing-docstring, |
||||
# NOTE(nathaniel): In numeric comparisons it is better to have the |
||||
# lesser (or lesser-or-equal-to) quantity on the left when the |
||||
# expression is true than it is to worry about which is an identifier |
||||
# and which a literal value. |
||||
misplaced-comparison-constant, |
||||
# NOTE(nathaniel): Our completely abstract interface classes don't have |
||||
# constructors. |
||||
no-init, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Doesn't yet play |
||||
# nicely with some of our code being implemented in Cython. Maybe in a |
||||
# later version? |
||||
no-name-in-module, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Suppress these where |
||||
# the odd shape of the authentication portion of the API forces them on |
||||
# us and enable everywhere else. |
||||
protected-access, |
||||
# NOTE(nathaniel): Pylint and I will probably never agree on this. |
||||
too-few-public-methods, |
||||
# NOTE(nathaniel): Pylint and I wil probably never agree on this for |
||||
# private classes. For public classes maybe? |
||||
too-many-instance-attributes, |
||||
# NOTE(nathaniel): Some of our modules have a lot of lines... of |
||||
# specification and documentation. Maybe if this were |
||||
# lines-of-code-based we would use it. |
||||
too-many-lines, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have |
||||
# this one if we extracted just a few more helper functions... |
||||
too-many-nested-blocks, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Disable unnecessary |
||||
# super-init requirement for abstract class implementations for now. |
||||
super-init-not-called, |
||||
# NOTE(nathaniel): A single statement that always returns program |
||||
# control is better than two statements the first of which sometimes |
||||
# returns program control and the second of which always returns |
||||
# program control. Probably generally, but definitely in the cases of |
||||
# if:/else: and for:/else:. |
||||
useless-else-on-loop, |
||||
no-else-return, |
||||
# NOTE(lidiz): Python 3 make object inheritance default, but not PY2 |
||||
useless-object-inheritance, |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,110 @@ |
||||
#
|
||||
# Copyright 2018 gRPC authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
|
||||
SYSTEM ?= $(HOST_SYSTEM)
|
||||
CXX = g++
|
||||
CPPFLAGS += `pkg-config --cflags protobuf grpc`
|
||||
CXXFLAGS += -std=c++11
|
||||
ifeq ($(SYSTEM),Darwin) |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-lgrpc++_reflection\
|
||||
-ldl
|
||||
else |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
|
||||
-ldl
|
||||
endif |
||||
PROTOC = protoc
|
||||
GRPC_CPP_PLUGIN = grpc_cpp_plugin
|
||||
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
|
||||
|
||||
PROTOS_PATH = ../../protos
|
||||
|
||||
vpath %.proto $(PROTOS_PATH) |
||||
|
||||
all: system-check greeter_client greeter_server |
||||
|
||||
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o |
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
|
||||
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o |
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
|
||||
.PRECIOUS: %.grpc.pb.cc |
||||
%.grpc.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
|
||||
|
||||
.PRECIOUS: %.pb.cc |
||||
%.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
|
||||
|
||||
clean: |
||||
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
|
||||
|
||||
|
||||
# The following is to test your system and ensure a smoother experience.
|
||||
# They are by no means necessary to actually compile a grpc-enabled software.
|
||||
|
||||
PROTOC_CMD = which $(PROTOC)
|
||||
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
|
||||
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
|
||||
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
|
||||
ifeq ($(HAS_PROTOC),true) |
||||
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
|
||||
endif |
||||
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
|
||||
|
||||
SYSTEM_OK = false
|
||||
ifeq ($(HAS_VALID_PROTOC),true) |
||||
ifeq ($(HAS_PLUGIN),true) |
||||
SYSTEM_OK = true
|
||||
endif |
||||
endif |
||||
|
||||
system-check: |
||||
ifneq ($(HAS_VALID_PROTOC),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have protoc 3.0.0 installed in your path."
|
||||
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
|
||||
@echo "You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to evaluate your version of protoc:"
|
||||
@echo
|
||||
-$(PROTOC) --version
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(HAS_PLUGIN),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
|
||||
@echo "Please install grpc. You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/grpc/grpc"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to detect if you have the plugin:"
|
||||
@echo
|
||||
-which $(GRPC_CPP_PLUGIN)
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(SYSTEM_OK),true) |
||||
@false
|
||||
endif |
@ -0,0 +1,84 @@ |
||||
# gRPC C++ Message Compression Tutorial |
||||
|
||||
### Prerequisite |
||||
Make sure you have run the [hello world example](../helloworld) or understood the basics of gRPC. We will not dive into the details that have been discussed in the hello world example. |
||||
|
||||
### Get the tutorial source code |
||||
|
||||
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: |
||||
|
||||
|
||||
```sh |
||||
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc |
||||
``` |
||||
|
||||
Change your current directory to examples/cpp/compression |
||||
|
||||
```sh |
||||
$ cd examples/cpp/compression/ |
||||
``` |
||||
|
||||
### Generating gRPC code |
||||
|
||||
To generate the client and server side interfaces: |
||||
|
||||
```sh |
||||
$ make helloworld.grpc.pb.cc helloworld.pb.cc |
||||
``` |
||||
Which internally invokes the proto-compiler as: |
||||
|
||||
```sh |
||||
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto |
||||
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto |
||||
``` |
||||
|
||||
### Writing a client and a server |
||||
|
||||
The client and the server can be based on the hello world example. |
||||
|
||||
Additionally, we can configure the compression settings. |
||||
|
||||
In the client, set the default compression algorithm of the channel via the channel arg. |
||||
|
||||
```cpp |
||||
ChannelArguments args; |
||||
// Set the default compression algorithm for the channel. |
||||
args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP); |
||||
GreeterClient greeter(grpc::CreateCustomChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args)); |
||||
``` |
||||
|
||||
Each call's compression configuration can be overwritten by client context. |
||||
|
||||
```cpp |
||||
// Overwrite the call's compression algorithm to DEFLATE. |
||||
context.set_compression_algorithm(GRPC_COMPRESS_DEFLATE); |
||||
``` |
||||
|
||||
In the server, set the default compression algorithm via the server builder. |
||||
|
||||
```cpp |
||||
ServerBuilder builder; |
||||
// Set the default compression algorithm for the server. |
||||
builder.SetDefaultCompressionAlgorithm(GRPC_COMPRESS_GZIP); |
||||
``` |
||||
|
||||
Each call's compression configuration can be overwritten by server context. |
||||
|
||||
```cpp |
||||
// Overwrite the call's compression algorithm to DEFLATE. |
||||
context->set_compression_algorithm(GRPC_COMPRESS_DEFLATE); |
||||
``` |
||||
|
||||
For a working example, refer to [greeter_client.cc](greeter_client.cc) and [greeter_server.cc](greeter_server.cc). |
||||
|
||||
Build and run the (compressing) client and the server by the following commands. |
||||
|
||||
```sh |
||||
make |
||||
./greeter_server |
||||
``` |
||||
|
||||
```sh |
||||
./greeter_client |
||||
``` |
@ -0,0 +1,93 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ChannelArguments; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
class GreeterClient { |
||||
public: |
||||
GreeterClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and presents the response back
|
||||
// from the server.
|
||||
std::string SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// Overwrite the call's compression algorithm to DEFLATE.
|
||||
context.set_compression_algorithm(GRPC_COMPRESS_DEFLATE); |
||||
|
||||
// The actual RPC.
|
||||
Status status = stub_->SayHello(&context, request, &reply); |
||||
|
||||
// Act upon its status.
|
||||
if (status.ok()) { |
||||
return reply.message(); |
||||
} else { |
||||
std::cout << status.error_code() << ": " << status.error_message() |
||||
<< std::endl; |
||||
return "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
ChannelArguments args; |
||||
// Set the default compression algorithm for the channel.
|
||||
args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP); |
||||
GreeterClient greeter(grpc::CreateCustomChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args)); |
||||
std::string user("world"); |
||||
std::string reply = greeter.SayHello(user); |
||||
std::cout << "Greeter received: " << reply << std::endl; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,76 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service { |
||||
Status SayHello(ServerContext* context, const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
// Overwrite the call's compression algorithm to DEFLATE.
|
||||
context->set_compression_algorithm(GRPC_COMPRESS_DEFLATE); |
||||
std::string prefix("Hello "); |
||||
reply->set_message(prefix + request->name()); |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void RunServer() { |
||||
std::string server_address("0.0.0.0:50051"); |
||||
GreeterServiceImpl service; |
||||
|
||||
ServerBuilder builder; |
||||
// Set the default compression algorithm for the server.
|
||||
builder.SetDefaultCompressionAlgorithm(GRPC_COMPRESS_GZIP); |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
RunServer(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,134 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <map> |
||||
|
||||
#include <grpcpp/support/client_interceptor.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/keyvaluestore.grpc.pb.h" |
||||
#else |
||||
#include "keyvaluestore.grpc.pb.h" |
||||
#endif |
||||
|
||||
// This is a naive implementation of a cache. A new cache is for each call. For
|
||||
// each new key request, the key is first searched in the map and if found, the
|
||||
// interceptor fills in the return value without making a request to the server.
|
||||
// Only if the key is not found in the cache do we make a request.
|
||||
class CachingInterceptor : public grpc::experimental::Interceptor { |
||||
public: |
||||
CachingInterceptor(grpc::experimental::ClientRpcInfo* info) {} |
||||
|
||||
void Intercept( |
||||
::grpc::experimental::InterceptorBatchMethods* methods) override { |
||||
bool hijack = false; |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints:: |
||||
PRE_SEND_INITIAL_METADATA)) { |
||||
// Hijack all calls
|
||||
hijack = true; |
||||
// Create a stream on which this interceptor can make requests
|
||||
stub_ = keyvaluestore::KeyValueStore::NewStub( |
||||
methods->GetInterceptedChannel()); |
||||
stream_ = stub_->GetValues(&context_); |
||||
} |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) { |
||||
// We know that clients perform a Read and a Write in a loop, so we don't
|
||||
// need to maintain a list of the responses.
|
||||
std::string requested_key; |
||||
const keyvaluestore::Request* req_msg = |
||||
static_cast<const keyvaluestore::Request*>(methods->GetSendMessage()); |
||||
if (req_msg != nullptr) { |
||||
requested_key = req_msg->key(); |
||||
} else { |
||||
// The non-serialized form would not be available in certain scenarios,
|
||||
// so add a fallback
|
||||
keyvaluestore::Request req_msg; |
||||
auto* buffer = methods->GetSerializedSendMessage(); |
||||
auto copied_buffer = *buffer; |
||||
GPR_ASSERT( |
||||
grpc::SerializationTraits<keyvaluestore::Request>::Deserialize( |
||||
&copied_buffer, &req_msg) |
||||
.ok()); |
||||
requested_key = req_msg.key(); |
||||
} |
||||
|
||||
// Check if the key is present in the map
|
||||
auto search = cached_map_.find(requested_key); |
||||
if (search != cached_map_.end()) { |
||||
std::cout << "Key " << requested_key << "found in map"; |
||||
response_ = search->second; |
||||
} else { |
||||
std::cout << "Key " << requested_key << "not found in cache"; |
||||
// Key was not found in the cache, so make a request
|
||||
keyvaluestore::Request req; |
||||
req.set_key(requested_key); |
||||
stream_->Write(req); |
||||
keyvaluestore::Response resp; |
||||
stream_->Read(&resp); |
||||
response_ = resp.value(); |
||||
// Insert the pair in the cache for future requests
|
||||
cached_map_.insert({requested_key, response_}); |
||||
} |
||||
} |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) { |
||||
stream_->WritesDone(); |
||||
} |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints::PRE_RECV_MESSAGE)) { |
||||
keyvaluestore::Response* resp = |
||||
static_cast<keyvaluestore::Response*>(methods->GetRecvMessage()); |
||||
resp->set_value(response_); |
||||
} |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints::PRE_RECV_STATUS)) { |
||||
auto* status = methods->GetRecvStatus(); |
||||
*status = grpc::Status::OK; |
||||
} |
||||
// One of Hijack or Proceed always needs to be called to make progress.
|
||||
if (hijack) { |
||||
// Hijack is called only once when PRE_SEND_INITIAL_METADATA is present in
|
||||
// the hook points
|
||||
methods->Hijack(); |
||||
} else { |
||||
// Proceed is an indicator that the interceptor is done intercepting the
|
||||
// batch.
|
||||
methods->Proceed(); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
grpc::ClientContext context_; |
||||
std::unique_ptr<keyvaluestore::KeyValueStore::Stub> stub_; |
||||
std::unique_ptr< |
||||
grpc::ClientReaderWriter<keyvaluestore::Request, keyvaluestore::Response>> |
||||
stream_; |
||||
std::map<std::string, std::string> cached_map_; |
||||
std::string response_; |
||||
}; |
||||
|
||||
class CachingInterceptorFactory |
||||
: public grpc::experimental::ClientInterceptorFactoryInterface { |
||||
public: |
||||
grpc::experimental::Interceptor* CreateClientInterceptor( |
||||
grpc::experimental::ClientRpcInfo* info) override { |
||||
return new CachingInterceptor(info); |
||||
} |
||||
}; |
@ -0,0 +1,99 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#include "caching_interceptor.h" |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/keyvaluestore.grpc.pb.h" |
||||
#else |
||||
#include "keyvaluestore.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using keyvaluestore::KeyValueStore; |
||||
using keyvaluestore::Request; |
||||
using keyvaluestore::Response; |
||||
|
||||
class KeyValueStoreClient { |
||||
public: |
||||
KeyValueStoreClient(std::shared_ptr<Channel> channel) |
||||
: stub_(KeyValueStore::NewStub(channel)) {} |
||||
|
||||
// Requests each key in the vector and displays the key and its corresponding
|
||||
// value as a pair
|
||||
void GetValues(const std::vector<std::string>& keys) { |
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
auto stream = stub_->GetValues(&context); |
||||
for (const auto& key : keys) { |
||||
// Key we are sending to the server.
|
||||
Request request; |
||||
request.set_key(key); |
||||
stream->Write(request); |
||||
|
||||
// Get the value for the sent key
|
||||
Response response; |
||||
stream->Read(&response); |
||||
std::cout << key << " : " << response.value() << "\n"; |
||||
} |
||||
stream->WritesDone(); |
||||
Status status = stream->Finish(); |
||||
if (!status.ok()) { |
||||
std::cout << status.error_code() << ": " << status.error_message() |
||||
<< std::endl; |
||||
std::cout << "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<KeyValueStore::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
// In this example, we are using a cache which has been added in as an
|
||||
// interceptor.
|
||||
grpc::ChannelArguments args; |
||||
std::vector< |
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>> |
||||
interceptor_creators; |
||||
interceptor_creators.push_back(std::unique_ptr<CachingInterceptorFactory>( |
||||
new CachingInterceptorFactory())); |
||||
auto channel = grpc::experimental::CreateCustomChannelWithInterceptors( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args, |
||||
std::move(interceptor_creators)); |
||||
KeyValueStoreClient client(channel); |
||||
std::vector<std::string> keys = {"key1", "key2", "key3", "key4", |
||||
"key5", "key1", "key2", "key4"}; |
||||
client.GetValues(keys); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,97 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/keyvaluestore.grpc.pb.h" |
||||
#else |
||||
#include "keyvaluestore.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::ServerReaderWriter; |
||||
using grpc::Status; |
||||
using keyvaluestore::KeyValueStore; |
||||
using keyvaluestore::Request; |
||||
using keyvaluestore::Response; |
||||
|
||||
struct kv_pair { |
||||
const char* key; |
||||
const char* value; |
||||
}; |
||||
|
||||
static const kv_pair kvs_map[] = { |
||||
{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}, |
||||
{"key4", "value4"}, {"key5", "value5"}, |
||||
}; |
||||
|
||||
const char* get_value_from_map(const char* key) { |
||||
for (size_t i = 0; i < sizeof(kvs_map) / sizeof(kv_pair); ++i) { |
||||
if (strcmp(key, kvs_map[i].key) == 0) { |
||||
return kvs_map[i].value; |
||||
} |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class KeyValueStoreServiceImpl final : public KeyValueStore::Service { |
||||
Status GetValues(ServerContext* context, |
||||
ServerReaderWriter<Response, Request>* stream) override { |
||||
Request request; |
||||
while (stream->Read(&request)) { |
||||
Response response; |
||||
response.set_value(get_value_from_map(request.key().c_str())); |
||||
stream->Write(response); |
||||
} |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void RunServer() { |
||||
std::string server_address("0.0.0.0:50051"); |
||||
KeyValueStoreServiceImpl service; |
||||
|
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case, it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
RunServer(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,110 @@ |
||||
#
|
||||
# Copyright 2018 gRPC authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
|
||||
SYSTEM ?= $(HOST_SYSTEM)
|
||||
CXX = g++
|
||||
CPPFLAGS += `pkg-config --cflags protobuf grpc`
|
||||
CXXFLAGS += -std=c++11
|
||||
ifeq ($(SYSTEM),Darwin) |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-lgrpc++_reflection\
|
||||
-ldl
|
||||
else |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
|
||||
-ldl
|
||||
endif |
||||
PROTOC = protoc
|
||||
GRPC_CPP_PLUGIN = grpc_cpp_plugin
|
||||
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
|
||||
|
||||
PROTOS_PATH = ../../protos
|
||||
|
||||
vpath %.proto $(PROTOS_PATH) |
||||
|
||||
all: system-check greeter_client greeter_server |
||||
|
||||
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o |
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
|
||||
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o |
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
|
||||
.PRECIOUS: %.grpc.pb.cc |
||||
%.grpc.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
|
||||
|
||||
.PRECIOUS: %.pb.cc |
||||
%.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
|
||||
|
||||
clean: |
||||
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
|
||||
|
||||
|
||||
# The following is to test your system and ensure a smoother experience.
|
||||
# They are by no means necessary to actually compile a grpc-enabled software.
|
||||
|
||||
PROTOC_CMD = which $(PROTOC)
|
||||
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
|
||||
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
|
||||
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
|
||||
ifeq ($(HAS_PROTOC),true) |
||||
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
|
||||
endif |
||||
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
|
||||
|
||||
SYSTEM_OK = false
|
||||
ifeq ($(HAS_VALID_PROTOC),true) |
||||
ifeq ($(HAS_PLUGIN),true) |
||||
SYSTEM_OK = true
|
||||
endif |
||||
endif |
||||
|
||||
system-check: |
||||
ifneq ($(HAS_VALID_PROTOC),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have protoc 3.0.0 installed in your path."
|
||||
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
|
||||
@echo "You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to evaluate your version of protoc:"
|
||||
@echo
|
||||
-$(PROTOC) --version
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(HAS_PLUGIN),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
|
||||
@echo "Please install grpc. You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/grpc/grpc"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to detect if you have the plugin:"
|
||||
@echo
|
||||
-which $(GRPC_CPP_PLUGIN)
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(SYSTEM_OK),true) |
||||
@false
|
||||
endif |
@ -0,0 +1,64 @@ |
||||
# gRPC C++ Load Balancing Tutorial |
||||
|
||||
### Prerequisite |
||||
Make sure you have run the [hello world example](../helloworld) or understood the basics of gRPC. We will not dive into the details that have been discussed in the hello world example. |
||||
|
||||
### Get the tutorial source code |
||||
|
||||
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: |
||||
|
||||
|
||||
```sh |
||||
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc |
||||
``` |
||||
|
||||
Change your current directory to examples/cpp/load_balancing |
||||
|
||||
```sh |
||||
$ cd examples/cpp/load_balancing/ |
||||
``` |
||||
|
||||
### Generating gRPC code |
||||
|
||||
To generate the client and server side interfaces: |
||||
|
||||
```sh |
||||
$ make helloworld.grpc.pb.cc helloworld.pb.cc |
||||
``` |
||||
Which internally invokes the proto-compiler as: |
||||
|
||||
```sh |
||||
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto |
||||
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto |
||||
``` |
||||
|
||||
### Writing a client and a server |
||||
|
||||
The client and the server can be based on the hello world example. |
||||
|
||||
Additionally, we can configure the load balancing policy. (To see what load balancing policies are available, check out [this folder](https://github.com/grpc/grpc/tree/master/src/core/ext/filters/client_channel/lb_policy).) |
||||
|
||||
In the client, set the load balancing policy of the channel via the channel arg (to, for example, Round Robin). |
||||
|
||||
```cpp |
||||
ChannelArguments args; |
||||
// Set the load balancing policy for the channel. |
||||
args.SetLoadBalancingPolicyName("round_robin"); |
||||
GreeterClient greeter(grpc::CreateCustomChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args)); |
||||
``` |
||||
|
||||
For a working example, refer to [greeter_client.cc](greeter_client.cc) and [greeter_server.cc](greeter_server.cc). |
||||
|
||||
Build and run the client and the server with the following commands. |
||||
|
||||
```sh |
||||
make |
||||
./greeter_server |
||||
``` |
||||
|
||||
```sh |
||||
./greeter_client |
||||
``` |
||||
|
||||
(Note that the case in this example is trivial because there is only one server resolved from the name.) |
@ -0,0 +1,90 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ChannelArguments; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
class GreeterClient { |
||||
public: |
||||
GreeterClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and presents the response back
|
||||
// from the server.
|
||||
std::string SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// The actual RPC.
|
||||
Status status = stub_->SayHello(&context, request, &reply); |
||||
|
||||
// Act upon its status.
|
||||
if (status.ok()) { |
||||
return reply.message(); |
||||
} else { |
||||
std::cout << status.error_code() << ": " << status.error_message() |
||||
<< std::endl; |
||||
return "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
ChannelArguments args; |
||||
// Set the load balancing policy for the channel.
|
||||
args.SetLoadBalancingPolicyName("round_robin"); |
||||
GreeterClient greeter(grpc::CreateCustomChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args)); |
||||
std::string user("world"); |
||||
std::string reply = greeter.SayHello(user); |
||||
std::cout << "Greeter received: " << reply << std::endl; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,72 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service { |
||||
Status SayHello(ServerContext* context, const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
std::string prefix("Hello "); |
||||
reply->set_message(prefix + request->name()); |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void RunServer() { |
||||
std::string server_address("0.0.0.0:50051"); |
||||
GreeterServiceImpl service; |
||||
|
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
RunServer(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,96 @@ |
||||
#
|
||||
# Copyright 2018 gRPC authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
|
||||
SYSTEM ?= $(HOST_SYSTEM)
|
||||
CXX = g++
|
||||
CPPFLAGS += `pkg-config --cflags protobuf grpc`
|
||||
CXXFLAGS += -std=c++11
|
||||
ifeq ($(SYSTEM),Darwin) |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-lgrpc++_reflection\
|
||||
-ldl
|
||||
else |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
|
||||
-ldl
|
||||
endif |
||||
PROTOC = protoc
|
||||
GRPC_CPP_PLUGIN = grpc_cpp_plugin
|
||||
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
|
||||
PROTOS_PATH = ../../protos
|
||||
vpath %.proto $(PROTOS_PATH)
|
||||
all: system-check greeter_client greeter_server
|
||||
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o
|
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o
|
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
.PRECIOUS: %.grpc.pb.cc
|
||||
%.grpc.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
|
||||
.PRECIOUS: %.pb.cc
|
||||
%.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
|
||||
clean:
|
||||
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
|
||||
# The following is to test your system and ensure a smoother experience.
|
||||
# They are by no means necessary to actually compile a grpc-enabled software.
|
||||
PROTOC_CMD = which $(PROTOC)
|
||||
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
|
||||
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
|
||||
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
|
||||
ifeq ($(HAS_PROTOC),true) |
||||
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
|
||||
endif |
||||
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
|
||||
SYSTEM_OK = false
|
||||
ifeq ($(HAS_VALID_PROTOC),true) |
||||
ifeq ($(HAS_PLUGIN),true) |
||||
SYSTEM_OK = true
|
||||
endif |
||||
endif |
||||
system-check:
|
||||
ifneq ($(HAS_VALID_PROTOC),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have protoc 3.0.0 installed in your path."
|
||||
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
|
||||
@echo "You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to evaluate your version of protoc:"
|
||||
@echo
|
||||
-$(PROTOC) --version
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(HAS_PLUGIN),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
|
||||
@echo "Please install grpc. You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/grpc/grpc"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to detect if you have the plugin:"
|
||||
@echo
|
||||
-which $(GRPC_CPP_PLUGIN)
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(SYSTEM_OK),true) |
||||
@false
|
||||
endif |
@ -0,0 +1,66 @@ |
||||
# Metadata Example |
||||
|
||||
## Overview |
||||
|
||||
This example shows you how to add custom headers on the client and server and |
||||
how to access them. |
||||
|
||||
Custom metadata must follow the "Custom-Metadata" format listed in |
||||
https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md, with the |
||||
exception of binary headers, which don't have to be base64 encoded. |
||||
|
||||
### Get the tutorial source code |
||||
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: |
||||
```sh |
||||
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc |
||||
``` |
||||
Change your current directory to examples/cpp/metadata |
||||
```sh |
||||
$ cd examples/cpp/metadata |
||||
``` |
||||
|
||||
### Generating gRPC code |
||||
To generate the client and server side interfaces: |
||||
```sh |
||||
$ make helloworld.grpc.pb.cc helloworld.pb.cc |
||||
``` |
||||
Which internally invokes the proto-compiler as: |
||||
```sh |
||||
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto |
||||
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto |
||||
``` |
||||
### Try it! |
||||
Build client and server: |
||||
|
||||
```sh |
||||
$ make |
||||
``` |
||||
|
||||
Run the server, which will listen on port 50051: |
||||
|
||||
```sh |
||||
$ ./greeter_server |
||||
``` |
||||
|
||||
Run the client (in a different terminal): |
||||
|
||||
```sh |
||||
$ ./greeter_client |
||||
``` |
||||
|
||||
If things go smoothly, you will see in the client terminal: |
||||
|
||||
"Client received initial metadata from server: initial metadata value" |
||||
"Client received trailing metadata from server: trailing metadata value" |
||||
"Client received message: Hello World" |
||||
|
||||
|
||||
And in the server terminal: |
||||
|
||||
"Header key: custom-bin , value: 01234567" |
||||
"Header key: custom-header , value: Custom Value" |
||||
"Header key: user-agent , value: grpc-c++/1.16.0-dev grpc-c/6.0.0-dev (linux; chttp2; gao)" |
||||
|
||||
We did not add the user-agent metadata as a custom header. This shows how |
||||
the gRPC framework adds some headers under the hood that may show up in the |
||||
metadata map. |
@ -0,0 +1,95 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
class CustomHeaderClient { |
||||
public: |
||||
CustomHeaderClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and presents the response back
|
||||
// from the server.
|
||||
std::string SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// Setting custom metadata to be sent to the server
|
||||
context.AddMetadata("custom-header", "Custom Value"); |
||||
|
||||
// Setting custom binary metadata
|
||||
char bytes[8] = {'\0', '\1', '\2', '\3', |
||||
'\4', '\5', '\6', '\7'}; |
||||
context.AddMetadata("custom-bin", grpc::string(bytes, 8)); |
||||
|
||||
// The actual RPC.
|
||||
Status status = stub_->SayHello(&context, request, &reply); |
||||
|
||||
// Act upon its status.
|
||||
if (status.ok()) { |
||||
std::cout << "Client received initial metadata from server: " << context.GetServerInitialMetadata().find("custom-server-metadata")->second << std::endl; |
||||
std::cout << "Client received trailing metadata from server: " << context.GetServerTrailingMetadata().find("custom-trailing-metadata")->second << std::endl; |
||||
return reply.message(); |
||||
} else { |
||||
std::cout << status.error_code() << ": " << status.error_message() |
||||
<< std::endl; |
||||
return "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
CustomHeaderClient greeter(grpc::CreateChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials())); |
||||
std::string user("world"); |
||||
std::string reply = greeter.SayHello(user); |
||||
std::cout << "Client received message: " << reply << std::endl; |
||||
return 0; |
||||
} |
@ -0,0 +1,94 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service { |
||||
Status SayHello(ServerContext* context, const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
std::string prefix("Hello "); |
||||
|
||||
// Get the client's initial metadata
|
||||
std::cout << "Client metadata: " << std::endl; |
||||
const std::multimap<grpc::string_ref, grpc::string_ref> metadata = context->client_metadata(); |
||||
for (auto iter = metadata.begin(); iter != metadata.end(); ++iter) { |
||||
std::cout << "Header key: " << iter->first << ", value: "; |
||||
// Check for binary value
|
||||
size_t isbin = iter->first.find("-bin"); |
||||
if ((isbin != std::string::npos) && (isbin + 4 == iter->first.size())) { |
||||
std::cout << std::hex; |
||||
for (auto c : iter->second) { |
||||
std::cout << static_cast<unsigned int>(c); |
||||
} |
||||
std::cout << std::dec; |
||||
} else { |
||||
std::cout << iter->second; |
||||
} |
||||
std::cout << std::endl; |
||||
} |
||||
|
||||
context->AddInitialMetadata("custom-server-metadata", "initial metadata value"); |
||||
context->AddTrailingMetadata("custom-trailing-metadata", "trailing metadata value"); |
||||
reply->set_message(prefix + request->name()); |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void RunServer() { |
||||
std::string server_address("0.0.0.0:50051"); |
||||
GreeterServiceImpl service; |
||||
|
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
RunServer(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,33 @@ |
||||
// Copyright 2018 gRPC authors. |
||||
// |
||||
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||
// you may not use this file except in compliance with the License. |
||||
// You may obtain a copy of the License at |
||||
// |
||||
// http://www.apache.org/licenses/LICENSE-2.0 |
||||
// |
||||
// Unless required by applicable law or agreed to in writing, software |
||||
// distributed under the License is distributed on an "AS IS" BASIS, |
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
// See the License for the specific language governing permissions and |
||||
// limitations under the License. |
||||
|
||||
syntax = "proto3"; |
||||
|
||||
package keyvaluestore; |
||||
|
||||
// A simple key-value storage service |
||||
service KeyValueStore { |
||||
// Provides a value for each key request |
||||
rpc GetValues (stream Request) returns (stream Response) {} |
||||
} |
||||
|
||||
// The request message containing the key |
||||
message Request { |
||||
string key = 1; |
||||
} |
||||
|
||||
// The response message containing the value associated with the key |
||||
message Response { |
||||
string value = 1; |
||||
} |
@ -0,0 +1,6 @@ |
||||
An example showing how to add custom HTTP2 headers (or [metadata](https://grpc.io/grpc/python/glossary.html) in gRPC glossary) |
||||
|
||||
HTTP2 supports initial headers and trailing headers, which gRPC utilizes both of them ([learn more](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md)). |
||||
|
||||
More complete documentation lives at [grpc.io](https://grpc.io/docs/tutorials/basic/python.html). |
||||
For API reference please see [API](https://grpc.io/grpc/python/grpc.html). |
@ -0,0 +1,134 @@ |
||||
# Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
# source: helloworld.proto |
||||
|
||||
import sys |
||||
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) |
||||
from google.protobuf import descriptor as _descriptor |
||||
from google.protobuf import message as _message |
||||
from google.protobuf import reflection as _reflection |
||||
from google.protobuf import symbol_database as _symbol_database |
||||
from google.protobuf import descriptor_pb2 |
||||
# @@protoc_insertion_point(imports) |
||||
|
||||
_sym_db = _symbol_database.Default() |
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor( |
||||
name='helloworld.proto', |
||||
package='helloworld', |
||||
syntax='proto3', |
||||
serialized_pb=_b('\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3') |
||||
) |
||||
|
||||
|
||||
|
||||
|
||||
_HELLOREQUEST = _descriptor.Descriptor( |
||||
name='HelloRequest', |
||||
full_name='helloworld.HelloRequest', |
||||
filename=None, |
||||
file=DESCRIPTOR, |
||||
containing_type=None, |
||||
fields=[ |
||||
_descriptor.FieldDescriptor( |
||||
name='name', full_name='helloworld.HelloRequest.name', index=0, |
||||
number=1, type=9, cpp_type=9, label=1, |
||||
has_default_value=False, default_value=_b("").decode('utf-8'), |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
], |
||||
extensions=[ |
||||
], |
||||
nested_types=[], |
||||
enum_types=[ |
||||
], |
||||
options=None, |
||||
is_extendable=False, |
||||
syntax='proto3', |
||||
extension_ranges=[], |
||||
oneofs=[ |
||||
], |
||||
serialized_start=32, |
||||
serialized_end=60, |
||||
) |
||||
|
||||
|
||||
_HELLOREPLY = _descriptor.Descriptor( |
||||
name='HelloReply', |
||||
full_name='helloworld.HelloReply', |
||||
filename=None, |
||||
file=DESCRIPTOR, |
||||
containing_type=None, |
||||
fields=[ |
||||
_descriptor.FieldDescriptor( |
||||
name='message', full_name='helloworld.HelloReply.message', index=0, |
||||
number=1, type=9, cpp_type=9, label=1, |
||||
has_default_value=False, default_value=_b("").decode('utf-8'), |
||||
message_type=None, enum_type=None, containing_type=None, |
||||
is_extension=False, extension_scope=None, |
||||
options=None), |
||||
], |
||||
extensions=[ |
||||
], |
||||
nested_types=[], |
||||
enum_types=[ |
||||
], |
||||
options=None, |
||||
is_extendable=False, |
||||
syntax='proto3', |
||||
extension_ranges=[], |
||||
oneofs=[ |
||||
], |
||||
serialized_start=62, |
||||
serialized_end=91, |
||||
) |
||||
|
||||
DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST |
||||
DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY |
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR) |
||||
|
||||
HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict( |
||||
DESCRIPTOR = _HELLOREQUEST, |
||||
__module__ = 'helloworld_pb2' |
||||
# @@protoc_insertion_point(class_scope:helloworld.HelloRequest) |
||||
)) |
||||
_sym_db.RegisterMessage(HelloRequest) |
||||
|
||||
HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict( |
||||
DESCRIPTOR = _HELLOREPLY, |
||||
__module__ = 'helloworld_pb2' |
||||
# @@protoc_insertion_point(class_scope:helloworld.HelloReply) |
||||
)) |
||||
_sym_db.RegisterMessage(HelloReply) |
||||
|
||||
|
||||
DESCRIPTOR.has_options = True |
||||
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW')) |
||||
|
||||
_GREETER = _descriptor.ServiceDescriptor( |
||||
name='Greeter', |
||||
full_name='helloworld.Greeter', |
||||
file=DESCRIPTOR, |
||||
index=0, |
||||
options=None, |
||||
serialized_start=93, |
||||
serialized_end=166, |
||||
methods=[ |
||||
_descriptor.MethodDescriptor( |
||||
name='SayHello', |
||||
full_name='helloworld.Greeter.SayHello', |
||||
index=0, |
||||
containing_service=None, |
||||
input_type=_HELLOREQUEST, |
||||
output_type=_HELLOREPLY, |
||||
options=None, |
||||
), |
||||
]) |
||||
_sym_db.RegisterServiceDescriptor(_GREETER) |
||||
|
||||
DESCRIPTOR.services_by_name['Greeter'] = _GREETER |
||||
|
||||
# @@protoc_insertion_point(module_scope) |
@ -0,0 +1,46 @@ |
||||
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! |
||||
import grpc |
||||
|
||||
import helloworld_pb2 as helloworld__pb2 |
||||
|
||||
|
||||
class GreeterStub(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
def __init__(self, channel): |
||||
"""Constructor. |
||||
|
||||
Args: |
||||
channel: A grpc.Channel. |
||||
""" |
||||
self.SayHello = channel.unary_unary( |
||||
'/helloworld.Greeter/SayHello', |
||||
request_serializer=helloworld__pb2.HelloRequest.SerializeToString, |
||||
response_deserializer=helloworld__pb2.HelloReply.FromString, |
||||
) |
||||
|
||||
|
||||
class GreeterServicer(object): |
||||
"""The greeting service definition. |
||||
""" |
||||
|
||||
def SayHello(self, request, context): |
||||
"""Sends a greeting |
||||
""" |
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED) |
||||
context.set_details('Method not implemented!') |
||||
raise NotImplementedError('Method not implemented!') |
||||
|
||||
|
||||
def add_GreeterServicer_to_server(servicer, server): |
||||
rpc_method_handlers = { |
||||
'SayHello': grpc.unary_unary_rpc_method_handler( |
||||
servicer.SayHello, |
||||
request_deserializer=helloworld__pb2.HelloRequest.FromString, |
||||
response_serializer=helloworld__pb2.HelloReply.SerializeToString, |
||||
), |
||||
} |
||||
generic_handler = grpc.method_handlers_generic_handler( |
||||
'helloworld.Greeter', rpc_method_handlers) |
||||
server.add_generic_rpc_handlers((generic_handler,)) |
@ -0,0 +1,48 @@ |
||||
# Copyright 2018 The gRPC Authors |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
"""Example gRPC client that gets/sets metadata (HTTP2 headers)""" |
||||
|
||||
from __future__ import print_function |
||||
import logging |
||||
|
||||
import grpc |
||||
|
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
|
||||
def run(): |
||||
# NOTE(gRPC Python Team): .close() is possible on a channel and should be |
||||
# used in circumstances in which the with statement does not fit the needs |
||||
# of the code. |
||||
with grpc.insecure_channel('localhost:50051') as channel: |
||||
stub = helloworld_pb2_grpc.GreeterStub(channel) |
||||
response, call = stub.SayHello.with_call( |
||||
helloworld_pb2.HelloRequest(name='you'), |
||||
metadata=( |
||||
('initial-metadata-1', 'The value should be str'), |
||||
('binary-metadata-bin', |
||||
b'With -bin surffix, the value can be bytes'), |
||||
('accesstoken', 'gRPC Python is great'), |
||||
)) |
||||
|
||||
print("Greeter client received: " + response.message) |
||||
for key, value in call.trailing_metadata(): |
||||
print('Greeter client received trailing metadata: key=%s value=%s' % |
||||
(key, value)) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
run() |
@ -0,0 +1,56 @@ |
||||
# Copyright 2018 The gRPC Authors |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
"""Example gRPC server that gets/sets metadata (HTTP2 headers)""" |
||||
|
||||
from __future__ import print_function |
||||
from concurrent import futures |
||||
import time |
||||
import logging |
||||
|
||||
import grpc |
||||
|
||||
import helloworld_pb2 |
||||
import helloworld_pb2_grpc |
||||
|
||||
_ONE_DAY_IN_SECONDS = 60 * 60 * 24 |
||||
|
||||
|
||||
class Greeter(helloworld_pb2_grpc.GreeterServicer): |
||||
|
||||
def SayHello(self, request, context): |
||||
for key, value in context.invocation_metadata(): |
||||
print('Received initial metadata: key=%s value=%s' % (key, value)) |
||||
|
||||
context.set_trailing_metadata(( |
||||
('checksum-bin', b'I agree'), |
||||
('retry', 'false'), |
||||
)) |
||||
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) |
||||
|
||||
|
||||
def serve(): |
||||
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) |
||||
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server) |
||||
server.add_insecure_port('[::]:50051') |
||||
server.start() |
||||
try: |
||||
while True: |
||||
time.sleep(_ONE_DAY_IN_SECONDS) |
||||
except KeyboardInterrupt: |
||||
server.stop(0) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
logging.basicConfig() |
||||
serve() |
@ -0,0 +1,116 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
/// An Alarm posts the user provided tag to its associated completion queue upon
|
||||
/// expiry or cancellation.
|
||||
#ifndef GRPCPP_ALARM_IMPL_H |
||||
#define GRPCPP_ALARM_IMPL_H |
||||
|
||||
#include <functional> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpcpp/impl/codegen/completion_queue.h> |
||||
#include <grpcpp/impl/codegen/completion_queue_tag.h> |
||||
#include <grpcpp/impl/codegen/grpc_library.h> |
||||
#include <grpcpp/impl/codegen/time.h> |
||||
#include <grpcpp/impl/grpc_library.h> |
||||
|
||||
namespace grpc_impl { |
||||
|
||||
/// A thin wrapper around \a grpc_alarm (see / \a / src/core/surface/alarm.h).
|
||||
class Alarm : private ::grpc::GrpcLibraryCodegen { |
||||
public: |
||||
/// Create an unset completion queue alarm
|
||||
Alarm(); |
||||
|
||||
/// Destroy the given completion queue alarm, cancelling it in the process.
|
||||
~Alarm(); |
||||
|
||||
/// DEPRECATED: Create and set a completion queue alarm instance associated to
|
||||
/// \a cq.
|
||||
/// This form is deprecated because it is inherently racy.
|
||||
/// \internal We rely on the presence of \a cq for grpc initialization. If \a
|
||||
/// cq were ever to be removed, a reference to a static
|
||||
/// internal::GrpcLibraryInitializer instance would need to be introduced
|
||||
/// here. \endinternal.
|
||||
template <typename T> |
||||
Alarm(::grpc::CompletionQueue* cq, const T& deadline, void* tag) : Alarm() { |
||||
SetInternal(cq, ::grpc::TimePoint<T>(deadline).raw_time(), tag); |
||||
} |
||||
|
||||
/// Trigger an alarm instance on completion queue \a cq at the specified time.
|
||||
/// Once the alarm expires (at \a deadline) or it's cancelled (see \a Cancel),
|
||||
/// an event with tag \a tag will be added to \a cq. If the alarm expired, the
|
||||
/// event's success bit will be true, false otherwise (ie, upon cancellation).
|
||||
template <typename T> |
||||
void Set(::grpc::CompletionQueue* cq, const T& deadline, void* tag) { |
||||
SetInternal(cq, ::grpc::TimePoint<T>(deadline).raw_time(), tag); |
||||
} |
||||
|
||||
/// Alarms aren't copyable.
|
||||
Alarm(const Alarm&) = delete; |
||||
Alarm& operator=(const Alarm&) = delete; |
||||
|
||||
/// Alarms are movable.
|
||||
Alarm(Alarm&& rhs) : alarm_(rhs.alarm_) { rhs.alarm_ = nullptr; } |
||||
Alarm& operator=(Alarm&& rhs) { |
||||
alarm_ = rhs.alarm_; |
||||
rhs.alarm_ = nullptr; |
||||
return *this; |
||||
} |
||||
|
||||
/// Cancel a completion queue alarm. Calling this function over an alarm that
|
||||
/// has already fired has no effect.
|
||||
void Cancel(); |
||||
|
||||
/// NOTE: class experimental_type is not part of the public API of this class
|
||||
/// TODO(vjpai): Move these contents to the public API of Alarm when
|
||||
/// they are no longer experimental
|
||||
class experimental_type { |
||||
public: |
||||
explicit experimental_type(Alarm* alarm) : alarm_(alarm) {} |
||||
|
||||
/// Set an alarm to invoke callback \a f. The argument to the callback
|
||||
/// states whether the alarm expired at \a deadline (true) or was cancelled
|
||||
/// (false)
|
||||
template <typename T> |
||||
void Set(const T& deadline, std::function<void(bool)> f) { |
||||
alarm_->SetInternal(::grpc::TimePoint<T>(deadline).raw_time(), |
||||
std::move(f)); |
||||
} |
||||
|
||||
private: |
||||
Alarm* alarm_; |
||||
}; |
||||
|
||||
/// NOTE: The function experimental() is not stable public API. It is a view
|
||||
/// to the experimental components of this class. It may be changed or removed
|
||||
/// at any time.
|
||||
experimental_type experimental() { return experimental_type(this); } |
||||
|
||||
private: |
||||
void SetInternal(::grpc::CompletionQueue* cq, gpr_timespec deadline, |
||||
void* tag); |
||||
void SetInternal(gpr_timespec deadline, std::function<void(bool)> f); |
||||
|
||||
::grpc::internal::CompletionQueueTag* alarm_; |
||||
}; |
||||
|
||||
} // namespace grpc_impl
|
||||
|
||||
#endif // GRPCPP_ALARM_IMPL_H
|
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H |
||||
#define GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H |
||||
|
||||
#include <grpcpp/impl/codegen/client_interceptor.h> |
||||
|
||||
#endif // GRPCPP_SUPPORT_CLIENT_INTERCEPTOR_H
|
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCPP_SUPPORT_INTERCEPTOR_H |
||||
#define GRPCPP_SUPPORT_INTERCEPTOR_H |
||||
|
||||
#include <grpcpp/impl/codegen/interceptor.h> |
||||
|
||||
#endif // GRPCPP_SUPPORT_INTERCEPTOR_H
|
@ -0,0 +1,24 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H |
||||
#define GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H |
||||
|
||||
#include <grpcpp/impl/codegen/server_interceptor.h> |
||||
|
||||
#endif // GRPCPP_SUPPORT_SERVER_INTERCEPTOR_H
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,177 @@ |
||||
//
|
||||
//
|
||||
// Copyright 2018 gRPC authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
//
|
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/global_subchannel_pool.h" |
||||
|
||||
#include "src/core/ext/filters/client_channel/subchannel.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
GlobalSubchannelPool::GlobalSubchannelPool() { |
||||
subchannel_map_ = grpc_avl_create(&subchannel_avl_vtable_); |
||||
gpr_mu_init(&mu_); |
||||
} |
||||
|
||||
GlobalSubchannelPool::~GlobalSubchannelPool() { |
||||
gpr_mu_destroy(&mu_); |
||||
grpc_avl_unref(subchannel_map_, nullptr); |
||||
} |
||||
|
||||
void GlobalSubchannelPool::Init() { |
||||
instance_ = New<RefCountedPtr<GlobalSubchannelPool>>( |
||||
MakeRefCounted<GlobalSubchannelPool>()); |
||||
} |
||||
|
||||
void GlobalSubchannelPool::Shutdown() { |
||||
// To ensure Init() was called before.
|
||||
GPR_ASSERT(instance_ != nullptr); |
||||
// To ensure Shutdown() was not called before.
|
||||
GPR_ASSERT(*instance_ != nullptr); |
||||
instance_->reset(); |
||||
Delete(instance_); |
||||
} |
||||
|
||||
RefCountedPtr<GlobalSubchannelPool> GlobalSubchannelPool::instance() { |
||||
GPR_ASSERT(instance_ != nullptr); |
||||
GPR_ASSERT(*instance_ != nullptr); |
||||
return *instance_; |
||||
} |
||||
|
||||
grpc_subchannel* GlobalSubchannelPool::RegisterSubchannel( |
||||
SubchannelKey* key, grpc_subchannel* constructed) { |
||||
grpc_subchannel* c = nullptr; |
||||
// Compare and swap (CAS) loop:
|
||||
while (c == nullptr) { |
||||
// Ref the shared map to have a local copy.
|
||||
gpr_mu_lock(&mu_); |
||||
grpc_avl old_map = grpc_avl_ref(subchannel_map_, nullptr); |
||||
gpr_mu_unlock(&mu_); |
||||
// Check to see if a subchannel already exists.
|
||||
c = static_cast<grpc_subchannel*>(grpc_avl_get(old_map, key, nullptr)); |
||||
if (c != nullptr) { |
||||
// The subchannel already exists. Reuse it.
|
||||
c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "subchannel_register+reuse"); |
||||
GRPC_SUBCHANNEL_UNREF(constructed, "subchannel_register+found_existing"); |
||||
// Exit the CAS loop without modifying the shared map.
|
||||
} else { |
||||
// There hasn't been such subchannel. Add one.
|
||||
// Note that we should ref the old map first because grpc_avl_add() will
|
||||
// unref it while we still need to access it later.
|
||||
grpc_avl new_map = grpc_avl_add( |
||||
grpc_avl_ref(old_map, nullptr), New<SubchannelKey>(*key), |
||||
GRPC_SUBCHANNEL_WEAK_REF(constructed, "subchannel_register+new"), |
||||
nullptr); |
||||
// Try to publish the change to the shared map. It may happen (but
|
||||
// unlikely) that some other thread has changed the shared map, so compare
|
||||
// to make sure it's unchanged before swapping. Retry if it's changed.
|
||||
gpr_mu_lock(&mu_); |
||||
if (old_map.root == subchannel_map_.root) { |
||||
GPR_SWAP(grpc_avl, new_map, subchannel_map_); |
||||
c = constructed; |
||||
} |
||||
gpr_mu_unlock(&mu_); |
||||
grpc_avl_unref(new_map, nullptr); |
||||
} |
||||
grpc_avl_unref(old_map, nullptr); |
||||
} |
||||
return c; |
||||
} |
||||
|
||||
void GlobalSubchannelPool::UnregisterSubchannel(SubchannelKey* key) { |
||||
bool done = false; |
||||
// Compare and swap (CAS) loop:
|
||||
while (!done) { |
||||
// Ref the shared map to have a local copy.
|
||||
gpr_mu_lock(&mu_); |
||||
grpc_avl old_map = grpc_avl_ref(subchannel_map_, nullptr); |
||||
gpr_mu_unlock(&mu_); |
||||
// Remove the subchannel.
|
||||
// Note that we should ref the old map first because grpc_avl_remove() will
|
||||
// unref it while we still need to access it later.
|
||||
grpc_avl new_map = |
||||
grpc_avl_remove(grpc_avl_ref(old_map, nullptr), key, nullptr); |
||||
// Try to publish the change to the shared map. It may happen (but
|
||||
// unlikely) that some other thread has changed the shared map, so compare
|
||||
// to make sure it's unchanged before swapping. Retry if it's changed.
|
||||
gpr_mu_lock(&mu_); |
||||
if (old_map.root == subchannel_map_.root) { |
||||
GPR_SWAP(grpc_avl, new_map, subchannel_map_); |
||||
done = true; |
||||
} |
||||
gpr_mu_unlock(&mu_); |
||||
grpc_avl_unref(new_map, nullptr); |
||||
grpc_avl_unref(old_map, nullptr); |
||||
} |
||||
} |
||||
|
||||
grpc_subchannel* GlobalSubchannelPool::FindSubchannel(SubchannelKey* key) { |
||||
// Lock, and take a reference to the subchannel map.
|
||||
// We don't need to do the search under a lock as AVL's are immutable.
|
||||
gpr_mu_lock(&mu_); |
||||
grpc_avl index = grpc_avl_ref(subchannel_map_, nullptr); |
||||
gpr_mu_unlock(&mu_); |
||||
grpc_subchannel* c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF( |
||||
static_cast<grpc_subchannel*>(grpc_avl_get(index, key, nullptr)), |
||||
"found_from_pool"); |
||||
grpc_avl_unref(index, nullptr); |
||||
return c; |
||||
} |
||||
|
||||
RefCountedPtr<GlobalSubchannelPool>* GlobalSubchannelPool::instance_ = nullptr; |
||||
|
||||
namespace { |
||||
|
||||
void sck_avl_destroy(void* p, void* user_data) { |
||||
SubchannelKey* key = static_cast<SubchannelKey*>(p); |
||||
Delete(key); |
||||
} |
||||
|
||||
void* sck_avl_copy(void* p, void* unused) { |
||||
const SubchannelKey* key = static_cast<const SubchannelKey*>(p); |
||||
auto* new_key = New<SubchannelKey>(*key); |
||||
return static_cast<void*>(new_key); |
||||
} |
||||
|
||||
long sck_avl_compare(void* a, void* b, void* unused) { |
||||
const SubchannelKey* key_a = static_cast<const SubchannelKey*>(a); |
||||
const SubchannelKey* key_b = static_cast<const SubchannelKey*>(b); |
||||
return key_a->Cmp(*key_b); |
||||
} |
||||
|
||||
void scv_avl_destroy(void* p, void* user_data) { |
||||
GRPC_SUBCHANNEL_WEAK_UNREF((grpc_subchannel*)p, "global_subchannel_pool"); |
||||
} |
||||
|
||||
void* scv_avl_copy(void* p, void* unused) { |
||||
GRPC_SUBCHANNEL_WEAK_REF((grpc_subchannel*)p, "global_subchannel_pool"); |
||||
return p; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
const grpc_avl_vtable GlobalSubchannelPool::subchannel_avl_vtable_ = { |
||||
sck_avl_destroy, // destroy_key
|
||||
sck_avl_copy, // copy_key
|
||||
sck_avl_compare, // compare_keys
|
||||
scv_avl_destroy, // destroy_value
|
||||
scv_avl_copy // copy_value
|
||||
}; |
||||
|
||||
} // namespace grpc_core
|
@ -0,0 +1,68 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_GLOBAL_SUBCHANNEL_POOL_H |
||||
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_GLOBAL_SUBCHANNEL_POOL_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/subchannel_pool_interface.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
// The global subchannel pool. It shares subchannels among channels. There
|
||||
// should be only one instance of this class. Init() should be called once at
|
||||
// the filter initialization time; Shutdown() should be called once at the
|
||||
// filter shutdown time.
|
||||
// TODO(juanlishen): Enable subchannel retention.
|
||||
class GlobalSubchannelPool final : public SubchannelPoolInterface { |
||||
public: |
||||
// The ctor and dtor are not intended to use directly.
|
||||
GlobalSubchannelPool(); |
||||
~GlobalSubchannelPool() override; |
||||
|
||||
// Should be called exactly once at filter initialization time.
|
||||
static void Init(); |
||||
// Should be called exactly once at filter shutdown time.
|
||||
static void Shutdown(); |
||||
|
||||
// Gets the singleton instance.
|
||||
static RefCountedPtr<GlobalSubchannelPool> instance(); |
||||
|
||||
// Implements interface methods.
|
||||
grpc_subchannel* RegisterSubchannel(SubchannelKey* key, |
||||
grpc_subchannel* constructed) override; |
||||
void UnregisterSubchannel(SubchannelKey* key) override; |
||||
grpc_subchannel* FindSubchannel(SubchannelKey* key) override; |
||||
|
||||
private: |
||||
// The singleton instance. (It's a pointer to RefCountedPtr so that this
|
||||
// non-local static object can be trivially destructible.)
|
||||
static RefCountedPtr<GlobalSubchannelPool>* instance_; |
||||
|
||||
// The vtable for subchannel operations in an AVL tree.
|
||||
static const grpc_avl_vtable subchannel_avl_vtable_; |
||||
// A map from subchannel key to subchannel.
|
||||
grpc_avl subchannel_map_; |
||||
// To protect subchannel_map_.
|
||||
gpr_mu mu_; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_GLOBAL_SUBCHANNEL_POOL_H */ |
@ -1,163 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
|
||||
#include "src/core/ext/filters/client_channel/lb_policy_factory.h" |
||||
#include "src/core/ext/filters/client_channel/parse_address.h" |
||||
|
||||
grpc_lb_addresses* grpc_lb_addresses_create( |
||||
size_t num_addresses, const grpc_lb_user_data_vtable* user_data_vtable) { |
||||
grpc_lb_addresses* addresses = |
||||
static_cast<grpc_lb_addresses*>(gpr_zalloc(sizeof(grpc_lb_addresses))); |
||||
addresses->num_addresses = num_addresses; |
||||
addresses->user_data_vtable = user_data_vtable; |
||||
const size_t addresses_size = sizeof(grpc_lb_address) * num_addresses; |
||||
addresses->addresses = |
||||
static_cast<grpc_lb_address*>(gpr_zalloc(addresses_size)); |
||||
return addresses; |
||||
} |
||||
|
||||
grpc_lb_addresses* grpc_lb_addresses_copy(const grpc_lb_addresses* addresses) { |
||||
grpc_lb_addresses* new_addresses = grpc_lb_addresses_create( |
||||
addresses->num_addresses, addresses->user_data_vtable); |
||||
memcpy(new_addresses->addresses, addresses->addresses, |
||||
sizeof(grpc_lb_address) * addresses->num_addresses); |
||||
for (size_t i = 0; i < addresses->num_addresses; ++i) { |
||||
if (new_addresses->addresses[i].balancer_name != nullptr) { |
||||
new_addresses->addresses[i].balancer_name = |
||||
gpr_strdup(new_addresses->addresses[i].balancer_name); |
||||
} |
||||
if (new_addresses->addresses[i].user_data != nullptr) { |
||||
new_addresses->addresses[i].user_data = addresses->user_data_vtable->copy( |
||||
new_addresses->addresses[i].user_data); |
||||
} |
||||
} |
||||
return new_addresses; |
||||
} |
||||
|
||||
void grpc_lb_addresses_set_address(grpc_lb_addresses* addresses, size_t index, |
||||
const void* address, size_t address_len, |
||||
bool is_balancer, const char* balancer_name, |
||||
void* user_data) { |
||||
GPR_ASSERT(index < addresses->num_addresses); |
||||
if (user_data != nullptr) GPR_ASSERT(addresses->user_data_vtable != nullptr); |
||||
grpc_lb_address* target = &addresses->addresses[index]; |
||||
memcpy(target->address.addr, address, address_len); |
||||
target->address.len = static_cast<socklen_t>(address_len); |
||||
target->is_balancer = is_balancer; |
||||
target->balancer_name = gpr_strdup(balancer_name); |
||||
target->user_data = user_data; |
||||
} |
||||
|
||||
bool grpc_lb_addresses_set_address_from_uri(grpc_lb_addresses* addresses, |
||||
size_t index, const grpc_uri* uri, |
||||
bool is_balancer, |
||||
const char* balancer_name, |
||||
void* user_data) { |
||||
grpc_resolved_address address; |
||||
if (!grpc_parse_uri(uri, &address)) return false; |
||||
grpc_lb_addresses_set_address(addresses, index, address.addr, address.len, |
||||
is_balancer, balancer_name, user_data); |
||||
return true; |
||||
} |
||||
|
||||
int grpc_lb_addresses_cmp(const grpc_lb_addresses* addresses1, |
||||
const grpc_lb_addresses* addresses2) { |
||||
if (addresses1->num_addresses > addresses2->num_addresses) return 1; |
||||
if (addresses1->num_addresses < addresses2->num_addresses) return -1; |
||||
if (addresses1->user_data_vtable > addresses2->user_data_vtable) return 1; |
||||
if (addresses1->user_data_vtable < addresses2->user_data_vtable) return -1; |
||||
for (size_t i = 0; i < addresses1->num_addresses; ++i) { |
||||
const grpc_lb_address* target1 = &addresses1->addresses[i]; |
||||
const grpc_lb_address* target2 = &addresses2->addresses[i]; |
||||
if (target1->address.len > target2->address.len) return 1; |
||||
if (target1->address.len < target2->address.len) return -1; |
||||
int retval = memcmp(target1->address.addr, target2->address.addr, |
||||
target1->address.len); |
||||
if (retval != 0) return retval; |
||||
if (target1->is_balancer > target2->is_balancer) return 1; |
||||
if (target1->is_balancer < target2->is_balancer) return -1; |
||||
const char* balancer_name1 = |
||||
target1->balancer_name != nullptr ? target1->balancer_name : ""; |
||||
const char* balancer_name2 = |
||||
target2->balancer_name != nullptr ? target2->balancer_name : ""; |
||||
retval = strcmp(balancer_name1, balancer_name2); |
||||
if (retval != 0) return retval; |
||||
if (addresses1->user_data_vtable != nullptr) { |
||||
retval = addresses1->user_data_vtable->cmp(target1->user_data, |
||||
target2->user_data); |
||||
if (retval != 0) return retval; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void grpc_lb_addresses_destroy(grpc_lb_addresses* addresses) { |
||||
for (size_t i = 0; i < addresses->num_addresses; ++i) { |
||||
gpr_free(addresses->addresses[i].balancer_name); |
||||
if (addresses->addresses[i].user_data != nullptr) { |
||||
addresses->user_data_vtable->destroy(addresses->addresses[i].user_data); |
||||
} |
||||
} |
||||
gpr_free(addresses->addresses); |
||||
gpr_free(addresses); |
||||
} |
||||
|
||||
static void* lb_addresses_copy(void* addresses) { |
||||
return grpc_lb_addresses_copy(static_cast<grpc_lb_addresses*>(addresses)); |
||||
} |
||||
static void lb_addresses_destroy(void* addresses) { |
||||
grpc_lb_addresses_destroy(static_cast<grpc_lb_addresses*>(addresses)); |
||||
} |
||||
static int lb_addresses_cmp(void* addresses1, void* addresses2) { |
||||
return grpc_lb_addresses_cmp(static_cast<grpc_lb_addresses*>(addresses1), |
||||
static_cast<grpc_lb_addresses*>(addresses2)); |
||||
} |
||||
static const grpc_arg_pointer_vtable lb_addresses_arg_vtable = { |
||||
lb_addresses_copy, lb_addresses_destroy, lb_addresses_cmp}; |
||||
|
||||
grpc_arg grpc_lb_addresses_create_channel_arg( |
||||
const grpc_lb_addresses* addresses) { |
||||
return grpc_channel_arg_pointer_create( |
||||
(char*)GRPC_ARG_LB_ADDRESSES, (void*)addresses, &lb_addresses_arg_vtable); |
||||
} |
||||
|
||||
grpc_lb_addresses* grpc_lb_addresses_find_channel_arg( |
||||
const grpc_channel_args* channel_args) { |
||||
const grpc_arg* lb_addresses_arg = |
||||
grpc_channel_args_find(channel_args, GRPC_ARG_LB_ADDRESSES); |
||||
if (lb_addresses_arg == nullptr || lb_addresses_arg->type != GRPC_ARG_POINTER) |
||||
return nullptr; |
||||
return static_cast<grpc_lb_addresses*>(lb_addresses_arg->value.pointer.p); |
||||
} |
||||
|
||||
bool grpc_lb_addresses_contains_balancer_address( |
||||
const grpc_lb_addresses& addresses) { |
||||
for (size_t i = 0; i < addresses.num_addresses; ++i) { |
||||
if (addresses.addresses[i].is_balancer) return true; |
||||
} |
||||
return false; |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue