From 63b55e1820bb656bd712f1972568052b5eca2923 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Tue, 9 Jul 2024 20:08:14 +0200 Subject: [PATCH] Revert "Remove some unused fbs files" This reverts commit 891036d89acd8f866c3d6abb7f3d4a1225f41b76. --- third_party/flatbuffers/grpc/BUILD.bazel | 0 third_party/flatbuffers/grpc/README.md | 42 + third_party/flatbuffers/grpc/boringssl.patch | 13 + third_party/flatbuffers/grpc/build_grpc.sh | 24 + .../grpc/build_grpc_with_cxx14.patch | 10 + .../flatbuffers/grpc/examples/README.md | 35 + .../flatbuffers/grpc/examples/go/format.sh | 36 + .../grpc/examples/go/greeter/.gitignore | 2 + .../grpc/examples/go/greeter/README.md | 25 + .../grpc/examples/go/greeter/client/go.mod | 11 + .../grpc/examples/go/greeter/client/main.go | 78 + .../go/greeter/models/Greeter_grpc.go | 158 ++ .../examples/go/greeter/models/HelloReply.go | 60 + .../go/greeter/models/HelloRequest.go | 60 + .../grpc/examples/go/greeter/models/go.mod | 8 + .../grpc/examples/go/greeter/server/go.mod | 11 + .../grpc/examples/go/greeter/server/main.go | 77 + .../flatbuffers/grpc/examples/greeter.fbs | 14 + .../grpc/examples/python/greeter/README.md | 12 + .../grpc/examples/python/greeter/client.py | 40 + .../python/greeter/models/HelloReply.py | 50 + .../python/greeter/models/HelloRequest.py | 50 + .../python/greeter/models/__init__.py | 0 .../python/greeter/models/greeter_grpc_fb.py | 52 + .../grpc/examples/python/greeter/server.py | 57 + .../grpc/examples/swift/Greeter/Package.swift | 58 + .../grpc/examples/swift/Greeter/README.md | 7 + .../Greeter/Sources/Model/greeter.grpc.swift | 145 ++ .../Sources/Model/greeter_generated.swift | 100 + .../swift/Greeter/Sources/client/main.swift | 107 + .../swift/Greeter/Sources/server/main.swift | 96 + .../grpc/examples/ts/greeter/README.md | 13 + .../grpc/examples/ts/greeter/package.json | 14 + .../grpc/examples/ts/greeter/src/client.ts | 34 + .../grpc/examples/ts/greeter/src/greeter.ts | 5 + .../ts/greeter/src/greeter_generated.ts | 4 + .../examples/ts/greeter/src/greeter_grpc.d.ts | 56 + .../examples/ts/greeter/src/greeter_grpc.js | 56 + .../grpc/examples/ts/greeter/src/models.ts | 6 + .../ts/greeter/src/models/hello-reply.ts | 60 + .../ts/greeter/src/models/hello-request.ts | 60 + .../grpc/examples/ts/greeter/src/server.ts | 49 + .../grpc/examples/ts/greeter/tsconfig.json | 17 + .../grpc/flatbuffers-java-grpc/pom.xml | 42 + .../flatbuffers/grpc/FlatbuffersUtils.java | 117 ++ third_party/flatbuffers/grpc/pom.xml | 219 ++ .../flatbuffers/grpc/samples/greeter/Makefile | 14 + .../grpc/samples/greeter/client.cpp | 85 + .../grpc/samples/greeter/greeter.fbs | 17 + .../grpc/samples/greeter/server.cpp | 81 + .../flatbuffers/grpc/src/compiler/BUILD.bazel | 131 ++ .../grpc/src/compiler/cpp_generator.cc | 1766 +++++++++++++++++ .../grpc/src/compiler/cpp_generator.h | 106 + .../grpc/src/compiler/go_generator.cc | 507 +++++ .../grpc/src/compiler/go_generator.h | 33 + .../grpc/src/compiler/java_generator.cc | 1123 +++++++++++ .../grpc/src/compiler/java_generator.h | 85 + .../grpc/src/compiler/python_generator.cc | 151 ++ .../grpc/src/compiler/python_generator.h | 32 + .../grpc/src/compiler/schema_interface.h | 119 ++ .../grpc/src/compiler/swift_generator.cc | 440 ++++ .../grpc/src/compiler/swift_generator.h | 37 + .../grpc/src/compiler/ts_generator.cc | 523 +++++ .../grpc/src/compiler/ts_generator.h | 26 + third_party/flatbuffers/grpc/tests/BUILD | 17 + .../flatbuffers/grpc/tests/GameFactory.java | 42 + .../flatbuffers/grpc/tests/JavaGrpcTest.java | 242 +++ third_party/flatbuffers/grpc/tests/go_test.go | 102 + .../flatbuffers/grpc/tests/grpctest.cpp | 193 ++ .../flatbuffers/grpc/tests/grpctest.py | 174 ++ .../flatbuffers/grpc/tests/java-grpc-test.sh | 4 + .../grpc/tests/message_builder_test.cpp | 368 ++++ third_party/flatbuffers/grpc/tests/pom.xml | 73 + 73 files changed, 8681 insertions(+) create mode 100644 third_party/flatbuffers/grpc/BUILD.bazel create mode 100644 third_party/flatbuffers/grpc/README.md create mode 100644 third_party/flatbuffers/grpc/boringssl.patch create mode 100755 third_party/flatbuffers/grpc/build_grpc.sh create mode 100644 third_party/flatbuffers/grpc/build_grpc_with_cxx14.patch create mode 100644 third_party/flatbuffers/grpc/examples/README.md create mode 100644 third_party/flatbuffers/grpc/examples/go/format.sh create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/.gitignore create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/README.md create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/client/go.mod create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/client/main.go create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/models/Greeter_grpc.go create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/models/HelloReply.go create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/models/HelloRequest.go create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/models/go.mod create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/server/go.mod create mode 100644 third_party/flatbuffers/grpc/examples/go/greeter/server/main.go create mode 100644 third_party/flatbuffers/grpc/examples/greeter.fbs create mode 100644 third_party/flatbuffers/grpc/examples/python/greeter/README.md create mode 100644 third_party/flatbuffers/grpc/examples/python/greeter/client.py create mode 100644 third_party/flatbuffers/grpc/examples/python/greeter/models/HelloReply.py create mode 100644 third_party/flatbuffers/grpc/examples/python/greeter/models/HelloRequest.py create mode 100644 third_party/flatbuffers/grpc/examples/python/greeter/models/__init__.py create mode 100644 third_party/flatbuffers/grpc/examples/python/greeter/models/greeter_grpc_fb.py create mode 100644 third_party/flatbuffers/grpc/examples/python/greeter/server.py create mode 100644 third_party/flatbuffers/grpc/examples/swift/Greeter/Package.swift create mode 100644 third_party/flatbuffers/grpc/examples/swift/Greeter/README.md create mode 100644 third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/Model/greeter.grpc.swift create mode 100644 third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift create mode 100644 third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/client/main.swift create mode 100644 third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/server/main.swift create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/README.md create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/package.json create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/client.ts create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter.ts create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_generated.ts create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_grpc.d.ts create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_grpc.js create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/models.ts create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/models/hello-reply.ts create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/models/hello-request.ts create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/src/server.ts create mode 100644 third_party/flatbuffers/grpc/examples/ts/greeter/tsconfig.json create mode 100644 third_party/flatbuffers/grpc/flatbuffers-java-grpc/pom.xml create mode 100644 third_party/flatbuffers/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java create mode 100644 third_party/flatbuffers/grpc/pom.xml create mode 100644 third_party/flatbuffers/grpc/samples/greeter/Makefile create mode 100644 third_party/flatbuffers/grpc/samples/greeter/client.cpp create mode 100644 third_party/flatbuffers/grpc/samples/greeter/greeter.fbs create mode 100644 third_party/flatbuffers/grpc/samples/greeter/server.cpp create mode 100644 third_party/flatbuffers/grpc/src/compiler/BUILD.bazel create mode 100644 third_party/flatbuffers/grpc/src/compiler/cpp_generator.cc create mode 100644 third_party/flatbuffers/grpc/src/compiler/cpp_generator.h create mode 100644 third_party/flatbuffers/grpc/src/compiler/go_generator.cc create mode 100644 third_party/flatbuffers/grpc/src/compiler/go_generator.h create mode 100644 third_party/flatbuffers/grpc/src/compiler/java_generator.cc create mode 100644 third_party/flatbuffers/grpc/src/compiler/java_generator.h create mode 100644 third_party/flatbuffers/grpc/src/compiler/python_generator.cc create mode 100644 third_party/flatbuffers/grpc/src/compiler/python_generator.h create mode 100644 third_party/flatbuffers/grpc/src/compiler/schema_interface.h create mode 100644 third_party/flatbuffers/grpc/src/compiler/swift_generator.cc create mode 100644 third_party/flatbuffers/grpc/src/compiler/swift_generator.h create mode 100644 third_party/flatbuffers/grpc/src/compiler/ts_generator.cc create mode 100644 third_party/flatbuffers/grpc/src/compiler/ts_generator.h create mode 100644 third_party/flatbuffers/grpc/tests/BUILD create mode 100644 third_party/flatbuffers/grpc/tests/GameFactory.java create mode 100644 third_party/flatbuffers/grpc/tests/JavaGrpcTest.java create mode 100644 third_party/flatbuffers/grpc/tests/go_test.go create mode 100644 third_party/flatbuffers/grpc/tests/grpctest.cpp create mode 100644 third_party/flatbuffers/grpc/tests/grpctest.py create mode 100755 third_party/flatbuffers/grpc/tests/java-grpc-test.sh create mode 100644 third_party/flatbuffers/grpc/tests/message_builder_test.cpp create mode 100644 third_party/flatbuffers/grpc/tests/pom.xml diff --git a/third_party/flatbuffers/grpc/BUILD.bazel b/third_party/flatbuffers/grpc/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/flatbuffers/grpc/README.md b/third_party/flatbuffers/grpc/README.md new file mode 100644 index 000000000..f46258fcb --- /dev/null +++ b/third_party/flatbuffers/grpc/README.md @@ -0,0 +1,42 @@ +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. + +## Building Flatbuffers with gRPC + +### Linux + +1. Download, build and install gRPC. See [instructions](https://github.com/grpc/grpc/tree/master/src/cpp). + * Lets say your gRPC clone is at `/your/path/to/grpc_repo`. + * Install gRPC in a custom directory by running `make install prefix=/your/path/to/grpc_repo/install`. +2. `export GRPC_INSTALL_PATH=/your/path/to/grpc_repo/install` +3. `export PROTOBUF_DOWNLOAD_PATH=/your/path/to/grpc_repo/third_party/protobuf` +4. `mkdir build ; cd build` +5. `cmake -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=${GRPC_INSTALL_PATH} -DPROTOBUF_DOWNLOAD_PATH=${PROTOBUF_DOWNLOAD_PATH} ..` +6. `make` + +For Bazel users: + +```shell +$bazel test src/compiler/... +``` + +## Running FlatBuffer gRPC tests + +### Linux + +1. `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GRPC_INSTALL_PATH}/lib` +2. `make test ARGS=-V` + +For Bazel users: + +```shell +$bazel test tests/... +``` \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/boringssl.patch b/third_party/flatbuffers/grpc/boringssl.patch new file mode 100644 index 000000000..632499e28 --- /dev/null +++ b/third_party/flatbuffers/grpc/boringssl.patch @@ -0,0 +1,13 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 1645a264a..12f8ca999 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -635,6 +635,8 @@ add_library( + src/ssl/tls_record.cc + ) + ++target_link_libraries(ssl crypto) ++ + add_executable( + bssl + diff --git a/third_party/flatbuffers/grpc/build_grpc.sh b/third_party/flatbuffers/grpc/build_grpc.sh new file mode 100755 index 000000000..49c5a60f0 --- /dev/null +++ b/third_party/flatbuffers/grpc/build_grpc.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +grpc_1_39_0_githash=58602e20a3f3e48f24a4114c757099b25b947f7b + +function build_grpc () { + git clone https://github.com/grpc/grpc.git google/grpc + cd google/grpc + git checkout ${grpc_1_39_0_githash} + git submodule update --init + # Apply boringssl build patch + cd third_party/boringssl-with-bazel + git apply ../../../../grpc/boringssl.patch + cd ../.. + mkdir ../grpc_build + cd ../grpc_build + cmake ../grpc -DgRPC_INSTALL=ON -DgRPC_BUILD_TESTS=OFF -DABSL_ENABLE_INSTALL=ON -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=`pwd`/../grpc/install + cmake --build . --target install ${JOBS:+-j$JOBS} + cd ../.. +} + +GRPC_INSTALL_PATH=`pwd`/google/grpc/install +PROTOBUF_DOWNLOAD_PATH=`pwd`/google/grpc/third_party/protobuf + +build_grpc diff --git a/third_party/flatbuffers/grpc/build_grpc_with_cxx14.patch b/third_party/flatbuffers/grpc/build_grpc_with_cxx14.patch new file mode 100644 index 000000000..38cdfe993 --- /dev/null +++ b/third_party/flatbuffers/grpc/build_grpc_with_cxx14.patch @@ -0,0 +1,10 @@ +diff --git a/bazel/copts.bzl b/bazel/copts.bzl +index 10be944f25..879518b92f 100644 +--- a/bazel/copts.bzl ++++ b/bazel/copts.bzl +@@ -59,4 +59,4 @@ GRPC_LLVM_WARNING_FLAGS = [ + GRPC_DEFAULT_COPTS = select({ + "//:use_strict_warning": GRPC_LLVM_WARNING_FLAGS + ["-DUSE_STRICT_WARNING=1"], + "//conditions:default": [], +-}) ++}) + ["-std=c++14"] diff --git a/third_party/flatbuffers/grpc/examples/README.md b/third_party/flatbuffers/grpc/examples/README.md new file mode 100644 index 000000000..c821218b3 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/README.md @@ -0,0 +1,35 @@ +## Languages known issues + +### Python + +- Assert the type required in your server/client since python is able to receive `Bytes array` or `utf8 strings`. + +```python +def SayHello(self, request, context): + # request might be a byte array or a utf8 string + + r = HelloRequest.HelloRequest().GetRootAs(request, 0) + reply = "Unknown" + if r.Name(): + reply = r.Name() + # Issues might happen if type checking isnt present. + # thus encoding it as a `reply.decode('UTF-8')` + return build_reply("welcome " + reply.decode('UTF-8')) + +``` + +This can be prevented by making sure all the requests coming to/from python are `Bytes array` + +```python +def say_hello(stub, builder): + hello_request = bytes(builder.Output()) + reply = stub.SayHello(hello_request) + r = HelloReply.HelloReply.GetRootAs(reply) + print(r.Message()) +``` + +### Go + +- Always requires the `content-type` of the payload to be set to `application/grpc+flatbuffers` + +example: `.SayHello(ctx, b, grpc.CallContentSubtype("flatbuffers"))` \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/go/format.sh b/third_party/flatbuffers/grpc/examples/go/format.sh new file mode 100644 index 000000000..a7ee9e315 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/format.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# +# Copyright 2021 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. + +set -e + + +format_greeter() { + cd greeter + + # Format client + cd client + gofmt -w . + cd .. + + # Format server + cd server + gofmt -w . + cd .. + + cd .. +} + +format_greeter \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/.gitignore b/third_party/flatbuffers/grpc/examples/go/greeter/.gitignore new file mode 100644 index 000000000..535db5e31 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/.gitignore @@ -0,0 +1,2 @@ +**/server +**/client \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/README.md b/third_party/flatbuffers/grpc/examples/go/greeter/README.md new file mode 100644 index 000000000..339050885 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/README.md @@ -0,0 +1,25 @@ +# Go Greeter example + +## Project Structure + + . + ├── server # Server module + ├── client # Client module + ├── models # Flatbuffers models & main grpc code. + └── README.md + +## How to run Server: + +- `cd server` + +- `go clean` + +- `go run main.go` + +## How to run Client: + +- `cd client` + +- `go clean` + +- `go run main.go --name NAME` \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/client/go.mod b/third_party/flatbuffers/grpc/examples/go/greeter/client/go.mod new file mode 100644 index 000000000..d0f219855 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/client/go.mod @@ -0,0 +1,11 @@ +module github.com/google/flatbuffers/grpc/examples/go/greeter/client + +go 1.15 + +replace github.com/google/flatbuffers/grpc/examples/go/greeter/models v0.0.0 => ../models + +require ( + github.com/google/flatbuffers v2.0.8+incompatible + github.com/google/flatbuffers/grpc/examples/go/greeter/models v0.0.0 + google.golang.org/grpc v1.56.3 +) diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/client/main.go b/third_party/flatbuffers/grpc/examples/go/greeter/client/main.go new file mode 100644 index 000000000..a7649126b --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/client/main.go @@ -0,0 +1,78 @@ +package main + +import ( + "context" + "flag" + "fmt" + "io" + "log" + "time" + + flatbuffers "github.com/google/flatbuffers/go" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + + models "github.com/google/flatbuffers/grpc/examples/go/greeter/models" +) + +var ( + addr = "3000" + name = flag.String("name", "Flatbuffers", "name to be sent to server :D") +) + +func printSayHello(client models.GreeterClient, name string) { + log.Printf("Name to be sent (%s)", name) + b := flatbuffers.NewBuilder(0) + i := b.CreateString(name) + models.HelloRequestStart(b) + models.HelloRequestAddName(b, i) + b.Finish(models.HelloRequestEnd(b)) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + request, err := client.SayHello(ctx, b, grpc.CallContentSubtype("flatbuffers")) + if err != nil { + log.Fatalf("%v.SayHello(_) = _, %v: ", client, err) + } + log.Printf("server said %q", request.Message()) +} + +func printSayManyHello(client models.GreeterClient, name string) { + log.Printf("Name to be sent (%s)", name) + b := flatbuffers.NewBuilder(0) + i := b.CreateString(name) + models.HelloRequestStart(b) + models.HelloRequestAddName(b, i) + b.Finish(models.HelloRequestEnd(b)) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + stream, err := client.SayManyHellos(ctx, b, grpc.CallContentSubtype("flatbuffers")) + if err != nil { + log.Fatalf("%v.SayManyHellos(_) = _, %v", client, err) + } + for { + request, err := stream.Recv() + if err == io.EOF { + break + } + if err != nil { + log.Fatalf("%v.SayManyHellos(_) = _, %v", client, err) + } + log.Printf("server said %q", request.Message()) + } +} + +func main() { + flag.Parse() + conn, err := grpc.Dial(fmt.Sprintf("localhost:%d", 3000), + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultCallOptions(grpc.ForceCodec(flatbuffers.FlatbuffersCodec{}))) + if err != nil { + log.Fatalf("fail to dial: %v", err) + } + defer conn.Close() + client := models.NewGreeterClient(conn) + printSayHello(client, *name) + printSayManyHello(client, *name) +} diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/models/Greeter_grpc.go b/third_party/flatbuffers/grpc/examples/go/greeter/models/Greeter_grpc.go new file mode 100644 index 000000000..9a2405c76 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/models/Greeter_grpc.go @@ -0,0 +1,158 @@ +//Generated by gRPC Go plugin +//If you make any local changes, they will be lost +//source: greeter + +package models + +import ( + context "context" + flatbuffers "github.com/google/flatbuffers/go" + grpc "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// Client API for Greeter service +type GreeterClient interface { + SayHello(ctx context.Context, in *flatbuffers.Builder, + opts ...grpc.CallOption) (*HelloReply, error) + SayManyHellos(ctx context.Context, in *flatbuffers.Builder, + opts ...grpc.CallOption) (Greeter_SayManyHellosClient, error) +} + +type greeterClient struct { + cc grpc.ClientConnInterface +} + +func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient { + return &greeterClient{cc} +} + +func (c *greeterClient) SayHello(ctx context.Context, in *flatbuffers.Builder, + opts ...grpc.CallOption) (*HelloReply, error) { + out := new(HelloReply) + err := c.cc.Invoke(ctx, "/models.Greeter/SayHello", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *greeterClient) SayManyHellos(ctx context.Context, in *flatbuffers.Builder, + opts ...grpc.CallOption) (Greeter_SayManyHellosClient, error) { + stream, err := c.cc.NewStream(ctx, &_Greeter_serviceDesc.Streams[0], "/models.Greeter/SayManyHellos", opts...) + if err != nil { + return nil, err + } + x := &greeterSayManyHellosClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Greeter_SayManyHellosClient interface { + Recv() (*HelloReply, error) + grpc.ClientStream +} + +type greeterSayManyHellosClient struct { + grpc.ClientStream +} + +func (x *greeterSayManyHellosClient) Recv() (*HelloReply, error) { + m := new(HelloReply) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// Server API for Greeter service +type GreeterServer interface { + SayHello(context.Context, *HelloRequest) (*flatbuffers.Builder, error) + SayManyHellos(*HelloRequest, Greeter_SayManyHellosServer) error + mustEmbedUnimplementedGreeterServer() +} + +type UnimplementedGreeterServer struct { +} + +func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*flatbuffers.Builder, error) { + return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented") +} + +func (UnimplementedGreeterServer) SayManyHellos(*HelloRequest, Greeter_SayManyHellosServer) error { + return status.Errorf(codes.Unimplemented, "method SayManyHellos not implemented") +} + +func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {} + +type UnsafeGreeterServer interface { + mustEmbedUnimplementedGreeterServer() +} + +func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) { + s.RegisterService(&_Greeter_serviceDesc, srv) +} + +func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, + dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(HelloRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(GreeterServer).SayHello(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/models.Greeter/SayHello", + } + + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest)) + } + return interceptor(ctx, in, info, handler) +} +func _Greeter_SayManyHellos_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(HelloRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(GreeterServer).SayManyHellos(m, &greeterSayManyHellosServer{stream}) +} + +type Greeter_SayManyHellosServer interface { + Send(*flatbuffers.Builder) error + grpc.ServerStream +} + +type greeterSayManyHellosServer struct { + grpc.ServerStream +} + +func (x *greeterSayManyHellosServer) Send(m *flatbuffers.Builder) error { + return x.ServerStream.SendMsg(m) +} + +var _Greeter_serviceDesc = grpc.ServiceDesc{ + ServiceName: "models.Greeter", + HandlerType: (*GreeterServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SayHello", + Handler: _Greeter_SayHello_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "SayManyHellos", + Handler: _Greeter_SayManyHellos_Handler, + ServerStreams: true, + }, + }, +} diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/models/HelloReply.go b/third_party/flatbuffers/grpc/examples/go/greeter/models/HelloReply.go new file mode 100644 index 000000000..747db2d87 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/models/HelloReply.go @@ -0,0 +1,60 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package models + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type HelloReply struct { + _tab flatbuffers.Table +} + +func GetRootAsHelloReply(buf []byte, offset flatbuffers.UOffsetT) *HelloReply { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &HelloReply{} + x.Init(buf, n+offset) + return x +} + +func FinishHelloReplyBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsHelloReply(buf []byte, offset flatbuffers.UOffsetT) *HelloReply { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &HelloReply{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedHelloReplyBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *HelloReply) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *HelloReply) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *HelloReply) Message() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func HelloReplyStart(builder *flatbuffers.Builder) { + builder.StartObject(1) +} +func HelloReplyAddMessage(builder *flatbuffers.Builder, message flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(message), 0) +} +func HelloReplyEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/models/HelloRequest.go b/third_party/flatbuffers/grpc/examples/go/greeter/models/HelloRequest.go new file mode 100644 index 000000000..3710cf5aa --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/models/HelloRequest.go @@ -0,0 +1,60 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package models + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type HelloRequest struct { + _tab flatbuffers.Table +} + +func GetRootAsHelloRequest(buf []byte, offset flatbuffers.UOffsetT) *HelloRequest { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &HelloRequest{} + x.Init(buf, n+offset) + return x +} + +func FinishHelloRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsHelloRequest(buf []byte, offset flatbuffers.UOffsetT) *HelloRequest { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &HelloRequest{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedHelloRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *HelloRequest) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *HelloRequest) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *HelloRequest) Name() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func HelloRequestStart(builder *flatbuffers.Builder) { + builder.StartObject(1) +} +func HelloRequestAddName(builder *flatbuffers.Builder, name flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(name), 0) +} +func HelloRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/models/go.mod b/third_party/flatbuffers/grpc/examples/go/greeter/models/go.mod new file mode 100644 index 000000000..31d6cdcb5 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/models/go.mod @@ -0,0 +1,8 @@ +module github.com/google/flatbuffers/grpc/examples/go/greeter/models + +go 1.15 + +require ( + github.com/google/flatbuffers v2.0.8+incompatible + google.golang.org/grpc v1.56.3 +) diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/server/go.mod b/third_party/flatbuffers/grpc/examples/go/greeter/server/go.mod new file mode 100644 index 000000000..eeb9e538a --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/server/go.mod @@ -0,0 +1,11 @@ +module github.com/google/flatbuffers/grpc/examples/go/greeter/server + +go 1.15 + +replace github.com/google/flatbuffers/grpc/examples/go/greeter/models v0.0.0 => ../models + +require ( + github.com/google/flatbuffers v2.0.8+incompatible + github.com/google/flatbuffers/grpc/examples/go/greeter/models v0.0.0 + google.golang.org/grpc v1.56.3 +) diff --git a/third_party/flatbuffers/grpc/examples/go/greeter/server/main.go b/third_party/flatbuffers/grpc/examples/go/greeter/server/main.go new file mode 100644 index 000000000..a5bb3a448 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/go/greeter/server/main.go @@ -0,0 +1,77 @@ +package main + +import ( + "context" + "fmt" + "log" + "net" + + flatbuffers "github.com/google/flatbuffers/go" + models "github.com/google/flatbuffers/grpc/examples/go/greeter/models" + "google.golang.org/grpc" +) + +var ( + greetings = [...]string{"Hi", "Hallo", "Ciao"} +) + +type greeterServer struct { + models.UnimplementedGreeterServer +} + +func (s *greeterServer) SayHello(ctx context.Context, request *models.HelloRequest) (*flatbuffers.Builder, error) { + v := request.Name() + var m string + if v == nil { + m = "Unknown" + } else { + m = string(v) + } + b := flatbuffers.NewBuilder(0) + idx := b.CreateString("welcome " + m) + models.HelloReplyStart(b) + models.HelloReplyAddMessage(b, idx) + b.Finish(models.HelloReplyEnd(b)) + return b, nil +} + +func (s *greeterServer) SayManyHellos(request *models.HelloRequest, stream models.Greeter_SayManyHellosServer) error { + v := request.Name() + var m string + if v == nil { + m = "Unknown" + } else { + m = string(v) + } + b := flatbuffers.NewBuilder(0) + + for _, greeting := range greetings { + idx := b.CreateString(greeting + " " + m) + models.HelloReplyStart(b) + models.HelloReplyAddMessage(b, idx) + b.Finish(models.HelloReplyEnd(b)) + if err := stream.Send(b); err != nil { + return err + } + } + return nil +} + +func newServer() *greeterServer { + s := &greeterServer{} + return s +} + +func main() { + lis, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", 3000)) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + codec := &flatbuffers.FlatbuffersCodec{} + grpcServer := grpc.NewServer(grpc.ForceServerCodec(codec)) + models.RegisterGreeterServer(grpcServer, newServer()) + if err := grpcServer.Serve(lis); err != nil { + fmt.Print(err) + panic(err) + } +} diff --git a/third_party/flatbuffers/grpc/examples/greeter.fbs b/third_party/flatbuffers/grpc/examples/greeter.fbs new file mode 100644 index 000000000..651fb6773 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/greeter.fbs @@ -0,0 +1,14 @@ +namespace models; + +table HelloReply { + message:string; +} + +table HelloRequest { + name:string; +} + +rpc_service Greeter { + SayHello(HelloRequest):HelloReply; + SayManyHellos(HelloRequest):HelloReply (streaming: "server"); +} diff --git a/third_party/flatbuffers/grpc/examples/python/greeter/README.md b/third_party/flatbuffers/grpc/examples/python/greeter/README.md new file mode 100644 index 000000000..fcf310c0d --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/python/greeter/README.md @@ -0,0 +1,12 @@ +# Python Greeter example + +## Prerequisite + +- You need to have grpc python installed on your device `pip install grpcio` +## How to run Server: + +- `python server.py ${PORT}` + +## How to run Client: + +- `python client.py ${PORT} ${NAME}` \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/python/greeter/client.py b/third_party/flatbuffers/grpc/examples/python/greeter/client.py new file mode 100644 index 000000000..d2d718452 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/python/greeter/client.py @@ -0,0 +1,40 @@ +import sys +import argparse +import grpc + +sys.path.insert(0, '../../../../../flatbuffers/python') + +import flatbuffers +from models import HelloReply, HelloRequest, greeter_grpc_fb + +parser = argparse.ArgumentParser() +parser.add_argument("port", help="server port to connect to", default=3000) +parser.add_argument("name", help="name to be sent to server", default="flatbuffers") + +def say_hello(stub, hello_request): + reply = stub.SayHello(hello_request) + r = HelloReply.HelloReply.GetRootAs(reply) + print(r.Message()) + +def say_many_hellos(stub, hello_request): + greetings = stub.SayManyHellos(hello_request) + for greeting in greetings: + r = HelloReply.HelloReply.GetRootAs(greeting) + print(r.Message()) + +def main(): + args = parser.parse_args() + + with grpc.insecure_channel('localhost:' + args.port) as channel: + builder = flatbuffers.Builder() + ind = builder.CreateString(args.name) + HelloRequest.HelloRequestStart(builder) + HelloRequest.HelloRequestAddName(builder, ind) + root = HelloRequest.HelloRequestEnd(builder) + builder.Finish(root) + output = bytes(builder.Output()) + stub = greeter_grpc_fb.GreeterStub(channel) + say_hello(stub, output) + say_many_hellos(stub, output) + +main() \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/python/greeter/models/HelloReply.py b/third_party/flatbuffers/grpc/examples/python/greeter/models/HelloReply.py new file mode 100644 index 000000000..b1adc8c31 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/python/greeter/models/HelloReply.py @@ -0,0 +1,50 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: models + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class HelloReply(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAs(cls, buf, offset=0): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = HelloReply() + x.Init(buf, n + offset) + return x + + @classmethod + def GetRootAsHelloReply(cls, buf, offset=0): + """This method is deprecated. Please switch to GetRootAs.""" + return cls.GetRootAs(buf, offset) + # HelloReply + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # HelloReply + def Message(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + +def HelloReplyStart(builder): + builder.StartObject(1) + +def Start(builder): + HelloReplyStart(builder) + +def HelloReplyAddMessage(builder, message): + builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(message), 0) + +def AddMessage(builder, message): + HelloReplyAddMessage(builder, message) + +def HelloReplyEnd(builder): + return builder.EndObject() + +def End(builder): + return HelloReplyEnd(builder) diff --git a/third_party/flatbuffers/grpc/examples/python/greeter/models/HelloRequest.py b/third_party/flatbuffers/grpc/examples/python/greeter/models/HelloRequest.py new file mode 100644 index 000000000..db217dd21 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/python/greeter/models/HelloRequest.py @@ -0,0 +1,50 @@ +# automatically generated by the FlatBuffers compiler, do not modify + +# namespace: models + +import flatbuffers +from flatbuffers.compat import import_numpy +np = import_numpy() + +class HelloRequest(object): + __slots__ = ['_tab'] + + @classmethod + def GetRootAs(cls, buf, offset=0): + n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset) + x = HelloRequest() + x.Init(buf, n + offset) + return x + + @classmethod + def GetRootAsHelloRequest(cls, buf, offset=0): + """This method is deprecated. Please switch to GetRootAs.""" + return cls.GetRootAs(buf, offset) + # HelloRequest + def Init(self, buf, pos): + self._tab = flatbuffers.table.Table(buf, pos) + + # HelloRequest + def Name(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4)) + if o != 0: + return self._tab.String(o + self._tab.Pos) + return None + +def HelloRequestStart(builder): + builder.StartObject(1) + +def Start(builder): + HelloRequestStart(builder) + +def HelloRequestAddName(builder, name): + builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(name), 0) + +def AddName(builder, name): + HelloRequestAddName(builder, name) + +def HelloRequestEnd(builder): + return builder.EndObject() + +def End(builder): + return HelloRequestEnd(builder) diff --git a/third_party/flatbuffers/grpc/examples/python/greeter/models/__init__.py b/third_party/flatbuffers/grpc/examples/python/greeter/models/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/third_party/flatbuffers/grpc/examples/python/greeter/models/greeter_grpc_fb.py b/third_party/flatbuffers/grpc/examples/python/greeter/models/greeter_grpc_fb.py new file mode 100644 index 000000000..b9f8a4ed2 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/python/greeter/models/greeter_grpc_fb.py @@ -0,0 +1,52 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! + +import grpc + +class GreeterStub(object): + """ Interface exported by the server. """ + + def __init__(self, channel): + """ Constructor. + + Args: + channel: A grpc.Channel. + """ + + self.SayHello = channel.unary_unary( + "/models.Greeter/SayHello" + ) + + self.SayManyHellos = channel.unary_stream( + "/models.Greeter/SayManyHellos" + ) + + +class GreeterServicer(object): + """ Interface exported by the server. """ + + def SayHello(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + + def SayManyHellos(self, request, context): + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + + +def add_GreeterServicer_to_server(servicer, server): + rpc_method_handlers = { + 'SayHello': grpc.unary_unary_rpc_method_handler( + servicer.SayHello + ), + 'SayManyHellos': grpc.unary_stream_rpc_method_handler( + servicer.SayManyHellos + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'models.Greeter', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + diff --git a/third_party/flatbuffers/grpc/examples/python/greeter/server.py b/third_party/flatbuffers/grpc/examples/python/greeter/server.py new file mode 100644 index 000000000..acca880b5 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/python/greeter/server.py @@ -0,0 +1,57 @@ +from concurrent import futures +import sys +import argparse +import grpc + +sys.path.insert(0, '../../../../../flatbuffers/python') + +import flatbuffers +from models import HelloReply, HelloRequest, greeter_grpc_fb + +parser = argparse.ArgumentParser() +parser.add_argument("port", help="server on port", default=3000) + +def build_reply(message): + builder = flatbuffers.Builder() + ind = builder.CreateString(message) + HelloReply.HelloReplyStart(builder) + HelloReply.HelloReplyAddMessage(builder, ind) + root = HelloReply.HelloReplyEnd(builder) + builder.Finish(root) + return bytes(builder.Output()) + +class GreeterServicer(greeter_grpc_fb.GreeterServicer): + + def __init__(self): + self.greetings = ["Hi", "Hallo", "Ciao"] + + def SayHello(self, request, context): + r = HelloRequest.HelloRequest().GetRootAs(request, 0) + reply = "Unknown" + if r.Name(): + reply = r.Name() + return build_reply("welcome " + reply.decode('UTF-8')) + + def SayManyHellos(self, request, context): + r = HelloRequest.HelloRequest().GetRootAs(request, 0) + reply = "Unknown" + if r.Name(): + reply = r.Name() + + for greeting in self.greetings: + print(type(reply)) + yield build_reply(greeting + " " + reply.decode('UTF-8')) + + +def serve(): + args = parser.parse_args() + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + greeter_grpc_fb.add_GreeterServicer_to_server( + GreeterServicer(), server + ) + server.add_insecure_port('[::]:' + args.port) + server.start() + server.wait_for_termination() + +if __name__ == '__main__': + serve() \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/swift/Greeter/Package.swift b/third_party/flatbuffers/grpc/examples/swift/Greeter/Package.swift new file mode 100644 index 000000000..5e6fb68cd --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/swift/Greeter/Package.swift @@ -0,0 +1,58 @@ +// swift-tools-version:5.1 +/* + * Copyright 2020 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. + */ + +import PackageDescription + +let package = Package( + name: "Greeter", + platforms: [ + .iOS(.v11), + .macOS(.v10_14), + ], + dependencies: [ + .package(path: "../../../../swift"), + .package(url: "https://github.com/grpc/grpc-swift.git", from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "Model", + dependencies: [ + "GRPC", + "FlatBuffers", + ], + path: "Sources/Model"), + + // Client for the Greeter example + .target( + name: "Client", + dependencies: [ + "GRPC", + "Model", + ], + path: "Sources/client"), + + // Server for the Greeter example + .target( + name: "Server", + dependencies: [ + "GRPC", + "Model", + ], + path: "Sources/server"), + ]) diff --git a/third_party/flatbuffers/grpc/examples/swift/Greeter/README.md b/third_party/flatbuffers/grpc/examples/swift/Greeter/README.md new file mode 100644 index 000000000..1632b783a --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/swift/Greeter/README.md @@ -0,0 +1,7 @@ +# FlatBuffers.GRPC.Swift + +The following is Swift example on how GRPC would be with Swift Flatbuffers, you can simply run the following commands: + +`swift run Server` + +`swift run Client {port} {name}` diff --git a/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/Model/greeter.grpc.swift b/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/Model/greeter.grpc.swift new file mode 100644 index 000000000..0f29f1958 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/Model/greeter.grpc.swift @@ -0,0 +1,145 @@ +// Generated GRPC code for FlatBuffers swift! +/// The following code is generated by the Flatbuffers library which might not be in sync with grpc-swift +/// in case of an issue please open github issue, though it would be maintained + +// swiftlint:disable all +// swiftformat:disable all + +import Foundation +import GRPC +import NIO +import NIOHTTP1 +import FlatBuffers + +public protocol GRPCFlatBufPayload: GRPCPayload, FlatBufferGRPCMessage {} +public extension GRPCFlatBufPayload { + init(serializedByteBuffer: inout NIO.ByteBuffer) throws { + self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: serializedByteBuffer.readableBytesView, count: serializedByteBuffer.readableBytes)) + } + func serialize(into buffer: inout NIO.ByteBuffer) throws { + let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: Int(self.size)) + buffer.writeBytes(buf) + } +} +extension Message: GRPCFlatBufPayload {} + +/// Usage: instantiate models_GreeterServiceClient, then call methods of this protocol to make API calls. +public protocol models_GreeterClientProtocol: GRPCClient { + + var serviceName: String { get } + + var interceptors: models_GreeterClientInterceptorFactoryProtocol? { get } + + func SayHello( + _ request: Message + , callOptions: CallOptions? + ) -> UnaryCall, Message> + + func SayManyHellos( + _ request: Message + , callOptions: CallOptions?, + handler: @escaping (Message) -> Void + ) -> ServerStreamingCall, Message> + +} + +extension models_GreeterClientProtocol { + + public var serviceName: String { "models.Greeter" } + + public func SayHello( + _ request: Message + , callOptions: CallOptions? = nil + ) -> UnaryCall, Message> { + return self.makeUnaryCall( + path: "/models.Greeter/SayHello", + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeSayHelloInterceptors() ?? [] + ) + } + + public func SayManyHellos( + _ request: Message + , callOptions: CallOptions? = nil, + handler: @escaping (Message) -> Void + ) -> ServerStreamingCall, Message> { + return self.makeServerStreamingCall( + path: "/models.Greeter/SayManyHellos", + request: request, + callOptions: callOptions ?? self.defaultCallOptions, + interceptors: self.interceptors?.makeSayManyHellosInterceptors() ?? [], + handler: handler + ) + } +} + +public protocol models_GreeterClientInterceptorFactoryProtocol { + /// - Returns: Interceptors to use when invoking 'SayHello'. + func makeSayHelloInterceptors() -> [ClientInterceptor, Message>] + + /// - Returns: Interceptors to use when invoking 'SayManyHellos'. + func makeSayManyHellosInterceptors() -> [ClientInterceptor, Message>] + +} + +public final class models_GreeterServiceClient: models_GreeterClientProtocol { + public let channel: GRPCChannel + public var defaultCallOptions: CallOptions + public var interceptors: models_GreeterClientInterceptorFactoryProtocol? + + public init( + channel: GRPCChannel, + defaultCallOptions: CallOptions = CallOptions(), + interceptors: models_GreeterClientInterceptorFactoryProtocol? = nil + ) { + self.channel = channel + self.defaultCallOptions = defaultCallOptions + self.interceptors = interceptors + } +} + +public protocol models_GreeterProvider: CallHandlerProvider { + var interceptors: models_GreeterServerInterceptorFactoryProtocol? { get } + func SayHello(request: Message, context: StatusOnlyCallContext) -> EventLoopFuture> + func SayManyHellos(request: Message, context: StreamingResponseCallContext>) -> EventLoopFuture +} + +public extension models_GreeterProvider { + + var serviceName: Substring { return "models.Greeter" } + + func handle(method name: Substring, context: CallHandlerContext) -> GRPCServerHandlerProtocol? { + switch name { + case "SayHello": + return UnaryServerHandler( + context: context, + requestDeserializer: GRPCPayloadDeserializer>(), + responseSerializer: GRPCPayloadSerializer>(), + interceptors: self.interceptors?.makeSayHelloInterceptors() ?? [], + userFunction: self.SayHello(request:context:)) + + case "SayManyHellos": + return ServerStreamingServerHandler( + context: context, + requestDeserializer: GRPCPayloadDeserializer>(), + responseSerializer: GRPCPayloadSerializer>(), + interceptors: self.interceptors?.makeSayManyHellosInterceptors() ?? [], + userFunction: self.SayManyHellos(request:context:)) + + default: return nil; + } + } + +} + +public protocol models_GreeterServerInterceptorFactoryProtocol { + /// - Returns: Interceptors to use when handling 'SayHello'. + /// Defaults to calling `self.makeInterceptors()`. + func makeSayHelloInterceptors() -> [ServerInterceptor, Message>] + + /// - Returns: Interceptors to use when handling 'SayManyHellos'. + /// Defaults to calling `self.makeInterceptors()`. + func makeSayManyHellosInterceptors() -> [ServerInterceptor, Message>] + +} diff --git a/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift b/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift new file mode 100644 index 000000000..81ffe48f8 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/Model/greeter_generated.swift @@ -0,0 +1,100 @@ +// automatically generated by the FlatBuffers compiler, do not modify +// swiftlint:disable all +// swiftformat:disable all + +import FlatBuffers + +public struct models_HelloReply: FlatBufferObject, Verifiable { + + static func validateVersion() { FlatBuffersVersion_24_3_25() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Table + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + private enum VTOFFSET: VOffset { + case message = 4 + var v: Int32 { Int32(self.rawValue) } + var p: VOffset { self.rawValue } + } + + public var message: String? { let o = _accessor.offset(VTOFFSET.message.v); return o == 0 ? nil : _accessor.string(at: o) } + public var messageSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.message.v) } + public static func startHelloReply(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) } + public static func add(message: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: message, at: VTOFFSET.message.p) } + public static func endHelloReply(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } + public static func createHelloReply( + _ fbb: inout FlatBufferBuilder, + messageOffset message: Offset = Offset() + ) -> Offset { + let __start = models_HelloReply.startHelloReply(&fbb) + models_HelloReply.add(message: message, &fbb) + return models_HelloReply.endHelloReply(&fbb, start: __start) + } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.message.p, fieldName: "message", required: false, type: ForwardOffset.self) + _v.finish() + } +} + +extension models_HelloReply: Encodable { + + enum CodingKeys: String, CodingKey { + case message = "message" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(message, forKey: .message) + } +} + +public struct models_HelloRequest: FlatBufferObject, Verifiable { + + static func validateVersion() { FlatBuffersVersion_24_3_25() } + public var __buffer: ByteBuffer! { return _accessor.bb } + private var _accessor: Table + + private init(_ t: Table) { _accessor = t } + public init(_ bb: ByteBuffer, o: Int32) { _accessor = Table(bb: bb, position: o) } + + private enum VTOFFSET: VOffset { + case name = 4 + var v: Int32 { Int32(self.rawValue) } + var p: VOffset { self.rawValue } + } + + public var name: String? { let o = _accessor.offset(VTOFFSET.name.v); return o == 0 ? nil : _accessor.string(at: o) } + public var nameSegmentArray: [UInt8]? { return _accessor.getVector(at: VTOFFSET.name.v) } + public static func startHelloRequest(_ fbb: inout FlatBufferBuilder) -> UOffset { fbb.startTable(with: 1) } + public static func add(name: Offset, _ fbb: inout FlatBufferBuilder) { fbb.add(offset: name, at: VTOFFSET.name.p) } + public static func endHelloRequest(_ fbb: inout FlatBufferBuilder, start: UOffset) -> Offset { let end = Offset(offset: fbb.endTable(at: start)); return end } + public static func createHelloRequest( + _ fbb: inout FlatBufferBuilder, + nameOffset name: Offset = Offset() + ) -> Offset { + let __start = models_HelloRequest.startHelloRequest(&fbb) + models_HelloRequest.add(name: name, &fbb) + return models_HelloRequest.endHelloRequest(&fbb, start: __start) + } + + public static func verify(_ verifier: inout Verifier, at position: Int, of type: T.Type) throws where T: Verifiable { + var _v = try verifier.visitTable(at: position) + try _v.visit(field: VTOFFSET.name.p, fieldName: "name", required: false, type: ForwardOffset.self) + _v.finish() + } +} + +extension models_HelloRequest: Encodable { + + enum CodingKeys: String, CodingKey { + case name = "name" + } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(name, forKey: .name) + } +} + diff --git a/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/client/main.swift b/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/client/main.swift new file mode 100644 index 000000000..a4b2a675c --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/client/main.swift @@ -0,0 +1,107 @@ +/* + * Copyright 2023 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. + */ + +import FlatBuffers +import GRPC +import Logging +import Model +import NIO + +// Quieten the logs. +LoggingSystem.bootstrap { + var handler = StreamLogHandler.standardOutput(label: $0) + handler.logLevel = .critical + return handler +} + +func greet(name: String, client greeter: models_GreeterServiceClient) { + // Form the request with the name, if one was provided. + var builder = FlatBufferBuilder() + let nameOff = builder.create(string: name) + let root = models_HelloRequest.createHelloRequest( + &builder, + nameOffset: nameOff) + builder.finish(offset: root) + + // Make the RPC call to the server. + let sayHello = greeter + .SayHello(Message(builder: &builder)) + + // wait() on the response to stop the program from exiting before the response is received. + do { + let response = try sayHello.response.wait() + print("Greeter SayHello received: \(response.object.message ?? "Unknown")") + } catch { + print("Greeter failed: \(error)") + } + + let surname = builder.create(string: name) + let manyRoot = models_HelloRequest.createHelloRequest( + &builder, + nameOffset: surname) + builder.finish(offset: manyRoot) + + let call = greeter.SayManyHellos(Message(builder: &builder)) { message in + print( + "Greeter SayManyHellos received: \(message.object.message ?? "Unknown")") + } + + let status = try! call.status.recover { _ in .processingError }.wait() + if status.code != .ok { + print("RPC failed: \(status)") + } +} + +func main(args: [String]) { + // arg0 (dropped) is the program name. We expect arg1 to be the port, and arg2 (optional) to be + // the name sent in the request. + let arg1 = args.dropFirst(1).first + let arg2 = args.dropFirst(2).first + + switch (arg1.flatMap(Int.init), arg2) { + case (.none, _): + print("Usage: PORT [NAME]") + exit(1) + + case let (.some(port), name): + // Setup an `EventLoopGroup` for the connection to run on. + // + // See: https://github.com/apple/swift-nio#eventloops-and-eventloopgroups + let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) + + // Make sure the group is shutdown when we're done with it. + defer { + try! group.syncShutdownGracefully() + } + + // Configure the channel, we're not using TLS so the connection is `insecure`. + let channel = ClientConnection.insecure(group: group) + .connect(host: "localhost", port: port) + + // Close the connection when we're done with it. + defer { + try! channel.close().wait() + } + + // Provide the connection to the generated client. + let greeter = models_GreeterServiceClient(channel: channel) + + // Do the greeting. + greet(name: name ?? "FlatBuffers!", client: greeter) + } +} + +main(args: CommandLine.arguments) diff --git a/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/server/main.swift b/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/server/main.swift new file mode 100644 index 000000000..62286c475 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/swift/Greeter/Sources/server/main.swift @@ -0,0 +1,96 @@ +/* + * Copyright 2023 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. + */ + +import FlatBuffers +import GRPC +import Logging +import Model +import NIO + +class Greeter: models_GreeterProvider { + + var interceptors: models_GreeterServerInterceptorFactoryProtocol? + + let greetings: [String] + + init() { + greetings = ["Hi", "Hallo", "Ciao"] + } + + func SayHello( + request: Message, + context: StatusOnlyCallContext) + -> EventLoopFuture> + { + let recipient = request.object.name ?? "Stranger" + + var builder = FlatBufferBuilder() + let off = builder.create(string: "Hello \(recipient)") + let root = models_HelloReply.createHelloReply(&builder, messageOffset: off) + builder.finish(offset: root) + return context.eventLoop + .makeSucceededFuture(Message(builder: &builder)) + } + + func SayManyHellos( + request: Message, + context: StreamingResponseCallContext>) + -> EventLoopFuture + { + for name in greetings { + var builder = FlatBufferBuilder() + let off = builder + .create(string: "\(name) \(request.object.name ?? "Unknown")") + let root = models_HelloReply.createHelloReply( + &builder, + messageOffset: off) + builder.finish(offset: root) + _ = context.sendResponse(Message(builder: &builder)) + } + return context.eventLoop.makeSucceededFuture(.ok) + } +} + +// Quieten the logs. +LoggingSystem.bootstrap { + var handler = StreamLogHandler.standardOutput(label: $0) + handler.logLevel = .critical + return handler +} + +let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) +defer { + try! group.syncShutdownGracefully() +} + +// Create some configuration for the server: +let configuration = Server.Configuration( + target: .hostAndPort("localhost", 0), + eventLoopGroup: group, + serviceProviders: [Greeter()]) + +// Start the server and print its address once it has started. +let server = Server.start(configuration: configuration) +server.map { + $0.channel.localAddress +}.whenSuccess { address in + print("server started on port \(address!.port!)") +} + +// Wait on the server's `onClose` future to stop the program from exiting. +_ = try server.flatMap { + $0.onClose +}.wait() diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/README.md b/third_party/flatbuffers/grpc/examples/ts/greeter/README.md new file mode 100644 index 000000000..5c7b380fd --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/README.md @@ -0,0 +1,13 @@ +# TS Greeter example + +The following is an example on how to run the TS grpc server. Make sure that you have `Typescript` installed + +you would need to run `npm run build` or simply use `npm install && tsc` + +## How to run Server: + +- `npm run server` + +## How to run Client: + +- `npm run client 3000` \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/package.json b/third_party/flatbuffers/grpc/examples/ts/greeter/package.json new file mode 100644 index 000000000..324bd3891 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/package.json @@ -0,0 +1,14 @@ +{ + "name": "flatbuffers-js-grpc", + "version": "1.0.0", + "author": "mustii@mmk.one", + "scripts": { + "build": "npm install && tsc", + "client": "node dist/client.js", + "server": "node dist/server.js" + }, + "dependencies": { + "@grpc/grpc-js": "^1.3.2", + "flatbuffers": "^2.0.0" + } +} diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/client.ts b/third_party/flatbuffers/grpc/examples/ts/greeter/src/client.ts new file mode 100644 index 000000000..62444f1eb --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/client.ts @@ -0,0 +1,34 @@ +import * as grpc from '@grpc/grpc-js'; +import * as flatbuffers from 'flatbuffers'; +import { HelloReply } from './models/hello-reply'; +import { HelloRequest } from './models/hello-request'; +import { GreeterClient } from './greeter_grpc'; + +async function main(PORT: Number, name: string) { + const client = new GreeterClient(`localhost:${PORT}`, grpc.credentials.createInsecure()); + const builder = new flatbuffers.Builder(); + const offset = builder.createString(name); + const root = HelloRequest.createHelloRequest(builder, offset); + builder.finish(root); + const buffer = HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(builder.asUint8Array())); + + client.SayHello(buffer, (err, response) => { + console.log(response.message()); + }); + + const data = client.SayManyHellos(buffer, null); + + data.on('data', (data) => { + console.log(data.message()); + }); +} + +const args = process.argv.slice(2) +const PORT = Number(args[0]); +const name: string = args[1] ?? "flatbuffers"; + +if (PORT) { + main(PORT, name); +} else { + throw new Error("Requires a valid port number.") +} \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter.ts b/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter.ts new file mode 100644 index 000000000..b6acab01f --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter.ts @@ -0,0 +1,5 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +export * as models from './models.js'; diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_generated.ts b/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_generated.ts new file mode 100644 index 000000000..c48afe538 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_generated.ts @@ -0,0 +1,4 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +export { HelloReply } from './models/hello-reply.js'; +export { HelloRequest } from './models/hello-request.js'; diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_grpc.d.ts b/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_grpc.d.ts new file mode 100644 index 000000000..657df5bbf --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_grpc.d.ts @@ -0,0 +1,56 @@ +// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT *** +import * as flatbuffers from 'flatbuffers'; +import { HelloReply as models_HelloReply } from './models/hello-reply'; +import { HelloRequest as models_HelloRequest } from './models/hello-request'; + +import * as grpc from '@grpc/grpc-js'; + +interface IGreeterService extends grpc.ServiceDefinition { + SayHello: IGreeterService_ISayHello; + SayManyHellos: IGreeterService_ISayManyHellos; +} +interface IGreeterService_ISayHello extends grpc.MethodDefinition { + path: string; // /models.Greeter/SayHello + requestStream: boolean; // false + responseStream: boolean; // false + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; +} + +interface IGreeterService_ISayManyHellos extends grpc.MethodDefinition { + path: string; // /models.Greeter/SayManyHellos + requestStream: boolean; // false + responseStream: boolean; // true + requestSerialize: grpc.serialize; + requestDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; +} + + +export const GreeterService: IGreeterService; + +export interface IGreeterServer extends grpc.UntypedServiceImplementation { + SayHello: grpc.handleUnaryCall; + SayManyHellos: grpc.handleServerStreamingCall; +} + +export interface IGreeterClient { + SayHello(request: models_HelloRequest, callback: (error: grpc.ServiceError | null, response: models_HelloReply) => void): grpc.ClientUnaryCall; + SayHello(request: models_HelloRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: models_HelloReply) => void): grpc.ClientUnaryCall; + SayHello(request: models_HelloRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: models_HelloReply) => void): grpc.ClientUnaryCall; + SayManyHellos(request: models_HelloRequest, metadata: grpc.Metadata): grpc.ClientReadableStream; + SayManyHellos(request: models_HelloRequest, options: Partial): grpc.ClientReadableStream; +} + +export class GreeterClient extends grpc.Client implements IGreeterClient { + constructor(address: string, credentials: grpc.ChannelCredentials, options?: object); + public SayHello(request: models_HelloRequest, callback: (error: grpc.ServiceError | null, response: models_HelloReply) => void): grpc.ClientUnaryCall; + public SayHello(request: models_HelloRequest, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: models_HelloReply) => void): grpc.ClientUnaryCall; + public SayHello(request: models_HelloRequest, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: models_HelloReply) => void): grpc.ClientUnaryCall; + public SayManyHellos(request: models_HelloRequest, metadata: grpc.Metadata): grpc.ClientReadableStream; + public SayManyHellos(request: models_HelloRequest, options: Partial): grpc.ClientReadableStream; +} + diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_grpc.js b/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_grpc.js new file mode 100644 index 000000000..242e6862a --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/greeter_grpc.js @@ -0,0 +1,56 @@ +// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT *** +import * as flatbuffers from 'flatbuffers'; +import { HelloReply as models_HelloReply } from './models/hello-reply'; +import { HelloRequest as models_HelloRequest } from './models/hello-request'; + +var grpc = require('@grpc/grpc-js'); + +function serialize_models_HelloReply(buffer_args) { + if (!(buffer_args instanceof models_HelloReply)) { + throw new Error('Expected argument of type HelloReply'); + } + return Buffer.from(buffer_args.serialize()); +} + +function deserialize_models_HelloReply(buffer) { + return models_HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(buffer)) +} + + +function serialize_models_HelloRequest(buffer_args) { + if (!(buffer_args instanceof models_HelloRequest)) { + throw new Error('Expected argument of type HelloRequest'); + } + return Buffer.from(buffer_args.serialize()); +} + +function deserialize_models_HelloRequest(buffer) { + return models_HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(buffer)) +} + + +var GreeterService = exports.GreeterService = { + SayHello: { + path: '/models.Greeter/SayHello', + requestStream: false, + responseStream: false, + requestType: flatbuffers.ByteBuffer, + responseType: models_HelloReply, + requestSerialize: serialize_models_HelloRequest, + requestDeserialize: deserialize_models_HelloRequest, + responseSerialize: serialize_models_HelloReply, + responseDeserialize: deserialize_models_HelloReply, + }, + SayManyHellos: { + path: '/models.Greeter/SayManyHellos', + requestStream: false, + responseStream: true, + requestType: flatbuffers.ByteBuffer, + responseType: models_HelloReply, + requestSerialize: serialize_models_HelloRequest, + requestDeserialize: deserialize_models_HelloRequest, + responseSerialize: serialize_models_HelloReply, + responseDeserialize: deserialize_models_HelloReply, + }, +}; +exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService); diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/models.ts b/third_party/flatbuffers/grpc/examples/ts/greeter/src/models.ts new file mode 100644 index 000000000..61d4731e3 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/models.ts @@ -0,0 +1,6 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +export { HelloReply } from './models/hello-reply.js'; +export { HelloRequest } from './models/hello-request.js'; diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/models/hello-reply.ts b/third_party/flatbuffers/grpc/examples/ts/greeter/src/models/hello-reply.ts new file mode 100644 index 000000000..c9dd72c2c --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/models/hello-reply.ts @@ -0,0 +1,60 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + + + +export class HelloReply { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):HelloReply { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsHelloReply(bb:flatbuffers.ByteBuffer, obj?:HelloReply):HelloReply { + return (obj || new HelloReply()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsHelloReply(bb:flatbuffers.ByteBuffer, obj?:HelloReply):HelloReply { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new HelloReply()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +message():string|null +message(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +message(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startHelloReply(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addMessage(builder:flatbuffers.Builder, messageOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, messageOffset, 0); +} + +static endHelloReply(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createHelloReply(builder:flatbuffers.Builder, messageOffset:flatbuffers.Offset):flatbuffers.Offset { + HelloReply.startHelloReply(builder); + HelloReply.addMessage(builder, messageOffset); + return HelloReply.endHelloReply(builder); +} + +serialize():Uint8Array { + return this.bb!.bytes(); +} + +static deserialize(buffer: Uint8Array):HelloReply { + return HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(buffer)) +} +} diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/models/hello-request.ts b/third_party/flatbuffers/grpc/examples/ts/greeter/src/models/hello-request.ts new file mode 100644 index 000000000..fb5239938 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/models/hello-request.ts @@ -0,0 +1,60 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ + +import * as flatbuffers from 'flatbuffers'; + + + +export class HelloRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):HelloRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsHelloRequest(bb:flatbuffers.ByteBuffer, obj?:HelloRequest):HelloRequest { + return (obj || new HelloRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsHelloRequest(bb:flatbuffers.ByteBuffer, obj?:HelloRequest):HelloRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new HelloRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +name():string|null +name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +name(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startHelloRequest(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, nameOffset, 0); +} + +static endHelloRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createHelloRequest(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset):flatbuffers.Offset { + HelloRequest.startHelloRequest(builder); + HelloRequest.addName(builder, nameOffset); + return HelloRequest.endHelloRequest(builder); +} + +serialize():Uint8Array { + return this.bb!.bytes(); +} + +static deserialize(buffer: Uint8Array):HelloRequest { + return HelloRequest.getRootAsHelloRequest(new flatbuffers.ByteBuffer(buffer)) +} +} diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/src/server.ts b/third_party/flatbuffers/grpc/examples/ts/greeter/src/server.ts new file mode 100644 index 000000000..a3f2eeec2 --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/src/server.ts @@ -0,0 +1,49 @@ +import * as grpc from '@grpc/grpc-js'; +import * as flatbuffers from 'flatbuffers'; +import { HelloReply } from './models/hello-reply'; +import { HelloRequest } from './models/hello-request'; +import { IGreeterServer, GreeterService } from './greeter_grpc'; + +const greeter: IGreeterServer = { + SayHello(call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData): void { + console.log(`SayHello ${call.request.name()}`); + const builder = new flatbuffers.Builder(); + const offset = builder.createString(`welcome ${call.request.name()}`); + const root = HelloReply.createHelloReply(builder, offset); + builder.finish(root); + callback(null, HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(builder.asUint8Array()))); + }, + async SayManyHellos(call: grpc.ServerWritableStream): Promise { + const name = call.request.name(); + console.log(`${call.request.name()} saying hi in different langagues`); + ['Hi', 'Hallo', 'Ciao'].forEach(element => { + const builder = new flatbuffers.Builder(); + const offset = builder.createString(`${element} ${name}`); + const root = HelloReply.createHelloReply(builder, offset); + builder.finish(root); + call.write(HelloReply.getRootAsHelloReply(new flatbuffers.ByteBuffer(builder.asUint8Array()))) + }); + call.end(); + } +} + +function serve(): void { + const PORT = 3000; + const server = new grpc.Server(); + server.addService(GreeterService, greeter); + console.log(`Listening on ${PORT}`); + server.bindAsync( + `localhost:${PORT}`, + grpc.ServerCredentials.createInsecure(), + (err: Error | null, port: number) => { + if (err) { + console.error(`Server error: ${err.message}`); + } else { + console.log(`Server bound on port: ${port}`); + server.start(); + } + } + ); +} + +serve(); \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/examples/ts/greeter/tsconfig.json b/third_party/flatbuffers/grpc/examples/ts/greeter/tsconfig.json new file mode 100644 index 000000000..70763787b --- /dev/null +++ b/third_party/flatbuffers/grpc/examples/ts/greeter/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "outDir": "./dist", + "allowJs": true, + "sourceMap": true, + "strict": true, + "noImplicitAny": false, + "strictNullChecks": false, + "esModuleInterop": true, + "baseUrl": "./", + "typeRoots": ["node_modules/@types"], + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + } + } \ No newline at end of file diff --git a/third_party/flatbuffers/grpc/flatbuffers-java-grpc/pom.xml b/third_party/flatbuffers/grpc/flatbuffers-java-grpc/pom.xml new file mode 100644 index 000000000..f7d417637 --- /dev/null +++ b/third_party/flatbuffers/grpc/flatbuffers-java-grpc/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + com.google.flatbuffers + flatbuffers-parent + 2.0.3 + + flatbuffers-java-grpc + ${project.artifactId} + bundle + + Utilities supporting generated code for GRPC + + + + Wouter van Oortmerssen + + + Yuri Finkelstein + https://github.com/yfinkelstein + + + + 1.36.0 + + + + com.google.flatbuffers + flatbuffers-java + ${project.parent.version} + + + io.grpc + grpc-core + ${gRPC.version} + + + + diff --git a/third_party/flatbuffers/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java b/third_party/flatbuffers/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java new file mode 100644 index 000000000..768708b11 --- /dev/null +++ b/third_party/flatbuffers/grpc/flatbuffers-java-grpc/src/main/java/com/google/flatbuffers/grpc/FlatbuffersUtils.java @@ -0,0 +1,117 @@ +/* + * 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. + */ +package com.google.flatbuffers.grpc; + +import com.google.flatbuffers.Table; +import io.grpc.Drainable; +import io.grpc.KnownLength; +import io.grpc.MethodDescriptor; + +import javax.annotation.Nullable; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +public class FlatbuffersUtils { + abstract public static class FBExtactor { + T extract (InputStream stream) throws IOException { + if (stream instanceof KnownLength) { + int size = stream.available(); + ByteBuffer buffer = ByteBuffer.allocate(size); + stream.read(buffer.array()); + return extract(buffer); + } else + throw new RuntimeException("The class " + stream.getClass().getCanonicalName() + " does not extend from KnownLength "); + } + + public abstract T extract(ByteBuffer buffer); + + } + + static class FBInputStream extends InputStream implements Drainable, KnownLength { + private final ByteBuffer buffer; + private final int size; + @Nullable private ByteArrayInputStream inputStream; + + FBInputStream(ByteBuffer buffer) { + this.buffer = buffer; + this.size = buffer.remaining(); + } + + private void makeStreamIfNotAlready() { + if (inputStream == null) + inputStream = new ByteArrayInputStream(buffer.array(), buffer.position(), size); + } + + @Override + public int drainTo(OutputStream target) throws IOException { + target.write(buffer.array(), buffer.position(), size); + return size; + } + + @Override + public int read() throws IOException { + makeStreamIfNotAlready(); + return inputStream.read(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + makeStreamIfNotAlready(); + if (inputStream == null) { + if (len >= size) { + System.arraycopy(buffer.array(), buffer.position(), b, off, size); + return size; + } else { + makeStreamIfNotAlready(); + return inputStream.read(b, off, len); + } + } else + return inputStream.read(b, off, len); + } + + @Override + public int available() throws IOException { + return inputStream == null ? size : inputStream.available(); + } + + } + + public static MethodDescriptor.Marshaller marshaller(final Class clazz, final FBExtactor extractor) { + return new MethodDescriptor.ReflectableMarshaller() { + @Override + public Class getMessageClass() { + return clazz; + } + + @Override + public InputStream stream(T value) { + return new FBInputStream (value.getByteBuffer()); + } + + @Override + public T parse(InputStream stream) { + try { + return extractor.extract(stream); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }; + } +} diff --git a/third_party/flatbuffers/grpc/pom.xml b/third_party/flatbuffers/grpc/pom.xml new file mode 100644 index 000000000..a0608ae8a --- /dev/null +++ b/third_party/flatbuffers/grpc/pom.xml @@ -0,0 +1,219 @@ + + 4.0.0 + com.google.flatbuffers + flatbuffers-parent + pom + 2.0.3 + flatbuffers-parent + parent pom for flatbuffers java artifacts + + https://github.com/google/flatbuffers + scm:git:${scm.url}.git + UTF-8 + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + GitHub + https://github.com/google/flatbuffers/issues + + + + + Wouter van Oortmerssen + + + + ${scm.url} + + + ${scm.connection} + ${scm.connection} + ${scm.url} + HEAD + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + + + + junit + junit + 4.13.1 + test + + + + + + + + kr.motd.maven + os-maven-plugin + 1.5.0.Final + + + + + + maven-compiler-plugin + 3.6.1 + + + maven-jar-plugin + 3.0.2 + + + maven-source-plugin + 3.0.1 + + + maven-surefire-plugin + 2.19.1 + + + maven-javadoc-plugin + 2.10.4 + + + org.codehaus.mojo + build-helper-maven-plugin + 1.12 + + + maven-dependency-plugin + 2.8 + + + maven-deploy-plugin + 2.7 + + + maven-gpg-plugin + 1.5 + + + maven-release-plugin + 2.5.3 + + + + org.codehaus.mojo + exec-maven-plugin + 1.5.0 + + + + + + + maven-compiler-plugin + + 1.6 + 1.6 + + + + maven-surefire-plugin + + + **/*Test.java + + + + + maven-source-plugin + + + attach-sources + + jar + + + + + + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + org.apache.felix + maven-bundle-plugin + 3.0.1 + true + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + + + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + --pinentry-mode + loopback + + + + + + + maven-release-plugin + + true + false + release + deploy + + + + + + + + flatbuffers-java-grpc + + + diff --git a/third_party/flatbuffers/grpc/samples/greeter/Makefile b/third_party/flatbuffers/grpc/samples/greeter/Makefile new file mode 100644 index 000000000..910483cac --- /dev/null +++ b/third_party/flatbuffers/grpc/samples/greeter/Makefile @@ -0,0 +1,14 @@ +CXXFLAGS ?= -I../../../include +LDFLAGS ?= + +.PHONY: all +all: server client + +greeter_generated: greeter.fbs + flatc --grpc --cpp $< + +server: greeter_generated server.cpp greeter.grpc.fb.cc greeter.grpc.fb.h + g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ server.cpp greeter.grpc.fb.cc -o $@ + +client: greeter_generated client.cpp greeter.grpc.fb.cc greeter.grpc.fb.h + g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ client.cpp greeter.grpc.fb.cc -o $@ diff --git a/third_party/flatbuffers/grpc/samples/greeter/client.cpp b/third_party/flatbuffers/grpc/samples/greeter/client.cpp new file mode 100644 index 000000000..0e4f34814 --- /dev/null +++ b/third_party/flatbuffers/grpc/samples/greeter/client.cpp @@ -0,0 +1,85 @@ +#include "greeter.grpc.fb.h" +#include "greeter_generated.h" + +#include + +#include +#include +#include + +class GreeterClient { + public: + GreeterClient(std::shared_ptr channel) + : stub_(Greeter::NewStub(channel)) {} + + std::string SayHello(const std::string &name) { + flatbuffers::grpc::MessageBuilder mb; + auto name_offset = mb.CreateString(name); + auto request_offset = CreateHelloRequest(mb, name_offset); + mb.Finish(request_offset); + auto request_msg = mb.ReleaseMessage(); + + flatbuffers::grpc::Message response_msg; + + grpc::ClientContext context; + + auto status = stub_->SayHello(&context, request_msg, &response_msg); + if (status.ok()) { + const HelloReply *response = response_msg.GetRoot(); + return response->message()->str(); + } else { + std::cerr << status.error_code() << ": " << status.error_message() + << std::endl; + return "RPC failed"; + } + } + + void SayManyHellos(const std::string &name, int num_greetings, + std::function callback) { + flatbuffers::grpc::MessageBuilder mb; + auto name_offset = mb.CreateString(name); + auto request_offset = + CreateManyHellosRequest(mb, name_offset, num_greetings); + mb.Finish(request_offset); + auto request_msg = mb.ReleaseMessage(); + + flatbuffers::grpc::Message response_msg; + + grpc::ClientContext context; + + auto stream = stub_->SayManyHellos(&context, request_msg); + while (stream->Read(&response_msg)) { + const HelloReply *response = response_msg.GetRoot(); + callback(response->message()->str()); + } + auto status = stream->Finish(); + if (!status.ok()) { + std::cerr << status.error_code() << ": " << status.error_message() + << std::endl; + callback("RPC failed"); + } + } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char **argv) { + std::string server_address("localhost:50051"); + + auto channel = + grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()); + GreeterClient greeter(channel); + + std::string name("world"); + + std::string message = greeter.SayHello(name); + std::cerr << "Greeter received: " << message << std::endl; + + int num_greetings = 10; + greeter.SayManyHellos(name, num_greetings, [](const std::string &message) { + std::cerr << "Greeter received: " << message << std::endl; + }); + + return 0; +} diff --git a/third_party/flatbuffers/grpc/samples/greeter/greeter.fbs b/third_party/flatbuffers/grpc/samples/greeter/greeter.fbs new file mode 100644 index 000000000..811303c93 --- /dev/null +++ b/third_party/flatbuffers/grpc/samples/greeter/greeter.fbs @@ -0,0 +1,17 @@ +table HelloReply { + message:string; +} + +table HelloRequest { + name:string; +} + +table ManyHellosRequest { + name:string; + num_greetings:int; +} + +rpc_service Greeter { + SayHello(HelloRequest):HelloReply; + SayManyHellos(ManyHellosRequest):HelloReply (streaming: "server"); +} diff --git a/third_party/flatbuffers/grpc/samples/greeter/server.cpp b/third_party/flatbuffers/grpc/samples/greeter/server.cpp new file mode 100644 index 000000000..ac38fa969 --- /dev/null +++ b/third_party/flatbuffers/grpc/samples/greeter/server.cpp @@ -0,0 +1,81 @@ +#include "greeter.grpc.fb.h" +#include "greeter_generated.h" + +#include + +#include +#include +#include + +class GreeterServiceImpl final : public Greeter::Service { + virtual grpc::Status SayHello( + grpc::ServerContext *context, + const flatbuffers::grpc::Message *request_msg, + flatbuffers::grpc::Message *response_msg) override { + flatbuffers::grpc::MessageBuilder mb_; + + // We call GetRoot to "parse" the message. Verification is already + // performed by default. See the notes below for more details. + const HelloRequest *request = request_msg->GetRoot(); + + // Fields are retrieved as usual with FlatBuffers + const std::string &name = request->name()->str(); + + // `flatbuffers::grpc::MessageBuilder` is a `FlatBufferBuilder` with a + // special allocator for efficient gRPC buffer transfer, but otherwise + // usage is the same as usual. + auto msg_offset = mb_.CreateString("Hello, " + name); + auto hello_offset = CreateHelloReply(mb_, msg_offset); + mb_.Finish(hello_offset); + + // The `ReleaseMessage()` function detaches the message from the + // builder, so we can transfer the resopnse to gRPC while simultaneously + // detaching that memory buffer from the builer. + *response_msg = mb_.ReleaseMessage(); + assert(response_msg->Verify()); + + // Return an OK status. + return grpc::Status::OK; + } + + virtual grpc::Status SayManyHellos( + grpc::ServerContext *context, + const flatbuffers::grpc::Message *request_msg, + grpc::ServerWriter> *writer) + override { + // The streaming usage below is simply a combination of standard gRPC + // streaming with the FlatBuffers usage shown above. + const ManyHellosRequest *request = request_msg->GetRoot(); + const std::string &name = request->name()->str(); + int num_greetings = request->num_greetings(); + + for (int i = 0; i < num_greetings; i++) { + auto msg_offset = mb_.CreateString("Many hellos, " + name); + auto hello_offset = CreateHelloReply(mb_, msg_offset); + mb_.Finish(hello_offset); + writer->Write(mb_.ReleaseMessage()); + } + + return grpc::Status::OK; + } + + flatbuffers::grpc::MessageBuilder mb_; +}; + +void RunServer() { + std::string server_address("0.0.0.0:50051"); + GreeterServiceImpl service; + + grpc::ServerBuilder builder; + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + std::unique_ptr server(builder.BuildAndStart()); + std::cerr << "Server listening on " << server_address << std::endl; + + server->Wait(); +} + +int main(int argc, const char *argv[]) { + RunServer(); + return 0; +} diff --git a/third_party/flatbuffers/grpc/src/compiler/BUILD.bazel b/third_party/flatbuffers/grpc/src/compiler/BUILD.bazel new file mode 100644 index 000000000..0efa9560c --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/BUILD.bazel @@ -0,0 +1,131 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +package( + default_visibility = ["//visibility:public"], +) + +filegroup( + name = "distribution", + srcs = [ + "BUILD.bazel", + ] + glob([ + "*.cc", + "*.h", + ]), +) + +filegroup( + name = "common_headers", + srcs = [ + "schema_interface.h", + ], +) + +cc_library( + name = "cpp_generator", + srcs = [ + "cpp_generator.cc", + ], + hdrs = [ + "cpp_generator.h", + ":common_headers", + ], + include_prefix = "src/compiler", + strip_include_prefix = "/grpc/src/compiler", + deps = [ + "//:flatbuffers", + ], +) + +cc_library( + name = "go_generator", + srcs = [ + "go_generator.cc", + ], + hdrs = [ + "go_generator.h", + ":common_headers", + ], + include_prefix = "src/compiler", + strip_include_prefix = "/grpc/src/compiler", + deps = [ + "//:flatbuffers", + ], +) + +cc_library( + name = "java_generator", + srcs = [ + "java_generator.cc", + ], + hdrs = [ + "java_generator.h", + ":common_headers", + ], + include_prefix = "src/compiler", + strip_include_prefix = "/grpc/src/compiler", + deps = [ + "//:flatbuffers", + ], +) + +cc_library( + name = "python_generator", + hdrs = [ + "python_generator.h", + ], + include_prefix = "src/compiler", + strip_include_prefix = "/grpc/src/compiler", + deps = [ + ":python_generator_private", + ], +) + +cc_library( + name = "python_generator_private", + srcs = [ + "python_generator.cc", + ], + hdrs = [ + "python_generator.h", + ":common_headers", + ], + include_prefix = "src/compiler", + strip_include_prefix = "/grpc/src/compiler", + visibility = ["//visibility:private"], + deps = [ + "//:flatbuffers", + ], +) + +cc_library( + name = "swift_generator", + srcs = [ + "swift_generator.cc", + ], + hdrs = [ + "swift_generator.h", + ":common_headers", + ], + include_prefix = "src/compiler", + strip_include_prefix = "/grpc/src/compiler", + deps = [ + "//:flatbuffers", + ], +) + +cc_library( + name = "ts_generator", + srcs = [ + "ts_generator.cc", + ], + hdrs = [ + "ts_generator.h", + ":common_headers", + ], + include_prefix = "src/compiler", + strip_include_prefix = "/grpc/src/compiler", + deps = [ + "//:flatbuffers", + ], +) diff --git a/third_party/flatbuffers/grpc/src/compiler/cpp_generator.cc b/third_party/flatbuffers/grpc/src/compiler/cpp_generator.cc new file mode 100644 index 000000000..fd635f2fa --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/cpp_generator.cc @@ -0,0 +1,1766 @@ +#include "src/compiler/cpp_generator.h" + +#include +#include + +#include "flatbuffers/util.h" + +namespace grpc_cpp_generator { +namespace { + +static grpc::string service_header_ext() { return ".grpc.fb.h"; } + +template +static grpc::string as_string(T x) { + std::ostringstream out; + out << x; + return out.str(); +} + +static inline bool ClientOnlyStreaming(const grpc_generator::Method *method) { + return method->ClientStreaming() && !method->ServerStreaming(); +} + +static inline bool ServerOnlyStreaming(const grpc_generator::Method *method) { + return !method->ClientStreaming() && method->ServerStreaming(); +} + +static grpc::string FilenameIdentifier(const grpc::string &filename) { + grpc::string result; + for (unsigned i = 0; i < filename.size(); i++) { + char c = filename[i]; + if (isalnum(c)) { + result.push_back(c); + } else { + static char hex[] = "0123456789abcdef"; + result.push_back('_'); + result.push_back(hex[(c >> 4) & 0xf]); + result.push_back(hex[c & 0xf]); + } + } + return result; +} + +template +static T *array_end(T (&array)[N]) { return array + N; } + +static void PrintIncludes(grpc_generator::Printer *printer, + const std::vector &headers, + const Parameters ¶ms) { + std::map vars; + + vars["l"] = params.use_system_headers ? '<' : '"'; + vars["r"] = params.use_system_headers ? '>' : '"'; + + auto &s = params.grpc_search_path; + if (!s.empty()) { + vars["l"] += s; + if (s[s.size() - 1] != '/') { vars["l"] += '/'; } + } + + for (auto i = headers.begin(); i != headers.end(); i++) { + vars["h"] = *i; + printer->Print(vars, "#include $l$$h$$r$\n"); + } +} + +} // namespace + +grpc::string GetHeaderPrologue(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + vars["filename"] = file->filename(); + vars["filename_identifier"] = FilenameIdentifier(file->filename()); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = params.message_header_extension; + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n"); + grpc::string leading_comments = file->GetLeadingComments("//"); + if (!leading_comments.empty()) { + printer->Print(vars, "// Original file comments:\n"); + printer->Print(leading_comments.c_str()); + } + printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n"); + printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n"); + printer->Print(vars, "\n"); + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, file->additional_headers().c_str()); + printer->Print(vars, "\n"); + } + return output; +} + +grpc::string GetHeaderIncludes(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + static const char *headers_strs[] = { + "grpcpp/impl/codegen/async_stream.h", + "grpcpp/impl/codegen/async_unary_call.h", + "grpcpp/impl/codegen/method_handler.h", + "grpcpp/impl/codegen/proto_utils.h", + "grpcpp/impl/codegen/rpc_method.h", + "grpcpp/impl/codegen/service_type.h", + "grpcpp/impl/codegen/status.h", + "grpcpp/impl/codegen/stub_options.h", + "grpcpp/impl/codegen/sync_stream.h" + }; + std::vector headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params); + printer->Print(vars, "\n"); + printer->Print(vars, "namespace grpc {\n"); + printer->Print(vars, "class CompletionQueue;\n"); + printer->Print(vars, "class Channel;\n"); + printer->Print(vars, "class ServerCompletionQueue;\n"); + printer->Print(vars, "class ServerContext;\n"); + printer->Print(vars, "} // namespace grpc\n\n"); + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + printer->Print(vars, "\n"); + } + } + return output; +} + + +namespace { + +static void PrintHeaderClientMethodInterfaces( + grpc_generator::Printer *printer, const grpc_generator::Method *method, + std::map *vars, bool is_public) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + struct { + grpc::string prefix; + grpc::string method_params; // extra arguments to method + grpc::string raw_args; // extra arguments to raw version of method + } async_prefixes[] = { { "Async", ", void* tag", ", tag" }, + { "PrepareAsync", "", "" } }; + + if (is_public) { + if (method->NoStreaming()) { + printer->Print( + *vars, + "virtual ::grpc::Status $Method$(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) = 0;\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + " $Method$(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + "($Method$Raw(context, response));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< $Request$>>" + " $AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "$Response$* " + "response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncWriterInterface< $Request$>>(" + "$AsyncPrefix$$Method$Raw(context, response, " + "cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + " $Method$(::grpc::ClientContext* context, const $Request$& request)" + " {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + "($Method$Raw(context, request));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReaderInterface< $Response$>> " + "$AsyncPrefix$$Method$(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderInterface< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "std::unique_ptr< ::grpc::ClientReaderWriterInterface< " + "$Request$, $Response$>> " + "$Method$(::grpc::ClientContext* context) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriterInterface< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else { + if (method->NoStreaming()) { + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncResponseReaderInterface< $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) = 0;\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientWriterInterface< $Request$>*" + " $Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) = 0;\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncWriterInterface< $Request$>*" + " $AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientReaderInterface< $Response$>* " + "$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request) = 0;\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncReaderInterface< $Response$>* " + "$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "virtual ::grpc::ClientReaderWriterInterface< $Request$, " + "$Response$>* " + "$Method$Raw(::grpc::ClientContext* context) = 0;\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncReaderWriterInterface< " + "$Request$, $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } + } +} + + + +static void PrintHeaderClientMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map *vars, + bool is_public) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + struct { + grpc::string prefix; + grpc::string method_params; // extra arguments to method + grpc::string raw_args; // extra arguments to raw version of method + } async_prefixes[] = { { "Async", ", void* tag", ", tag" }, + { "PrepareAsync", "", "" } }; + + if (is_public) { + if (method->NoStreaming()) { + printer->Print( + *vars, + "::grpc::Status $Method$(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) override;\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncResponseReader< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientWriter< $Request$>>" + " $Method$(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< ::grpc::ClientWriter< $Request$>>" + "($Method$Raw(context, response));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print(*vars, + "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>" + " $AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>(" + "$AsyncPrefix$$Method$Raw(context, response, " + "cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReader< $Response$>>" + " $Method$(::grpc::ClientContext* context, const $Request$& request)" + " {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReader< $Response$>>" + "($Method$Raw(context, request));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> " + "$AsyncPrefix$$Method$(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>>" + " $Method$(::grpc::ClientContext* context) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriter< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print(*vars, + "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " + "$Request$, $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else { + if (method->NoStreaming()) { + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "::grpc::ClientAsyncResponseReader< $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) override;\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientWriter< $Request$>* $Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) " + "override;\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncWriter< $Request$>* $AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientReader< $Response$>* $Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request)" + " override;\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReader< $Response$>* $AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "::grpc::ClientReaderWriter< $Request$, $Response$>* " + "$Method$Raw(::grpc::ClientContext* context) override;\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } + } +} + +static void PrintHeaderClientMethodData(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map *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 *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + printer->Print(method->GetLeadingComments("//").c_str()); + if (method->NoStreaming()) { + printer->Print(*vars, + "virtual ::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "$Response$* response);\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "virtual ::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReader< $Request$>* reader, " + "$Response$* response);\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "virtual ::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer);\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "virtual ::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);" + "\n"); + } + printer->Print(method->GetTrailingComments("//").c_str()); +} + +static void PrintHeaderServerMethodAsync(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithAsyncMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service */*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithAsyncMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodAsync($Idx$);\n" + "}\n"); + printer->Print(*vars, + "~WithAsyncMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + if (method->NoStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "$Response$* /*response*/) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, $Request$* request, " + "::grpc::ServerAsyncResponseWriter< $Response$>* response, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncUnary($Idx$, context, " + "request, response, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReader< $Request$>* /*reader*/, " + "$Response$* /*response*/) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncClientStreaming($Idx$, " + "context, reader, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "::grpc::ServerWriter< $Response$>* /*writer*/) final override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, $Request$* request, " + "::grpc::ServerAsyncWriter< $Response$>* writer, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print( + *vars, + " ::grpc::Service::RequestAsyncServerStreaming($Idx$, " + "context, request, writer, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* /*stream*/) " + "final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncBidiStreaming($Idx$, " + "context, stream, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +static void PrintHeaderServerMethodStreamedUnary( + grpc_generator::Printer *printer, const grpc_generator::Method *method, + std::map *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (method->NoStreaming()) { + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithStreamedUnaryMethod_$Method$ : " + "public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service */*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithStreamedUnaryMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodStreamed($Idx$,\n" + " new ::grpc::internal::StreamedUnaryHandler< $Request$, " + "$Response$>(std::bind" + "(&WithStreamedUnaryMethod_$Method$::" + "Streamed$Method$, this, std::placeholders::_1, " + "std::placeholders::_2)));\n" + "}\n"); + printer->Print(*vars, + "~WithStreamedUnaryMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + printer->Print( + *vars, + "// disable regular version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "$Response$* /*response*/) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print(*vars, + "// replace default version of method with streamed unary\n" + "virtual ::grpc::Status Streamed$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerUnaryStreamer< " + "$Request$,$Response$>* server_unary_streamer)" + " = 0;\n"); + printer->Outdent(); + printer->Print(*vars, "};\n"); + } +} + +static void PrintHeaderServerMethodSplitStreaming( + grpc_generator::Printer *printer, const grpc_generator::Method *method, + std::map *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (ServerOnlyStreaming(method)) { + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithSplitStreamingMethod_$Method$ : " + "public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service */*service*/) " + "{ }\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print( + *vars, + "WithSplitStreamingMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodStreamed($Idx$,\n" + " new ::grpc::internal::SplitServerStreamingHandler< $Request$, " + "$Response$>(std::bind" + "(&WithSplitStreamingMethod_$Method$::" + "Streamed$Method$, this, std::placeholders::_1, " + "std::placeholders::_2)));\n" + "}\n"); + printer->Print(*vars, + "~WithSplitStreamingMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + printer->Print( + *vars, + "// disable regular version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "::grpc::ServerWriter< $Response$>* /*writer*/) final override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print(*vars, + "// replace default version of method with split streamed\n" + "virtual ::grpc::Status Streamed$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerSplitStreamer< " + "$Request$,$Response$>* server_split_streamer)" + " = 0;\n"); + printer->Outdent(); + printer->Print(*vars, "};\n"); + } +} + +static void PrintHeaderServerMethodGeneric( + grpc_generator::Printer *printer, const grpc_generator::Method *method, + std::map *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + printer->Print(*vars, "template \n"); + printer->Print(*vars, + "class WithGenericMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service */*service*/) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithGenericMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodGeneric($Idx$);\n" + "}\n"); + printer->Print(*vars, + "~WithGenericMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + if (method->NoStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "$Response$* /*response*/) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReader< $Request$>* /*reader*/, " + "$Response$* /*response*/) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, const $Request$* /*request*/, " + "::grpc::ServerWriter< $Response$>* /*writer*/) final override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* /*stream*/) " + "final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +static void PrintHeaderService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, + std::map *vars) { + (*vars)["Service"] = service->name(); + + printer->Print(service->GetLeadingComments("//").c_str()); + printer->Print(*vars, + "class $Service$ final {\n" + " public:\n"); + printer->Indent(); + + // Service metadata + printer->Print(*vars, + "static constexpr char const* service_full_name() {\n" + " return \"$Package$$Service$\";\n" + "}\n"); + + // Client side + printer->Print( + "class StubInterface {\n" + " public:\n"); + printer->Indent(); + printer->Print("virtual ~StubInterface() {}\n"); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(service->method(i)->GetLeadingComments("//").c_str()); + PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, + true); + printer->Print(service->method(i)->GetTrailingComments("//").c_str()); + } + printer->Outdent(); + printer->Print("private:\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, + false); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print( + "class Stub final : public StubInterface" + " {\n public:\n"); + printer->Indent(); + printer->Print( + "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& " + "channel);\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethod(printer, service->method(i).get(), vars, true); + } + printer->Outdent(); + printer->Print("\n private:\n"); + printer->Indent(); + printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethod(printer, service->method(i).get(), vars, false); + } + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodData(printer, service->method(i).get(), vars); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print( + "static std::unique_ptr NewStub(const std::shared_ptr< " + "::grpc::ChannelInterface>& channel, " + "const ::grpc::StubOptions& options = ::grpc::StubOptions());\n"); + + printer->Print("\n"); + + // Server side - base + printer->Print( + "class Service : public ::grpc::Service {\n" + " public:\n"); + printer->Indent(); + printer->Print("Service();\n"); + printer->Print("virtual ~Service();\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderServerMethodSync(printer, service->method(i).get(), vars); + } + printer->Outdent(); + printer->Print("};\n"); + + // Server side - Asynchronous + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodAsync(printer, service->method(i).get(), vars); + } + + printer->Print("typedef "); + + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i).get()->name(); + printer->Print(*vars, "WithAsyncMethod_$method_name$<"); + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { printer->Print(" >"); } + printer->Print(" AsyncService;\n"); + + // Server side - Generic + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodGeneric(printer, service->method(i).get(), vars); + } + + // Server side - Streamed Unary + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodStreamedUnary(printer, service->method(i).get(), + vars); + } + + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i).get()->name(); + if (service->method(i)->NoStreaming()) { + printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + if (service->method(i)->NoStreaming()) { printer->Print(" >"); } + } + printer->Print(" StreamedUnaryService;\n"); + + // Server side - controlled server-side streaming + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodSplitStreaming(printer, service->method(i).get(), + vars); + } + + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i).get()->name(); + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { + printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { printer->Print(" >"); } + } + printer->Print(" SplitStreamedService;\n"); + + // Server side - typedef for controlled both unary and server-side streaming + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i).get()->name(); + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { + printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); + } + if (service->method(i)->NoStreaming()) { + printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (service->method(i)->NoStreaming() || + ServerOnlyStreaming(method.get())) { + printer->Print(" >"); + } + } + printer->Print(" StreamedService;\n"); + + printer->Outdent(); + printer->Print("};\n"); + printer->Print(service->GetTrailingComments("//").c_str()); +} + +} // namespace + +grpc::string GetHeaderServices(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { vars["Package"].append("."); } + + if (!params.services_namespace.empty()) { + vars["services_namespace"] = params.services_namespace; + printer->Print(vars, "\nnamespace $services_namespace$ {\n\n"); + } + + for (int i = 0; i < file->service_count(); ++i) { + PrintHeaderService(printer.get(), file->service(i).get(), &vars); + printer->Print("\n"); + } + + if (!params.services_namespace.empty()) { + printer->Print(vars, "} // namespace $services_namespace$\n\n"); + } + } + return output; +} + +grpc::string GetHeaderEpilogue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + vars["filename"] = file->filename(); + vars["filename_identifier"] = FilenameIdentifier(file->filename()); + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.rbegin(); part != parts.rend(); part++) { + vars["part"] = *part; + printer->Print(vars, "} // namespace $part$\n"); + } + printer->Print(vars, "\n"); + } + + printer->Print(vars, "\n"); + printer->Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n"); + + printer->Print(file->GetTrailingComments("//").c_str()); + } + return output; +} + +grpc::string GetSourcePrologue(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + vars["filename"] = file->filename(); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = params.message_header_extension; + vars["service_header_ext"] = service_header_ext(); + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n\n"); + + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n"); + printer->Print(vars, "\n"); + } + return output; +} + +grpc::string GetSourceIncludes(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + static const char *headers_strs[] = { + "grpcpp/impl/codegen/async_stream.h", + "grpcpp/impl/codegen/async_unary_call.h", + "grpcpp/impl/codegen/channel_interface.h", + "grpcpp/impl/codegen/client_unary_call.h", + "grpcpp/impl/codegen/method_handler.h", + "grpcpp/impl/codegen/rpc_service_method.h", + "grpcpp/impl/codegen/service_type.h", + "grpcpp/impl/codegen/sync_stream.h" + }; + std::vector headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params); + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + } + + printer->Print(vars, "\n"); + } + return output; +} + + +namespace { + +static void PrintSourceClientMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + struct { + grpc::string prefix; + grpc::string start; // bool literal expressed as string + grpc::string method_params; // extra arguments to method + grpc::string create_args; // extra arguments to creator + } async_prefixes[] = { { "Async", "true", ", void* tag", ", tag" }, + { "PrepareAsync", "false", "", ", nullptr" } }; + if (method->NoStreaming()) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Stub::$Method$(" + "::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) {\n"); + printer->Print(*vars, + " return ::grpc::internal::BlockingUnaryCall" + "(channel_.get(), rpcmethod_$Method$_, " + "context, request, response);\n}\n\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + printer->Print(*vars, + "::grpc::ClientAsyncResponseReader< $Response$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(::grpc::" + "ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Print( + *vars, + " return " + "::grpc::internal::ClientAsyncResponseReaderFactory< $Response$>" + "::Create(channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, request, $AsyncStart$);\n" + "}\n\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientWriter< $Request$>* " + "$ns$$Service$::Stub::$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientWriterFactory< $Request$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, response);\n" + "}\n\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print(*vars, + "::grpc::ClientAsyncWriter< $Request$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientAsyncWriterFactory< $Request$>" + "::Create(channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, response, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "::grpc::ClientReader< $Response$>* " + "$ns$$Service$::Stub::$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientReaderFactory< $Response$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, request);\n" + "}\n\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReader< $Response$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientAsyncReaderFactory< $Response$>" + "::Create(channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, request, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "::grpc::ClientReaderWriter< $Request$, $Response$>* " + "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); + printer->Print(*vars, + " return ::grpc::internal::ClientReaderWriterFactory< " + "$Request$, $Response$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context);\n" + "}\n\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print(*vars, + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(::grpc::" + "ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print(*vars, + " return " + "::grpc::internal::ClientAsyncReaderWriterFactory< " + "$Request$, $Response$>::Create(" + "channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } +} + +static void PrintSourceServerMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (method->NoStreaming()) { + printer->Print( + *vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* /*context*/, " + "const $Request$* /*request*/, $Response$* /*response*/) {\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReader< $Request$>* /*reader*/, " + "$Response$* /*response*/) {\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* /*context*/, " + "const $Request$* /*request*/, " + "::grpc::ServerWriter< $Response$>* /*writer*/) {\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* /*context*/, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* " + "/*stream*/) {\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } +} + +static void PrintSourceService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, + std::map *vars) { + (*vars)["Service"] = service->name(); + + if (service->method_count() > 0) { + printer->Print(*vars, + "static const char* $prefix$$Service$_method_names[] = {\n"); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Method"] = service->method(i).get()->name(); + printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n"); + } + printer->Print(*vars, "};\n\n"); + } + + printer->Print(*vars, + "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub(" + "const std::shared_ptr< ::grpc::ChannelInterface>& channel, " + "const ::grpc::StubOptions& /*options*/) {\n" + " std::unique_ptr< $ns$$Service$::Stub> stub(new " + "$ns$$Service$::Stub(channel));\n" + " return stub;\n" + "}\n\n"); + printer->Print(*vars, + "$ns$$Service$::Stub::Stub(const std::shared_ptr< " + "::grpc::ChannelInterface>& channel)\n"); + printer->Indent(); + printer->Print(": channel_(channel)"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + (*vars)["Method"] = method->name(); + (*vars)["Idx"] = as_string(i); + if (method->NoStreaming()) { + (*vars)["StreamingType"] = "NORMAL_RPC"; + // NOTE: There is no reason to consider streamed-unary as a separate + // category here since this part is setting up the client-side stub + // and this appears as a NORMAL_RPC from the client-side. + } else if (ClientOnlyStreaming(method.get())) { + (*vars)["StreamingType"] = "CLIENT_STREAMING"; + } else if (ServerOnlyStreaming(method.get())) { + (*vars)["StreamingType"] = "SERVER_STREAMING"; + } else { + (*vars)["StreamingType"] = "BIDI_STREAMING"; + } + printer->Print(*vars, + ", rpcmethod_$Method$_(" + "$prefix$$Service$_method_names[$Idx$], " + "::grpc::internal::RpcMethod::$StreamingType$, " + "channel" + ")\n"); + } + printer->Print("{}\n\n"); + printer->Outdent(); + + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintSourceClientMethod(printer, service->method(i).get(), vars); + } + + printer->Print(*vars, "$ns$$Service$::Service::Service() {\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::RpcMethodHandler< $ns$$Service$::Service, " + "$Request$, " + "$Response$>(\n" + " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\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::ClientStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\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::ServerStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\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::BidiStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); + } + } + printer->Outdent(); + printer->Print(*vars, "}\n\n"); + printer->Print(*vars, + "$ns$$Service$::Service::~Service() {\n" + "}\n\n"); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintSourceServerMethod(printer, service->method(i).get(), vars); + } +} + +} // namespace + +grpc::string GetSourceServices(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { vars["Package"].append("."); } + if (!params.services_namespace.empty()) { + vars["ns"] = params.services_namespace + "::"; + vars["prefix"] = params.services_namespace; + } else { + vars["ns"] = ""; + vars["prefix"] = ""; + } + + for (int i = 0; i < file->service_count(); ++i) { + PrintSourceService(printer.get(), file->service(i).get(), &vars); + printer->Print("\n"); + } + } + return output; +} + +grpc::string GetSourceEpilogue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string temp; + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + temp.append("} // namespace "); + temp.append(*part); + temp.append("\n"); + } + temp.append("\n"); + } + + return temp; +} + +grpc::string GetMockPrologue(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + vars["filename"] = file->filename(); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = params.message_header_extension; + vars["service_header_ext"] = service_header_ext(); + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n\n"); + + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n"); + printer->Print(vars, file->additional_headers().c_str()); + printer->Print(vars, "\n"); + } + return output; +} + +// TODO(mmukhi): Add client-stream and completion-queue headers. +grpc::string GetMockIncludes(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + + static const char *headers_strs[] = { + "grpcpp/impl/codegen/async_stream.h", + "grpcpp/impl/codegen/sync_stream.h", + "gmock/gmock.h", + }; + std::vector headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params); + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + } + + printer->Print(vars, "\n"); + } + return output; +} + + +namespace { + +static void PrintMockClientMethods(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + struct { + grpc::string prefix; + grpc::string method_params; // extra arguments to method + int extra_method_param_count; + } async_prefixes[] = { { "Async", ", void* tag", 1 }, + { "PrepareAsync", "", 0 } }; + + if (method->NoStreaming()) { + printer->Print( + *vars, + "MOCK_METHOD3($Method$, ::grpc::Status(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response));\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "MOCK_METHOD3($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq));\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "MOCK_METHOD2($Method$Raw, " + "::grpc::ClientWriterInterface< $Request$>*" + "(::grpc::ClientContext* context, $Response$* response));\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + flatbuffers::NumToString(3 + async_prefix.extra_method_param_count); + printer->Print(*vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncWriterInterface< $Request$>*" + "(::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$));\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "MOCK_METHOD2($Method$Raw, " + "::grpc::ClientReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request));\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + flatbuffers::NumToString(3 + async_prefix.extra_method_param_count); + printer->Print( + *vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$));\n"); + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "MOCK_METHOD1($Method$Raw, " + "::grpc::ClientReaderWriterInterface< $Request$, $Response$>*" + "(::grpc::ClientContext* context));\n"); + for (size_t i = 0; i < sizeof(async_prefixes) / sizeof(async_prefixes[0]); + i++) { + auto &async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + flatbuffers::NumToString(2 + async_prefix.extra_method_param_count); + printer->Print( + *vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*" + "(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq" + "$AsyncMethodParams$));\n"); + } + } +} + +static void PrintMockService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, + std::map *vars) { + (*vars)["Service"] = service->name(); + + printer->Print(*vars, + "class Mock$Service$Stub : public $Service$::StubInterface {\n" + " public:\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + PrintMockClientMethods(printer, service->method(i).get(), vars); + } + printer->Outdent(); + printer->Print("};\n"); +} + +} // namespace + +grpc::string GetMockServices(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { vars["Package"].append("."); } + + if (!params.services_namespace.empty()) { + vars["services_namespace"] = params.services_namespace; + printer->Print(vars, "\nnamespace $services_namespace$ {\n\n"); + } + + for (int i = 0; i < file->service_count(); i++) { + PrintMockService(printer.get(), file->service(i).get(), &vars); + printer->Print("\n"); + } + + if (!params.services_namespace.empty()) { + printer->Print(vars, "} // namespace $services_namespace$\n\n"); + } + } + return output; +} + +grpc::string GetMockEpilogue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string temp; + + if (!file->package().empty()) { + std::vector parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + temp.append("} // namespace "); + temp.append(*part); + temp.append("\n"); + } + temp.append("\n"); + } + + return temp; +} + +} // namespace grpc_cpp_generator diff --git a/third_party/flatbuffers/grpc/src/compiler/cpp_generator.h b/third_party/flatbuffers/grpc/src/compiler/cpp_generator.h new file mode 100644 index 000000000..a9af1a679 --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/cpp_generator.h @@ -0,0 +1,106 @@ +#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 +#include + +#include "src/compiler/schema_interface.h" + +#ifndef GRPC_CUSTOM_STRING +# include +# 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; + // Generate GMOCK code to facilitate unit testing. + bool generate_mock_code; + // By default, use "_generated.h" + std::string message_header_extension; +}; + +// Return the prologue of the generated header file. +grpc::string GetHeaderPrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated header file. +grpc::string GetHeaderIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated source file. +grpc::string GetSourceIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of the generated header file. +grpc::string GetHeaderEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the prologue of the generated source file. +grpc::string GetSourcePrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated header file. +grpc::string GetHeaderServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated source file. +grpc::string GetSourceServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of the generated source file. +grpc::string GetSourceEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the prologue of the generated mock file. +grpc::string GetMockPrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated mock file. +grpc::string GetMockIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated mock file. +grpc::string GetMockServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of generated mock file. +grpc::string GetMockEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the prologue of the generated mock file. +grpc::string GetMockPrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated mock file. +grpc::string GetMockIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated mock file. +grpc::string GetMockServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of generated mock file. +grpc::string GetMockEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +} // namespace grpc_cpp_generator + +#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H diff --git a/third_party/flatbuffers/grpc/src/compiler/go_generator.cc b/third_party/flatbuffers/grpc/src/compiler/go_generator.cc new file mode 100644 index 000000000..ad4694b10 --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/go_generator.cc @@ -0,0 +1,507 @@ +#include "src/compiler/go_generator.h" + +#include +#include +#include + +template grpc::string as_string(T x) { + std::ostringstream out; + out << x; + return out.str(); +} + +inline bool ClientOnlyStreaming(const grpc_generator::Method *method) { + return method->ClientStreaming() && !method->ServerStreaming(); +} + +inline bool ServerOnlyStreaming(const grpc_generator::Method *method) { + return !method->ClientStreaming() && method->ServerStreaming(); +} + +namespace grpc_go_generator { +namespace { + +// Returns string with first letter to lowerCase +static grpc::string unexportName(grpc::string s) { + if (s.empty()) return s; + s[0] = static_cast(std::tolower(s[0])); + return s; +} + +// Returns string with first letter to uppercase +static grpc::string exportName(grpc::string s) { + if (s.empty()) return s; + s[0] = static_cast(std::toupper(s[0])); + return s; +} + +static void GenerateError(grpc_generator::Printer *printer, + std::map vars, + const bool multiple_return = true) { + printer->Print(vars, "if $Error_Check$ {\n"); + printer->Indent(); + vars["Return"] = multiple_return ? "nil, err" : "err"; + printer->Print(vars, "return $Return$\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +// Generates imports for the service +static void GenerateImports(grpc_generator::File *file, + grpc_generator::Printer *printer, + std::map vars) { + vars["filename"] = file->filename(); + printer->Print("//Generated by gRPC Go plugin\n"); + printer->Print("//If you make any local changes, they will be lost\n"); + printer->Print(vars, "//source: $filename$\n\n"); + printer->Print(vars, "package $Package$\n\n"); + printer->Print("import (\n"); + printer->Indent(); + printer->Print(vars, "$context$ \"context\"\n"); + printer->Print("flatbuffers \"github.com/google/flatbuffers/go\"\n"); + printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n"); + printer->Print("\"google.golang.org/grpc/codes\"\n"); + printer->Print("\"google.golang.org/grpc/status\"\n"); + printer->Outdent(); + printer->Print(")\n\n"); +} + +// Generates Server method signature source +static void GenerateServerMethodSignature(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map vars) { + vars["Method"] = exportName(method->name()); + vars["Request"] = method->get_input_type_name(); + vars["Response"] = (vars["CustomMethodIO"] == "") + ? method->get_output_type_name() + : vars["CustomMethodIO"]; + if (method->NoStreaming()) { + printer->Print( + vars, + "$Method$($context$.Context, *$Request$) (*$Response$, error)$Ending$"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + vars, "$Method$(*$Request$, $Service$_$Method$Server) error$Ending$"); + } else { + printer->Print(vars, "$Method$($Service$_$Method$Server) error$Ending$"); + } +} + +static void GenerateServerMethod(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map vars) { + vars["Method"] = exportName(method->name()); + vars["Request"] = method->get_input_type_name(); + vars["Response"] = (vars["CustomMethodIO"] == "") + ? method->get_output_type_name() + : vars["CustomMethodIO"]; + vars["FullMethodName"] = + "/" + vars["ServicePrefix"] + vars["Service"] + "/" + vars["Method"]; + vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; + if (method->NoStreaming()) { + printer->Print( + vars, + "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec " + "func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) " + "(interface{}, error) {\n"); + printer->Indent(); + printer->Print(vars, "in := new($Request$)\n"); + vars["Error_Check"] = "err := dec(in); err != nil"; + GenerateError(printer, vars); + printer->Print("if interceptor == nil {\n"); + printer->Indent(); + printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, in)\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n"); + printer->Indent(); + printer->Print("Server: srv,\n"); + printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Outdent(); + printer->Print("\n"); + printer->Indent(); + printer->Print(vars, + "handler := func(ctx $context$.Context, req interface{}) " + "(interface{}, error) {\n"); + printer->Indent(); + printer->Print( + vars, "return srv.($Service$Server).$Method$(ctx, req.(*$Request$))\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print("return interceptor(ctx, in, info, handler)\n"); + printer->Outdent(); + printer->Print("}\n"); + return; + } + vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server"; + printer->Print( + vars, + "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n"); + printer->Indent(); + if (ServerOnlyStreaming(method)) { + printer->Print(vars, "m := new($Request$)\n"); + vars["Error_Check"] = "err := stream.RecvMsg(m); err != nil"; + GenerateError(printer, vars, false); + printer->Print( + vars, + "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n"); + } else { + printer->Print( + vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n"); + } + printer->Outdent(); + printer->Print("}\n\n"); + + bool genSend = method->BidiStreaming() || ServerOnlyStreaming(method); + bool genRecv = method->BidiStreaming() || ClientOnlyStreaming(method); + bool genSendAndClose = ClientOnlyStreaming(method); + + printer->Print(vars, "type $Service$_$Method$Server interface {\n"); + printer->Indent(); + if (genSend) { printer->Print(vars, "Send(*$Response$) error\n"); } + if (genRecv) { printer->Print(vars, "Recv() (*$Request$, error)\n"); } + if (genSendAndClose) { + printer->Print(vars, "SendAndClose(*$Response$) error\n"); + } + printer->Print(vars, "$grpc$.ServerStream\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + printer->Print(vars, "type $StreamType$ struct {\n"); + printer->Indent(); + printer->Print(vars, "$grpc$.ServerStream\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + if (genSend) { + printer->Print(vars, + "func (x *$StreamType$) Send(m *$Response$) error {\n"); + printer->Indent(); + printer->Print("return x.ServerStream.SendMsg(m)\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + if (genRecv) { + printer->Print(vars, + "func (x *$StreamType$) Recv() (*$Request$, error) {\n"); + printer->Indent(); + printer->Print(vars, "m := new($Request$)\n"); + vars["Error_Check"] = "err := x.ServerStream.RecvMsg(m); err != nil"; + GenerateError(printer, vars); + printer->Print("return m, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + if (genSendAndClose) { + printer->Print( + vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n"); + printer->Indent(); + printer->Print("return x.ServerStream.SendMsg(m)\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } +} + +// Generates Client method signature source +static void GenerateClientMethodSignature(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map vars) { + vars["Method"] = exportName(method->name()); + vars["Request"] = + ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() + : vars["CustomMethodIO"]); + if (ClientOnlyStreaming(method) || method->BidiStreaming()) { + vars["Request"] = ""; + } + vars["Response"] = "*" + method->get_output_type_name(); + if (ClientOnlyStreaming(method) || method->BidiStreaming() || + ServerOnlyStreaming(method)) { + vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client"; + } + printer->Print(vars, + "$Method$(ctx $context$.Context$Request$,\n\topts " + "...$grpc$.CallOption) ($Response$, error)$Ending$"); +} + +// Generates Client method source +static void GenerateClientMethod(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map vars) { + printer->Print(vars, "func (c *$ServiceUnexported$Client) "); + vars["Ending"] = " {\n"; + GenerateClientMethodSignature(method, printer, vars); + printer->Indent(); + vars["Method"] = exportName(method->name()); + vars["Request"] = (vars["CustomMethodIO"] == "") + ? method->get_input_type_name() + : vars["CustomMethodIO"]; + vars["Response"] = method->get_output_type_name(); + vars["FullMethodName"] = + "/" + vars["ServicePrefix"] + vars["Service"] + "/" + vars["Method"]; + if (method->NoStreaming()) { + printer->Print(vars, "out := new($Response$)\n"); + printer->Print( + vars, + "err := c.cc.Invoke(ctx, \"$FullMethodName$\", in, out, opts...)\n"); + vars["Error_Check"] = "err != nil"; + GenerateError(printer, vars); + printer->Print("return out, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + return; + } + vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client"; + printer->Print(vars, + "stream, err := c.cc.NewStream(ctx, &$MethodDesc$, " + "\"$FullMethodName$\", opts...)\n"); + vars["Error_Check"] = "err != nil"; + GenerateError(printer, vars); + + printer->Print(vars, "x := &$StreamType${stream}\n"); + if (ServerOnlyStreaming(method)) { + vars["Error_Check"] = "err := x.ClientStream.SendMsg(in); err != nil"; + GenerateError(printer, vars); + vars["Error_Check"] = "err := x.ClientStream.CloseSend(); err != nil"; + GenerateError(printer, vars); + } + printer->Print("return x, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + bool genSend = method->BidiStreaming() || ClientOnlyStreaming(method); + bool genRecv = method->BidiStreaming() || ServerOnlyStreaming(method); + bool genCloseAndRecv = ClientOnlyStreaming(method); + + // Stream interface + printer->Print(vars, "type $Service$_$Method$Client interface {\n"); + printer->Indent(); + if (genSend) { printer->Print(vars, "Send(*$Request$) error\n"); } + if (genRecv) { printer->Print(vars, "Recv() (*$Response$, error)\n"); } + if (genCloseAndRecv) { + printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n"); + } + printer->Print(vars, "$grpc$.ClientStream\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + // Stream Client + printer->Print(vars, "type $StreamType$ struct {\n"); + printer->Indent(); + printer->Print(vars, "$grpc$.ClientStream\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + if (genSend) { + printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n"); + printer->Indent(); + printer->Print("return x.ClientStream.SendMsg(m)\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + + if (genRecv) { + printer->Print(vars, + "func (x *$StreamType$) Recv() (*$Response$, error) {\n"); + printer->Indent(); + printer->Print(vars, "m := new($Response$)\n"); + vars["Error_Check"] = "err := x.ClientStream.RecvMsg(m); err != nil"; + GenerateError(printer, vars); + printer->Print("return m, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + + if (genCloseAndRecv) { + printer->Print( + vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n"); + printer->Indent(); + vars["Error_Check"] = "err := x.ClientStream.CloseSend(); err != nil"; + GenerateError(printer, vars); + printer->Print(vars, "m := new($Response$)\n"); + vars["Error_Check"] = "err := x.ClientStream.RecvMsg(m); err != nil"; + GenerateError(printer, vars); + printer->Print("return m, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } +} + +// Generates client API for the service +void GenerateService(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map vars) { + vars["Service"] = exportName(service->name()); + // Client Interface + printer->Print(vars, "// Client API for $Service$ service\n"); + printer->Print(vars, "type $Service$Client interface {\n"); + printer->Indent(); + vars["Ending"] = "\n"; + for (int i = 0; i < service->method_count(); i++) { + GenerateClientMethodSignature(service->method(i).get(), printer, vars); + } + printer->Outdent(); + printer->Print("}\n\n"); + + // Client structure + vars["ServiceUnexported"] = unexportName(vars["Service"]); + printer->Print(vars, "type $ServiceUnexported$Client struct {\n"); + printer->Indent(); + printer->Print(vars, "cc $grpc$.ClientConnInterface\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + // NewClient + printer->Print(vars, + "func New$Service$Client(cc $grpc$.ClientConnInterface) " + "$Service$Client {\n"); + printer->Indent(); + printer->Print(vars, "return &$ServiceUnexported$Client{cc}"); + printer->Outdent(); + printer->Print("\n}\n\n"); + + int unary_methods = 0, streaming_methods = 0; + vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc"; + for (int i = 0; i < service->method_count(); i++) { + auto method = service->method(i); + if (method->NoStreaming()) { + vars["MethodDesc"] = + vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]"; + unary_methods++; + } else { + vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + + as_string(streaming_methods) + "]"; + streaming_methods++; + } + GenerateClientMethod(method.get(), printer, vars); + } + + // Server Interface + printer->Print(vars, "// Server API for $Service$ service\n"); + printer->Print(vars, "type $Service$Server interface {\n"); + printer->Indent(); + vars["Ending"] = "\n"; + for (int i = 0; i < service->method_count(); i++) { + GenerateServerMethodSignature(service->method(i).get(), printer, vars); + } + printer->Print(vars, "mustEmbedUnimplemented$Service$Server()\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + printer->Print(vars, "type Unimplemented$Service$Server struct {\n"); + printer->Print("}\n\n"); + + vars["Ending"] = " {\n"; + for (int i = 0; i < service->method_count(); i++) { + auto method = service->method(i); + vars["Method"] = exportName(method->name()); + vars["Nil"] = method->NoStreaming() ? "nil, " : ""; + printer->Print(vars, "func (Unimplemented$Service$Server) "); + GenerateServerMethodSignature(method.get(), printer, vars); + printer->Indent(); + printer->Print(vars, + "return $Nil$status.Errorf(codes.Unimplemented, \"method " + "$Method$ not implemented\")\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print("\n"); + } + + printer->Print(vars, + "func (Unimplemented$Service$Server) " + "mustEmbedUnimplemented$Service$Server() {}"); + printer->Print("\n\n"); + + printer->Print(vars, "type Unsafe$Service$Server interface {\n"); + printer->Indent(); + printer->Print(vars, "mustEmbedUnimplemented$Service$Server()\n"); + printer->Outdent(); + printer->Print("}\n\n"); + // Server registration. + printer->Print(vars, + "func Register$Service$Server(s $grpc$.ServiceRegistrar, srv " + "$Service$Server) {\n"); + printer->Indent(); + printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + for (int i = 0; i < service->method_count(); i++) { + GenerateServerMethod(service->method(i).get(), printer, vars); + } + + // Service Descriptor + printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n"); + printer->Indent(); + printer->Print(vars, "ServiceName: \"$ServicePrefix$$Service$\",\n"); + printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n"); + printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); i++) { + auto method = service->method(i); + vars["Method"] = exportName(method->name()); + vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; + if (method->NoStreaming()) { + printer->Print("{\n"); + printer->Indent(); + printer->Print(vars, "MethodName: \"$Method$\",\n"); + printer->Print(vars, "Handler: $Handler$,\n"); + printer->Outdent(); + printer->Print("},\n"); + } + } + printer->Outdent(); + printer->Print("},\n"); + printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); i++) { + auto method = service->method(i); + vars["Method"] = exportName(method->name()); + vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; + if (!method->NoStreaming()) { + printer->Print("{\n"); + printer->Indent(); + printer->Print(vars, "StreamName: \"$Method$\",\n"); + printer->Print(vars, "Handler: $Handler$,\n"); + if (ClientOnlyStreaming(method.get())) { + printer->Print("ClientStreams: true,\n"); + } else if (ServerOnlyStreaming(method.get())) { + printer->Print("ServerStreams: true,\n"); + } else { + printer->Print("ServerStreams: true,\n"); + printer->Print("ClientStreams: true,\n"); + } + printer->Outdent(); + printer->Print("},\n"); + } + } + printer->Outdent(); + printer->Print("},\n"); + printer->Outdent(); + printer->Print("}\n"); +} +} // namespace + +// Returns source for the service +grpc::string GenerateServiceSource(grpc_generator::File *file, + const grpc_generator::Service *service, + grpc_go_generator::Parameters *parameters) { + grpc::string out; + auto p = file->CreatePrinter(&out, '\t'); + p->SetIndentationSize(1); + auto printer = p.get(); + std::map vars; + vars["Package"] = parameters->package_name; + vars["ServicePrefix"] = parameters->service_prefix; + if (!parameters->service_prefix.empty()) vars["ServicePrefix"].append("."); + vars["grpc"] = "grpc"; + vars["context"] = "context"; + GenerateImports(file, printer, vars); + if (parameters->custom_method_io_type != "") { + vars["CustomMethodIO"] = parameters->custom_method_io_type; + } + GenerateService(service, printer, vars); + return out; +} +} // Namespace grpc_go_generator diff --git a/third_party/flatbuffers/grpc/src/compiler/go_generator.h b/third_party/flatbuffers/grpc/src/compiler/go_generator.h new file mode 100644 index 000000000..766e100c5 --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/go_generator.h @@ -0,0 +1,33 @@ +#ifndef GRPC_INTERNAL_COMPILER_GO_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_GO_GENERATOR_H + +// go generator is used to generate GRPC code for serialization system, such as +// flatbuffers +#include +#include + +#include "src/compiler/schema_interface.h" + +namespace grpc_go_generator { + +struct Parameters { + // Defines the custom parameter types for methods + // eg: flatbuffers uses flatbuffers.Builder as input for the client and output + // for the server + grpc::string custom_method_io_type; + + // Package name for the service + grpc::string package_name; + + // Prefix for RPC Calls + grpc::string service_prefix; +}; + +// Return the source of the generated service file. +grpc::string GenerateServiceSource(grpc_generator::File *file, + const grpc_generator::Service *service, + grpc_go_generator::Parameters *parameters); + +} // namespace grpc_go_generator + +#endif // GRPC_INTERNAL_COMPILER_GO_GENERATOR_H diff --git a/third_party/flatbuffers/grpc/src/compiler/java_generator.cc b/third_party/flatbuffers/grpc/src/compiler/java_generator.cc new file mode 100644 index 000000000..bfe2b111d --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/java_generator.cc @@ -0,0 +1,1123 @@ +/* + * Copyright 2016 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 "src/compiler/java_generator.h" + +#include +#include +#include +#include +#include +#include + +#include "flatbuffers/util.h" +#define to_string flatbuffers::NumToString + +// Stringify helpers used solely to cast GRPC_VERSION +#ifndef STR +# define STR(s) # s +#endif + +#ifndef XSTR +# define XSTR(s) STR(s) +#endif + +typedef grpc_generator::Printer Printer; +typedef std::map VARS; +typedef grpc_generator::Service ServiceDescriptor; +typedef grpc_generator::CommentHolder + DescriptorType; // base class of all 'descriptors' +typedef grpc_generator::Method MethodDescriptor; + +namespace grpc_java_generator { +typedef std::string string; +namespace { +// Generates imports for the service +static void GenerateImports(grpc_generator::File *file, + grpc_generator::Printer *printer, VARS &vars) { + vars["filename"] = file->filename(); + printer->Print(vars, + "//Generated by flatc compiler (version $flatc_version$)\n"); + printer->Print("//If you make any local changes, they will be lost\n"); + printer->Print(vars, "//source: $filename$.fbs\n\n"); + printer->Print(vars, "package $Package$;\n\n"); + vars["Package"] = vars["Package"] + "."; + if (!file->additional_headers().empty()) { + printer->Print(file->additional_headers().c_str()); + printer->Print("\n\n"); + } +} + +// Adjust a method name prefix identifier to follow the JavaBean spec: +// - decapitalize the first letter +// - remove embedded underscores & capitalize the following letter +static string MixedLower(const string &word) { + string w; + w += static_cast(tolower(word[0])); + bool after_underscore = false; + for (size_t i = 1; i < word.length(); ++i) { + if (word[i] == '_') { + after_underscore = true; + } else { + w += after_underscore ? static_cast(toupper(word[i])) + : word[i]; + after_underscore = false; + } + } + return w; +} + +// Converts to the identifier to the ALL_UPPER_CASE format. +// - An underscore is inserted where a lower case letter is followed by an +// upper case letter. +// - All letters are converted to upper case +static string ToAllUpperCase(const string &word) { + string w; + for (size_t i = 0; i < word.length(); ++i) { + w += static_cast(toupper(word[i])); + if ((i < word.length() - 1) && islower(word[i]) && isupper(word[i + 1])) { + w += '_'; + } + } + return w; +} + +static inline string LowerMethodName(const MethodDescriptor *method) { + return MixedLower(method->name()); +} + +static inline string MethodPropertiesFieldName(const MethodDescriptor *method) { + return "METHOD_" + ToAllUpperCase(method->name()); +} + +static inline string MethodPropertiesGetterName( + const MethodDescriptor *method) { + return MixedLower("get_" + method->name() + "_method"); +} + +static inline string MethodIdFieldName(const MethodDescriptor *method) { + return "METHODID_" + ToAllUpperCase(method->name()); +} + +static inline string JavaClassName(VARS &vars, const string &name) { + // string name = google::protobuf::compiler::java::ClassName(desc); + return vars["Package"] + name; +} + +static inline string ServiceClassName(const string &service_name) { + return service_name + "Grpc"; +} + +// TODO(nmittler): Remove once protobuf includes javadoc methods in +// distribution. +template +static void GrpcSplitStringToIteratorUsing(const string &full, + const char *delim, ITR &result) { + // Optimize the common case where delim is a single character. + if (delim[0] != '\0' && delim[1] == '\0') { + char c = delim[0]; + const char *p = full.data(); + const char *end = p + full.size(); + while (p != end) { + if (*p == c) { + ++p; + } else { + const char *start = p; + while (++p != end && *p != c) + ; + *result++ = string(start, p - start); + } + } + return; + } + + string::size_type begin_index, end_index; + begin_index = full.find_first_not_of(delim); + while (begin_index != string::npos) { + end_index = full.find_first_of(delim, begin_index); + if (end_index == string::npos) { + *result++ = full.substr(begin_index); + return; + } + *result++ = full.substr(begin_index, (end_index - begin_index)); + begin_index = full.find_first_not_of(delim, end_index); + } +} + +static void GrpcSplitStringUsing(const string &full, const char *delim, + std::vector *result) { + std::back_insert_iterator> it(*result); + GrpcSplitStringToIteratorUsing(full, delim, it); +} + +static std::vector GrpcSplit(const string &full, const char *delim) { + std::vector result; + GrpcSplitStringUsing(full, delim, &result); + return result; +} + +// TODO(nmittler): Remove once protobuf includes javadoc methods in +// distribution. +static string GrpcEscapeJavadoc(const string &input) { + string result; + result.reserve(input.size() * 2); + + char prev = '*'; + + for (string::size_type i = 0; i < input.size(); i++) { + char c = input[i]; + switch (c) { + case '*': + // Avoid "/*". + if (prev == '/') { + result.append("*"); + } else { + result.push_back(c); + } + break; + case '/': + // Avoid "*/". + if (prev == '*') { + result.append("/"); + } else { + result.push_back(c); + } + break; + case '@': + // '@' starts javadoc tags including the @deprecated tag, which will + // cause a compile-time error if inserted before a declaration that + // does not have a corresponding @Deprecated annotation. + result.append("@"); + break; + case '<': + // Avoid interpretation as HTML. + result.append("<"); + break; + case '>': + // Avoid interpretation as HTML. + result.append(">"); + break; + case '&': + // Avoid interpretation as HTML. + result.append("&"); + break; + case '\\': + // Java interprets Unicode escape sequences anywhere! + result.append("\"); + break; + default: result.push_back(c); break; + } + + prev = c; + } + + return result; +} + +static std::vector GrpcGetDocLines(const string &comments) { + if (!comments.empty()) { + // TODO(kenton): Ideally we should parse the comment text as Markdown and + // write it back as HTML, but this requires a Markdown parser. For now + // we just use
 to get fixed-width text formatting.
+
+    // If the comment itself contains block comment start or end markers,
+    // HTML-escape them so that they don't accidentally close the doc comment.
+    string escapedComments = GrpcEscapeJavadoc(comments);
+
+    std::vector lines = GrpcSplit(escapedComments, "\n");
+    while (!lines.empty() && lines.back().empty()) { lines.pop_back(); }
+    return lines;
+  }
+  return std::vector();
+}
+
+static std::vector GrpcGetDocLinesForDescriptor(
+    const DescriptorType *descriptor) {
+  return descriptor->GetAllComments();
+  // return GrpcGetDocLines(descriptor->GetLeadingComments("///"));
+}
+
+static void GrpcWriteDocCommentBody(Printer *printer, VARS &vars,
+                                    const std::vector &lines,
+                                    bool surroundWithPreTag) {
+  if (!lines.empty()) {
+    if (surroundWithPreTag) { printer->Print(" * 
\n"); }
+
+    for (size_t i = 0; i < lines.size(); i++) {
+      // Most lines should start with a space.  Watch out for lines that start
+      // with a /, since putting that right after the leading asterisk will
+      // close the comment.
+      vars["line"] = lines[i];
+      if (!lines[i].empty() && lines[i][0] == '/') {
+        printer->Print(vars, " * $line$\n");
+      } else {
+        printer->Print(vars, " *$line$\n");
+      }
+    }
+
+    if (surroundWithPreTag) { printer->Print(" * 
\n"); } + } +} + +static void GrpcWriteDocComment(Printer *printer, VARS &vars, + const string &comments) { + printer->Print("/**\n"); + std::vector lines = GrpcGetDocLines(comments); + GrpcWriteDocCommentBody(printer, vars, lines, false); + printer->Print(" */\n"); +} + +static void GrpcWriteServiceDocComment(Printer *printer, VARS &vars, + const ServiceDescriptor *service) { + printer->Print("/**\n"); + std::vector lines = GrpcGetDocLinesForDescriptor(service); + GrpcWriteDocCommentBody(printer, vars, lines, true); + printer->Print(" */\n"); +} + +static void GrpcWriteMethodDocComment(Printer *printer, VARS &vars, + const MethodDescriptor *method) { + printer->Print("/**\n"); + std::vector lines = GrpcGetDocLinesForDescriptor(method); + GrpcWriteDocCommentBody(printer, vars, lines, true); + printer->Print(" */\n"); +} + +// outputs static singleton extractor for type stored in "extr_type" and +// "extr_type_name" vars +static void PrintTypeExtractor(Printer *p, VARS &vars) { + p->Print(vars, + "private static volatile FlatbuffersUtils.FBExtactor<$extr_type$> " + "extractorOf$extr_type_name$;\n" + "private static FlatbuffersUtils.FBExtactor<$extr_type$> " + "getExtractorOf$extr_type_name$() {\n" + " if (extractorOf$extr_type_name$ != null) return " + "extractorOf$extr_type_name$;\n" + " synchronized ($service_class_name$.class) {\n" + " if (extractorOf$extr_type_name$ != null) return " + "extractorOf$extr_type_name$;\n" + " extractorOf$extr_type_name$ = new " + "FlatbuffersUtils.FBExtactor<$extr_type$>() {\n" + " public $extr_type$ extract (ByteBuffer buffer) {\n" + " return " + "$extr_type$.getRootAs$extr_type_name$(buffer);\n" + " }\n" + " };\n" + " return extractorOf$extr_type_name$;\n" + " }\n" + "}\n\n"); +} +static void PrintMethodFields(Printer *p, VARS &vars, + const ServiceDescriptor *service) { + p->Print("// Static method descriptors that strictly reflect the proto.\n"); + vars["service_name"] = service->name(); + + // set of names of rpc input- and output- types that were already encountered. + // this is needed to avoid duplicating type extractor since it's possible that + // the same type is used as an input or output type of more than a single RPC + // method + std::set encounteredTypes; + + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + vars["arg_in_id"] = to_string(2L * i); // trying to make msvc 10 happy + vars["arg_out_id"] = to_string(2L * i + 1); + vars["method_name"] = method->name(); + vars["input_type_name"] = method->get_input_type_name(); + vars["output_type_name"] = method->get_output_type_name(); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + vars["method_field_name"] = MethodPropertiesFieldName(method.get()); + vars["method_new_field_name"] = MethodPropertiesGetterName(method.get()); + vars["method_method_name"] = MethodPropertiesGetterName(method.get()); + bool client_streaming = + method->ClientStreaming() || method->BidiStreaming(); + bool server_streaming = + method->ServerStreaming() || method->BidiStreaming(); + if (client_streaming) { + if (server_streaming) { + vars["method_type"] = "BIDI_STREAMING"; + } else { + vars["method_type"] = "CLIENT_STREAMING"; + } + } else { + if (server_streaming) { + vars["method_type"] = "SERVER_STREAMING"; + } else { + vars["method_type"] = "UNARY"; + } + } + + p->Print( + vars, + "@$ExperimentalApi$(\"https://github.com/grpc/grpc-java/issues/" + "1901\")\n" + "@$Deprecated$ // Use {@link #$method_method_name$()} instead. \n" + "public static final $MethodDescriptor$<$input_type$,\n" + " $output_type$> $method_field_name$ = $method_method_name$();\n" + "\n" + "private static volatile $MethodDescriptor$<$input_type$,\n" + " $output_type$> $method_new_field_name$;\n" + "\n"); + + if (encounteredTypes.insert(vars["input_type_name"]).second) { + vars["extr_type"] = vars["input_type"]; + vars["extr_type_name"] = vars["input_type_name"]; + PrintTypeExtractor(p, vars); + } + + if (encounteredTypes.insert(vars["output_type_name"]).second) { + vars["extr_type"] = vars["output_type"]; + vars["extr_type_name"] = vars["output_type_name"]; + PrintTypeExtractor(p, vars); + } + + p->Print( + vars, + "@$ExperimentalApi$(\"https://github.com/grpc/grpc-java/issues/" + "1901\")\n" + "public static $MethodDescriptor$<$input_type$,\n" + " $output_type$> $method_method_name$() {\n" + " $MethodDescriptor$<$input_type$, $output_type$> " + "$method_new_field_name$;\n" + " if (($method_new_field_name$ = " + "$service_class_name$.$method_new_field_name$) == null) {\n" + " synchronized ($service_class_name$.class) {\n" + " if (($method_new_field_name$ = " + "$service_class_name$.$method_new_field_name$) == null) {\n" + " $service_class_name$.$method_new_field_name$ = " + "$method_new_field_name$ = \n" + " $MethodDescriptor$.<$input_type$, " + "$output_type$>newBuilder()\n" + " .setType($MethodType$.$method_type$)\n" + " .setFullMethodName(generateFullMethodName(\n" + " \"$Package$$service_name$\", \"$method_name$\"))\n" + " .setSampledToLocalTracing(true)\n" + " .setRequestMarshaller(FlatbuffersUtils.marshaller(\n" + " $input_type$.class, " + "getExtractorOf$input_type_name$()))\n" + " .setResponseMarshaller(FlatbuffersUtils.marshaller(\n" + " $output_type$.class, " + "getExtractorOf$output_type_name$()))\n"); + + // vars["proto_method_descriptor_supplier"] = service->name() + + // "MethodDescriptorSupplier"; + p->Print(vars, " .setSchemaDescriptor(null)\n"); + //" .setSchemaDescriptor(new + //$proto_method_descriptor_supplier$(\"$method_name$\"))\n"); + + p->Print(vars, " .build();\n"); + p->Print(vars, + " }\n" + " }\n" + " }\n" + " return $method_new_field_name$;\n" + "}\n"); + + p->Print("\n"); + } +} +enum StubType { + ASYNC_INTERFACE = 0, + BLOCKING_CLIENT_INTERFACE = 1, + FUTURE_CLIENT_INTERFACE = 2, + BLOCKING_SERVER_INTERFACE = 3, + ASYNC_CLIENT_IMPL = 4, + BLOCKING_CLIENT_IMPL = 5, + FUTURE_CLIENT_IMPL = 6, + ABSTRACT_CLASS = 7, +}; + +enum CallType { ASYNC_CALL = 0, BLOCKING_CALL = 1, FUTURE_CALL = 2 }; + +static void PrintBindServiceMethodBody(Printer *p, VARS &vars, + const ServiceDescriptor *service); + +// Prints a client interface or implementation class, or a server interface. +static void PrintStub(Printer *p, VARS &vars, const ServiceDescriptor *service, + StubType type) { + const string service_name = service->name(); + vars["service_name"] = service_name; + vars["abstract_name"] = service_name + "ImplBase"; + string stub_name = service_name; + string client_name = service_name; + CallType call_type = ASYNC_CALL; + bool impl_base = false; + bool interface = false; + switch (type) { + case ABSTRACT_CLASS: + call_type = ASYNC_CALL; + impl_base = true; + break; + case ASYNC_CLIENT_IMPL: + call_type = ASYNC_CALL; + stub_name += "Stub"; + break; + case BLOCKING_CLIENT_INTERFACE: + interface = true; + FLATBUFFERS_FALLTHROUGH(); // fall thru + case BLOCKING_CLIENT_IMPL: + call_type = BLOCKING_CALL; + stub_name += "BlockingStub"; + client_name += "BlockingClient"; + break; + case FUTURE_CLIENT_INTERFACE: + interface = true; + FLATBUFFERS_FALLTHROUGH(); // fall thru + case FUTURE_CLIENT_IMPL: + call_type = FUTURE_CALL; + stub_name += "FutureStub"; + client_name += "FutureClient"; + break; + case ASYNC_INTERFACE: + call_type = ASYNC_CALL; + interface = true; + break; + default: + GRPC_CODEGEN_FAIL << "Cannot determine class name for StubType: " << type; + } + vars["stub_name"] = stub_name; + vars["client_name"] = client_name; + + // Class head + if (!interface) { GrpcWriteServiceDocComment(p, vars, service); } + if (impl_base) { + p->Print(vars, + "public static abstract class $abstract_name$ implements " + "$BindableService$ {\n"); + } else { + p->Print(vars, + "public static final class $stub_name$ extends " + "$AbstractStub$<$stub_name$> {\n"); + } + p->Indent(); + + // Constructor and build() method + if (!impl_base && !interface) { + p->Print(vars, "private $stub_name$($Channel$ channel) {\n"); + p->Indent(); + p->Print("super(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + p->Print(vars, + "private $stub_name$($Channel$ channel,\n" + " $CallOptions$ callOptions) {\n"); + p->Indent(); + p->Print("super(channel, callOptions);\n"); + p->Outdent(); + p->Print("}\n\n"); + p->Print(vars, + "@$Override$\n" + "protected $stub_name$ build($Channel$ channel,\n" + " $CallOptions$ callOptions) {\n"); + p->Indent(); + p->Print(vars, "return new $stub_name$(channel, callOptions);\n"); + p->Outdent(); + p->Print("}\n"); + } + + // RPC methods + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + vars["lower_method_name"] = LowerMethodName(&*method); + vars["method_method_name"] = MethodPropertiesGetterName(&*method); + bool client_streaming = + method->ClientStreaming() || method->BidiStreaming(); + bool server_streaming = + method->ServerStreaming() || method->BidiStreaming(); + + if (call_type == BLOCKING_CALL && client_streaming) { + // Blocking client interface with client streaming is not available + continue; + } + + if (call_type == FUTURE_CALL && (client_streaming || server_streaming)) { + // Future interface doesn't support streaming. + continue; + } + + // Method signature + p->Print("\n"); + // TODO(nmittler): Replace with WriteMethodDocComment once included by the + // protobuf distro. + if (!interface) { GrpcWriteMethodDocComment(p, vars, &*method); } + p->Print("public "); + switch (call_type) { + case BLOCKING_CALL: + GRPC_CODEGEN_CHECK(!client_streaming) + << "Blocking client interface with client streaming is unavailable"; + if (server_streaming) { + // Server streaming + p->Print(vars, + "$Iterator$<$output_type$> $lower_method_name$(\n" + " $input_type$ request)"); + } else { + // Simple RPC + p->Print(vars, + "$output_type$ $lower_method_name$($input_type$ request)"); + } + break; + case ASYNC_CALL: + if (client_streaming) { + // Bidirectional streaming or client streaming + p->Print(vars, + "$StreamObserver$<$input_type$> $lower_method_name$(\n" + " $StreamObserver$<$output_type$> responseObserver)"); + } else { + // Server streaming or simple RPC + p->Print(vars, + "void $lower_method_name$($input_type$ request,\n" + " $StreamObserver$<$output_type$> responseObserver)"); + } + break; + case FUTURE_CALL: + GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming) + << "Future interface doesn't support streaming. " + << "client_streaming=" << client_streaming << ", " + << "server_streaming=" << server_streaming; + p->Print(vars, + "$ListenableFuture$<$output_type$> $lower_method_name$(\n" + " $input_type$ request)"); + break; + } + + if (interface) { + p->Print(";\n"); + continue; + } + // Method body. + p->Print(" {\n"); + p->Indent(); + if (impl_base) { + switch (call_type) { + // NB: Skipping validation of service methods. If something is wrong, + // we wouldn't get to this point as compiler would return errors when + // generating service interface. + case ASYNC_CALL: + if (client_streaming) { + p->Print(vars, + "return " + "asyncUnimplementedStreamingCall($method_method_name$(), " + "responseObserver);\n"); + } else { + p->Print(vars, + "asyncUnimplementedUnaryCall($method_method_name$(), " + "responseObserver);\n"); + } + break; + default: break; + } + } else if (!interface) { + switch (call_type) { + case BLOCKING_CALL: + GRPC_CODEGEN_CHECK(!client_streaming) + << "Blocking client streaming interface is not available"; + if (server_streaming) { + vars["calls_method"] = "blockingServerStreamingCall"; + vars["params"] = "request"; + } else { + vars["calls_method"] = "blockingUnaryCall"; + vars["params"] = "request"; + } + p->Print(vars, + "return $calls_method$(\n" + " getChannel(), $method_method_name$(), " + "getCallOptions(), $params$);\n"); + break; + case ASYNC_CALL: + if (server_streaming) { + if (client_streaming) { + vars["calls_method"] = "asyncBidiStreamingCall"; + vars["params"] = "responseObserver"; + } else { + vars["calls_method"] = "asyncServerStreamingCall"; + vars["params"] = "request, responseObserver"; + } + } else { + if (client_streaming) { + vars["calls_method"] = "asyncClientStreamingCall"; + vars["params"] = "responseObserver"; + } else { + vars["calls_method"] = "asyncUnaryCall"; + vars["params"] = "request, responseObserver"; + } + } + vars["last_line_prefix"] = client_streaming ? "return " : ""; + p->Print(vars, + "$last_line_prefix$$calls_method$(\n" + " getChannel().newCall($method_method_name$(), " + "getCallOptions()), $params$);\n"); + break; + case FUTURE_CALL: + GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming) + << "Future interface doesn't support streaming. " + << "client_streaming=" << client_streaming << ", " + << "server_streaming=" << server_streaming; + vars["calls_method"] = "futureUnaryCall"; + p->Print(vars, + "return $calls_method$(\n" + " getChannel().newCall($method_method_name$(), " + "getCallOptions()), request);\n"); + break; + } + } + p->Outdent(); + p->Print("}\n"); + } + + if (impl_base) { + p->Print("\n"); + p->Print( + vars, + "@$Override$ public final $ServerServiceDefinition$ bindService() {\n"); + vars["instance"] = "this"; + PrintBindServiceMethodBody(p, vars, service); + p->Print("}\n"); + } + + p->Outdent(); + p->Print("}\n\n"); +} + +static bool CompareMethodClientStreaming( + const std::unique_ptr &method1, + const std::unique_ptr &method2) { + return method1->ClientStreaming() < method2->ClientStreaming(); +} + +// Place all method invocations into a single class to reduce memory footprint +// on Android. +static void PrintMethodHandlerClass(Printer *p, VARS &vars, + const ServiceDescriptor *service) { + // Sort method ids based on ClientStreaming() so switch tables are compact. + std::vector> sorted_methods( + service->method_count()); + for (int i = 0; i < service->method_count(); ++i) { + sorted_methods[i] = service->method(i); + } + stable_sort(sorted_methods.begin(), sorted_methods.end(), + CompareMethodClientStreaming); + for (size_t i = 0; i < sorted_methods.size(); i++) { + auto &method = sorted_methods[i]; + vars["method_id"] = to_string(i); + vars["method_id_name"] = MethodIdFieldName(&*method); + p->Print(vars, + "private static final int $method_id_name$ = $method_id$;\n"); + } + p->Print("\n"); + vars["service_name"] = service->name() + "ImplBase"; + p->Print(vars, + "private static final class MethodHandlers implements\n" + " io.grpc.stub.ServerCalls.UnaryMethod,\n" + " io.grpc.stub.ServerCalls.ServerStreamingMethod,\n" + " io.grpc.stub.ServerCalls.ClientStreamingMethod,\n" + " io.grpc.stub.ServerCalls.BidiStreamingMethod {\n" + " private final $service_name$ serviceImpl;\n" + " private final int methodId;\n" + "\n" + " MethodHandlers($service_name$ serviceImpl, int methodId) {\n" + " this.serviceImpl = serviceImpl;\n" + " this.methodId = methodId;\n" + " }\n\n"); + p->Indent(); + p->Print(vars, + "@$Override$\n" + "@java.lang.SuppressWarnings(\"unchecked\")\n" + "public void invoke(Req request, $StreamObserver$ " + "responseObserver) {\n" + " switch (methodId) {\n"); + p->Indent(); + p->Indent(); + + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (method->ClientStreaming() || method->BidiStreaming()) { continue; } + vars["method_id_name"] = MethodIdFieldName(&*method); + vars["lower_method_name"] = LowerMethodName(&*method); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + p->Print(vars, + "case $method_id_name$:\n" + " serviceImpl.$lower_method_name$(($input_type$) request,\n" + " ($StreamObserver$<$output_type$>) responseObserver);\n" + " break;\n"); + } + p->Print( + "default:\n" + " throw new AssertionError();\n"); + + p->Outdent(); + p->Outdent(); + p->Print( + " }\n" + "}\n\n"); + + p->Print(vars, + "@$Override$\n" + "@java.lang.SuppressWarnings(\"unchecked\")\n" + "public $StreamObserver$ invoke(\n" + " $StreamObserver$ responseObserver) {\n" + " switch (methodId) {\n"); + p->Indent(); + p->Indent(); + + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (!(method->ClientStreaming() || method->BidiStreaming())) { continue; } + vars["method_id_name"] = MethodIdFieldName(&*method); + vars["lower_method_name"] = LowerMethodName(&*method); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + p->Print( + vars, + "case $method_id_name$:\n" + " return ($StreamObserver$) serviceImpl.$lower_method_name$(\n" + " ($StreamObserver$<$output_type$>) responseObserver);\n"); + } + p->Print( + "default:\n" + " throw new AssertionError();\n"); + + p->Outdent(); + p->Outdent(); + p->Print( + " }\n" + "}\n"); + + p->Outdent(); + p->Print("}\n\n"); +} + +static void PrintGetServiceDescriptorMethod(Printer *p, VARS &vars, + const ServiceDescriptor *service) { + vars["service_name"] = service->name(); + // vars["proto_base_descriptor_supplier"] = service->name() + + // "BaseDescriptorSupplier"; vars["proto_file_descriptor_supplier"] = + // service->name() + "FileDescriptorSupplier"; + // vars["proto_method_descriptor_supplier"] = service->name() + + // "MethodDescriptorSupplier"; vars["proto_class_name"] = + // google::protobuf::compiler::java::ClassName(service->file()); + // p->Print( + // vars, + // "private static abstract class + // $proto_base_descriptor_supplier$\n" " implements + // $ProtoFileDescriptorSupplier$, + // $ProtoServiceDescriptorSupplier$ {\n" " + // $proto_base_descriptor_supplier$() {}\n" + // "\n" + // " @$Override$\n" + // " public com.google.protobuf.Descriptors.FileDescriptor + // getFileDescriptor() {\n" " return + // $proto_class_name$.getDescriptor();\n" " }\n" + // "\n" + // " @$Override$\n" + // " public com.google.protobuf.Descriptors.ServiceDescriptor + // getServiceDescriptor() {\n" " return + // getFileDescriptor().findServiceByName(\"$service_name$\");\n" + // " }\n" + // "}\n" + // "\n" + // "private static final class + // $proto_file_descriptor_supplier$\n" " extends + // $proto_base_descriptor_supplier$ {\n" " + // $proto_file_descriptor_supplier$() {}\n" + // "}\n" + // "\n" + // "private static final class + // $proto_method_descriptor_supplier$\n" " extends + // $proto_base_descriptor_supplier$\n" " implements + // $ProtoMethodDescriptorSupplier$ {\n" " private final + // String methodName;\n" + // "\n" + // " $proto_method_descriptor_supplier$(String methodName) + // {\n" " this.methodName = methodName;\n" " }\n" + // "\n" + // " @$Override$\n" + // " public com.google.protobuf.Descriptors.MethodDescriptor + // getMethodDescriptor() {\n" " return + // getServiceDescriptor().findMethodByName(methodName);\n" " + // }\n" + // "}\n\n"); + + p->Print( + vars, + "private static volatile $ServiceDescriptor$ serviceDescriptor;\n\n"); + + p->Print(vars, + "public static $ServiceDescriptor$ getServiceDescriptor() {\n"); + p->Indent(); + p->Print(vars, "$ServiceDescriptor$ result = serviceDescriptor;\n"); + p->Print("if (result == null) {\n"); + p->Indent(); + p->Print(vars, "synchronized ($service_class_name$.class) {\n"); + p->Indent(); + p->Print("result = serviceDescriptor;\n"); + p->Print("if (result == null) {\n"); + p->Indent(); + + p->Print(vars, + "serviceDescriptor = result = " + "$ServiceDescriptor$.newBuilder(SERVICE_NAME)"); + p->Indent(); + p->Indent(); + p->Print(vars, "\n.setSchemaDescriptor(null)"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + vars["method_method_name"] = MethodPropertiesGetterName(&*method); + p->Print(vars, "\n.addMethod($method_method_name$())"); + } + p->Print("\n.build();\n"); + p->Outdent(); + p->Outdent(); + + p->Outdent(); + p->Print("}\n"); + p->Outdent(); + p->Print("}\n"); + p->Outdent(); + p->Print("}\n"); + p->Print("return result;\n"); + p->Outdent(); + p->Print("}\n"); +} + +static void PrintBindServiceMethodBody(Printer *p, VARS &vars, + const ServiceDescriptor *service) { + vars["service_name"] = service->name(); + p->Indent(); + p->Print(vars, + "return " + "$ServerServiceDefinition$.builder(getServiceDescriptor())\n"); + p->Indent(); + p->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + vars["lower_method_name"] = LowerMethodName(&*method); + vars["method_method_name"] = MethodPropertiesGetterName(&*method); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + vars["method_id_name"] = MethodIdFieldName(&*method); + bool client_streaming = + method->ClientStreaming() || method->BidiStreaming(); + bool server_streaming = + method->ServerStreaming() || method->BidiStreaming(); + if (client_streaming) { + if (server_streaming) { + vars["calls_method"] = "asyncBidiStreamingCall"; + } else { + vars["calls_method"] = "asyncClientStreamingCall"; + } + } else { + if (server_streaming) { + vars["calls_method"] = "asyncServerStreamingCall"; + } else { + vars["calls_method"] = "asyncUnaryCall"; + } + } + p->Print(vars, ".addMethod(\n"); + p->Indent(); + p->Print(vars, + "$method_method_name$(),\n" + "$calls_method$(\n"); + p->Indent(); + p->Print(vars, + "new MethodHandlers<\n" + " $input_type$,\n" + " $output_type$>(\n" + " $instance$, $method_id_name$)))\n"); + p->Outdent(); + p->Outdent(); + } + p->Print(".build();\n"); + p->Outdent(); + p->Outdent(); + p->Outdent(); +} + +static void PrintService(Printer *p, VARS &vars, + const ServiceDescriptor *service, + bool disable_version) { + vars["service_name"] = service->name(); + vars["service_class_name"] = ServiceClassName(service->name()); + vars["grpc_version"] = ""; +#ifdef GRPC_VERSION + if (!disable_version) { + vars["grpc_version"] = " (version " XSTR(GRPC_VERSION) ")"; + } +#else + (void)disable_version; +#endif + // TODO(nmittler): Replace with WriteServiceDocComment once included by + // protobuf distro. + GrpcWriteServiceDocComment(p, vars, service); + p->Print(vars, + "@$Generated$(\n" + " value = \"by gRPC proto compiler$grpc_version$\",\n" + " comments = \"Source: $file_name$.fbs\")\n" + "public final class $service_class_name$ {\n\n"); + p->Indent(); + p->Print(vars, "private $service_class_name$() {}\n\n"); + + p->Print(vars, + "public static final String SERVICE_NAME = " + "\"$Package$$service_name$\";\n\n"); + + PrintMethodFields(p, vars, service); + + // TODO(nmittler): Replace with WriteDocComment once included by protobuf + // distro. + GrpcWriteDocComment( + p, vars, + " Creates a new async stub that supports all call types for the service"); + p->Print(vars, + "public static $service_name$Stub newStub($Channel$ channel) {\n"); + p->Indent(); + p->Print(vars, "return new $service_name$Stub(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + + // TODO(nmittler): Replace with WriteDocComment once included by protobuf + // distro. + GrpcWriteDocComment( + p, vars, + " Creates a new blocking-style stub that supports unary and streaming " + "output calls on the service"); + p->Print(vars, + "public static $service_name$BlockingStub newBlockingStub(\n" + " $Channel$ channel) {\n"); + p->Indent(); + p->Print(vars, "return new $service_name$BlockingStub(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + + // TODO(nmittler): Replace with WriteDocComment once included by protobuf + // distro. + GrpcWriteDocComment( + p, vars, + " Creates a new ListenableFuture-style stub that supports unary calls " + "on the service"); + p->Print(vars, + "public static $service_name$FutureStub newFutureStub(\n" + " $Channel$ channel) {\n"); + p->Indent(); + p->Print(vars, "return new $service_name$FutureStub(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + + PrintStub(p, vars, service, ABSTRACT_CLASS); + PrintStub(p, vars, service, ASYNC_CLIENT_IMPL); + PrintStub(p, vars, service, BLOCKING_CLIENT_IMPL); + PrintStub(p, vars, service, FUTURE_CLIENT_IMPL); + + PrintMethodHandlerClass(p, vars, service); + PrintGetServiceDescriptorMethod(p, vars, service); + p->Outdent(); + p->Print("}\n"); +} + +static void PrintStaticImports(Printer *p) { + p->Print( + "import java.nio.ByteBuffer;\n" + "import static " + "io.grpc.MethodDescriptor.generateFullMethodName;\n" + "import static " + "io.grpc.stub.ClientCalls.asyncBidiStreamingCall;\n" + "import static " + "io.grpc.stub.ClientCalls.asyncClientStreamingCall;\n" + "import static " + "io.grpc.stub.ClientCalls.asyncServerStreamingCall;\n" + "import static " + "io.grpc.stub.ClientCalls.asyncUnaryCall;\n" + "import static " + "io.grpc.stub.ClientCalls.blockingServerStreamingCall;\n" + "import static " + "io.grpc.stub.ClientCalls.blockingUnaryCall;\n" + "import static " + "io.grpc.stub.ClientCalls.futureUnaryCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncBidiStreamingCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncClientStreamingCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncServerStreamingCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncUnaryCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;\n\n"); +} + +static void GenerateService(const grpc_generator::Service *service, + grpc_generator::Printer *printer, VARS &vars, + bool disable_version) { + // All non-generated classes must be referred by fully qualified names to + // avoid collision with generated classes. + vars["String"] = "java.lang.String"; + vars["Deprecated"] = "java.lang.Deprecated"; + vars["Override"] = "java.lang.Override"; + vars["Channel"] = "io.grpc.Channel"; + vars["CallOptions"] = "io.grpc.CallOptions"; + vars["MethodType"] = "io.grpc.MethodDescriptor.MethodType"; + vars["ServerMethodDefinition"] = "io.grpc.ServerMethodDefinition"; + vars["BindableService"] = "io.grpc.BindableService"; + vars["ServerServiceDefinition"] = "io.grpc.ServerServiceDefinition"; + vars["ServiceDescriptor"] = "io.grpc.ServiceDescriptor"; + vars["ProtoFileDescriptorSupplier"] = + "io.grpc.protobuf.ProtoFileDescriptorSupplier"; + vars["ProtoServiceDescriptorSupplier"] = + "io.grpc.protobuf.ProtoServiceDescriptorSupplier"; + vars["ProtoMethodDescriptorSupplier"] = + "io.grpc.protobuf.ProtoMethodDescriptorSupplier"; + vars["AbstractStub"] = "io.grpc.stub.AbstractStub"; + vars["MethodDescriptor"] = "io.grpc.MethodDescriptor"; + vars["NanoUtils"] = "io.grpc.protobuf.nano.NanoUtils"; + vars["StreamObserver"] = "io.grpc.stub.StreamObserver"; + vars["Iterator"] = "java.util.Iterator"; + vars["Generated"] = "javax.annotation.Generated"; + vars["ListenableFuture"] = + "com.google.common.util.concurrent.ListenableFuture"; + vars["ExperimentalApi"] = "io.grpc.ExperimentalApi"; + + PrintStaticImports(printer); + + PrintService(printer, vars, service, disable_version); +} +} // namespace + +grpc::string GenerateServiceSource( + grpc_generator::File *file, const grpc_generator::Service *service, + grpc_java_generator::Parameters *parameters) { + grpc::string out; + auto printer = file->CreatePrinter(&out); + VARS vars; + vars["flatc_version"] = grpc::string( + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." FLATBUFFERS_STRING( + FLATBUFFERS_VERSION_MINOR) "." FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION)); + + vars["file_name"] = file->filename(); + + if (!parameters->package_name.empty()) { + vars["Package"] = parameters->package_name; // ServiceJavaPackage(service); + } + GenerateImports(file, &*printer, vars); + GenerateService(service, &*printer, vars, false); + return out; +} + +} // namespace grpc_java_generator diff --git a/third_party/flatbuffers/grpc/src/compiler/java_generator.h b/third_party/flatbuffers/grpc/src/compiler/java_generator.h new file mode 100644 index 000000000..b101fbf56 --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/java_generator.h @@ -0,0 +1,85 @@ +/* + * Copyright 2016 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. + */ + +#ifndef NET_GRPC_COMPILER_JAVA_GENERATOR_H_ +#define NET_GRPC_COMPILER_JAVA_GENERATOR_H_ + +#include // for abort() +#include +#include +#include + +#include "src/compiler/schema_interface.h" + +class LogMessageVoidify { + public: + LogMessageVoidify() {} + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) {} +}; + +class LogHelper { + std::ostream* os_; + + public: + LogHelper(std::ostream* os) : os_(os) {} +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning( \ + disable : 4722) // the flow of control terminates in a destructor + // (needed to compile ~LogHelper where destructor emits abort intentionally - + // inherited from grpc/java code generator). +#endif + ~LogHelper() { + *os_ << std::endl; + ::abort(); + } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + std::ostream& get_os() const { return *os_; } +}; + +// Abort the program after logging the mesage if the given condition is not +// true. Otherwise, do nothing. +#define GRPC_CODEGEN_CHECK(x) \ + (x) ? (void)0 \ + : LogMessageVoidify() & LogHelper(&std::cerr).get_os() \ + << "CHECK FAILED: " << __FILE__ << ":" \ + << __LINE__ << ": " + +// Abort the program after logging the mesage. +#define GRPC_CODEGEN_FAIL GRPC_CODEGEN_CHECK(false) + +namespace grpc_java_generator { +struct Parameters { + // //Defines the custom parameter types for methods + // //eg: flatbuffers uses flatbuffers.Builder as input for the client + // and output for the server grpc::string custom_method_io_type; + + // Package name for the service + grpc::string package_name; +}; + +// Return the source of the generated service file. +grpc::string GenerateServiceSource(grpc_generator::File* file, + const grpc_generator::Service* service, + grpc_java_generator::Parameters* parameters); + +} // namespace grpc_java_generator + +#endif // NET_GRPC_COMPILER_JAVA_GENERATOR_H_ diff --git a/third_party/flatbuffers/grpc/src/compiler/python_generator.cc b/third_party/flatbuffers/grpc/src/compiler/python_generator.cc new file mode 100644 index 000000000..d5f69e20e --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/python_generator.cc @@ -0,0 +1,151 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * 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 +#include + +#include "flatbuffers/util.h" +#include "src/compiler/python_generator.h" + +namespace grpc_python_generator { +namespace { + +static grpc::string GenerateMethodType(const grpc_generator::Method *method) { + + if (method->NoStreaming()) + return "unary_unary"; + + if (method->ServerStreaming()) + return "unary_stream"; + + if (method->ClientStreaming()) + return "stream_unary"; + + return "stream_stream"; +} + +grpc::string GenerateMethodInput(const grpc_generator::Method *method) { + + if (method->NoStreaming() || method->ServerStreaming()) + return "self, request, context"; + + return "self, request_iterator, context"; +} + +void GenerateStub(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "class $ServiceName$Stub(object):\n"); + printer->Indent(); + printer->Print("\"\"\" Interface exported by the server. \"\"\""); + printer->Print("\n\n"); + printer->Print("def __init__(self, channel):\n"); + printer->Indent(); + printer->Print("\"\"\" Constructor. \n\n"); + printer->Print("Args: \n"); + printer->Print("channel: A grpc.Channel. \n"); + printer->Print("\"\"\"\n\n"); + + for (int j = 0; j < service->method_count(); j++) { + auto method = service->method(j); + vars["MethodName"] = method->name(); + vars["MethodType"] = GenerateMethodType(&*method); + printer->Print(vars, "self.$MethodName$ = channel.$MethodType$(\n"); + printer->Indent(); + printer->Print(vars, "\"/$PATH$$ServiceName$/$MethodName$\"\n"); + printer->Print(")\n"); + printer->Outdent(); + printer->Print("\n"); + } + printer->Outdent(); + printer->Outdent(); + printer->Print("\n"); +} + +void GenerateServicer(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "class $ServiceName$Servicer(object):\n"); + printer->Indent(); + printer->Print("\"\"\" Interface exported by the server. \"\"\""); + printer->Print("\n\n"); + + for (int j = 0; j < service->method_count(); j++) { + auto method = service->method(j); + vars["MethodName"] = method->name(); + vars["MethodInput"] = GenerateMethodInput(&*method); + printer->Print(vars, "def $MethodName$($MethodInput$):\n"); + printer->Indent(); + printer->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n"); + printer->Print("context.set_details('Method not implemented!')\n"); + printer->Print("raise NotImplementedError('Method not implemented!')\n"); + printer->Outdent(); + printer->Print("\n\n"); + } + printer->Outdent(); + printer->Print("\n"); + +} + +void GenerateRegister(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "def add_$ServiceName$Servicer_to_server(servicer, server):\n"); + printer->Indent(); + printer->Print("rpc_method_handlers = {\n"); + printer->Indent(); + for (int j = 0; j < service->method_count(); j++) { + auto method = service->method(j); + vars["MethodName"] = method->name(); + vars["MethodType"] = GenerateMethodType(&*method); + printer->Print(vars, "'$MethodName$': grpc.$MethodType$_rpc_method_handler(\n"); + printer->Indent(); + printer->Print(vars, "servicer.$MethodName$\n"); + printer->Outdent(); + printer->Print("),\n"); + } + printer->Outdent(); + printer->Print("}\n"); + printer->Print(vars, "generic_handler = grpc.method_handlers_generic_handler(\n"); + printer->Indent(); + printer->Print(vars, "'$PATH$$ServiceName$', rpc_method_handlers)\n"); + printer->Outdent(); + printer->Print("server.add_generic_rpc_handlers((generic_handler,))"); + printer->Outdent(); + printer->Print("\n"); +} +} // namespace + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service) { + grpc::string output; + std::map vars; + vars["PATH"] = file->package(); + if (!file->package().empty()) { vars["PATH"].append("."); } + vars["ServiceName"] = service->name(); + auto printer = file->CreatePrinter(&output); + GenerateStub(service, &*printer, &vars); + GenerateServicer(service, &*printer, &vars); + GenerateRegister(service, &*printer, &vars); + return output; +} + +} // namespace grpc_python_generator diff --git a/third_party/flatbuffers/grpc/src/compiler/python_generator.h b/third_party/flatbuffers/grpc/src/compiler/python_generator.h new file mode 100644 index 000000000..40d29aada --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/python_generator.h @@ -0,0 +1,32 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * 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. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H + +#include + +#include "src/compiler/schema_interface.h" + +namespace grpc_python_generator { + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service); +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H diff --git a/third_party/flatbuffers/grpc/src/compiler/schema_interface.h b/third_party/flatbuffers/grpc/src/compiler/schema_interface.h new file mode 100644 index 000000000..f89288d75 --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/schema_interface.h @@ -0,0 +1,119 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * 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. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H +#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H + +#include +#include +#include + +#ifndef GRPC_CUSTOM_STRING +# include +# define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_generator { + +// A common interface for objects having comments in the source. +// Return formatted comments to be inserted in generated code. +struct CommentHolder { + virtual ~CommentHolder() {} + virtual grpc::string GetLeadingComments(const grpc::string prefix) const = 0; + virtual grpc::string GetTrailingComments(const grpc::string prefix) const = 0; + virtual std::vector GetAllComments() const = 0; +}; + +// An abstract interface representing a method. +struct Method : public CommentHolder { + 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 get_module_and_message_path_input( + grpc::string *str, grpc::string generator_file_name, + bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0; + virtual bool get_module_and_message_path_output( + grpc::string *str, grpc::string generator_file_name, + bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0; + + virtual std::vector get_input_namespace_parts() const = 0; + virtual grpc::string get_input_type_name() const = 0; + virtual std::vector get_output_namespace_parts() const = 0; + virtual grpc::string get_output_type_name() const = 0; + + virtual grpc::string get_fb_builder() const = 0; + + virtual bool NoStreaming() const = 0; + virtual bool ClientStreaming() const = 0; + virtual bool ServerStreaming() const = 0; + virtual bool BidiStreaming() const = 0; +}; + +// An abstract interface representing a service. +struct Service : public CommentHolder { + virtual ~Service() {} + + virtual std::vector namespace_parts() const = 0; + virtual grpc::string name() const = 0; + virtual bool is_internal() const = 0; + + virtual int method_count() const = 0; + virtual std::unique_ptr method(int i) const = 0; +}; + +struct Printer { + virtual ~Printer() {} + + virtual void Print(const std::map &vars, + const char *template_string) = 0; + virtual void Print(const char *string) = 0; + virtual void SetIndentationSize(const size_t size) = 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 : public CommentHolder { + virtual ~File() {} + + virtual grpc::string filename() const = 0; + virtual grpc::string filename_without_ext() const = 0; + virtual grpc::string package() const = 0; + virtual std::vector package_parts() const = 0; + virtual grpc::string additional_headers() const = 0; + + virtual int service_count() const = 0; + virtual std::unique_ptr service(int i) const = 0; + + virtual std::unique_ptr CreatePrinter( + grpc::string *str, const char indentation_type = ' ') const = 0; +}; +} // namespace grpc_generator + +#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H diff --git a/third_party/flatbuffers/grpc/src/compiler/swift_generator.cc b/third_party/flatbuffers/grpc/src/compiler/swift_generator.cc new file mode 100644 index 000000000..b0a96d869 --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/swift_generator.cc @@ -0,0 +1,440 @@ +/* + * Copyright 2020 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. + */ + +/* + * NOTE: The following implementation is a translation for the Swift-grpc + * generator since flatbuffers doesnt allow plugins for now. if an issue arises + * please open an issue in the flatbuffers repository. This file should always + * be maintained according to the Swift-grpc repository + */ +#include +#include + +#include "flatbuffers/util.h" +#include "src/compiler/schema_interface.h" +#include "src/compiler/swift_generator.h" + +namespace grpc_swift_generator { +namespace { + +static std::string WrapInNameSpace(const std::vector &components, + const grpc::string &name) { + std::string qualified_name; + for (auto it = components.begin(); it != components.end(); ++it) + qualified_name += *it + "_"; + return qualified_name + name; +} + +static grpc::string GenerateMessage(const std::vector &components, + const grpc::string &name) { + return "Message<" + WrapInNameSpace(components, name) + ">"; +} + +// MARK: - Client + +static void GenerateClientFuncName(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + if (method->NoStreaming()) { + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " _ request: $Input$\n" + " , callOptions: CallOptions?$isNil$\n" + " ) -> UnaryCall<$Input$, $Output$>"); + return; + } + + if (method->ServerStreaming()) { + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " _ request: $Input$\n" + " , callOptions: CallOptions?$isNil$,\n" + " handler: @escaping ($Output$) -> Void\n" + " ) -> ServerStreamingCall<$Input$, $Output$>"); + return; + } + + if (method->ClientStreaming()) { + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " callOptions: CallOptions?$isNil$\n" + " ) -> ClientStreamingCall<$Input$, $Output$>"); + return; + } + + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " callOptions: CallOptions?$isNil$,\n" + " handler: @escaping ($Output$ ) -> Void\n" + " ) -> BidirectionalStreamingCall<$Input$, $Output$>"); +} + +static void GenerateClientFuncBody(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + vars["Interceptor"] = + "interceptors: self.interceptors?.make$MethodName$Interceptors() ?? []"; + if (method->NoStreaming()) { + printer->Print( + vars, + " return self.makeUnaryCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " request: request,\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$\n" + " )\n"); + return; + } + + if (method->ServerStreaming()) { + printer->Print( + vars, + " return self.makeServerStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " request: request,\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$,\n" + " handler: handler\n" + " )\n"); + return; + } + + if (method->ClientStreaming()) { + printer->Print( + vars, + " return self.makeClientStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$\n" + " )\n"); + return; + } + printer->Print(vars, + " return self.makeBidirectionalStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$,\n" + " handler: handler\n" + " )\n"); +} + +void GenerateClientProtocol(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print( + vars, + "$ACCESS$ protocol $ServiceQualifiedName$ClientProtocol: GRPCClient {"); + printer->Print("\n\n"); + printer->Print(" var serviceName: String { get }"); + printer->Print("\n\n"); + printer->Print( + vars, + " var interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol? { get }"); + printer->Print("\n\n"); + + vars["GenAccess"] = ""; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + vars["isNil"] = ""; + GenerateClientFuncName(method.get(), &*printer, &vars); + printer->Print("\n\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, "extension $ServiceQualifiedName$ClientProtocol {"); + printer->Print("\n\n"); + printer->Print(vars, + " $ACCESS$ var serviceName: String { " + "\"$PATH$$ServiceName$\" }\n"); + + vars["GenAccess"] = service->is_internal() ? "internal " : "public "; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + vars["isNil"] = " = nil"; + printer->Print("\n"); + GenerateClientFuncName(method.get(), &*printer, &vars); + printer->Print(" {\n"); + GenerateClientFuncBody(method.get(), &*printer, &vars); + printer->Print(" }\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, + "$ACCESS$ protocol " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol {\n"); + + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print( + vars, + " /// - Returns: Interceptors to use when invoking '$MethodName$'.\n"); + printer->Print(vars, + " func make$MethodName$Interceptors() -> " + "[ClientInterceptor<$Input$, $Output$>]\n\n"); + } + printer->Print("}\n\n"); +} + +void GenerateClientClass(grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "$ACCESS$ final class $ServiceQualifiedName$ServiceClient: " + "$ServiceQualifiedName$ClientProtocol {\n"); + printer->Print(vars, " $ACCESS$ let channel: GRPCChannel\n"); + printer->Print(vars, " $ACCESS$ var defaultCallOptions: CallOptions\n"); + printer->Print(vars, + " $ACCESS$ var interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol?\n"); + printer->Print("\n"); + printer->Print( + vars, + " $ACCESS$ init(\n" + " channel: GRPCChannel,\n" + " defaultCallOptions: CallOptions = CallOptions(),\n" + " interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol? = nil\n" + " ) {\n"); + printer->Print(" self.channel = channel\n"); + printer->Print(" self.defaultCallOptions = defaultCallOptions\n"); + printer->Print(" self.interceptors = interceptors\n"); + printer->Print(" }"); + printer->Print("\n"); + printer->Print("}\n"); +} + +// MARK: - Server + +grpc::string GenerateServerFuncName(const grpc_generator::Method *method) { + if (method->NoStreaming()) { + return "func $MethodName$(request: $Input$" + ", context: StatusOnlyCallContext) -> EventLoopFuture<$Output$>"; + } + + if (method->ClientStreaming()) { + return "func $MethodName$(context: UnaryResponseCallContext<$Output$>) -> " + "EventLoopFuture<(StreamEvent<$Input$" + ">) -> Void>"; + } + + if (method->ServerStreaming()) { + return "func $MethodName$(request: $Input$" + ", context: StreamingResponseCallContext<$Output$>) -> " + "EventLoopFuture"; + } + return "func $MethodName$(context: StreamingResponseCallContext<$Output$>) " + "-> EventLoopFuture<(StreamEvent<$Input$>) -> Void>"; +} + +grpc::string GenerateServerExtensionBody(const grpc_generator::Method *method) { + grpc::string start = " case \"$MethodName$\":\n "; + grpc::string interceptors = + " interceptors: self.interceptors?.make$MethodName$Interceptors() " + "?? [],\n"; + if (method->NoStreaming()) { + return start + + "return UnaryServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " userFunction: self.$MethodName$(request:context:))\n"; + } + if (method->ServerStreaming()) { + return start + + "return ServerStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " userFunction: self.$MethodName$(request:context:))\n"; + } + if (method->ClientStreaming()) { + return start + + "return ClientStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " observerFactory: self.$MethodName$(context:))\n"; + } + if (method->BidiStreaming()) { + return start + + "return BidirectionalStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " observerFactory: self.$MethodName$(context:))\n"; + } + return ""; +} + +void GenerateServerProtocol(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "$ACCESS$ protocol $ServiceQualifiedName$Provider: " + "CallHandlerProvider {\n"); + printer->Print( + vars, + " var interceptors: " + "$ServiceQualifiedName$ServerInterceptorFactoryProtocol? { get }\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print(" "); + auto func = GenerateServerFuncName(method.get()); + printer->Print(vars, func.c_str()); + printer->Print("\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, "$ACCESS$ extension $ServiceQualifiedName$Provider {\n"); + printer->Print("\n"); + printer->Print(vars, + " var serviceName: Substring { return " + "\"$PATH$$ServiceName$\" }\n"); + printer->Print("\n"); + printer->Print( + " func handle(method name: Substring, context: " + "CallHandlerContext) -> GRPCServerHandlerProtocol? {\n"); + printer->Print(" switch name {\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + auto body = GenerateServerExtensionBody(method.get()); + printer->Print(vars, body.c_str()); + printer->Print("\n"); + } + printer->Print(" default: return nil;\n"); + printer->Print(" }\n"); + printer->Print(" }\n\n"); + printer->Print("}\n\n"); + + printer->Print(vars, + "$ACCESS$ protocol " + "$ServiceQualifiedName$ServerInterceptorFactoryProtocol {\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print( + vars, + " /// - Returns: Interceptors to use when handling '$MethodName$'.\n" + " /// Defaults to calling `self.makeInterceptors()`.\n"); + printer->Print(vars, + " func make$MethodName$Interceptors() -> " + "[ServerInterceptor<$Input$, $Output$>]\n\n"); + } + printer->Print("}"); +} +} // namespace + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service) { + grpc::string output; + std::map vars; + vars["PATH"] = file->package(); + if (!file->package().empty()) { vars["PATH"].append("."); } + vars["ServiceQualifiedName"] = + WrapInNameSpace(service->namespace_parts(), service->name()); + vars["ServiceName"] = service->name(); + vars["ACCESS"] = service->is_internal() ? "internal" : "public"; + auto printer = file->CreatePrinter(&output); + printer->Print( + vars, + "/// Usage: instantiate $ServiceQualifiedName$ServiceClient, then call " + "methods of this protocol to make API calls.\n"); + GenerateClientProtocol(service, &*printer, &vars); + GenerateClientClass(&*printer, &vars); + printer->Print("\n"); + GenerateServerProtocol(service, &*printer, &vars); + return output; +} + +grpc::string GenerateHeader() { + grpc::string code; + code += + "/// The following code is generated by the Flatbuffers library which " + "might not be in sync with grpc-swift\n"; + code += + "/// in case of an issue please open github issue, though it would be " + "maintained\n"; + code += "\n"; + code += "// swiftlint:disable all\n"; + code += "// swiftformat:disable all\n"; + code += "\n"; + code += "import Foundation\n"; + code += "import GRPC\n"; + code += "import NIO\n"; + code += "import NIOHTTP1\n"; + code += "import FlatBuffers\n"; + code += "\n"; + code += + "public protocol GRPCFlatBufPayload: GRPCPayload, FlatBufferGRPCMessage " + "{}\n"; + + code += "public extension GRPCFlatBufPayload {\n"; + code += " init(serializedByteBuffer: inout NIO.ByteBuffer) throws {\n"; + code += + " self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: " + "serializedByteBuffer.readableBytesView, count: " + "serializedByteBuffer.readableBytes))\n"; + code += " }\n"; + + code += " func serialize(into buffer: inout NIO.ByteBuffer) throws {\n"; + code += + " let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: " + "Int(self.size))\n"; + code += " buffer.writeBytes(buf)\n"; + code += " }\n"; + code += "}\n"; + code += "extension Message: GRPCFlatBufPayload {}\n"; + return code; +} +} // namespace grpc_swift_generator diff --git a/third_party/flatbuffers/grpc/src/compiler/swift_generator.h b/third_party/flatbuffers/grpc/src/compiler/swift_generator.h new file mode 100644 index 000000000..2a226fa94 --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/swift_generator.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 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 +#include + +#include "src/compiler/schema_interface.h" + +#ifndef GRPC_CUSTOM_STRING +# include +# define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_swift_generator { +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service); +grpc::string GenerateHeader(); +} // namespace grpc_swift_generator diff --git a/third_party/flatbuffers/grpc/src/compiler/ts_generator.cc b/third_party/flatbuffers/grpc/src/compiler/ts_generator.cc new file mode 100644 index 000000000..ff362b774 --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/ts_generator.cc @@ -0,0 +1,523 @@ +/* + * Copyright 2020 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. + */ + +/* + * NOTE: The following implementation is a translation for the Swift-grpc + * generator since flatbuffers doesnt allow plugins for now. if an issue arises + * please open an issue in the flatbuffers repository. This file should always + * be maintained according to the Swift-grpc repository + */ + +#include "src/compiler/ts_generator.h" + +#include +#include + +#include "flatbuffers/util.h" +#include "src/compiler/schema_interface.h" + +namespace grpc_ts_generator { +namespace { + +static grpc::string GenerateNamespace(const std::vector ns, + const std::string filename, + const bool include_separator) { + grpc::string path = ""; + if (include_separator) path += "."; + + for (auto it = ns.begin(); it < ns.end(); it++) { + if (include_separator) path += "/"; + path += include_separator + ? flatbuffers::ConvertCase(*it, flatbuffers::Case::kDasher, + flatbuffers::Case::kUpperCamel) + : *it + "_"; + } + + if (include_separator) path += "/"; + path += include_separator + ? flatbuffers::ConvertCase(filename, flatbuffers::Case::kDasher, + flatbuffers::Case::kUpperCamel) + : filename; + return path; +} + +// MARK: - Shared code + +static void GenerateImports(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary, + const bool grpc_var_import) { + auto vars = *dictonary; + printer->Print( + "// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***\n"); + printer->Print("import * as flatbuffers from 'flatbuffers';\n"); + + std::set generated_imports; + + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + auto output = method->get_output_type_name(); + auto input = method->get_input_type_name(); + auto input_namespace = method->get_input_namespace_parts(); + + vars["OUTPUT"] = output; + vars["INPUT"] = input; + + if (generated_imports.find(output) == generated_imports.end()) { + generated_imports.insert(output); + vars["OUTPUT_DIR"] = + GenerateNamespace(method->get_output_namespace_parts(), output, true); + vars["Output_alias"] = GenerateNamespace( + method->get_output_namespace_parts(), output, false); + printer->Print( + vars, "import { $OUTPUT$ as $Output_alias$ } from '$OUTPUT_DIR$';\n"); + } + if (generated_imports.find(input) == generated_imports.end()) { + generated_imports.insert(input); + vars["INPUT_DIR"] = + GenerateNamespace(method->get_output_namespace_parts(), input, true); + vars["Input_alias"] = + GenerateNamespace(method->get_output_namespace_parts(), input, false); + printer->Print( + vars, "import { $INPUT$ as $Input_alias$ } from '$INPUT_DIR$';\n"); + } + } + printer->Print("\n"); + if (grpc_var_import) + printer->Print("var grpc = require('@grpc/grpc-js');\n"); + else + printer->Print("import * as grpc from '@grpc/grpc-js';\n"); + printer->Print("\n"); +} + +// MARK: - Generate Main GRPC Code + +static void GetStreamType(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map *dictonary) { + auto vars = *dictonary; + auto client_streaming = method->ClientStreaming() || method->BidiStreaming(); + auto server_streaming = method->ServerStreaming() || method->BidiStreaming(); + vars["ClientStreaming"] = client_streaming ? "true" : "false"; + vars["ServerStreaming"] = server_streaming ? "true" : "false"; + printer->Print(vars, "requestStream: $ClientStreaming$,\n"); + printer->Print(vars, "responseStream: $ServerStreaming$,\n"); +} + +static void GenerateSerializeMethod(grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "function serialize_$Type$(buffer_args) {\n"); + printer->Indent(); + printer->Print(vars, "if (!(buffer_args instanceof $Type$)) {\n"); + printer->Indent(); + printer->Print(vars, + "throw new Error('Expected argument of type $VALUE$');\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print(vars, "return Buffer.from(buffer_args.serialize());\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +static void GenerateDeserializeMethod( + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "function deserialize_$Type$(buffer) {\n"); + printer->Indent(); + printer->Print(vars, + "return $Type$.getRootAs$VALUE$(new " + "flatbuffers.ByteBuffer(buffer))\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +static void GenerateMethods(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + + std::set generated_functions; + + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + auto output = method->get_output_type_name(); + auto input = method->get_input_type_name(); + + if (generated_functions.find(output) == generated_functions.end()) { + generated_functions.insert(output); + vars["VALUE"] = output; + vars["Type"] = GenerateNamespace(method->get_output_namespace_parts(), + output, false); + GenerateSerializeMethod(printer, &vars); + GenerateDeserializeMethod(printer, &vars); + } + printer->Print("\n"); + if (generated_functions.find(input) == generated_functions.end()) { + generated_functions.insert(input); + vars["VALUE"] = input; + vars["Type"] = + GenerateNamespace(method->get_input_namespace_parts(), input, false); + GenerateSerializeMethod(printer, &vars); + GenerateDeserializeMethod(printer, &vars); + } + } +} + +static void GenerateService(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + vars["NAME"] = service->name() + "Service"; + + printer->Print(vars, "var $NAME$ = exports.$NAME$ = {\n"); + printer->Indent(); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["MethodName"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + printer->Print(vars, "$MethodName$: {\n"); + printer->Indent(); + printer->Print(vars, "path: '/$PATH$$ServiceName$/$MethodName$',\n"); + GetStreamType(printer, &*method, &vars); + printer->Print(vars, "requestType: flatbuffers.ByteBuffer,\n"); + printer->Print(vars, "responseType: $OUTPUT$,\n"); + printer->Print(vars, "requestSerialize: serialize_$INPUT$,\n"); + printer->Print(vars, "requestDeserialize: deserialize_$INPUT$,\n"); + printer->Print(vars, "responseSerialize: serialize_$OUTPUT$,\n"); + printer->Print(vars, "responseDeserialize: deserialize_$OUTPUT$,\n"); + printer->Outdent(); + printer->Print("},\n"); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print(vars, + "exports.$ServiceName$Client = " + "grpc.makeGenericClientConstructor($NAME$);"); +} + +} // namespace + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service, + const grpc::string &filename) { + grpc::string output; + std::map vars; + + vars["PATH"] = file->package(); + + if (!file->package().empty()) { vars["PATH"].append("."); } + + vars["ServiceName"] = service->name(); + vars["FBSFile"] = service->name() + "_fbs"; + vars["Filename"] = filename; + auto printer = file->CreatePrinter(&output); + + GenerateImports(service, &*printer, &vars, true); + GenerateMethods(service, &*printer, &vars); + GenerateService(service, &*printer, &vars); + return output; +} + +namespace { + +// MARK: - Generate Interface + +static void FillInterface(grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "interface I$ServiceName$Service_I$MethodName$ extends " + "grpc.MethodDefinition<$INPUT$, $OUTPUT$> {\n"); + printer->Indent(); + printer->Print(vars, "path: string; // /$PATH$$ServiceName$/$MethodName$\n"); + printer->Print(vars, "requestStream: boolean; // $ClientStreaming$\n"); + printer->Print(vars, "responseStream: boolean; // $ServerStreaming$\n"); + printer->Print(vars, "requestSerialize: grpc.serialize<$INPUT$>;\n"); + printer->Print(vars, "requestDeserialize: grpc.deserialize<$INPUT$>;\n"); + printer->Print(vars, "responseSerialize: grpc.serialize<$OUTPUT$>;\n"); + printer->Print(vars, "responseDeserialize: grpc.deserialize<$OUTPUT$>;\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +static void GenerateInterfaces(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + auto client_streaming = + method->ClientStreaming() || method->BidiStreaming(); + auto server_streaming = + method->ServerStreaming() || method->BidiStreaming(); + vars["ClientStreaming"] = client_streaming ? "true" : "false"; + vars["ServerStreaming"] = server_streaming ? "true" : "false"; + vars["MethodName"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + FillInterface(printer, &vars); + printer->Print("\n"); + } +} + +static void GenerateExportedInterface( + const grpc_generator::Service *service, grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "export interface I$ServiceName$Server extends " + "grpc.UntypedServiceImplementation {\n"); + printer->Indent(); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Name"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + if (method->BidiStreaming()) { + printer->Print(vars, + "$Name$: grpc.handleBidiStreamingCall<$INPUT$, " + "$OUTPUT$>;\n"); + continue; + } + if (method->NoStreaming()) { + printer->Print(vars, + "$Name$: grpc.handleUnaryCall<$INPUT$, " + "$OUTPUT$>;\n"); + continue; + } + if (method->ClientStreaming()) { + printer->Print(vars, + "$Name$: grpc.handleClientStreamingCall<$INPUT$, " + "$OUTPUT$>;\n"); + continue; + } + if (method->ServerStreaming()) { + printer->Print(vars, + "$Name$: grpc.handleServerStreamingCall<$INPUT$, " + "$OUTPUT$>;\n"); + continue; + } + } + printer->Outdent(); + printer->Print("}\n"); +} + +static void GenerateMainInterface(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print( + vars, + "interface I$ServiceName$Service extends " + "grpc.ServiceDefinition {\n"); + printer->Indent(); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["MethodName"] = method->name(); + printer->Print(vars, + "$MethodName$: I$ServiceName$Service_I$MethodName$;\n"); + } + printer->Outdent(); + printer->Print("}\n"); + GenerateInterfaces(service, printer, &vars); + printer->Print("\n"); + printer->Print(vars, + "export const $ServiceName$Service: I$ServiceName$Service;\n"); + printer->Print("\n"); + GenerateExportedInterface(service, printer, &vars); +} + +static grpc::string GenerateMetaData() { return "metadata: grpc.Metadata"; } + +static grpc::string GenerateOptions() { return "options: Partial"; } + +static void GenerateUnaryClientInterface( + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + grpc::string main = "$ISPUBLIC$$MethodName$(request: $INPUT$, "; + grpc::string callback = + "callback: (error: grpc.ServiceError | null, response: " + "$OUTPUT$) => void): grpc.ClientUnaryCall;\n"; + auto meta_data = GenerateMetaData() + ", "; + auto options = GenerateOptions() + ", "; + printer->Print(vars, (main + callback).c_str()); + printer->Print(vars, (main + meta_data + callback).c_str()); + printer->Print(vars, (main + meta_data + options + callback).c_str()); +} + +static void GenerateClientWriteStreamInterface( + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + grpc::string main = "$ISPUBLIC$$MethodName$("; + grpc::string callback = + "callback: (error: grpc.ServiceError | null, response: " + "$INPUT$) => void): " + "grpc.ClientWritableStream<$OUTPUT$>;\n"; + auto meta_data = GenerateMetaData() + ", "; + auto options = GenerateOptions() + ", "; + printer->Print(vars, (main + callback).c_str()); + printer->Print(vars, (main + meta_data + callback).c_str()); + printer->Print(vars, (main + options + callback).c_str()); + printer->Print(vars, (main + meta_data + options + callback).c_str()); +} + +static void GenerateClientReadableStreamInterface( + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + grpc::string main = "$ISPUBLIC$$MethodName$(request: $INPUT$, "; + grpc::string end_function = "): grpc.ClientReadableStream<$OUTPUT$>;\n"; + auto meta_data = GenerateMetaData(); + auto options = GenerateOptions(); + printer->Print(vars, (main + meta_data + end_function).c_str()); + printer->Print(vars, (main + options + end_function).c_str()); +} + +static void GenerateDepluxStreamInterface( + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + grpc::string main = "$ISPUBLIC$$MethodName$("; + grpc::string end_function = + "): grpc.ClientDuplexStream<$INPUT$, $OUTPUT$>;\n"; + auto meta_data = GenerateMetaData(); + auto options = GenerateOptions(); + printer->Print(vars, (main + end_function).c_str()); + printer->Print(vars, (main + options + end_function).c_str()); + printer->Print(vars, (main + meta_data + + ", options?: Partial" + end_function) + .c_str()); +} + +static void GenerateClientInterface(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "export interface I$ServiceName$Client {\n"); + printer->Indent(); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["MethodName"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + vars["ISPUBLIC"] = ""; + + if (method->NoStreaming()) { + GenerateUnaryClientInterface(printer, &vars); + continue; + } + if (method->BidiStreaming()) { + GenerateDepluxStreamInterface(printer, &vars); + continue; + } + + if (method->ClientStreaming()) { + GenerateClientWriteStreamInterface(printer, &vars); + continue; + } + + if (method->ServerStreaming()) { + GenerateClientReadableStreamInterface(printer, &vars); + continue; + } + } + printer->Outdent(); + printer->Print("}\n"); +} + +static void GenerateClientClassInterface( + const grpc_generator::Service *service, grpc_generator::Printer *printer, + std::map *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "export class $ServiceName$Client extends grpc.Client " + "implements I$ServiceName$Client {\n"); + printer->Indent(); + printer->Print( + "constructor(address: string, credentials: grpc.ChannelCredentials, " + "options?: object);\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["MethodName"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + vars["ISPUBLIC"] = "public "; + if (method->NoStreaming()) { + GenerateUnaryClientInterface(printer, &vars); + continue; + } + if (method->BidiStreaming()) { + GenerateDepluxStreamInterface(printer, &vars); + continue; + } + + if (method->ClientStreaming()) { + GenerateClientWriteStreamInterface(printer, &vars); + continue; + } + + if (method->ServerStreaming()) { + GenerateClientReadableStreamInterface(printer, &vars); + continue; + } + } + printer->Outdent(); + printer->Print("}\n"); +} +} // namespace + + +grpc::string GenerateInterface(grpc_generator::File *file, + const grpc_generator::Service *service, + const grpc::string &filename) { + grpc::string output; + + std::set generated_functions; + std::map vars; + + vars["PATH"] = file->package(); + + if (!file->package().empty()) { vars["PATH"].append("."); } + + vars["ServiceName"] = service->name(); + vars["FBSFile"] = service->name() + "_fbs"; + vars["Filename"] = filename; + auto printer = file->CreatePrinter(&output); + + GenerateImports(service, &*printer, &vars, false); + GenerateMainInterface(service, &*printer, &vars); + printer->Print("\n"); + GenerateClientInterface(service, &*printer, &vars); + printer->Print("\n"); + GenerateClientClassInterface(service, &*printer, &vars); + return output; +} +} // namespace grpc_ts_generator diff --git a/third_party/flatbuffers/grpc/src/compiler/ts_generator.h b/third_party/flatbuffers/grpc/src/compiler/ts_generator.h new file mode 100644 index 000000000..a356659da --- /dev/null +++ b/third_party/flatbuffers/grpc/src/compiler/ts_generator.h @@ -0,0 +1,26 @@ +#include +#include +#include + +#include "src/compiler/schema_interface.h" + +#ifndef GRPC_CUSTOM_STRING +# include +# define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_ts_generator { +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service, + const grpc::string &filename); + +grpc::string GenerateInterface(grpc_generator::File *file, + const grpc_generator::Service *service, + const grpc::string &filename); +} // namespace grpc_ts_generator diff --git a/third_party/flatbuffers/grpc/tests/BUILD b/third_party/flatbuffers/grpc/tests/BUILD new file mode 100644 index 000000000..5d4023ec7 --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/BUILD @@ -0,0 +1,17 @@ +cc_test( + name = "grpc_test", + srcs = [ + "grpctest.cpp", + "message_builder_test.cpp", + ], + copts = ["-Itests"], + # This is required. + linkstatic = 1, + deps = [ + "//tests:monster_test_cc_fbs", + "//tests:monster_test_grpc", + "//tests:test_assert", + "//tests:test_builder", + "@com_github_grpc_grpc//:grpc++", + ], +) diff --git a/third_party/flatbuffers/grpc/tests/GameFactory.java b/third_party/flatbuffers/grpc/tests/GameFactory.java new file mode 100644 index 000000000..520ae3920 --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/GameFactory.java @@ -0,0 +1,42 @@ +import java.nio.ByteBuffer; +import MyGame.Example.Monster; +import MyGame.Example.Stat; +import com.google.flatbuffers.FlatBufferBuilder; + +class GameFactory { + public static Monster createMonster(String monsterName, short nestedMonsterHp, short nestedMonsterMana) { + FlatBufferBuilder builder = new FlatBufferBuilder(); + + int name_offset = builder.createString(monsterName); + Monster.startMonster(builder); + Monster.addName(builder, name_offset); + Monster.addHp(builder, nestedMonsterHp); + Monster.addMana(builder, nestedMonsterMana); + int monster_offset = Monster.endMonster(builder); + Monster.finishMonsterBuffer(builder, monster_offset); + + ByteBuffer buffer = builder.dataBuffer(); + Monster monster = Monster.getRootAsMonster(buffer); + return monster; + } + + public static Monster createMonsterFromStat(Stat stat, int seqNo) { + FlatBufferBuilder builder = new FlatBufferBuilder(); + int name_offset = builder.createString(stat.id() + " No." + seqNo); + Monster.startMonster(builder); + Monster.addName(builder, name_offset); + int monster_offset = Monster.endMonster(builder); + Monster.finishMonsterBuffer(builder, monster_offset); + Monster monster = Monster.getRootAsMonster(builder.dataBuffer()); + return monster; + } + + public static Stat createStat(String greeting, long val, int count) { + FlatBufferBuilder builder = new FlatBufferBuilder(); + int statOffset = Stat.createStat(builder, builder.createString(greeting), val, count); + builder.finish(statOffset); + Stat stat = Stat.getRootAsStat(builder.dataBuffer()); + return stat; + } + +} diff --git a/third_party/flatbuffers/grpc/tests/JavaGrpcTest.java b/third_party/flatbuffers/grpc/tests/JavaGrpcTest.java new file mode 100644 index 000000000..273291161 --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/JavaGrpcTest.java @@ -0,0 +1,242 @@ +/* + * 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. + */ + +import MyGame.Example.Monster; +import MyGame.Example.MonsterStorageGrpc; +import MyGame.Example.Stat; +import com.google.flatbuffers.FlatBufferBuilder; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.stub.StreamObserver; +import org.junit.Assert; + +import java.io.IOException; +import java.lang.InterruptedException; +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.CountDownLatch; + + +/** + * Demonstrates basic client-server interaction using grpc-java over netty. + */ +public class JavaGrpcTest { + static final String BIG_MONSTER_NAME = "Cyberdemon"; + static final short nestedMonsterHp = 600; + static final short nestedMonsterMana = 1024; + static final int numStreamedMsgs = 10; + static final int timeoutMs = 3000; + static Server server; + static ManagedChannel channel; + static MonsterStorageGrpc.MonsterStorageBlockingStub blockingStub; + static MonsterStorageGrpc.MonsterStorageStub asyncStub; + + static class MyService extends MonsterStorageGrpc.MonsterStorageImplBase { + @Override + public void store(Monster request, io.grpc.stub.StreamObserver responseObserver) { + Assert.assertEquals(request.name(), BIG_MONSTER_NAME); + Assert.assertEquals(request.hp(), nestedMonsterHp); + Assert.assertEquals(request.mana(), nestedMonsterMana); + System.out.println("Received store request from " + request.name()); + // Create a response from the incoming request name. + Stat stat = GameFactory.createStat("Hello " + request.name(), 100, 10); + responseObserver.onNext(stat); + responseObserver.onCompleted(); + } + + @Override + public void retrieve(Stat request, io.grpc.stub.StreamObserver responseObserver) { + // Create 10 monsters for streaming response. + for (int i=0; i getMaxHitPoint(final StreamObserver responseObserver) { + return computeMinMax(responseObserver, false); + } + + @Override + public StreamObserver getMinMaxHitPoints(final StreamObserver responseObserver) { + return computeMinMax(responseObserver, true); + } + + private StreamObserver computeMinMax(final StreamObserver responseObserver, final boolean includeMin) { + final AtomicInteger maxHp = new AtomicInteger(Integer.MIN_VALUE); + final AtomicReference maxHpMonsterName = new AtomicReference(); + final AtomicInteger maxHpCount = new AtomicInteger(); + + final AtomicInteger minHp = new AtomicInteger(Integer.MAX_VALUE); + final AtomicReference minHpMonsterName = new AtomicReference(); + final AtomicInteger minHpCount = new AtomicInteger(); + + return new StreamObserver() { + public void onNext(Monster monster) { + if (monster.hp() > maxHp.get()) { + // Found a monster of higher hit points. + maxHp.set(monster.hp()); + maxHpMonsterName.set(monster.name()); + maxHpCount.set(1); + } + else if (monster.hp() == maxHp.get()) { + // Count how many times we saw a monster of current max hit points. + maxHpCount.getAndIncrement(); + } + + if (monster.hp() < minHp.get()) { + // Found a monster of a lower hit points. + minHp.set(monster.hp()); + minHpMonsterName.set(monster.name()); + minHpCount.set(1); + } + else if (monster.hp() == minHp.get()) { + // Count how many times we saw a monster of current min hit points. + minHpCount.getAndIncrement(); + } + } + public void onCompleted() { + Stat maxHpStat = GameFactory.createStat(maxHpMonsterName.get(), maxHp.get(), maxHpCount.get()); + // Send max hit points first. + responseObserver.onNext(maxHpStat); + if (includeMin) { + // Send min hit points. + Stat minHpStat = GameFactory.createStat(minHpMonsterName.get(), minHp.get(), minHpCount.get()); + responseObserver.onNext(minHpStat); + } + responseObserver.onCompleted(); + } + public void onError(Throwable t) { + // Not expected + Assert.fail(); + }; + }; + } + } + + @org.junit.BeforeClass + public static void startServer() throws IOException { + server = ServerBuilder.forPort(0).addService(new MyService()).build().start(); + int port = server.getPort(); + channel = ManagedChannelBuilder.forAddress("localhost", port) + // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid + // needing certificates. + .usePlaintext() + .directExecutor() + .build(); + blockingStub = MonsterStorageGrpc.newBlockingStub(channel); + asyncStub = MonsterStorageGrpc.newStub(channel); + } + + @org.junit.Test + public void testUnary() throws IOException { + Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana); + Stat stat = blockingStub.store(monsterRequest); + Assert.assertEquals(stat.id(), "Hello " + BIG_MONSTER_NAME); + System.out.println("Received stat response from service: " + stat.id()); + } + + @org.junit.Test + public void testServerStreaming() throws IOException { + Monster monsterRequest = GameFactory.createMonster(BIG_MONSTER_NAME, nestedMonsterHp, nestedMonsterMana); + Stat stat = blockingStub.store(monsterRequest); + Iterator iterator = blockingStub.retrieve(stat); + int counter = 0; + while(iterator.hasNext()) { + Monster m = iterator.next(); + System.out.println("Received monster " + m.name()); + counter ++; + } + Assert.assertEquals(counter, numStreamedMsgs); + System.out.println("FlatBuffers GRPC client/server test: completed successfully"); + } + + @org.junit.Test + public void testClientStreaming() throws IOException, InterruptedException { + final AtomicReference maxHitStat = new AtomicReference(); + final CountDownLatch streamAlive = new CountDownLatch(1); + + StreamObserver statObserver = new StreamObserver() { + public void onCompleted() { + streamAlive.countDown(); + } + public void onError(Throwable ex) { } + public void onNext(Stat stat) { + maxHitStat.set(stat); + } + }; + StreamObserver monsterStream = asyncStub.getMaxHitPoint(statObserver); + short count = 10; + for (short i = 0;i < count; ++i) { + Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana); + monsterStream.onNext(monster); + } + monsterStream.onCompleted(); + // Wait a little bit for the server to send the stats of the monster with the max hit-points. + streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS); + Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1)); + Assert.assertEquals(maxHitStat.get().val(), nestedMonsterHp * (count - 1)); + Assert.assertEquals(maxHitStat.get().count(), 1); + } + + @org.junit.Test + public void testBiDiStreaming() throws IOException, InterruptedException { + final AtomicReference maxHitStat = new AtomicReference(); + final AtomicReference minHitStat = new AtomicReference(); + final CountDownLatch streamAlive = new CountDownLatch(1); + + StreamObserver statObserver = new StreamObserver() { + public void onCompleted() { + streamAlive.countDown(); + } + public void onError(Throwable ex) { } + public void onNext(Stat stat) { + // We expect the server to send the max stat first and then the min stat. + if (maxHitStat.get() == null) { + maxHitStat.set(stat); + } + else { + minHitStat.set(stat); + } + } + }; + StreamObserver monsterStream = asyncStub.getMinMaxHitPoints(statObserver); + short count = 10; + for (short i = 0;i < count; ++i) { + Monster monster = GameFactory.createMonster(BIG_MONSTER_NAME + i, (short) (nestedMonsterHp * i), nestedMonsterMana); + monsterStream.onNext(monster); + } + monsterStream.onCompleted(); + + // Wait a little bit for the server to send the stats of the monster with the max and min hit-points. + streamAlive.await(timeoutMs, TimeUnit.MILLISECONDS); + + Assert.assertEquals(maxHitStat.get().id(), BIG_MONSTER_NAME + (count - 1)); + Assert.assertEquals(maxHitStat.get().val(), nestedMonsterHp * (count - 1)); + Assert.assertEquals(maxHitStat.get().count(), 1); + + Assert.assertEquals(minHitStat.get().id(), BIG_MONSTER_NAME + 0); + Assert.assertEquals(minHitStat.get().val(), nestedMonsterHp * 0); + Assert.assertEquals(minHitStat.get().count(), 1); + } +} diff --git a/third_party/flatbuffers/grpc/tests/go_test.go b/third_party/flatbuffers/grpc/tests/go_test.go new file mode 100644 index 000000000..7c94feb8f --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/go_test.go @@ -0,0 +1,102 @@ +package testing + +import ( + flatbuffers "github.com/google/flatbuffers/go" + "github.com/google/flatbuffers/tests/MyGame/Example" + + "context" + "net" + "testing" + + "google.golang.org/grpc" + "google.golang.org/grpc/encoding" +) + +type server struct { + Example.UnimplementedMonsterStorageServer +} + +// test used to send and receive in grpc methods +var test = "Flatbuffers" +var addr = "0.0.0.0:50051" + +// gRPC server store method +func (s *server) Store(context context.Context, in *Example.Monster) (*flatbuffers.Builder, error) { + b := flatbuffers.NewBuilder(0) + i := b.CreateString(test) + Example.StatStart(b) + Example.StatAddId(b, i) + b.Finish(Example.StatEnd(b)) + return b, nil + +} + +// gRPC server retrieve method +func (s *server) Retrieve(context context.Context, in *Example.Stat) (*flatbuffers.Builder, error) { + b := flatbuffers.NewBuilder(0) + i := b.CreateString(test) + Example.MonsterStart(b) + Example.MonsterAddName(b, i) + b.Finish(Example.MonsterEnd(b)) + return b, nil +} + +func StoreClient(c Example.MonsterStorageClient, t *testing.T) { + b := flatbuffers.NewBuilder(0) + i := b.CreateString(test) + Example.MonsterStart(b) + Example.MonsterAddName(b, i) + b.Finish(Example.MonsterEnd(b)) + out, err := c.Store(context.Background(), b) + if err != nil { + t.Fatalf("Store client failed: %v", err) + } + if string(out.Id()) != test { + t.Errorf("StoreClient failed: expected=%s, got=%s\n", test, out.Id()) + t.Fail() + } +} + +func RetrieveClient(c Example.MonsterStorageClient, t *testing.T) { + b := flatbuffers.NewBuilder(0) + i := b.CreateString(test) + Example.StatStart(b) + Example.StatAddId(b, i) + b.Finish(Example.StatEnd(b)) + out, err := c.Retrieve(context.Background(), b) + if err != nil { + t.Fatalf("Retrieve client failed: %v", err) + } + monster, err := out.Recv() + if err != nil { + t.Fatalf("Recv failed: %v", err) + } + if string(monster.Name()) != test { + t.Errorf("RetrieveClient failed: expected=%s, got=%s\n", test, monster.Name()) + t.Fail() + } +} + +func TestGRPC(t *testing.T) { + lis, err := net.Listen("tcp", addr) + if err != nil { + t.Fatalf("Failed to listen: %v", err) + } + ser := grpc.NewServer() + encoding.RegisterCodec(flatbuffers.FlatbuffersCodec{}) + Example.RegisterMonsterStorageServer(ser, &server{}) + go func() { + if err := ser.Serve(lis); err != nil { + t.Fatalf("Failed to serve: %v", err) + t.FailNow() + } + }() + conn, err := grpc.Dial(addr, grpc.WithInsecure(), grpc.WithCodec(flatbuffers.FlatbuffersCodec{})) + if err != nil { + t.Fatalf("Failed to connect: %v", err) + } + defer conn.Close() + client := Example.NewMonsterStorageClient(conn) + StoreClient(client, t) + RetrieveClient(client, t) +} diff --git a/third_party/flatbuffers/grpc/tests/grpctest.cpp b/third_party/flatbuffers/grpc/tests/grpctest.cpp new file mode 100644 index 000000000..6991b7ebb --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/grpctest.cpp @@ -0,0 +1,193 @@ +/* + * 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 + +#include +#include + +#include "monster_test.grpc.fb.h" +#include "monster_test_generated.h" +#include "test_assert.h" + +using namespace MyGame::Example; +using flatbuffers::FlatBufferBuilder; +using flatbuffers::grpc::MessageBuilder; + +void message_builder_tests(); + +// 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::grpc::Message *request, + flatbuffers::grpc::Message *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); + // Transfer ownership of the message to gRPC + *response = fbb_.ReleaseMessage(); + return grpc::Status::OK; + } + virtual ::grpc::Status Retrieve( + ::grpc::ServerContext *context, + const flatbuffers::grpc::Message *request, + ::grpc::ServerWriter> *writer) + override { + for (int i = 0; i < 5; i++) { + fbb_.Clear(); + // Create 5 monsters for resposne. + auto monster_offset = + CreateMonster(fbb_, 0, 0, 0, + fbb_.CreateString(request->GetRoot()->id()->str() + + " No." + std::to_string(i))); + fbb_.Finish(monster_offset); + + flatbuffers::grpc::Message monster = + fbb_.ReleaseMessage(); + + // Send monster to client using streaming. + writer->Write(monster); + } + return grpc::Status::OK; + } + + private: + flatbuffers::grpc::MessageBuilder 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(); +} + +template void StoreRPC(MonsterStorage::Stub *stub) { + Builder fbb; + grpc::ClientContext context; + // Build a request with the name set. + auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred")); + MessageBuilder mb(std::move(fbb)); + mb.Finish(monster_offset); + auto request = mb.ReleaseMessage(); + flatbuffers::grpc::Message 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; + } +} + +template void RetrieveRPC(MonsterStorage::Stub *stub) { + Builder fbb; + grpc::ClientContext context; + fbb.Clear(); + auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred")); + fbb.Finish(stat_offset); + auto request = MessageBuilder(std::move(fbb)).ReleaseMessage(); + + flatbuffers::grpc::Message response; + auto stream = stub->Retrieve(&context, request); + while (stream->Read(&response)) { + auto resp = response.GetRoot()->name(); + std::cout << "RPC Streaming response: " << resp->str() << std::endl; + } +} + +int grpc_server_test() { + // Launch server. + std::thread server_thread(RunServer); + + // wait for server to spin up. + std::unique_lock 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); + + StoreRPC(stub.get()); + StoreRPC(stub.get()); + + RetrieveRPC(stub.get()); + RetrieveRPC(stub.get()); + +#if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION + { + // Test that an invalid request errors out correctly + grpc::ClientContext context; + flatbuffers::grpc::Message request; // simulate invalid message + flatbuffers::grpc::Message response; + auto status = stub->Store(&context, request, &response); + // The rpc status should be INTERNAL to indicate a verification error. This + // matches the protobuf gRPC status code for an unparseable message. + assert(!status.ok()); + assert(status.error_code() == ::grpc::StatusCode::INTERNAL); + assert(strcmp(status.error_message().c_str(), + "Message verification failed") == 0); + } +#endif + + server_instance->Shutdown(); + + server_thread.join(); + + delete server_instance; + + return 0; +} + +int main(int /*argc*/, const char * /*argv*/[]) { + message_builder_tests(); + grpc_server_test(); + + if (!testing_fails) { + TEST_OUTPUT_LINE("ALL TESTS PASSED"); + return 0; + } else { + TEST_OUTPUT_LINE("%d FAILED TESTS", testing_fails); + return 1; + } +} diff --git a/third_party/flatbuffers/grpc/tests/grpctest.py b/third_party/flatbuffers/grpc/tests/grpctest.py new file mode 100644 index 000000000..9cfeda689 --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/grpctest.py @@ -0,0 +1,174 @@ +from __future__ import print_function + +import os +import sys +import grpc +import flatbuffers + +from concurrent import futures + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'tests')) +import MyGame.Example.Monster as Monster +import MyGame.Example.Stat as Stat +import MyGame.Example.Vec3 as Vec3 +import MyGame.Example.Test as Test +import MyGame.Example.monster_test_grpc_fb as monster_grpc_fb + + +test_stat_id = "test_stat_id" +test_stat_val = 8 +test_stat_count = 1 + +test_monster_name1 = "test_monster_name1" +test_monster_name2 = "test_monster_name2" +test_string = "test_string" +test_color = 2 +test_X = 3.0 +test_Y = 2.0 +test_Z = 6.0 +test_test1 = 4.0 +test_a = 8 +test_b = 5 +test_hp = 67 +test_inventory = [1, 1, 2, 3, 5, 8] +test_testtype = 4 + +test_monsters_name_retrieve = ["big_monster", "small_monster"] +test_no_of_monsters = 2 + + +class MonsterStorage(monster_grpc_fb.MonsterStorageServicer): + + def Store(self, request, context): + + m = Monster.Monster().GetRootAsMonster(request, 0) + + assert m.Name().decode("utf-8") == test_monster_name1 + + assert m.Pos().X() == test_X + assert m.Pos().Y() == test_Y + assert m.Pos().Z() == test_Z + assert m.Pos().Test1() == test_test1 + assert m.Pos().Test2() == test_color + test3 = Test.Test() + assert m.Pos().Test3(test3).A() == test_a + assert m.Pos().Test3(test3).B() == test_b + + assert m.Hp() == test_hp + + assert m.Color() == test_color + + assert m.InventoryLength() == len(test_inventory) + for i in range(0, len(test_inventory)): + assert m.Inventory(i) == test_inventory[len(test_inventory)-i -1] + + assert m.TestType() == test_testtype + + assert m.Test() is not None + table = m.Test() + + m2 = Monster.Monster() + m2.Init(table.Bytes, table.Pos) + assert m2.Name().decode("utf-8") == test_monster_name2 + + m3 = m.Enemy() + assert m3.Name().decode("utf-8") == test_monster_name2 + + assert m.Testarrayofstring(0).decode("utf-8") == test_string + + b = flatbuffers.Builder(0) + i = b.CreateString(test_stat_id) + Stat.StatStart(b) + Stat.StatAddId(b, i) + Stat.StatAddVal(b, test_stat_val) + Stat.StatAddCount(b, test_stat_count) + b.Finish(Stat.StatEnd(b)) + return bytes(b.Output()) + + def Retrieve(self, request, context): + + s = Stat.Stat().GetRootAsStat(request, 0) + + no_of_monsters = test_no_of_monsters + for i in range(0, no_of_monsters): + b = flatbuffers.Builder(0) + i = b.CreateString(test_monsters_name_retrieve[i]) + Monster.MonsterStart(b) + Monster.MonsterAddName(b, i) + b.Finish(Monster.MonsterEnd(b)) + yield bytes(b.Output()) + + +def serve(): + + server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) + monster_grpc_fb.add_MonsterStorageServicer_to_server(MonsterStorage(), server) + server.add_insecure_port('[::]:50051') + + server.start() + + run() + + +def run(): + + channel = grpc.insecure_channel('127.0.0.1:50051') + stub = monster_grpc_fb.MonsterStorageStub(channel) + + b = flatbuffers.Builder(0) + name2 = b.CreateString(test_monster_name2) + name1 = b.CreateString(test_monster_name1) + Monster.MonsterStart(b) + Monster.MonsterAddName(b, name2) + monster2 = Monster.MonsterEnd(b) + test1 = b.CreateString(test_string) + + Monster.MonsterStartInventoryVector(b, len(test_inventory)) + for i in range(0, len(test_inventory)): + b.PrependByte(test_inventory[i]) + inv = b.EndVector() + + Monster.MonsterStartTest4Vector(b, 2) + Test.CreateTest(b, 10, 20) + Test.CreateTest(b, 30, 40) + test4 = b.EndVector() + + Monster.MonsterStartTestarrayofstringVector(b, 1) + b.PrependUOffsetTRelative(test1) + test_array_of_string = b.EndVector() + + Monster.MonsterStart(b) + + Monster.MonsterAddHp(b, test_hp) + Monster.MonsterAddName(b, name1) + Monster.MonsterAddColor(b, test_color) + pos = Vec3.CreateVec3(b, test_X, test_Y, test_Z, test_test1, test_color, test_a, test_b) + Monster.MonsterAddPos(b, pos) + Monster.MonsterAddInventory(b, inv) + Monster.MonsterAddTestType(b, test_testtype) + Monster.MonsterAddTest(b, monster2) + Monster.MonsterAddTest4(b, test4) + Monster.MonsterAddEnemy(b, monster2) + Monster.MonsterAddTestarrayofstring(b, test_array_of_string) + monster = Monster.MonsterEnd(b) + + b.Finish(monster) + + stat_response = stub.Store(bytes(b.Output())) + + s = Stat.Stat().GetRootAsStat(stat_response, 0) + + assert s.Id().decode("utf-8") == test_stat_id + assert s.Val() == test_stat_val + assert s.Count() == test_stat_count + + monster_reponses = stub.Retrieve(stat_response) + count = 0 + for monster_reponse in monster_reponses: + m = Monster.Monster().GetRootAsMonster(monster_reponse, 0) + assert m.Name().decode("utf-8") == test_monsters_name_retrieve[count] + count = count + 1 + + +if __name__ == '__main__': + serve() diff --git a/third_party/flatbuffers/grpc/tests/java-grpc-test.sh b/third_party/flatbuffers/grpc/tests/java-grpc-test.sh new file mode 100755 index 000000000..ec4296055 --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/java-grpc-test.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +# NOTE: make sure `mvn install` in /gprc is executed before running this test +mvn test diff --git a/third_party/flatbuffers/grpc/tests/message_builder_test.cpp b/third_party/flatbuffers/grpc/tests/message_builder_test.cpp new file mode 100644 index 000000000..8af0c2141 --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/message_builder_test.cpp @@ -0,0 +1,368 @@ +#include "flatbuffers/grpc.h" +#include "monster_test_generated.h" +#include "test_assert.h" +#include "test_builder.h" + +using MyGame::Example::Any_NONE; +using MyGame::Example::CreateStat; +using MyGame::Example::Vec3; + +bool verify(flatbuffers::grpc::Message &msg, + const std::string &expected_name, Color expected_color) { + const Monster *monster = msg.GetRoot(); + const auto name = monster->name()->str(); + const auto color = monster->color(); + TEST_EQ(name, expected_name); + TEST_EQ(color, expected_color); + return (name == expected_name) && (color == expected_color); +} + +bool release_n_verify(flatbuffers::grpc::MessageBuilder &mbb, + const std::string &expected_name, Color expected_color) { + flatbuffers::grpc::Message msg = mbb.ReleaseMessage(); + return verify(msg, expected_name, expected_color); +} + +void builder_move_assign_after_releaseraw_test( + flatbuffers::grpc::MessageBuilder dst) { + auto root_offset1 = populate1(dst); + dst.Finish(root_offset1); + size_t size, offset; + ::grpc::Slice slice; + dst.ReleaseRaw(size, offset, slice); + flatbuffers::FlatBufferBuilder src; + auto root_offset2 = populate2(src); + src.Finish(root_offset2); + auto src_size = src.GetSize(); + // Move into a released builder. + dst = std::move(src); + TEST_EQ(dst.GetSize(), src_size); + TEST_ASSERT(release_n_verify(dst, m2_name(), m2_color())); + TEST_EQ(src.GetSize(), 0); +} + +template +struct BuilderReuseTests { + static void builder_reusable_after_release_message_test( + TestSelector selector) { + if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE)) { return; } + + flatbuffers::grpc::MessageBuilder mb; + std::vector> buffers; + for (int i = 0; i < 5; ++i) { + auto root_offset1 = populate1(mb); + mb.Finish(root_offset1); + buffers.push_back(mb.ReleaseMessage()); + TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); + } + } + + static void builder_reusable_after_release_test(TestSelector selector) { + if (!selector.count(REUSABLE_AFTER_RELEASE)) { return; } + + // FIXME: Populate-Release loop fails assert(GRPC_SLICE_IS_EMPTY(slice_)) in + // SliceAllocator::allocate in the second iteration. + + flatbuffers::grpc::MessageBuilder mb; + std::vector buffers; + for (int i = 0; i < 2; ++i) { + auto root_offset1 = populate1(mb); + mb.Finish(root_offset1); + buffers.push_back(mb.Release()); + TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); + } + } + + static void builder_reusable_after_releaseraw_test(TestSelector selector) { + if (!selector.count(REUSABLE_AFTER_RELEASE_RAW)) { return; } + + flatbuffers::grpc::MessageBuilder mb; + for (int i = 0; i < 5; ++i) { + auto root_offset1 = populate1(mb); + mb.Finish(root_offset1); + size_t size, offset; + ::grpc::Slice slice; + const uint8_t *buf = mb.ReleaseRaw(size, offset, slice); + TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color())); + } + } + + static void builder_reusable_after_release_and_move_assign_test( + TestSelector selector) { + if (!selector.count(REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN)) { return; } + + // FIXME: Release-move_assign loop fails assert(p == + // GRPC_SLICE_START_PTR(slice_)) in DetachedBuffer destructor after all the + // iterations + + flatbuffers::grpc::MessageBuilder dst; + std::vector buffers; + + for (int i = 0; i < 2; ++i) { + auto root_offset1 = populate1(dst); + dst.Finish(root_offset1); + buffers.push_back(dst.Release()); + TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); + + // bring dst back to life. + SrcBuilder src; + dst = std::move(src); + TEST_EQ_FUNC(dst.GetSize(), 0); + TEST_EQ_FUNC(src.GetSize(), 0); + } + } + + static void builder_reusable_after_release_message_and_move_assign_test( + TestSelector selector) { + if (!selector.count(REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN)) { + return; + } + + flatbuffers::grpc::MessageBuilder dst; + std::vector> buffers; + + for (int i = 0; i < 5; ++i) { + auto root_offset1 = populate1(dst); + dst.Finish(root_offset1); + buffers.push_back(dst.ReleaseMessage()); + TEST_ASSERT_FUNC(verify(buffers[i], m1_name(), m1_color())); + + // bring dst back to life. + SrcBuilder src; + dst = std::move(src); + TEST_EQ_FUNC(dst.GetSize(), 0); + TEST_EQ_FUNC(src.GetSize(), 0); + } + } + + static void builder_reusable_after_releaseraw_and_move_assign_test( + TestSelector selector) { + if (!selector.count(REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN)) { return; } + + flatbuffers::grpc::MessageBuilder dst; + for (int i = 0; i < 5; ++i) { + auto root_offset1 = populate1(dst); + dst.Finish(root_offset1); + size_t size, offset; + ::grpc::Slice slice; + const uint8_t *buf = dst.ReleaseRaw(size, offset, slice); + TEST_ASSERT_FUNC(verify(buf, offset, m1_name(), m1_color())); + + SrcBuilder src; + dst = std::move(src); + TEST_EQ_FUNC(dst.GetSize(), 0); + TEST_EQ_FUNC(src.GetSize(), 0); + } + } + + static void run_tests(TestSelector selector) { + builder_reusable_after_release_test(selector); + builder_reusable_after_release_message_test(selector); + builder_reusable_after_releaseraw_test(selector); + builder_reusable_after_release_and_move_assign_test(selector); + builder_reusable_after_releaseraw_and_move_assign_test(selector); + builder_reusable_after_release_message_and_move_assign_test(selector); + } +}; + +void slice_allocator_tests() { + // move-construct no-delete test + { + size_t size = 2048; + flatbuffers::grpc::SliceAllocator sa1; + uint8_t *buf = sa1.allocate(size); + TEST_ASSERT_FUNC(buf != 0); + buf[0] = 100; + buf[size - 1] = 200; + flatbuffers::grpc::SliceAllocator sa2(std::move(sa1)); + // buf should not be deleted after move-construct + TEST_EQ_FUNC(buf[0], 100); + TEST_EQ_FUNC(buf[size - 1], 200); + // buf is freed here + } + + // move-assign test + { + flatbuffers::grpc::SliceAllocator sa1, sa2; + uint8_t *buf = sa1.allocate(2048); + sa1 = std::move(sa2); + // sa1 deletes previously allocated memory in move-assign. + // So buf is no longer usable here. + TEST_ASSERT_FUNC(buf != 0); + } +} + +/// This function does not populate exactly the first half of the table. But it +/// could. +void populate_first_half(MyGame::Example::MonsterBuilder &wrapper, + flatbuffers::Offset name_offset) { + wrapper.add_name(name_offset); + wrapper.add_color(m1_color()); +} + +/// This function does not populate exactly the second half of the table. But it +/// could. +void populate_second_half(MyGame::Example::MonsterBuilder &wrapper) { + wrapper.add_hp(77); + wrapper.add_mana(88); + Vec3 vec3; + wrapper.add_pos(&vec3); +} + +/// This function is a hack to update the FlatBufferBuilder reference (fbb_) in +/// the MonsterBuilder object. This function will break if fbb_ is not the first +/// member in MonsterBuilder. In that case, some offset must be added. This +/// function is used exclusively for testing correctness of move operations +/// between FlatBufferBuilders. If MonsterBuilder had a fbb_ pointer, this hack +/// would be unnecessary. That involves a code-generator change though. +void test_only_hack_update_fbb_reference( + MyGame::Example::MonsterBuilder &monsterBuilder, + flatbuffers::grpc::MessageBuilder &mb) { + *reinterpret_cast(&monsterBuilder) = &mb; +} + +/// This test validates correctness of move conversion of FlatBufferBuilder to a +/// MessageBuilder DURING a table construction. Half of the table is constructed +/// using FlatBufferBuilder and the other half of the table is constructed using +/// a MessageBuilder. +void builder_move_ctor_conversion_before_finish_half_n_half_table_test() { + for (size_t initial_size = 4; initial_size <= 2048; initial_size *= 2) { + flatbuffers::FlatBufferBuilder fbb(initial_size); + auto name_offset = fbb.CreateString(m1_name()); + MyGame::Example::MonsterBuilder monsterBuilder( + fbb); // starts a table in FlatBufferBuilder + populate_first_half(monsterBuilder, name_offset); + flatbuffers::grpc::MessageBuilder mb(std::move(fbb)); + test_only_hack_update_fbb_reference(monsterBuilder, mb); // hack + populate_second_half(monsterBuilder); + mb.Finish(monsterBuilder.Finish()); // ends the table in MessageBuilder + TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color())); + TEST_EQ_FUNC(fbb.GetSize(), 0); + } +} + +/// This test populates a COMPLETE inner table before move conversion and later +/// populates more members in the outer table. +void builder_move_ctor_conversion_before_finish_test() { + for (size_t initial_size = 1; initial_size <= 2048; initial_size += 1) { + flatbuffers::FlatBufferBuilder fbb(initial_size); + auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0); + flatbuffers::grpc::MessageBuilder mb(std::move(fbb)); + auto monster_offset = + CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name()), 0, + m1_color(), Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset); + mb.Finish(monster_offset); + { + auto mon = flatbuffers::GetRoot(mb.GetBufferPointer()); + TEST_NOTNULL(mon); + TEST_NOTNULL(mon->name()); + TEST_EQ_STR(mon->name()->c_str(), m1_name().c_str()); + TEST_EQ(mon->color(), m1_color()); + } + TEST_EQ(1, MyGame::Example::Color_Red); + TEST_EQ(1, m1_color()); + TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color())); + TEST_EQ_FUNC(fbb.GetSize(), 0); + } +} + +/// This test validates correctness of move conversion of FlatBufferBuilder to a +/// MessageBuilder DURING a table construction. Half of the table is constructed +/// using FlatBufferBuilder and the other half of the table is constructed using +/// a MessageBuilder. +void builder_move_assign_conversion_before_finish_half_n_half_table_test() { + flatbuffers::FlatBufferBuilder fbb; + flatbuffers::grpc::MessageBuilder mb; + + for (int i = 0; i < 5; ++i) { + flatbuffers::FlatBufferBuilder fbb; + auto name_offset = fbb.CreateString(m1_name()); + MyGame::Example::MonsterBuilder monsterBuilder( + fbb); // starts a table in FlatBufferBuilder + populate_first_half(monsterBuilder, name_offset); + mb = std::move(fbb); + test_only_hack_update_fbb_reference(monsterBuilder, mb); // hack + populate_second_half(monsterBuilder); + mb.Finish(monsterBuilder.Finish()); // ends the table in MessageBuilder + TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color())); + TEST_EQ_FUNC(fbb.GetSize(), 0); + } +} + +/// This test populates a COMPLETE inner table before move conversion and later +/// populates more members in the outer table. +void builder_move_assign_conversion_before_finish_test() { + flatbuffers::FlatBufferBuilder fbb; + flatbuffers::grpc::MessageBuilder mb; + + for (int i = 0; i < 5; ++i) { + auto stat_offset = CreateStat(fbb, fbb.CreateString("SomeId"), 0, 0); + mb = std::move(fbb); + auto monster_offset = + CreateMonster(mb, 0, 150, 100, mb.CreateString(m1_name()), 0, + m1_color(), Any_NONE, 0, 0, 0, 0, 0, 0, stat_offset); + mb.Finish(monster_offset); + TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color())); + TEST_EQ_FUNC(fbb.GetSize(), 0); + } +} + +/// This test populates data, finishes the buffer, and does move conversion +/// after. +void builder_move_ctor_conversion_after_finish_test() { + flatbuffers::FlatBufferBuilder fbb; + fbb.Finish(populate1(fbb)); + flatbuffers::grpc::MessageBuilder mb(std::move(fbb)); + TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color())); + TEST_EQ_FUNC(fbb.GetSize(), 0); +} + +/// This test populates data, finishes the buffer, and does move conversion +/// after. +void builder_move_assign_conversion_after_finish_test() { + flatbuffers::FlatBufferBuilder fbb; + flatbuffers::grpc::MessageBuilder mb; + + for (int i = 0; i < 5; ++i) { + fbb.Finish(populate1(fbb)); + mb = std::move(fbb); + TEST_ASSERT_FUNC(release_n_verify(mb, m1_name(), m1_color())); + TEST_EQ_FUNC(fbb.GetSize(), 0); + } +} + +void message_builder_tests() { + using flatbuffers::FlatBufferBuilder; + using flatbuffers::grpc::MessageBuilder; + + slice_allocator_tests(); + +#ifndef __APPLE__ + builder_move_ctor_conversion_before_finish_half_n_half_table_test(); + builder_move_assign_conversion_before_finish_half_n_half_table_test(); +#endif // __APPLE__ + builder_move_ctor_conversion_before_finish_test(); + builder_move_assign_conversion_before_finish_test(); + + builder_move_ctor_conversion_after_finish_test(); + builder_move_assign_conversion_after_finish_test(); + + BuilderTests::all_tests(); + BuilderTests::all_tests(); + + BuilderReuseTestSelector tests[6] = { + // REUSABLE_AFTER_RELEASE, // Assertion failed: + // (GRPC_SLICE_IS_EMPTY(slice_)) + // REUSABLE_AFTER_RELEASE_AND_MOVE_ASSIGN, // Assertion failed: (p == + // GRPC_SLICE_START_PTR(slice_) + + REUSABLE_AFTER_RELEASE_RAW, REUSABLE_AFTER_RELEASE_MESSAGE, + REUSABLE_AFTER_RELEASE_MESSAGE_AND_MOVE_ASSIGN, + REUSABLE_AFTER_RELEASE_RAW_AND_MOVE_ASSIGN + }; + + BuilderReuseTests::run_tests( + TestSelector(tests, tests + 6)); + BuilderReuseTests::run_tests( + TestSelector(tests, tests + 6)); +} diff --git a/third_party/flatbuffers/grpc/tests/pom.xml b/third_party/flatbuffers/grpc/tests/pom.xml new file mode 100644 index 000000000..5aca387bf --- /dev/null +++ b/third_party/flatbuffers/grpc/tests/pom.xml @@ -0,0 +1,73 @@ + + 4.0.0 + + com.google.flatbuffers + flatbuffers-parent + 2.0.3 + + grpc-test + Example/Test project demonstrating usage of flatbuffers with GRPC-Java instead of protobufs + + + 2.0.3 + + + + com.google.flatbuffers + flatbuffers-java + ${project.parent.version} + test + + + com.google.flatbuffers + flatbuffers-java-grpc + ${project.parent.version} + test + + + io.grpc + grpc-stub + ${gRPC.version} + test + + + io.grpc + grpc-netty + ${gRPC.version} + test + + + junit + junit + 4.13.1 + test + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + generate-sources + + add-test-source + + + + ${project.basedir} + ${project.basedir}/../../tests + + + + + + + + + +