mirror of https://github.com/grpc/grpc.git
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
8.0 KiB
216 lines
8.0 KiB
/* |
|
* |
|
* 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; |
|
}
|
|
|