[c++ grpc] Merge initial gRPC++ support

This commit is contained in:
Christopher Warrington 2017-05-31 14:30:13 -07:00
Родитель f9f2250356 12164849fa
Коммит 4b96096668
113 изменённых файлов: 6666 добавлений и 269 удалений

4
.gitmodules поставляемый
Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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:

Просмотреть файл

@ -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;
}

40
cpp/test/grpc/main.cpp Normal file
Просмотреть файл

@ -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">

Просмотреть файл

@ -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;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше