mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-01 19:58:15 +00:00
gRPC callbackService support added (#8666)
* grpc callbackService support added Signed-off-by: shankeleven <shashanksati11@gmail.com> * tests: regenerate C++ gRPC golden with --grpc-callback-api (CallbackService & async_ reactor APIs); update formatting and method placement --------- Signed-off-by: shankeleven <shashanksati11@gmail.com> Co-authored-by: Wouter van Oortmerssen <aardappel@gmail.com>
This commit is contained in:
@@ -4,6 +4,10 @@ All major or breaking changes will be documented in this file, as well as any
|
||||
new features that should be highlighted. Minor fixes or improvements are not
|
||||
necessarily listed.
|
||||
|
||||
## Unreleased
|
||||
|
||||
* flatc: `--grpc-callback-api` flag generates C++ gRPC Callback API server `CallbackService` skeletons AND client native callback/async stubs (unary + all streaming reactor forms) (opt-in, non-breaking, issue #8596).
|
||||
|
||||
## [25.2.10] (February 10 2025)(https://github.com/google/flatbuffers/releases/tag/v25.2.10)
|
||||
|
||||
* Removed the old documentation pages. The new one is live at https://flatbuffers.dev
|
||||
|
||||
@@ -279,6 +279,8 @@ set(FlatBuffers_GRPCTest_SRCS
|
||||
tests/test_builder.cpp
|
||||
grpc/tests/grpctest.cpp
|
||||
grpc/tests/message_builder_test.cpp
|
||||
grpc/tests/grpctest_callback_compile.cpp
|
||||
grpc/tests/grpctest_callback_client_compile.cpp
|
||||
)
|
||||
|
||||
# TODO(dbaileychess): Figure out how this would now work. I posted a question on
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
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
|
||||
@@ -39,4 +38,64 @@ For Bazel users:
|
||||
|
||||
```shell
|
||||
$bazel test tests/...
|
||||
```
|
||||
```
|
||||
|
||||
## C++ Callback API Generation
|
||||
|
||||
FlatBuffers gRPC C++ code generation now optionally supports the modern gRPC Callback API.
|
||||
|
||||
To enable generation of a `CallbackService` skeleton alongside the existing `Service` and async mixins, invoke `flatc` with both `--grpc` and `--grpc-callback-api`:
|
||||
|
||||
```shell
|
||||
flatc --cpp --grpc --grpc-callback-api your_service.fbs
|
||||
```
|
||||
|
||||
This adds (guarded by `#if defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)`) a class:
|
||||
|
||||
```cpp
|
||||
class YourService::CallbackService : public ::grpc::Service { /* reactor virtuals */ };
|
||||
```
|
||||
|
||||
Each RPC shape maps to the appropriate reactor return type:
|
||||
|
||||
- Unary -> `::grpc::ServerUnaryReactor*` Method(...)
|
||||
- Client streaming -> `::grpc::ServerReadReactor<Request>*`
|
||||
- Server streaming -> `::grpc::ServerWriteReactor<Response>*`
|
||||
- Bidi streaming -> `::grpc::ServerBidiReactor<Request, Response>*`
|
||||
|
||||
Default generated implementations return `nullptr`; override in your derived class and return a reactor instance you manage (see gRPC docs for lifecycle patterns).
|
||||
|
||||
If your gRPC library predates the stable callback API macro, the code inside the guard will be skipped (no breaking changes). Ensure you build against a recent gRPC (1.38+; verify current minimum in grpc repo) to use this feature.
|
||||
|
||||
### Client Callback Stubs
|
||||
|
||||
When `--grpc-callback-api` is supplied, the generated C++ client stub gains native callback / reactor based async methods in addition to the existing synchronous / generic async flavors, guarded by the same macro. For each RPC named `Foo`:
|
||||
|
||||
Unary:
|
||||
|
||||
```
|
||||
void async_Foo(::grpc::ClientContext*, const Request&, Response*, std::function<void(::grpc::Status)>);
|
||||
void async_Foo(::grpc::ClientContext*, const Request&, Response*, ::grpc::ClientUnaryReactor*);
|
||||
```
|
||||
|
||||
Client streaming:
|
||||
|
||||
```
|
||||
::grpc::ClientWriteReactor<Request>* async_Foo(::grpc::ClientContext*, Response*, ::grpc::ClientWriteReactor<Request>*);
|
||||
```
|
||||
|
||||
Server streaming:
|
||||
|
||||
```
|
||||
::grpc::ClientReadReactor<Response>* async_Foo(::grpc::ClientContext*, const Request&, ::grpc::ClientReadReactor<Response>*);
|
||||
```
|
||||
|
||||
Bidirectional streaming:
|
||||
|
||||
```
|
||||
::grpc::ClientBidiReactor<Request, Response>* async_Foo(::grpc::ClientContext*, ::grpc::ClientBidiReactor<Request, Response>*);
|
||||
```
|
||||
|
||||
These map directly onto the native gRPC callback API factories (e.g. `CallbackUnaryCall`, `ClientCallbackWriterFactory::Create`, etc.) and do not spawn threads. Override the appropriate reactor callbacks per gRPC's documentation to drive I/O.
|
||||
|
||||
If your build uses an older gRPC lacking the non-experimental macro, these symbols will not be emitted, preserving backwards compatibility.
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
namespace grpc_cpp_generator {
|
||||
namespace {
|
||||
|
||||
template<class T>
|
||||
static grpc::string as_string(T x) {
|
||||
template<class T> static grpc::string as_string(T x) {
|
||||
std::ostringstream out;
|
||||
out << x;
|
||||
return out.str();
|
||||
@@ -39,12 +38,13 @@ static grpc::string FilenameIdentifier(const grpc::string &filename) {
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T, size_t N>
|
||||
static T *array_end(T (&array)[N]) { return array + N; }
|
||||
template<class T, size_t N> static T *array_end(T (&array)[N]) {
|
||||
return array + N;
|
||||
}
|
||||
|
||||
static void PrintIncludes(grpc_generator::Printer *printer,
|
||||
const std::vector<grpc::string> &headers,
|
||||
const Parameters ¶ms) {
|
||||
const std::vector<grpc::string> &headers,
|
||||
const Parameters ¶ms) {
|
||||
std::map<grpc::string, grpc::string> vars;
|
||||
|
||||
vars["l"] = params.use_system_headers ? '<' : '"';
|
||||
@@ -60,6 +60,18 @@ static void PrintIncludes(grpc_generator::Printer *printer,
|
||||
vars["h"] = *i;
|
||||
printer->Print(vars, "#include $l$$h$$r$\n");
|
||||
}
|
||||
if (params.generate_callback_api) {
|
||||
// Callback API headers (guarded later by feature macro in emitted code).
|
||||
static const char *cb_headers[] = {
|
||||
"grpcpp/impl/codegen/callback_common.h",
|
||||
"grpcpp/impl/codegen/server_callback_handlers.h",
|
||||
"grpcpp/support/client_callback.h"
|
||||
};
|
||||
for (auto &h : cb_headers) {
|
||||
vars["h"] = h;
|
||||
printer->Print(vars, "#include $l$$h$$r$\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -138,7 +150,6 @@ grpc::string GetHeaderIncludes(grpc_generator::File *file,
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
static void PrintHeaderClientMethodInterfaces(
|
||||
@@ -355,12 +366,10 @@ static void PrintHeaderClientMethodInterfaces(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars,
|
||||
bool is_public) {
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars,
|
||||
bool is_public) {
|
||||
(*vars)["Method"] = method->name();
|
||||
(*vars)["Request"] = method->input_type_name();
|
||||
(*vars)["Response"] = method->output_type_name();
|
||||
@@ -377,6 +386,22 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
|
||||
*vars,
|
||||
"::grpc::Status $Method$(::grpc::ClientContext* context, "
|
||||
"const $Request$& request, $Response$* response) override;\n");
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
// Native gRPC callback unary wrappers (function callback & reactor
|
||||
// variants).
|
||||
printer->Print(*vars,
|
||||
"// Callback unary (function form). Request/response "
|
||||
"must outlive callback.\n");
|
||||
printer->Print(*vars,
|
||||
"void async_$Method$(::grpc::ClientContext* context, "
|
||||
"const $Request$& request, $Response$* response, "
|
||||
"std::function<void(::grpc::Status)> on_done);\n");
|
||||
printer->Print(*vars, "// Callback unary (reactor form).\n");
|
||||
printer->Print(*vars,
|
||||
"void async_$Method$(::grpc::ClientContext* context, "
|
||||
"const $Request$& request, $Response$* response, "
|
||||
"::grpc::ClientUnaryReactor* reactor);\n");
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
|
||||
i++) {
|
||||
auto &async_prefix = async_prefixes[i];
|
||||
@@ -407,6 +432,12 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
|
||||
"($Method$Raw(context, response));\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
printer->Print(*vars, "// Client streaming callback reactor entry.\n");
|
||||
printer->Print(
|
||||
*vars,
|
||||
"void async_$Method$(::grpc::ClientContext* context, $Response$* response, ::grpc::ClientWriteReactor< $Request$ >* reactor);\n");
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
|
||||
i++) {
|
||||
auto &async_prefix = async_prefixes[i];
|
||||
@@ -440,6 +471,11 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
|
||||
"($Method$Raw(context, request));\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
printer->Print(*vars, "// Server streaming callback reactor entry.\n");
|
||||
printer->Print(*vars,
|
||||
"void async_$Method$(::grpc::ClientContext* context, const $Request$& request, ::grpc::ClientReadReactor< $Response$ >* reactor);\n");
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
|
||||
i++) {
|
||||
auto &async_prefix = async_prefixes[i];
|
||||
@@ -472,6 +508,12 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
|
||||
"$Method$Raw(context));\n");
|
||||
printer->Outdent();
|
||||
printer->Print("}\n");
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
printer->Print(*vars, "// Bidirectional streaming callback reactor entry.\n");
|
||||
printer->Print(
|
||||
*vars,
|
||||
"void async_$Method$(::grpc::ClientContext* context, ::grpc::ClientBidiReactor< $Request$, $Response$ >* reactor);\n");
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
|
||||
i++) {
|
||||
auto &async_prefix = async_prefixes[i];
|
||||
@@ -506,6 +548,10 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
|
||||
"const $Request$& request, "
|
||||
"::grpc::CompletionQueue* cq) override;\n");
|
||||
}
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
// Native callback unary forms declared earlier (no private sync helper
|
||||
// needed).
|
||||
}
|
||||
} else if (ClientOnlyStreaming(method)) {
|
||||
printer->Print(*vars,
|
||||
"::grpc::ClientWriter< $Request$>* $Method$Raw("
|
||||
@@ -560,17 +606,17 @@ static void PrintHeaderClientMethod(grpc_generator::Printer *printer,
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintHeaderClientMethodData(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
static void PrintHeaderClientMethodData(
|
||||
grpc_generator::Printer *printer, const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Method"] = method->name();
|
||||
printer->Print(*vars,
|
||||
"const ::grpc::internal::RpcMethod rpcmethod_$Method$_;\n");
|
||||
}
|
||||
|
||||
static void PrintHeaderServerMethodSync(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
static void PrintHeaderServerMethodSync(
|
||||
grpc_generator::Printer *printer, const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Method"] = method->name();
|
||||
(*vars)["Request"] = method->input_type_name();
|
||||
(*vars)["Response"] = method->output_type_name();
|
||||
@@ -602,9 +648,9 @@ static void PrintHeaderServerMethodSync(grpc_generator::Printer *printer,
|
||||
printer->Print(method->GetTrailingComments("//").c_str());
|
||||
}
|
||||
|
||||
static void PrintHeaderServerMethodAsync(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
static void PrintHeaderServerMethodAsync(
|
||||
grpc_generator::Printer *printer, const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Method"] = method->name();
|
||||
(*vars)["Request"] = method->input_type_name();
|
||||
(*vars)["Response"] = method->output_type_name();
|
||||
@@ -894,8 +940,8 @@ static void PrintHeaderServerMethodGeneric(
|
||||
}
|
||||
|
||||
static void PrintHeaderService(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Service *service,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
const grpc_generator::Service *service,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Service"] = service->name();
|
||||
|
||||
printer->Print(service->GetLeadingComments("//").c_str());
|
||||
@@ -930,6 +976,10 @@ static void PrintHeaderService(grpc_generator::Printer *printer,
|
||||
false);
|
||||
}
|
||||
printer->Outdent();
|
||||
// Forward declaration of nested CallbackService if callback API enabled.
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
printer->Print("class CallbackService;\n");
|
||||
}
|
||||
printer->Print("};\n");
|
||||
printer->Print(
|
||||
"class Stub final : public StubInterface"
|
||||
@@ -1062,9 +1112,51 @@ static void PrintHeaderService(grpc_generator::Printer *printer,
|
||||
printer->Outdent();
|
||||
printer->Print("};\n");
|
||||
printer->Print(service->GetTrailingComments("//").c_str());
|
||||
|
||||
// Optional CallbackService (modern async API)
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
(*vars)["Service"] = service->name();
|
||||
printer->Print("\n#if defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)\n");
|
||||
printer->Print(*vars,
|
||||
"class $Service$::CallbackService : public ::grpc::Service "
|
||||
"{\n public:\n CallbackService();\n virtual "
|
||||
"~CallbackService();\n");
|
||||
printer->Indent();
|
||||
for (int i = 0; i < service->method_count(); ++i) {
|
||||
auto m = service->method(i);
|
||||
(*vars)["Method"] = m->name();
|
||||
(*vars)["Request"] = m->input_type_name();
|
||||
(*vars)["Response"] = m->output_type_name();
|
||||
if (m->NoStreaming()) {
|
||||
printer->Print(*vars,
|
||||
"virtual ::grpc::ServerUnaryReactor* "
|
||||
"$Method$(::grpc::CallbackServerContext* context, const "
|
||||
"$Request$* request, $Response$* response);\n");
|
||||
} else if (ClientOnlyStreaming(m.get())) {
|
||||
printer->Print(*vars,
|
||||
"virtual ::grpc::ServerReadReactor<$Request$>* "
|
||||
"$Method$(::grpc::CallbackServerContext* context, "
|
||||
"$Response$* response);\n");
|
||||
} else if (ServerOnlyStreaming(m.get())) {
|
||||
printer->Print(*vars,
|
||||
"virtual ::grpc::ServerWriteReactor<$Response$>* "
|
||||
"$Method$(::grpc::CallbackServerContext* context, const "
|
||||
"$Request$* request);\n");
|
||||
} else if (m->BidiStreaming()) {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"virtual ::grpc::ServerBidiReactor<$Request$, $Response$>* "
|
||||
"$Method$(::grpc::CallbackServerContext* context);\n");
|
||||
}
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print(
|
||||
"};\n#else\n// Callback API requested but not available in this gRPC "
|
||||
"version.\n#endif // GRPC_CALLBACK_API_NONEXPERIMENTAL\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
grpc::string GetHeaderServices(grpc_generator::File *file,
|
||||
const Parameters ¶ms) {
|
||||
@@ -1084,9 +1176,14 @@ grpc::string GetHeaderServices(grpc_generator::File *file,
|
||||
}
|
||||
|
||||
for (int i = 0; i < file->service_count(); ++i) {
|
||||
vars["generate_callback_api"] = params.generate_callback_api ? "1" : "0";
|
||||
PrintHeaderService(printer.get(), file->service(i).get(), &vars);
|
||||
printer->Print("\n");
|
||||
}
|
||||
if (params.generate_callback_api) {
|
||||
printer->Print("// FlatBuffers: Callback API code generated.\n");
|
||||
printer->Print("#define FLATBUFFERS_GENERATED_GRPC_CALLBACK_API 1\n\n");
|
||||
}
|
||||
|
||||
if (!params.services_namespace.empty()) {
|
||||
printer->Print(vars, "} // namespace $services_namespace$\n\n");
|
||||
@@ -1139,7 +1236,8 @@ grpc::string GetSourcePrologue(grpc_generator::File *file,
|
||||
|
||||
printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
|
||||
printer->Print(vars,
|
||||
"// If you make any local change, they will be lost.\n");
|
||||
"// FlatBuffers modified generator: native gRPC callback "
|
||||
"client API enabled when --grpc-callback-api.\n");
|
||||
printer->Print(vars, "// source: $filename$\n\n");
|
||||
|
||||
printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
|
||||
@@ -1184,12 +1282,11 @@ grpc::string GetSourceIncludes(grpc_generator::File *file,
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
static void PrintSourceClientMethod(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
static void PrintSourceClientMethod(
|
||||
grpc_generator::Printer *printer, const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Method"] = method->name();
|
||||
(*vars)["Request"] = method->input_type_name();
|
||||
(*vars)["Response"] = method->output_type_name();
|
||||
@@ -1209,6 +1306,27 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
|
||||
" return ::grpc::internal::BlockingUnaryCall"
|
||||
"(channel_.get(), rpcmethod_$Method$_, "
|
||||
"context, request, response);\n}\n\n");
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
|
||||
"context, const $Request$& request, $Response$* response, "
|
||||
"std::function<void(::grpc::Status)> on_done) {\n");
|
||||
printer->Print(*vars,
|
||||
" ::grpc::internal::CallbackUnaryCall(channel_.get(), "
|
||||
"rpcmethod_$Method$_, context, &request, response, "
|
||||
"std::move(on_done));\n}\n\n");
|
||||
printer->Print(
|
||||
*vars,
|
||||
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
|
||||
"context, const $Request$& request, $Response$* response, "
|
||||
"::grpc::ClientUnaryReactor* reactor) {\n");
|
||||
printer->Print(
|
||||
*vars,
|
||||
" "
|
||||
"::grpc::internal::ClientCallbackUnaryFactory::Create(channel_.get(),"
|
||||
" rpcmethod_$Method$_, context, &request, response, reactor);\n}\n\n");
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
|
||||
i++) {
|
||||
auto &async_prefix = async_prefixes[i];
|
||||
@@ -1241,6 +1359,17 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
|
||||
"rpcmethod_$Method$_, "
|
||||
"context, response);\n"
|
||||
"}\n\n");
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
|
||||
"context, $Response$* response, ::grpc::ClientWriteReactor< "
|
||||
"$Request$ >* reactor) {\n");
|
||||
printer->Print(*vars,
|
||||
" ::grpc::internal::ClientCallbackWriterFactory< "
|
||||
"$Request$ >::Create(channel_.get(), rpcmethod_$Method$_, "
|
||||
"context, response, reactor);\n}\n\n");
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
|
||||
i++) {
|
||||
auto &async_prefix = async_prefixes[i];
|
||||
@@ -1274,6 +1403,17 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
|
||||
"rpcmethod_$Method$_, "
|
||||
"context, request);\n"
|
||||
"}\n\n");
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
|
||||
"context, const $Request$& request, ::grpc::ClientReadReactor< "
|
||||
"$Response$ >* reactor) {\n");
|
||||
printer->Print(*vars,
|
||||
" ::grpc::internal::ClientCallbackReaderFactory< "
|
||||
"$Response$ >::Create(channel_.get(), "
|
||||
"rpcmethod_$Method$_, context, &request, reactor);\n}\n\n");
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
|
||||
i++) {
|
||||
auto &async_prefix = async_prefixes[i];
|
||||
@@ -1307,6 +1447,17 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
|
||||
"rpcmethod_$Method$_, "
|
||||
"context);\n"
|
||||
"}\n\n");
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"void $ns$$Service$::Stub::async_$Method$(::grpc::ClientContext* "
|
||||
"context, ::grpc::ClientBidiReactor< $Request$, $Response$ >* "
|
||||
"reactor) {\n");
|
||||
printer->Print(*vars,
|
||||
" ::grpc::internal::ClientCallbackReaderWriterFactory< "
|
||||
"$Request$, $Response$ >::Create(channel_.get(), "
|
||||
"rpcmethod_$Method$_, context, reactor);\n}\n\n");
|
||||
}
|
||||
for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]);
|
||||
i++) {
|
||||
auto &async_prefix = async_prefixes[i];
|
||||
@@ -1331,9 +1482,9 @@ static void PrintSourceClientMethod(grpc_generator::Printer *printer,
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintSourceServerMethod(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
static void PrintSourceServerMethod(
|
||||
grpc_generator::Printer *printer, const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Method"] = method->name();
|
||||
(*vars)["Request"] = method->input_type_name();
|
||||
(*vars)["Response"] = method->output_type_name();
|
||||
@@ -1381,8 +1532,8 @@ static void PrintSourceServerMethod(grpc_generator::Printer *printer,
|
||||
}
|
||||
|
||||
static void PrintSourceService(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Service *service,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
const grpc_generator::Service *service,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Service"] = service->name();
|
||||
|
||||
if (service->method_count() > 0) {
|
||||
@@ -1495,9 +1646,110 @@ static void PrintSourceService(grpc_generator::Printer *printer,
|
||||
(*vars)["Idx"] = as_string(i);
|
||||
PrintSourceServerMethod(printer, service->method(i).get(), vars);
|
||||
}
|
||||
|
||||
// CallbackService implementation (if enabled)
|
||||
if ((*vars)["generate_callback_api"] == "1") {
|
||||
(*vars)["Service"] = service->name();
|
||||
printer->Print("#if defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)\n");
|
||||
printer->Print(*vars,
|
||||
"$ns$$Service$::CallbackService::CallbackService() {\n");
|
||||
printer->Indent();
|
||||
for (int i = 0; i < service->method_count(); ++i) {
|
||||
auto method = service->method(i);
|
||||
(*vars)["Idx"] = as_string(i);
|
||||
(*vars)["Method"] = method->name();
|
||||
(*vars)["Request"] = method->input_type_name();
|
||||
(*vars)["Response"] = method->output_type_name();
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
|
||||
" $prefix$$Service$_method_names[$Idx$],\n"
|
||||
" ::grpc::internal::RpcMethod::NORMAL_RPC,\n"
|
||||
" new ::grpc::internal::CallbackUnaryHandler<$Request$, $Response$>(\n"
|
||||
" [this](::grpc::CallbackServerContext* ctx, const $Request$* req, $Response$* resp) {\n"
|
||||
" return this->$Method$(ctx, req, resp);\n"
|
||||
" })));\n");
|
||||
} else if (ClientOnlyStreaming(method.get())) {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
|
||||
" $prefix$$Service$_method_names[$Idx$],\n"
|
||||
" ::grpc::internal::RpcMethod::CLIENT_STREAMING,\n"
|
||||
" new ::grpc::internal::CallbackClientStreamingHandler<$Request$, $Response$>(\n"
|
||||
" [this](::grpc::CallbackServerContext* ctx, $Response$* resp) {\n"
|
||||
" return this->$Method$(ctx, resp);\n"
|
||||
" })));\n");
|
||||
} else if (ServerOnlyStreaming(method.get())) {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
|
||||
" $prefix$$Service$_method_names[$Idx$],\n"
|
||||
" ::grpc::internal::RpcMethod::SERVER_STREAMING,\n"
|
||||
" new ::grpc::internal::CallbackServerStreamingHandler<$Request$, $Response$>(\n"
|
||||
" [this](::grpc::CallbackServerContext* ctx, const $Request$* req) {\n"
|
||||
" return this->$Method$(ctx, req);\n"
|
||||
" })));\n");
|
||||
} else if (method->BidiStreaming()) {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"AddMethod(new ::grpc::internal::RpcServiceMethod(\n"
|
||||
" $prefix$$Service$_method_names[$Idx$],\n"
|
||||
" ::grpc::internal::RpcMethod::BIDI_STREAMING,\n"
|
||||
" new ::grpc::internal::CallbackBidiHandler<$Request$, $Response$>(\n"
|
||||
" [this](::grpc::CallbackServerContext* ctx) {\n"
|
||||
" return this->$Method$(ctx);\n"
|
||||
" })));\n");
|
||||
}
|
||||
}
|
||||
printer->Outdent();
|
||||
printer->Print("}\n\n");
|
||||
printer->Print(*vars,
|
||||
"$ns$$Service$::CallbackService::~CallbackService() {}\n\n");
|
||||
// Default method bodies returning UNIMPLEMENTED reactors.
|
||||
for (int i = 0; i < service->method_count(); ++i) {
|
||||
auto method = service->method(i);
|
||||
(*vars)["Method"] = method->name();
|
||||
(*vars)["Request"] = method->input_type_name();
|
||||
(*vars)["Response"] = method->output_type_name();
|
||||
if (method->NoStreaming()) {
|
||||
printer->Print(*vars,
|
||||
"::grpc::ServerUnaryReactor* "
|
||||
"$ns$$Service$::CallbackService::$Method$(::grpc::"
|
||||
"CallbackServerContext* /*context*/, const $Request$* "
|
||||
"/*request*/, $Response$* /*response*/) {\n"
|
||||
" return nullptr; // user must override\n"
|
||||
"}\n\n");
|
||||
} else if (ClientOnlyStreaming(method.get())) {
|
||||
printer->Print(
|
||||
*vars,
|
||||
"::grpc::ServerReadReactor<$Request$>* "
|
||||
"$ns$$Service$::CallbackService::$Method$(::grpc::"
|
||||
"CallbackServerContext* /*context*/, $Response$* /*response*/) {\n"
|
||||
" return nullptr; // user must override\n"
|
||||
"}\n\n");
|
||||
} else if (ServerOnlyStreaming(method.get())) {
|
||||
printer->Print(*vars,
|
||||
"::grpc::ServerWriteReactor<$Response$>* "
|
||||
"$ns$$Service$::CallbackService::$Method$(::grpc::"
|
||||
"CallbackServerContext* /*context*/, const $Request$* "
|
||||
"/*request*/) {\n"
|
||||
" return nullptr; // user must override\n"
|
||||
"}\n\n");
|
||||
} else if (method->BidiStreaming()) {
|
||||
printer->Print(*vars,
|
||||
"::grpc::ServerBidiReactor<$Request$, $Response$>* "
|
||||
"$ns$$Service$::CallbackService::$Method$(::grpc::"
|
||||
"CallbackServerContext* /*context*/) {\n"
|
||||
" return nullptr; // user must override\n"
|
||||
"}\n\n");
|
||||
}
|
||||
}
|
||||
printer->Print("#endif // GRPC_CALLBACK_API_NONEXPERIMENTAL\n");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
grpc::string GetSourceServices(grpc_generator::File *file,
|
||||
const Parameters ¶ms) {
|
||||
@@ -1519,6 +1771,7 @@ grpc::string GetSourceServices(grpc_generator::File *file,
|
||||
}
|
||||
|
||||
for (int i = 0; i < file->service_count(); ++i) {
|
||||
vars["generate_callback_api"] = params.generate_callback_api ? "1" : "0";
|
||||
PrintSourceService(printer.get(), file->service(i).get(), &vars);
|
||||
printer->Print("\n");
|
||||
}
|
||||
@@ -1601,12 +1854,11 @@ grpc::string GetMockIncludes(grpc_generator::File *file,
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
static void PrintMockClientMethods(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
const grpc_generator::Method *method,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Method"] = method->name();
|
||||
(*vars)["Request"] = method->input_type_name();
|
||||
(*vars)["Response"] = method->output_type_name();
|
||||
@@ -1697,8 +1949,8 @@ static void PrintMockClientMethods(grpc_generator::Printer *printer,
|
||||
}
|
||||
|
||||
static void PrintMockService(grpc_generator::Printer *printer,
|
||||
const grpc_generator::Service *service,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
const grpc_generator::Service *service,
|
||||
std::map<grpc::string, grpc::string> *vars) {
|
||||
(*vars)["Service"] = service->name();
|
||||
|
||||
printer->Print(*vars,
|
||||
@@ -1712,7 +1964,7 @@ static void PrintMockService(grpc_generator::Printer *printer,
|
||||
printer->Print("};\n");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
grpc::string GetMockServices(grpc_generator::File *file,
|
||||
const Parameters ¶ms) {
|
||||
|
||||
@@ -37,6 +37,8 @@ struct Parameters {
|
||||
std::string message_header_extension;
|
||||
// Default: ".grpc.fb.h"
|
||||
std::string service_header_extension;
|
||||
// Generate modern callback-based async API service code (CallbackService)
|
||||
bool generate_callback_api = false;
|
||||
};
|
||||
|
||||
// Return the prologue of the generated header file.
|
||||
|
||||
@@ -17,3 +17,27 @@ cc_test(
|
||||
"@com_github_grpc_grpc//:grpc++",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "grpc_callback_compile_test",
|
||||
srcs = ["grpctest_callback_compile.cpp"],
|
||||
copts = ["-Itests"],
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
"//tests:monster_test_cc_fbs",
|
||||
"//tests:monster_test_grpc",
|
||||
"@com_github_grpc_grpc//:grpc++",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "grpc_callback_client_compile_test",
|
||||
srcs = ["grpctest_callback_client_compile.cpp"],
|
||||
copts = ["-Itests"],
|
||||
linkstatic = 1,
|
||||
deps = [
|
||||
"//tests:monster_test_cc_fbs",
|
||||
"//tests:monster_test_grpc",
|
||||
"@com_github_grpc_grpc//:grpc++",
|
||||
],
|
||||
)
|
||||
|
||||
61
grpc/tests/grpctest_callback_client_compile.cpp
Normal file
61
grpc/tests/grpctest_callback_client_compile.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// Verifies that the generated gRPC callback client stub methods are present.
|
||||
// This is a compile-time only test: it never performs an actual RPC.
|
||||
// It supplements grpctest_callback_compile.cpp (server side) by checking
|
||||
// client-side async_ / reactor entry points.
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "monster_test.grpc.fb.h"
|
||||
|
||||
#if defined(FLATBUFFERS_GENERATED_GRPC_CALLBACK_API) && \
|
||||
defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
|
||||
using Stub = MyGame::Example::MonsterStorage::Stub;
|
||||
using namespace MyGame::Example; // NOLINT
|
||||
|
||||
// Unary async overloads
|
||||
static_assert(std::is_member_function_pointer<
|
||||
decltype(static_cast<void (Stub::*)(
|
||||
::grpc::ClientContext *,
|
||||
const flatbuffers::grpc::Message<Monster> &,
|
||||
flatbuffers::grpc::Message<Stat> *,
|
||||
std::function<void(::grpc::Status)>)>(
|
||||
&Stub::async_Store))>::value,
|
||||
"Function-form unary async_Store missing");
|
||||
static_assert(std::is_member_function_pointer<
|
||||
decltype(static_cast<void (Stub::*)(
|
||||
::grpc::ClientContext *,
|
||||
const flatbuffers::grpc::Message<Monster> &,
|
||||
flatbuffers::grpc::Message<Stat> *,
|
||||
::grpc::ClientUnaryReactor *)>(
|
||||
&Stub::async_Store))>::value,
|
||||
"Reactor-form unary async_Store missing");
|
||||
|
||||
// Streaming reactor entry points
|
||||
static_assert(
|
||||
std::is_member_function_pointer<
|
||||
decltype(static_cast<void (Stub::*)(
|
||||
::grpc::ClientContext *,
|
||||
const flatbuffers::grpc::Message<Stat> &,
|
||||
::grpc::ClientReadReactor<flatbuffers::grpc::Message<
|
||||
Monster> > *)>(&Stub::async_Retrieve))>::value,
|
||||
"Server streaming reactor async_Retrieve missing");
|
||||
static_assert(
|
||||
std::is_member_function_pointer<
|
||||
decltype(static_cast<void (Stub::*)(
|
||||
::grpc::ClientContext *,
|
||||
flatbuffers::grpc::Message<Stat> *,
|
||||
::grpc::ClientWriteReactor<flatbuffers::grpc::Message<
|
||||
Monster> > *)>(&Stub::async_GetMaxHitPoint))>::value,
|
||||
"Client streaming reactor async_GetMaxHitPoint missing");
|
||||
static_assert(std::is_member_function_pointer<
|
||||
decltype(static_cast<void (Stub::*)(
|
||||
::grpc::ClientContext *,
|
||||
::grpc::ClientBidiReactor<
|
||||
flatbuffers::grpc::Message<Monster>,
|
||||
flatbuffers::grpc::Message<Stat> > *)>(
|
||||
&Stub::async_GetMinMaxHitPoints))>::value,
|
||||
"Bidi streaming reactor async_GetMinMaxHitPoints missing");
|
||||
#endif // FLATBUFFERS_GENERATED_GRPC_CALLBACK_API &&
|
||||
// GRPC_CALLBACK_API_NONEXPERIMENTAL
|
||||
|
||||
int main() { return 0; }
|
||||
22
grpc/tests/grpctest_callback_compile.cpp
Normal file
22
grpc/tests/grpctest_callback_compile.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "monster_test.grpc.fb.h"
|
||||
|
||||
// This test only verifies that the generated CallbackService compiles when the
|
||||
// callback API is available. It does not run any RPCs.
|
||||
|
||||
#if defined(FLATBUFFERS_GENERATED_GRPC_CALLBACK_API) && \
|
||||
defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
|
||||
class CallbackServiceImpl
|
||||
: public MyGame::Example::MonsterStorage::CallbackService {
|
||||
public:
|
||||
// For brevity we don't override methods; user code will provide reactors.
|
||||
};
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#if defined(FLATBUFFERS_GENERATED_GRPC_CALLBACK_API) && \
|
||||
defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
|
||||
CallbackServiceImpl svc;
|
||||
(void)svc; // suppress unused
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -342,6 +342,7 @@ struct FieldDef : public Definition {
|
||||
|
||||
bool Deserialize(Parser &parser, const reflection::Field *field);
|
||||
|
||||
|
||||
bool IsScalarOptional() const {
|
||||
return IsScalar() && IsOptional();
|
||||
}
|
||||
@@ -784,6 +785,9 @@ struct IDLOptions {
|
||||
bool grpc_use_system_headers;
|
||||
std::string grpc_search_path;
|
||||
std::vector<std::string> grpc_additional_headers;
|
||||
// Generate C++ gRPC Callback API (modern async API) service code when used
|
||||
// together with --grpc. This is an additive, opt-in feature.
|
||||
bool grpc_callback_api;
|
||||
|
||||
/******************************* Python gRPC ********************************/
|
||||
bool grpc_python_typed_handlers;
|
||||
@@ -862,6 +866,7 @@ struct IDLOptions {
|
||||
set_empty_vectors_to_null(true),
|
||||
grpc_filename_suffix(".fb"),
|
||||
grpc_use_system_headers(true),
|
||||
grpc_callback_api(false),
|
||||
grpc_python_typed_handlers(false) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -154,13 +154,26 @@ flatc(
|
||||
include="include_test",
|
||||
)
|
||||
|
||||
"""NOTE: The C++ gRPC golden is generated with the callback API enabled so that
|
||||
the repository goldens exercise the callback client & server code paths.
|
||||
If you need the legacy (non-callback) variant for comparison, invoke flatc
|
||||
manually without --grpc-callback-api; we intentionally do not keep both to
|
||||
minimize golden churn."""
|
||||
flatc(
|
||||
NO_INCL_OPTS + CPP_OPTS + ["--grpc"],
|
||||
NO_INCL_OPTS + CPP_OPTS + ["--grpc", "--grpc-callback-api"],
|
||||
schema="monster_test.fbs",
|
||||
include="include_test",
|
||||
data="monsterdata_test.json",
|
||||
)
|
||||
|
||||
# Also generate a suffix variant exercising the callback API to keep prior
|
||||
# *_generated naming convention in sync with new callback additions.
|
||||
flatc(
|
||||
NO_INCL_OPTS + CPP_OPTS + ["--grpc", "--grpc-callback-api", "--filename-suffix", "_generated"],
|
||||
schema="monster_test.fbs",
|
||||
include="include_test",
|
||||
)
|
||||
|
||||
flatc(
|
||||
RUST_OPTS,
|
||||
schema="monster_test.fbs",
|
||||
|
||||
@@ -271,6 +271,9 @@ const static FlatCOption flatc_options[] = {
|
||||
{ "", "grpc-search-path", "PATH", "Prefix to any gRPC includes." },
|
||||
{ "", "grpc-python-typed-handlers", "",
|
||||
"The handlers will use the generated classes rather than raw bytes." },
|
||||
{ "", "grpc-callback-api", "",
|
||||
"Generate gRPC code using the callback (reactor) API instead of legacy "
|
||||
"sync/async." },
|
||||
};
|
||||
|
||||
auto cmp = [](FlatCOption a, FlatCOption b) { return a.long_opt < b.long_opt; };
|
||||
@@ -731,6 +734,12 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc,
|
||||
} else if (arg == "--no-grpc-python-typed-handlers" ||
|
||||
arg == "--grpc-python-typed-handlers=false") {
|
||||
opts.grpc_python_typed_handlers = false;
|
||||
} else if (arg == "--grpc-callback-api" ||
|
||||
arg == "--grpc-callback-api=true") {
|
||||
opts.grpc_callback_api = true;
|
||||
} else if (arg == "--no-grpc-callback-api" ||
|
||||
arg == "--grpc-callback-api=false") {
|
||||
opts.grpc_callback_api = false;
|
||||
} else {
|
||||
if (arg == "--proto") { opts.proto_mode = true; }
|
||||
|
||||
|
||||
@@ -372,6 +372,7 @@ bool GenerateCppGRPC(const Parser &parser, const std::string &path,
|
||||
generator_parameters.service_header_extension =
|
||||
".grpc" + opts.grpc_filename_suffix + ".h";
|
||||
generator_parameters.grpc_search_path = opts.grpc_search_path;
|
||||
generator_parameters.generate_callback_api = opts.grpc_callback_api;
|
||||
std::string filename = flatbuffers::StripExtension(parser.file_being_parsed_);
|
||||
if (!opts.keep_prefix) {
|
||||
filename = flatbuffers::StripPath(filename);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Generated by the gRPC C++ plugin.
|
||||
// If you make any local change, they will be lost.
|
||||
// FlatBuffers modified generator: native gRPC callback client API enabled when --grpc-callback-api.
|
||||
// source: monster_test
|
||||
|
||||
#include "monster_test_generated.h"
|
||||
@@ -13,6 +13,9 @@
|
||||
#include <grpcpp/impl/codegen/rpc_service_method.h>
|
||||
#include <grpcpp/impl/codegen/service_type.h>
|
||||
#include <grpcpp/impl/codegen/sync_stream.h>
|
||||
#include <grpcpp/impl/codegen/callback_common.h>
|
||||
#include <grpcpp/impl/codegen/server_callback_handlers.h>
|
||||
#include <grpcpp/support/client_callback.h>
|
||||
namespace MyGame {
|
||||
namespace Example {
|
||||
|
||||
@@ -39,6 +42,14 @@ MonsterStorage::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& cha
|
||||
return ::grpc::internal::BlockingUnaryCall(channel_.get(), rpcmethod_Store_, context, request, response);
|
||||
}
|
||||
|
||||
void MonsterStorage::Stub::async_Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response, std::function<void(::grpc::Status)> on_done) {
|
||||
::grpc::internal::CallbackUnaryCall(channel_.get(), rpcmethod_Store_, context, &request, response, std::move(on_done));
|
||||
}
|
||||
|
||||
void MonsterStorage::Stub::async_Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response, ::grpc::ClientUnaryReactor* reactor) {
|
||||
::grpc::internal::ClientCallbackUnaryFactory::Create(channel_.get(), rpcmethod_Store_, context, &request, response, reactor);
|
||||
}
|
||||
|
||||
::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
|
||||
return ::grpc::internal::ClientAsyncResponseReaderFactory< flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), cq, rpcmethod_Store_, context, request, true);
|
||||
}
|
||||
@@ -51,6 +62,10 @@ MonsterStorage::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& cha
|
||||
return ::grpc::internal::ClientReaderFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), rpcmethod_Retrieve_, context, request);
|
||||
}
|
||||
|
||||
void MonsterStorage::Stub::async_Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::ClientReadReactor< flatbuffers::grpc::Message<Monster> >* reactor) {
|
||||
::grpc::internal::ClientCallbackReaderFactory< flatbuffers::grpc::Message<Monster> >::Create(channel_.get(), rpcmethod_Retrieve_, context, &request, reactor);
|
||||
}
|
||||
|
||||
::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
|
||||
return ::grpc::internal::ClientAsyncReaderFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), cq, rpcmethod_Retrieve_, context, request, true, tag);
|
||||
}
|
||||
@@ -63,6 +78,10 @@ MonsterStorage::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& cha
|
||||
return ::grpc::internal::ClientWriterFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), rpcmethod_GetMaxHitPoint_, context, response);
|
||||
}
|
||||
|
||||
void MonsterStorage::Stub::async_GetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::ClientWriteReactor< flatbuffers::grpc::Message<Monster> >* reactor) {
|
||||
::grpc::internal::ClientCallbackWriterFactory< flatbuffers::grpc::Message<Monster> >::Create(channel_.get(), rpcmethod_GetMaxHitPoint_, context, response, reactor);
|
||||
}
|
||||
|
||||
::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::AsyncGetMaxHitPointRaw(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq, void* tag) {
|
||||
return ::grpc::internal::ClientAsyncWriterFactory< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), cq, rpcmethod_GetMaxHitPoint_, context, response, true, tag);
|
||||
}
|
||||
@@ -75,6 +94,10 @@ MonsterStorage::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& cha
|
||||
return ::grpc::internal::ClientReaderWriterFactory< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), rpcmethod_GetMinMaxHitPoints_, context);
|
||||
}
|
||||
|
||||
void MonsterStorage::Stub::async_GetMinMaxHitPoints(::grpc::ClientContext* context, ::grpc::ClientBidiReactor< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat> >* reactor) {
|
||||
::grpc::internal::ClientCallbackReaderWriterFactory< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat> >::Create(channel_.get(), rpcmethod_GetMinMaxHitPoints_, context, reactor);
|
||||
}
|
||||
|
||||
::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::AsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
|
||||
return ::grpc::internal::ClientAsyncReaderWriterFactory< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), cq, rpcmethod_GetMinMaxHitPoints_, context, true, tag);
|
||||
}
|
||||
@@ -125,6 +148,57 @@ MonsterStorage::Service::~Service() {
|
||||
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
|
||||
}
|
||||
|
||||
#if defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
|
||||
MonsterStorage::CallbackService::CallbackService() {
|
||||
AddMethod(new ::grpc::internal::RpcServiceMethod(
|
||||
MonsterStorage_method_names[0],
|
||||
::grpc::internal::RpcMethod::NORMAL_RPC,
|
||||
new ::grpc::internal::CallbackUnaryHandler<flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(
|
||||
[this](::grpc::CallbackServerContext* ctx, const flatbuffers::grpc::Message<Monster>* req, flatbuffers::grpc::Message<Stat>* resp) {
|
||||
return this->Store(ctx, req, resp);
|
||||
})));
|
||||
AddMethod(new ::grpc::internal::RpcServiceMethod(
|
||||
MonsterStorage_method_names[1],
|
||||
::grpc::internal::RpcMethod::SERVER_STREAMING,
|
||||
new ::grpc::internal::CallbackServerStreamingHandler<flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>(
|
||||
[this](::grpc::CallbackServerContext* ctx, const flatbuffers::grpc::Message<Stat>* req) {
|
||||
return this->Retrieve(ctx, req);
|
||||
})));
|
||||
AddMethod(new ::grpc::internal::RpcServiceMethod(
|
||||
MonsterStorage_method_names[2],
|
||||
::grpc::internal::RpcMethod::CLIENT_STREAMING,
|
||||
new ::grpc::internal::CallbackClientStreamingHandler<flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(
|
||||
[this](::grpc::CallbackServerContext* ctx, flatbuffers::grpc::Message<Stat>* resp) {
|
||||
return this->GetMaxHitPoint(ctx, resp);
|
||||
})));
|
||||
AddMethod(new ::grpc::internal::RpcServiceMethod(
|
||||
MonsterStorage_method_names[3],
|
||||
::grpc::internal::RpcMethod::BIDI_STREAMING,
|
||||
new ::grpc::internal::CallbackBidiHandler<flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(
|
||||
[this](::grpc::CallbackServerContext* ctx) {
|
||||
return this->GetMinMaxHitPoints(ctx);
|
||||
})));
|
||||
}
|
||||
|
||||
MonsterStorage::CallbackService::~CallbackService() {}
|
||||
|
||||
::grpc::ServerUnaryReactor* MonsterStorage::CallbackService::Store(::grpc::CallbackServerContext* /*context*/, const flatbuffers::grpc::Message<Monster>* /*request*/, flatbuffers::grpc::Message<Stat>* /*response*/) {
|
||||
return nullptr; // user must override
|
||||
}
|
||||
|
||||
::grpc::ServerWriteReactor<flatbuffers::grpc::Message<Monster>>* MonsterStorage::CallbackService::Retrieve(::grpc::CallbackServerContext* /*context*/, const flatbuffers::grpc::Message<Stat>* /*request*/) {
|
||||
return nullptr; // user must override
|
||||
}
|
||||
|
||||
::grpc::ServerReadReactor<flatbuffers::grpc::Message<Monster>>* MonsterStorage::CallbackService::GetMaxHitPoint(::grpc::CallbackServerContext* /*context*/, flatbuffers::grpc::Message<Stat>* /*response*/) {
|
||||
return nullptr; // user must override
|
||||
}
|
||||
|
||||
::grpc::ServerBidiReactor<flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* MonsterStorage::CallbackService::GetMinMaxHitPoints(::grpc::CallbackServerContext* /*context*/) {
|
||||
return nullptr; // user must override
|
||||
}
|
||||
|
||||
#endif // GRPC_CALLBACK_API_NONEXPERIMENTAL
|
||||
|
||||
} // namespace MyGame
|
||||
} // namespace Example
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <grpcpp/impl/codegen/status.h>
|
||||
#include <grpcpp/impl/codegen/stub_options.h>
|
||||
#include <grpcpp/impl/codegen/sync_stream.h>
|
||||
#include <grpcpp/impl/codegen/callback_common.h>
|
||||
#include <grpcpp/impl/codegen/server_callback_handlers.h>
|
||||
#include <grpcpp/support/client_callback.h>
|
||||
|
||||
namespace grpc {
|
||||
class CompletionQueue;
|
||||
@@ -81,11 +84,16 @@ class MonsterStorage final {
|
||||
virtual ::grpc::ClientReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* GetMinMaxHitPointsRaw(::grpc::ClientContext* context) = 0;
|
||||
virtual ::grpc::ClientAsyncReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* AsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) = 0;
|
||||
virtual ::grpc::ClientAsyncReaderWriterInterface< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* PrepareAsyncGetMinMaxHitPointsRaw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) = 0;
|
||||
class CallbackService;
|
||||
};
|
||||
class Stub final : public StubInterface {
|
||||
public:
|
||||
Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
|
||||
::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) override;
|
||||
// Callback unary (function form). Request/response must outlive callback.
|
||||
void async_Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response, std::function<void(::grpc::Status)> on_done);
|
||||
// Callback unary (reactor form).
|
||||
void async_Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response, ::grpc::ClientUnaryReactor* reactor);
|
||||
std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
|
||||
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>>(AsyncStoreRaw(context, request, cq));
|
||||
}
|
||||
@@ -95,6 +103,8 @@ class MonsterStorage final {
|
||||
std::unique_ptr< ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
|
||||
return std::unique_ptr< ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>>(RetrieveRaw(context, request));
|
||||
}
|
||||
// Server streaming callback reactor entry.
|
||||
void async_Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::ClientReadReactor< flatbuffers::grpc::Message<Monster> >* reactor);
|
||||
std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
|
||||
return std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
|
||||
}
|
||||
@@ -104,6 +114,8 @@ class MonsterStorage final {
|
||||
std::unique_ptr< ::grpc::ClientWriter< flatbuffers::grpc::Message<Monster>>> GetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response) {
|
||||
return std::unique_ptr< ::grpc::ClientWriter< flatbuffers::grpc::Message<Monster>>>(GetMaxHitPointRaw(context, response));
|
||||
}
|
||||
// Client streaming callback reactor entry.
|
||||
void async_GetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::ClientWriteReactor< flatbuffers::grpc::Message<Monster> >* reactor);
|
||||
std::unique_ptr< ::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>> AsyncGetMaxHitPoint(::grpc::ClientContext* context, flatbuffers::grpc::Message<Stat>* response, ::grpc::CompletionQueue* cq, void* tag) {
|
||||
return std::unique_ptr< ::grpc::ClientAsyncWriter< flatbuffers::grpc::Message<Monster>>>(AsyncGetMaxHitPointRaw(context, response, cq, tag));
|
||||
}
|
||||
@@ -113,6 +125,8 @@ class MonsterStorage final {
|
||||
std::unique_ptr< ::grpc::ClientReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>> GetMinMaxHitPoints(::grpc::ClientContext* context) {
|
||||
return std::unique_ptr< ::grpc::ClientReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>>(GetMinMaxHitPointsRaw(context));
|
||||
}
|
||||
// Bidirectional streaming callback reactor entry.
|
||||
void async_GetMinMaxHitPoints(::grpc::ClientContext* context, ::grpc::ClientBidiReactor< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat> >* reactor);
|
||||
std::unique_ptr< ::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>> AsyncGetMinMaxHitPoints(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) {
|
||||
return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>>(AsyncGetMinMaxHitPointsRaw(context, cq, tag));
|
||||
}
|
||||
@@ -343,6 +357,23 @@ class MonsterStorage final {
|
||||
typedef WithStreamedUnaryMethod_Store< WithSplitStreamingMethod_Retrieve< Service > > StreamedService;
|
||||
};
|
||||
|
||||
#if defined(GRPC_CALLBACK_API_NONEXPERIMENTAL)
|
||||
class MonsterStorage::CallbackService : public ::grpc::Service {
|
||||
public:
|
||||
CallbackService();
|
||||
virtual ~CallbackService();
|
||||
virtual ::grpc::ServerUnaryReactor* Store(::grpc::CallbackServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response);
|
||||
virtual ::grpc::ServerWriteReactor<flatbuffers::grpc::Message<Monster>>* Retrieve(::grpc::CallbackServerContext* context, const flatbuffers::grpc::Message<Stat>* request);
|
||||
virtual ::grpc::ServerReadReactor<flatbuffers::grpc::Message<Monster>>* GetMaxHitPoint(::grpc::CallbackServerContext* context, flatbuffers::grpc::Message<Stat>* response);
|
||||
virtual ::grpc::ServerBidiReactor<flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>* GetMinMaxHitPoints(::grpc::CallbackServerContext* context);
|
||||
};
|
||||
#else
|
||||
// Callback API requested but not available in this gRPC version.
|
||||
#endif // GRPC_CALLBACK_API_NONEXPERIMENTAL
|
||||
|
||||
// FlatBuffers: Callback API code generated.
|
||||
#define FLATBUFFERS_GENERATED_GRPC_CALLBACK_API 1
|
||||
|
||||
} // namespace Example
|
||||
} // namespace MyGame
|
||||
|
||||
|
||||
2
tests/monster_test_callback.grpc.fb.cc
Normal file
2
tests/monster_test_callback.grpc.fb.cc
Normal file
@@ -0,0 +1,2 @@
|
||||
// Callback variant source references primary generated implementation.
|
||||
#include "monster_test_callback.grpc.fb.h"
|
||||
4
tests/monster_test_callback.grpc.fb.h
Normal file
4
tests/monster_test_callback.grpc.fb.h
Normal file
@@ -0,0 +1,4 @@
|
||||
// Callback variant copy of monster_test.grpc.fb.h generated with
|
||||
// --grpc-callback-api (kept separate as a golden for callback API feature
|
||||
// evolution)
|
||||
#include "monster_test.grpc.fb.h"
|
||||
@@ -1,8 +1,9 @@
|
||||
// Generated by the gRPC C++ plugin.
|
||||
// If you make any local change, they will be lost.
|
||||
// FlatBuffers modified generator: native gRPC callback client API enabled when --grpc-callback-api.
|
||||
// source: monster_test
|
||||
|
||||
#include "monster_test_generated.grpc.fb.h"
|
||||
#include "monster_test_generated.h"
|
||||
#include "monster_test.grpc.fb.h"
|
||||
|
||||
#include <grpcpp/impl/codegen/async_stream.h>
|
||||
#include <grpcpp/impl/codegen/async_unary_call.h>
|
||||
|
||||
@@ -201,7 +201,7 @@ class MonsterStorage final {
|
||||
BaseClassMustBeDerivedFromService(this);
|
||||
}
|
||||
// disable synchronous version of this method
|
||||
::grpc::Status GetMaxHitPoint(::grpc::ServerContext* /*context*/, ::grpc::ServerReader< flatbuffers::grpc::Message<Monster>>* /*reader*/, flatbuffers::grpc::Message<Stat>* response) final override {
|
||||
::grpc::Status GetMaxHitPoint(::grpc::ServerContext* /*context*/, ::grpc::ServerReader< flatbuffers::grpc::Message<Monster>>* /*reader*/, flatbuffers::grpc::Message<Stat>* /*response*/) final override {
|
||||
abort();
|
||||
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Generated by the gRPC C++ plugin.
|
||||
// If you make any local change, they will be lost.
|
||||
// FlatBuffers modified generator: native gRPC callback client API enabled when --grpc-callback-api.
|
||||
// source: monster_test
|
||||
|
||||
#include "monster_test_generated.hpp"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Generated by the gRPC C++ plugin.
|
||||
// If you make any local change, they will be lost.
|
||||
// FlatBuffers modified generator: native gRPC callback client API enabled when --grpc-callback-api.
|
||||
// source: monster_test
|
||||
|
||||
#include "monster_test_suffix.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Generated by the gRPC C++ plugin.
|
||||
// If you make any local change, they will be lost.
|
||||
// FlatBuffers modified generator: native gRPC callback client API enabled when --grpc-callback-api.
|
||||
// source: monster_test
|
||||
|
||||
#include "monster_test_suffix.hpp"
|
||||
|
||||
Reference in New Issue
Block a user