diff --git a/BUILD b/BUILD index 0598132141b..d28384cb2a4 100644 --- a/BUILD +++ b/BUILD @@ -2108,6 +2108,7 @@ grpc_cc_library( deps = [ "grpc++", "grpc++_config_proto", + "//src/proto/grpc/reflection/v1:reflection_proto", "//src/proto/grpc/reflection/v1alpha:reflection_proto", ], alwayslink = 1, diff --git a/CMakeLists.txt b/CMakeLists.txt index 55e4a78f577..925843e7cf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -624,6 +624,9 @@ protobuf_generate_grpc_cpp_with_import_path_correction( protobuf_generate_grpc_cpp_with_import_path_correction( src/proto/grpc/lookup/v1/rls_config.proto src/proto/grpc/lookup/v1/rls_config.proto ) +protobuf_generate_grpc_cpp_with_import_path_correction( + src/proto/grpc/reflection/v1/reflection.proto src/proto/grpc/reflection/v1/reflection.proto +) protobuf_generate_grpc_cpp_with_import_path_correction( src/proto/grpc/reflection/v1alpha/reflection.proto src/proto/grpc/reflection/v1alpha/reflection.proto ) @@ -4280,6 +4283,10 @@ endif() if(gRPC_BUILD_CODEGEN) add_library(grpc++_reflection + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1/reflection.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1/reflection.grpc.pb.cc + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1/reflection.pb.h + ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1/reflection.grpc.pb.h ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.cc ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.cc ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/reflection/v1alpha/reflection.pb.h diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml index a1b0db7444e..f2370733b8b 100644 --- a/build_autogenerated.yaml +++ b/build_autogenerated.yaml @@ -3673,6 +3673,7 @@ libs: headers: - src/cpp/ext/proto_server_reflection.h src: + - src/proto/grpc/reflection/v1/reflection.proto - src/proto/grpc/reflection/v1alpha/reflection.proto - src/cpp/ext/proto_server_reflection.cc - src/cpp/ext/proto_server_reflection_plugin.cc diff --git a/grpc.gyp b/grpc.gyp index 6868b4996b7..8c8a3f4af85 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -1842,6 +1842,7 @@ 'grpc++', ], 'sources': [ + 'src/proto/grpc/reflection/v1/reflection.proto', 'src/proto/grpc/reflection/v1alpha/reflection.proto', 'src/cpp/ext/proto_server_reflection.cc', 'src/cpp/ext/proto_server_reflection_plugin.cc', diff --git a/include/grpcpp/ext/proto_server_reflection_plugin.h b/include/grpcpp/ext/proto_server_reflection_plugin.h index 2e3964c957f..b1cbb5a67c2 100644 --- a/include/grpcpp/ext/proto_server_reflection_plugin.h +++ b/include/grpcpp/ext/proto_server_reflection_plugin.h @@ -19,11 +19,15 @@ #ifndef GRPCPP_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H #define GRPCPP_EXT_PROTO_SERVER_REFLECTION_PLUGIN_H +#include + #include #include namespace grpc { class ProtoServerReflection; +class ProtoServerReflectionBackend; +class ProtoServerReflectionV1; class ServerInitializer; namespace reflection { @@ -39,7 +43,9 @@ class ProtoServerReflectionPlugin : public grpc::ServerBuilderPlugin { bool has_sync_methods() const override; private: - std::shared_ptr reflection_service_; + std::shared_ptr backend_; + std::shared_ptr reflection_service_v1alpha_; + std::shared_ptr reflection_service_v1_; }; /// Add proto reflection plugin to \a ServerBuilder. diff --git a/src/cpp/ext/proto_server_reflection.cc b/src/cpp/ext/proto_server_reflection.cc index ce49768c6a7..7d008794c43 100644 --- a/src/cpp/ext/proto_server_reflection.cc +++ b/src/cpp/ext/proto_server_reflection.cc @@ -23,58 +23,41 @@ #include #include +#include // IWYU pragma: no_include "google/protobuf/descriptor.h" // IWYU pragma: no_include - -using grpc::reflection::v1alpha::ErrorResponse; -using grpc::reflection::v1alpha::ExtensionNumberResponse; -using grpc::reflection::v1alpha::ExtensionRequest; -using grpc::reflection::v1alpha::ListServiceResponse; -using grpc::reflection::v1alpha::ServerReflectionRequest; -using grpc::reflection::v1alpha::ServerReflectionResponse; -using grpc::reflection::v1alpha::ServiceResponse; +// IWYU pragma: no_include "src/proto/grpc/reflection/v1/reflection.pb.h" +// IWYU pragma: no_include "src/proto/grpc/reflection/v1alpha/reflection.pb.h" namespace grpc { -ProtoServerReflection::ProtoServerReflection() - : descriptor_pool_(protobuf::DescriptorPool::generated_pool()) {} - -void ProtoServerReflection::SetServiceList( - const std::vector* services) { - services_ = services; -} - -Status ProtoServerReflection::ServerReflectionInfo( - ServerContext* context, - ServerReaderWriter* - stream) { - ServerReflectionRequest request; - ServerReflectionResponse response; +template +Status ProtoServerReflectionBackend::ServerReflectionInfo( + ServerReaderWriter* stream) const { + Request request; + Response response; Status status; while (stream->Read(&request)) { switch (request.message_request_case()) { - case ServerReflectionRequest::MessageRequestCase::kFileByFilename: - status = GetFileByName(context, request.file_by_filename(), &response); + case Request::MessageRequestCase::kFileByFilename: + status = GetFileByName(request.file_by_filename(), &response); break; - case ServerReflectionRequest::MessageRequestCase::kFileContainingSymbol: - status = GetFileContainingSymbol( - context, request.file_containing_symbol(), &response); + case Request::MessageRequestCase::kFileContainingSymbol: + status = GetFileContainingSymbol(request.file_containing_symbol(), + &response); break; - case ServerReflectionRequest::MessageRequestCase:: - kFileContainingExtension: + case Request::MessageRequestCase::kFileContainingExtension: status = GetFileContainingExtension( - context, &request.file_containing_extension(), &response); + &request.file_containing_extension(), &response); break; - case ServerReflectionRequest::MessageRequestCase:: - kAllExtensionNumbersOfType: + case Request::MessageRequestCase::kAllExtensionNumbersOfType: status = GetAllExtensionNumbers( - context, request.all_extension_numbers_of_type(), + request.all_extension_numbers_of_type(), response.mutable_all_extension_numbers_response()); break; - case ServerReflectionRequest::MessageRequestCase::kListServices: - status = - ListService(context, response.mutable_list_services_response()); + case Request::MessageRequestCase::kListServices: + status = ListService(response.mutable_list_services_response()); break; default: status = Status(StatusCode::UNIMPLEMENTED, ""); @@ -84,35 +67,34 @@ Status ProtoServerReflection::ServerReflectionInfo( FillErrorResponse(status, response.mutable_error_response()); } response.set_valid_host(request.host()); - response.set_allocated_original_request( - new ServerReflectionRequest(request)); + response.set_allocated_original_request(new Request(request)); stream->Write(response); } - return Status::OK; } -void ProtoServerReflection::FillErrorResponse(const Status& status, - ErrorResponse* error_response) { +template +void ProtoServerReflectionBackend::FillErrorResponse( + const Status& status, Response* error_response) const { error_response->set_error_code(status.error_code()); error_response->set_error_message(status.error_message()); } -Status ProtoServerReflection::ListService(ServerContext* /*context*/, - ListServiceResponse* response) { +template +Status ProtoServerReflectionBackend::ListService(Response* response) const { if (services_ == nullptr) { return Status(StatusCode::NOT_FOUND, "Services not found."); } for (const auto& value : *services_) { - ServiceResponse* service_response = response->add_service(); + auto* service_response = response->add_service(); service_response->set_name(value); } return Status::OK; } -Status ProtoServerReflection::GetFileByName( - ServerContext* /*context*/, const std::string& file_name, - ServerReflectionResponse* response) { +template +Status ProtoServerReflectionBackend::GetFileByName(const std::string& file_name, + Response* response) const { if (descriptor_pool_ == nullptr) { return Status::CANCELLED; } @@ -127,9 +109,9 @@ Status ProtoServerReflection::GetFileByName( return Status::OK; } -Status ProtoServerReflection::GetFileContainingSymbol( - ServerContext* /*context*/, const std::string& symbol, - ServerReflectionResponse* response) { +template +Status ProtoServerReflectionBackend::GetFileContainingSymbol( + const std::string& symbol, Response* response) const { if (descriptor_pool_ == nullptr) { return Status::CANCELLED; } @@ -144,9 +126,9 @@ Status ProtoServerReflection::GetFileContainingSymbol( return Status::OK; } -Status ProtoServerReflection::GetFileContainingExtension( - ServerContext* /*context*/, const ExtensionRequest* request, - ServerReflectionResponse* response) { +template +Status ProtoServerReflectionBackend::GetFileContainingExtension( + const Request* request, Response* response) const { if (descriptor_pool_ == nullptr) { return Status::CANCELLED; } @@ -168,9 +150,9 @@ Status ProtoServerReflection::GetFileContainingExtension( return Status::OK; } -Status ProtoServerReflection::GetAllExtensionNumbers( - ServerContext* /*context*/, const std::string& type, - ExtensionNumberResponse* response) { +template +Status ProtoServerReflectionBackend::GetAllExtensionNumbers( + const std::string& type, Response* response) const { if (descriptor_pool_ == nullptr) { return Status::CANCELLED; } @@ -190,10 +172,10 @@ Status ProtoServerReflection::GetAllExtensionNumbers( return Status::OK; } -void ProtoServerReflection::FillFileDescriptorResponse( - const protobuf::FileDescriptor* file_desc, - ServerReflectionResponse* response, - std::unordered_set* seen_files) { +template +void ProtoServerReflectionBackend::FillFileDescriptorResponse( + const protobuf::FileDescriptor* file_desc, Response* response, + std::unordered_set* seen_files) const { if (seen_files->find(file_desc->name()) != seen_files->end()) { return; } @@ -210,4 +192,18 @@ void ProtoServerReflection::FillFileDescriptorResponse( } } +Status ProtoServerReflection::ServerReflectionInfo( + ServerContext* /* context */, + ServerReaderWriter* stream) { + return backend_->ServerReflectionInfo(stream); +} + +Status ProtoServerReflectionV1::ServerReflectionInfo( + ServerContext* /* context */, + ServerReaderWriter* stream) { + return backend_->ServerReflectionInfo(stream); +} + } // namespace grpc diff --git a/src/cpp/ext/proto_server_reflection.h b/src/cpp/ext/proto_server_reflection.h index 60a6f5614af..5482c9bc254 100644 --- a/src/cpp/ext/proto_server_reflection.h +++ b/src/cpp/ext/proto_server_reflection.h @@ -19,8 +19,10 @@ #ifndef GRPC_SRC_CPP_EXT_PROTO_SERVER_REFLECTION_H #define GRPC_SRC_CPP_EXT_PROTO_SERVER_REFLECTION_H +#include #include #include +#include #include #include @@ -29,18 +31,72 @@ #include #include +#include "src/proto/grpc/reflection/v1/reflection.grpc.pb.h" +#include "src/proto/grpc/reflection/v1/reflection.pb.h" #include "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h" #include "src/proto/grpc/reflection/v1alpha/reflection.pb.h" namespace grpc { +class ProtoServerReflectionBackend { + public: + ProtoServerReflectionBackend() + : descriptor_pool_(protobuf::DescriptorPool::generated_pool()) {} + + void SetServiceList(const std::vector* services) { + services_ = services; + } + + template + Status ServerReflectionInfo( + ServerReaderWriter* stream) const; + + private: + template + Status ListService(Response* response) const; + + template + Status GetFileByName(const std::string& file_name, Response* response) const; + + template + Status GetFileContainingSymbol(const std::string& symbol, + Response* response) const; + + template + Status GetFileContainingExtension(const Request* request, + Response* response) const; + + template + Status GetAllExtensionNumbers(const std::string& type, + Response* response) const; + + template + void FillFileDescriptorResponse( + const protobuf::FileDescriptor* file_desc, Response* response, + std::unordered_set* seen_files) const; + + template + void FillErrorResponse(const Status& status, Response* error_response) const; + + const protobuf::DescriptorPool* descriptor_pool_; + const std::vector* services_; +}; + class ProtoServerReflection final : public reflection::v1alpha::ServerReflection::Service { public: - ProtoServerReflection(); + ProtoServerReflection() + : grpc::ProtoServerReflection( + std::make_shared()) {} + + explicit ProtoServerReflection( + std::shared_ptr backend) + : backend_(std::move(backend)) {} // Add the full names of registered services - void SetServiceList(const std::vector* services); + void SetServiceList(const std::vector* services) { + backend_->SetServiceList(services); + } // implementation of ServerReflectionInfo(stream ServerReflectionRequest) rpc // in ServerReflection service @@ -50,36 +106,26 @@ class ProtoServerReflection final reflection::v1alpha::ServerReflectionRequest>* stream) override; - private: - Status ListService(ServerContext* context, - reflection::v1alpha::ListServiceResponse* response); - - Status GetFileByName(ServerContext* context, const std::string& file_name, - reflection::v1alpha::ServerReflectionResponse* response); - - Status GetFileContainingSymbol( - ServerContext* context, const std::string& symbol, - reflection::v1alpha::ServerReflectionResponse* response); - - Status GetFileContainingExtension( - ServerContext* context, - const reflection::v1alpha::ExtensionRequest* request, - reflection::v1alpha::ServerReflectionResponse* response); - - Status GetAllExtensionNumbers( - ServerContext* context, const std::string& type, - reflection::v1alpha::ExtensionNumberResponse* response); + std::shared_ptr backend_; +}; - void FillFileDescriptorResponse( - const protobuf::FileDescriptor* file_desc, - reflection::v1alpha::ServerReflectionResponse* response, - std::unordered_set* seen_files); +class ProtoServerReflectionV1 final + : public reflection::v1::ServerReflection::Service { + public: + explicit ProtoServerReflectionV1( + std::shared_ptr backend) + : backend_(std::move(backend)) {} - void FillErrorResponse(const Status& status, - reflection::v1alpha::ErrorResponse* error_response); + // implementation of ServerReflectionInfo(stream ServerReflectionRequest) rpc + // in ServerReflection service + Status ServerReflectionInfo( + ServerContext* /* context */, + ServerReaderWriter* stream) + override; - const protobuf::DescriptorPool* descriptor_pool_; - const std::vector* services_; + private: + std::shared_ptr backend_; }; } // namespace grpc diff --git a/src/cpp/ext/proto_server_reflection_plugin.cc b/src/cpp/ext/proto_server_reflection_plugin.cc index 4aae3ea17b4..78080fa8cbe 100644 --- a/src/cpp/ext/proto_server_reflection_plugin.cc +++ b/src/cpp/ext/proto_server_reflection_plugin.cc @@ -16,6 +16,9 @@ // // +#include +#include + #include #include #include @@ -27,35 +30,40 @@ namespace grpc { namespace reflection { ProtoServerReflectionPlugin::ProtoServerReflectionPlugin() - : reflection_service_(new grpc::ProtoServerReflection()) {} + : backend_(std::make_shared()), + reflection_service_v1alpha_( + std::make_shared(backend_)), + reflection_service_v1_( + std::make_shared(backend_)) {} std::string ProtoServerReflectionPlugin::name() { return "proto_server_reflection"; } void ProtoServerReflectionPlugin::InitServer(grpc::ServerInitializer* si) { - si->RegisterService(reflection_service_); + si->RegisterService(reflection_service_v1_); + si->RegisterService(reflection_service_v1alpha_); } void ProtoServerReflectionPlugin::Finish(grpc::ServerInitializer* si) { - reflection_service_->SetServiceList(si->GetServiceList()); + backend_->SetServiceList(si->GetServiceList()); } void ProtoServerReflectionPlugin::ChangeArguments(const std::string& /*name*/, void* /*value*/) {} bool ProtoServerReflectionPlugin::has_sync_methods() const { - if (reflection_service_) { - return reflection_service_->has_synchronous_methods(); - } - return false; + return (reflection_service_v1_ && + reflection_service_v1_->has_synchronous_methods()) || + (reflection_service_v1alpha_ && + reflection_service_v1alpha_->has_synchronous_methods()); } bool ProtoServerReflectionPlugin::has_async_methods() const { - if (reflection_service_) { - return reflection_service_->has_async_methods(); - } - return false; + return (reflection_service_v1_ && + reflection_service_v1_->has_async_methods()) || + (reflection_service_v1alpha_ && + reflection_service_v1alpha_->has_async_methods()); } static std::unique_ptr CreateProtoReflection() { diff --git a/test/cpp/end2end/proto_server_reflection_test.cc b/test/cpp/end2end/proto_server_reflection_test.cc index 5f6c38f3c16..17b3913b367 100644 --- a/test/cpp/end2end/proto_server_reflection_test.cc +++ b/test/cpp/end2end/proto_server_reflection_test.cc @@ -16,9 +16,11 @@ // // -#include +#include +#include -#include "absl/memory/memory.h" +#include +#include #include #include @@ -31,10 +33,13 @@ #include #include +#include "src/proto/grpc/reflection/v1/reflection.grpc.pb.h" +#include "src/proto/grpc/reflection/v1/reflection.pb.h" +#include "src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h" +#include "src/proto/grpc/reflection/v1alpha/reflection.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" #include "test/core/util/port.h" #include "test/core/util/test_config.h" -#include "test/cpp/end2end/test_service_impl.h" #include "test/cpp/util/proto_reflection_descriptor_database.h" namespace grpc { @@ -56,10 +61,9 @@ class ProtoServerReflectionTest : public ::testing::Test { void ResetStub() { string target = "dns:localhost:" + to_string(port_); - std::shared_ptr channel = - grpc::CreateChannel(target, InsecureChannelCredentials()); - stub_ = grpc::testing::EchoTestService::NewStub(channel); - desc_db_ = std::make_unique(channel); + channel_ = grpc::CreateChannel(target, InsecureChannelCredentials()); + stub_ = grpc::testing::EchoTestService::NewStub(channel_); + desc_db_ = std::make_unique(channel_); desc_pool_ = std::make_unique(desc_db_.get()); } @@ -117,8 +121,18 @@ class ProtoServerReflectionTest : public ::testing::Test { EXPECT_EQ(desc->DebugString(), ref_desc->DebugString()); } + template + std::vector ServicesFromResponse(const Response& response) { + std::vector services; + for (const auto& service : response.list_services_response().service()) { + services.emplace_back(service.name()); + } + return services; + } + protected: std::unique_ptr server_; + std::shared_ptr channel_; std::unique_ptr stub_; std::unique_ptr desc_db_; std::unique_ptr desc_pool_; @@ -142,6 +156,58 @@ TEST_F(ProtoServerReflectionTest, CheckResponseWithLocalDescriptorPool) { } } +TEST_F(ProtoServerReflectionTest, V1AlphaApiInstalled) { + ResetStub(); + using Service = reflection::v1alpha::ServerReflection; + using Request = reflection::v1alpha::ServerReflectionRequest; + using Response = reflection::v1alpha::ServerReflectionResponse; + Service::Stub stub(channel_); + ClientContext context; + auto reader_writer = stub.ServerReflectionInfo(&context); + Request request; + request.set_list_services("*"); + reader_writer->Write(request); + Response response; + ASSERT_EQ(reader_writer->Read(&response), true); + EXPECT_THAT(ServicesFromResponse(response), + ::testing::UnorderedElementsAre( + reflection::v1alpha::ServerReflection::service_full_name(), + reflection::v1::ServerReflection::service_full_name())); + request = Request::default_instance(); + request.set_file_containing_symbol(Service::service_full_name()); + reader_writer->WriteLast(request, WriteOptions()); + response = Response::default_instance(); + ASSERT_EQ(reader_writer->Read(&response), true); + EXPECT_EQ(response.file_descriptor_response().file_descriptor_proto_size(), 1) + << response.DebugString(); +} + +TEST_F(ProtoServerReflectionTest, V1ApiInstalled) { + ResetStub(); + using Service = reflection::v1::ServerReflection; + using Request = reflection::v1::ServerReflectionRequest; + using Response = reflection::v1::ServerReflectionResponse; + Service::Stub stub(channel_); + ClientContext context; + auto reader_writer = stub.ServerReflectionInfo(&context); + Request request; + request.set_list_services("*"); + reader_writer->Write(request); + Response response; + ASSERT_TRUE(reader_writer->Read(&response)); + EXPECT_THAT(ServicesFromResponse(response), + ::testing::UnorderedElementsAre( + reflection::v1alpha::ServerReflection::service_full_name(), + reflection::v1::ServerReflection::service_full_name())); + request = Request::default_instance(); + request.set_file_containing_symbol(Service::service_full_name()); + reader_writer->WriteLast(request, WriteOptions()); + response = Response::default_instance(); + ASSERT_TRUE(reader_writer->Read(&response)); + EXPECT_EQ(response.file_descriptor_response().file_descriptor_proto_size(), 1) + << response.DebugString(); +} + } // namespace testing } // namespace grpc diff --git a/test/cpp/util/grpc_tool_test.cc b/test/cpp/util/grpc_tool_test.cc index c204702dfd2..890c5546658 100644 --- a/test/cpp/util/grpc_tool_test.cc +++ b/test/cpp/util/grpc_tool_test.cc @@ -21,10 +21,12 @@ #include #include +#include #include #include "absl/flags/declare.h" #include "absl/flags/flag.h" +#include "absl/strings/str_split.h" #include #include @@ -384,9 +386,11 @@ TEST_F(GrpcToolTest, ListCommand) { EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(), std::bind(PrintStream, &output_stream, std::placeholders::_1))); - EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), - "grpc.testing.EchoTestService\n" - "grpc.reflection.v1alpha.ServerReflection\n")); + EXPECT_THAT(absl::StrSplit(output_stream.str(), "\n"), + ::testing::UnorderedElementsAre( + "grpc.testing.EchoTestService", + "grpc.reflection.v1alpha.ServerReflection", + "grpc.reflection.v1.ServerReflection", "")); ShutdownServer(); } @@ -1395,9 +1399,11 @@ TEST_F(GrpcToolTest, ListCommandOverrideSslHostName) { 0 == GrpcToolMainLib( ArraySize(argv), argv, TestCliCredentials(true), std::bind(PrintStream, &output_stream, std::placeholders::_1))); - EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), - "grpc.testing.EchoTestService\n" - "grpc.reflection.v1alpha.ServerReflection\n")); + EXPECT_THAT( + absl::StrSplit(output_stream.str(), '\n'), + ::testing::UnorderedElementsAre( + "grpc.testing.EchoTestService", "grpc.reflection.v1.ServerReflection", + "grpc.reflection.v1alpha.ServerReflection", "")); absl::SetFlag(&FLAGS_channel_creds_type, ""); absl::SetFlag(&FLAGS_ssl_target, ""); @@ -1420,9 +1426,11 @@ TEST_F(GrpcToolTest, ConfiguringDefaultServiceConfig) { std::bind(PrintStream, &output_stream, std::placeholders::_1))); absl::SetFlag(&FLAGS_default_service_config, ""); - EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), - "grpc.testing.EchoTestService\n" - "grpc.reflection.v1alpha.ServerReflection\n")); + EXPECT_THAT( + absl::StrSplit(output_stream.str().c_str(), '\n'), + ::testing::UnorderedElementsAre( + "grpc.testing.EchoTestService", "grpc.reflection.v1.ServerReflection", + "grpc.reflection.v1alpha.ServerReflection", "")); ShutdownServer(); }