[c++ grpc] Merge initial gRPC++ support
This commit is contained in:
Коммит
4b96096668
|
@ -1,3 +1,7 @@
|
|||
[submodule "thirdparty/grpc"]
|
||||
path = thirdparty/grpc
|
||||
url = https://github.com/chwarr/grpc.git
|
||||
|
||||
[submodule "thirdparty/rapidjson"]
|
||||
path = thirdparty/rapidjson
|
||||
url = https://github.com/miloyip/rapidjson.git
|
||||
|
|
26
.travis.yml
26
.travis.yml
|
@ -11,14 +11,16 @@ cache:
|
|||
- /home/travis/.ccache
|
||||
env:
|
||||
- FLAVOR="cs"
|
||||
- FLAVOR="cpp" BOOST="1.64.0"
|
||||
- FLAVOR="cpp" BOOST="1.63.0"
|
||||
- FLAVOR="cpp" BOOST="1.62.0"
|
||||
- FLAVOR="cpp" BOOST="1.61.0"
|
||||
- FLAVOR="cpp" BOOST="1.60.0"
|
||||
- FLAVOR="cpp" BOOST="1.59.0"
|
||||
- FLAVOR="cpp" BOOST="1.58.0"
|
||||
- FLAVOR="cpp-comm"
|
||||
- FLAVOR="cpp-core" BOOST="1.64.0"
|
||||
- FLAVOR="cpp-core" BOOST="1.63.0"
|
||||
- FLAVOR="cpp-core" BOOST="1.62.0"
|
||||
- FLAVOR="cpp-core" BOOST="1.61.0"
|
||||
- FLAVOR="cpp-core" BOOST="1.60.0"
|
||||
- FLAVOR="cpp-core" BOOST="1.59.0"
|
||||
- FLAVOR="cpp-core" BOOST="1.58.0"
|
||||
- FLAVOR="cpp-comm" BOOST="1.63.0"
|
||||
- FLAVOR="cpp-grpc" BOOST="1.64.0"
|
||||
- FLAVOR="cpp-grpc" BOOST="1.63.0"
|
||||
- FLAVOR="hs" GHC_VERSION="7.8.4"
|
||||
- FLAVOR="hs" GHC_VERSION="7.6.3"
|
||||
addons:
|
||||
|
@ -78,10 +80,12 @@ script:
|
|||
- if [ "$FLAVOR" == "cs" ]; then xbuild /p:Configuration=Debug cs/cs.sln; fi
|
||||
- if [ "$FLAVOR" == "cs" ]; then xbuild /p:Configuration=Fields cs/cs.sln; fi
|
||||
- if [ "$FLAVOR" == "cs" ]; then mono NUnit.Runners.2.6.4/tools/nunit-console.exe -framework=mono-4.5 -labels cs/test/core/bin/debug/net45/Properties/Bond.UnitTest.dll cs/test/core/bin/debug/net45/Fields/Bond.UnitTest.dll cs/test/internal/bin/debug/net45/Bond.InternalTest.dll; fi
|
||||
- if [ "$FLAVOR" == "cpp" ]; then cmake -DBOND_SKIP_GBC_TESTS=TRUE -DBOND_CORE_ONLY=TRUE ..; fi
|
||||
- if [ "$FLAVOR" == "cpp" ]; then make --jobs 2 check; fi
|
||||
- if [ "$FLAVOR" == "cpp-comm" ]; then cmake -DBOND_SKIP_GBC_TESTS=TRUE -DBOND_SKIP_CORE_TESTS=TRUE ..; fi
|
||||
- if [ "$FLAVOR" == "cpp-core" ]; then cmake -DBOND_SKIP_GBC_TESTS=TRUE -DBOND_ENABLE_COMM=FALSE -DBOND_ENABLE_GRPC=FALSE ..; fi
|
||||
- if [ "$FLAVOR" == "cpp-core" ]; then make --jobs 2 check; fi
|
||||
- if [ "$FLAVOR" == "cpp-comm" ]; then cmake -DBOND_SKIP_GBC_TESTS=TRUE -DBOND_SKIP_CORE_TESTS=TRUE -DBOND_ENABLE_GRPC=FALSE ..; fi
|
||||
- if [ "$FLAVOR" == "cpp-comm" ]; then make --jobs 2 check; fi
|
||||
- if [ "$FLAVOR" == "cpp-grpc" ]; then cmake -DBOND_SKIP_GBC_TESTS=TRUE -DBOND_SKIP_CORE_TESTS=TRUE -DBOND_ENABLE_COMM=FALSE ..; fi
|
||||
- if [ "$FLAVOR" == "cpp-grpc" ]; then make --jobs 2 check; fi
|
||||
- if [ "$FLAVOR" == "hs" ]; then cmake ..; fi
|
||||
- if [ "$FLAVOR" == "hs" ]; then make gbc-tests; fi
|
||||
- if [ "$FLAVOR" == "hs" ]; then cd ../compiler; fi
|
||||
|
|
|
@ -53,6 +53,9 @@ different versioning scheme, following the Haskell community's
|
|||
and
|
||||
[the bf example](https://github.com/Microsoft/bond/commit/11beaf5319639e4bdee96a25f95154e4fed93a75#diff-bdda0f39d99280d4858b4453906eea17)
|
||||
for more details.
|
||||
* Initial support for sending
|
||||
[Bond objects over gRPC](https://microsoft.github.io/bond/manual/bond_over_grpc.html)
|
||||
has been added.
|
||||
* The `bond::Apply` function now has a uniform signature. Call sites for
|
||||
the `Marshaler<Writer>` transform overload that were _mistakenly_ passing
|
||||
`Writer` explicitly (e.g. `bond::Apply<Writer>(marshaler, value)`) will now
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
cmake_minimum_required (VERSION 3.1)
|
||||
project (bond)
|
||||
|
||||
project (bond)
|
||||
cmake_policy (SET CMP0022 NEW)
|
||||
|
||||
set (CMAKE_MODULE_PATH
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/cmake
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/cmake-modules)
|
||||
|
||||
# Initialize before ThirdParty
|
||||
set (BOND_ENABLE_GRPC
|
||||
"TRUE"
|
||||
CACHE BOOL "If FALSE, then do not build gRPC integration")
|
||||
|
||||
# We need to include third-party CMake modules before we configure our own
|
||||
# settings so that we don't apply our settings to third-party code.
|
||||
add_subdirectory (thirdparty)
|
||||
|
||||
enable_testing()
|
||||
|
||||
set (BOND_IDL ${CMAKE_CURRENT_SOURCE_DIR}/idl)
|
||||
|
@ -35,6 +44,7 @@ add_subfolder (doc "doc")
|
|||
add_python_subdirectory (python)
|
||||
add_subdirectory (examples)
|
||||
|
||||
|
||||
install (DIRECTORY
|
||||
cpp/inc/bond
|
||||
cpp/generated/bond
|
||||
|
|
42
README.md
42
README.md
|
@ -20,13 +20,16 @@ are preserved for transition purposes.**
|
|||
|
||||
Bond is published on GitHub at [https://github.com/Microsoft/bond/](https://github.com/Microsoft/bond/).
|
||||
|
||||
For details, see the User's Manuals for
|
||||
[C++](https://Microsoft.github.io/bond/manual/bond_cpp.html),
|
||||
[C#](https://Microsoft.github.io/bond/manual/bond_cs.html) and
|
||||
[Python](https://Microsoft.github.io/bond/manual/bond_py.html), and the
|
||||
documentation of the compiler
|
||||
[tool](https://microsoft.github.io/bond/manual/compiler.html) and
|
||||
[library](https://hackage.haskell.org/package/bond).
|
||||
For details, see the User's Manuals:
|
||||
|
||||
* [C++](https://Microsoft.github.io/bond/manual/bond_cpp.html)
|
||||
* [C#](https://Microsoft.github.io/bond/manual/bond_cs.html)
|
||||
* [Python](https://Microsoft.github.io/bond/manual/bond_py.html)
|
||||
* [Bond-over-gRPC](https://Microsoft.github.io/bond/manual/bond_over_grpc.html)
|
||||
* [`gbc`, the Bond compiler/codegen tool](https://microsoft.github.io/bond/manual/compiler.html)
|
||||
* See also
|
||||
[the compiler library](https://hackage.haskell.org/package/bond) that
|
||||
powers `gbc`.
|
||||
|
||||
For a discussion how Bond compares to similar frameworks see [Why Bond](https://Microsoft.github.io/bond/why_bond.html).
|
||||
|
||||
|
@ -82,15 +85,18 @@ sudo make install
|
|||
The `build` directory is just an example. Any directory can be used as the build
|
||||
destination.
|
||||
|
||||
In order to build all the C++ and Python tests and examples, a few more
|
||||
packages are needed:
|
||||
In order to build all the C++ and Python tests and examples, as well as
|
||||
Bond-over-gRPC and Bond Comm, a few more packages are needed:
|
||||
|
||||
```bash
|
||||
sudo apt-get install \
|
||||
python2.7-dev \
|
||||
autoconf \
|
||||
build-essential \
|
||||
libboost-date-time-dev \
|
||||
libboost-python-dev \
|
||||
libboost-test-dev \
|
||||
libboost-python-dev
|
||||
libtool \
|
||||
python2.7-dev
|
||||
|
||||
cabal install happy
|
||||
```
|
||||
|
@ -219,9 +225,17 @@ set BOOST_LIBRARYDIR=D:\boost_1_58_0\lib64-msvc-14.0
|
|||
```
|
||||
|
||||
The core Bond library and most examples only require Boost headers. The
|
||||
pre-built libraries are only needed for unit tests and Python support. If Boost
|
||||
or Python libraries are not found on the system, then some tests and examples will
|
||||
not be built.
|
||||
pre-built libraries are only needed for unit tests, Python, gRPC, and Comm
|
||||
support. If Boost or Python libraries are not found on the system, then some
|
||||
tests and examples will not be built.
|
||||
|
||||
To build Bond's gRPC++ integration from source, some of
|
||||
[gRPC's prerequisites](https://github.com/grpc/grpc/blob/master/INSTALL.md#building-using-cmake-with-boringssl)
|
||||
are also needed:
|
||||
|
||||
```bash
|
||||
choco install activeperl golang ninja yasm
|
||||
```
|
||||
|
||||
In order to generate a solution to build the C++ and Python versions with Visual
|
||||
Studio 2015 run the following commands from the root `bond` directory:
|
||||
|
|
102
appveyor.yml
102
appveyor.yml
|
@ -20,57 +20,89 @@
|
|||
environment:
|
||||
BOND_TOKEN:
|
||||
secure: MdnZ86SpR3+/fVz2u31blV83LH6juiobrvO/l1Ak4zG7ykxtvfUI/Vd4l7etYB4J
|
||||
# The slowest configurations should come first to help reduce
|
||||
# overall completion time since we run multiple configurations in
|
||||
# parallel.
|
||||
matrix:
|
||||
# C++ Core build and tests (Visual C++ 2013)
|
||||
- BOND_BUILD: C++
|
||||
BOND_VS: "Visual Studio 12 2013"
|
||||
BOND_VS_NUM: 12
|
||||
BOND_ARCH: 32
|
||||
BOND_BOOST: 58
|
||||
BOND_CMAKE_FLAGS: "-DBOND_ENABLE_COMM=FALSE;-DBOND_ENABLE_GRPC=FALSE;-DBOND_SKIP_GBC_TESTS=TRUE"
|
||||
- BOND_BUILD: C++
|
||||
BOND_VS: "Visual Studio 14 2015"
|
||||
BOND_VS_NUM: 14
|
||||
BOND_ARCH: 64
|
||||
BOND_BOOST: 60
|
||||
BOND_CMAKE_FLAGS: "-DBOND_ENABLE_COMM=FALSE;-DBOND_ENABLE_GRPC=FALSE"
|
||||
- BOND_BUILD: C#
|
||||
BOND_OUTPUT: Properties
|
||||
BOND_CONFIG: Debug
|
||||
- BOND_BUILD: "C# .NET Core"
|
||||
BOND_CONFIG: Debug
|
||||
- BOND_BUILD: C++
|
||||
BOND_VS: "Visual Studio 14 2015"
|
||||
BOND_VS_NUM: 14
|
||||
BOND_ARCH: 64
|
||||
BOND_BOOST: 60
|
||||
BOND_CMAKE_FLAGS: "-DBOND_CORE_ONLY=TRUE"
|
||||
# C++ Core build and tests
|
||||
- BOND_BUILD: Doc
|
||||
- BOND_BUILD: C#
|
||||
BOND_OUTPUT: Fields
|
||||
BOND_CONFIG: Fields
|
||||
- BOND_BUILD: C++
|
||||
BOND_VS: "Visual Studio 14 2015"
|
||||
BOND_VS_NUM: 14
|
||||
BOND_ARCH: 64
|
||||
BOND_BOOST: 60
|
||||
BOND_CMAKE_FLAGS: "-DBOND_SKIP_CORE_TESTS=TRUE;-DBOND_SKIP_GBC_TESTS=TRUE"
|
||||
- BOND_BUILD: Python
|
||||
BOND_VS: "Visual Studio 14 2015"
|
||||
BOND_VS_NUM: 14
|
||||
BOND_ARCH: 32
|
||||
BOND_BOOST: 60
|
||||
BOND_CMAKE_FLAGS: "-DBOND_ENABLE_COMM=FALSE;-DBOND_ENABLE_GRPC=FALSE"
|
||||
- BOND_BUILD: Python
|
||||
BOND_VS: "Visual Studio 14 2015"
|
||||
BOND_VS_NUM: 14
|
||||
BOND_ARCH: 64
|
||||
BOND_BOOST: 63
|
||||
BOND_CMAKE_FLAGS: "-DBOND_ENABLE_COMM=FALSE;-DBOND_ENABLE_GRPC=FALSE"
|
||||
# C++ Comm build and tests
|
||||
- BOND_BUILD: C++
|
||||
BOND_VS: "Visual Studio 12 2013"
|
||||
BOND_VS_NUM: 12
|
||||
BOND_ARCH: 32
|
||||
BOND_BOOST: 58
|
||||
BOND_CMAKE_FLAGS: "-DBOND_CORE_ONLY=TRUE;-DBOND_SKIP_GBC_TESTS=TRUE"
|
||||
BOND_VS: "Visual Studio 14 2015"
|
||||
BOND_VS_NUM: 14
|
||||
BOND_ARCH: 64
|
||||
BOND_BOOST: 63
|
||||
BOND_CMAKE_FLAGS: "-DBOND_ENABLE_GRPC=FALSE;-DBOND_SKIP_CORE_TESTS=TRUE;-DBOND_SKIP_GBC_TESTS=TRUE"
|
||||
# C++ gRPC build and tests
|
||||
- BOND_BUILD: C++
|
||||
BOND_VS: "Visual Studio 14 2015"
|
||||
BOND_VS_NUM: 14
|
||||
BOND_ARCH: 64
|
||||
BOND_BOOST: 63
|
||||
BOND_CMAKE_FLAGS: "-DBOND_ENABLE_COMM=FALSE;-DBOND_SKIP_CORE_TESTS=TRUE;-DBOND_SKIP_GBC_TESTS=TRUE"
|
||||
- BOND_BUILD: C#
|
||||
BOND_OUTPUT: Properties
|
||||
BOND_CONFIG: Debug
|
||||
# C++ Comm build and tests (Visual C++ 2013)
|
||||
- BOND_BUILD: C++
|
||||
BOND_VS: "Visual Studio 12 2013"
|
||||
BOND_VS_NUM: 12
|
||||
BOND_ARCH: 64
|
||||
BOND_BOOST: 58
|
||||
BOND_CMAKE_FLAGS: "-DBOND_SKIP_CORE_TESTS=TRUE;-DBOND_SKIP_GBC_TESTS=TRUE"
|
||||
|
||||
BOND_CMAKE_FLAGS: "-DBOND_ENABLE_GRPC=FALSE;-DBOND_SKIP_CORE_TESTS=TRUE;-DBOND_SKIP_GBC_TESTS=TRUE"
|
||||
- BOND_BUILD: C#
|
||||
BOND_OUTPUT: Fields
|
||||
BOND_CONFIG: Fields
|
||||
install:
|
||||
- ps: >-
|
||||
git submodule update --init
|
||||
if (($env:BOND_BUILD -eq 'C++') -or ($env:BOND_BUILD -eq 'Python')) {
|
||||
|
||||
git submodule update --init thirdparty\rapidjson
|
||||
|
||||
# If gRPC is not disabled, init gRPC and its dependencies
|
||||
|
||||
if (($env:BOND_BUILD -eq 'C++') -and (-not ($env:BOND_CMAKE_FLAGS -match '-DBOND_ENABLE_GRPC=FALSE'))) {
|
||||
git submodule update --init --recursive thirdparty\grpc
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($env:BOND_BOOST -eq 56) {
|
||||
# Hard-coded Boost path per https://www.appveyor.com/docs/installed-software#languages-libraries-frameworks
|
||||
|
||||
$env:BOOST_ROOT = "C:/Libraries/boost"
|
||||
$env:BOOST_LIBRARYDIR = "C:/Libraries/boost/lib${env:BOND_ARCH}-msvc-${env:BOND_VS_NUM}.0"
|
||||
}
|
||||
|
@ -105,6 +137,21 @@
|
|||
|
||||
}
|
||||
|
||||
if (($env:BOND_BUILD -eq 'C++') -and (-not ($env:BOND_CMAKE_FLAGS -match '-DBOND_ENABLE_GRPC=FALSE'))) {
|
||||
|
||||
# We're building C++ and gRPC isn't disabled, so we need
|
||||
# gRPC dependencies.
|
||||
|
||||
choco install yasm -y
|
||||
|
||||
$machinePath = [System.Environment]::GetEnvironmentVariable("Path","Machine")
|
||||
|
||||
$userPath = [System.Environment]::GetEnvironmentVariable("Path","User")
|
||||
|
||||
$env:Path = "$machinePath;$userPath"
|
||||
|
||||
}
|
||||
|
||||
cache:
|
||||
- cs\packages -> cs\test\core\packages.config
|
||||
- compiler\.cabal-sandbox -> compiler\bond.cabal
|
||||
|
@ -132,6 +179,7 @@
|
|||
if ($env:BOND_BUILD -eq "Python" -Or $env:BOND_BUILD -eq "C++") {
|
||||
|
||||
# Make sure we have Python27-64 before any other version
|
||||
|
||||
if ($env:BOND_ARCH -eq 64) {
|
||||
$env:Path = "C:\Python27-x64\scripts;C:\Python27-x64\;${env:Path}"
|
||||
}
|
||||
|
@ -150,13 +198,21 @@
|
|||
|
||||
if ($env:BOND_BUILD -eq "C++") {
|
||||
|
||||
msbuild cs\cs.sln /verbosity:minimal /target:Tests\Compat /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
# We don't always need all of these compat tests--depending
|
||||
# on what part of C++ we're building--but they're pretty
|
||||
# fast to build, so build them all.
|
||||
|
||||
$compatTests = ('Tests\CommCompatClient', 'Tests\CommCompatServer', 'Tests\Compat', 'Tests\GrpcCompatClient', 'Tests\GrpcCompatServer')
|
||||
|
||||
msbuild cs\cs.sln /verbosity:minimal "/target:$($compatTests -join ';')" /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
|
||||
|
||||
mkdir build
|
||||
|
||||
cd build
|
||||
|
||||
cmake $cmakeFlags -G $cmakeGenerator ..
|
||||
cmake $cmakeFlags -G $cmakeGenerator .. 2>cmake_stderr.log
|
||||
|
||||
Get-Content cmake_stderr.log
|
||||
|
||||
}
|
||||
|
||||
|
@ -251,7 +307,7 @@
|
|||
nunit-console-x86 /framework:net-4.5 /labels "cs\test\core\bin\debug\net45\${env:BOND_OUTPUT}\Bond.UnitTest.dll" cs\test\internal\bin\debug\net45\Bond.InternalTest.dll
|
||||
if (-not $?) { throw "tests failed" }
|
||||
|
||||
& examples\cs\comm\grpc_pingpong\bin\Debug\pingpong.exe
|
||||
& examples\cs\grpc\pingpong\bin\Debug\pingpong.exe
|
||||
if (-not $?) { throw "tests failed" }
|
||||
|
||||
# We need to investigate why these tests are failing in AppVeyor, but not locally.
|
||||
|
|
|
@ -5,13 +5,14 @@ include (Folders)
|
|||
# add_bond_codegen (file.bond [file2.bond ...]
|
||||
# [ENUM_HEADER]
|
||||
# [COMM]
|
||||
# [GRPC]
|
||||
# [OUTPUT_DIR dir]
|
||||
# [IMPORT_DIR dir [dir2, ...]]
|
||||
# [OPTIONS opt [opt2 ...]])
|
||||
# [TARGET name]
|
||||
#
|
||||
function (add_bond_codegen)
|
||||
set (flagArgs ENUM_HEADER COMM)
|
||||
set (flagArgs ENUM_HEADER COMM GRPC)
|
||||
set (oneValueArgs OUTPUT_DIR TARGET)
|
||||
set (multiValueArgs IMPORT_DIR OPTIONS)
|
||||
cmake_parse_arguments (arg "${flagArgs}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
@ -19,7 +20,6 @@ function (add_bond_codegen)
|
|||
set (outputDir ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR})
|
||||
if (arg_OUTPUT_DIR)
|
||||
set (outputDir ${arg_OUTPUT_DIR})
|
||||
else()
|
||||
endif()
|
||||
list (APPEND options --output-dir="${outputDir}")
|
||||
list (APPEND options --import-dir="${BOND_IDL}")
|
||||
|
@ -32,6 +32,12 @@ function (add_bond_codegen)
|
|||
if (arg_ENUM_HEADER)
|
||||
list(APPEND options --enum-header)
|
||||
endif()
|
||||
if (arg_COMM)
|
||||
list(APPEND options --comm)
|
||||
endif()
|
||||
if (arg_GRPC)
|
||||
list(APPEND options --grpc)
|
||||
endif()
|
||||
set (inputs "${arg_UNPARSED_ARGUMENTS}")
|
||||
set (outputs)
|
||||
foreach (file ${inputs})
|
||||
|
@ -50,6 +56,9 @@ function (add_bond_codegen)
|
|||
list(APPEND outputs "${outputDir}/${name}_comm.cpp")
|
||||
list(APPEND outputs "${outputDir}/${name}_comm.h")
|
||||
endif()
|
||||
if (arg_GRPC)
|
||||
list(APPEND outputs "${outputDir}/${name}_grpc.h")
|
||||
endif()
|
||||
endforeach()
|
||||
# if BOND_GBC_PATH is not set we must add a dependency on the "gbc" target to build it
|
||||
if (NOT BOND_GBC_PATH)
|
||||
|
@ -74,12 +83,13 @@ endfunction()
|
|||
# add_bond_executable (name
|
||||
# [schem.bond [schema2.bond]]
|
||||
# source.cpp [source2.cpp]
|
||||
# [COMM])
|
||||
# [COMM]
|
||||
# [GRPC])
|
||||
#
|
||||
function (add_bond_executable target)
|
||||
set (schemas)
|
||||
set (sources)
|
||||
set (flagArgs COMM)
|
||||
set (flagArgs COMM GRPC)
|
||||
cmake_parse_arguments (arg "${flagArgs}" "" "" ${ARGN})
|
||||
foreach (file ${ARGV})
|
||||
get_filename_component (ext ${file} EXT)
|
||||
|
@ -93,13 +103,17 @@ function (add_bond_executable target)
|
|||
endif()
|
||||
endforeach()
|
||||
if (schemas)
|
||||
set (options)
|
||||
if (arg_COMM)
|
||||
add_bond_codegen (${schemas} COMM)
|
||||
else()
|
||||
add_bond_codegen (${schemas})
|
||||
list (APPEND options COMM)
|
||||
endif()
|
||||
if (arg_GRPC)
|
||||
list (APPEND options GRPC)
|
||||
endif()
|
||||
add_bond_codegen (${schemas} ${options})
|
||||
endif()
|
||||
list (REMOVE_ITEM ARGV COMM)
|
||||
list (REMOVE_ITEM ARGV GRPC)
|
||||
add_executable (${ARGV} ${sources})
|
||||
add_target_to_folder(${target})
|
||||
target_link_libraries (${target} PRIVATE
|
||||
|
@ -114,7 +128,9 @@ endfunction()
|
|||
# add_bond_test (name
|
||||
# [schem.bond [schema2.bond]]
|
||||
# source.cpp [source2.cpp]
|
||||
# [BUILD_ONLY])
|
||||
# [BUILD_ONLY]
|
||||
# [COMM]
|
||||
# [GRPC])
|
||||
#
|
||||
function (add_bond_test test)
|
||||
set (flagArgs BUILD_ONLY)
|
||||
|
|
|
@ -73,6 +73,20 @@ if (WIN32)
|
|||
PATHS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cs/test/compat/comm/client/bin/debug"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cs/test/compat/comm/client/bin/retail")
|
||||
|
||||
find_program (BOND_CSHARP_GRPC_COMPAT_SERVER GrpcCompatServer.exe
|
||||
PATH_SUFFIXES net45
|
||||
NO_DEFAULT_PATH
|
||||
PATHS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cs/test/compat/grpc/server/bin/debug"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cs/test/compat/grpc/server/bin/retail")
|
||||
|
||||
find_program (BOND_CSHARP_GRPC_COMPAT_CLIENT GrpcCompatClient.exe
|
||||
PATH_SUFFIXES net45
|
||||
NO_DEFAULT_PATH
|
||||
PATHS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cs/test/compat/grpc/client/bin/debug"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cs/test/compat/grpc/client/bin/retail")
|
||||
endif()
|
||||
|
||||
# find python interpreter, library and boost python library.
|
||||
|
@ -164,9 +178,9 @@ set (BOND_LIBRARIES_INSTALL_CPP
|
|||
"FALSE"
|
||||
CACHE BOOL "If TRUE, the generated .cpp files for the Bond libraries will be installed under src/ as part of the INSTALL target.")
|
||||
|
||||
set (BOND_CORE_ONLY
|
||||
"FALSE"
|
||||
CACHE BOOL "If TRUE, then only build the Bond Core")
|
||||
set (BOND_ENABLE_COMM
|
||||
"TRUE"
|
||||
CACHE BOOL "If FALSE, then do not build Comm")
|
||||
|
||||
set (BOND_SKIP_GBC_TESTS
|
||||
"FALSE"
|
||||
|
@ -176,6 +190,6 @@ set (BOND_SKIP_CORE_TESTS
|
|||
"FALSE"
|
||||
CACHE BOOL "If TRUE, then skip Bond Core tests and examples")
|
||||
|
||||
if ((NOT BOND_CORE_ONLY) AND ((CXX_STANDARD LESS 11) OR (MSVC_VERSION LESS 1800)))
|
||||
message(FATAL_ERROR "BOND_CORE_ONLY is FALSE but compiler specified does not support C++11 standard")
|
||||
if (((BOND_ENABLE_COMM) OR (BOND_ENABLE_GRPC)) AND ((CXX_STANDARD LESS 11) OR (MSVC_VERSION LESS 1800)))
|
||||
message(FATAL_ERROR "BOND_ENABLE_COMM and/or BOND_ENABLE_GRPC is TRUE but compiler specified does not support C++11 standard")
|
||||
endif()
|
||||
|
|
|
@ -69,16 +69,7 @@ writeSchema _ = error "writeSchema: impossible happened."
|
|||
cppCodegen :: Options -> IO()
|
||||
cppCodegen options@Cpp {..} = do
|
||||
let typeMapping = maybe cppTypeMapping cppCustomAllocTypeMapping allocator
|
||||
concurrentlyFor_ files $ codeGen options typeMapping $
|
||||
[ reflection_h export_attribute
|
||||
, types_h header enum_header allocator
|
||||
, types_cpp
|
||||
, apply_h applyProto export_attribute
|
||||
, apply_cpp applyProto
|
||||
, comm_h export_attribute
|
||||
, comm_cpp
|
||||
] <>
|
||||
[ enum_h | enum_header]
|
||||
concurrentlyFor_ files $ codeGen options typeMapping templates
|
||||
where
|
||||
applyProto = map snd $ filter (enabled apply) protocols
|
||||
enabled a p = null a || fst p `elem` a
|
||||
|
@ -91,6 +82,19 @@ cppCodegen options@Cpp {..} = do
|
|||
, (Simple, ProtocolReader " ::bond::SimpleBinaryReader< ::bond::InputBuffer>")
|
||||
, (Simple, ProtocolWriter " ::bond::SimpleBinaryWriter< ::bond::OutputBuffer>")
|
||||
]
|
||||
templates = concat $ map snd $ filter fst codegen_templates
|
||||
codegen_templates = [ (core_enabled, core_files)
|
||||
, (comm_enabled, [comm_h export_attribute, comm_cpp])
|
||||
, (grpc_enabled, [grpc_h export_attribute])
|
||||
]
|
||||
core_files = [
|
||||
reflection_h export_attribute
|
||||
, types_h header enum_header allocator
|
||||
, types_cpp
|
||||
, apply_h applyProto export_attribute
|
||||
, apply_cpp applyProto
|
||||
] <>
|
||||
[ enum_h | enum_header]
|
||||
cppCodegen _ = error "cppCodegen: impossible happened."
|
||||
|
||||
csCodegen :: Options -> IO()
|
||||
|
|
|
@ -38,6 +38,9 @@ data Options
|
|||
, export_attribute :: Maybe String
|
||||
, jobs :: Maybe Int
|
||||
, no_banner :: Bool
|
||||
, core_enabled :: Bool
|
||||
, comm_enabled :: Bool
|
||||
, grpc_enabled :: Bool
|
||||
}
|
||||
| Cs
|
||||
{ files :: [FilePath]
|
||||
|
@ -77,6 +80,9 @@ cpp = Cpp
|
|||
, export_attribute = def &= typ "ATTRIBUTE" &= explicit &= name "apply-attribute" &= name "export-attribute" &= help "Prefix declarations for library export with the specified C++ attribute/declspec. apply-attribute is a deprecated synonym."
|
||||
, jobs = def &= opt "0" &= typ "NUM" &= name "j" &= help "Run NUM jobs simultaneously (or '$ncpus' if no NUM is not given)"
|
||||
, no_banner = def &= help "Omit the banner at the top of generated files"
|
||||
, core_enabled = True &= explicit &= name "core" &= help "Generate core serialization definitions (true by default, --core=false to disable)"
|
||||
, comm_enabled = False &= explicit &= name "comm" &= help "Generate comm definitions"
|
||||
, grpc_enabled = False &= explicit &= name "grpc" &= help "Generate gRPC definitions"
|
||||
} &=
|
||||
name "c++" &=
|
||||
help "Generate C++ code"
|
||||
|
|
|
@ -65,6 +65,7 @@ library
|
|||
Language.Bond.Codegen.Cpp.Types_h
|
||||
Language.Bond.Codegen.Cpp.Comm_cpp
|
||||
Language.Bond.Codegen.Cpp.Comm_h
|
||||
Language.Bond.Codegen.Cpp.Grpc_h
|
||||
Language.Bond.Codegen.Cs.Types_cs
|
||||
Language.Bond.Codegen.Cs.Comm_cs
|
||||
Language.Bond.Codegen.Cs.Grpc_cs
|
||||
|
@ -86,6 +87,9 @@ test-suite gbc-tests
|
|||
build-depends: bond,
|
||||
aeson >= 0.7.0.6 && < 0.12.0.0,
|
||||
aeson-pretty == 0.7.2,
|
||||
-- pinned to a lower version pending resolution of
|
||||
-- https://github.com/feuerbach/ansi-terminal/issues/22
|
||||
ansi-terminal < 0.6.3,
|
||||
base >= 4.5 && < 5,
|
||||
bytestring >= 0.10,
|
||||
cmdargs >= 0.10.10,
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
-- Copyright (c) Microsoft. All rights reserved.
|
||||
-- Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
{-# LANGUAGE QuasiQuotes, OverloadedStrings, RecordWildCards #-}
|
||||
|
||||
module Language.Bond.Codegen.Cpp.Grpc_h (grpc_h) where
|
||||
|
||||
import System.FilePath
|
||||
import Data.Monoid
|
||||
import Prelude
|
||||
import qualified Data.Text.Lazy as L
|
||||
import Data.Text.Lazy.Builder
|
||||
import Text.Shakespeare.Text
|
||||
import Language.Bond.Syntax.Types
|
||||
import Language.Bond.Codegen.Util
|
||||
import Language.Bond.Codegen.TypeMapping
|
||||
import qualified Language.Bond.Codegen.Cpp.Util as CPP
|
||||
|
||||
|
||||
-- | Codegen template for generating /base_name/_grpc.h containing declarations of
|
||||
-- of service interface and proxy.
|
||||
grpc_h :: Maybe String -> MappingContext -> String -> [Import] -> [Declaration] -> (String, L.Text)
|
||||
grpc_h _ cpp file imports declarations = ("_grpc.h", [lt|
|
||||
#pragma once
|
||||
|
||||
#include "#{file}_reflection.h"
|
||||
#include "#{file}_types.h"
|
||||
#{newlineSep 0 includeImport imports}
|
||||
#include <bond/core/bonded.h>
|
||||
#include <bond/ext/grpc/bond_utils.h>
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
#include <bond/ext/grpc/detail/client_call_data.h>
|
||||
#include <bond/ext/grpc/detail/service.h>
|
||||
#include <bond/ext/grpc/detail/service_call_data.h>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4267)
|
||||
#endif
|
||||
|
||||
#include <grpc++/impl/codegen/channel_interface.h>
|
||||
#include <grpc++/impl/codegen/client_context.h>
|
||||
#include <grpc++/impl/codegen/completion_queue.h>
|
||||
#include <grpc++/impl/codegen/rpc_method.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#{CPP.openNamespace cpp}
|
||||
#{doubleLineSep 1 grpc declarations}
|
||||
|
||||
#{CPP.closeNamespace cpp}
|
||||
|
||||
|])
|
||||
where
|
||||
includeImport (Import path) = [lt|#include "#{dropExtension path}_grpc.h"|]
|
||||
|
||||
idl = MappingContext idlTypeMapping [] [] []
|
||||
|
||||
cppType = getTypeName cpp
|
||||
|
||||
payload = maybe "::bond::Void" cppType
|
||||
|
||||
bonded mt = bonded' (payload mt)
|
||||
where
|
||||
bonded' params = [lt|::bond::bonded<#{padLeft}#{params}>|]
|
||||
where
|
||||
paramsText = toLazyText params
|
||||
padLeft = if L.head paramsText == ':' then [lt| |] else mempty
|
||||
|
||||
grpc s@Service{..} = [lt|
|
||||
#{template}class #{declName} final
|
||||
{
|
||||
public:
|
||||
template <typename TThreadPool>
|
||||
class #{proxyName}
|
||||
{
|
||||
public:
|
||||
#{proxyName}(
|
||||
const std::shared_ptr< ::grpc::ChannelInterface>& channel,
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool);
|
||||
|
||||
#{doubleLineSep 2 publicProxyMethodDecl serviceMethods}
|
||||
|
||||
#{proxyName}(const #{proxyName}&) = delete;
|
||||
#{proxyName}& operator=(const #{proxyName}&) = delete;
|
||||
|
||||
#{proxyName}(#{proxyName}&&) = default;
|
||||
#{proxyName}& operator=(#{proxyName}&&) = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr< ::grpc::ChannelInterface> _channel;
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> _ioManager;
|
||||
std::shared_ptr<TThreadPool> _threadPool;
|
||||
|
||||
#{doubleLineSep 2 privateProxyMethodDecl serviceMethods}
|
||||
};
|
||||
|
||||
using Client = #{proxyName}< ::bond::ext::gRPC::thread_pool>;
|
||||
|
||||
template <typename TThreadPool>
|
||||
class #{serviceName} : public ::bond::ext::gRPC::detail::service<TThreadPool>
|
||||
{
|
||||
public:
|
||||
#{serviceName}()
|
||||
{
|
||||
#{newlineSep 3 serviceAddMethod serviceMethods}
|
||||
}
|
||||
|
||||
virtual ~#{serviceName}() { }
|
||||
#{serviceStartMethod}
|
||||
|
||||
#{newlineSep 2 serviceVirtualMethod serviceMethods}
|
||||
|
||||
private:
|
||||
#{newlineSep 2 serviceMethodReceiveData serviceMethods}
|
||||
};
|
||||
|
||||
using Service = #{serviceName}< ::bond::ext::gRPC::thread_pool>;
|
||||
};
|
||||
|
||||
#{template}template <typename TThreadPool>
|
||||
inline #{className}::#{proxyName}<TThreadPool>::#{proxyName}(
|
||||
const std::shared_ptr< ::grpc::ChannelInterface>& channel,
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool)
|
||||
: _channel(channel)
|
||||
, _ioManager(ioManager)
|
||||
, _threadPool(threadPool)
|
||||
#{newlineSep 1 proxyMethodMemberInit serviceMethods}
|
||||
{ }
|
||||
|
||||
#{doubleLineSep 0 methodDecl serviceMethods}
|
||||
|]
|
||||
where
|
||||
className = CPP.className s
|
||||
template = CPP.template s
|
||||
proxyName = "ClientCore" :: String
|
||||
serviceName = "ServiceCore" :: String
|
||||
|
||||
methodNames :: [String]
|
||||
methodNames = map methodName serviceMethods
|
||||
|
||||
serviceMethodsWithIndex :: [(Integer,Method)]
|
||||
serviceMethodsWithIndex = zip [0..] serviceMethods
|
||||
|
||||
publicProxyMethodDecl Function{methodInput = Nothing, ..} = [lt|void Async#{methodName}(::grpc::ClientContext* context, const std::function<void(const #{bonded methodResult}&, const ::grpc::Status&)>& cb);|]
|
||||
publicProxyMethodDecl Function{..} = [lt|void Async#{methodName}(::grpc::ClientContext* context, const #{bonded methodInput}& request, const std::function<void(const #{bonded methodResult}&, const ::grpc::Status&)>& cb);
|
||||
void Async#{methodName}(::grpc::ClientContext* context, const #{payload methodInput}& request, const std::function<void(const #{bonded methodResult}&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Async#{methodName}(context, #{bonded methodInput}{request}, cb);
|
||||
}|]
|
||||
publicProxyMethodDecl Event{methodInput = Nothing, ..} = [lt|void Async#{methodName}(::grpc::ClientContext* context);|]
|
||||
publicProxyMethodDecl Event{..} = [lt|void Async#{methodName}(::grpc::ClientContext* context, const #{bonded methodInput}& request);
|
||||
void Async#{methodName}(::grpc::ClientContext* context, const #{payload methodInput}& request)
|
||||
{
|
||||
Async#{methodName}(context, #{bonded methodInput}{request});
|
||||
}|]
|
||||
|
||||
privateProxyMethodDecl Function{..} = [lt|const ::grpc::RpcMethod rpcmethod_#{methodName}_;|]
|
||||
privateProxyMethodDecl Event{..} = [lt|const ::grpc::RpcMethod rpcmethod_#{methodName}_;|]
|
||||
|
||||
proxyMethodMemberInit Function{..} = [lt|, rpcmethod_#{methodName}_("/#{getDeclTypeName idl s}/#{methodName}", ::grpc::RpcMethod::NORMAL_RPC, channel)|]
|
||||
proxyMethodMemberInit Event{..} = [lt|, rpcmethod_#{methodName}_("/#{getDeclTypeName idl s}/#{methodName}", ::grpc::RpcMethod::NORMAL_RPC, channel)|]
|
||||
|
||||
methodDecl Function{..} = [lt|#{template}template <typename TThreadPool>
|
||||
inline void #{className}::#{proxyName}<TThreadPool>::Async#{methodName}(
|
||||
::grpc::ClientContext* context,
|
||||
#{voidParam methodInput}
|
||||
const std::function<void(const #{bonded methodResult}&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
#{voidRequest methodInput}
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< #{bonded methodInput}, #{bonded methodResult}, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_#{methodName}_, context, request);
|
||||
}|]
|
||||
where
|
||||
voidRequest Nothing = [lt|auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};|]
|
||||
voidRequest _ = mempty
|
||||
voidParam Nothing = mempty
|
||||
voidParam _ = [lt|const #{bonded methodInput}& request,|]
|
||||
|
||||
methodDecl Event{..} = [lt|#{template}template <typename TThreadPool>
|
||||
inline void #{className}::#{proxyName}<TThreadPool>::Async#{methodName}(
|
||||
::grpc::ClientContext* context
|
||||
#{voidParam methodInput})
|
||||
{
|
||||
#{voidRequest methodInput}
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< #{bonded methodInput}, #{bonded Nothing}, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool);
|
||||
calldata->dispatch(rpcmethod_#{methodName}_, context, request);
|
||||
}|]
|
||||
where
|
||||
voidRequest Nothing = [lt|auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};|]
|
||||
voidRequest _ = mempty
|
||||
voidParam Nothing = mempty
|
||||
voidParam _ = [lt|, const #{bonded methodInput}& request|]
|
||||
|
||||
serviceAddMethod Function{..} = [lt|this->AddMethod("/#{getDeclTypeName idl s}/#{methodName}");|]
|
||||
serviceAddMethod Event{..} = [lt|this->AddMethod("/#{getDeclTypeName idl s}/#{methodName}");|]
|
||||
|
||||
serviceStartMethod = [lt|virtual void start(
|
||||
::grpc::ServerCompletionQueue* #{cqParam},
|
||||
std::shared_ptr<TThreadPool> #{tpParam}) override
|
||||
{
|
||||
BOOST_ASSERT(#{cqParam});
|
||||
BOOST_ASSERT(#{tpParam});
|
||||
|
||||
#{newlineSep 3 initMethodReceiveData serviceMethodsWithIndex}
|
||||
|
||||
#{newlineSep 3 queueReceive serviceMethodsWithIndex}
|
||||
}|]
|
||||
where cqParam = uniqueName "cq" methodNames
|
||||
tpParam = uniqueName "tp" methodNames
|
||||
initMethodReceiveData (index,Function{..}) = [lt|#{serviceRdMember methodName}.emplace(
|
||||
this,
|
||||
#{index},
|
||||
#{cqParam},
|
||||
#{tpParam},
|
||||
std::bind(&#{serviceName}::#{methodName}, this, std::placeholders::_1));|]
|
||||
initMethodReceiveData (index,Event{..}) = [lt|#{serviceRdMember methodName}.emplace(
|
||||
this,
|
||||
#{index},
|
||||
#{cqParam},
|
||||
#{tpParam},
|
||||
std::bind(&#{serviceName}::#{methodName}, this, std::placeholders::_1));|]
|
||||
queueReceive (index,Function{..}) = [lt|this->queue_receive(
|
||||
#{index},
|
||||
&#{serviceRdMember methodName}->_receivedCall->_context,
|
||||
&#{serviceRdMember methodName}->_receivedCall->_request,
|
||||
&#{serviceRdMember methodName}->_receivedCall->_responder,
|
||||
#{cqParam},
|
||||
&#{serviceRdMember methodName}.get());|]
|
||||
queueReceive (index,Event{..}) = [lt|this->queue_receive(
|
||||
#{index},
|
||||
&#{serviceRdMember methodName}->_receivedCall->_context,
|
||||
&#{serviceRdMember methodName}->_receivedCall->_request,
|
||||
&#{serviceRdMember methodName}->_receivedCall->_responder,
|
||||
#{cqParam},
|
||||
&#{serviceRdMember methodName}.get());|]
|
||||
|
||||
serviceMethodReceiveData Function{..} = [lt|::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< #{bonded methodInput}, #{payload methodResult}, TThreadPool>> #{serviceRdMember methodName};|]
|
||||
serviceMethodReceiveData Event{..} = [lt|::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< #{bonded methodInput}, #{payload Nothing}, TThreadPool>> #{serviceRdMember methodName};|]
|
||||
|
||||
serviceVirtualMethod Function{..} = [lt|virtual void #{methodName}(::bond::ext::gRPC::unary_call< #{bonded methodInput}, #{payload methodResult}>) = 0;|]
|
||||
serviceVirtualMethod Event{..} = [lt|virtual void #{methodName}(::bond::ext::gRPC::unary_call< #{bonded methodInput}, #{payload Nothing}>) = 0;|]
|
||||
|
||||
serviceRdMember methodName = uniqueName ("_rd_" ++ methodName) methodNames
|
||||
|
||||
grpc _ = mempty
|
|
@ -44,6 +44,7 @@ module Language.Bond.Codegen.Templates
|
|||
-- ** C++ Comm
|
||||
, comm_h
|
||||
, comm_cpp
|
||||
, grpc_h
|
||||
-- ** C#
|
||||
, FieldMapping(..)
|
||||
, StructMapping(..)
|
||||
|
@ -64,6 +65,7 @@ import Language.Bond.Codegen.Cpp.Types_cpp
|
|||
import Language.Bond.Codegen.Cpp.Types_h
|
||||
import Language.Bond.Codegen.Cpp.Comm_cpp
|
||||
import Language.Bond.Codegen.Cpp.Comm_h
|
||||
import Language.Bond.Codegen.Cpp.Grpc_h
|
||||
import Language.Bond.Codegen.Cs.Types_cs
|
||||
import Language.Bond.Codegen.Cs.Comm_cs
|
||||
import Language.Bond.Codegen.Cs.Grpc_cs
|
||||
|
|
|
@ -128,6 +128,20 @@ tests = testGroup "Compiler tests"
|
|||
]
|
||||
"service_attributes"
|
||||
]
|
||||
, testGroup "Grpc"
|
||||
[ verifyCppGrpcCodegen
|
||||
[ "c++"
|
||||
]
|
||||
"service"
|
||||
, verifyCppGrpcCodegen
|
||||
[ "c++"
|
||||
]
|
||||
"generic_service"
|
||||
, verifyCppGrpcCodegen
|
||||
[ "c++"
|
||||
]
|
||||
"service_attributes"
|
||||
]
|
||||
]
|
||||
, testGroup "C#"
|
||||
[ verifyCsCodegen "attributes"
|
||||
|
|
|
@ -8,6 +8,7 @@ module Tests.Codegen
|
|||
( verifyCodegen
|
||||
, verifyCppCodegen
|
||||
, verifyCppCommCodegen
|
||||
, verifyCppGrpcCodegen
|
||||
, verifyApplyCodegen
|
||||
, verifyExportsCodegen
|
||||
, verifyCsCodegen
|
||||
|
@ -87,6 +88,17 @@ verifyCppCommCodegen args baseName =
|
|||
, types_cpp
|
||||
]
|
||||
|
||||
verifyCppGrpcCodegen :: [String] -> FilePath -> TestTree
|
||||
verifyCppGrpcCodegen args baseName =
|
||||
testGroup baseName $
|
||||
map (verifyFile options baseName cppTypeMapping "") templates
|
||||
where
|
||||
options = processOptions args
|
||||
templates =
|
||||
[ grpc_h (export_attribute options)
|
||||
, types_cpp
|
||||
]
|
||||
|
||||
verifyCsCommCodegen :: [String] -> FilePath -> TestTree
|
||||
verifyCsCommCodegen args baseName =
|
||||
testGroup baseName $
|
||||
|
|
|
@ -46,6 +46,9 @@ namespace tests
|
|||
virtual void foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) = 0;
|
||||
|
||||
virtual void _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) = 0;
|
||||
|
||||
virtual void foo34(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) = 0;
|
||||
|
||||
|
@ -61,6 +64,9 @@ namespace tests
|
|||
virtual void foo44(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::dummy>&)>& callback) = 0;
|
||||
|
||||
virtual void cq(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) = 0;
|
||||
|
||||
struct Schema;
|
||||
class Proxy;
|
||||
|
||||
|
@ -100,6 +106,8 @@ namespace tests
|
|||
private: DllExport
|
||||
static const ::bond::Metadata s_foo33_metadata;
|
||||
private: DllExport
|
||||
static const ::bond::Metadata s__rd_foo33_metadata;
|
||||
private: DllExport
|
||||
static const ::bond::Metadata s_foo34_metadata;
|
||||
private: DllExport
|
||||
static const ::bond::Metadata s_foo41_metadata;
|
||||
|
@ -109,6 +117,8 @@ namespace tests
|
|||
static const ::bond::Metadata s_foo43_metadata;
|
||||
private: DllExport
|
||||
static const ::bond::Metadata s_foo44_metadata;
|
||||
private: DllExport
|
||||
static const ::bond::Metadata s_cq_metadata;
|
||||
|
||||
public: struct service
|
||||
{
|
||||
|
@ -216,6 +226,14 @@ namespace tests
|
|||
&s_foo33_metadata
|
||||
> foo33;
|
||||
|
||||
typedef ::bond::reflection::MethodTemplate<
|
||||
Foo,
|
||||
::bond::comm::payload< ::tests::BasicTypes>,
|
||||
::bond::comm::message< ::tests::BasicTypes>,
|
||||
&Foo::_rd_foo33,
|
||||
&s__rd_foo33_metadata
|
||||
> _rd_foo33;
|
||||
|
||||
typedef ::bond::reflection::MethodTemplate<
|
||||
Foo,
|
||||
::bond::comm::payload< ::tests::dummy>,
|
||||
|
@ -255,29 +273,39 @@ namespace tests
|
|||
&Foo::foo44,
|
||||
&s_foo44_metadata
|
||||
> foo44;
|
||||
|
||||
typedef ::bond::reflection::MethodTemplate<
|
||||
Foo,
|
||||
::bond::comm::payload<void>,
|
||||
::bond::comm::message< ::tests::BasicTypes>,
|
||||
&Foo::cq,
|
||||
&s_cq_metadata
|
||||
> cq;
|
||||
};
|
||||
|
||||
private: typedef boost::mpl::list<> methods0;
|
||||
private: typedef boost::mpl::push_front<methods0, service::foo44>::type methods1;
|
||||
private: typedef boost::mpl::push_front<methods1, service::foo43>::type methods2;
|
||||
private: typedef boost::mpl::push_front<methods2, service::foo42>::type methods3;
|
||||
private: typedef boost::mpl::push_front<methods3, service::foo41>::type methods4;
|
||||
private: typedef boost::mpl::push_front<methods4, service::foo34>::type methods5;
|
||||
private: typedef boost::mpl::push_front<methods5, service::foo33>::type methods6;
|
||||
private: typedef boost::mpl::push_front<methods6, service::foo32>::type methods7;
|
||||
private: typedef boost::mpl::push_front<methods7, service::foo31>::type methods8;
|
||||
private: typedef boost::mpl::push_front<methods8, service::foo24>::type methods9;
|
||||
private: typedef boost::mpl::push_front<methods9, service::foo23>::type methods10;
|
||||
private: typedef boost::mpl::push_front<methods10, service::foo22>::type methods11;
|
||||
private: typedef boost::mpl::push_front<methods11, service::foo21>::type methods12;
|
||||
private: typedef boost::mpl::push_front<methods12, service::foo15>::type methods13;
|
||||
private: typedef boost::mpl::push_front<methods13, service::foo14>::type methods14;
|
||||
private: typedef boost::mpl::push_front<methods14, service::foo13>::type methods15;
|
||||
private: typedef boost::mpl::push_front<methods15, service::foo12_impl>::type methods16;
|
||||
private: typedef boost::mpl::push_front<methods16, service::foo12>::type methods17;
|
||||
private: typedef boost::mpl::push_front<methods17, service::foo11>::type methods18;
|
||||
private: typedef boost::mpl::push_front<methods0, service::cq>::type methods1;
|
||||
private: typedef boost::mpl::push_front<methods1, service::foo44>::type methods2;
|
||||
private: typedef boost::mpl::push_front<methods2, service::foo43>::type methods3;
|
||||
private: typedef boost::mpl::push_front<methods3, service::foo42>::type methods4;
|
||||
private: typedef boost::mpl::push_front<methods4, service::foo41>::type methods5;
|
||||
private: typedef boost::mpl::push_front<methods5, service::foo34>::type methods6;
|
||||
private: typedef boost::mpl::push_front<methods6, service::_rd_foo33>::type methods7;
|
||||
private: typedef boost::mpl::push_front<methods7, service::foo33>::type methods8;
|
||||
private: typedef boost::mpl::push_front<methods8, service::foo32>::type methods9;
|
||||
private: typedef boost::mpl::push_front<methods9, service::foo31>::type methods10;
|
||||
private: typedef boost::mpl::push_front<methods10, service::foo24>::type methods11;
|
||||
private: typedef boost::mpl::push_front<methods11, service::foo23>::type methods12;
|
||||
private: typedef boost::mpl::push_front<methods12, service::foo22>::type methods13;
|
||||
private: typedef boost::mpl::push_front<methods13, service::foo21>::type methods14;
|
||||
private: typedef boost::mpl::push_front<methods14, service::foo15>::type methods15;
|
||||
private: typedef boost::mpl::push_front<methods15, service::foo14>::type methods16;
|
||||
private: typedef boost::mpl::push_front<methods16, service::foo13>::type methods17;
|
||||
private: typedef boost::mpl::push_front<methods17, service::foo12_impl>::type methods18;
|
||||
private: typedef boost::mpl::push_front<methods18, service::foo12>::type methods19;
|
||||
private: typedef boost::mpl::push_front<methods19, service::foo11>::type methods20;
|
||||
|
||||
public: typedef methods18::type methods;
|
||||
public: typedef methods20::type methods;
|
||||
|
||||
};
|
||||
|
||||
|
@ -444,6 +472,18 @@ namespace tests
|
|||
_impl->foo33(boost::cref(input), callback);
|
||||
}
|
||||
|
||||
void _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
_impl->_rd_foo33(input, callback);
|
||||
}
|
||||
|
||||
void _rd_foo33(const ::tests::BasicTypes& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback)
|
||||
{
|
||||
_impl->_rd_foo33(boost::cref(input), callback);
|
||||
}
|
||||
|
||||
void foo34(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
|
@ -504,6 +544,18 @@ namespace tests
|
|||
_impl->foo44(boost::cref(input), callback);
|
||||
}
|
||||
|
||||
void cq(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
_impl->cq(input, callback);
|
||||
}
|
||||
|
||||
void cq(
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback)
|
||||
{
|
||||
_impl->cq(::bond::comm::payload<void>(), callback);
|
||||
}
|
||||
|
||||
template <template <typename> class Promise>
|
||||
class Using;
|
||||
|
||||
|
@ -594,6 +646,12 @@ namespace tests
|
|||
_proxy.Send(_name, Schema::service::foo33::metadata.name, input, callback);
|
||||
}
|
||||
|
||||
void _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
_proxy.Send(_name, Schema::service::_rd_foo33::metadata.name, input, callback);
|
||||
}
|
||||
|
||||
void foo34(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
|
@ -624,6 +682,12 @@ namespace tests
|
|||
_proxy.Send(_name, Schema::service::foo44::metadata.name, input, callback);
|
||||
}
|
||||
|
||||
void cq(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
_proxy.Send(_name, Schema::service::cq::metadata.name, input, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
ServiceProxy _proxy;
|
||||
const std::string _name;
|
||||
|
@ -656,6 +720,9 @@ namespace tests
|
|||
virtual auto foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future()) = 0;
|
||||
|
||||
virtual auto _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future()) = 0;
|
||||
|
||||
virtual auto foo34(const ::bond::comm::payload< ::tests::dummy>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future()) = 0;
|
||||
|
||||
|
@ -671,6 +738,9 @@ namespace tests
|
|||
virtual auto foo44(const ::bond::comm::payload< ::tests::dummy>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::dummy>>>().get_future()) = 0;
|
||||
|
||||
virtual auto cq(const ::bond::comm::payload<void>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future()) = 0;
|
||||
|
||||
void foo21(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
|
||||
{
|
||||
|
@ -713,6 +783,12 @@ namespace tests
|
|||
when(foo33(input), ::bond::comm::Continuation(callback));
|
||||
}
|
||||
|
||||
void _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
when(_rd_foo33(input), ::bond::comm::Continuation(callback));
|
||||
}
|
||||
|
||||
void foo34(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
|
@ -742,6 +818,12 @@ namespace tests
|
|||
{
|
||||
when(foo44(input), ::bond::comm::Continuation(callback));
|
||||
}
|
||||
|
||||
void cq(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
when(cq(input), ::bond::comm::Continuation(callback));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename> class Promise>
|
||||
|
@ -920,6 +1002,29 @@ namespace tests
|
|||
}
|
||||
|
||||
|
||||
using Foo::Proxy::_rd_foo33;
|
||||
|
||||
auto _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future())
|
||||
{
|
||||
auto promise = boost::make_shared<Promise< ::bond::comm::message< ::tests::BasicTypes>>>();
|
||||
|
||||
_impl->_rd_foo33(input,
|
||||
[=](const ::bond::comm::message< ::tests::BasicTypes>& result) mutable
|
||||
{
|
||||
promise->set_value(result);
|
||||
});
|
||||
|
||||
return promise->get_future();
|
||||
}
|
||||
|
||||
auto _rd_foo33(const ::tests::BasicTypes& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future())
|
||||
{
|
||||
return _rd_foo33(::bond::comm::payload< ::tests::BasicTypes>(boost::cref(input)));
|
||||
}
|
||||
|
||||
|
||||
using Foo::Proxy::foo34;
|
||||
|
||||
auto foo34(const ::bond::comm::payload< ::tests::dummy>& input)
|
||||
|
@ -1032,6 +1137,28 @@ namespace tests
|
|||
return foo44(::bond::comm::payload< ::tests::dummy>(boost::cref(input)));
|
||||
}
|
||||
|
||||
|
||||
using Foo::Proxy::cq;
|
||||
|
||||
auto cq(const ::bond::comm::payload<void>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future())
|
||||
{
|
||||
auto promise = boost::make_shared<Promise< ::bond::comm::message< ::tests::BasicTypes>>>();
|
||||
|
||||
_impl->cq(input,
|
||||
[=](const ::bond::comm::message< ::tests::BasicTypes>& result) mutable
|
||||
{
|
||||
promise->set_value(result);
|
||||
});
|
||||
|
||||
return promise->get_future();
|
||||
}
|
||||
|
||||
auto cq()
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future())
|
||||
{
|
||||
return cq(::bond::comm::payload<void>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "generic_service_reflection.h"
|
||||
#include "generic_service_types.h"
|
||||
|
||||
#include <bond/core/bonded.h>
|
||||
#include <bond/ext/grpc/bond_utils.h>
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
#include <bond/ext/grpc/detail/client_call_data.h>
|
||||
#include <bond/ext/grpc/detail/service.h>
|
||||
#include <bond/ext/grpc/detail/service_call_data.h>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4267)
|
||||
#endif
|
||||
|
||||
#include <grpc++/impl/codegen/channel_interface.h>
|
||||
#include <grpc++/impl/codegen/client_context.h>
|
||||
#include <grpc++/impl/codegen/completion_queue.h>
|
||||
#include <grpc++/impl/codegen/rpc_method.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
namespace tests
|
||||
{
|
||||
|
||||
template <typename Payload>
|
||||
class Foo final
|
||||
{
|
||||
public:
|
||||
template <typename TThreadPool>
|
||||
class ClientCore
|
||||
{
|
||||
public:
|
||||
ClientCore(
|
||||
const std::shared_ptr< ::grpc::ChannelInterface>& channel,
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool);
|
||||
|
||||
void Asyncfoo31(::grpc::ClientContext* context, const ::bond::bonded<Payload>& request, const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo31(::grpc::ClientContext* context, const Payload& request, const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo31(context, ::bond::bonded<Payload>{request}, cb);
|
||||
}
|
||||
|
||||
void Asyncfoo32(::grpc::ClientContext* context, const std::function<void(const ::bond::bonded<Payload>&, const ::grpc::Status&)>& cb);
|
||||
|
||||
void Asyncfoo33(::grpc::ClientContext* context, const ::bond::bonded<Payload>& request, const std::function<void(const ::bond::bonded<Payload>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo33(::grpc::ClientContext* context, const Payload& request, const std::function<void(const ::bond::bonded<Payload>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo33(context, ::bond::bonded<Payload>{request}, cb);
|
||||
}
|
||||
|
||||
ClientCore(const ClientCore&) = delete;
|
||||
ClientCore& operator=(const ClientCore&) = delete;
|
||||
|
||||
ClientCore(ClientCore&&) = default;
|
||||
ClientCore& operator=(ClientCore&&) = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr< ::grpc::ChannelInterface> _channel;
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> _ioManager;
|
||||
std::shared_ptr<TThreadPool> _threadPool;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo31_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo32_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo33_;
|
||||
};
|
||||
|
||||
using Client = ClientCore< ::bond::ext::gRPC::thread_pool>;
|
||||
|
||||
template <typename TThreadPool>
|
||||
class ServiceCore : public ::bond::ext::gRPC::detail::service<TThreadPool>
|
||||
{
|
||||
public:
|
||||
ServiceCore()
|
||||
{
|
||||
this->AddMethod("/tests.Foo/foo31");
|
||||
this->AddMethod("/tests.Foo/foo32");
|
||||
this->AddMethod("/tests.Foo/foo33");
|
||||
}
|
||||
|
||||
virtual ~ServiceCore() { }
|
||||
virtual void start(
|
||||
::grpc::ServerCompletionQueue* cq,
|
||||
std::shared_ptr<TThreadPool> tp) override
|
||||
{
|
||||
BOOST_ASSERT(cq);
|
||||
BOOST_ASSERT(tp);
|
||||
|
||||
_rd_foo31.emplace(
|
||||
this,
|
||||
0,
|
||||
cq,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo31, this, std::placeholders::_1));
|
||||
_rd_foo32.emplace(
|
||||
this,
|
||||
1,
|
||||
cq,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo32, this, std::placeholders::_1));
|
||||
_rd_foo33.emplace(
|
||||
this,
|
||||
2,
|
||||
cq,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo33, this, std::placeholders::_1));
|
||||
|
||||
this->queue_receive(
|
||||
0,
|
||||
&_rd_foo31->_receivedCall->_context,
|
||||
&_rd_foo31->_receivedCall->_request,
|
||||
&_rd_foo31->_receivedCall->_responder,
|
||||
cq,
|
||||
&_rd_foo31.get());
|
||||
this->queue_receive(
|
||||
1,
|
||||
&_rd_foo32->_receivedCall->_context,
|
||||
&_rd_foo32->_receivedCall->_request,
|
||||
&_rd_foo32->_receivedCall->_responder,
|
||||
cq,
|
||||
&_rd_foo32.get());
|
||||
this->queue_receive(
|
||||
2,
|
||||
&_rd_foo33->_receivedCall->_context,
|
||||
&_rd_foo33->_receivedCall->_request,
|
||||
&_rd_foo33->_receivedCall->_responder,
|
||||
cq,
|
||||
&_rd_foo33.get());
|
||||
}
|
||||
|
||||
virtual void foo31(::bond::ext::gRPC::unary_call< ::bond::bonded<Payload>, ::bond::Void>) = 0;
|
||||
virtual void foo32(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, Payload>) = 0;
|
||||
virtual void foo33(::bond::ext::gRPC::unary_call< ::bond::bonded<Payload>, Payload>) = 0;
|
||||
|
||||
private:
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded<Payload>, ::bond::Void, TThreadPool>> _rd_foo31;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, Payload, TThreadPool>> _rd_foo32;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded<Payload>, Payload, TThreadPool>> _rd_foo33;
|
||||
};
|
||||
|
||||
using Service = ServiceCore< ::bond::ext::gRPC::thread_pool>;
|
||||
};
|
||||
|
||||
template <typename Payload>
|
||||
template <typename TThreadPool>
|
||||
inline Foo<Payload>::ClientCore<TThreadPool>::ClientCore(
|
||||
const std::shared_ptr< ::grpc::ChannelInterface>& channel,
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool)
|
||||
: _channel(channel)
|
||||
, _ioManager(ioManager)
|
||||
, _threadPool(threadPool)
|
||||
, rpcmethod_foo31_("/tests.Foo/foo31", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo32_("/tests.Foo/foo32", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo33_("/tests.Foo/foo33", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
{ }
|
||||
|
||||
template <typename Payload>
|
||||
template <typename TThreadPool>
|
||||
inline void Foo<Payload>::ClientCore<TThreadPool>::Asyncfoo31(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded<Payload>& request,
|
||||
const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded<Payload>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo31_, context, request);
|
||||
}
|
||||
|
||||
template <typename Payload>
|
||||
template <typename TThreadPool>
|
||||
inline void Foo<Payload>::ClientCore<TThreadPool>::Asyncfoo32(
|
||||
::grpc::ClientContext* context,
|
||||
|
||||
const std::function<void(const ::bond::bonded<Payload>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded<Payload>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo32_, context, request);
|
||||
}
|
||||
|
||||
template <typename Payload>
|
||||
template <typename TThreadPool>
|
||||
inline void Foo<Payload>::ClientCore<TThreadPool>::Asyncfoo33(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded<Payload>& request,
|
||||
const std::function<void(const ::bond::bonded<Payload>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded<Payload>, ::bond::bonded<Payload>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo33_, context, request);
|
||||
}
|
||||
|
||||
|
||||
} // namespace tests
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "service_attributes_reflection.h"
|
||||
#include "service_attributes_types.h"
|
||||
|
||||
#include <bond/core/bonded.h>
|
||||
#include <bond/ext/grpc/bond_utils.h>
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
#include <bond/ext/grpc/detail/client_call_data.h>
|
||||
#include <bond/ext/grpc/detail/service.h>
|
||||
#include <bond/ext/grpc/detail/service_call_data.h>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4267)
|
||||
#endif
|
||||
|
||||
#include <grpc++/impl/codegen/channel_interface.h>
|
||||
#include <grpc++/impl/codegen/client_context.h>
|
||||
#include <grpc++/impl/codegen/completion_queue.h>
|
||||
#include <grpc++/impl/codegen/rpc_method.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
namespace tests
|
||||
{
|
||||
|
||||
class Foo final
|
||||
{
|
||||
public:
|
||||
template <typename TThreadPool>
|
||||
class ClientCore
|
||||
{
|
||||
public:
|
||||
ClientCore(
|
||||
const std::shared_ptr< ::grpc::ChannelInterface>& channel,
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool);
|
||||
|
||||
void Asyncfoo(::grpc::ClientContext* context, const ::bond::bonded< ::tests::Param>& request, const std::function<void(const ::bond::bonded< ::tests::Result>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo(::grpc::ClientContext* context, const ::tests::Param& request, const std::function<void(const ::bond::bonded< ::tests::Result>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo(context, ::bond::bonded< ::tests::Param>{request}, cb);
|
||||
}
|
||||
|
||||
ClientCore(const ClientCore&) = delete;
|
||||
ClientCore& operator=(const ClientCore&) = delete;
|
||||
|
||||
ClientCore(ClientCore&&) = default;
|
||||
ClientCore& operator=(ClientCore&&) = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr< ::grpc::ChannelInterface> _channel;
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> _ioManager;
|
||||
std::shared_ptr<TThreadPool> _threadPool;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo_;
|
||||
};
|
||||
|
||||
using Client = ClientCore< ::bond::ext::gRPC::thread_pool>;
|
||||
|
||||
template <typename TThreadPool>
|
||||
class ServiceCore : public ::bond::ext::gRPC::detail::service<TThreadPool>
|
||||
{
|
||||
public:
|
||||
ServiceCore()
|
||||
{
|
||||
this->AddMethod("/tests.Foo/foo");
|
||||
}
|
||||
|
||||
virtual ~ServiceCore() { }
|
||||
virtual void start(
|
||||
::grpc::ServerCompletionQueue* cq,
|
||||
std::shared_ptr<TThreadPool> tp) override
|
||||
{
|
||||
BOOST_ASSERT(cq);
|
||||
BOOST_ASSERT(tp);
|
||||
|
||||
_rd_foo.emplace(
|
||||
this,
|
||||
0,
|
||||
cq,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo, this, std::placeholders::_1));
|
||||
|
||||
this->queue_receive(
|
||||
0,
|
||||
&_rd_foo->_receivedCall->_context,
|
||||
&_rd_foo->_receivedCall->_request,
|
||||
&_rd_foo->_receivedCall->_responder,
|
||||
cq,
|
||||
&_rd_foo.get());
|
||||
}
|
||||
|
||||
virtual void foo(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::Param>, ::tests::Result>) = 0;
|
||||
|
||||
private:
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::Param>, ::tests::Result, TThreadPool>> _rd_foo;
|
||||
};
|
||||
|
||||
using Service = ServiceCore< ::bond::ext::gRPC::thread_pool>;
|
||||
};
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline Foo::ClientCore<TThreadPool>::ClientCore(
|
||||
const std::shared_ptr< ::grpc::ChannelInterface>& channel,
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool)
|
||||
: _channel(channel)
|
||||
, _ioManager(ioManager)
|
||||
, _threadPool(threadPool)
|
||||
, rpcmethod_foo_("/tests.Foo/foo", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
{ }
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded< ::tests::Param>& request,
|
||||
const std::function<void(const ::bond::bonded< ::tests::Result>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::Param>, ::bond::bonded< ::tests::Result>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo_, context, request);
|
||||
}
|
||||
|
||||
|
||||
} // namespace tests
|
||||
|
|
@ -49,6 +49,9 @@ namespace tests
|
|||
const ::bond::Metadata Foo::Schema::s_foo33_metadata
|
||||
= ::bond::reflection::MetadataInit("foo33");
|
||||
|
||||
const ::bond::Metadata Foo::Schema::s__rd_foo33_metadata
|
||||
= ::bond::reflection::MetadataInit("_rd_foo33");
|
||||
|
||||
const ::bond::Metadata Foo::Schema::s_foo34_metadata
|
||||
= ::bond::reflection::MetadataInit("foo34");
|
||||
|
||||
|
@ -63,6 +66,9 @@ namespace tests
|
|||
|
||||
const ::bond::Metadata Foo::Schema::s_foo44_metadata
|
||||
= ::bond::reflection::MetadataInit("foo44");
|
||||
|
||||
const ::bond::Metadata Foo::Schema::s_cq_metadata
|
||||
= ::bond::reflection::MetadataInit("cq");
|
||||
|
||||
|
||||
} // namespace tests
|
||||
|
|
|
@ -46,6 +46,9 @@ namespace tests
|
|||
virtual void foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) = 0;
|
||||
|
||||
virtual void _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) = 0;
|
||||
|
||||
virtual void foo34(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) = 0;
|
||||
|
||||
|
@ -61,6 +64,9 @@ namespace tests
|
|||
virtual void foo44(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::dummy>&)>& callback) = 0;
|
||||
|
||||
virtual void cq(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) = 0;
|
||||
|
||||
struct Schema;
|
||||
class Proxy;
|
||||
|
||||
|
@ -85,11 +91,13 @@ namespace tests
|
|||
private: static const ::bond::Metadata s_foo31_metadata;
|
||||
private: static const ::bond::Metadata s_foo32_metadata;
|
||||
private: static const ::bond::Metadata s_foo33_metadata;
|
||||
private: static const ::bond::Metadata s__rd_foo33_metadata;
|
||||
private: static const ::bond::Metadata s_foo34_metadata;
|
||||
private: static const ::bond::Metadata s_foo41_metadata;
|
||||
private: static const ::bond::Metadata s_foo42_metadata;
|
||||
private: static const ::bond::Metadata s_foo43_metadata;
|
||||
private: static const ::bond::Metadata s_foo44_metadata;
|
||||
private: static const ::bond::Metadata s_cq_metadata;
|
||||
|
||||
public: struct service
|
||||
{
|
||||
|
@ -197,6 +205,14 @@ namespace tests
|
|||
&s_foo33_metadata
|
||||
> foo33;
|
||||
|
||||
typedef ::bond::reflection::MethodTemplate<
|
||||
Foo,
|
||||
::bond::comm::payload< ::tests::BasicTypes>,
|
||||
::bond::comm::message< ::tests::BasicTypes>,
|
||||
&Foo::_rd_foo33,
|
||||
&s__rd_foo33_metadata
|
||||
> _rd_foo33;
|
||||
|
||||
typedef ::bond::reflection::MethodTemplate<
|
||||
Foo,
|
||||
::bond::comm::payload< ::tests::dummy>,
|
||||
|
@ -236,29 +252,39 @@ namespace tests
|
|||
&Foo::foo44,
|
||||
&s_foo44_metadata
|
||||
> foo44;
|
||||
|
||||
typedef ::bond::reflection::MethodTemplate<
|
||||
Foo,
|
||||
::bond::comm::payload<void>,
|
||||
::bond::comm::message< ::tests::BasicTypes>,
|
||||
&Foo::cq,
|
||||
&s_cq_metadata
|
||||
> cq;
|
||||
};
|
||||
|
||||
private: typedef boost::mpl::list<> methods0;
|
||||
private: typedef boost::mpl::push_front<methods0, service::foo44>::type methods1;
|
||||
private: typedef boost::mpl::push_front<methods1, service::foo43>::type methods2;
|
||||
private: typedef boost::mpl::push_front<methods2, service::foo42>::type methods3;
|
||||
private: typedef boost::mpl::push_front<methods3, service::foo41>::type methods4;
|
||||
private: typedef boost::mpl::push_front<methods4, service::foo34>::type methods5;
|
||||
private: typedef boost::mpl::push_front<methods5, service::foo33>::type methods6;
|
||||
private: typedef boost::mpl::push_front<methods6, service::foo32>::type methods7;
|
||||
private: typedef boost::mpl::push_front<methods7, service::foo31>::type methods8;
|
||||
private: typedef boost::mpl::push_front<methods8, service::foo24>::type methods9;
|
||||
private: typedef boost::mpl::push_front<methods9, service::foo23>::type methods10;
|
||||
private: typedef boost::mpl::push_front<methods10, service::foo22>::type methods11;
|
||||
private: typedef boost::mpl::push_front<methods11, service::foo21>::type methods12;
|
||||
private: typedef boost::mpl::push_front<methods12, service::foo15>::type methods13;
|
||||
private: typedef boost::mpl::push_front<methods13, service::foo14>::type methods14;
|
||||
private: typedef boost::mpl::push_front<methods14, service::foo13>::type methods15;
|
||||
private: typedef boost::mpl::push_front<methods15, service::foo12_impl>::type methods16;
|
||||
private: typedef boost::mpl::push_front<methods16, service::foo12>::type methods17;
|
||||
private: typedef boost::mpl::push_front<methods17, service::foo11>::type methods18;
|
||||
private: typedef boost::mpl::push_front<methods0, service::cq>::type methods1;
|
||||
private: typedef boost::mpl::push_front<methods1, service::foo44>::type methods2;
|
||||
private: typedef boost::mpl::push_front<methods2, service::foo43>::type methods3;
|
||||
private: typedef boost::mpl::push_front<methods3, service::foo42>::type methods4;
|
||||
private: typedef boost::mpl::push_front<methods4, service::foo41>::type methods5;
|
||||
private: typedef boost::mpl::push_front<methods5, service::foo34>::type methods6;
|
||||
private: typedef boost::mpl::push_front<methods6, service::_rd_foo33>::type methods7;
|
||||
private: typedef boost::mpl::push_front<methods7, service::foo33>::type methods8;
|
||||
private: typedef boost::mpl::push_front<methods8, service::foo32>::type methods9;
|
||||
private: typedef boost::mpl::push_front<methods9, service::foo31>::type methods10;
|
||||
private: typedef boost::mpl::push_front<methods10, service::foo24>::type methods11;
|
||||
private: typedef boost::mpl::push_front<methods11, service::foo23>::type methods12;
|
||||
private: typedef boost::mpl::push_front<methods12, service::foo22>::type methods13;
|
||||
private: typedef boost::mpl::push_front<methods13, service::foo21>::type methods14;
|
||||
private: typedef boost::mpl::push_front<methods14, service::foo15>::type methods15;
|
||||
private: typedef boost::mpl::push_front<methods15, service::foo14>::type methods16;
|
||||
private: typedef boost::mpl::push_front<methods16, service::foo13>::type methods17;
|
||||
private: typedef boost::mpl::push_front<methods17, service::foo12_impl>::type methods18;
|
||||
private: typedef boost::mpl::push_front<methods18, service::foo12>::type methods19;
|
||||
private: typedef boost::mpl::push_front<methods19, service::foo11>::type methods20;
|
||||
|
||||
public: typedef methods18::type methods;
|
||||
public: typedef methods20::type methods;
|
||||
|
||||
};
|
||||
|
||||
|
@ -425,6 +451,18 @@ namespace tests
|
|||
_impl->foo33(boost::cref(input), callback);
|
||||
}
|
||||
|
||||
void _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
_impl->_rd_foo33(input, callback);
|
||||
}
|
||||
|
||||
void _rd_foo33(const ::tests::BasicTypes& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback)
|
||||
{
|
||||
_impl->_rd_foo33(boost::cref(input), callback);
|
||||
}
|
||||
|
||||
void foo34(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
|
@ -485,6 +523,18 @@ namespace tests
|
|||
_impl->foo44(boost::cref(input), callback);
|
||||
}
|
||||
|
||||
void cq(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
_impl->cq(input, callback);
|
||||
}
|
||||
|
||||
void cq(
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback)
|
||||
{
|
||||
_impl->cq(::bond::comm::payload<void>(), callback);
|
||||
}
|
||||
|
||||
template <template <typename> class Promise>
|
||||
class Using;
|
||||
|
||||
|
@ -575,6 +625,12 @@ namespace tests
|
|||
_proxy.Send(_name, Schema::service::foo33::metadata.name, input, callback);
|
||||
}
|
||||
|
||||
void _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
_proxy.Send(_name, Schema::service::_rd_foo33::metadata.name, input, callback);
|
||||
}
|
||||
|
||||
void foo34(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
|
@ -605,6 +661,12 @@ namespace tests
|
|||
_proxy.Send(_name, Schema::service::foo44::metadata.name, input, callback);
|
||||
}
|
||||
|
||||
void cq(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
_proxy.Send(_name, Schema::service::cq::metadata.name, input, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
ServiceProxy _proxy;
|
||||
const std::string _name;
|
||||
|
@ -637,6 +699,9 @@ namespace tests
|
|||
virtual auto foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future()) = 0;
|
||||
|
||||
virtual auto _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future()) = 0;
|
||||
|
||||
virtual auto foo34(const ::bond::comm::payload< ::tests::dummy>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future()) = 0;
|
||||
|
||||
|
@ -652,6 +717,9 @@ namespace tests
|
|||
virtual auto foo44(const ::bond::comm::payload< ::tests::dummy>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::dummy>>>().get_future()) = 0;
|
||||
|
||||
virtual auto cq(const ::bond::comm::payload<void>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future()) = 0;
|
||||
|
||||
void foo21(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message<void>&)>& callback) override
|
||||
{
|
||||
|
@ -694,6 +762,12 @@ namespace tests
|
|||
when(foo33(input), ::bond::comm::Continuation(callback));
|
||||
}
|
||||
|
||||
void _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
when(_rd_foo33(input), ::bond::comm::Continuation(callback));
|
||||
}
|
||||
|
||||
void foo34(const ::bond::comm::payload< ::tests::dummy>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
|
@ -723,6 +797,12 @@ namespace tests
|
|||
{
|
||||
when(foo44(input), ::bond::comm::Continuation(callback));
|
||||
}
|
||||
|
||||
void cq(const ::bond::comm::payload<void>& input,
|
||||
const std::function<void (const ::bond::comm::message< ::tests::BasicTypes>&)>& callback) override
|
||||
{
|
||||
when(cq(input), ::bond::comm::Continuation(callback));
|
||||
}
|
||||
};
|
||||
|
||||
template <template <typename> class Promise>
|
||||
|
@ -901,6 +981,29 @@ namespace tests
|
|||
}
|
||||
|
||||
|
||||
using Foo::Proxy::_rd_foo33;
|
||||
|
||||
auto _rd_foo33(const ::bond::comm::payload< ::tests::BasicTypes>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future())
|
||||
{
|
||||
auto promise = boost::make_shared<Promise< ::bond::comm::message< ::tests::BasicTypes>>>();
|
||||
|
||||
_impl->_rd_foo33(input,
|
||||
[=](const ::bond::comm::message< ::tests::BasicTypes>& result) mutable
|
||||
{
|
||||
promise->set_value(result);
|
||||
});
|
||||
|
||||
return promise->get_future();
|
||||
}
|
||||
|
||||
auto _rd_foo33(const ::tests::BasicTypes& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future())
|
||||
{
|
||||
return _rd_foo33(::bond::comm::payload< ::tests::BasicTypes>(boost::cref(input)));
|
||||
}
|
||||
|
||||
|
||||
using Foo::Proxy::foo34;
|
||||
|
||||
auto foo34(const ::bond::comm::payload< ::tests::dummy>& input)
|
||||
|
@ -1013,6 +1116,28 @@ namespace tests
|
|||
return foo44(::bond::comm::payload< ::tests::dummy>(boost::cref(input)));
|
||||
}
|
||||
|
||||
|
||||
using Foo::Proxy::cq;
|
||||
|
||||
auto cq(const ::bond::comm::payload<void>& input)
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future())
|
||||
{
|
||||
auto promise = boost::make_shared<Promise< ::bond::comm::message< ::tests::BasicTypes>>>();
|
||||
|
||||
_impl->cq(input,
|
||||
[=](const ::bond::comm::message< ::tests::BasicTypes>& result) mutable
|
||||
{
|
||||
promise->set_value(result);
|
||||
});
|
||||
|
||||
return promise->get_future();
|
||||
}
|
||||
|
||||
auto cq()
|
||||
-> decltype(std::declval< Promise< ::bond::comm::message< ::tests::BasicTypes>>>().get_future())
|
||||
{
|
||||
return cq(::bond::comm::payload<void>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -112,6 +112,13 @@ namespace tests
|
|||
global::Bond.Grpc.Marshaller<BasicTypes>.Instance,
|
||||
global::Bond.Grpc.Marshaller<BasicTypes>.Instance);
|
||||
|
||||
static readonly global::Grpc.Core.Method<global::Bond.Grpc.IMessage<BasicTypes>, global::Bond.Grpc.IMessage<BasicTypes>> Method__rd_foo33 = new global::Grpc.Core.Method<global::Bond.Grpc.IMessage<BasicTypes>, global::Bond.Grpc.IMessage<BasicTypes>>(
|
||||
global::Grpc.Core.MethodType.Unary,
|
||||
ServiceName,
|
||||
"_rd_foo33",
|
||||
global::Bond.Grpc.Marshaller<BasicTypes>.Instance,
|
||||
global::Bond.Grpc.Marshaller<BasicTypes>.Instance);
|
||||
|
||||
static readonly global::Grpc.Core.Method<global::Bond.Grpc.IMessage<dummy>, global::Bond.Grpc.IMessage<BasicTypes>> Method_foo34 = new global::Grpc.Core.Method<global::Bond.Grpc.IMessage<dummy>, global::Bond.Grpc.IMessage<BasicTypes>>(
|
||||
global::Grpc.Core.MethodType.Unary,
|
||||
ServiceName,
|
||||
|
@ -147,6 +154,13 @@ namespace tests
|
|||
global::Bond.Grpc.Marshaller<dummy>.Instance,
|
||||
global::Bond.Grpc.Marshaller<dummy>.Instance);
|
||||
|
||||
static readonly global::Grpc.Core.Method<global::Bond.Grpc.IMessage<global::Bond.Void>, global::Bond.Grpc.IMessage<BasicTypes>> Method_cq = new global::Grpc.Core.Method<global::Bond.Grpc.IMessage<global::Bond.Void>, global::Bond.Grpc.IMessage<BasicTypes>>(
|
||||
global::Grpc.Core.MethodType.Unary,
|
||||
ServiceName,
|
||||
"cq",
|
||||
global::Bond.Grpc.Marshaller<global::Bond.Void>.Instance,
|
||||
global::Bond.Grpc.Marshaller<BasicTypes>.Instance);
|
||||
|
||||
public abstract class FooBase
|
||||
{
|
||||
public abstract global::System.Threading.Tasks.Task foo11(global::Bond.Grpc.IMessage<global::Bond.Void> request, global::Grpc.Core.ServerCallContext context);
|
||||
|
@ -199,6 +213,8 @@ namespace tests
|
|||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<BasicTypes>> foo33(global::Bond.Grpc.IMessage<BasicTypes> request, global::Grpc.Core.ServerCallContext context);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<BasicTypes>> _rd_foo33(global::Bond.Grpc.IMessage<BasicTypes> request, global::Grpc.Core.ServerCallContext context);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<BasicTypes>> foo34(global::Bond.Grpc.IMessage<dummy> request, global::Grpc.Core.ServerCallContext context);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<dummy>> foo41(global::Bond.Grpc.IMessage<global::Bond.Void> request, global::Grpc.Core.ServerCallContext context);
|
||||
|
@ -208,6 +224,8 @@ namespace tests
|
|||
public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<dummy>> foo43(global::Bond.Grpc.IMessage<BasicTypes> request, global::Grpc.Core.ServerCallContext context);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<dummy>> foo44(global::Bond.Grpc.IMessage<dummy> request, global::Grpc.Core.ServerCallContext context);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Grpc.IMessage<BasicTypes>> cq(global::Bond.Grpc.IMessage<global::Bond.Void> request, global::Grpc.Core.ServerCallContext context);
|
||||
}
|
||||
|
||||
public class FooClient : global::Grpc.Core.ClientBase<FooClient>
|
||||
|
@ -367,6 +385,17 @@ namespace tests
|
|||
return CallInvoker.AsyncUnaryCall(Method_foo33, null, options, request);
|
||||
}
|
||||
|
||||
public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<BasicTypes>> _rd_foo33Async(BasicTypes request, global::Grpc.Core.Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
|
||||
{
|
||||
var message = global::Bond.Grpc.Message.From(request);
|
||||
return _rd_foo33Async(message, new global::Grpc.Core.CallOptions(headers, deadline, cancellationToken));
|
||||
}
|
||||
|
||||
public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<BasicTypes>> _rd_foo33Async(global::Bond.Grpc.IMessage<BasicTypes> request, global::Grpc.Core.CallOptions options)
|
||||
{
|
||||
return CallInvoker.AsyncUnaryCall(Method__rd_foo33, null, options, request);
|
||||
}
|
||||
|
||||
public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<BasicTypes>> foo34Async(dummy request, global::Grpc.Core.Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
|
||||
{
|
||||
var message = global::Bond.Grpc.Message.From(request);
|
||||
|
@ -422,6 +451,17 @@ namespace tests
|
|||
return CallInvoker.AsyncUnaryCall(Method_foo44, null, options, request);
|
||||
}
|
||||
|
||||
public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<BasicTypes>> cqAsync(global::Grpc.Core.Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
|
||||
{
|
||||
var message = global::Bond.Grpc.Message.Void;
|
||||
return cqAsync(message, new global::Grpc.Core.CallOptions(headers, deadline, cancellationToken));
|
||||
}
|
||||
|
||||
public virtual global::Grpc.Core.AsyncUnaryCall<global::Bond.Grpc.IMessage<BasicTypes>> cqAsync(global::Bond.Grpc.IMessage<global::Bond.Void> request, global::Grpc.Core.CallOptions options)
|
||||
{
|
||||
return CallInvoker.AsyncUnaryCall(Method_cq, null, options, request);
|
||||
}
|
||||
|
||||
protected override FooClient NewInstance(global::Grpc.Core.ClientBase.ClientBaseConfiguration configuration)
|
||||
{
|
||||
return new FooClient(configuration);
|
||||
|
@ -444,11 +484,13 @@ namespace tests
|
|||
.AddMethod(Method_foo31, serviceImpl.foo31)
|
||||
.AddMethod(Method_foo32, serviceImpl.foo32)
|
||||
.AddMethod(Method_foo33, serviceImpl.foo33)
|
||||
.AddMethod(Method__rd_foo33, serviceImpl._rd_foo33)
|
||||
.AddMethod(Method_foo34, serviceImpl.foo34)
|
||||
.AddMethod(Method_foo41, serviceImpl.foo41)
|
||||
.AddMethod(Method_foo42, serviceImpl.foo42)
|
||||
.AddMethod(Method_foo43, serviceImpl.foo43)
|
||||
.AddMethod(Method_foo44, serviceImpl.foo44)
|
||||
.AddMethod(Method_cq, serviceImpl.cq)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,851 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "service_reflection.h"
|
||||
#include "service_types.h"
|
||||
#include "basic_types_grpc.h"
|
||||
#include "namespace_basic_types_grpc.h"
|
||||
#include <bond/core/bonded.h>
|
||||
#include <bond/ext/grpc/bond_utils.h>
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
#include <bond/ext/grpc/detail/client_call_data.h>
|
||||
#include <bond/ext/grpc/detail/service.h>
|
||||
#include <bond/ext/grpc/detail/service_call_data.h>
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4267)
|
||||
#endif
|
||||
|
||||
#include <grpc++/impl/codegen/channel_interface.h>
|
||||
#include <grpc++/impl/codegen/client_context.h>
|
||||
#include <grpc++/impl/codegen/completion_queue.h>
|
||||
#include <grpc++/impl/codegen/rpc_method.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
namespace tests
|
||||
{
|
||||
|
||||
class Foo final
|
||||
{
|
||||
public:
|
||||
template <typename TThreadPool>
|
||||
class ClientCore
|
||||
{
|
||||
public:
|
||||
ClientCore(
|
||||
const std::shared_ptr< ::grpc::ChannelInterface>& channel,
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool);
|
||||
|
||||
void Asyncfoo11(::grpc::ClientContext* context);
|
||||
|
||||
void Asyncfoo12(::grpc::ClientContext* context);
|
||||
|
||||
void Asyncfoo12_impl(::grpc::ClientContext* context);
|
||||
|
||||
void Asyncfoo13(::grpc::ClientContext* context, const ::bond::bonded< ::tests::BasicTypes>& request);
|
||||
void Asyncfoo13(::grpc::ClientContext* context, const ::tests::BasicTypes& request)
|
||||
{
|
||||
Asyncfoo13(context, ::bond::bonded< ::tests::BasicTypes>{request});
|
||||
}
|
||||
|
||||
void Asyncfoo14(::grpc::ClientContext* context, const ::bond::bonded< ::tests::dummy>& request);
|
||||
void Asyncfoo14(::grpc::ClientContext* context, const ::tests::dummy& request)
|
||||
{
|
||||
Asyncfoo14(context, ::bond::bonded< ::tests::dummy>{request});
|
||||
}
|
||||
|
||||
void Asyncfoo15(::grpc::ClientContext* context, const ::bond::bonded< ::tests2::OtherBasicTypes>& request);
|
||||
void Asyncfoo15(::grpc::ClientContext* context, const ::tests2::OtherBasicTypes& request)
|
||||
{
|
||||
Asyncfoo15(context, ::bond::bonded< ::tests2::OtherBasicTypes>{request});
|
||||
}
|
||||
|
||||
void Asyncfoo21(::grpc::ClientContext* context, const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb);
|
||||
|
||||
void Asyncfoo22(::grpc::ClientContext* context, const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb);
|
||||
|
||||
void Asyncfoo23(::grpc::ClientContext* context, const ::bond::bonded< ::tests::BasicTypes>& request, const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo23(::grpc::ClientContext* context, const ::tests::BasicTypes& request, const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo23(context, ::bond::bonded< ::tests::BasicTypes>{request}, cb);
|
||||
}
|
||||
|
||||
void Asyncfoo24(::grpc::ClientContext* context, const ::bond::bonded< ::tests::dummy>& request, const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo24(::grpc::ClientContext* context, const ::tests::dummy& request, const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo24(context, ::bond::bonded< ::tests::dummy>{request}, cb);
|
||||
}
|
||||
|
||||
void Asyncfoo31(::grpc::ClientContext* context, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb);
|
||||
|
||||
void Asyncfoo32(::grpc::ClientContext* context, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb);
|
||||
|
||||
void Asyncfoo33(::grpc::ClientContext* context, const ::bond::bonded< ::tests::BasicTypes>& request, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo33(::grpc::ClientContext* context, const ::tests::BasicTypes& request, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo33(context, ::bond::bonded< ::tests::BasicTypes>{request}, cb);
|
||||
}
|
||||
|
||||
void Async_rd_foo33(::grpc::ClientContext* context, const ::bond::bonded< ::tests::BasicTypes>& request, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb);
|
||||
void Async_rd_foo33(::grpc::ClientContext* context, const ::tests::BasicTypes& request, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Async_rd_foo33(context, ::bond::bonded< ::tests::BasicTypes>{request}, cb);
|
||||
}
|
||||
|
||||
void Asyncfoo34(::grpc::ClientContext* context, const ::bond::bonded< ::tests::dummy>& request, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo34(::grpc::ClientContext* context, const ::tests::dummy& request, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo34(context, ::bond::bonded< ::tests::dummy>{request}, cb);
|
||||
}
|
||||
|
||||
void Asyncfoo41(::grpc::ClientContext* context, const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb);
|
||||
|
||||
void Asyncfoo42(::grpc::ClientContext* context, const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb);
|
||||
|
||||
void Asyncfoo43(::grpc::ClientContext* context, const ::bond::bonded< ::tests::BasicTypes>& request, const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo43(::grpc::ClientContext* context, const ::tests::BasicTypes& request, const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo43(context, ::bond::bonded< ::tests::BasicTypes>{request}, cb);
|
||||
}
|
||||
|
||||
void Asyncfoo44(::grpc::ClientContext* context, const ::bond::bonded< ::tests::dummy>& request, const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb);
|
||||
void Asyncfoo44(::grpc::ClientContext* context, const ::tests::dummy& request, const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
Asyncfoo44(context, ::bond::bonded< ::tests::dummy>{request}, cb);
|
||||
}
|
||||
|
||||
void Asynccq(::grpc::ClientContext* context, const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb);
|
||||
|
||||
ClientCore(const ClientCore&) = delete;
|
||||
ClientCore& operator=(const ClientCore&) = delete;
|
||||
|
||||
ClientCore(ClientCore&&) = default;
|
||||
ClientCore& operator=(ClientCore&&) = default;
|
||||
|
||||
private:
|
||||
std::shared_ptr< ::grpc::ChannelInterface> _channel;
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> _ioManager;
|
||||
std::shared_ptr<TThreadPool> _threadPool;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo11_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo12_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo12_impl_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo13_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo14_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo15_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo21_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo22_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo23_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo24_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo31_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo32_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo33_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod__rd_foo33_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo34_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo41_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo42_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo43_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_foo44_;
|
||||
|
||||
const ::grpc::RpcMethod rpcmethod_cq_;
|
||||
};
|
||||
|
||||
using Client = ClientCore< ::bond::ext::gRPC::thread_pool>;
|
||||
|
||||
template <typename TThreadPool>
|
||||
class ServiceCore : public ::bond::ext::gRPC::detail::service<TThreadPool>
|
||||
{
|
||||
public:
|
||||
ServiceCore()
|
||||
{
|
||||
this->AddMethod("/tests.Foo/foo11");
|
||||
this->AddMethod("/tests.Foo/foo12");
|
||||
this->AddMethod("/tests.Foo/foo12_impl");
|
||||
this->AddMethod("/tests.Foo/foo13");
|
||||
this->AddMethod("/tests.Foo/foo14");
|
||||
this->AddMethod("/tests.Foo/foo15");
|
||||
this->AddMethod("/tests.Foo/foo21");
|
||||
this->AddMethod("/tests.Foo/foo22");
|
||||
this->AddMethod("/tests.Foo/foo23");
|
||||
this->AddMethod("/tests.Foo/foo24");
|
||||
this->AddMethod("/tests.Foo/foo31");
|
||||
this->AddMethod("/tests.Foo/foo32");
|
||||
this->AddMethod("/tests.Foo/foo33");
|
||||
this->AddMethod("/tests.Foo/_rd_foo33");
|
||||
this->AddMethod("/tests.Foo/foo34");
|
||||
this->AddMethod("/tests.Foo/foo41");
|
||||
this->AddMethod("/tests.Foo/foo42");
|
||||
this->AddMethod("/tests.Foo/foo43");
|
||||
this->AddMethod("/tests.Foo/foo44");
|
||||
this->AddMethod("/tests.Foo/cq");
|
||||
}
|
||||
|
||||
virtual ~ServiceCore() { }
|
||||
virtual void start(
|
||||
::grpc::ServerCompletionQueue* cq0,
|
||||
std::shared_ptr<TThreadPool> tp) override
|
||||
{
|
||||
BOOST_ASSERT(cq0);
|
||||
BOOST_ASSERT(tp);
|
||||
|
||||
_rd_foo11.emplace(
|
||||
this,
|
||||
0,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo11, this, std::placeholders::_1));
|
||||
_rd_foo12.emplace(
|
||||
this,
|
||||
1,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo12, this, std::placeholders::_1));
|
||||
_rd_foo12_impl.emplace(
|
||||
this,
|
||||
2,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo12_impl, this, std::placeholders::_1));
|
||||
_rd_foo13.emplace(
|
||||
this,
|
||||
3,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo13, this, std::placeholders::_1));
|
||||
_rd_foo14.emplace(
|
||||
this,
|
||||
4,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo14, this, std::placeholders::_1));
|
||||
_rd_foo15.emplace(
|
||||
this,
|
||||
5,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo15, this, std::placeholders::_1));
|
||||
_rd_foo21.emplace(
|
||||
this,
|
||||
6,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo21, this, std::placeholders::_1));
|
||||
_rd_foo22.emplace(
|
||||
this,
|
||||
7,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo22, this, std::placeholders::_1));
|
||||
_rd_foo23.emplace(
|
||||
this,
|
||||
8,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo23, this, std::placeholders::_1));
|
||||
_rd_foo24.emplace(
|
||||
this,
|
||||
9,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo24, this, std::placeholders::_1));
|
||||
_rd_foo31.emplace(
|
||||
this,
|
||||
10,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo31, this, std::placeholders::_1));
|
||||
_rd_foo32.emplace(
|
||||
this,
|
||||
11,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo32, this, std::placeholders::_1));
|
||||
_rd_foo330.emplace(
|
||||
this,
|
||||
12,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo33, this, std::placeholders::_1));
|
||||
_rd__rd_foo33.emplace(
|
||||
this,
|
||||
13,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::_rd_foo33, this, std::placeholders::_1));
|
||||
_rd_foo34.emplace(
|
||||
this,
|
||||
14,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo34, this, std::placeholders::_1));
|
||||
_rd_foo41.emplace(
|
||||
this,
|
||||
15,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo41, this, std::placeholders::_1));
|
||||
_rd_foo42.emplace(
|
||||
this,
|
||||
16,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo42, this, std::placeholders::_1));
|
||||
_rd_foo43.emplace(
|
||||
this,
|
||||
17,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo43, this, std::placeholders::_1));
|
||||
_rd_foo44.emplace(
|
||||
this,
|
||||
18,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::foo44, this, std::placeholders::_1));
|
||||
_rd_cq.emplace(
|
||||
this,
|
||||
19,
|
||||
cq0,
|
||||
tp,
|
||||
std::bind(&ServiceCore::cq, this, std::placeholders::_1));
|
||||
|
||||
this->queue_receive(
|
||||
0,
|
||||
&_rd_foo11->_receivedCall->_context,
|
||||
&_rd_foo11->_receivedCall->_request,
|
||||
&_rd_foo11->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo11.get());
|
||||
this->queue_receive(
|
||||
1,
|
||||
&_rd_foo12->_receivedCall->_context,
|
||||
&_rd_foo12->_receivedCall->_request,
|
||||
&_rd_foo12->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo12.get());
|
||||
this->queue_receive(
|
||||
2,
|
||||
&_rd_foo12_impl->_receivedCall->_context,
|
||||
&_rd_foo12_impl->_receivedCall->_request,
|
||||
&_rd_foo12_impl->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo12_impl.get());
|
||||
this->queue_receive(
|
||||
3,
|
||||
&_rd_foo13->_receivedCall->_context,
|
||||
&_rd_foo13->_receivedCall->_request,
|
||||
&_rd_foo13->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo13.get());
|
||||
this->queue_receive(
|
||||
4,
|
||||
&_rd_foo14->_receivedCall->_context,
|
||||
&_rd_foo14->_receivedCall->_request,
|
||||
&_rd_foo14->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo14.get());
|
||||
this->queue_receive(
|
||||
5,
|
||||
&_rd_foo15->_receivedCall->_context,
|
||||
&_rd_foo15->_receivedCall->_request,
|
||||
&_rd_foo15->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo15.get());
|
||||
this->queue_receive(
|
||||
6,
|
||||
&_rd_foo21->_receivedCall->_context,
|
||||
&_rd_foo21->_receivedCall->_request,
|
||||
&_rd_foo21->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo21.get());
|
||||
this->queue_receive(
|
||||
7,
|
||||
&_rd_foo22->_receivedCall->_context,
|
||||
&_rd_foo22->_receivedCall->_request,
|
||||
&_rd_foo22->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo22.get());
|
||||
this->queue_receive(
|
||||
8,
|
||||
&_rd_foo23->_receivedCall->_context,
|
||||
&_rd_foo23->_receivedCall->_request,
|
||||
&_rd_foo23->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo23.get());
|
||||
this->queue_receive(
|
||||
9,
|
||||
&_rd_foo24->_receivedCall->_context,
|
||||
&_rd_foo24->_receivedCall->_request,
|
||||
&_rd_foo24->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo24.get());
|
||||
this->queue_receive(
|
||||
10,
|
||||
&_rd_foo31->_receivedCall->_context,
|
||||
&_rd_foo31->_receivedCall->_request,
|
||||
&_rd_foo31->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo31.get());
|
||||
this->queue_receive(
|
||||
11,
|
||||
&_rd_foo32->_receivedCall->_context,
|
||||
&_rd_foo32->_receivedCall->_request,
|
||||
&_rd_foo32->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo32.get());
|
||||
this->queue_receive(
|
||||
12,
|
||||
&_rd_foo330->_receivedCall->_context,
|
||||
&_rd_foo330->_receivedCall->_request,
|
||||
&_rd_foo330->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo330.get());
|
||||
this->queue_receive(
|
||||
13,
|
||||
&_rd__rd_foo33->_receivedCall->_context,
|
||||
&_rd__rd_foo33->_receivedCall->_request,
|
||||
&_rd__rd_foo33->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd__rd_foo33.get());
|
||||
this->queue_receive(
|
||||
14,
|
||||
&_rd_foo34->_receivedCall->_context,
|
||||
&_rd_foo34->_receivedCall->_request,
|
||||
&_rd_foo34->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo34.get());
|
||||
this->queue_receive(
|
||||
15,
|
||||
&_rd_foo41->_receivedCall->_context,
|
||||
&_rd_foo41->_receivedCall->_request,
|
||||
&_rd_foo41->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo41.get());
|
||||
this->queue_receive(
|
||||
16,
|
||||
&_rd_foo42->_receivedCall->_context,
|
||||
&_rd_foo42->_receivedCall->_request,
|
||||
&_rd_foo42->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo42.get());
|
||||
this->queue_receive(
|
||||
17,
|
||||
&_rd_foo43->_receivedCall->_context,
|
||||
&_rd_foo43->_receivedCall->_request,
|
||||
&_rd_foo43->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo43.get());
|
||||
this->queue_receive(
|
||||
18,
|
||||
&_rd_foo44->_receivedCall->_context,
|
||||
&_rd_foo44->_receivedCall->_request,
|
||||
&_rd_foo44->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_foo44.get());
|
||||
this->queue_receive(
|
||||
19,
|
||||
&_rd_cq->_receivedCall->_context,
|
||||
&_rd_cq->_receivedCall->_request,
|
||||
&_rd_cq->_receivedCall->_responder,
|
||||
cq0,
|
||||
&_rd_cq.get());
|
||||
}
|
||||
|
||||
virtual void foo11(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::bond::Void>) = 0;
|
||||
virtual void foo12(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::bond::Void>) = 0;
|
||||
virtual void foo12_impl(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::bond::Void>) = 0;
|
||||
virtual void foo13(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::BasicTypes>, ::bond::Void>) = 0;
|
||||
virtual void foo14(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::dummy>, ::bond::Void>) = 0;
|
||||
virtual void foo15(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests2::OtherBasicTypes>, ::bond::Void>) = 0;
|
||||
virtual void foo21(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::bond::Void>) = 0;
|
||||
virtual void foo22(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::bond::Void>) = 0;
|
||||
virtual void foo23(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::BasicTypes>, ::bond::Void>) = 0;
|
||||
virtual void foo24(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::dummy>, ::bond::Void>) = 0;
|
||||
virtual void foo31(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::tests::BasicTypes>) = 0;
|
||||
virtual void foo32(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::tests::BasicTypes>) = 0;
|
||||
virtual void foo33(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::BasicTypes>, ::tests::BasicTypes>) = 0;
|
||||
virtual void _rd_foo33(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::BasicTypes>, ::tests::BasicTypes>) = 0;
|
||||
virtual void foo34(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::dummy>, ::tests::BasicTypes>) = 0;
|
||||
virtual void foo41(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::tests::dummy>) = 0;
|
||||
virtual void foo42(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::tests::dummy>) = 0;
|
||||
virtual void foo43(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::BasicTypes>, ::tests::dummy>) = 0;
|
||||
virtual void foo44(::bond::ext::gRPC::unary_call< ::bond::bonded< ::tests::dummy>, ::tests::dummy>) = 0;
|
||||
virtual void cq(::bond::ext::gRPC::unary_call< ::bond::bonded< ::bond::Void>, ::tests::BasicTypes>) = 0;
|
||||
|
||||
private:
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::Void, TThreadPool>> _rd_foo11;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::Void, TThreadPool>> _rd_foo12;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::Void, TThreadPool>> _rd_foo12_impl;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::bond::Void, TThreadPool>> _rd_foo13;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::dummy>, ::bond::Void, TThreadPool>> _rd_foo14;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests2::OtherBasicTypes>, ::bond::Void, TThreadPool>> _rd_foo15;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::Void, TThreadPool>> _rd_foo21;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::Void, TThreadPool>> _rd_foo22;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::bond::Void, TThreadPool>> _rd_foo23;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::dummy>, ::bond::Void, TThreadPool>> _rd_foo24;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::tests::BasicTypes, TThreadPool>> _rd_foo31;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::tests::BasicTypes, TThreadPool>> _rd_foo32;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::tests::BasicTypes, TThreadPool>> _rd_foo330;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::tests::BasicTypes, TThreadPool>> _rd__rd_foo33;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::dummy>, ::tests::BasicTypes, TThreadPool>> _rd_foo34;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::tests::dummy, TThreadPool>> _rd_foo41;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::tests::dummy, TThreadPool>> _rd_foo42;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::tests::dummy, TThreadPool>> _rd_foo43;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::tests::dummy>, ::tests::dummy, TThreadPool>> _rd_foo44;
|
||||
::boost::optional< ::bond::ext::gRPC::detail::service_unary_call_data< ::bond::bonded< ::bond::Void>, ::tests::BasicTypes, TThreadPool>> _rd_cq;
|
||||
};
|
||||
|
||||
using Service = ServiceCore< ::bond::ext::gRPC::thread_pool>;
|
||||
};
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline Foo::ClientCore<TThreadPool>::ClientCore(
|
||||
const std::shared_ptr< ::grpc::ChannelInterface>& channel,
|
||||
std::shared_ptr< ::bond::ext::gRPC::io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool)
|
||||
: _channel(channel)
|
||||
, _ioManager(ioManager)
|
||||
, _threadPool(threadPool)
|
||||
, rpcmethod_foo11_("/tests.Foo/foo11", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo12_("/tests.Foo/foo12", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo12_impl_("/tests.Foo/foo12_impl", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo13_("/tests.Foo/foo13", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo14_("/tests.Foo/foo14", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo15_("/tests.Foo/foo15", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo21_("/tests.Foo/foo21", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo22_("/tests.Foo/foo22", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo23_("/tests.Foo/foo23", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo24_("/tests.Foo/foo24", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo31_("/tests.Foo/foo31", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo32_("/tests.Foo/foo32", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo33_("/tests.Foo/foo33", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod__rd_foo33_("/tests.Foo/_rd_foo33", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo34_("/tests.Foo/foo34", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo41_("/tests.Foo/foo41", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo42_("/tests.Foo/foo42", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo43_("/tests.Foo/foo43", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_foo44_("/tests.Foo/foo44", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
, rpcmethod_cq_("/tests.Foo/cq", ::grpc::RpcMethod::NORMAL_RPC, channel)
|
||||
{ }
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo11(
|
||||
::grpc::ClientContext* context
|
||||
)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool);
|
||||
calldata->dispatch(rpcmethod_foo11_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo12(
|
||||
::grpc::ClientContext* context
|
||||
)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool);
|
||||
calldata->dispatch(rpcmethod_foo12_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo12_impl(
|
||||
::grpc::ClientContext* context
|
||||
)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool);
|
||||
calldata->dispatch(rpcmethod_foo12_impl_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo13(
|
||||
::grpc::ClientContext* context
|
||||
, const ::bond::bonded< ::tests::BasicTypes>& request)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool);
|
||||
calldata->dispatch(rpcmethod_foo13_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo14(
|
||||
::grpc::ClientContext* context
|
||||
, const ::bond::bonded< ::tests::dummy>& request)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::dummy>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool);
|
||||
calldata->dispatch(rpcmethod_foo14_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo15(
|
||||
::grpc::ClientContext* context
|
||||
, const ::bond::bonded< ::tests2::OtherBasicTypes>& request)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests2::OtherBasicTypes>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool);
|
||||
calldata->dispatch(rpcmethod_foo15_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo21(
|
||||
::grpc::ClientContext* context,
|
||||
|
||||
const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo21_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo22(
|
||||
::grpc::ClientContext* context,
|
||||
|
||||
const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo22_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo23(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded< ::tests::BasicTypes>& request,
|
||||
const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo23_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo24(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded< ::tests::dummy>& request,
|
||||
const std::function<void(const ::bond::bonded< ::bond::Void>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::dummy>, ::bond::bonded< ::bond::Void>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo24_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo31(
|
||||
::grpc::ClientContext* context,
|
||||
|
||||
const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::tests::BasicTypes>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo31_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo32(
|
||||
::grpc::ClientContext* context,
|
||||
|
||||
const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::tests::BasicTypes>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo32_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo33(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded< ::tests::BasicTypes>& request,
|
||||
const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::bond::bonded< ::tests::BasicTypes>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo33_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Async_rd_foo33(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded< ::tests::BasicTypes>& request,
|
||||
const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::bond::bonded< ::tests::BasicTypes>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod__rd_foo33_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo34(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded< ::tests::dummy>& request,
|
||||
const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::dummy>, ::bond::bonded< ::tests::BasicTypes>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo34_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo41(
|
||||
::grpc::ClientContext* context,
|
||||
|
||||
const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::tests::dummy>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo41_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo42(
|
||||
::grpc::ClientContext* context,
|
||||
|
||||
const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::tests::dummy>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo42_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo43(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded< ::tests::BasicTypes>& request,
|
||||
const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::BasicTypes>, ::bond::bonded< ::tests::dummy>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo43_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asyncfoo44(
|
||||
::grpc::ClientContext* context,
|
||||
const ::bond::bonded< ::tests::dummy>& request,
|
||||
const std::function<void(const ::bond::bonded< ::tests::dummy>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::tests::dummy>, ::bond::bonded< ::tests::dummy>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_foo44_, context, request);
|
||||
}
|
||||
|
||||
template <typename TThreadPool>
|
||||
inline void Foo::ClientCore<TThreadPool>::Asynccq(
|
||||
::grpc::ClientContext* context,
|
||||
|
||||
const std::function<void(const ::bond::bonded< ::tests::BasicTypes>&, const ::grpc::Status&)>& cb)
|
||||
{
|
||||
auto request = ::bond::bonded< ::bond::Void>{ ::bond::Void()};
|
||||
auto calldata = new ::bond::ext::gRPC::detail::client_unary_call_data< ::bond::bonded< ::bond::Void>, ::bond::bonded< ::tests::BasicTypes>, TThreadPool >(
|
||||
_channel,
|
||||
_ioManager,
|
||||
_threadPool,
|
||||
cb);
|
||||
calldata->dispatch(rpcmethod_cq_, context, request);
|
||||
}
|
||||
|
||||
|
||||
} // namespace tests
|
||||
|
|
@ -44,6 +44,8 @@ namespace tests
|
|||
|
||||
global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> foo33Async(global::Bond.Comm.IMessage<BasicTypes> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> _rd_foo33Async(global::Bond.Comm.IMessage<BasicTypes> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> foo34Async(global::Bond.Comm.IMessage<dummy> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<dummy>> foo41Async(global::Bond.Comm.IMessage<global::Bond.Void> param, global::System.Threading.CancellationToken ct);
|
||||
|
@ -53,6 +55,8 @@ namespace tests
|
|||
global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<dummy>> foo43Async(global::Bond.Comm.IMessage<BasicTypes> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<dummy>> foo44Async(global::Bond.Comm.IMessage<dummy> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> cqAsync(global::Bond.Comm.IMessage<global::Bond.Void> param, global::System.Threading.CancellationToken ct);
|
||||
}
|
||||
|
||||
} // tests
|
||||
|
|
|
@ -214,6 +214,21 @@ namespace tests
|
|||
ct);
|
||||
}
|
||||
|
||||
public global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> _rd_foo33Async(BasicTypes param)
|
||||
{
|
||||
var message = new global::Bond.Comm.Message<BasicTypes>(param);
|
||||
return _rd_foo33Async(message, global::System.Threading.CancellationToken.None);
|
||||
}
|
||||
|
||||
public global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> _rd_foo33Async(global::Bond.Comm.IMessage<BasicTypes> param, global::System.Threading.CancellationToken ct)
|
||||
{
|
||||
return m_connection.RequestResponseAsync<BasicTypes, BasicTypes>(
|
||||
"tests.Foo",
|
||||
"_rd_foo33",
|
||||
param,
|
||||
ct);
|
||||
}
|
||||
|
||||
public global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> foo34Async(dummy param)
|
||||
{
|
||||
var message = new global::Bond.Comm.Message<dummy>(param);
|
||||
|
@ -288,5 +303,20 @@ namespace tests
|
|||
param,
|
||||
ct);
|
||||
}
|
||||
|
||||
public global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> cqAsync()
|
||||
{
|
||||
var message = new global::Bond.Comm.Message<global::Bond.Void>(new global::Bond.Void());
|
||||
return cqAsync(message, global::System.Threading.CancellationToken.None);
|
||||
}
|
||||
|
||||
public global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> cqAsync(global::Bond.Comm.IMessage<global::Bond.Void> param, global::System.Threading.CancellationToken ct)
|
||||
{
|
||||
return m_connection.RequestResponseAsync<global::Bond.Void, BasicTypes>(
|
||||
"tests.Foo",
|
||||
"cq",
|
||||
param,
|
||||
ct);
|
||||
}
|
||||
}
|
||||
} // tests
|
||||
|
|
|
@ -35,11 +35,13 @@ namespace tests
|
|||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.foo31", Callback = foo31Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.foo32", Callback = foo32Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.foo33", Callback = foo33Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo._rd_foo33", Callback = _rd_foo33Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.foo34", Callback = foo34Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.foo41", Callback = foo41Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.foo42", Callback = foo42Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.foo43", Callback = foo43Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.foo44", Callback = foo44Async_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
yield return new global::Bond.Comm.ServiceMethodInfo {MethodName="tests.Foo.cq", Callback = cqAsync_Glue, CallbackType = global::Bond.Comm.ServiceCallbackType.RequestResponse};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,6 +71,8 @@ namespace tests
|
|||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> foo33Async(global::Bond.Comm.IMessage<BasicTypes> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> _rd_foo33Async(global::Bond.Comm.IMessage<BasicTypes> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> foo34Async(global::Bond.Comm.IMessage<dummy> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<dummy>> foo41Async(global::Bond.Comm.IMessage<global::Bond.Void> param, global::System.Threading.CancellationToken ct);
|
||||
|
@ -79,6 +83,8 @@ namespace tests
|
|||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<dummy>> foo44Async(global::Bond.Comm.IMessage<dummy> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
public abstract global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage<BasicTypes>> cqAsync(global::Bond.Comm.IMessage<global::Bond.Void> param, global::System.Threading.CancellationToken ct);
|
||||
|
||||
private global::System.Threading.Tasks.Task foo11Async_Glue(global::Bond.Comm.IMessage param, global::Bond.Comm.ReceiveContext context, global::System.Threading.CancellationToken ct)
|
||||
{
|
||||
foo11Async(param.Convert<global::Bond.Void>());
|
||||
|
@ -164,6 +170,13 @@ namespace tests
|
|||
foo33Async(param.Convert<BasicTypes>(), ct));
|
||||
}
|
||||
|
||||
private global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage> _rd_foo33Async_Glue(global::Bond.Comm.IMessage param, global::Bond.Comm.ReceiveContext context, global::System.Threading.CancellationToken ct)
|
||||
{
|
||||
return global::Bond.Comm.CodegenHelpers.Upcast<global::Bond.Comm.IMessage<BasicTypes>,
|
||||
global::Bond.Comm.IMessage>(
|
||||
_rd_foo33Async(param.Convert<BasicTypes>(), ct));
|
||||
}
|
||||
|
||||
private global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage> foo34Async_Glue(global::Bond.Comm.IMessage param, global::Bond.Comm.ReceiveContext context, global::System.Threading.CancellationToken ct)
|
||||
{
|
||||
return global::Bond.Comm.CodegenHelpers.Upcast<global::Bond.Comm.IMessage<BasicTypes>,
|
||||
|
@ -198,6 +211,13 @@ namespace tests
|
|||
global::Bond.Comm.IMessage>(
|
||||
foo44Async(param.Convert<dummy>(), ct));
|
||||
}
|
||||
|
||||
private global::System.Threading.Tasks.Task<global::Bond.Comm.IMessage> cqAsync_Glue(global::Bond.Comm.IMessage param, global::Bond.Comm.ReceiveContext context, global::System.Threading.CancellationToken ct)
|
||||
{
|
||||
return global::Bond.Comm.CodegenHelpers.Upcast<global::Bond.Comm.IMessage<BasicTypes>,
|
||||
global::Bond.Comm.IMessage>(
|
||||
cqAsync(param.Convert<global::Bond.Void>(), ct));
|
||||
}
|
||||
}
|
||||
|
||||
} // tests
|
||||
|
|
|
@ -15,6 +15,7 @@ service Foo
|
|||
{
|
||||
nothing foo11();
|
||||
nothing foo12(void);
|
||||
// test name conflict with _impl methods used by Bond Comm
|
||||
nothing foo12_impl(void);
|
||||
nothing foo13(BasicTypes);
|
||||
nothing foo14(bar);
|
||||
|
@ -28,11 +29,15 @@ service Foo
|
|||
BasicTypes foo31();
|
||||
BasicTypes foo32(void);
|
||||
BasicTypes foo33(BasicTypes);
|
||||
// test name conflict with gRC++ receive data member
|
||||
BasicTypes _rd_foo33(BasicTypes);
|
||||
BasicTypes foo34(bar);
|
||||
|
||||
bar foo41();
|
||||
bar foo42(void);
|
||||
bar foo43(BasicTypes);
|
||||
bar foo44(bar);
|
||||
}
|
||||
|
||||
// test name conflict with gRPC++ cq parameter
|
||||
BasicTypes cq();
|
||||
}
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -7,6 +7,7 @@ list (APPEND schemas ${core-schemas})
|
|||
|
||||
add_bond_codegen (${core_schemas}
|
||||
ENUM_HEADER
|
||||
COMM
|
||||
OUTPUT_DIR ${BOND_GENERATED}/bond/core)
|
||||
|
||||
# Generate again into intermediate dir so that we can build libraries
|
||||
|
@ -18,6 +19,7 @@ add_bond_codegen (${core_schemas}
|
|||
# in a clean build, leading to collisions in multi-processor build.
|
||||
add_bond_codegen (${core_schemas}
|
||||
ENUM_HEADER
|
||||
COMM
|
||||
OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bond/core)
|
||||
|
||||
file (GLOB core_headers "inc/bond/core/*.h")
|
||||
|
@ -51,7 +53,7 @@ list (APPEND headers
|
|||
${protocol_detail_headers}
|
||||
${stream_headers})
|
||||
|
||||
if (NOT BOND_CORE_ONLY)
|
||||
if (BOND_ENABLE_COMM)
|
||||
set (comm_schemas
|
||||
${BOND_IDL}/bond/comm/comm.bond
|
||||
${BOND_IDL}/bond/comm/transport/packet.bond
|
||||
|
@ -101,7 +103,7 @@ if (NOT BOND_CORE_ONLY)
|
|||
${comm_layers_headers}
|
||||
${comm_transport_headers}
|
||||
${comm_transport_detail_headers})
|
||||
endif(NOT BOND_CORE_ONLY)
|
||||
endif(BOND_ENABLE_COMM)
|
||||
|
||||
source_group ("generated" FILES ${generated_files})
|
||||
|
||||
|
@ -137,7 +139,7 @@ install (TARGETS bond bond_apply
|
|||
|
||||
install (DIRECTORY ${BOND_IDL}/bond/core DESTINATION include/bond)
|
||||
|
||||
if (NOT BOND_CORE_ONLY)
|
||||
if (BOND_ENABLE_COMM)
|
||||
install (DIRECTORY ${BOND_IDL}/bond/comm DESTINATION include/bond)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "event.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
|
||||
namespace bond { namespace ext { namespace detail {
|
||||
|
||||
/// @brief A synchronization primitive that is signaled when a certain
|
||||
/// number of threads are waiting on it at the same time.
|
||||
///
|
||||
/// A barrier can only be used once: there is no way to reset it, even after
|
||||
/// all the threads have entered.
|
||||
class barrier final
|
||||
{
|
||||
public:
|
||||
/// @param count the number of threads that must enter before they will
|
||||
/// all be released. Must be positive.
|
||||
explicit barrier(size_t count)
|
||||
: _e(),
|
||||
_cnt(count)
|
||||
{
|
||||
BOOST_ASSERT(count > 0);
|
||||
}
|
||||
|
||||
/// @brief Enter the barrier, decrement the count, and potentially
|
||||
/// release the other waiting threads.
|
||||
///
|
||||
/// @warning If more threads enter the barrier than its \p count, the
|
||||
/// behavior is undefined.
|
||||
///
|
||||
/// @return \p true for exactly one thread, \p false for the rest.
|
||||
bool enter()
|
||||
{
|
||||
size_t newValue = --_cnt;
|
||||
|
||||
if (newValue == 0)
|
||||
{
|
||||
_e.set();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_e.wait();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Wait for all the threads to enter the barrier.
|
||||
///
|
||||
/// @note This is intended for "observer" threads. It doesn't affect the
|
||||
/// count and will never release any other threads.
|
||||
void wait()
|
||||
{
|
||||
_e.wait();
|
||||
}
|
||||
|
||||
/// @brief Waits at least \p timeout for all the threads to enter the
|
||||
/// barrier.
|
||||
///
|
||||
/// @note This is intended for "observer" threads. It doesn't affect the
|
||||
/// count and will never release any other threads.
|
||||
///
|
||||
/// @param timeout the minimum amount of time to wait for the event to
|
||||
/// enter the signaled state.
|
||||
///
|
||||
/// @return \p true if the event was signaled. \p false if the timeout
|
||||
/// occured.
|
||||
template <typename Rep, typename Period>
|
||||
bool wait_for(const std::chrono::duration<Rep, Period>& timeout)
|
||||
{
|
||||
return _e.wait_for(timeout);
|
||||
}
|
||||
|
||||
private:
|
||||
event _e;
|
||||
std::atomic<size_t> _cnt;
|
||||
|
||||
barrier(const barrier&) = delete;
|
||||
barrier(barrier&&) = delete;
|
||||
barrier& operator=(const barrier&) = delete;
|
||||
barrier& operator=(barrier&&) = delete;
|
||||
};
|
||||
|
||||
} } } // namespace bond::ext::detail
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "event.h"
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
|
||||
namespace bond { namespace ext { namespace detail {
|
||||
|
||||
/// @ A synchronization primitive that is signaled when its count reaches
|
||||
/// zero.
|
||||
class countdown_event final
|
||||
{
|
||||
public:
|
||||
/// @param count the number of times the event must be set before it is
|
||||
/// signaled. Must be positive.
|
||||
explicit countdown_event(size_t count)
|
||||
: _e(),
|
||||
_cnt(count)
|
||||
{
|
||||
BOOST_ASSERT(count > 0);
|
||||
}
|
||||
|
||||
/// @brief Decrements the count, potentially signalling the event.
|
||||
///
|
||||
/// @warning If \ref set is called more times that the initial count,
|
||||
/// the behavior is undefined.
|
||||
///
|
||||
/// @return \p true if this signal caused the event to be signaled,
|
||||
/// otherwise \p false.
|
||||
bool set()
|
||||
{
|
||||
size_t newValue = --_cnt;
|
||||
|
||||
if (newValue == 0)
|
||||
{
|
||||
_e.set();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief Wait for the count to reach zero.
|
||||
void wait()
|
||||
{
|
||||
_e.wait();
|
||||
}
|
||||
|
||||
/// @brief Waits at least \p timeout for the count to reach zero.
|
||||
///
|
||||
/// @param timeout the minimum amount of time to wait for the event to
|
||||
/// enter the signaled state.
|
||||
///
|
||||
/// @return \p true if the event was signaled. \p false if the timeout
|
||||
/// occured.
|
||||
template <typename Rep, typename Period>
|
||||
bool wait_for(const std::chrono::duration<Rep, Period>& timeout)
|
||||
{
|
||||
return _e.wait_for(timeout);
|
||||
}
|
||||
|
||||
private:
|
||||
event _e;
|
||||
std::atomic<size_t> _cnt;
|
||||
|
||||
countdown_event(const countdown_event&) = delete;
|
||||
countdown_event(countdown_event&&) = delete;
|
||||
countdown_event& operator=(const countdown_event&) = delete;
|
||||
countdown_event& operator=(countdown_event&&) = delete;
|
||||
};
|
||||
|
||||
} } } // namespace bond::ext::detail
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
namespace bond { namespace ext { namespace detail {
|
||||
|
||||
/// @brief A synchronization primitive that is signaled manually.
|
||||
///
|
||||
/// @remarks This class only provides a \ref set method. It
|
||||
/// intentionally does not have a \p reset method to avoid the potential
|
||||
/// for waiters missing a signal if \p set and \p reset were to be
|
||||
/// called in quick succession.
|
||||
class event final
|
||||
{
|
||||
public:
|
||||
explicit event()
|
||||
: _m(),
|
||||
_cv(),
|
||||
_isSet(false)
|
||||
{}
|
||||
|
||||
/// @brief Signals the event, releasing current and future waiters.
|
||||
void set()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_m);
|
||||
_isSet = true;
|
||||
}
|
||||
|
||||
_cv.notify_all();
|
||||
}
|
||||
|
||||
/// @brief Waits for the event to enter the signaled state.
|
||||
void wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_m);
|
||||
return _cv.wait(lock, [this]() {return _isSet;});
|
||||
}
|
||||
|
||||
/// @brief Waits at least \p timeout for the event to enter the
|
||||
/// signaled state.
|
||||
///
|
||||
/// @param timeout the minimum amount of time to wait for the event
|
||||
/// to enter the signaled state.
|
||||
///
|
||||
/// @return \p true if the event was signaled. \p false if the
|
||||
/// timeout occured.
|
||||
template <typename Rep, typename Period>
|
||||
bool wait_for(const std::chrono::duration<Rep, Period>& timeout)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_m);
|
||||
return _cv.wait_for(lock, timeout, [this]() {return _isSet;});
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex _m;
|
||||
std::condition_variable _cv;
|
||||
bool _isSet;
|
||||
|
||||
event(const event&) = delete;
|
||||
event(event&&) = delete;
|
||||
event& operator=(const event&) = delete;
|
||||
event& operator=(event&&) = delete;
|
||||
};
|
||||
|
||||
} } } // namespace bond::ext::detail
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <grpc++/impl/codegen/config.h>
|
||||
#include <grpc++/impl/codegen/core_codegen.h>
|
||||
#include <grpc++/impl/codegen/core_codegen_interface.h>
|
||||
#include <grpc++/impl/codegen/serialization_traits.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
#include <grpc++/impl/codegen/status_code_enum.h>
|
||||
#include <grpc/impl/codegen/byte_buffer_reader.h>
|
||||
#include <grpc/impl/codegen/slice.h>
|
||||
|
||||
#include <bond/core/bond.h>
|
||||
#include <bond/core/bonded.h>
|
||||
#include <bond/core/reflection.h>
|
||||
#include <bond/stream/output_buffer.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace grpc {
|
||||
|
||||
template <class T>
|
||||
class SerializationTraits<bond::bonded<T>, typename std::enable_if<bond::is_bond_type<T>::value>::type>
|
||||
{
|
||||
public:
|
||||
static Status Serialize(
|
||||
const bond::bonded<T>& msg,
|
||||
grpc_byte_buffer** bp,
|
||||
bool* own_buffer)
|
||||
{
|
||||
*own_buffer = true;
|
||||
|
||||
bond::OutputBuffer output;
|
||||
bond::CompactBinaryWriter<bond::OutputBuffer> writer(output);
|
||||
|
||||
msg.Serialize(writer);
|
||||
|
||||
bond::blob data = output.GetBuffer();
|
||||
|
||||
grpc_slice slice = grpc_slice_from_copied_buffer(data.content(), data.length());
|
||||
|
||||
*bp = grpc_raw_byte_buffer_create(&slice, 1);
|
||||
|
||||
grpc_slice_unref(slice);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
static Status Deserialize(grpc_byte_buffer* buffer, bond::bonded<T>* msg)
|
||||
{
|
||||
if (!buffer)
|
||||
{
|
||||
return Status(StatusCode::INTERNAL, "No payload");
|
||||
}
|
||||
|
||||
const size_t bufferSize = grpc_byte_buffer_length(buffer);
|
||||
|
||||
if (bufferSize > std::numeric_limits<uint32_t>::max())
|
||||
{
|
||||
grpc_byte_buffer_destroy(buffer);
|
||||
return Status(StatusCode::INTERNAL, "Buffer is too large");
|
||||
}
|
||||
|
||||
boost::shared_ptr<char[]> buff = boost::make_shared_noinit<char[]>(bufferSize);
|
||||
|
||||
// TODO: exception safety of reader, s, buffer
|
||||
grpc_byte_buffer_reader reader;
|
||||
if (!grpc_byte_buffer_reader_init(&reader, buffer))
|
||||
{
|
||||
grpc_byte_buffer_destroy(buffer);
|
||||
return Status(StatusCode::INTERNAL, "Failed to init buffer reader");
|
||||
}
|
||||
|
||||
char* dest = buff.get();
|
||||
|
||||
grpc_slice s;
|
||||
while (grpc_byte_buffer_reader_next(&reader, &s) != 0)
|
||||
{
|
||||
std::memcpy(dest, GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s));
|
||||
dest += GRPC_SLICE_LENGTH(s);
|
||||
}
|
||||
|
||||
BOOST_ASSERT(dest == buff.get() + bufferSize);
|
||||
|
||||
grpc_slice_unref(s);
|
||||
grpc_byte_buffer_reader_destroy(&reader);
|
||||
grpc_byte_buffer_destroy(buffer);
|
||||
|
||||
// TODO: create a Bond input stream over grpc_byte_buffer to avoid
|
||||
// having to make this copy into a blob.
|
||||
bond::blob data = bond::blob(buff, static_cast<uint32_t>(bufferSize));
|
||||
bond::CompactBinaryReader<bond::InputBuffer> cbreader(data);
|
||||
*msg = bond::bonded<T>(cbreader);
|
||||
|
||||
return Status::OK;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace grpc
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4702)
|
||||
#endif
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
#include <grpc++/impl/codegen/rpc_method.h>
|
||||
#include <grpc++/impl/codegen/service_type.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/detail/service.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC { namespace detail {
|
||||
|
||||
/// @brief Implementation class that hold the state associated with
|
||||
/// outgoing unary calls.
|
||||
template <typename TRequest, typename TResponse, typename TThreadPool>
|
||||
struct client_unary_call_data : io_manager_tag
|
||||
{
|
||||
/// The type of the user-defined callback that will be invoked for the
|
||||
/// response.
|
||||
typedef std::function<void(const TResponse&, const grpc::Status&)> CallbackType;
|
||||
|
||||
/// The channel to send the request on.
|
||||
std::shared_ptr<grpc::ChannelInterface> _channel;
|
||||
/// The io_manager to use for both sending and receiving.
|
||||
std::shared_ptr<io_manager> _ioManager;
|
||||
/// The thread pool in which to invoke the callback.
|
||||
std::shared_ptr<TThreadPool> _threadPool;
|
||||
/// A response reader.
|
||||
std::unique_ptr<grpc::ClientAsyncResponseReader<TResponse>> _responseReader;
|
||||
|
||||
/// The user code to invoke when a response is received.
|
||||
CallbackType _cb;
|
||||
/// The response received.
|
||||
TResponse _response;
|
||||
/// The status received.
|
||||
grpc::Status _status;
|
||||
|
||||
client_unary_call_data(
|
||||
std::shared_ptr<grpc::ChannelInterface> channel,
|
||||
std::shared_ptr<io_manager> ioManager,
|
||||
std::shared_ptr<TThreadPool> threadPool,
|
||||
CallbackType cb = {})
|
||||
: _channel(channel),
|
||||
_ioManager(ioManager),
|
||||
_threadPool(threadPool),
|
||||
_responseReader(),
|
||||
_cb(cb),
|
||||
_response(),
|
||||
_status()
|
||||
{
|
||||
BOOST_ASSERT(channel);
|
||||
BOOST_ASSERT(ioManager);
|
||||
BOOST_ASSERT(threadPool);
|
||||
}
|
||||
|
||||
void dispatch(
|
||||
grpc::RpcMethod method,
|
||||
grpc::ClientContext* context,
|
||||
const TRequest& request)
|
||||
{
|
||||
_responseReader = std::unique_ptr<grpc::ClientAsyncResponseReader<TResponse>>(
|
||||
new ::grpc::ClientAsyncResponseReader<TResponse>(
|
||||
_channel.get(),
|
||||
_ioManager->cq(),
|
||||
method,
|
||||
context,
|
||||
request));
|
||||
_responseReader->Finish(&_response, &_status, static_cast<void*>(this));
|
||||
}
|
||||
|
||||
void invoke(bool ok) override
|
||||
{
|
||||
if (ok && _cb)
|
||||
{
|
||||
_threadPool->schedule([this]()
|
||||
{
|
||||
_cb(_response, _status);
|
||||
|
||||
delete this;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} } } } //namespace bond::ext::gRPC::detail
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC { namespace detail {
|
||||
|
||||
/// @brief Interface for completion queue tag types that \ref io_manager
|
||||
/// expects.
|
||||
///
|
||||
/// Typically, a type inherits from this type, captures at construction
|
||||
/// time in its locals the state of some operation, and resumes that
|
||||
/// operation in its implementation of \ref invoke.
|
||||
struct io_manager_tag
|
||||
{
|
||||
virtual ~io_manager_tag() { }
|
||||
|
||||
/// @brief Called when this instance is dequeued from a completion
|
||||
/// queue.
|
||||
///
|
||||
/// @param ok whether or not the initial operation succeeded
|
||||
virtual void invoke(bool ok) = 0;
|
||||
};
|
||||
|
||||
} } } } // namespace bond::ext::gRPC::detail
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4702)
|
||||
#endif
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
#include <grpc++/impl/codegen/rpc_method.h>
|
||||
#include <grpc++/impl/codegen/service_type.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC { namespace detail {
|
||||
|
||||
struct io_manager_tag;
|
||||
|
||||
/// @brief Base class that all Bond gRPC++ services implement.
|
||||
///
|
||||
/// @note This class is for use by generated and helper code only.
|
||||
///
|
||||
/// Helper class that codegen uses to generate abstract service classes,
|
||||
/// which a bond::ext::gRPC::server then hosts multiple services.
|
||||
template <typename TThreadPool>
|
||||
class service : private grpc::Service
|
||||
{
|
||||
public:
|
||||
virtual ~service() { }
|
||||
|
||||
/// @brief Starts the service.
|
||||
///
|
||||
/// @note This method is for use by generated and helper code only.
|
||||
///
|
||||
/// Typical implementations call queue_receive on all the methods in the
|
||||
/// service to kick of the process of receiving messages.
|
||||
virtual void start(grpc::ServerCompletionQueue* cq, std::shared_ptr<TThreadPool> threadPool) = 0;
|
||||
|
||||
/// @brief Starts the receive process for a method.
|
||||
///
|
||||
/// @note This method is for use by generated and helper code only.
|
||||
///
|
||||
/// When a request for the method has been received, \p tag will be
|
||||
/// added to \p cq.
|
||||
///
|
||||
/// @param methodIndex the index of the method (indices are assigned by
|
||||
/// the order in which the methods are registered via calls to
|
||||
/// AddMethod)
|
||||
///
|
||||
/// @param context a fresh grpc::ServerContext for the call to populate
|
||||
///
|
||||
/// @param request pointer to a request object to populate
|
||||
///
|
||||
/// @param responseStream pointer to a response stream to populate
|
||||
///
|
||||
/// @param cq the completion queue to notify when a call has been
|
||||
/// received
|
||||
///
|
||||
/// @param tag the io_manager_tag to include with the completion queue
|
||||
/// notification
|
||||
template <typename TRequest>
|
||||
void queue_receive(
|
||||
int methodIndex,
|
||||
grpc::ServerContext* context,
|
||||
TRequest* request,
|
||||
grpc::ServerAsyncStreamingInterface* responseStream,
|
||||
grpc::ServerCompletionQueue* cq,
|
||||
io_manager_tag* tag)
|
||||
{
|
||||
RequestAsyncUnary(
|
||||
methodIndex,
|
||||
context,
|
||||
request,
|
||||
responseStream,
|
||||
cq,
|
||||
cq,
|
||||
tag);
|
||||
}
|
||||
|
||||
/// @brief Provides access to the raw grpc::Service type.
|
||||
///
|
||||
/// @note This method is for use by generated and helper code only.
|
||||
grpc::Service* grpc_service()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// @brief Registers a method name for dispatch to this service.
|
||||
///
|
||||
/// @note This method is for use by generated and helper code only.
|
||||
///
|
||||
/// The order in which methods are registered assigned the method index,
|
||||
/// which is used elsewhere.
|
||||
void AddMethod(const char* methodName)
|
||||
{
|
||||
BOOST_ASSERT(methodName);
|
||||
|
||||
// ownership of the service method is transfered to grpc::Service
|
||||
AddMethod(
|
||||
new grpc::RpcServiceMethod(
|
||||
methodName,
|
||||
grpc::RpcMethod::NORMAL_RPC,
|
||||
nullptr)); // nullptr indicates async handler
|
||||
}
|
||||
|
||||
private:
|
||||
using grpc::Service::AddMethod;
|
||||
};
|
||||
|
||||
} } } } //namespace bond::ext::gRPC::detail
|
|
@ -0,0 +1,111 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4702)
|
||||
#endif
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
#include <grpc++/impl/codegen/rpc_method.h>
|
||||
#include <grpc++/impl/codegen/service_type.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#include <bond/ext/grpc/detail/io_manager_tag.h>
|
||||
#include <bond/ext/grpc/detail/service.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC { namespace detail {
|
||||
|
||||
/// @brief Implementation class that hold the state associated with
|
||||
/// receiving incomming calls for one method.
|
||||
///
|
||||
/// There only needs to be one of these per method in a service, and it can
|
||||
/// be re-used for receiving subsequent calls. A new detail::unary_call_impl
|
||||
/// is created for each individual call to hold the call-specific data. Once
|
||||
/// the detail::unary_call_impl has been dispatched to the user callback,
|
||||
/// detail::unary_call_impl is in charge of its own lifetime, and
|
||||
/// detail::service_unary_call_data re-enqueues itself to get the next call.
|
||||
template <typename TRequest, typename TResponse, typename TThreadPool>
|
||||
struct service_unary_call_data : io_manager_tag
|
||||
{
|
||||
/// The type of the user-defined callback that will be invoked upon receipt
|
||||
/// of this call.
|
||||
typedef std::function<void(unary_call<TRequest, TResponse> call)> CallbackType;
|
||||
|
||||
/// The service implementing the method.
|
||||
service<TThreadPool>* _service;
|
||||
/// The index of the method. Method indices correspond to the order in
|
||||
/// which they were registered with detail::service::AddMethod
|
||||
int _methodIndex;
|
||||
/// The completion port to post IO operations to.
|
||||
grpc::ServerCompletionQueue* _cq;
|
||||
/// The thread pool implementation to use to invoke the user callback.
|
||||
std::shared_ptr<TThreadPool> _threadPool;
|
||||
/// The user code to invoke when a call to this method is received.
|
||||
CallbackType _cb;
|
||||
/// Individual state for one specific call to this method.
|
||||
std::unique_ptr<unary_call_impl<TRequest, TResponse>> _receivedCall;
|
||||
|
||||
service_unary_call_data(
|
||||
service<TThreadPool>* service,
|
||||
int methodIndex,
|
||||
grpc::ServerCompletionQueue* cq,
|
||||
std::shared_ptr<TThreadPool> threadPool,
|
||||
CallbackType cb)
|
||||
: _service(service),
|
||||
_methodIndex(methodIndex),
|
||||
_cq(cq),
|
||||
_threadPool(threadPool),
|
||||
_cb(cb),
|
||||
_receivedCall(new unary_call_impl<TRequest, TResponse>)
|
||||
{
|
||||
BOOST_ASSERT(service);
|
||||
BOOST_ASSERT(cq);
|
||||
BOOST_ASSERT(threadPool);
|
||||
BOOST_ASSERT(cb);
|
||||
}
|
||||
|
||||
void invoke(bool ok) override
|
||||
{
|
||||
if (ok)
|
||||
{
|
||||
// unary_call_impl::invoke will delete itself after it's posted
|
||||
// back to the completion queue as the result of sending a
|
||||
// response. The UnaryCall wrapper that we create inside the
|
||||
// thread guarantees that some response will always be sent.
|
||||
unary_call_impl<TRequest, TResponse>* receivedCall = _receivedCall.release();
|
||||
|
||||
_threadPool->schedule([this, receivedCall]()
|
||||
{
|
||||
_cb(unary_call<TRequest, TResponse> { receivedCall });
|
||||
});
|
||||
|
||||
_receivedCall.reset(new unary_call_impl<TRequest, TResponse>);
|
||||
_service->queue_receive(
|
||||
_methodIndex,
|
||||
&_receivedCall->_context,
|
||||
&_receivedCall->_request,
|
||||
&_receivedCall->_responder,
|
||||
_cq,
|
||||
this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're shutting down, so don't requeue
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} } } } //namespace bond::ext::gRPC::detail
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <bond/core/exception.h>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC {
|
||||
|
||||
/// @brief Exception thrown to indicate that a callback has been invoked
|
||||
/// multiple times when only one invocation is expected.
|
||||
class MultipleInvocationException : public Exception
|
||||
{
|
||||
public:
|
||||
MultipleInvocationException() : Exception("The callback was invoked more than once.") { }
|
||||
};
|
||||
|
||||
} } } // namespace bond::ext::gRPC
|
|
@ -0,0 +1,239 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4702)
|
||||
#endif
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
#include <grpc++/impl/codegen/completion_queue.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#include <bond/ext/detail/event.h>
|
||||
#include <bond/ext/grpc/detail/io_manager_tag.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC {
|
||||
|
||||
/// @brief Manages a pool of threads polling for work from the same
|
||||
/// %grpc::CompletionQueue
|
||||
///
|
||||
/// All of the tags enqueued in this completion queue must inherit from
|
||||
/// \ref io_manager_tag. If not, the behavior is undefined.
|
||||
class io_manager final
|
||||
{
|
||||
public:
|
||||
/// @brief Tag type used to indicate that an io_manager should not
|
||||
/// automatically start its polling threads.
|
||||
struct delay_start_tag final { };
|
||||
|
||||
static constexpr size_t USE_HARDWARE_CONC = 0;
|
||||
|
||||
/// @brief Creates and starts and io_manager.
|
||||
///
|
||||
/// @param numThreads the number of threads to start. If \ref
|
||||
/// USE_HARDWARE_CONC, then a number of threads depending on the
|
||||
/// hardware's available concurrency will be started.
|
||||
explicit io_manager(size_t numThreads = USE_HARDWARE_CONC)
|
||||
: _cq(new grpc::CompletionQueue),
|
||||
_numThreads(compute_real_num_threads(numThreads)),
|
||||
_threads(),
|
||||
_isShutdownRequested(),
|
||||
_isShutdownInProgress(),
|
||||
_shutdownCompleted()
|
||||
{
|
||||
BOOST_ASSERT(_cq);
|
||||
start();
|
||||
}
|
||||
|
||||
/// @brief Creates and starts and io_manager.
|
||||
///
|
||||
/// @param cq the completion queue to poll. Takes ownership.
|
||||
///
|
||||
/// @param numThreads the number of threads to start. If \ref
|
||||
/// USE_HARDWARE_CONC, then a number of threads depending on the
|
||||
/// hardware's available concurrency will be started.
|
||||
explicit io_manager(std::unique_ptr<grpc::CompletionQueue> cq, size_t numThreads = USE_HARDWARE_CONC)
|
||||
: _cq(std::move(cq)),
|
||||
_numThreads(compute_real_num_threads(numThreads)),
|
||||
_threads(),
|
||||
_isShutdownRequested(),
|
||||
_isShutdownInProgress(),
|
||||
_shutdownCompleted()
|
||||
{
|
||||
BOOST_ASSERT(_cq);
|
||||
start();
|
||||
}
|
||||
|
||||
/// @brief Creates an io_managed, but does not start it.
|
||||
///
|
||||
/// @param numThreads the number of threads to start. If \ref
|
||||
/// USE_HARDWARE_CONC, then a number of threads depending on the
|
||||
/// hardware's available concurrency will be started.
|
||||
io_manager(size_t numThreads, delay_start_tag)
|
||||
: _cq(new grpc::CompletionQueue),
|
||||
_numThreads(compute_real_num_threads(numThreads)),
|
||||
_threads(),
|
||||
_isShutdownRequested(),
|
||||
_isShutdownInProgress(),
|
||||
_shutdownCompleted()
|
||||
{
|
||||
BOOST_ASSERT(_cq);
|
||||
|
||||
// this overload does NOT call start()
|
||||
}
|
||||
|
||||
/// @brief Creates an io_managed, but does not start it.
|
||||
///
|
||||
/// @param cq the completion queue to poll. Takes ownership.
|
||||
///
|
||||
/// @param numThreads the number of threads to start. If \ref
|
||||
/// USE_HARDWARE_CONC, then a number of threads depending on the
|
||||
/// hardware's available concurrency will be started.
|
||||
io_manager(std::unique_ptr<grpc::CompletionQueue> cq, size_t numThreads, delay_start_tag)
|
||||
: _cq(std::move(cq)),
|
||||
_numThreads(compute_real_num_threads(numThreads)),
|
||||
_threads(),
|
||||
_isShutdownRequested(),
|
||||
_isShutdownInProgress(),
|
||||
_shutdownCompleted()
|
||||
{
|
||||
BOOST_ASSERT(_cq);
|
||||
|
||||
// this overload does NOT call start()
|
||||
}
|
||||
|
||||
/// Waits for the \p io_manager to stop.
|
||||
~io_manager()
|
||||
{
|
||||
shutdown();
|
||||
wait();
|
||||
}
|
||||
|
||||
/// Gets the underlying completion queue.
|
||||
///
|
||||
/// @note Ownership of the completion queue remains with the
|
||||
/// io_manager.
|
||||
grpc::CompletionQueue* cq()
|
||||
{
|
||||
return _cq.get();
|
||||
}
|
||||
|
||||
/// @brief Starts polling the completion queue.
|
||||
///
|
||||
/// @remarks Can be called multiple times, but not safe to be called
|
||||
/// concurrently.
|
||||
///
|
||||
/// @remarks An io_manager cannot be restarted after it has been
|
||||
/// shutdown.
|
||||
void start()
|
||||
{
|
||||
BOOST_ASSERT(_cq);
|
||||
|
||||
if (_threads.empty())
|
||||
{
|
||||
_threads.reserve(_numThreads);
|
||||
|
||||
for (size_t i = 0; i < _numThreads; ++i)
|
||||
{
|
||||
_threads.emplace_back([this]()
|
||||
{
|
||||
void* tag;
|
||||
bool ok;
|
||||
while (_cq->Next(&tag, &ok))
|
||||
{
|
||||
BOOST_ASSERT(tag);
|
||||
static_cast<detail::io_manager_tag*>(tag)->invoke(ok);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Requests that the io_manager shutdown.
|
||||
///
|
||||
/// @remarks If the io_manager is being used for by a
|
||||
/// bond::ext::gRPC::server, that server needs to be shutdown first.
|
||||
///
|
||||
/// @remarks Can be called from multiple threads concurrently.
|
||||
void shutdown()
|
||||
{
|
||||
bool shouldRequest = !_isShutdownRequested.test_and_set();
|
||||
if (shouldRequest)
|
||||
{
|
||||
_cq->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/// Waits for remaining work to drain from the io_manager and for
|
||||
/// the worker threads to be shutdown.
|
||||
///
|
||||
/// @remarks Can be called from multiple threads concurrently.
|
||||
///
|
||||
/// @warning Cannot be called from an io_manager worker thread. In
|
||||
/// other words, never call this function from inside of
|
||||
/// io_manager_tag::invoke.
|
||||
///
|
||||
/// @warning Either \ref shutdown must have been called already, or
|
||||
/// some other thread must call \p shutdown for this function to
|
||||
/// return.
|
||||
void wait()
|
||||
{
|
||||
bool shouldShutdown = !_isShutdownInProgress.test_and_set();
|
||||
if (shouldShutdown)
|
||||
{
|
||||
// borrow the current thread to clean up
|
||||
for (auto& thread : _threads)
|
||||
{
|
||||
BOOST_ASSERT(thread.joinable());
|
||||
thread.join();
|
||||
}
|
||||
|
||||
_threads.clear();
|
||||
|
||||
_cq.reset();
|
||||
_shutdownCompleted.set();
|
||||
}
|
||||
else
|
||||
{
|
||||
// some other thread is performing clean up, so wait for it
|
||||
_shutdownCompleted.wait();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t compute_real_num_threads(size_t numThreads)
|
||||
{
|
||||
if (numThreads == USE_HARDWARE_CONC)
|
||||
{
|
||||
numThreads = static_cast<size_t>(std::thread::hardware_concurrency());
|
||||
}
|
||||
|
||||
// hardware_concurency can fail and return 0. If so, we need a
|
||||
// non-zero number of threads.
|
||||
const size_t recourseNumThreads = 2;
|
||||
return numThreads != 0 ? numThreads : recourseNumThreads;
|
||||
}
|
||||
|
||||
std::unique_ptr<grpc::CompletionQueue> _cq;
|
||||
size_t _numThreads;
|
||||
std::vector<std::thread> _threads;
|
||||
|
||||
std::atomic_flag _isShutdownRequested;
|
||||
std::atomic_flag _isShutdownInProgress;
|
||||
bond::ext::detail::event _shutdownCompleted;
|
||||
};
|
||||
|
||||
} } } // namespace bond::ext::gRPC
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
/*
|
||||
*
|
||||
* Portions Copyright 2015, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4702)
|
||||
#endif
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC {
|
||||
|
||||
template <typename TThreadPool> class server_builder_core;
|
||||
|
||||
/// @brief Models a gRPC server powered by Bond services.
|
||||
///
|
||||
/// Servers are configured and started via
|
||||
/// bond::ext:gRPC::server_builder.
|
||||
template <typename TThreadPool>
|
||||
class server_core final
|
||||
{
|
||||
public:
|
||||
~server_core()
|
||||
{
|
||||
Shutdown();
|
||||
Wait();
|
||||
}
|
||||
|
||||
server_core(const server_core&) = delete;
|
||||
server_core& operator=(const server_core&) = delete;
|
||||
|
||||
server_core(server_core&&) = default;
|
||||
server_core& operator=(server_core&&) = default;
|
||||
|
||||
/// @brief Shutdown the server, blocking until all rpc processing
|
||||
/// finishes.
|
||||
///
|
||||
/// Forcefully terminate pending calls after \p deadline expires.
|
||||
///
|
||||
/// @param deadline How long to wait until pending rpcs are
|
||||
/// forcefully terminated.
|
||||
template <class T>
|
||||
void Shutdown(const T& deadline)
|
||||
{
|
||||
_grpcServer->Shutdown(deadline);
|
||||
_ioManager.shutdown();
|
||||
}
|
||||
|
||||
/// Shutdown the server, waiting for all rpc processing to finish.
|
||||
void Shutdown()
|
||||
{
|
||||
_grpcServer->Shutdown();
|
||||
_ioManager.shutdown();
|
||||
}
|
||||
|
||||
/// @brief Block waiting for all work to complete.
|
||||
///
|
||||
/// @warning The server must be either shutting down or some other
|
||||
/// thread must call \p Shutdown for this function to ever return.
|
||||
void Wait()
|
||||
{
|
||||
_grpcServer->Wait();
|
||||
_ioManager.wait();
|
||||
}
|
||||
|
||||
friend class server_builder_core<TThreadPool>;
|
||||
|
||||
private:
|
||||
server_core(
|
||||
std::unique_ptr<grpc::Server> grpcServer,
|
||||
std::unique_ptr<grpc::ServerCompletionQueue> cq)
|
||||
: _grpcServer(std::move(grpcServer)),
|
||||
_ioManager(std::move(cq))
|
||||
{
|
||||
BOOST_ASSERT(_grpcServer);
|
||||
}
|
||||
|
||||
std::unique_ptr<grpc::Server> _grpcServer;
|
||||
io_manager _ioManager;
|
||||
};
|
||||
|
||||
using server = server_core<bond::ext::gRPC::thread_pool>;
|
||||
|
||||
} } } //namespace bond::ext::gRPC
|
|
@ -0,0 +1,213 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
/*
|
||||
*
|
||||
* Portions Copyright 2015-2016, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4702)
|
||||
#endif
|
||||
|
||||
#include <grpc++/server_builder.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#include <bond/ext/grpc/server.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/grpc/detail/service.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC {
|
||||
|
||||
/// @brief A builder class for the creation and startup of \a
|
||||
/// bond::ext::gRPC::server instances.
|
||||
template <typename TThreadPool>
|
||||
class server_builder_core final {
|
||||
public:
|
||||
server_builder_core()
|
||||
: _grpcServerBuilder(),
|
||||
_services(),
|
||||
_threadPool()
|
||||
{
|
||||
}
|
||||
|
||||
/// Register a service. This call does not take ownership of the
|
||||
/// service. The service must exist for the lifetime of the \p
|
||||
/// server instance returned by \p BuildAndStart().
|
||||
///
|
||||
/// Matches requests with any :authority
|
||||
server_builder_core& RegisterService(detail::service<TThreadPool>* service)
|
||||
{
|
||||
BOOST_ASSERT(service);
|
||||
_grpcServerBuilder.RegisterService(service->grpc_service());
|
||||
_services.insert(service);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Register a service. This call does not take ownership of the
|
||||
/// service. The service must exist for the lifetime of the \p
|
||||
/// server instance returned by BuildAndStart().
|
||||
///
|
||||
/// Only matches requests with :authority \p host
|
||||
server_builder_core& RegisterService(const grpc::string& host, detail::service<TThreadPool>* service)
|
||||
{
|
||||
BOOST_ASSERT(service);
|
||||
_grpcServerBuilder.RegisterService(host, service->grpc_service());
|
||||
_services.insert(service);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set max receive message size in bytes.
|
||||
server_builder_core& SetMaxReceiveMessageSize(int max_receive_message_size)
|
||||
{
|
||||
_grpcServerBuilder.SetMaxReceiveMessageSize(max_receive_message_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set max send message size in bytes.
|
||||
server_builder_core& SetMaxSendMessageSize(int max_send_message_size)
|
||||
{
|
||||
_grpcServerBuilder.SetMaxSendMessageSize(max_send_message_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// @brief Set the support status for compression algorithms.
|
||||
///
|
||||
/// All algorithms are enabled by default.
|
||||
///
|
||||
/// Incoming calls compressed with an unsupported algorithm will
|
||||
/// fail with GRPC_STATUS_UNIMPLEMENTED.
|
||||
server_builder_core& SetCompressionAlgorithmSupportStatus(
|
||||
grpc_compression_algorithm algorithm,
|
||||
bool enabled)
|
||||
{
|
||||
_grpcServerBuilder.SetCompressionAlgorithmSupportStatus(algorithm, enabled);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// The default compression level to use for all channel calls in
|
||||
/// the absence of a call-specific level.
|
||||
server_builder_core& SetDefaultCompressionLevel(grpc_compression_level level)
|
||||
{
|
||||
_grpcServerBuilder.SetDefaultCompressionLevel(level);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// The default compression algorithm to use for all channel calls
|
||||
/// in the absence of a call-specific level. Note that it overrides
|
||||
/// any compression level set by \p SetDefaultCompressionLevel.
|
||||
server_builder_core& SetDefaultCompressionAlgorithm(
|
||||
grpc_compression_algorithm algorithm)
|
||||
{
|
||||
_grpcServerBuilder.SetDefaultCompressionAlgorithm(algorithm);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Set the attached buffer pool for this server.
|
||||
server_builder_core& SetResourceQuota(const grpc::ResourceQuota& resource_quota)
|
||||
{
|
||||
_grpcServerBuilder.SetResourceQuota(resource_quota);
|
||||
return *this;
|
||||
}
|
||||
|
||||
server_builder_core& SetThreadPool(std::shared_ptr<TThreadPool> thread_pool)
|
||||
{
|
||||
_threadPool = thread_pool;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Tries to bind this server to the given \p addr.
|
||||
///
|
||||
/// It can be invoked multiple times.
|
||||
///
|
||||
/// @param addr The address to try to bind to the server (eg,
|
||||
/// localhost:1234, 192.168.1.1:31416, [::1]:27182, etc.).
|
||||
/// @param creds The credentials associated with the server.
|
||||
/// @param[out] selected_port Upon success, updated to contain the
|
||||
/// port number. \p nullptr otherwise.
|
||||
server_builder_core& AddListeningPort(
|
||||
const grpc::string& addr,
|
||||
std::shared_ptr<grpc::ServerCredentials> creds,
|
||||
int* selected_port = nullptr)
|
||||
{
|
||||
_grpcServerBuilder.AddListeningPort(addr, creds, selected_port);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Return a running server which is ready for processing calls.
|
||||
std::unique_ptr<bond::ext::gRPC::server_core<TThreadPool>> BuildAndStart()
|
||||
{
|
||||
std::unique_ptr<grpc::ServerCompletionQueue> cq =
|
||||
_grpcServerBuilder.AddCompletionQueue();
|
||||
std::unique_ptr<grpc::Server> server =
|
||||
_grpcServerBuilder.BuildAndStart();
|
||||
|
||||
if (!_threadPool)
|
||||
{
|
||||
_threadPool = std::make_shared<TThreadPool>();
|
||||
}
|
||||
|
||||
// Tickle all the services so they queue a receive for all their
|
||||
// methods.
|
||||
for (auto& service : _services)
|
||||
{
|
||||
service->start(cq.get(), _threadPool);
|
||||
}
|
||||
|
||||
std::unique_ptr<bond::ext::gRPC::server_core<TThreadPool>> result {
|
||||
new bond::ext::gRPC::server_core<TThreadPool> {
|
||||
std::move(server),
|
||||
std::move(cq) } };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
grpc::ServerBuilder _grpcServerBuilder;
|
||||
std::set<detail::service<TThreadPool>*> _services;
|
||||
std::shared_ptr<TThreadPool> _threadPool;
|
||||
};
|
||||
|
||||
using server_builder = server_builder_core<bond::ext::gRPC::thread_pool>;
|
||||
|
||||
} } } // namespace bond::ext::gRPC
|
|
@ -0,0 +1,110 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined (__APPLE__)
|
||||
// Work-around: 'OSMemoryBarrier' has been explicitly marked deprecated
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#include <boost/asio.hpp>
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined (_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4242) // C4242: 'identifier' : conversion from 'type1' to 'type2', possible loss of data
|
||||
#include <boost/asio.hpp>
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#include <boost/asio.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC
|
||||
{
|
||||
|
||||
#if 0
|
||||
/// @brief The interface that a compliant thread pool must implement.
|
||||
class thread_pool_concept
|
||||
{
|
||||
/// @brief Schedules a callback for execution.
|
||||
///
|
||||
/// @warning The scheduled callback must be executed at some point in
|
||||
/// the future. Some components use the thread_pool_concept to schedule
|
||||
/// the freeing of resources. If a scheduled callback is dropped, these
|
||||
/// resources may not be freed.
|
||||
///
|
||||
/// @param callback functor object to be scheduled. Must accept any
|
||||
/// callable object.
|
||||
template <typename Callback>
|
||||
void schedule(Callback&& callback);
|
||||
};
|
||||
#endif
|
||||
|
||||
/// @brief Basic thread pool implementation.
|
||||
class thread_pool : private boost::asio::io_service
|
||||
{
|
||||
public:
|
||||
static constexpr size_t USE_HARDWARE_CONC = 0;
|
||||
|
||||
/// @brief Constructs and starts a thread pool with the specified number of
|
||||
/// threads.
|
||||
///
|
||||
/// @param numThreads total number of threads to be created. If
|
||||
/// \ref USE_HARDWARE_CONC then as many threads as CPU/cores are available
|
||||
/// will be created.
|
||||
explicit
|
||||
thread_pool(size_t numThreads = USE_HARDWARE_CONC)
|
||||
: _work(*this)
|
||||
{
|
||||
if (USE_HARDWARE_CONC == numThreads)
|
||||
{
|
||||
numThreads = static_cast<size_t>(std::thread::hardware_concurrency());
|
||||
if (numThreads == 0)
|
||||
{
|
||||
// hardware_concurrency can return 0 if it can't figure out
|
||||
// the hardware concurrency. Use a small number larger than 1.
|
||||
const size_t recourseNumThreads = 2;
|
||||
numThreads = recourseNumThreads;
|
||||
}
|
||||
}
|
||||
|
||||
// Spin working threads.
|
||||
for (size_t i = 0; i < numThreads; ++i)
|
||||
{
|
||||
_threads.emplace_back(
|
||||
[this]()
|
||||
{
|
||||
this->run();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// @brief Schedules a callback for execution.
|
||||
///
|
||||
/// @param callback: functor object to be scheduled.
|
||||
template <typename Callback>
|
||||
void schedule(Callback&& callback)
|
||||
{
|
||||
this->post(std::forward<Callback>(callback));
|
||||
}
|
||||
|
||||
/// @brief Get the underlying boost::asio::io_service
|
||||
boost::asio::io_service& get_io_service()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Working threads.
|
||||
std::vector<boost::scoped_thread<boost::join_if_joinable>> _threads;
|
||||
|
||||
/// Helper to keep io_service spinning.
|
||||
boost::asio::io_service::work _work;
|
||||
};
|
||||
|
||||
} } } // namespace bond::ext::gRPC
|
|
@ -0,0 +1,221 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4100 4702)
|
||||
#endif
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
#include <grpc++/impl/codegen/async_unary_call.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
#include <grpc++/impl/codegen/server_context.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#include <bond/ext/grpc/detail/io_manager_tag.h>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <atomic>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// @brief Implementation class that holds the state associated with a
|
||||
/// single async, unary call.
|
||||
///
|
||||
/// It manages its own lifetime: to send a response, it enques itself in
|
||||
/// the completion queue. When that sending of the response is done and
|
||||
/// it is dequeued from the completion queue, it deletes itself.
|
||||
template <typename TRequest, typename TResponse>
|
||||
struct unary_call_impl final : detail::io_manager_tag
|
||||
{
|
||||
grpc::ServerContext _context;
|
||||
TRequest _request;
|
||||
grpc::ServerAsyncResponseWriter<bond::bonded<TResponse>> _responder;
|
||||
std::atomic_flag _responseSentFlag;
|
||||
|
||||
unary_call_impl()
|
||||
: _context(),
|
||||
_request(),
|
||||
_responder(&_context),
|
||||
_responseSentFlag()
|
||||
{ }
|
||||
|
||||
unary_call_impl(const unary_call_impl&) = delete;
|
||||
unary_call_impl& operator=(const unary_call_impl&) = delete;
|
||||
|
||||
void Finish(const bond::bonded<TResponse>& msg, const grpc::Status& status)
|
||||
{
|
||||
bool wasResponseSent = _responseSentFlag.test_and_set();
|
||||
if (!wasResponseSent)
|
||||
{
|
||||
_responder.Finish(msg, status, this);
|
||||
}
|
||||
}
|
||||
|
||||
void FinishWithError(const grpc::Status& status)
|
||||
{
|
||||
bool wasResponseSent = _responseSentFlag.test_and_set();
|
||||
if (!wasResponseSent)
|
||||
{
|
||||
_responder.FinishWithError(status, this);
|
||||
}
|
||||
}
|
||||
|
||||
void invoke(bool /* ok */) override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// @brief The details of a single async, unary call.
|
||||
///
|
||||
/// Call \p Finish or \p FinishWithError to send a response back to the
|
||||
/// client.
|
||||
///
|
||||
/// If no explicit call to Finish/FinishWithError has been made before this
|
||||
/// call is destroyed, a generic internal server error is sent.
|
||||
///
|
||||
/// \note This class can only be moved.
|
||||
template <typename TRequest, typename TResponse>
|
||||
class unary_call final
|
||||
{
|
||||
public:
|
||||
unary_call() noexcept : _impl(nullptr) {}
|
||||
|
||||
explicit unary_call(detail::unary_call_impl<TRequest, TResponse>* impl) noexcept
|
||||
: _impl(impl)
|
||||
{
|
||||
BOOST_ASSERT(impl);
|
||||
}
|
||||
|
||||
unary_call(unary_call&& other) noexcept
|
||||
: _impl(other._impl)
|
||||
{
|
||||
other._impl = nullptr;
|
||||
}
|
||||
|
||||
unary_call& operator=(unary_call&& rhs)
|
||||
{
|
||||
if (this != &rhs)
|
||||
{
|
||||
reset(rhs.impl);
|
||||
rhs._impl = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// unary_call is move-only
|
||||
unary_call(const unary_call&) = delete;
|
||||
unary_call& operator=(const unary_call&) = delete;
|
||||
|
||||
~unary_call()
|
||||
{
|
||||
reset(nullptr);
|
||||
}
|
||||
|
||||
void swap(unary_call& rhs) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(_impl, rhs._impl);
|
||||
}
|
||||
|
||||
/// @brief Get the server context for this call.
|
||||
const grpc::ServerContext& context() const
|
||||
{
|
||||
return _impl->_context;
|
||||
}
|
||||
|
||||
/// @brief Get the server context for this call.
|
||||
grpc::ServerContext& context()
|
||||
{
|
||||
return _impl->_context;
|
||||
}
|
||||
|
||||
/// @brief Get the request message for this call.
|
||||
const TRequest& request() const
|
||||
{
|
||||
return _impl->_request;
|
||||
}
|
||||
|
||||
/// @brief Get the request message for this call.
|
||||
TRequest& request()
|
||||
{
|
||||
return _impl->_request;
|
||||
}
|
||||
|
||||
/// @brief Responds to the client with the given message and status.
|
||||
///
|
||||
/// Only the first call to \p Finish or \p FinishWithError will be
|
||||
/// honored.
|
||||
void Finish(const TResponse& msg, const grpc::Status& status = grpc::Status::OK)
|
||||
{
|
||||
Finish(bond::bonded<TResponse>{msg}, status);
|
||||
}
|
||||
|
||||
/// @brief Responds to the client with the given message and status.
|
||||
///
|
||||
/// Only the first call to \p Finish or \p FinishWithError will be
|
||||
/// honored.
|
||||
void Finish(const bond::bonded<TResponse>& msg, const grpc::Status& status = grpc::Status::OK)
|
||||
{
|
||||
_impl->Finish(msg, status);
|
||||
}
|
||||
|
||||
/// @brief Responds to the client with the given status and no message.
|
||||
///
|
||||
/// Only the first call to \p Finish or \p FinishWithError will be
|
||||
/// honored.
|
||||
void FinishWithError(const grpc::Status& status)
|
||||
{
|
||||
_impl->FinishWithError(status);
|
||||
}
|
||||
|
||||
private:
|
||||
detail::unary_call_impl<TRequest, TResponse>* _impl;
|
||||
|
||||
/// Resets the underlying detail::unary_call_impl that this is wrapping.
|
||||
/// If the previous \p _impl was non-null, attempts to send an internal
|
||||
/// server error.
|
||||
///
|
||||
/// By always sending something back we get two benefits:
|
||||
/// - the client will get some sort of response instead of having to
|
||||
/// wait for a timeout
|
||||
/// - resources will be cleaned up after the response has been sent
|
||||
void reset(detail::unary_call_impl<TRequest, TResponse>* newValue)
|
||||
{
|
||||
auto oldValue = _impl;
|
||||
_impl = newValue;
|
||||
|
||||
if (oldValue != newValue)
|
||||
{
|
||||
if (oldValue)
|
||||
{
|
||||
// the current impl is being destroyed, so send an error
|
||||
// response. Relies on unary_call_impl to only send on
|
||||
// actual response.
|
||||
oldValue->FinishWithError(
|
||||
grpc::Status{
|
||||
grpc::StatusCode::INTERNAL,
|
||||
"An internal server error has occurred." });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TRequest, typename TResponse>
|
||||
void swap(unary_call<TRequest, TResponse>& lhs, unary_call<TRequest, TResponse>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} } } //namespace bond::ext::gRPC
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <bond/core/bonded.h>
|
||||
#include <bond/ext/grpc/exception.h>
|
||||
#include <grpc++/impl/codegen/status.h>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <tuple>
|
||||
|
||||
namespace bond { namespace ext { namespace gRPC {
|
||||
|
||||
/// @brief A callback type that can be manually waited upon.
|
||||
///
|
||||
/// The type can be used to synchronously get the result of invoking an
|
||||
/// async proxy method.
|
||||
///
|
||||
/// The wait() member function can be used to wait until the callback has
|
||||
/// been called. Then, the status() and response() member functions can be
|
||||
/// called to inspect the results.
|
||||
template <typename TResponse>
|
||||
class wait_callback final
|
||||
{
|
||||
public:
|
||||
wait_callback() : _impl(std::make_shared<impl>()) { }
|
||||
|
||||
/// @brief Records the response and status.
|
||||
///
|
||||
/// @exception MultipleInvocationException thrown if the callback (or a
|
||||
/// copy of the callback) is invoked more than once.
|
||||
void operator()(const bond::bonded<TResponse>& response, const grpc::Status& status)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_impl->_m);
|
||||
if (!_impl->_results)
|
||||
{
|
||||
_impl->_results.emplace(response, status);
|
||||
|
||||
// Drop the lock before notifying so we don't wake someone up to
|
||||
// then have them wait on the lock.
|
||||
lock.unlock();
|
||||
_impl->_cv.notify_all();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw MultipleInvocationException();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Waits for this to have been invoked.
|
||||
void wait() const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_impl->_m);
|
||||
_impl->_cv.wait(lock, [this]() { return static_cast<bool>(_impl->_results); });
|
||||
}
|
||||
|
||||
/// @brief Waits at least \p timeout for this to have been invoked.
|
||||
///
|
||||
/// @param timeout the minimum amount of time to wait.
|
||||
///
|
||||
/// @return \p true if a callback was invoked. \p false if the timeout
|
||||
/// occured.
|
||||
template <typename Rep, typename Period>
|
||||
bool wait_for(const std::chrono::duration<Rep, Period>& timeout) const
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_impl->_m);
|
||||
return _impl->_cv.wait_for(lock, timeout, [this]() { return static_cast<bool>(_impl->_results); });
|
||||
}
|
||||
|
||||
/// @brief Gets the response.
|
||||
///
|
||||
/// @warning Blocks until this has been invoked.
|
||||
const bond::bonded<TResponse>& response() const
|
||||
{
|
||||
wait();
|
||||
return std::get<0>(_impl->_results.get());
|
||||
}
|
||||
|
||||
/// @brief Gets the status.
|
||||
///
|
||||
/// @warning Blocks until this has been invoked.
|
||||
const grpc::Status& status() const
|
||||
{
|
||||
wait();
|
||||
return std::get<1>(_impl->_results.get());
|
||||
}
|
||||
|
||||
private:
|
||||
/// The interesting guts of wait_callback. We use an impl class so that
|
||||
/// wait_callback can be copied and all the copies affect the same underlying
|
||||
/// state.
|
||||
struct impl final
|
||||
{
|
||||
impl() = default;
|
||||
impl(const impl&) = delete;
|
||||
impl(impl&&) = delete;
|
||||
impl& operator=(const impl&) = delete;
|
||||
impl& operator=(impl&&) = delete;
|
||||
|
||||
/// mutex to lock the shared state
|
||||
std::mutex _m;
|
||||
/// condition variable used to signal anyone waiting
|
||||
std::condition_variable _cv;
|
||||
/// The response and status, but more importantly, doubles as a flag
|
||||
/// indicating whether a callback has been invoked yet. If this is
|
||||
/// empty, no callback has been invoked yet. If non-empty, a
|
||||
/// callback has already been invoked.
|
||||
boost::optional<std::tuple<bond::bonded<TResponse>, grpc::Status>> _results;
|
||||
};
|
||||
|
||||
/// shared_ptr to the actual state.
|
||||
std::shared_ptr<impl> _impl;
|
||||
};
|
||||
|
||||
/// @example wait_callback_example.cpp
|
||||
///
|
||||
/// This is a brief example showing how wait_callback can be used to
|
||||
/// synchronously get the result of invoking an async proxy method.
|
||||
|
||||
} } } // bond::extgrpc
|
|
@ -12,9 +12,13 @@ if (Boost_UNIT_TEST_FRAMEWORK_FOUND)
|
|||
if (NOT BOND_SKIP_CORE_TESTS)
|
||||
add_subfolder (core "tests/unit_test/core")
|
||||
endif()
|
||||
if (NOT BOND_CORE_ONLY)
|
||||
if (BOND_ENABLE_COMM)
|
||||
add_subfolder (comm "tests/unit_test/comm")
|
||||
add_subfolder (comm/epoxy "tests/unit_test/comm/epoxy")
|
||||
add_subfolder (compat/comm "tests/compat/comm")
|
||||
endif()
|
||||
if (BOND_ENABLE_GRPC)
|
||||
add_subfolder (compat/grpc "tests/compat/grpc")
|
||||
add_subfolder (grpc "tests/unit_test/grpc")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
cxx_add_compile_options(Clang -Wno-unused-value)
|
||||
|
||||
add_bond_executable (comm_compatibility_test COMM EXCLUDE_FROM_ALL
|
||||
add_bond_executable (comm_compatibility_test EXCLUDE_FROM_ALL
|
||||
commcmd_arg.bond
|
||||
commcompat.cpp)
|
||||
|
||||
|
@ -26,8 +26,6 @@ target_compile_definitions (comm_compatibility_test PRIVATE
|
|||
-DBOND_COMPACT_BINARY_PROTOCOL
|
||||
-DBOND_FAST_BINARY_PROTOCOL)
|
||||
|
||||
target_link_libraries (cpp_comm_compat_server PRIVATE
|
||||
${Boost_CHRONO_LIBRARY})
|
||||
target_link_libraries (cpp_comm_compat_client PRIVATE
|
||||
${Boost_CHRONO_LIBRARY})
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ int main(int argc, char** argv)
|
|||
bool server_ok = false;
|
||||
bool client_ok = false;
|
||||
|
||||
char server_buffer[128];
|
||||
char server_buffer[128];
|
||||
|
||||
if (fgets(server_buffer, 128, server_process))
|
||||
{
|
||||
|
@ -99,7 +99,7 @@ int main(int argc, char** argv)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
char client_buffer[128];
|
||||
char client_buffer[128];
|
||||
|
||||
while (fgets(client_buffer, 128, client_process))
|
||||
{
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
|
||||
using namespace PingPongNS;
|
||||
|
||||
const int NumRequests = 10;
|
||||
const int NumEvents = 9;
|
||||
const int NumErrors = 8;
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
|
@ -36,7 +32,7 @@ int main()
|
|||
TestLayer<2>
|
||||
> layers(layer1, layer2);
|
||||
|
||||
bond::comm::SocketAddress loopback("127.0.0.1", 25188);
|
||||
bond::comm::SocketAddress loopback("127.0.0.1", Port);
|
||||
bond::comm::epoxy::EpoxyTransport transport(layers);
|
||||
|
||||
printf("Start client\n");
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <future>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <bond/ext/detail/countdown_event.h>
|
||||
|
||||
// Include preferred transport
|
||||
#include <bond/comm/transport/epoxy.h>
|
||||
|
@ -16,17 +16,17 @@
|
|||
#include "testlayer.h"
|
||||
|
||||
using namespace PingPongNS;
|
||||
using namespace bond::ext::detail;
|
||||
|
||||
const int NumRequestsExpected = 10;
|
||||
const int NumEventsExpected = 9;
|
||||
const int NumErrorsExpected = 8;
|
||||
static int NumRequests = 0;
|
||||
static int NumEvents = 0;
|
||||
static int NumErrors = 0;
|
||||
static countdown_event Countdown(NumRequests + NumEvents + NumErrors);
|
||||
static std::atomic<uint32_t> NumRequestsReceived(0);
|
||||
static std::atomic<uint32_t> NumEventsReceived(0);
|
||||
static std::atomic<uint32_t> NumErrorsReceived(0);
|
||||
|
||||
// Implement service
|
||||
struct PingPongImpl : PingPong
|
||||
{
|
||||
public:
|
||||
void Ping(const bond::comm::payload<PingRequest>& request_payload,
|
||||
const std::function<void(const bond::comm::message<PingResponse>&)>& callback) override
|
||||
{
|
||||
|
@ -34,36 +34,40 @@ struct PingPongImpl : PingPong
|
|||
|
||||
switch (request.Action)
|
||||
{
|
||||
case PingAction::Identity:
|
||||
{
|
||||
printf("Received request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
case PingAction::Identity:
|
||||
{
|
||||
printf("Received request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
|
||||
PingResponse response;
|
||||
response.Payload = request.Payload;
|
||||
NumRequests++;
|
||||
callback(std::move(response));
|
||||
break;
|
||||
}
|
||||
PingResponse response;
|
||||
response.Payload = request.Payload;
|
||||
NumRequestsReceived++;
|
||||
Countdown.set();
|
||||
callback(std::move(response));
|
||||
break;
|
||||
}
|
||||
|
||||
case PingAction::Error:
|
||||
{
|
||||
printf("Received error request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
case PingAction::Error:
|
||||
{
|
||||
printf("Received error request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
|
||||
bond::comm::Error err;
|
||||
err.error_code = 1234;
|
||||
err.message = request.Payload;
|
||||
NumErrors++;
|
||||
callback(bond::comm::error(err));
|
||||
break;
|
||||
}
|
||||
bond::comm::Error err;
|
||||
err.error_code = 1234;
|
||||
err.message = request.Payload;
|
||||
NumErrorsReceived++;
|
||||
Countdown.set();
|
||||
callback(bond::comm::error(err));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printf("Received unknown request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
|
||||
throw new std::invalid_argument("Unknown PingAction");
|
||||
default:
|
||||
{
|
||||
printf("Received unknown request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
Countdown.set();
|
||||
throw new std::invalid_argument("Unknown PingAction");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +76,8 @@ struct PingPongImpl : PingPong
|
|||
printf("Received request \"%s\"\n", theEvent.value().Deserialize().Payload.c_str());
|
||||
fflush(stdout);
|
||||
|
||||
NumEvents++;
|
||||
NumEventsReceived++;
|
||||
Countdown.set();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -88,7 +93,7 @@ int main()
|
|||
TestLayer<2>
|
||||
> layers(layer1, layer2);
|
||||
|
||||
bond::comm::SocketAddress loopback("127.0.0.1", 25188);
|
||||
bond::comm::SocketAddress loopback("127.0.0.1", Port);
|
||||
bond::comm::epoxy::EpoxyTransport transport(layers);
|
||||
|
||||
auto server = transport.Bind(loopback, boost::make_shared<PingPongImpl>());
|
||||
|
@ -96,11 +101,12 @@ int main()
|
|||
printf("Server ready\n");
|
||||
fflush(stdout);
|
||||
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(3));
|
||||
bool countdownSet = Countdown.wait_for(std::chrono::seconds(30));
|
||||
|
||||
if ((NumRequests != NumRequestsExpected) ||
|
||||
(NumEvents != NumEventsExpected) ||
|
||||
(NumErrors != NumErrorsExpected))
|
||||
if (!countdownSet ||
|
||||
(NumRequestsReceived != NumRequests) ||
|
||||
(NumEventsReceived != NumEvents) ||
|
||||
(NumErrorsReceived != NumErrors))
|
||||
{
|
||||
printf("Server failed: Did not receive all expected messages\n");
|
||||
fflush(stdout);
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
cxx_add_compile_options(Clang -Wno-unused-value)
|
||||
|
||||
add_bond_executable (grpc_compatibility_test EXCLUDE_FROM_ALL
|
||||
grpccmd_arg.bond
|
||||
grpccompat.cpp)
|
||||
|
||||
add_bond_executable (cpp_grpc_compat_server GRPC EXCLUDE_FROM_ALL
|
||||
${BOND_COMPAT_TEST_DIR}/grpc/pingpong.bond
|
||||
pingpong_server.cpp)
|
||||
|
||||
add_bond_executable (cpp_grpc_compat_client GRPC EXCLUDE_FROM_ALL
|
||||
${BOND_COMPAT_TEST_DIR}/grpc/pingpong.bond
|
||||
pingpong_client.cpp)
|
||||
|
||||
add_dependencies (grpc_compatibility_test cpp_grpc_compat_server)
|
||||
add_dependencies (grpc_compatibility_test cpp_grpc_compat_client)
|
||||
add_dependencies (check grpc_compatibility_test)
|
||||
|
||||
target_compile_definitions (cpp_grpc_compat_server PRIVATE
|
||||
-DBOND_COMPACT_BINARY_PROTOCOL
|
||||
-DBOND_FAST_BINARY_PROTOCOL)
|
||||
|
||||
cxx_target_compile_definitions (MSVC cpp_grpc_compat_server PRIVATE
|
||||
-D_WIN32_WINNT=0x0600)
|
||||
|
||||
target_compile_definitions (cpp_grpc_compat_client PRIVATE
|
||||
-DBOND_COMPACT_BINARY_PROTOCOL
|
||||
-DBOND_FAST_BINARY_PROTOCOL)
|
||||
|
||||
cxx_target_compile_definitions (MSVC cpp_grpc_compat_client PRIVATE
|
||||
-D_WIN32_WINNT=0x0600)
|
||||
|
||||
target_compile_definitions (grpc_compatibility_test PRIVATE
|
||||
-DBOND_COMPACT_BINARY_PROTOCOL
|
||||
-DBOND_FAST_BINARY_PROTOCOL)
|
||||
|
||||
target_link_libraries (cpp_grpc_compat_server PRIVATE
|
||||
grpc++)
|
||||
target_link_libraries (cpp_grpc_compat_client PRIVATE
|
||||
grpc++
|
||||
${Boost_CHRONO_LIBRARY})
|
||||
|
||||
# TODO: It feels like the grpc++ target should have this as part of its
|
||||
# interface... Perhaps a patch for upstream?
|
||||
target_include_directories(cpp_grpc_compat_server
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/grpc/include
|
||||
)
|
||||
target_include_directories(cpp_grpc_compat_client
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/grpc/include
|
||||
)
|
||||
|
||||
# disable generation of debug symbols to speed up build
|
||||
no_pdb()
|
||||
|
||||
add_test (
|
||||
NAME grpc_compatibility_cpp_cpp
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND grpc_compatibility_test
|
||||
-s $<TARGET_FILE:cpp_grpc_compat_server>
|
||||
-c $<TARGET_FILE:cpp_grpc_compat_client>)
|
||||
|
||||
if (BOND_CSHARP_GRPC_COMPAT_SERVER)
|
||||
if (BOND_CSHARP_GRPC_COMPAT_CLIENT)
|
||||
add_test (
|
||||
NAME grpc_compatibility_cs_cs
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND grpc_compatibility_test
|
||||
-s ${BOND_CSHARP_GRPC_COMPAT_SERVER}
|
||||
-c ${BOND_CSHARP_GRPC_COMPAT_CLIENT})
|
||||
endif()
|
||||
|
||||
add_test (
|
||||
NAME grpc_compatibility_cs_cpp
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND grpc_compatibility_test
|
||||
-s ${BOND_CSHARP_GRPC_COMPAT_SERVER}
|
||||
-c $<TARGET_FILE:cpp_grpc_compat_client>)
|
||||
endif()
|
||||
|
||||
if (BOND_CSHARP_GRPC_COMPAT_CLIENT)
|
||||
add_test (
|
||||
NAME grpc_compatibility_cpp_cs
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND grpc_compatibility_test
|
||||
-s $<TARGET_FILE:cpp_grpc_compat_server>
|
||||
-c ${BOND_CSHARP_GRPC_COMPAT_CLIENT})
|
||||
endif()
|
|
@ -0,0 +1,17 @@
|
|||
namespace unittest.compat
|
||||
|
||||
[help("-s SERVER_EXE -c CLIENT_EXE [options]")]
|
||||
struct Options
|
||||
{
|
||||
[help("show this help text")]
|
||||
[abbr("?")]
|
||||
0: bool help;
|
||||
|
||||
[help("server exe to invoke")]
|
||||
[abbr("s")]
|
||||
10: string server_exe;
|
||||
|
||||
[help("client exe to invoke")]
|
||||
[abbr("c")]
|
||||
20: string client_exe;
|
||||
};
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <bond/core/bond.h>
|
||||
#include <bond/core/cmdargs.h>
|
||||
#include <bond/stream/stdio_output_stream.h>
|
||||
|
||||
#include "grpccmd_arg_types.h"
|
||||
#include "grpccmd_arg_reflection.h"
|
||||
|
||||
#define die(ARGS) printf(ARGS); exit(1);
|
||||
|
||||
using namespace unittest::compat;
|
||||
|
||||
FILE* popen_wrapper(const char* command, const char* mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _popen(command, mode);
|
||||
#else
|
||||
return popen(command, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
int pclose_wrapper(FILE* stream)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _pclose(stream);
|
||||
#else
|
||||
return pclose(stream);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Options options;
|
||||
|
||||
try
|
||||
{
|
||||
options = bond::cmd::GetArgs<Options>(argc, argv);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
printf("\n%s\n", e.what());
|
||||
options.help = true;
|
||||
}
|
||||
|
||||
if (options.help)
|
||||
{
|
||||
bond::cmd::ShowUsage<Options>(argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
else if (options.server_exe.empty())
|
||||
{
|
||||
die("Server exe must be provided");
|
||||
}
|
||||
else if (options.client_exe.empty())
|
||||
{
|
||||
die("Client exe must be provided");
|
||||
}
|
||||
|
||||
FILE *server_process;
|
||||
|
||||
printf("Spawning server\n");
|
||||
|
||||
if ((server_process = popen_wrapper(options.server_exe.c_str(), "r")) == NULL)
|
||||
{
|
||||
printf("popen of server process failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool server_ok = false;
|
||||
bool client_ok = false;
|
||||
|
||||
char server_buffer[128];
|
||||
|
||||
if (fgets(server_buffer, 128, server_process))
|
||||
{
|
||||
printf("Server status: %s\n", server_buffer);
|
||||
if (strcmp("Server ready\n", server_buffer) != 0)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
printf("Moving to client\n");
|
||||
|
||||
FILE *client_process;
|
||||
|
||||
if ((client_process = popen_wrapper(options.client_exe.c_str(), "r")) == NULL)
|
||||
{
|
||||
printf("popen of client process failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char client_buffer[128];
|
||||
|
||||
while (fgets(client_buffer, 128, client_process))
|
||||
{
|
||||
printf("Client status: %s\n", client_buffer);
|
||||
if (strcmp("Client succeeded\n", client_buffer) == 0)
|
||||
{
|
||||
client_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
while (fgets(server_buffer, 128, server_process))
|
||||
{
|
||||
printf("Server status: %s\n", server_buffer);
|
||||
if (strcmp("Server completed\n", server_buffer) == 0)
|
||||
{
|
||||
server_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
pclose_wrapper(server_process);
|
||||
pclose_wrapper(client_process);
|
||||
|
||||
if (!server_ok || !client_ok)
|
||||
{
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// Include auto-generated files
|
||||
#include "pingpong_grpc.h"
|
||||
#include "pingpong_reflection.h"
|
||||
#include "pingpong_types.h"
|
||||
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/grpc/wait_callback.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
using grpc::Channel;
|
||||
using grpc::ClientContext;
|
||||
using grpc::Status;
|
||||
|
||||
using namespace PingPongNS;
|
||||
|
||||
int main()
|
||||
{
|
||||
auto ioManager = std::make_shared<bond::ext::gRPC::io_manager>();
|
||||
auto threadPool = std::make_shared<bond::ext::gRPC::thread_pool>();
|
||||
|
||||
const std::string server_address("127.0.0.1:" + std::to_string(Port));
|
||||
std::shared_ptr<Channel> channel = grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials());
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
|
||||
PingPong::Client client(channel, ioManager, threadPool);
|
||||
|
||||
printf("Start client\n");
|
||||
fflush(stdout);
|
||||
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < NumRequests; i++)
|
||||
{
|
||||
ClientContext context;
|
||||
PingRequest request;
|
||||
|
||||
request.Payload = "request" + std::to_string(i);
|
||||
request.Action = PingAction::Identity;
|
||||
|
||||
printf("Sending\n");
|
||||
fflush(stdout);
|
||||
|
||||
bond::ext::gRPC::wait_callback<PingResponse> cb;
|
||||
client.AsyncPing(&context, bond::bonded<PingRequest>{ request }, cb);
|
||||
bool gotResponse = cb.wait_for(std::chrono::seconds(1));
|
||||
|
||||
if (!gotResponse)
|
||||
{
|
||||
printf("Client timed out waiting for response\n");
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Status status = cb.status();
|
||||
|
||||
if (!status.ok())
|
||||
{
|
||||
printf("Error response received: %d\n", status.error_code());
|
||||
printf("Client failed\n");
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (cb.response().Deserialize().Payload != request.Payload)
|
||||
{
|
||||
printf("Response payload did not match request\n");
|
||||
printf("Client failed\n");
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumErrors; i++)
|
||||
{
|
||||
ClientContext context;
|
||||
PingRequest request;
|
||||
|
||||
request.Payload = "error" + std::to_string(i);
|
||||
request.Action = PingAction::Error;
|
||||
|
||||
bond::ext::gRPC::wait_callback<PingResponse> cb;
|
||||
client.AsyncPing(&context, bond::bonded<PingRequest> { request }, cb);
|
||||
bool gotResponse = cb.wait_for(std::chrono::seconds(1));
|
||||
|
||||
if (!gotResponse)
|
||||
{
|
||||
printf("Client timed out waiting for response\n");
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Status status = cb.status();
|
||||
|
||||
if (status.ok())
|
||||
{
|
||||
printf("Non-error response received: %s\n", cb.response().Deserialize().Payload.c_str());
|
||||
printf("Client failed\n");
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
printf("Caught exception: %s\n", e.what());
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
printf("Caught something\n");
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Client succeeded\n");
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// Include auto-generated files
|
||||
#include "pingpong_grpc.h"
|
||||
#include "pingpong_reflection.h"
|
||||
#include "pingpong_types.h"
|
||||
|
||||
#include <bond/ext/detail/countdown_event.h>
|
||||
#include <bond/ext/grpc/server.h>
|
||||
#include <bond/ext/grpc/server_builder.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
using grpc::Status;
|
||||
using grpc::StatusCode;
|
||||
|
||||
using grpc::Server;
|
||||
using grpc::ServerBuilder;
|
||||
using grpc::ServerContext;
|
||||
|
||||
using namespace PingPongNS;
|
||||
using namespace bond::ext::detail;
|
||||
|
||||
static countdown_event Countdown(NumRequests + NumErrors);
|
||||
static std::atomic<uint32_t> NumRequestsReceived(0);
|
||||
static std::atomic<uint32_t> NumErrorsReceived(0);
|
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class PingPongServiceImpl final : public PingPong::Service
|
||||
{
|
||||
public:
|
||||
|
||||
void Ping(
|
||||
bond::ext::gRPC::unary_call<
|
||||
bond::bonded<PingRequest>,
|
||||
PingResponse> call) override
|
||||
{
|
||||
PingRequest request = call.request().Deserialize();
|
||||
|
||||
switch (request.Action)
|
||||
{
|
||||
case PingAction::Identity:
|
||||
{
|
||||
printf("Received identity request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
|
||||
PingResponse response;
|
||||
response.Payload = request.Payload;
|
||||
|
||||
NumRequestsReceived++;
|
||||
|
||||
call.Finish(response);
|
||||
Countdown.set();
|
||||
break;
|
||||
}
|
||||
|
||||
case PingAction::Error:
|
||||
{
|
||||
printf("Received error request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
|
||||
NumErrorsReceived++;
|
||||
|
||||
Status error(StatusCode::UNIMPLEMENTED, "Application Exception");
|
||||
call.FinishWithError(error);
|
||||
Countdown.set();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
printf("Received unknown request \"%s\"\n", request.Payload.c_str());
|
||||
fflush(stdout);
|
||||
|
||||
Status error(StatusCode::UNIMPLEMENTED, "Unknown PingAction");
|
||||
call.FinishWithError(error);
|
||||
Countdown.set();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
PingPongServiceImpl service;
|
||||
auto threadPool = std::make_shared<bond::ext::gRPC::thread_pool>();
|
||||
|
||||
bond::ext::gRPC::server_builder builder;
|
||||
builder.SetThreadPool(threadPool);
|
||||
const std::string server_address("127.0.0.1:" + std::to_string(Port));
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
||||
builder.RegisterService(&service);
|
||||
std::unique_ptr<bond::ext::gRPC::server> server(builder.BuildAndStart());
|
||||
|
||||
printf("Server ready\n");
|
||||
fflush(stdout);
|
||||
|
||||
bool countdownSet = Countdown.wait_for(std::chrono::seconds(30));
|
||||
|
||||
server->Shutdown(std::chrono::system_clock::now() + std::chrono::seconds(10));
|
||||
server->Wait();
|
||||
|
||||
if (!countdownSet ||
|
||||
(NumRequestsReceived != NumRequests) ||
|
||||
(NumErrorsReceived != NumErrors))
|
||||
{
|
||||
printf("Server failed: Did not receive all expected messages\n");
|
||||
fflush(stdout);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Server completed\n");
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
# To add a new unit test suite, call add_unit_test at the bottom of this file on
|
||||
# all of the files you want built into your test suite. The name of the suite
|
||||
# will be derived from the name of the file that is given first.
|
||||
function (add_unit_test)
|
||||
get_filename_component(name ${ARGV0} NAME_WE)
|
||||
set (files ${ARGV})
|
||||
add_bond_test (${name} EXCLUDE_FROM_ALL ${files} COMM)
|
||||
add_target_to_folder (${name})
|
||||
add_dependencies (${name}
|
||||
bond)
|
||||
target_include_directories (${name} PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR})
|
||||
target_compile_definitions (${name} PUBLIC
|
||||
-DBOND_COMPACT_BINARY_PROTOCOL
|
||||
-DBOND_SIMPLE_BINARY_PROTOCOL
|
||||
-DBOND_FAST_BINARY_PROTOCOL)
|
||||
target_link_libraries (${name} PRIVATE
|
||||
bond
|
||||
grpc_test_common
|
||||
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
|
||||
${Boost_CHRONO_LIBRARY})
|
||||
|
||||
cxx_target_compile_options (MSVC ${name} PRIVATE -D_WIN32_WINNT=0x0600)
|
||||
|
||||
cxx_target_compile_options (Clang ${name} PRIVATE -DBOOST_ASIO_HAS_STD_CHRONO)
|
||||
cxx_target_compile_options (AppleClang ${name} PRIVATE -DBOOST_ASIO_HAS_STD_CHRONO)
|
||||
endfunction()
|
||||
|
||||
|
||||
# Build common code into its own library.
|
||||
add_library (grpc_test_common EXCLUDE_FROM_ALL "main.cpp")
|
||||
add_target_to_folder (grpc_test_common)
|
||||
target_include_directories (grpc_test_common PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
|
||||
# TODO: It feels like the grpc++ target should have this as part of its
|
||||
# interface... Perhaps a patch for upstream?
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../../thirdparty/grpc/include)
|
||||
target_link_libraries (grpc_test_common PUBLIC
|
||||
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
|
||||
grpc++)
|
||||
|
||||
add_unit_test (io_manager.cpp)
|
||||
add_unit_test (thread_pool.cpp)
|
||||
add_unit_test (wait_callback.cpp)
|
||||
target_link_libraries(wait_callback PRIVATE bond_apply)
|
|
@ -0,0 +1,184 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4100) // disable "unreferenced formal parameter" warning
|
||||
#pragma warning(disable : 4505) // disable "unreferenced local function has been removed" warning
|
||||
#endif
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
#include <grpc++/alarm.h>
|
||||
#include <grpc++/impl/codegen/completion_queue.h>
|
||||
#include <grpc++/impl/grpc_library.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <grpc/support/time.h>
|
||||
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/detail/io_manager_tag.h>
|
||||
#include <bond/ext/detail/countdown_event.h>
|
||||
#include <bond/ext/detail/barrier.h>
|
||||
#include <bond/ext/detail/event.h>
|
||||
|
||||
// TODO: move unit_test_framework.h to cpp/test/inc
|
||||
#include "../core/unit_test_framework.h"
|
||||
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/test/debug.hpp>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
using namespace bond::ext::detail;
|
||||
using namespace bond::ext::gRPC::detail;
|
||||
using namespace bond::ext::gRPC;
|
||||
|
||||
template <typename TEvent>
|
||||
struct alarm_completion_tag : io_manager_tag
|
||||
{
|
||||
TEvent completion_event;
|
||||
|
||||
template <typename... TArg>
|
||||
explicit alarm_completion_tag(TArg&&... args)
|
||||
: completion_event(std::forward<TArg>(args)...)
|
||||
{ }
|
||||
|
||||
void invoke(bool) override
|
||||
{
|
||||
completion_event.set();
|
||||
}
|
||||
};
|
||||
|
||||
class io_managerTests
|
||||
{
|
||||
static void PollOneItem()
|
||||
{
|
||||
io_manager ioManager;
|
||||
|
||||
alarm_completion_tag<event> act;
|
||||
gpr_timespec deadline = gpr_time_0(GPR_CLOCK_MONOTONIC);
|
||||
grpc::Alarm alarm(ioManager.cq(), deadline, &act);
|
||||
|
||||
bool wasSet = act.completion_event.wait_for(std::chrono::seconds(30));
|
||||
UT_AssertIsTrue(wasSet);
|
||||
}
|
||||
|
||||
static void PollManyItems()
|
||||
{
|
||||
io_manager ioManager;
|
||||
|
||||
const size_t numItems = 1000;
|
||||
|
||||
alarm_completion_tag<countdown_event> act(numItems);
|
||||
|
||||
const gpr_timespec deadline = gpr_time_0(GPR_CLOCK_MONOTONIC);
|
||||
|
||||
std::vector<grpc::Alarm> alarms;
|
||||
alarms.reserve(numItems);
|
||||
for (size_t i = 0; i < numItems; ++i)
|
||||
{
|
||||
alarms.emplace_back(ioManager.cq(), deadline, &act);
|
||||
}
|
||||
|
||||
bool wasSet = act.completion_event.wait_for(std::chrono::seconds(30));
|
||||
UT_AssertIsTrue(wasSet);
|
||||
}
|
||||
|
||||
static void ShutdownUnstarted()
|
||||
{
|
||||
io_manager ioManager(
|
||||
io_manager::USE_HARDWARE_CONC,
|
||||
io_manager::delay_start_tag{});
|
||||
ioManager.shutdown();
|
||||
ioManager.wait();
|
||||
|
||||
// also tests that we can run the dtor after successful shutdown
|
||||
}
|
||||
|
||||
static void ConcurrentShutdown()
|
||||
{
|
||||
io_manager ioManager(
|
||||
// also tests that we can pass an explicit completion queue
|
||||
std::unique_ptr<grpc::CompletionQueue>(new grpc::CompletionQueue));
|
||||
|
||||
const size_t numConcurrentShutdowns = 5;
|
||||
barrier threadsStarted(numConcurrentShutdowns);
|
||||
barrier threadsObservedShutdown(numConcurrentShutdowns);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
threads.reserve(5);
|
||||
for (size_t i = 0; i < numConcurrentShutdowns; ++i)
|
||||
{
|
||||
threads.emplace_back([&ioManager, &threadsStarted, &threadsObservedShutdown]()
|
||||
{
|
||||
threadsStarted.enter();
|
||||
|
||||
ioManager.shutdown();
|
||||
ioManager.wait();
|
||||
|
||||
threadsObservedShutdown.enter();
|
||||
});
|
||||
}
|
||||
|
||||
bool wasSet = threadsStarted.wait_for(std::chrono::seconds(30));
|
||||
UT_AssertIsTrue(wasSet); // all the threads took too long to get started
|
||||
|
||||
wasSet = threadsObservedShutdown.wait_for(std::chrono::seconds(30));
|
||||
UT_AssertIsTrue(wasSet); // took too long to see the io_manager shutdown
|
||||
|
||||
for (auto& thread : threads)
|
||||
{
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
static void DelayStartDoesntStart()
|
||||
{
|
||||
io_manager ioManager(
|
||||
// also tests that we can pass an explicit completion queue
|
||||
std::unique_ptr<grpc::CompletionQueue>(new grpc::CompletionQueue),
|
||||
io_manager::USE_HARDWARE_CONC,
|
||||
io_manager::delay_start_tag{});
|
||||
|
||||
alarm_completion_tag<event> act;
|
||||
gpr_timespec deadline = gpr_time_0(GPR_CLOCK_MONOTONIC);
|
||||
grpc::Alarm alarm(ioManager.cq(), deadline, &act);
|
||||
|
||||
bool wasSet = act.completion_event.wait_for(std::chrono::milliseconds(1250));
|
||||
UT_AssertIsTrue(!wasSet);
|
||||
|
||||
// since we've put something into the completion queue, we need to
|
||||
// start it so that it can be drained and shutdown.
|
||||
ioManager.start();
|
||||
|
||||
// test that we can call start multiple times
|
||||
ioManager.start();
|
||||
|
||||
wasSet = act.completion_event.wait_for(std::chrono::seconds(30));
|
||||
UT_AssertIsTrue(wasSet);
|
||||
}
|
||||
|
||||
public:
|
||||
static void Initialize()
|
||||
{
|
||||
UnitTestSuite suite("io_manager");
|
||||
suite.AddTestCase(PollOneItem, "Poll one item");
|
||||
suite.AddTestCase(PollManyItems, "Poll many items");
|
||||
suite.AddTestCase(ShutdownUnstarted, "Shutdown unstarted");
|
||||
suite.AddTestCase(ConcurrentShutdown, "Concurrent shutdown");
|
||||
suite.AddTestCase(DelayStartDoesntStart, "Delay Start doesn't start");
|
||||
}
|
||||
};
|
||||
|
||||
bool init_unit_test()
|
||||
{
|
||||
// grpc allocates a bunch of stuff on-demand caused the leak tracker to
|
||||
// report leaks. Disable it for this test.
|
||||
boost::debug::detect_memory_leaks(false);
|
||||
|
||||
// Initialize the gRPC++ library
|
||||
grpc::internal::GrpcLibraryInitializer initializer;
|
||||
initializer.summon();
|
||||
|
||||
io_managerTests::Initialize();
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#define BOOST_TEST_NO_MAIN
|
||||
#define BOOST_TEST_ALTERNATIVE_INIT_API
|
||||
/*
|
||||
* We need to include different boost unit test headers on Windows and *nix.
|
||||
*
|
||||
* Using boost/test/unit_test.hpp on Windows causes linker errors.
|
||||
*
|
||||
* Using boost/test/included/unit_test.hpp on *nix causes segfaults during
|
||||
* teardown in some suites.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4702) // C4702: unreachable code
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#else
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "../core/unit_test_framework.h"
|
||||
#include "../logging.h"
|
||||
|
||||
extern bool init_unit_test();
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
return ::boost::unit_test::unit_test_main(&init_unit_test, argc, argv);
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4505) // disable "unreferenced local function has been removed" warning
|
||||
#endif
|
||||
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/detail/event.h>
|
||||
|
||||
// TODO: move unit_test_framework.h to cpp/test/inc
|
||||
#include "../core/unit_test_framework.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
using namespace bond::ext::detail;
|
||||
|
||||
class BasicThreadPoolTests
|
||||
{
|
||||
static void addOne(int* i, event* sum_event)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
(*i)++;
|
||||
sum_event->set();
|
||||
}
|
||||
|
||||
static void UseStdFunction()
|
||||
{
|
||||
bond::ext::gRPC::thread_pool threads(1);
|
||||
int sum = 0;
|
||||
event sum_event;
|
||||
|
||||
std::function<void(int*, event*)> f_addOne = addOne;
|
||||
|
||||
threads.schedule(std::bind(f_addOne, &sum, &sum_event));
|
||||
|
||||
bool waitResult = sum_event.wait_for(std::chrono::seconds(30));
|
||||
|
||||
UT_AssertIsTrue(waitResult);
|
||||
UT_AssertIsTrue(sum == 1);
|
||||
}
|
||||
|
||||
static void UseLambda()
|
||||
{
|
||||
bond::ext::gRPC::thread_pool threads(1);
|
||||
int sum = 0;
|
||||
event sum_event;
|
||||
|
||||
threads.schedule([&sum, &sum_event]()
|
||||
{
|
||||
++sum;
|
||||
sum_event.set();
|
||||
});
|
||||
|
||||
bool waitResult = sum_event.wait_for(std::chrono::seconds(30));
|
||||
|
||||
UT_AssertIsTrue(waitResult);
|
||||
UT_AssertIsTrue(sum == 1);
|
||||
}
|
||||
|
||||
static void FinishAllTasksAfterDelete()
|
||||
{
|
||||
std::unique_ptr<bond::ext::gRPC::thread_pool> threads(new bond::ext::gRPC::thread_pool(2));
|
||||
std::atomic<int> sum(0);
|
||||
|
||||
auto increment = [&sum](){
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
sum++;
|
||||
};
|
||||
|
||||
threads->schedule(increment);
|
||||
threads->schedule(increment);
|
||||
threads->schedule(increment);
|
||||
threads->schedule(increment);
|
||||
|
||||
// blocks until all schedule tasks are finished
|
||||
threads.reset();
|
||||
|
||||
UT_AssertIsTrue(sum == 4);
|
||||
}
|
||||
|
||||
public:
|
||||
static void Initialize()
|
||||
{
|
||||
UnitTestSuite suite("ThreadPool");
|
||||
|
||||
suite.AddTestCase(UseStdFunction, "UseStdFunction");
|
||||
suite.AddTestCase(UseLambda, "UseLambda");
|
||||
suite.AddTestCase(FinishAllTasksAfterDelete, "FinishAllTasksAfterDelete");
|
||||
}
|
||||
};
|
||||
|
||||
bool init_unit_test()
|
||||
{
|
||||
BasicThreadPoolTests::Initialize();
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
// TODO: move unit_test_framework.h to cpp/test/inc
|
||||
#include "../core/unit_test_framework.h"
|
||||
|
||||
#include <bond/core/bond.h>
|
||||
#include <bond/core/bond_reflection.h>
|
||||
#include <bond/ext/detail/event.h>
|
||||
#include <bond/ext/grpc/wait_callback.h>
|
||||
#include <bond/protocol/compact_binary.h>
|
||||
#include <bond/stream/output_buffer.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
namespace wait_callback_tests
|
||||
{
|
||||
using wait_callbackBox = bond::ext::gRPC::wait_callback<bond::Box<int>>;
|
||||
|
||||
static const int ANY_INT_VALUE = 100;
|
||||
static bond::bonded<bond::Box<int>> anyBondedValue;
|
||||
static grpc::Status anyStatus;
|
||||
|
||||
static bond::bonded<bond::Box<int>> MakeAnyBonded()
|
||||
{
|
||||
bond::Box<int> boxedInt;
|
||||
boxedInt.value = ANY_INT_VALUE;
|
||||
|
||||
bond::OutputBuffer ob;
|
||||
bond::CompactBinaryWriter<bond::OutputBuffer> writer(ob);
|
||||
bond::Serialize(boxedInt, writer);
|
||||
|
||||
bond::blob buffer = ob.GetBuffer();
|
||||
|
||||
bond::InputBuffer ib(buffer);
|
||||
bond::CompactBinaryReader<bond::InputBuffer> reader(ib);
|
||||
|
||||
return bond::bonded<bond::Box<int>>(reader);
|
||||
}
|
||||
|
||||
static void CallbackCapturesValues()
|
||||
{
|
||||
wait_callbackBox cb;
|
||||
cb(anyBondedValue, anyStatus);
|
||||
|
||||
UT_AssertIsTrue(cb.response().Deserialize().value == ANY_INT_VALUE);
|
||||
UT_AssertIsTrue(cb.status().ok());
|
||||
}
|
||||
|
||||
static void SubsequentInvocationThrow()
|
||||
{
|
||||
wait_callbackBox cb;
|
||||
cb(anyBondedValue, anyStatus);
|
||||
|
||||
UT_AssertThrows(cb(anyBondedValue, grpc::Status::CANCELLED), bond::ext::gRPC::MultipleInvocationException);
|
||||
|
||||
UT_AssertIsTrue(cb.response().Deserialize().value == ANY_INT_VALUE);
|
||||
UT_AssertIsTrue(cb.status().ok());
|
||||
}
|
||||
|
||||
static void SubsequentInvocationOnCopyThrow()
|
||||
{
|
||||
wait_callbackBox cb;
|
||||
wait_callbackBox otherCb(cb);
|
||||
cb(anyBondedValue, anyStatus);
|
||||
|
||||
UT_AssertThrows(otherCb(anyBondedValue, grpc::Status::CANCELLED), bond::ext::gRPC::MultipleInvocationException);
|
||||
|
||||
UT_AssertIsTrue(otherCb.response().Deserialize().value == ANY_INT_VALUE);
|
||||
UT_AssertIsTrue(otherCb.status().ok());
|
||||
}
|
||||
|
||||
static void CanBeConvertedToStdFunction()
|
||||
{
|
||||
wait_callbackBox cb;
|
||||
std::function<void(const bond::bonded<bond::Box<int>>&, const grpc::Status&)> f = cb;
|
||||
|
||||
f(anyBondedValue, anyStatus);
|
||||
|
||||
UT_AssertIsTrue(cb.response().Deserialize().value == ANY_INT_VALUE);
|
||||
UT_AssertIsTrue(cb.status().ok());
|
||||
}
|
||||
|
||||
static void CopiesSeeSameValues()
|
||||
{
|
||||
wait_callbackBox cb;
|
||||
wait_callbackBox otherCb(cb);
|
||||
|
||||
cb(anyBondedValue, anyStatus);
|
||||
|
||||
UT_AssertIsTrue(otherCb.response().Deserialize().value == ANY_INT_VALUE);
|
||||
UT_AssertIsTrue(otherCb.status().ok());
|
||||
}
|
||||
|
||||
static void AsignmentSeesSameValues()
|
||||
{
|
||||
wait_callbackBox cb;
|
||||
cb(anyBondedValue, anyStatus);
|
||||
|
||||
wait_callbackBox otherCb;
|
||||
otherCb(anyBondedValue, grpc::Status::CANCELLED);
|
||||
|
||||
UT_AssertIsTrue(!otherCb.status().ok());
|
||||
|
||||
otherCb = cb;
|
||||
UT_AssertIsTrue(otherCb.status().ok());
|
||||
}
|
||||
|
||||
static void WaitReturnsTrueAfterCBInvoked()
|
||||
{
|
||||
wait_callbackBox cb;
|
||||
|
||||
bool wasInvoked = cb.wait_for(std::chrono::milliseconds(0));
|
||||
UT_AssertIsFalse(wasInvoked);
|
||||
|
||||
cb(anyBondedValue, anyStatus);
|
||||
wasInvoked = cb.wait_for(std::chrono::milliseconds(0));
|
||||
UT_AssertIsTrue(wasInvoked);
|
||||
}
|
||||
|
||||
static void WaitingThreadGetsNotified()
|
||||
{
|
||||
wait_callbackBox cb;
|
||||
bond::ext::detail::event threadStarted;
|
||||
std::atomic<bool> wasInvoked(false);
|
||||
|
||||
|
||||
std::thread t([&cb, &threadStarted, &wasInvoked]()
|
||||
{
|
||||
threadStarted.set();
|
||||
wasInvoked = cb.wait_for(std::chrono::seconds(30));
|
||||
});
|
||||
|
||||
// This is a clumsy attempt to get the thread into the wait_for method
|
||||
// before invoking the callback.
|
||||
bool wasStarted = threadStarted.wait_for(std::chrono::seconds(30));
|
||||
UT_AssertIsTrue(wasStarted);
|
||||
|
||||
cb(anyBondedValue, anyStatus);
|
||||
t.join();
|
||||
|
||||
UT_AssertIsTrue(wasInvoked);
|
||||
}
|
||||
|
||||
static void Initialize()
|
||||
{
|
||||
anyBondedValue = MakeAnyBonded();
|
||||
anyStatus = grpc::Status::OK;
|
||||
|
||||
UnitTestSuite suite("wait_callback");
|
||||
suite.AddTestCase(&CallbackCapturesValues, "CallbackCapturesValues");
|
||||
suite.AddTestCase(&SubsequentInvocationThrow, "SubsequentInvocationThrow");
|
||||
suite.AddTestCase(&SubsequentInvocationOnCopyThrow, "SubsequentInvocationOnCopyThrow");
|
||||
suite.AddTestCase(&CanBeConvertedToStdFunction, "CanBeConvertedToStdFunction");
|
||||
suite.AddTestCase(&CopiesSeeSameValues, "CopiesSeeSameValues");
|
||||
suite.AddTestCase(&AsignmentSeesSameValues, "AsignmentSeesSameValues");
|
||||
suite.AddTestCase(&WaitReturnsTrueAfterCBInvoked, "WaitReturnsTrueAfterCBInvoked");
|
||||
suite.AddTestCase(&WaitingThreadGetsNotified, "WaitingThreadGetsNotified");
|
||||
}
|
||||
}
|
||||
|
||||
bool init_unit_test()
|
||||
{
|
||||
wait_callback_tests::Initialize();
|
||||
return true;
|
||||
}
|
|
@ -66,9 +66,10 @@ if %errorlevel% neq 0 goto :VCEnd
|
|||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\ApplyOverloads.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Apply_cpp.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Apply_h.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Comm_h.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Comm_cpp.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Comm_h.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Enum_h.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Grpc_h.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Reflection_h.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Types_cpp.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Types_h.hs" />
|
||||
|
@ -77,6 +78,7 @@ if %errorlevel% neq 0 goto :VCEnd
|
|||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cs\Grpc_cs.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cs\Types_cs.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cs\Util.hs" />
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cs\Grpc_cs.hs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
|
|
|
@ -44,9 +44,6 @@
|
|||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Util.hs">
|
||||
<Filter>Bond\Codegen</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Reflection_h.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Apply_cpp.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
|
@ -56,15 +53,21 @@
|
|||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\ApplyOverloads.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Comm_h.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Comm_cpp.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Comm_h.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Enum_h.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Grpc_h.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Reflection_h.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
<None Include="$(ProjectDir)..\compiler\src\Language\Bond\Codegen\Cpp\Types_cpp.hs">
|
||||
<Filter>Bond\Codegen\Cpp</Filter>
|
||||
</None>
|
||||
|
@ -106,4 +109,4 @@
|
|||
<UniqueIdentifier>{905ABB36-088E-4045-8EA5-7316C8675D60}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
<DocumentationFile>$(OutDir)\$(TargetName).xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<FileToCopy Include="$(TargetDir)\$(TargetName).pdb" Condition="'$(OS)' != 'Unix'" />
|
||||
<FileToCopy Include="$(TargetPath).mdb" Condition="'$(OS)' == 'Unix'" />
|
||||
<FileToCopy Include="$(TargetDir)\$(TargetName).pdb" Condition="'$(MSBuildRuntimeType)' != 'Mono' or '$(_DebugFileExt)' == '.pdb'" />
|
||||
<FileToCopy Include="$(TargetPath).mdb" Condition="'$(MSBuildRuntimeType)' == 'Mono' and '$(_DebugFileExt)' == '.mdb'" />
|
||||
<FileToCopy Include="$(OutDir)\$(TargetName).xml" />
|
||||
</ItemGroup>
|
||||
<Target Name="AfterBuild">
|
||||
|
|
77
cs/cs.sln
77
cs/cs.sln
|
@ -258,7 +258,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "output-no-slash", "test\cod
|
|||
{92915BD9-8AB1-4E4D-A2AC-95BBF4F82D89} = {92915BD9-8AB1-4E4D-A2AC-95BBF4F82D89}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "grpc_pingpong", "..\examples\cs\comm\grpc_pingpong\grpc_pingpong.csproj", "{618420F1-6465-4DF4-BD1B-747765F481FF}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "grpc_pingpong", "..\examples\cs\grpc\pingpong\grpc_pingpong.csproj", "{618420F1-6465-4DF4-BD1B-747765F481FF}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{2E6E238C-9017-445C-9611-66DA780609BE} = {2E6E238C-9017-445C-9611-66DA780609BE}
|
||||
{43CBBA9B-C4BC-4E64-8733-7B72562D2E91} = {43CBBA9B-C4BC-4E64-8733-7B72562D2E91}
|
||||
|
@ -284,6 +284,24 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "grpc", "test\grpc\grpc.cspr
|
|||
{AF03BAE6-2470-4E1B-A683-3EBDCDC595FA} = {AF03BAE6-2470-4E1B-A683-3EBDCDC595FA}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCompatClient", "test\compat\grpc\client\GrpcCompatClient.csproj", "{D82898E8-4695-4233-98C6-1B3624241A2D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{43CBBA9B-C4BC-4E64-8733-7B72562D2E91} = {43CBBA9B-C4BC-4E64-8733-7B72562D2E91}
|
||||
{92915BD9-8AB1-4E4D-A2AC-95BBF4F82D89} = {92915BD9-8AB1-4E4D-A2AC-95BBF4F82D89}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCompatServer", "test\compat\grpc\server\GrpcCompatServer.csproj", "{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{43CBBA9B-C4BC-4E64-8733-7B72562D2E91} = {43CBBA9B-C4BC-4E64-8733-7B72562D2E91}
|
||||
{92915BD9-8AB1-4E4D-A2AC-95BBF4F82D89} = {92915BD9-8AB1-4E4D-A2AC-95BBF4F82D89}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GrpcCompatShared", "test\compat\grpc\shared\GrpcCompatShared.csproj", "{8FC5BF4E-6932-48FC-AA57-3D5F43130699}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{43CBBA9B-C4BC-4E64-8733-7B72562D2E91} = {43CBBA9B-C4BC-4E64-8733-7B72562D2E91}
|
||||
{92915BD9-8AB1-4E4D-A2AC-95BBF4F82D89} = {92915BD9-8AB1-4E4D-A2AC-95BBF4F82D89}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -1077,6 +1095,60 @@ Global
|
|||
{D5F087E7-1EE9-4AEB-83AF-5F234C69B867}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{D5F087E7-1EE9-4AEB-83AF-5F234C69B867}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{D5F087E7-1EE9-4AEB-83AF-5F234C69B867}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Fields|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Fields|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Fields|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Fields|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Fields|Win32.ActiveCfg = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Fields|Win32.Build.0 = Debug|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Fields|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Fields|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Fields|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Fields|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Fields|Win32.ActiveCfg = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Fields|Win32.Build.0 = Debug|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}.Release|Win32.Build.0 = Release|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Debug|Win32.ActiveCfg = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Debug|Win32.Build.0 = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Fields|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Fields|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Fields|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Fields|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Fields|Win32.ActiveCfg = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Fields|Win32.Build.0 = Debug|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Release|Win32.ActiveCfg = Release|Any CPU
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699}.Release|Win32.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -1125,5 +1197,8 @@ Global
|
|||
{BC01695D-D3C6-4569-A032-FDDEAA77260D} = {8CF1F5CD-548F-4323-869E-AA5903C88B6A}
|
||||
{618420F1-6465-4DF4-BD1B-747765F481FF} = {621A2166-EEE0-4A27-88AA-5BE5AC996452}
|
||||
{D5F087E7-1EE9-4AEB-83AF-5F234C69B867} = {4268A1D3-AF40-4120-B021-D95A0F754221}
|
||||
{D82898E8-4695-4233-98C6-1B3624241A2D} = {4268A1D3-AF40-4120-B021-D95A0F754221}
|
||||
{A6D526FD-22B0-4151-9B3E-D20C3C05D81D} = {4268A1D3-AF40-4120-B021-D95A0F754221}
|
||||
{8FC5BF4E-6932-48FC-AA57-3D5F43130699} = {4268A1D3-AF40-4120-B021-D95A0F754221}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<tags>Bond .NET C# serialization grpc RPC messaging</tags>
|
||||
<dependencies>
|
||||
<dependency id="Bond.Core.CSharp" version ="[$version$] "/>
|
||||
<dependency id="Grpc.Core" version="1.1.0" />
|
||||
<dependency id="Grpc.Core" version="1.3.0" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
|
|
@ -27,13 +27,13 @@
|
|||
<Reference Include="Bond.IO">
|
||||
<HintPath>..\io\$(OutputPath)\Bond.IO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Grpc.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Grpc.Core.1.1.0\lib\net45\Grpc.Core.dll</HintPath>
|
||||
<Reference Include="Grpc.Core">
|
||||
<HintPath>..\..\packages\Grpc.Core.1.3.0\lib\net45\Grpc.Core.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\build\internal\Common.Internal.targets" />
|
||||
<Import Project="..\..\packages\Grpc.Core.1.1.0\build\net45\Grpc.Core.targets" Condition="Exists('..\..\packages\Grpc.Core.1.1.0\build\net45\Grpc.Core.targets')" />
|
||||
<Import Project="..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets" Condition="Exists('..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets')" />
|
||||
</Project>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Grpc.Core" version="1.1.0" targetFramework="net45" />
|
||||
<package id="Grpc.Core" version="1.3.0" targetFramework="net45" />
|
||||
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
|
||||
</packages>
|
|
@ -8,7 +8,7 @@
|
|||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CommCompatClient</RootNamespace>
|
||||
<AssemblyName>CommCompatClient</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<DontBuildNet40>true</DontBuildNet40>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -17,11 +17,6 @@ namespace PingPongClient
|
|||
|
||||
public class Program
|
||||
{
|
||||
private const int NumRequests = 10;
|
||||
private const int NumEvents = 9;
|
||||
private const int NumErrors = 8;
|
||||
private const int NumThrows = 7;
|
||||
|
||||
private static async Task<PingPongProxy<EpoxyConnection>> SetupProxyAsync(ILayerStackProvider layerStack)
|
||||
{
|
||||
var transport = new EpoxyTransportBuilder().SetLayerStackProvider(layerStack).Construct();
|
||||
|
@ -64,7 +59,7 @@ namespace PingPongClient
|
|||
{
|
||||
var proxy = SetupProxyAsync(layerStackProvider).GetAwaiter().GetResult();
|
||||
|
||||
for (int i = 0; i < NumRequests; i++)
|
||||
for (int i = 0; i < (int)PingConstants.NumRequests; i++)
|
||||
{
|
||||
var request = new PingRequest { Payload = "request" + i, Action = PingAction.Identity };
|
||||
var message = DoPingPongAsync(proxy, request).GetAwaiter().GetResult();
|
||||
|
@ -75,22 +70,26 @@ namespace PingPongClient
|
|||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
else if (message.Payload.Deserialize().Payload != request.Payload)
|
||||
else
|
||||
{
|
||||
Console.Out.WriteLine("Response payload did not match request");
|
||||
Console.Out.WriteLine("Client failed");
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
string msg = message.Payload.Deserialize().Payload;
|
||||
if (msg != request.Payload)
|
||||
{
|
||||
Console.Out.WriteLine($"Response message did not match request payload: expected \"{request.Payload}\", got \"{msg}\"");
|
||||
Console.Out.WriteLine("Client failed");
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumEvents; i++)
|
||||
for (int i = 0; i < (int)PingConstants.NumEvents; i++)
|
||||
{
|
||||
var request = new PingRequest { Payload = "event" + i };
|
||||
DoPingEvent(proxy, request);
|
||||
}
|
||||
|
||||
for (int i = 0; i < NumErrors; i++)
|
||||
for (int i = 0; i < (int)PingConstants.NumErrors; i++)
|
||||
{
|
||||
var request = new PingRequest { Payload = "error" + i, Action = PingAction.Error };
|
||||
var message = DoPingPongAsync(proxy, request).GetAwaiter().GetResult();
|
||||
|
@ -101,12 +100,16 @@ namespace PingPongClient
|
|||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
else if (message.Error.Deserialize().message != request.Payload)
|
||||
else
|
||||
{
|
||||
Console.Out.WriteLine("Error message did not match request payload");
|
||||
Console.Out.WriteLine("Client failed");
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
string msg = message.Error.Deserialize().message;
|
||||
if (msg != request.Payload)
|
||||
{
|
||||
Console.Out.WriteLine($"Error message did not match request payload: expected \"{request.Payload}\", got \"{msg}\"");
|
||||
Console.Out.WriteLine("Client failed");
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CommCompatServer</RootNamespace>
|
||||
<AssemblyName>CommCompatServer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<DontBuildNet40>true</DontBuildNet40>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -16,13 +16,13 @@ namespace PingPongServer
|
|||
|
||||
public class PingPongService : PingPongServiceBase
|
||||
{
|
||||
const int NumRequestsExpected = 10;
|
||||
const int NumEventsExpected = 9;
|
||||
const int NumErrorsExpected = 8;
|
||||
const int NumThrowsExpected = 7;
|
||||
static int NumRequests = 0;
|
||||
static int NumEvents = 0;
|
||||
static int NumErrors = 0;
|
||||
static CountdownEvent Countdown = new CountdownEvent((int)PingConstants.NumRequests +
|
||||
(int)PingConstants.NumEvents +
|
||||
(int)PingConstants.NumErrors);
|
||||
|
||||
static int NumRequestsReceived = 0;
|
||||
static int NumEventsReceived = 0;
|
||||
static int NumErrorsReceived = 0;
|
||||
|
||||
public override Task<IMessage<PingResponse>> PingAsync(IMessage<PingRequest> param, CancellationToken ct)
|
||||
{
|
||||
|
@ -38,7 +38,8 @@ namespace PingPongServer
|
|||
|
||||
var response = new PingResponse { Payload = request.Payload };
|
||||
message = Message.FromPayload(response);
|
||||
NumRequests++;
|
||||
Interlocked.Increment(ref NumRequestsReceived);
|
||||
Countdown.Signal();
|
||||
break;
|
||||
|
||||
case PingAction.Error:
|
||||
|
@ -47,10 +48,12 @@ namespace PingPongServer
|
|||
|
||||
var error = new Error { error_code = 1234, message = request.Payload };
|
||||
message = Message.FromError<PingResponse>(error);
|
||||
NumErrors++;
|
||||
Interlocked.Increment(ref NumErrorsReceived);
|
||||
Countdown.Signal();
|
||||
break;
|
||||
|
||||
default:
|
||||
Countdown.Signal();
|
||||
throw new NotImplementedException("Unknown PingAction");
|
||||
}
|
||||
|
||||
|
@ -64,12 +67,13 @@ namespace PingPongServer
|
|||
Console.Out.WriteLine($"Received event \"{request.Payload}\"");
|
||||
Console.Out.Flush();
|
||||
|
||||
NumEvents++;
|
||||
Interlocked.Increment(ref NumEventsReceived);
|
||||
Countdown.Signal();
|
||||
}
|
||||
|
||||
private static async Task SetupAsync(ILayerStackProvider layerStackProvider)
|
||||
{
|
||||
var endpoint = new IPEndPoint(IPAddress.Loopback, 25188);
|
||||
var endpoint = new IPEndPoint(IPAddress.Loopback, (int)PingConstants.Port);
|
||||
EpoxyTransport transport = new EpoxyTransportBuilder().SetLayerStackProvider(layerStackProvider).Construct();
|
||||
EpoxyListener pingPongListener = transport.MakeListener(endpoint);
|
||||
|
||||
|
@ -90,11 +94,12 @@ namespace PingPongServer
|
|||
Console.Out.WriteLine("Server ready");
|
||||
Console.Out.Flush();
|
||||
|
||||
Thread.Sleep(3000);
|
||||
bool countdownSet = Countdown.Wait(30000);
|
||||
|
||||
if ((NumRequests != NumRequestsExpected) ||
|
||||
(NumEvents != NumEventsExpected) ||
|
||||
(NumErrors != NumErrorsExpected))
|
||||
if (!countdownSet ||
|
||||
(NumRequestsReceived != (int)PingConstants.NumRequests) ||
|
||||
(NumEventsReceived != (int)PingConstants.NumEvents) ||
|
||||
(NumErrorsReceived != (int)PingConstants.NumErrors))
|
||||
{
|
||||
Console.Out.WriteLine("Server failed: Did not receive all expected messages");
|
||||
Console.Out.Flush();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>CommCompatShared</RootNamespace>
|
||||
<AssemblyName>CommCompatShared</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<DontBuildNet40>true</DontBuildNet40>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\..\build\internal\Common.Internal.props" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{D82898E8-4695-4233-98C6-1B3624241A2D}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>GrpcCompatClient</RootNamespace>
|
||||
<AssemblyName>GrpcCompatClient</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<DontBuildNet40>true</DontBuildNet40>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Grpc.Core">
|
||||
<HintPath>..\..\..\..\packages\Grpc.Core.1.3.0\lib\net45\Grpc.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Interactive.Async">
|
||||
<HintPath>..\..\..\..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Bond">
|
||||
<HintPath>..\..\..\..\$(OutputPath)\Bond.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Bond.Attributes">
|
||||
<HintPath>..\..\..\..\$(OutputPath)\Bond.Attributes.dll</HintPath>
|
||||
</Reference>
|
||||
<ProjectReference Include="..\..\..\..\src\grpc\grpc.csproj">
|
||||
<Project>{af03bae6-2470-4e1b-a683-3ebdcdc595fa}</Project>
|
||||
<Name>grpc</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\shared\GrpcCompatShared.csproj">
|
||||
<Project>{8FC5BF4E-6932-48FC-AA57-3D5F43130699}</Project>
|
||||
<Name>GrpcCompatShared</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\..\build\internal\Common.Internal.targets" />
|
||||
<Import Project="..\..\..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets" Condition="Exists('..\..\..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets')" />
|
||||
</Project>
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace PingPongClient
|
||||
{
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Bond.Grpc;
|
||||
using Grpc.Core;
|
||||
|
||||
using PingPongNS;
|
||||
|
||||
public class Program
|
||||
{
|
||||
|
||||
private static async Task<IMessage<PingResponse>> DoPingPongAsync(PingPong.PingPongClient client, PingRequest request)
|
||||
{
|
||||
Console.Out.WriteLine("Sending request");
|
||||
Console.Out.Flush();
|
||||
|
||||
IMessage<PingResponse> response = await client.PingAsync(request);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
|
||||
Console.Out.WriteLine("Start client");
|
||||
Console.Out.Flush();
|
||||
|
||||
try
|
||||
{
|
||||
Channel pingChannel = new Channel("127.0.0.1", (int)PingConstants.Port, ChannelCredentials.Insecure);
|
||||
var pingClient = new PingPong.PingPongClient(pingChannel);
|
||||
|
||||
for (int i = 0; i < (int)PingConstants.NumRequests; i++)
|
||||
{
|
||||
var request = new PingRequest { Payload = "request" + i, Action = PingAction.Identity };
|
||||
var message = DoPingPongAsync(pingClient, request).GetAwaiter().GetResult();
|
||||
if (message.Payload.Deserialize().Payload != request.Payload)
|
||||
{
|
||||
Console.Out.WriteLine("Response payload did not match request");
|
||||
Console.Out.WriteLine("Client failed");
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)PingConstants.NumErrors; i++)
|
||||
{
|
||||
var request = new PingRequest { Payload = "error" + i, Action = PingAction.Error };
|
||||
try
|
||||
{
|
||||
var message = DoPingPongAsync(pingClient, request).GetAwaiter().GetResult();
|
||||
Console.Out.WriteLine("Non-error response received: " + message.Payload.Deserialize().Payload);
|
||||
Console.Out.WriteLine("Client failed");
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Out.WriteLine("Error caught: " + ex.Message);
|
||||
Console.Out.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.Out.WriteLine("Exception caught: " + ex.Message);
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Out.WriteLine("Client succeeded");
|
||||
Console.Out.Flush();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Grpc.Core" version="1.1.0" targetFramework="net45" />
|
||||
<package id="Grpc.Core" version="1.3.0" targetFramework="net45" />
|
||||
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
|
||||
</packages>
|
|
@ -0,0 +1,32 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("GrpcCompatClient")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("GrpcCompatClient")]
|
||||
[assembly: AssemblyCopyright("Copyright (C) Microsoft. All rights reserved.")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\..\build\internal\Common.Internal.props" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{A6D526FD-22B0-4151-9B3E-D20C3C05D81D}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>GrpcCompatServer</RootNamespace>
|
||||
<AssemblyName>GrpcCompatServer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<DontBuildNet40>true</DontBuildNet40>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Grpc.Core">
|
||||
<HintPath>..\..\..\..\packages\Grpc.Core.1.3.0\lib\net45\Grpc.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Interactive.Async">
|
||||
<HintPath>..\..\..\..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Bond">
|
||||
<HintPath>..\..\..\..\$(OutputPath)\Bond.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Bond.Attributes">
|
||||
<HintPath>..\..\..\..\$(OutputPath)\Bond.Attributes.dll</HintPath>
|
||||
</Reference>
|
||||
<ProjectReference Include="..\..\..\..\src\grpc\grpc.csproj">
|
||||
<Project>{af03bae6-2470-4e1b-a683-3ebdcdc595fa}</Project>
|
||||
<Name>grpc</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\shared\GrpcCompatShared.csproj">
|
||||
<Project>{8FC5BF4E-6932-48FC-AA57-3D5F43130699}</Project>
|
||||
<Name>GrpcCompatShared</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\..\build\internal\Common.Internal.targets" />
|
||||
<Import Project="..\..\..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets" Condition="Exists('..\..\..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets')" />
|
||||
</Project>
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace PingPongServer
|
||||
{
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Bond.Grpc;
|
||||
using Grpc.Core;
|
||||
|
||||
using PingPongNS;
|
||||
|
||||
public class PingPongService : PingPong.PingPongBase
|
||||
{
|
||||
static Server pingServer;
|
||||
|
||||
static CountdownEvent Countdown = new CountdownEvent((int)PingConstants.NumRequests + (int)PingConstants.NumErrors);
|
||||
|
||||
static int NumRequestsReceived = 0;
|
||||
static int NumErrorsReceived = 0;
|
||||
|
||||
public override Task<IMessage<PingResponse>> Ping(IMessage<PingRequest> param, ServerCallContext context)
|
||||
{
|
||||
PingRequest request = param.Payload.Deserialize();
|
||||
|
||||
IMessage<PingResponse> message = null;
|
||||
|
||||
switch (request.Action)
|
||||
{
|
||||
case PingAction.Identity:
|
||||
Console.Out.WriteLine($"Received identity request \"{request.Payload}\"");
|
||||
Console.Out.Flush();
|
||||
|
||||
var response = new PingResponse { Payload = request.Payload };
|
||||
message = Message.From(response);
|
||||
Interlocked.Increment(ref NumRequestsReceived);
|
||||
Countdown.Signal();
|
||||
break;
|
||||
|
||||
case PingAction.Error:
|
||||
Console.Out.WriteLine($"Received error request \"{request.Payload}\"");
|
||||
Console.Out.Flush();
|
||||
Interlocked.Increment(ref NumErrorsReceived);
|
||||
Countdown.Signal();
|
||||
throw new ApplicationException("Application Exception");
|
||||
|
||||
default:
|
||||
Countdown.Signal();
|
||||
throw new NotImplementedException("Unknown PingAction");
|
||||
}
|
||||
|
||||
return Task.FromResult(message);
|
||||
}
|
||||
|
||||
private static void Setup()
|
||||
{
|
||||
pingServer = new Server
|
||||
{
|
||||
Services =
|
||||
{
|
||||
PingPong.BindService(new PingPongService()),
|
||||
},
|
||||
Ports = { new ServerPort("127.0.0.1", (int)PingConstants.Port, ServerCredentials.Insecure) }
|
||||
};
|
||||
pingServer.Start();
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Setup();
|
||||
|
||||
Console.Out.WriteLine("Server ready");
|
||||
Console.Out.Flush();
|
||||
|
||||
bool countdownSet = Countdown.Wait(TimeSpan.FromSeconds(30));
|
||||
bool didShutdown = pingServer.ShutdownAsync().Wait(TimeSpan.FromSeconds(10));
|
||||
|
||||
if (!didShutdown)
|
||||
{
|
||||
Console.Out.WriteLine("Server failed: Didn't shutdown in time");
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
else if (
|
||||
!countdownSet ||
|
||||
(NumRequestsReceived != (int)PingConstants.NumRequests) ||
|
||||
(NumErrorsReceived != (int)PingConstants.NumErrors))
|
||||
{
|
||||
Console.Out.WriteLine("Server failed: Did not receive all expected messages");
|
||||
Console.Out.Flush();
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Out.WriteLine("Server completed");
|
||||
Console.Out.Flush();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Grpc.Core" version="1.3.0" targetFramework="net45" />
|
||||
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
|
||||
</packages>
|
|
@ -0,0 +1,32 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("GrpcCompatServer")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("GrpcCompatServer")]
|
||||
[assembly: AssemblyCopyright("Copyright (C) Microsoft. All rights reserved.")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,52 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\..\build\internal\Common.Internal.props" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{8FC5BF4E-6932-48FC-AA57-3D5F43130699}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>GrpcCompatShared</RootNamespace>
|
||||
<AssemblyName>GrpcCompatShared</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<DontBuildNet40>true</DontBuildNet40>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Grpc.Core">
|
||||
<HintPath>..\..\..\..\packages\Grpc.Core.1.3.0\lib\net45\Grpc.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Interactive.Async">
|
||||
<HintPath>..\..\..\..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(IntermediateOutputPath)\pingpong_grpc.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<BondCodegen Include="..\..\..\..\..\test\compat\grpc\pingpong.bond">
|
||||
<Options>--grpc</Options>
|
||||
</BondCodegen>
|
||||
<!-- Resharper Workaround -->
|
||||
<Compile Include="$(IntermediateOutputPath)\pingpong_types.cs" Condition="False" />
|
||||
<!-- End Resharper Workaround -->
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Bond">
|
||||
<HintPath>..\..\..\..\$(OutputPath)\Bond.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Bond.Attributes">
|
||||
<HintPath>..\..\..\..\$(OutputPath)\Bond.Attributes.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\src\grpc\grpc.csproj">
|
||||
<Project>{af03bae6-2470-4e1b-a683-3ebdcdc595fa}</Project>
|
||||
<Name>grpc</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\..\..\build\internal\Common.Internal.targets" />
|
||||
<Import Project="..\..\..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets" Condition="Exists('..\..\..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets')" />
|
||||
</Project>
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("GrpcCompatShared")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("GrpcCompatShared")]
|
||||
[assembly: AssemblyCopyright("Copyright (C) Microsoft. All rights reserved.")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("5d90c693-10df-4378-8073-0d8e58d1245f")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Grpc.Core" version="1.3.0" targetFramework="net45" />
|
||||
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
|
||||
</packages>
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath32)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\build\internal\Common.Internal.props" />
|
||||
|
@ -30,8 +30,8 @@
|
|||
<Compile Include="Schemas.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Grpc.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\packages\Grpc.Core.1.1.0\lib\net45\Grpc.Core.dll</HintPath>
|
||||
<Reference Include="Grpc.Core">
|
||||
<HintPath>..\..\packages\Grpc.Core.1.3.0\lib\net45\Grpc.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NUnit.VisualStudio.TestAdapter" Condition="'$(OS)' != 'Unix'">
|
||||
<HintPath>..\..\packages\NUnitTestAdapter.2.0.0\lib\NUnit.VisualStudio.TestAdapter.dll</HintPath>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<Reference Include="nunit.framework">
|
||||
<HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Interactive.Async, Version=3.0.1000.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Interactive.Async">
|
||||
<HintPath>..\..\packages\System.Interactive.Async.3.1.1\lib\net45\System.Interactive.Async.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
@ -71,5 +71,5 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildThisFileDirectory)\..\..\build\internal\Common.Internal.targets" />
|
||||
<Import Project="..\..\packages\Grpc.Core.1.1.0\build\net45\Grpc.Core.targets" Condition="Exists('..\..\packages\Grpc.Core.1.1.0\build\net45\Grpc.Core.targets')" />
|
||||
<Import Project="..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets" Condition="Exists('..\..\packages\Grpc.Core.1.3.0\build\net45\Grpc.Core.targets')" />
|
||||
</Project>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Grpc.Core" version="1.1.0" targetFramework="net45" />
|
||||
<package id="Grpc.Core" version="1.3.0" targetFramework="net45" />
|
||||
<package id="NUnit" version="2.6.4" targetFramework="net45" />
|
||||
<package id="NUnitTestAdapter" version="2.0.0" targetFramework="net45" />
|
||||
<package id="System.Interactive.Async" version="3.1.1" targetFramework="net45" />
|
||||
|
|
|
@ -124,11 +124,15 @@ if (Haskell_PANDOC_EXECUTABLE AND Doxygen_EXECUTABLE)
|
|||
CODE python
|
||||
OPTIONS --self-contained --table-of-contents)
|
||||
|
||||
file(GLOB_RECURSE cpp_headers ../cpp/inc/bond/*.h)
|
||||
|
||||
set (doxygen_sources
|
||||
doxygen/bond.doxygen
|
||||
doxygen/bond_layout.xml
|
||||
doxygen/bond_reference.css
|
||||
doxygen/mainpage.md)
|
||||
doxygen/mainpage.md
|
||||
doxygen/examples/wait_callback_example.cpp
|
||||
${cpp_headers})
|
||||
|
||||
set (doxygen_output_dir
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/html/reference")
|
||||
|
|
|
@ -645,7 +645,7 @@ WARN_LOGFILE =
|
|||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = doxygen/mainpage.md ../cpp/inc/bond
|
||||
INPUT = doxygen/mainpage.md ../cpp/inc/bond/
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
|
||||
|
@ -705,7 +705,7 @@ EXCLUDE_SYMBOLS =
|
|||
# directories that contain example code fragments that are included (see
|
||||
# the \include command).
|
||||
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATH = doxygen/examples/
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#include <bond/ext/grpc/wait_callback.h>
|
||||
// ...
|
||||
|
||||
int main()
|
||||
{
|
||||
Example::Client client(/* ... */);
|
||||
|
||||
bond::ext::gRPC::wait_callback<ExampleResponse> cb;
|
||||
client.AsyncExampleMethod(/* ... */, cb);
|
||||
|
||||
cb.wait();
|
||||
if (cb.status().ok())
|
||||
{
|
||||
DoSomeThingWith(cb.response());
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
# About #
|
||||
|
||||
Bond-over-gRPC provides code generation from Bond IDL service definitions
|
||||
to send Bond objects via gRPC. The gRPC functionality supercedes the
|
||||
(now deprecated) Bond Comm framework.
|
||||
to send Bond objects via [gRPC](http://www.grpc.io/) The gRPC functionality
|
||||
supercedes the (now deprecated) Bond Comm framework.
|
||||
|
||||
# Features #
|
||||
|
||||
|
@ -13,70 +13,222 @@ to send Bond objects via gRPC. The gRPC functionality supercedes the
|
|||
The Bond IDL has been extended to support the definition of
|
||||
[services](compiler.html#service-definition) and
|
||||
[generic services](compiler.html#generic-service). These definitions are
|
||||
used by the Bond compiler to generate:
|
||||
used by the Bond compiler to generate classes that provide:
|
||||
|
||||
* service stubs that can be used as the base for implementing services'
|
||||
* a service base that can be used as the basis for implementing services'
|
||||
methods
|
||||
* proxy stubs that can be used by clients to invoke those methods
|
||||
* a proxy stub that can be used by clients to invoke those methods
|
||||
|
||||
To generate these stubs, pass the `--grpc` flag to `gbc` (the Bond compiler
|
||||
To generate these classes, pass the `--grpc` flag to `gbc` (the Bond compiler
|
||||
tool).
|
||||
|
||||
Note that gRPC doesn't provide a messaging pattern that matches
|
||||
the semantics of methods with a return type of `nothing`; to compensate,
|
||||
`gbc` provides generated wrappers to simulate the appropriate semantics.
|
||||
|
||||
Also note that Bond-over-gRPC does not yet provide interfaces for gRPC's
|
||||
streaming; this functionality will be added in the coming months.
|
||||
|
||||
# Implementations #
|
||||
|
||||
Bond-over-gRPC is available for C# now and will be released for C++ in a
|
||||
few weeks.
|
||||
Bond-over-gRPC is available for C# and C++.
|
||||
|
||||
## Bond-over-gRPC for C# ##
|
||||
|
||||
Given a service definition like the following:
|
||||
|
||||
service ExampleService
|
||||
service Example
|
||||
{
|
||||
ExampleResponse Method(ExampleRequest);
|
||||
ExampleResponse ExampleMethod(ExampleRequest);
|
||||
}
|
||||
|
||||
`gbc` will produce stubs for gRPC with the `--grpc` flag:
|
||||
`gbc` will generate C# classes for gRPC with the `--grpc` flag:
|
||||
|
||||
gbc c# --grpc example.bond
|
||||
|
||||
The service stub allows for the definition of the service implementation like this:
|
||||
The key generated C# classes for gRPC are:
|
||||
* A simple class with the name of the service (e.g.: `Example`). This class
|
||||
provides some basic encapsulation of the server-side service base, the
|
||||
client-side proxy stub, and some static methods and data members for
|
||||
initialization.
|
||||
* The service base, which is named with the name of the service plus the suffix
|
||||
`Base` (e.g.: `Example.ExampleBase`). This class has abstract methods
|
||||
for each of the methods defined in the service IDL, serving as a base for the
|
||||
concrete implementation which will provide the actual server-side business
|
||||
logic.
|
||||
* The proxy stub, which is named with the name of the service plus the suffix
|
||||
`Client' (e.g.: `Example.ExampleClient`). This is used to invoke the service
|
||||
from the client side.
|
||||
|
||||
public class ExampleService : ExampleServiceBase
|
||||
To build the service functionality, simply write a concrete service
|
||||
implementation by subclassing the server base and supplying the business logic:
|
||||
|
||||
public class ExampleServiceImpl : Example.ExampleBase
|
||||
{
|
||||
public override async Task<IMessage<ExampleResponse>> Method(IMessage<ExampleRequest> param, ServerCallContext context)
|
||||
public override async Task<IMessage<ExampleResponse>> ExampleMethod(IMessage<ExampleRequest> param, ServerCallContext context)
|
||||
{
|
||||
ExampleRequest request = param.Payload.Deserialize();
|
||||
|
||||
// Service business logic
|
||||
|
||||
var response = new ExampleResponse();
|
||||
|
||||
// Service business logic goes here
|
||||
|
||||
return Message.From(response);
|
||||
}
|
||||
}
|
||||
|
||||
The proxy stub allows the client to invoke the remote service method like this:
|
||||
This service implementation is hooked up to a gRPC server as follows:
|
||||
|
||||
var channel = new Channel("localhost", Port, ChannelCredentials.Insecure);
|
||||
var client = new ExampleClient(channel);
|
||||
var server = new Grpc.Core.Server
|
||||
{
|
||||
Services = { Example.BindService(new ExampleServiceImpl()) },
|
||||
Ports = { new Grpc.Core.ServerPort(ExampleHost, ExamplePort, Grpc.Core.ServerCredentials.Insecure) }
|
||||
};
|
||||
server.Start();
|
||||
|
||||
At this point the server is ready to receive requests and route them to the
|
||||
service implemetation.
|
||||
|
||||
On the client side, the proxy stub establishes a connection to the server like this:
|
||||
|
||||
var channel = new Grpc.Core.Channel(ExampleHost, ExamplePort, Grpc.Core.ChannelCredentials.Insecure);
|
||||
var client = new Example.ExampleClient(channel);
|
||||
|
||||
The proxy stub can then be used to make calls to the server as follows:
|
||||
|
||||
var request = new ExampleRequest();
|
||||
// Fill in request fields here
|
||||
|
||||
IMessage<ExampleResponse> responseMessage = await client.Method(request);
|
||||
var response = responseMessage.Payload.Deserialize().Payload;
|
||||
|
||||
ExampleResponse response = responseMessage.Payload.Deserialize().Payload;
|
||||
// Examine response here
|
||||
|
||||
Note that the singatures generated by `gbc` are slightly different from the
|
||||
ones in the gRPC documentation: on the service side, the request is wrapped in
|
||||
`IMessage<T>` and on the client side, the response is wrapped in
|
||||
`IMessage<T>; this allows for better control over the time of
|
||||
deserialization and also helps prevent slicing when using polymorphic Bond
|
||||
types. Note also that Bond-over-gRPC does not provide synchronous APIs in C#
|
||||
by design.
|
||||
|
||||
For more information about gRPC in C#, take a look at the
|
||||
[gRPC C# tutorial](http://www.grpc.io/docs/tutorials/basic/csharp.html).
|
||||
Note that the singatures generated by `gbc` are slightly different from the
|
||||
ones in the gRPC tutorial: on the service side, the request is wrapped in
|
||||
`IMessage<T>` and on the client side, the response is wrapped in
|
||||
`IMessage<T>`. This allows for better control over the time of
|
||||
deserialization and also helps prevent slicing when using polymorphic Bond
|
||||
types.
|
||||
|
||||
There is a [Bond-over-gRPC standalone example project](https://github.com/Microsoft/bond-grpc-examples).
|
||||
|
||||
See also the following example:
|
||||
|
||||
- `examples/cs/comm/grpc_pingpong`
|
||||
- `examples/cs/grpc/pingpong`
|
||||
|
||||
## Bond-over-gRPC for C++ ##
|
||||
|
||||
Given a service definition like the following:
|
||||
|
||||
service Example
|
||||
{
|
||||
ExampleResponse ExampleMethod(ExampleRequest);
|
||||
}
|
||||
|
||||
`gbc` will generate C++ classes for gRPC with the `--grpc` flag:
|
||||
|
||||
gbc c++ --grpc example.bond
|
||||
|
||||
The key generated C++ classes for gRPC are:
|
||||
* A simple class with the name of the service (e.g.: `Example`). This class
|
||||
provides some basic encapsulation of the server-side service base and the
|
||||
client-side proxy stub.
|
||||
* The service base, which is an inner class named `Service` (e.g.:
|
||||
`Example::Service`). This class has abstract methods
|
||||
for each of the methods defined in the service IDL, serving as a base for the
|
||||
concrete implementation which will provide the actual server-side business
|
||||
logic. (Technically, `Service` is a type alias for
|
||||
`ServiceCore<bond::ext::gRPC::thread_pool>`. The `ServiceCore<T>` template
|
||||
can be used to customize the service implementation to use a different
|
||||
thread pool implementation.)
|
||||
* The proxy stub, which is an inner class named `Client` (e.g.:
|
||||
`Example::Client`). This is used to invoke the service from the
|
||||
client side. (Likewise, `Client` is a type alias for
|
||||
`ClientCore<bond::ext::gRPC::thread_pool>`. The `ClientCore<T>` template
|
||||
can be used to customize the client implementation to use a different
|
||||
thread pool implementation.)
|
||||
|
||||
To build the service functionality, simply write a concrete service
|
||||
implementation by subclassing the server base and supplying the business logic:
|
||||
|
||||
class ExampleServiceImpl final : Example::Service
|
||||
{
|
||||
void ExampleMethod(
|
||||
bond::ext::gRPC::unary_call<
|
||||
bond::bonded<ExampleRequest>,
|
||||
ExampleResponse> call) override
|
||||
{
|
||||
ExampleRequest request = call.request().Deserialize();
|
||||
ExampleResponse reply;
|
||||
|
||||
// Service business logic goes here
|
||||
|
||||
call.Finish(response);
|
||||
}
|
||||
}
|
||||
|
||||
This service implementation is hooked up to a gRPC server as follows:
|
||||
|
||||
auto ioManager = std::make_shared<bond::ext::gRPC::io_manager>();
|
||||
auto threadPool = std::make_shared<bond::ext::gRPC::thread_pool>();
|
||||
const std::string server_address(Host + ":" + Port);
|
||||
|
||||
ExampleServiceImpl service;
|
||||
bond::ext::gRPC::server_builder builder;
|
||||
builder.SetThreadPool(threadPool);
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
||||
builder.RegisterService(&service);
|
||||
std::unique_ptr<bond::ext::gRPC::server> server(builder.BuildAndStart());
|
||||
|
||||
At this point the server is ready to receive requests and route them to the
|
||||
service implemetation.
|
||||
|
||||
On the client side, the proxy stub establishes a connection to the server like this:
|
||||
|
||||
auto ioManager = std::make_shared<bond::ext::gRPC::io_manager>();
|
||||
auto threadPool = std::make_shared<bond::ext::gRPC::thread_pool>();
|
||||
const std::string server_address(Host + ":" + Port);
|
||||
|
||||
Example::Client client(
|
||||
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()),
|
||||
ioManager,
|
||||
threadPool);
|
||||
|
||||
The proxy stub can then be used to make calls to the server as follows:
|
||||
|
||||
ExampleRequest request;
|
||||
// Fill in request fields here
|
||||
|
||||
bond::ext::gRPC::wait_callback<ExampleResponse> cb;
|
||||
client.AsyncExampleMethod(&context, request, callback);
|
||||
|
||||
callback.wait();
|
||||
ExampleResponse response = callback.response().Deserialize();
|
||||
// Examine response here
|
||||
|
||||
Note these APIs are significantly different from the APIs presented in the
|
||||
gRPC documentation; Bond-over-gRPC is attempting to provide a more
|
||||
straightforward API for aynchronous communication than gRPC currently
|
||||
presents in C++. The use of [`wait_callback<T>`][wait_callback_reference]
|
||||
here is for illustrative purposes; any callback implementation with the same
|
||||
signature can be used. Note also the use of `bonded<T>` to wrap the request
|
||||
and response objects in several places; this allows for better control over
|
||||
the time of deserialization and also helps prevent slicing when using
|
||||
polymorphic Bond types. Convenience APIs are provided in some places to hide
|
||||
the use `bonded<T>` where possible. Finally, note that Bond-over-gRPC does
|
||||
not provide synchronous APIs in C++ by design.
|
||||
|
||||
For more information about gRPC in C++, take a look at the
|
||||
[gRPC C++ tutorial](http://www.grpc.io/docs/tutorials/basic/c.html);
|
||||
however, keep in mind that the Bond-over-gRPC APIs diverge significantly
|
||||
from those documented there.
|
||||
|
||||
See also the following example:
|
||||
|
||||
- `examples/cpp/grpc/helloworld`
|
||||
|
||||
[wait_callback_reference]: ../reference/cpp/classbond_1_1ext_1_1g_r_p_c_1_1wait__callback.html
|
||||
|
|
|
@ -2,6 +2,10 @@ if (NOT BOND_SKIP_CORE_TESTS)
|
|||
add_subfolder (core "examples/core")
|
||||
endif()
|
||||
|
||||
if (NOT BOND_CORE_ONLY)
|
||||
if (BOND_ENABLE_COMM)
|
||||
add_subfolder (comm "examples/comm")
|
||||
endif()
|
||||
|
||||
if (BOND_ENABLE_GRPC)
|
||||
add_subfolder (grpc "examples/grpc")
|
||||
endif()
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
if (MSVC)
|
||||
add_subdirectory (grpc_dll)
|
||||
endif()
|
||||
add_subdirectory (grpc_static_library)
|
||||
add_subdirectory (helloworld)
|
||||
add_subdirectory (pingpong)
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
add_bond_codegen (grpc_dll.bond
|
||||
OPTIONS --header=\\\"dllexample_dynlink.h\\\" --apply=compact --export-attribute=DLLEXAMPLE_DYNLINK
|
||||
GRPC)
|
||||
|
||||
add_library (grpc_dll_example_lib EXCLUDE_FROM_ALL
|
||||
SHARED
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/grpc_dll_types.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/grpc_dll_apply.cpp)
|
||||
|
||||
target_include_directories(grpc_dll_example_lib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_compile_definitions (grpc_dll_example_lib PRIVATE -DBUILDING_DLLEXAMPLE_DLL)
|
||||
|
||||
add_target_to_folder (grpc_dll_example_lib)
|
||||
|
||||
target_link_libraries (grpc_dll_example_lib PUBLIC
|
||||
grpc++
|
||||
bond)
|
||||
|
||||
# TODO: It feels like the grpc++ target should have this as part of its
|
||||
# interface... Perhaps a patch for upstream?
|
||||
target_include_directories(grpc_dll_example_lib
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/grpc/include
|
||||
)
|
||||
|
||||
cxx_target_compile_definitions (MSVC grpc_dll_example_lib PRIVATE
|
||||
-D_WIN32_WINNT=0x0600)
|
||||
|
||||
add_bond_test (grpc_dll_example
|
||||
using_grpc_dll.cpp)
|
||||
|
||||
target_compile_definitions (grpc_dll_example PRIVATE -DUSING_DLLEXAMPLE_DLL)
|
||||
|
||||
target_include_directories(grpc_dll_example PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
target_link_libraries (grpc_dll_example PUBLIC
|
||||
grpc_dll_example_lib)
|
||||
|
||||
# TODO: It feels like the grpc++ target should have this as part of its
|
||||
# interface... Perhaps a patch for upstream?
|
||||
target_include_directories(grpc_dll_example
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/grpc/include
|
||||
)
|
||||
|
||||
cxx_target_compile_definitions (MSVC grpc_dll_example PRIVATE
|
||||
-D_WIN32_WINNT=0x0600)
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(BUILDING_DLLEXAMPLE_DLL)
|
||||
#define DLLEXAMPLE_DYNLINK __declspec(dllexport)
|
||||
#elif defined(USING_DLLEXAMPLE_DLL)
|
||||
#define DLLEXAMPLE_DYNLINK __declspec(dllimport)
|
||||
#else
|
||||
#define DLLEXAMPLE_DYNLINK
|
||||
#endif
|
|
@ -0,0 +1,18 @@
|
|||
namespace examples.grpc_dll
|
||||
|
||||
struct Item
|
||||
{
|
||||
0: string str = "default string value";
|
||||
1: list<uint32> numbers;
|
||||
}
|
||||
|
||||
struct MyStruct
|
||||
{
|
||||
0: vector<Item> items;
|
||||
1: bonded<Item> item;
|
||||
}
|
||||
|
||||
service TestService
|
||||
{
|
||||
Item TestMethod(MyStruct);
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
// The program uses a generated Bond service TestService; however the
|
||||
// project doesn't contain any .bond file. Instead it includes headers from
|
||||
// and links to grpc_dll_example.dll which contain definition of TestService
|
||||
// and pre-built Bond de/serialization code for it. This approach is useful
|
||||
// when multiple projects use the same Bond types; it allows compiling Bond
|
||||
// code once and distributing as a binary .lib file. The static library
|
||||
// needs to be rebuilt only when .bond file (i.e. data schema) changes. Note
|
||||
// that the DLL and the programs that consume it have to use the same
|
||||
// version of Bond.
|
||||
//
|
||||
// This program tests the use of the gRPC client and service code.
|
||||
|
||||
// Must include the _apply.h file to use the pre-compiled routines;
|
||||
// otherwise they'll be expanded again in this compilation unit.
|
||||
#include <grpc_dll_apply.h>
|
||||
|
||||
// Reflection header needed only for explicit metadata access -- don't
|
||||
// include by default as it will increase your build times
|
||||
#include <grpc_dll_reflection.h>
|
||||
|
||||
#include <grpc_dll_grpc.h>
|
||||
|
||||
#include <bond/core/bond.h>
|
||||
#include <bond/core/reflection.h>
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/server.h>
|
||||
#include <bond/ext/grpc/server_builder.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
#include <bond/protocol/compact_binary.h>
|
||||
#include <bond/stream/output_buffer.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
using grpc::Channel;
|
||||
using grpc::ClientContext;
|
||||
using grpc::Status;
|
||||
using grpc::StatusCode;
|
||||
|
||||
using grpc::Server;
|
||||
using grpc::ServerBuilder;
|
||||
using grpc::ServerContext;
|
||||
|
||||
using namespace examples::grpc_dll;
|
||||
|
||||
struct TestServiceImpl : TestService::Service
|
||||
{
|
||||
void TestMethod(bond::ext::gRPC::unary_call<
|
||||
bond::bonded<MyStruct>,
|
||||
Item> call) override
|
||||
{
|
||||
MyStruct request = call.request().Deserialize();
|
||||
|
||||
Item response;
|
||||
response = request.items[0];
|
||||
|
||||
call.Finish(response);
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
{ // Exercise Core facilities
|
||||
|
||||
MyStruct obj;
|
||||
|
||||
// Initialize
|
||||
obj.items.resize(1);
|
||||
obj.items[0].numbers.push_back(13);
|
||||
|
||||
Item item;
|
||||
|
||||
item.numbers.push_back(11);
|
||||
obj.item = bond::bonded<Item>(item);
|
||||
|
||||
// Serialize
|
||||
bond::OutputBuffer buffer;
|
||||
bond::CompactBinaryWriter<bond::OutputBuffer> writer(buffer);
|
||||
bond::Serialize(obj, writer);
|
||||
|
||||
bond::blob data = buffer.GetBuffer();
|
||||
|
||||
MyStruct obj2;
|
||||
|
||||
// Deserialize
|
||||
bond::CompactBinaryReader<bond::InputBuffer> reader(data);
|
||||
bond::Deserialize(reader, obj2);
|
||||
|
||||
Item item2;
|
||||
|
||||
obj2.item.Deserialize(item2);
|
||||
|
||||
// Access metadata
|
||||
bond::Metadata myMetadata = MyStruct::Schema::GetMetadata();
|
||||
|
||||
std::cout << myMetadata.name << std::endl;
|
||||
|
||||
bond::RuntimeSchema schema = bond::GetRuntimeSchema<MyStruct>();
|
||||
|
||||
std::cout << schema.GetSchema().structs[schema.GetSchema().root.struct_def].fields[0].metadata.name << std::endl;
|
||||
}
|
||||
|
||||
{ // Exercise gRPC facilities
|
||||
|
||||
const std::string server_address("127.0.0.1:50051");
|
||||
|
||||
auto ioManager = std::make_shared<bond::ext::gRPC::io_manager>();
|
||||
auto threadPool = std::make_shared<bond::ext::gRPC::thread_pool>();
|
||||
|
||||
// Create and start a service instance
|
||||
TestServiceImpl service;
|
||||
bond::ext::gRPC::server_builder builder;
|
||||
builder.SetThreadPool(threadPool);
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
||||
builder.RegisterService(&service);
|
||||
std::unique_ptr<bond::ext::gRPC::server> server(builder.BuildAndStart());
|
||||
|
||||
// Create a proxy
|
||||
TestService::Client proxy(
|
||||
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()),
|
||||
ioManager,
|
||||
threadPool);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
add_bond_codegen (lib/grpc_static_library.bond
|
||||
OPTIONS --apply=compact
|
||||
GRPC)
|
||||
|
||||
add_library (grpc_static_library_lib EXCLUDE_FROM_ALL
|
||||
STATIC
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/grpc_static_library_types.cpp
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/grpc_static_library_apply.cpp)
|
||||
|
||||
add_target_to_folder (grpc_static_library_lib)
|
||||
|
||||
target_link_libraries (grpc_static_library_lib PUBLIC
|
||||
grpc++
|
||||
bond)
|
||||
|
||||
add_bond_test (grpc_static_library_server
|
||||
server/grpc_static_library_server.cpp)
|
||||
|
||||
target_link_libraries (grpc_static_library_server PRIVATE
|
||||
grpc_static_library_lib)
|
||||
|
||||
add_bond_test (grpc_static_library_client
|
||||
client/grpc_static_library_client.cpp)
|
||||
|
||||
target_link_libraries (grpc_static_library_client PRIVATE
|
||||
grpc_static_library_lib)
|
||||
|
||||
# TODO: It feels like the grpc++ target should have this as part of its
|
||||
# interface... Perhaps a patch for upstream?
|
||||
target_include_directories(grpc_static_library_lib
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/grpc/include
|
||||
)
|
||||
target_include_directories(grpc_static_library_server
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/grpc/include
|
||||
)
|
||||
target_include_directories(grpc_static_library_client
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/grpc/include
|
||||
)
|
||||
|
||||
cxx_target_compile_definitions (MSVC grpc_static_library_lib PRIVATE
|
||||
-D_WIN32_WINNT=0x0600)
|
||||
|
||||
cxx_target_compile_definitions (MSVC grpc_static_library_server PRIVATE
|
||||
-D_WIN32_WINNT=0x0600)
|
||||
|
||||
cxx_target_compile_definitions (MSVC grpc_static_library_client PRIVATE
|
||||
-D_WIN32_WINNT=0x0600)
|
|
@ -0,0 +1,71 @@
|
|||
// The program uses a generated Bond service PingPong; however the project
|
||||
// doesn't contain any .bond file. Instead it includes
|
||||
// grpc_static_library_apply.h and grpc_static_library_grpc.h and links to
|
||||
// grpc_static_library.lib which contain definition of PingPong and
|
||||
// pre-built Bond de/serialization code for it. This approach is useful when
|
||||
// multiple projects use the same Bond types; it allows compiling Bond code
|
||||
// once and distributing as a binary .lib file. The static library needs to
|
||||
// be rebuilt only when .bond file (i.e. data schema) changes. Note that the
|
||||
// static library and the programs that consume it have to use the same
|
||||
// version of Bond.
|
||||
//
|
||||
// This program tests the use of the client-side proxies.
|
||||
|
||||
// Must include the _apply.h file to use the pre-compiled routines;
|
||||
// otherwise they'll be expanded again in this compilation unit.
|
||||
#include <grpc_static_library_apply.h>
|
||||
#include <grpc_static_library_reflection.h>
|
||||
#include <grpc_static_library_grpc.h>
|
||||
|
||||
#include <bond/core/bond.h>
|
||||
#include <bond/core/reflection.h>
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/protocol/compact_binary.h>
|
||||
#include <bond/stream/output_buffer.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using grpc::Channel;
|
||||
using grpc::ClientContext;
|
||||
using grpc::Status;
|
||||
|
||||
using namespace examples::grpc_static_library;
|
||||
|
||||
int main()
|
||||
{
|
||||
{ // Serialize and deserialize
|
||||
PingRequest obj;
|
||||
|
||||
obj.Payload = "ping0";
|
||||
|
||||
bond::OutputBuffer buffer;
|
||||
bond::CompactBinaryWriter<bond::OutputBuffer> writer(buffer);
|
||||
bond::Serialize(obj, writer);
|
||||
|
||||
bond::blob data = buffer.GetBuffer();
|
||||
|
||||
PingRequest obj2;
|
||||
|
||||
bond::CompactBinaryReader<bond::InputBuffer> reader(data);
|
||||
bond::Deserialize(reader, obj2);
|
||||
}
|
||||
|
||||
{// Access metadata
|
||||
bond::Metadata myMetadata = PingRequest::Schema::GetMetadata();
|
||||
}
|
||||
|
||||
{ // Initialize proxy
|
||||
const std::string server_address("127.0.0.1:50051");
|
||||
|
||||
auto ioManager = std::make_shared<bond::ext::gRPC::io_manager>();
|
||||
auto threadPool = std::make_shared<bond::ext::gRPC::thread_pool>();
|
||||
|
||||
PingPong::Client client(
|
||||
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()),
|
||||
ioManager,
|
||||
threadPool);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
namespace examples.grpc_static_library
|
||||
|
||||
struct PingRequest
|
||||
{
|
||||
0: string Payload;
|
||||
}
|
||||
|
||||
struct PingResponse
|
||||
{
|
||||
0: string Payload;
|
||||
}
|
||||
|
||||
service PingPong
|
||||
{
|
||||
PingResponse Ping(PingRequest);
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// The program uses a generated Bond service PingPong; however the project
|
||||
// doesn't contain any .bond file. Instead it includes
|
||||
// grpc_static_library_apply.h and grpc_static_library_grpc.h and links to
|
||||
// grpc_static_library.lib which contain definition of PingPong and
|
||||
// pre-built Bond de/serialization code for it. This approach is useful when
|
||||
// multiple projects use the same Bond types; it allows compiling Bond code
|
||||
// once and distributing as a binary .lib file. The static library needs to
|
||||
// be rebuilt only when .bond file (i.e. data schema) changes. Note that the
|
||||
// static library and the programs that consume it have to use the same
|
||||
// version of Bond.
|
||||
//
|
||||
// This program tests the use of the server-side service implementation.
|
||||
|
||||
// Must include the _apply.h file to use the pre-compiled routines;
|
||||
// otherwise they'll be expanded again in this compilation unit.
|
||||
#include <grpc_static_library_apply.h>
|
||||
#include <grpc_static_library_reflection.h>
|
||||
#include <grpc_static_library_grpc.h>
|
||||
|
||||
#include <bond/core/bond.h>
|
||||
#include <bond/core/reflection.h>
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/server.h>
|
||||
#include <bond/ext/grpc/server_builder.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
#include <bond/protocol/compact_binary.h>
|
||||
#include <bond/stream/output_buffer.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
using grpc::Status;
|
||||
using grpc::StatusCode;
|
||||
|
||||
using grpc::Server;
|
||||
using grpc::ServerBuilder;
|
||||
using grpc::ServerContext;
|
||||
|
||||
using namespace examples::grpc_static_library;
|
||||
|
||||
class PingPongServiceImpl final : public PingPong::Service
|
||||
{
|
||||
void Ping(
|
||||
bond::ext::gRPC::unary_call<
|
||||
bond::bonded<::examples::grpc_static_library::PingRequest>,
|
||||
::examples::grpc_static_library::PingResponse> call) override
|
||||
{
|
||||
PingRequest request = call.request().Deserialize();
|
||||
|
||||
PingResponse response;
|
||||
response.Payload = request.Payload;
|
||||
|
||||
call.Finish(response);
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
{ // Serialize and deserialize
|
||||
PingRequest obj;
|
||||
|
||||
obj.Payload = "ping0";
|
||||
|
||||
bond::OutputBuffer buffer;
|
||||
bond::CompactBinaryWriter<bond::OutputBuffer> writer(buffer);
|
||||
bond::Serialize(obj, writer);
|
||||
|
||||
bond::blob data = buffer.GetBuffer();
|
||||
|
||||
PingRequest obj2;
|
||||
|
||||
bond::CompactBinaryReader<bond::InputBuffer> reader(data);
|
||||
bond::Deserialize(reader, obj2);
|
||||
}
|
||||
|
||||
{ // Access metadata
|
||||
bond::Metadata myMetadata = PingRequest::Schema::GetMetadata();
|
||||
}
|
||||
|
||||
{ // Create and start a service
|
||||
PingPongServiceImpl service;
|
||||
|
||||
auto threadPool = std::make_shared<bond::ext::gRPC::thread_pool>();
|
||||
bond::ext::gRPC::server_builder builder;
|
||||
builder.SetThreadPool(threadPool);
|
||||
const std::string server_address("127.0.0.1:50051");
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
||||
builder.RegisterService(&service);
|
||||
std::unique_ptr<bond::ext::gRPC::server> server(builder.BuildAndStart());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
add_bond_test (grpc-helloworld helloworld.bond helloworld.cpp GRPC)
|
||||
|
||||
cxx_target_compile_definitions (MSVC grpc-helloworld PRIVATE -D_WIN32_WINNT=0x0600)
|
||||
|
||||
target_link_libraries(grpc-helloworld PRIVATE grpc++)
|
||||
target_include_directories(grpc-helloworld
|
||||
# TODO: It feels like the grpc++ target should have this as part of its
|
||||
# interface... Perhaps a patch for upstream?
|
||||
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../../../thirdparty/grpc/include
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
namespace helloworld;
|
||||
|
||||
struct HelloRequest
|
||||
{
|
||||
0: string name;
|
||||
}
|
||||
|
||||
struct HelloReply
|
||||
{
|
||||
0: string message;
|
||||
}
|
||||
|
||||
service Greeter
|
||||
{
|
||||
HelloReply SayHello(HelloRequest);
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
#include "helloworld_grpc.h"
|
||||
#include "helloworld_types.h"
|
||||
|
||||
#include <bond/ext/grpc/io_manager.h>
|
||||
#include <bond/ext/grpc/server.h>
|
||||
#include <bond/ext/grpc/server_builder.h>
|
||||
#include <bond/ext/grpc/thread_pool.h>
|
||||
#include <bond/ext/grpc/unary_call.h>
|
||||
#include <bond/ext/grpc/wait_callback.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
using grpc::Channel;
|
||||
using grpc::ClientContext;
|
||||
using grpc::ServerBuilder;
|
||||
using grpc::Status;
|
||||
|
||||
using namespace helloworld;
|
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service
|
||||
{
|
||||
void SayHello(
|
||||
bond::ext::gRPC::unary_call<
|
||||
bond::bonded<HelloRequest>,
|
||||
HelloReply> call) override
|
||||
{
|
||||
HelloRequest request = call.request().Deserialize();
|
||||
|
||||
HelloReply reply;
|
||||
reply.message = "hello " + request.name;
|
||||
|
||||
call.Finish(reply);
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
auto ioManager = std::make_shared<bond::ext::gRPC::io_manager>();
|
||||
auto threadPool = std::make_shared<bond::ext::gRPC::thread_pool>();
|
||||
|
||||
GreeterServiceImpl service;
|
||||
|
||||
bond::ext::gRPC::server_builder builder;
|
||||
builder.SetThreadPool(threadPool);
|
||||
const std::string server_address("127.0.0.1:50051");
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
|
||||
builder.RegisterService(&service);
|
||||
std::unique_ptr<bond::ext::gRPC::server> server(builder.BuildAndStart());
|
||||
|
||||
Greeter::Client greeter(
|
||||
grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()),
|
||||
ioManager,
|
||||
threadPool);
|
||||
|
||||
ClientContext context;
|
||||
|
||||
const std::string user("world");
|
||||
|
||||
HelloRequest request;
|
||||
request.name = user;
|
||||
|
||||
bond::ext::gRPC::wait_callback<HelloReply> cb;
|
||||
greeter.AsyncSayHello(&context, request, cb);
|
||||
|
||||
bool waitResult = cb.wait_for(std::chrono::seconds(10));
|
||||
|
||||
if (!waitResult)
|
||||
{
|
||||
std::cout << "timeout ocurred";
|
||||
return 1;
|
||||
}
|
||||
else if (!cb.status().ok())
|
||||
{
|
||||
std::cout << "request failed";
|
||||
return 1;
|
||||
}
|
||||
|
||||
HelloReply reply;
|
||||
cb.response().Deserialize(reply);
|
||||
|
||||
if (reply.message.compare("hello world") != 0)
|
||||
{
|
||||
std::cout << "Wrong response: " << reply.message;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "Correct response: " << reply.message;
|
||||
return 0;
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче