Added GRPC code generator to flatc.

Also added simple (in-process) test.

Change-Id: I38580d554dd52f590e3396ec4846e07546dcf07d
Tested: on Linux.
This commit is contained in:
Wouter van Oortmerssen
2016-04-13 18:16:05 -07:00
parent 6dff7c68f1
commit 48f37f9e0a
18 changed files with 2081 additions and 6 deletions

11
grpc/README.md Normal file
View File

@@ -0,0 +1,11 @@
GRPC implementation and test
============================
NOTE: files in `src/` are shared with the GRPC project, and maintained there
(any changes should be submitted to GRPC instead). These files are copied
from GRPC, and work with both the Protobuf and FlatBuffers code generator.
`tests/` contains a GRPC specific test, you need to have built and installed
the GRPC libraries for this to compile. This test will build using the
`FLATBUFFERS_BUILD_GRPCTEST` option to the main FlatBuffers CMake project.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
/*
*
* Copyright 2015, 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.
*
*/
#ifndef GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
#define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H
// cpp_generator.h/.cc do not directly depend on GRPC/ProtoBuf, such that they
// can be used to generate code for other serialization systems, such as
// FlatBuffers.
#include <memory>
#include <vector>
#ifndef GRPC_CUSTOM_STRING
#include <string>
#define GRPC_CUSTOM_STRING std::string
#endif
namespace grpc {
typedef GRPC_CUSTOM_STRING string;
} // namespace grpc
namespace grpc_cpp_generator {
// Contains all the parameters that are parsed from the command line.
struct Parameters {
// Puts the service into a namespace
grpc::string services_namespace;
// Use system includes (<>) or local includes ("")
bool use_system_headers;
// Prefix to any grpc include
grpc::string grpc_search_path;
};
// An abstract interface representing a method.
struct Method {
virtual ~Method() {}
virtual grpc::string name() const = 0;
virtual grpc::string input_type_name() const = 0;
virtual grpc::string output_type_name() const = 0;
virtual bool NoStreaming() const = 0;
virtual bool ClientOnlyStreaming() const = 0;
virtual bool ServerOnlyStreaming() const = 0;
virtual bool BidiStreaming() const = 0;
};
// An abstract interface representing a service.
struct Service {
virtual ~Service() {}
virtual grpc::string name() const = 0;
virtual int method_count() const = 0;
virtual std::unique_ptr<const Method> method(int i) const = 0;
};
struct Printer {
virtual ~Printer() {}
virtual void Print(const std::map<grpc::string, grpc::string> &vars,
const char *template_string) = 0;
virtual void Print(const char *string) = 0;
virtual void Indent() = 0;
virtual void Outdent() = 0;
};
// An interface that allows the source generated to be output using various
// libraries/idls/serializers.
struct File {
virtual ~File() {}
virtual grpc::string filename() const = 0;
virtual grpc::string filename_without_ext() const = 0;
virtual grpc::string message_header_ext() const = 0;
virtual grpc::string service_header_ext() const = 0;
virtual grpc::string package() const = 0;
virtual std::vector<grpc::string> package_parts() const = 0;
virtual grpc::string additional_headers() const = 0;
virtual int service_count() const = 0;
virtual std::unique_ptr<const Service> service(int i) const = 0;
virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
};
// Return the prologue of the generated header file.
grpc::string GetHeaderPrologue(File *file, const Parameters &params);
// Return the includes needed for generated header file.
grpc::string GetHeaderIncludes(File *file, const Parameters &params);
// Return the includes needed for generated source file.
grpc::string GetSourceIncludes(File *file, const Parameters &params);
// Return the epilogue of the generated header file.
grpc::string GetHeaderEpilogue(File *file, const Parameters &params);
// Return the prologue of the generated source file.
grpc::string GetSourcePrologue(File *file, const Parameters &params);
// Return the services for generated header file.
grpc::string GetHeaderServices(File *file, const Parameters &params);
// Return the services for generated source file.
grpc::string GetSourceServices(File *file, const Parameters &params);
// Return the epilogue of the generated source file.
grpc::string GetSourceEpilogue(File *file, const Parameters &params);
} // namespace grpc_cpp_generator
#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H

124
grpc/tests/grpctest.cpp Normal file
View File

@@ -0,0 +1,124 @@
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* 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 <thread>
#include <grpc++/grpc++.h>
#include "monster_test_generated.h"
#include "monster_test.grpc.fb.h"
using namespace MyGame::Example;
// The callback implementation of our server, that derives from the generated
// code. It implements all rpcs specified in the FlatBuffers schema.
class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
virtual ::grpc::Status Store(::grpc::ServerContext* context,
const flatbuffers::BufferRef<Monster> *request,
flatbuffers::BufferRef<Stat> *response)
override {
// Create a response from the incoming request name.
fbb_.Clear();
auto stat_offset = CreateStat(fbb_, fbb_.CreateString("Hello, " +
request->GetRoot()->name()->str()));
fbb_.Finish(stat_offset);
// Since we keep reusing the same FlatBufferBuilder, the memory it owns
// remains valid until the next call (this BufferRef doesn't own the
// memory it points to).
*response = flatbuffers::BufferRef<Stat>(fbb_.GetBufferPointer(),
fbb_.GetSize());
return grpc::Status::OK;
}
virtual ::grpc::Status Retrieve(::grpc::ServerContext *context,
const flatbuffers::BufferRef<Stat> *request,
flatbuffers::BufferRef<Monster> *response)
override {
assert(false); // We're not actually using this RPC.
return grpc::Status::CANCELLED;
}
private:
flatbuffers::FlatBufferBuilder fbb_;
};
// Track the server instance, so we can terminate it later.
grpc::Server *server_instance = nullptr;
// Mutex to protec this variable.
std::mutex wait_for_server;
std::condition_variable server_instance_cv;
// This function implements the server thread.
void RunServer() {
auto server_address = "0.0.0.0:50051";
// Callback interface we implemented above.
ServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
// Start the server. Lock to change the variable we're changing.
wait_for_server.lock();
server_instance = builder.BuildAndStart().release();
wait_for_server.unlock();
server_instance_cv.notify_one();
std::cout << "Server listening on " << server_address << std::endl;
// This will block the thread and serve requests.
server_instance->Wait();
}
int main(int /*argc*/, const char * /*argv*/[]) {
// Launch server.
std::thread server_thread(RunServer);
// wait for server to spin up.
std::unique_lock<std::mutex> lock(wait_for_server);
while (!server_instance) server_instance_cv.wait(lock);
// Now connect the client.
auto channel = grpc::CreateChannel("localhost:50051",
grpc::InsecureChannelCredentials());
auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
grpc::ClientContext context;
// Build a request with the name set.
flatbuffers::FlatBufferBuilder fbb;
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
fbb.Finish(monster_offset);
auto request = flatbuffers::BufferRef<Monster>(fbb.GetBufferPointer(),
fbb.GetSize());
flatbuffers::BufferRef<Stat> response;
// The actual RPC.
auto status = stub->Store(&context, request, &response);
if (status.ok()) {
auto resp = response.GetRoot()->id();
std::cout << "RPC response: " << resp->str() << std::endl;
} else {
std::cout << "RPC failed" << std::endl;
}
server_instance->Shutdown();
server_thread.join();
delete server_instance;
return 0;
}