Implement gRPC command line interface.
This commit is contained in:
parent
67050147f2
commit
dfe5509412
148
src/grpc-cli.cc
148
src/grpc-cli.cc
|
@ -7,20 +7,73 @@
|
|||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <functional>
|
||||
|
||||
#include "clipp.h"
|
||||
#include "grpc++/grpc++.h"
|
||||
#include "rslp.pb.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#include "rslp.grpc.pb.h"
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
|
||||
struct Options {
|
||||
Options() : host{"localhost"}, port{"6543"} { }
|
||||
Options() : host{"localhost:6544"} { }
|
||||
|
||||
std::string host;
|
||||
std::string port;
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
std::ostream& operator<<(std::ostream& ostream, const rslp::Command& command)
|
||||
{
|
||||
using Type = rslp::Command_Data::DataCase;
|
||||
|
||||
for (int i{}; i < command.data_size(); i++) {
|
||||
auto data{command.data(i)};
|
||||
|
||||
if (command.data_size() > 1) {
|
||||
ostream << i+1 << ") ";
|
||||
}
|
||||
|
||||
switch (data.data_case()) {
|
||||
case Type::kErr:
|
||||
ostream << "(error) \"" << data.err() << '"';
|
||||
break;
|
||||
|
||||
case Type::kStr:
|
||||
ostream << '"' << data.str() << '"';
|
||||
break;
|
||||
|
||||
case Type::kInt:
|
||||
ostream << data.int_();
|
||||
break;
|
||||
|
||||
case Type::kArray:
|
||||
ostream << data.array();
|
||||
break;
|
||||
|
||||
default:
|
||||
ostream << "(nil)";
|
||||
break;
|
||||
}
|
||||
|
||||
if (command.data_size() > 1 && i < command.data_size()-1) {
|
||||
ostream << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
return ostream;
|
||||
}
|
||||
|
||||
Options parse_commandline(int argc, char** argv)
|
||||
{
|
||||
Options options;
|
||||
|
@ -28,9 +81,7 @@ Options parse_commandline(int argc, char** argv)
|
|||
|
||||
auto cli = (
|
||||
clipp::option("-h", "--host").set(options.host)
|
||||
.doc("Set the host to connect to [default: localhost]"),
|
||||
clipp::option("-p", "--port").set(options.port)
|
||||
.doc("Set the port to connect to [default: 6543]"),
|
||||
.doc("Set the host (and port, optional) to connect to [default: localhost:6544]"),
|
||||
clipp::option("--help").set(show_help).doc("Show help and exit.")
|
||||
);
|
||||
|
||||
|
@ -42,6 +93,56 @@ Options parse_commandline(int argc, char** argv)
|
|||
return options;
|
||||
}
|
||||
|
||||
class GrpcResplyClient {
|
||||
public:
|
||||
GrpcResplyClient(std::shared_ptr<grpc::Channel> channel) :
|
||||
stub_{rslp::ProtoAdapter::NewStub(channel)}
|
||||
{ }
|
||||
|
||||
rslp::Command command(const std::vector<std::string>& arguments)
|
||||
{
|
||||
rslp::Command command;
|
||||
|
||||
for (const std::string& arg: arguments) {
|
||||
command.add_data()->set_str(arg);
|
||||
}
|
||||
|
||||
grpc::ClientContext context;
|
||||
rslp::Command response;
|
||||
|
||||
if (stub_->execute(&context, command, &response).ok()) {
|
||||
return response;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void subscribe(const std::vector<std::string>& arguments,
|
||||
std::function<void(const std::string& channel, const std::string& message)> callback)
|
||||
{
|
||||
rslp::Command command;
|
||||
|
||||
for (const std::string& arg: arguments) {
|
||||
command.add_data()->set_str(arg);
|
||||
}
|
||||
|
||||
grpc::ClientContext context;
|
||||
rslp::Command response;
|
||||
|
||||
auto reader{stub_->subscribe(&context, command)};
|
||||
reader->Read(&response);
|
||||
|
||||
while (reader->Read(&response)) {
|
||||
callback(response.data(1).str(), response.data(2).str());
|
||||
}
|
||||
|
||||
reader->Finish();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<rslp::ProtoAdapter::Stub> stub_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,5 +150,42 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
auto options{parse_commandline(argc, argv)};
|
||||
|
||||
auto channel{grpc::CreateChannel(
|
||||
options.host, grpc::InsecureChannelCredentials()
|
||||
)};
|
||||
GrpcResplyClient client{channel};
|
||||
|
||||
while (std::cin) {
|
||||
std::cout << options.host << ':' << "> ";
|
||||
|
||||
std::string line;
|
||||
std::getline(std::cin, line);
|
||||
|
||||
if (!line.length()) {
|
||||
continue;
|
||||
}
|
||||
std::stringstream linestream{line};
|
||||
|
||||
std::vector<std::string> command;
|
||||
while (linestream >> line) {
|
||||
command.push_back(line);
|
||||
}
|
||||
|
||||
std::string name{command.front()};
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
|
||||
if (name == "subscribe" || name == "psubscribe") {
|
||||
client.subscribe(command, [](const auto& channel, const auto& message) {
|
||||
std::cout << channel << ": " << message << std::endl;
|
||||
});
|
||||
} else {
|
||||
rslp::Command result{client.command(command)};
|
||||
std::cout << result << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
return 0;
|
||||
}
|
||||
|
|
Reference in a new issue