diff options
author | 2016-05-04 16:30:11 -0700 | |
---|---|---|
committer | 2016-05-04 16:57:08 -0700 | |
commit | c84ed6813e24b6d64d2eea7e39188ddae11528c6 (patch) | |
tree | ba551a21362ff1e09f7f2c3035450478d7f32965 /test/cpp | |
parent | 099b7562695d854897ff4b56fb306597e78d4f48 (diff) |
Proto server reflection
Diffstat (limited to 'test/cpp')
-rw-r--r-- | test/cpp/util/proto_reflection_descriptor_database.cc | 238 | ||||
-rw-r--r-- | test/cpp/util/proto_reflection_descriptor_database.h | 95 | ||||
-rw-r--r-- | test/cpp/util/reflection_debug/Makefile | 50 | ||||
-rw-r--r-- | test/cpp/util/reflection_debug/reflection_client.cc | 216 |
4 files changed, 599 insertions, 0 deletions
diff --git a/test/cpp/util/proto_reflection_descriptor_database.cc b/test/cpp/util/proto_reflection_descriptor_database.cc new file mode 100644 index 0000000000..c2ed93c12b --- /dev/null +++ b/test/cpp/util/proto_reflection_descriptor_database.cc @@ -0,0 +1,238 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "proto_reflection_descriptor_database.h" + +#include <vector> + +#include <grpc/support/log.h> + +namespace grpc { + +ProtoReflectionDescriptorDatabase::ProtoReflectionDescriptorDatabase( + std::unique_ptr<reflection::v1alpha::ServerReflection::Stub> stub) + : stub_(std::move(stub)) {} + +ProtoReflectionDescriptorDatabase::ProtoReflectionDescriptorDatabase( + std::shared_ptr<grpc::Channel> channel) + : stub_(reflection::v1alpha::ServerReflection::NewStub(channel)) {} + +ProtoReflectionDescriptorDatabase::~ProtoReflectionDescriptorDatabase() {} + +bool ProtoReflectionDescriptorDatabase::FindFileByName( + const string& filename, google::protobuf::FileDescriptorProto* output) { + if (cached_db_.FindFileByName(filename, output)) { + return true; + } + + if (known_files_.find(filename) != known_files_.end()) { + return false; + } + + ClientContext ctx; + reflection::v1alpha::FileNameRequest request; + request.set_filename(filename); + reflection::v1alpha::FileDescriptorProtoResponse response; + + Status status = stub_->GetFileByName(&ctx, request, &response); + if (status.ok()) { + // const google::protobuf::FileDescriptorProto* file_proto = + // response.mutable_file_descriptor_proto(); + const google::protobuf::FileDescriptorProto file_proto = + ParseFileDescriptorProtoResponse(&response); + known_files_.insert(file_proto.name()); + cached_db_.Add(file_proto); + } else if (status.error_code() == StatusCode::NOT_FOUND) { + gpr_log(GPR_INFO, "NOT_FOUND from server for FindFileByName(%s)", + filename.c_str()); + } else { + gpr_log(GPR_INFO, + "Error on FindFileByName(%s)\n\tError code: %d\n" + "\tError Message: %s", + filename.c_str(), status.error_code(), + status.error_message().c_str()); + } + + return cached_db_.FindFileByName(filename, output); +} + +bool ProtoReflectionDescriptorDatabase::FindFileContainingSymbol( + const string& symbol_name, google::protobuf::FileDescriptorProto* output) { + if (cached_db_.FindFileContainingSymbol(symbol_name, output)) { + return true; + } + + if (missing_symbols_.find(symbol_name) != missing_symbols_.end()) { + return false; + } + + ClientContext ctx; + reflection::v1alpha::SymbolRequest request; + request.set_symbol(symbol_name); + reflection::v1alpha::FileDescriptorProtoResponse response; + + Status status = stub_->GetFileContainingSymbol(&ctx, request, &response); + if (status.ok()) { + const google::protobuf::FileDescriptorProto file_proto = + ParseFileDescriptorProtoResponse(&response); + if (known_files_.find(file_proto.name()) == known_files_.end()) { + known_files_.insert(file_proto.name()); + cached_db_.Add(file_proto); + } + } else if (status.error_code() == StatusCode::NOT_FOUND) { + missing_symbols_.insert(symbol_name); + gpr_log(GPR_INFO, "NOT_FOUND from server for FindFileContainingSymbol(%s)", + symbol_name.c_str()); + } else { + gpr_log(GPR_INFO, + "Error on FindFileContainingSymbol(%s)\n" + "\tError code: %d\n\tError Message: %s", + symbol_name.c_str(), status.error_code(), + status.error_message().c_str()); + } + + return cached_db_.FindFileContainingSymbol(symbol_name, output); +} + +bool ProtoReflectionDescriptorDatabase::FindFileContainingExtension( + const string& containing_type, int field_number, + google::protobuf::FileDescriptorProto* output) { + if (cached_db_.FindFileContainingExtension(containing_type, field_number, + output)) { + return true; + } + + if (missing_extensions_.find(containing_type) != missing_extensions_.end() && + missing_extensions_[containing_type].find(field_number) != + missing_extensions_[containing_type].end()) { + gpr_log(GPR_INFO, "nested map."); + return false; + } + + ClientContext ctx; + reflection::v1alpha::ExtensionRequest request; + request.set_containing_type(containing_type); + request.set_extension_number(field_number); + reflection::v1alpha::FileDescriptorProtoResponse response; + + Status status = stub_->GetFileContainingExtension(&ctx, request, &response); + if (status.ok()) { + const google::protobuf::FileDescriptorProto file_proto = + ParseFileDescriptorProtoResponse(&response); + if (known_files_.find(file_proto.name()) == known_files_.end()) { + known_files_.insert(file_proto.name()); + cached_db_.Add(file_proto); + } + } else if (status.error_code() == StatusCode::NOT_FOUND) { + if (missing_extensions_.find(containing_type) == + missing_extensions_.end()) { + missing_extensions_[containing_type] = {}; + } + missing_extensions_[containing_type].insert(field_number); + gpr_log(GPR_INFO, + "NOT_FOUND from server for FindFileContainingExtension(%s, %d)", + containing_type.c_str(), field_number); + } else { + gpr_log(GPR_INFO, + "Error on FindFileContainingExtension(%s, %d)\n" + "\tError code: %d\n\tError Message: %s", + containing_type.c_str(), field_number, status.error_code(), + status.error_message().c_str()); + } + + return cached_db_.FindFileContainingExtension(containing_type, field_number, + output); +} + +bool ProtoReflectionDescriptorDatabase::FindAllExtensionNumbers( + const string& extendee_type, std::vector<int>* output) { + if (cached_extension_numbers_.find(extendee_type) != + cached_extension_numbers_.end()) { + *output = cached_extension_numbers_[extendee_type]; + return true; + } + + ClientContext ctx; + reflection::v1alpha::TypeRequest request; + request.set_type(extendee_type); + reflection::v1alpha::ExtensionNumberResponse response; + + Status status = stub_->GetAllExtensionNumbers(&ctx, request, &response); + if (status.ok()) { + auto number = response.extension_number(); + *output = std::vector<int>(number.begin(), number.end()); + cached_extension_numbers_[extendee_type] = *output; + return true; + } else if (status.error_code() == StatusCode::NOT_FOUND) { + gpr_log(GPR_INFO, "NOT_FOUND from server for FindAllExtensionNumbers(%s)", + extendee_type.c_str()); + } else { + gpr_log(GPR_INFO, + "Error on FindAllExtensionNumbersExtension(%s)\n" + "\tError code: %d\n\tError Message: %s", + extendee_type.c_str(), status.error_code(), + status.error_message().c_str()); + } + return false; +} + +bool ProtoReflectionDescriptorDatabase::GetServices( + std::vector<std::string>* output) { + ClientContext ctx; + reflection::v1alpha::EmptyRequest request; + reflection::v1alpha::ListServiceResponse response; + + Status status = stub_->ListService(&ctx, request, &response); + if (status.ok()) { + for (int i = 0; i < response.services_size(); ++i) { + (*output).push_back(response.services(i)); + } + return true; + } else { + gpr_log(GPR_INFO, + "Error on GetServices()\n\tError code: %d\n" + "\tError Message: %s", + status.error_code(), status.error_message().c_str()); + } + return false; +} + +const google::protobuf::FileDescriptorProto +ProtoReflectionDescriptorDatabase::ParseFileDescriptorProtoResponse( + reflection::v1alpha::FileDescriptorProtoResponse* response) { + google::protobuf::FileDescriptorProto file_desc_proto; + file_desc_proto.ParseFromString(response->file_descriptor_proto()); + return file_desc_proto; +} + +} // namespace grpc diff --git a/test/cpp/util/proto_reflection_descriptor_database.h b/test/cpp/util/proto_reflection_descriptor_database.h new file mode 100644 index 0000000000..bf94654c3d --- /dev/null +++ b/test/cpp/util/proto_reflection_descriptor_database.h @@ -0,0 +1,95 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <memory> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor_database.h> +#include <grpc++/grpc++.h> +#include <grpc++/impl/reflection.grpc.pb.h> + +// #include "reflection.grpc.pb.h" + +namespace grpc { + +class ProtoReflectionDescriptorDatabase + : public google::protobuf::DescriptorDatabase { + public: + explicit ProtoReflectionDescriptorDatabase( + std::unique_ptr<reflection::v1alpha::ServerReflection::Stub> stub); + + explicit ProtoReflectionDescriptorDatabase( + std::shared_ptr<grpc::Channel> channel); + + virtual ~ProtoReflectionDescriptorDatabase(); + + // DescriptorDatabase methods + bool FindFileByName(const string& filename, + google::protobuf::FileDescriptorProto* output) + GRPC_OVERRIDE; + + bool FindFileContainingSymbol(const string& symbol_name, + google::protobuf::FileDescriptorProto* output) + GRPC_OVERRIDE; + + bool FindFileContainingExtension( + const string& containing_type, int field_number, + google::protobuf::FileDescriptorProto* output) GRPC_OVERRIDE; + + bool FindAllExtensionNumbers(const string& extendee_type, + std::vector<int>* output) GRPC_OVERRIDE; + + bool GetServices(std::vector<std::string>* output); + + grpc::reflection::v1alpha::ServerReflection::Stub* stub() { + return stub_.get(); + } + + private: + const google::protobuf::FileDescriptorProto ParseFileDescriptorProtoResponse( + reflection::v1alpha::FileDescriptorProtoResponse* response); + + std::unique_ptr<grpc::reflection::v1alpha::ServerReflection::Stub> stub_; + std::unordered_set<string> known_files_; + std::unordered_set<string> missing_symbols_; + std::unordered_map<string, std::unordered_set<int>> missing_extensions_; + std::unordered_map<string, std::vector<int>> cached_extension_numbers_; + + google::protobuf::SimpleDescriptorDatabase cached_db_; +}; + +} // namespace grpc diff --git a/test/cpp/util/reflection_debug/Makefile b/test/cpp/util/reflection_debug/Makefile new file mode 100644 index 0000000000..9eea5ae734 --- /dev/null +++ b/test/cpp/util/reflection_debug/Makefile @@ -0,0 +1,50 @@ + +# Copyright 2015-2016, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +CXX = g++ +INCLUDES += -I. -I.. +CPPFLAGS += -I/usr/local/include -pthread +CXXFLAGS += -std=c++11 ${INCLUDES} +LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lgrpc++_reflection -lprotobuf -lpthread -ldl +VPATH = .. + +# PROTOS_PATH = ../../../src/cpp/plugin/reflection + +vpath %.proto $(PROTOS_PATH) + +all: reflection_client + +reflection_client: proto_reflection_descriptor_database.o reflection_client.o + $(CXX) $(INCLUDES) $^ $(LDFLAGS) -o $@ + + +clean: + rm -f *.o reflection_client diff --git a/test/cpp/util/reflection_debug/reflection_client.cc b/test/cpp/util/reflection_debug/reflection_client.cc new file mode 100644 index 0000000000..fb40627514 --- /dev/null +++ b/test/cpp/util/reflection_debug/reflection_client.cc @@ -0,0 +1,216 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <iomanip> +#include <iostream> +#include <memory> +#include <string> + +#include <google/protobuf/descriptor.h> +#include <google/protobuf/descriptor.pb.h> +#include <grpc++/grpc++.h> + +#include "proto_reflection_descriptor_database.h" +// #include "reflection.grpc.pb.h" + +using grpc::Channel; +using grpc::ClientContext; +using grpc::Status; +using grpc::ProtoReflectionDescriptorDatabase; +using grpc::reflection::v1alpha::ServerReflection; +using grpc::reflection::v1alpha::EmptyRequest; +using grpc::reflection::v1alpha::ListServiceResponse; +using google::protobuf::FileDescriptorProto; +using google::protobuf::DescriptorPool; +using google::protobuf::ServiceDescriptor; +using google::protobuf::MethodDescriptor; +using google::protobuf::Descriptor; +using google::protobuf::FieldDescriptor; + +class ReflectionClient { + public: + ReflectionClient(std::shared_ptr<Channel> channel) + : db_(new ProtoReflectionDescriptorDatabase( + ServerReflection::NewStub(channel))), + desc_pool_(new DescriptorPool(db_.get())) {} + + void PrintInfo() { + EmptyRequest request; + ListServiceResponse response; + ClientContext context; + Status status = db_->stub()->ListService(&context, request, &response); + if (status.ok()) { + std::string padding = ""; + std::cout << "Service amount:" << response.services_size() << std::endl; + for (int i = 0; i < response.services_size(); ++i) { + if (i != response.services_size() - 1) { + std::cout << padding << "│ " << std::endl; + std::cout << padding << "├─" << response.services(i) << std::endl; + PrintService(desc_pool_->FindServiceByName(response.services(i)), + padding + "│ "); + } else { + std::cout << padding << "│ " << std::endl; + std::cout << padding << "└─" << response.services(i) << std::endl; + PrintService(desc_pool_->FindServiceByName(response.services(i)), + padding + " "); + } + } + } else { + std::cout << status.error_message(); + } + } + + void PrintService(const ServiceDescriptor* service_desc, + const std::string padding) { + if (service_desc != nullptr) { + std::cout << padding << "│ Method amount:" << service_desc->method_count() + << std::endl; + for (int i = 0; i < service_desc->method_count(); ++i) { + if (i != service_desc->method_count() - 1) { + std::cout << padding << "├─" << service_desc->method(i)->name() + << std::endl; + PrintMethod(service_desc->method(i), padding + "│ "); + } else { + std::cout << padding << "└─" << service_desc->method(i)->name() + << std::endl; + PrintMethod(service_desc->method(i), padding + " "); + } + } + } + } + + void PrintMethod(const MethodDescriptor* method_desc, + const std::string padding) { + if (method_desc != nullptr) { + std::cout << padding + << "├─input type: " << method_desc->input_type()->name() + << std::endl; + PrintMessageType(method_desc->input_type(), padding + "│ "); + std::cout << padding + << "└─output type: " << method_desc->output_type()->name() + << std::endl; + PrintMessageType(method_desc->output_type(), padding + " "); + } + } + + void PrintMessageType(const Descriptor* type_desc, + const std::string padding) { + if (type_desc != nullptr) { + if (type_desc->field_count() > 0) { + std::cout << padding << "│ Field amount:" << type_desc->field_count() + << std::endl; + } + for (int i = 0; i < type_desc->field_count(); ++i) { + if (i != type_desc->field_count() - 1) { + const FieldDescriptor* field = type_desc->field(i); + std::cout << padding << "├─ " << std::left << std::setw(15) + << kLabelToName[field->label()] << std::setw(30) + << " name: " + field->name() << std::setw(50) + << " type: " + + (field->type() == FieldDescriptor::Type::TYPE_MESSAGE + ? field->message_type()->name() + : field->type_name()) + << std::endl; + } else { + const FieldDescriptor* field = type_desc->field(i); + std::cout << padding << "└─ " << std::left << std::setw(15) + << kLabelToName[field->label()] << std::setw(30) + << " name: " + field->name() << std::setw(50) + << " type: " + + (field->type() == FieldDescriptor::Type::TYPE_MESSAGE + ? field->message_type()->name() + : field->type_name()) + << std::endl; + } + } + } + } + + void Test() { + { + FileDescriptorProto output; + bool found = db_->FindFileByName("helloworld.proto", &output); + if (found) std::cout << output.name() << std::endl; + } + { + FileDescriptorProto output; + bool found = + db_->FindFileContainingSymbol("helloworld.Greeter.SayHello", &output); + if (found) std::cout << output.name() << std::endl; + } + { + FileDescriptorProto output; + bool found = db_->FindFileContainingExtension( + "helloworld.Greeter.HelloRequest", 1, &output); + found = db_->FindFileContainingExtension( + "helloworld.Greeter.HelloRequest", 1, &output); + if (found) std::cout << output.name() << std::endl; + } + DescriptorPool pool(db_.get()); + std::cout << pool.FindServiceByName("helloworld.Greeter")->name() + << std::endl; + } + + private: + const char* const kLabelToName[FieldDescriptor::Label::MAX_LABEL + 1] = { + "ERROR", // 0 is reserved for errors + + "optional", // LABEL_OPTIONAL + "required", // LABEL_REQUIRED + "repeated", // LABEL_REPEATED + }; + + std::unique_ptr<ProtoReflectionDescriptorDatabase> db_; + std::unique_ptr<DescriptorPool> desc_pool_; +}; + +int main(int argc, char** argv) { + int port = 50051; + if (argc == 2) { + try { + port = std::stoi(argv[1]); + if (port > 65535 || port < 1024) { + throw std::out_of_range("Port number out of range."); + } + } catch (std::invalid_argument&) { + } catch (std::out_of_range&) { + } + } + + ReflectionClient reflection_client(grpc::CreateChannel( + "localhost:" + std::to_string(port), grpc::InsecureChannelCredentials())); + + reflection_client.PrintInfo(); + + return 0; +} |