mirror of https://github.com/grpc/grpc.git
commit
89349eaaae
2034 changed files with 122417 additions and 50460 deletions
@ -1,14 +1,18 @@ |
||||
mergeable: |
||||
pull_requests: |
||||
label: |
||||
or: |
||||
- and: |
||||
and: |
||||
- must_exclude: |
||||
regex: '^disposition/DO NOT MERGE' |
||||
message: 'Pull request marked not mergeable' |
||||
- or: |
||||
- and: |
||||
- must_include: |
||||
regex: 'release notes: yes' |
||||
message: 'Please add the label "release notes: yes"' |
||||
- must_include: |
||||
regex: '^lang\/' |
||||
message: 'Please add a language ("lang/*") label' |
||||
- must_include: |
||||
regex: 'release notes: yes' |
||||
message: 'Please add the label "release notes: yes"' |
||||
- must_include: |
||||
regex: '^lang\/' |
||||
message: 'Please add a language ("lang/*") label' |
||||
- must_include: |
||||
regex: 'release notes: no' |
||||
message: 'Please add the label "release notes: no"' |
||||
regex: 'release notes: no' |
||||
message: 'Please add the label "release notes: no"' |
@ -0,0 +1,100 @@ |
||||
[MASTER] |
||||
ignore= |
||||
src/python/grpcio/grpc/beta, |
||||
src/python/grpcio/grpc/framework, |
||||
src/python/grpcio/grpc/framework/common, |
||||
src/python/grpcio/grpc/framework/foundation, |
||||
src/python/grpcio/grpc/framework/interfaces, |
||||
|
||||
[VARIABLES] |
||||
|
||||
# TODO(https://github.com/PyCQA/pylint/issues/1345): How does the inspection |
||||
# not include "unused_" and "ignored_" by default? |
||||
dummy-variables-rgx=^ignored_|^unused_ |
||||
|
||||
[DESIGN] |
||||
|
||||
# NOTE(nathaniel): Not particularly attached to this value; it just seems to |
||||
# be what works for us at the moment (excepting the dead-code-walking Beta |
||||
# API). |
||||
max-args=6 |
||||
|
||||
[MISCELLANEOUS] |
||||
|
||||
# NOTE(nathaniel): We are big fans of "TODO(<issue link>): " and |
||||
# "NOTE(<username or issue link>): ". We do not allow "TODO:", |
||||
# "TODO(<username>):", "FIXME:", or anything else. |
||||
notes=FIXME,XXX |
||||
|
||||
[MESSAGES CONTROL] |
||||
|
||||
disable= |
||||
# -- START OF EXAMPLE-SPECIFIC SUPPRESSIONS -- |
||||
no-self-use, |
||||
unused-argument, |
||||
unused-variable, |
||||
# -- END OF EXAMPLE-SPECIFIC SUPPRESSIONS -- |
||||
|
||||
# TODO(https://github.com/PyCQA/pylint/issues/59#issuecomment-283774279): |
||||
# Enable cyclic-import after a 1.7-or-later pylint release that |
||||
# recognizes our disable=cyclic-import suppressions. |
||||
cyclic-import, |
||||
# TODO(https://github.com/grpc/grpc/issues/8622): Enable this after the |
||||
# Beta API is removed. |
||||
duplicate-code, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Doesn't seem to |
||||
# understand enum and concurrent.futures; look into this later with the |
||||
# latest pylint version. |
||||
import-error, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Enable this one. |
||||
# Should take a little configuration but not much. |
||||
invalid-name, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): This doesn't seem to |
||||
# work for now? Try with a later pylint? |
||||
locally-disabled, |
||||
# NOTE(nathaniel): What even is this? *Enabling* an inspection results |
||||
# in a warning? How does that encourage more analysis and coverage? |
||||
locally-enabled, |
||||
# NOTE(nathaniel): We don't write doc strings for most private code |
||||
# elements. |
||||
missing-docstring, |
||||
# NOTE(nathaniel): In numeric comparisons it is better to have the |
||||
# lesser (or lesser-or-equal-to) quantity on the left when the |
||||
# expression is true than it is to worry about which is an identifier |
||||
# and which a literal value. |
||||
misplaced-comparison-constant, |
||||
# NOTE(nathaniel): Our completely abstract interface classes don't have |
||||
# constructors. |
||||
no-init, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Doesn't yet play |
||||
# nicely with some of our code being implemented in Cython. Maybe in a |
||||
# later version? |
||||
no-name-in-module, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Suppress these where |
||||
# the odd shape of the authentication portion of the API forces them on |
||||
# us and enable everywhere else. |
||||
protected-access, |
||||
# NOTE(nathaniel): Pylint and I will probably never agree on this. |
||||
too-few-public-methods, |
||||
# NOTE(nathaniel): Pylint and I wil probably never agree on this for |
||||
# private classes. For public classes maybe? |
||||
too-many-instance-attributes, |
||||
# NOTE(nathaniel): Some of our modules have a lot of lines... of |
||||
# specification and documentation. Maybe if this were |
||||
# lines-of-code-based we would use it. |
||||
too-many-lines, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Maybe we could have |
||||
# this one if we extracted just a few more helper functions... |
||||
too-many-nested-blocks, |
||||
# TODO(https://github.com/grpc/grpc/issues/261): Disable unnecessary |
||||
# super-init requirement for abstract class implementations for now. |
||||
super-init-not-called, |
||||
# NOTE(nathaniel): A single statement that always returns program |
||||
# control is better than two statements the first of which sometimes |
||||
# returns program control and the second of which always returns |
||||
# program control. Probably generally, but definitely in the cases of |
||||
# if:/else: and for:/else:. |
||||
useless-else-on-loop, |
||||
no-else-return, |
||||
# NOTE(lidiz): Python 3 make object inheritance default, but not PY2 |
||||
useless-object-inheritance, |
@ -1,30 +0,0 @@ |
||||
{ |
||||
"version": "0.2.0", |
||||
"configurations": [ |
||||
{ |
||||
"type": "node", |
||||
"request": "launch", |
||||
"name": "Mocha Tests", |
||||
"cwd": "${workspaceRoot}", |
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha", |
||||
"windows": { |
||||
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha.cmd" |
||||
}, |
||||
"runtimeArgs": [ |
||||
"-u", |
||||
"tdd", |
||||
"--timeout", |
||||
"999999", |
||||
"--colors", |
||||
"${workspaceRoot}/src/node/test" |
||||
], |
||||
"internalConsoleOptions": "openOnSessionStart" |
||||
}, |
||||
{ |
||||
"type": "node", |
||||
"request": "attach", |
||||
"name": "Attach to Process", |
||||
"port": 5858 |
||||
} |
||||
] |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,45 +1,67 @@ |
||||
workspace(name="com_github_grpc_grpc") |
||||
workspace(name = "com_github_grpc_grpc") |
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") |
||||
load("//bazel:grpc_deps.bzl", "grpc_deps", "grpc_test_only_deps") |
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") |
||||
|
||||
grpc_deps() |
||||
|
||||
grpc_test_only_deps() |
||||
|
||||
new_http_archive( |
||||
name="cython", |
||||
sha256="d68138a2381afbdd0876c3cb2a22389043fa01c4badede1228ee073032b07a27", |
||||
urls=[ |
||||
"https://github.com/cython/cython/archive/c2b80d87658a8525ce091cbe146cb7eaa29fed5c.tar.gz", |
||||
], |
||||
strip_prefix="cython-c2b80d87658a8525ce091cbe146cb7eaa29fed5c", |
||||
build_file="//third_party:cython.BUILD", |
||||
register_execution_platforms( |
||||
"//third_party/toolchains:local", |
||||
"//third_party/toolchains:local_large", |
||||
"//third_party/toolchains:rbe_windows", |
||||
) |
||||
|
||||
load("//third_party/py:python_configure.bzl", "python_configure") |
||||
python_configure(name="local_config_python") |
||||
register_toolchains( |
||||
"//third_party/toolchains/bazel_0.23.2_rbe_windows:cc-toolchain-x64_windows", |
||||
) |
||||
|
||||
git_repository( |
||||
name="io_bazel_rules_python", |
||||
remote="https://github.com/bazelbuild/rules_python.git", |
||||
commit="8b5d0683a7d878b28fffe464779c8a53659fc645", |
||||
name = "io_bazel_rules_python", |
||||
commit = "8b5d0683a7d878b28fffe464779c8a53659fc645", |
||||
remote = "https://github.com/bazelbuild/rules_python.git", |
||||
) |
||||
|
||||
load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories", "pip_import") |
||||
|
||||
pip_repositories() |
||||
pip_import( |
||||
name="grpc_python_dependencies", |
||||
requirements="//:requirements.bazel.txt", |
||||
name = "grpc_python_dependencies", |
||||
requirements = "//:requirements.bazel.txt", |
||||
) |
||||
|
||||
http_archive( |
||||
name = "cython", |
||||
build_file = "//third_party:cython.BUILD", |
||||
sha256 = "d68138a2381afbdd0876c3cb2a22389043fa01c4badede1228ee073032b07a27", |
||||
strip_prefix = "cython-c2b80d87658a8525ce091cbe146cb7eaa29fed5c", |
||||
urls = [ |
||||
"https://github.com/cython/cython/archive/c2b80d87658a8525ce091cbe146cb7eaa29fed5c.tar.gz", |
||||
], |
||||
) |
||||
|
||||
load("@grpc_python_dependencies//:requirements.bzl", "pip_install") |
||||
pip_install() |
||||
load("//bazel:grpc_python_deps.bzl", "grpc_python_deps") |
||||
|
||||
# NOTE(https://github.com/pubref/rules_protobuf/pull/196): Switch to upstream repo after this gets merged. |
||||
git_repository( |
||||
name="org_pubref_rules_protobuf", |
||||
remote="https://github.com/ghostwriternr/rules_protobuf", |
||||
tag="v0.8.2.1-alpha", |
||||
grpc_python_deps() |
||||
|
||||
load("@bazel_toolchains//rules:rbe_repo.bzl", "rbe_autoconfig") |
||||
|
||||
# Create toolchain configuration for remote execution. |
||||
rbe_autoconfig( |
||||
name = "rbe_default", |
||||
) |
||||
|
||||
load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_repositories") |
||||
py_proto_repositories() |
||||
load("@bazel_toolchains//rules:environments.bzl", "clang_env") |
||||
load("@bazel_skylib//lib:dicts.bzl", "dicts") |
||||
|
||||
# Create msan toolchain configuration for remote execution. |
||||
rbe_autoconfig( |
||||
name = "rbe_msan", |
||||
env = dicts.add( |
||||
clang_env(), |
||||
{ |
||||
"BAZEL_LINKOPTS": "-lc++:-lc++abi:-lm", |
||||
}, |
||||
), |
||||
) |
||||
|
@ -1,71 +1,105 @@ |
||||
"""Generates and compiles C++ grpc stubs from proto_library rules.""" |
||||
|
||||
load("//:bazel/generate_cc.bzl", "generate_cc") |
||||
load("//bazel:generate_cc.bzl", "generate_cc") |
||||
load("//bazel:protobuf.bzl", "well_known_proto_libs") |
||||
|
||||
def cc_grpc_library(name, srcs, deps, proto_only, well_known_protos, generate_mocks = False, use_external = False, **kwargs): |
||||
"""Generates C++ grpc classes from a .proto file. |
||||
def cc_grpc_library( |
||||
name, |
||||
srcs, |
||||
deps, |
||||
proto_only = False, |
||||
well_known_protos = False, |
||||
generate_mocks = False, |
||||
use_external = False, |
||||
grpc_only = False, |
||||
**kwargs): |
||||
"""Generates C++ grpc classes for services defined in a proto file. |
||||
|
||||
Assumes the generated classes will be used in cc_api_version = 2. |
||||
If grpc_only is True, this rule is compatible with proto_library and |
||||
cc_proto_library native rules such that it expects proto_library target |
||||
as srcs argument and generates only grpc library classes, expecting |
||||
protobuf messages classes library (cc_proto_library target) to be passed in |
||||
deps argument. By default grpc_only is False which makes this rule to behave |
||||
in a backwards-compatible mode (trying to generate both proto and grpc |
||||
classes). |
||||
|
||||
Arguments: |
||||
name: name of rule. |
||||
srcs: a single proto_library, which wraps the .proto files with services. |
||||
deps: a list of C++ proto_library (or cc_proto_library) which provides |
||||
the compiled code of any message that the services depend on. |
||||
well_known_protos: Should this library additionally depend on well known |
||||
protos |
||||
use_external: When True the grpc deps are prefixed with //external. This |
||||
allows grpc to be used as a dependency in other bazel projects. |
||||
generate_mocks: When True, Google Mock code for client stub is generated. |
||||
**kwargs: rest of arguments, e.g., compatible_with and visibility. |
||||
""" |
||||
if len(srcs) > 1: |
||||
fail("Only one srcs value supported", "srcs") |
||||
Assumes the generated classes will be used in cc_api_version = 2. |
||||
|
||||
proto_target = "_" + name + "_only" |
||||
codegen_target = "_" + name + "_codegen" |
||||
codegen_grpc_target = "_" + name + "_grpc_codegen" |
||||
proto_deps = ["_" + dep + "_only" for dep in deps if dep.find(':') == -1] |
||||
proto_deps += [dep.split(':')[0] + ':' + "_" + dep.split(':')[1] + "_only" for dep in deps if dep.find(':') != -1] |
||||
Args: |
||||
name (str): Name of rule. |
||||
srcs (list): A single .proto file which contains services definitions, |
||||
or if grpc_only parameter is True, a single proto_library which |
||||
contains services descriptors. |
||||
deps (list): A list of C++ proto_library (or cc_proto_library) which |
||||
provides the compiled code of any message that the services depend on. |
||||
proto_only (bool): If True, create only C++ proto classes library, |
||||
avoid creating C++ grpc classes library (expect it in deps). |
||||
Deprecated, use native cc_proto_library instead. False by default. |
||||
well_known_protos (bool): Should this library additionally depend on |
||||
well known protos. Deprecated, the well known protos should be |
||||
specified as explicit dependencies of the proto_library target |
||||
(passed in srcs parameter) instead. False by default. |
||||
generate_mocks (bool): when True, Google Mock code for client stub is |
||||
generated. False by default. |
||||
use_external (bool): Not used. |
||||
grpc_only (bool): if True, generate only grpc library, expecting |
||||
protobuf messages library (cc_proto_library target) to be passed as |
||||
deps. False by default (will become True by default eventually). |
||||
**kwargs: rest of arguments, e.g., compatible_with and visibility |
||||
""" |
||||
if len(srcs) > 1: |
||||
fail("Only one srcs value supported", "srcs") |
||||
if grpc_only and proto_only: |
||||
fail("A mutualy exclusive configuration is specified: grpc_only = True and proto_only = True") |
||||
|
||||
native.proto_library( |
||||
name = proto_target, |
||||
srcs = srcs, |
||||
deps = proto_deps, |
||||
**kwargs |
||||
) |
||||
extra_deps = [] |
||||
proto_targets = [] |
||||
|
||||
generate_cc( |
||||
name = codegen_target, |
||||
srcs = [proto_target], |
||||
well_known_protos = well_known_protos, |
||||
**kwargs |
||||
) |
||||
if not grpc_only: |
||||
proto_target = "_" + name + "_only" |
||||
cc_proto_target = name if proto_only else "_" + name + "_cc_proto" |
||||
|
||||
if not proto_only: |
||||
plugin = "@com_github_grpc_grpc//:grpc_cpp_plugin" |
||||
generate_cc( |
||||
name = codegen_grpc_target, |
||||
srcs = [proto_target], |
||||
plugin = plugin, |
||||
well_known_protos = well_known_protos, |
||||
generate_mocks = generate_mocks, |
||||
**kwargs |
||||
) |
||||
grpc_deps = ["@com_github_grpc_grpc//:grpc++_codegen_proto", |
||||
"//external:protobuf"] |
||||
native.cc_library( |
||||
name = name, |
||||
srcs = [":" + codegen_grpc_target, ":" + codegen_target], |
||||
hdrs = [":" + codegen_grpc_target, ":" + codegen_target], |
||||
deps = deps + grpc_deps, |
||||
**kwargs |
||||
) |
||||
else: |
||||
native.cc_library( |
||||
name = name, |
||||
srcs = [":" + codegen_target], |
||||
hdrs = [":" + codegen_target], |
||||
deps = deps + ["//external:protobuf"], |
||||
**kwargs |
||||
) |
||||
proto_deps = ["_" + dep + "_only" for dep in deps if dep.find(":") == -1] |
||||
proto_deps += [dep.split(":")[0] + ":" + "_" + dep.split(":")[1] + "_only" for dep in deps if dep.find(":") != -1] |
||||
if well_known_protos: |
||||
proto_deps += well_known_proto_libs() |
||||
|
||||
native.proto_library( |
||||
name = proto_target, |
||||
srcs = srcs, |
||||
deps = proto_deps, |
||||
**kwargs |
||||
) |
||||
|
||||
native.cc_proto_library( |
||||
name = cc_proto_target, |
||||
deps = [":" + proto_target], |
||||
**kwargs |
||||
) |
||||
extra_deps.append(":" + cc_proto_target) |
||||
proto_targets.append(proto_target) |
||||
else: |
||||
if not srcs: |
||||
fail("srcs cannot be empty", "srcs") |
||||
proto_targets += srcs |
||||
|
||||
if not proto_only: |
||||
codegen_grpc_target = "_" + name + "_grpc_codegen" |
||||
generate_cc( |
||||
name = codegen_grpc_target, |
||||
srcs = proto_targets, |
||||
plugin = "@com_github_grpc_grpc//:grpc_cpp_plugin", |
||||
well_known_protos = well_known_protos, |
||||
generate_mocks = generate_mocks, |
||||
**kwargs |
||||
) |
||||
|
||||
native.cc_library( |
||||
name = name, |
||||
srcs = [":" + codegen_grpc_target], |
||||
hdrs = [":" + codegen_grpc_target], |
||||
deps = deps + |
||||
extra_deps + |
||||
["@com_github_grpc_grpc//:grpc++_codegen_proto"], |
||||
**kwargs |
||||
) |
||||
|
@ -0,0 +1,8 @@ |
||||
load("//third_party/py:python_configure.bzl", "python_configure") |
||||
load("@io_bazel_rules_python//python:pip.bzl", "pip_repositories") |
||||
load("@grpc_python_dependencies//:requirements.bzl", "pip_install") |
||||
|
||||
def grpc_python_deps(): |
||||
python_configure(name = "local_config_python") |
||||
pip_repositories() |
||||
pip_install() |
@ -0,0 +1,104 @@ |
||||
"""Utility functions for generating protobuf code.""" |
||||
|
||||
_PROTO_EXTENSION = ".proto" |
||||
|
||||
def well_known_proto_libs(): |
||||
return [ |
||||
"@com_google_protobuf//:any_proto", |
||||
"@com_google_protobuf//:api_proto", |
||||
"@com_google_protobuf//:compiler_plugin_proto", |
||||
"@com_google_protobuf//:descriptor_proto", |
||||
"@com_google_protobuf//:duration_proto", |
||||
"@com_google_protobuf//:empty_proto", |
||||
"@com_google_protobuf//:field_mask_proto", |
||||
"@com_google_protobuf//:source_context_proto", |
||||
"@com_google_protobuf//:struct_proto", |
||||
"@com_google_protobuf//:timestamp_proto", |
||||
"@com_google_protobuf//:type_proto", |
||||
"@com_google_protobuf//:wrappers_proto", |
||||
] |
||||
|
||||
def get_proto_root(workspace_root): |
||||
"""Gets the root protobuf directory. |
||||
|
||||
Args: |
||||
workspace_root: context.label.workspace_root |
||||
|
||||
Returns: |
||||
The directory relative to which generated include paths should be. |
||||
""" |
||||
if workspace_root: |
||||
return "/{}".format(workspace_root) |
||||
else: |
||||
return "" |
||||
|
||||
def _strip_proto_extension(proto_filename): |
||||
if not proto_filename.endswith(_PROTO_EXTENSION): |
||||
fail('"{}" does not end with "{}"'.format( |
||||
proto_filename, |
||||
_PROTO_EXTENSION, |
||||
)) |
||||
return proto_filename[:-len(_PROTO_EXTENSION)] |
||||
|
||||
def proto_path_to_generated_filename(proto_path, fmt_str): |
||||
"""Calculates the name of a generated file for a protobuf path. |
||||
|
||||
For example, "examples/protos/helloworld.proto" might map to |
||||
"helloworld.pb.h". |
||||
|
||||
Args: |
||||
proto_path: The path to the .proto file. |
||||
fmt_str: A format string used to calculate the generated filename. For |
||||
example, "{}.pb.h" might be used to calculate a C++ header filename. |
||||
|
||||
Returns: |
||||
The generated filename. |
||||
""" |
||||
return fmt_str.format(_strip_proto_extension(proto_path)) |
||||
|
||||
def _get_include_directory(include): |
||||
directory = include.path |
||||
prefix_len = 0 |
||||
if not include.is_source and directory.startswith(include.root.path): |
||||
prefix_len = len(include.root.path) + 1 |
||||
|
||||
if directory.startswith("external", prefix_len): |
||||
external_separator = directory.find("/", prefix_len) |
||||
repository_separator = directory.find("/", external_separator + 1) |
||||
return directory[:repository_separator] |
||||
else: |
||||
return include.root.path if include.root.path else "." |
||||
|
||||
def get_include_protoc_args(includes): |
||||
"""Returns protoc args that imports protos relative to their import root. |
||||
|
||||
Args: |
||||
includes: A list of included proto files. |
||||
|
||||
Returns: |
||||
A list of arguments to be passed to protoc. For example, ["--proto_path=."]. |
||||
""" |
||||
return [ |
||||
"--proto_path={}".format(_get_include_directory(include)) |
||||
for include in includes |
||||
] |
||||
|
||||
def get_plugin_args(plugin, flags, dir_out, generate_mocks): |
||||
"""Returns arguments configuring protoc to use a plugin for a language. |
||||
|
||||
Args: |
||||
plugin: An executable file to run as the protoc plugin. |
||||
flags: The plugin flags to be passed to protoc. |
||||
dir_out: The output directory for the plugin. |
||||
generate_mocks: A bool indicating whether to generate mocks. |
||||
|
||||
Returns: |
||||
A list of protoc arguments configuring the plugin. |
||||
""" |
||||
augmented_flags = list(flags) |
||||
if generate_mocks: |
||||
augmented_flags.append("generate_mock_code=true") |
||||
return [ |
||||
"--plugin=protoc-gen-PLUGIN=" + plugin.path, |
||||
"--PLUGIN_out=" + ",".join(augmented_flags) + ":" + dir_out, |
||||
] |
@ -0,0 +1,186 @@ |
||||
"""Generates and compiles Python gRPC stubs from proto_library rules.""" |
||||
|
||||
load("@grpc_python_dependencies//:requirements.bzl", "requirement") |
||||
load( |
||||
"//bazel:protobuf.bzl", |
||||
"get_include_protoc_args", |
||||
"get_plugin_args", |
||||
"get_proto_root", |
||||
"proto_path_to_generated_filename", |
||||
) |
||||
|
||||
_GENERATED_PROTO_FORMAT = "{}_pb2.py" |
||||
_GENERATED_GRPC_PROTO_FORMAT = "{}_pb2_grpc.py" |
||||
|
||||
def _get_staged_proto_file(context, source_file): |
||||
if source_file.dirname == context.label.package: |
||||
return source_file |
||||
else: |
||||
copied_proto = context.actions.declare_file(source_file.basename) |
||||
context.actions.run_shell( |
||||
inputs = [source_file], |
||||
outputs = [copied_proto], |
||||
command = "cp {} {}".format(source_file.path, copied_proto.path), |
||||
mnemonic = "CopySourceProto", |
||||
) |
||||
return copied_proto |
||||
|
||||
def _generate_py_impl(context): |
||||
protos = [] |
||||
for src in context.attr.deps: |
||||
for file in src.proto.direct_sources: |
||||
protos.append(_get_staged_proto_file(context, file)) |
||||
includes = [ |
||||
file |
||||
for src in context.attr.deps |
||||
for file in src.proto.transitive_imports |
||||
] |
||||
proto_root = get_proto_root(context.label.workspace_root) |
||||
format_str = (_GENERATED_GRPC_PROTO_FORMAT if context.executable.plugin else _GENERATED_PROTO_FORMAT) |
||||
out_files = [ |
||||
context.actions.declare_file( |
||||
proto_path_to_generated_filename( |
||||
proto.basename, |
||||
format_str, |
||||
), |
||||
) |
||||
for proto in protos |
||||
] |
||||
|
||||
arguments = [] |
||||
tools = [context.executable._protoc] |
||||
if context.executable.plugin: |
||||
arguments += get_plugin_args( |
||||
context.executable.plugin, |
||||
context.attr.flags, |
||||
context.genfiles_dir.path, |
||||
False, |
||||
) |
||||
tools += [context.executable.plugin] |
||||
else: |
||||
arguments += [ |
||||
"--python_out={}:{}".format( |
||||
",".join(context.attr.flags), |
||||
context.genfiles_dir.path, |
||||
), |
||||
] |
||||
|
||||
arguments += get_include_protoc_args(includes) |
||||
arguments += [ |
||||
"--proto_path={}".format(context.genfiles_dir.path) |
||||
for proto in protos |
||||
] |
||||
for proto in protos: |
||||
massaged_path = proto.path |
||||
if massaged_path.startswith(context.genfiles_dir.path): |
||||
massaged_path = proto.path[len(context.genfiles_dir.path) + 1:] |
||||
arguments.append(massaged_path) |
||||
|
||||
well_known_proto_files = [] |
||||
if context.attr.well_known_protos: |
||||
well_known_proto_directory = context.attr.well_known_protos.files.to_list( |
||||
)[0].dirname |
||||
|
||||
arguments += ["-I{}".format(well_known_proto_directory + "/../..")] |
||||
well_known_proto_files = context.attr.well_known_protos.files.to_list() |
||||
|
||||
context.actions.run( |
||||
inputs = protos + includes + well_known_proto_files, |
||||
tools = tools, |
||||
outputs = out_files, |
||||
executable = context.executable._protoc, |
||||
arguments = arguments, |
||||
mnemonic = "ProtocInvocation", |
||||
) |
||||
return struct(files = depset(out_files)) |
||||
|
||||
__generate_py = rule( |
||||
attrs = { |
||||
"deps": attr.label_list( |
||||
mandatory = True, |
||||
allow_empty = False, |
||||
providers = ["proto"], |
||||
), |
||||
"plugin": attr.label( |
||||
executable = True, |
||||
providers = ["files_to_run"], |
||||
cfg = "host", |
||||
), |
||||
"flags": attr.string_list( |
||||
mandatory = False, |
||||
allow_empty = True, |
||||
), |
||||
"well_known_protos": attr.label(mandatory = False), |
||||
"_protoc": attr.label( |
||||
default = Label("//external:protocol_compiler"), |
||||
executable = True, |
||||
cfg = "host", |
||||
), |
||||
}, |
||||
output_to_genfiles = True, |
||||
implementation = _generate_py_impl, |
||||
) |
||||
|
||||
def _generate_py(well_known_protos, **kwargs): |
||||
if well_known_protos: |
||||
__generate_py( |
||||
well_known_protos = "@com_google_protobuf//:well_known_protos", |
||||
**kwargs |
||||
) |
||||
else: |
||||
__generate_py(**kwargs) |
||||
|
||||
def py_proto_library( |
||||
name, |
||||
deps, |
||||
well_known_protos = True, |
||||
proto_only = False, |
||||
**kwargs): |
||||
"""Generate python code for a protobuf. |
||||
|
||||
Args: |
||||
name: The name of the target. |
||||
deps: A list of dependencies. Must contain a single element. |
||||
well_known_protos: A bool indicating whether or not to include well-known |
||||
protos. |
||||
proto_only: A bool indicating whether to generate vanilla protobuf code |
||||
or to also generate gRPC code. |
||||
""" |
||||
if len(deps) > 1: |
||||
fail("The supported length of 'deps' is 1.") |
||||
|
||||
codegen_target = "_{}_codegen".format(name) |
||||
codegen_grpc_target = "_{}_grpc_codegen".format(name) |
||||
|
||||
_generate_py( |
||||
name = codegen_target, |
||||
deps = deps, |
||||
well_known_protos = well_known_protos, |
||||
**kwargs |
||||
) |
||||
|
||||
if not proto_only: |
||||
_generate_py( |
||||
name = codegen_grpc_target, |
||||
deps = deps, |
||||
plugin = "//:grpc_python_plugin", |
||||
well_known_protos = well_known_protos, |
||||
**kwargs |
||||
) |
||||
|
||||
native.py_library( |
||||
name = name, |
||||
srcs = [ |
||||
":{}".format(codegen_grpc_target), |
||||
":{}".format(codegen_target), |
||||
], |
||||
deps = [requirement("protobuf")], |
||||
**kwargs |
||||
) |
||||
else: |
||||
native.py_library( |
||||
name = name, |
||||
srcs = [":{}".format(codegen_target), ":{}".format(codegen_target)], |
||||
deps = [requirement("protobuf")], |
||||
**kwargs |
||||
) |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,22 @@ |
||||
# gRPC Release Schedule |
||||
|
||||
Below is the release schedule for gRPC [Java](https://github.com/grpc/grpc-java/releases), [Go](https://github.com/grpc/grpc-go/releases) and [Core](https://github.com/grpc/grpc/releases) and its dependent languages C++, C#, Objective-C, PHP, Python and Ruby. |
||||
|
||||
Releases are scheduled every six weeks on Tuesdays on a best effort basis. In some unavoidable situations a release may be delayed or a language may skip a release altogether and do the next release to catch up with other languages. See the past releases in the links above. A six-week cycle gives us a good balance between delivering new features/fixes quickly and keeping the release overhead low. |
||||
|
||||
Releases are cut from release branches. For Core and Java repos, the release branch is cut two weeks before the scheduled release date. For Go, the branch is cut just before the release. An RC (release candidate) is published for Core and its dependent languages just after the branch cut. This RC is later promoted to release version if no further changes are made to the release branch. We do our best to keep head of master branch stable at all times regardless of release schedule. Daily build packages from master branch for C#, PHP, Python, Ruby and Protoc plugins are published on [packages.grpc.io](https://packages.grpc.io/). If you depend on gRPC in production we recommend to set up your CI system to test the RCs and, if possible, the daily builds. |
||||
|
||||
Names of gRPC releases are [here](https://github.com/grpc/grpc/blob/master/doc/g_stands_for.md). |
||||
|
||||
Release |Scheduled Branch Cut|Scheduled Release Date |
||||
--------|--------------------|------------- |
||||
v1.17.0 |Nov 19, 2018 |Dec 4, 2018 |
||||
v1.18.0 |Jan 2, 2019 |Jan 15, 2019 |
||||
v1.19.0 |Feb 12, 2019 |Feb 26, 2019 |
||||
v1.20.0 |Mar 26, 2019 |Apr 9, 2019 |
||||
v1.21.0 |May 7, 2019 |May 21, 2019 |
||||
v1.22.0 |Jun 18, 2019 |Jul 2, 2019 |
||||
v1.23.0 |Jul 30, 2019 |Aug 13, 2019 |
||||
v1.24.0 |Sept 10, 2019 |Sept 24, 2019 |
||||
v1.25.0 |Oct 22, 2019 |Nov 5, 2019 |
||||
v1.26.0 |Dec 3, 2019 |Dec 17, 2019 |
@ -0,0 +1,12 @@ |
||||
gRPC Channelz |
||||
==================== |
||||
|
||||
What is gRPC Channelz? |
||||
--------------------------------------------- |
||||
|
||||
Design Document `gRPC Channelz <https://github.com/grpc/proposal/blob/master/A14-channelz.md>`_ |
||||
|
||||
Module Contents |
||||
--------------- |
||||
|
||||
.. automodule:: grpc_channelz.v1.channelz |
@ -0,0 +1,7 @@ |
||||
gRPC Status |
||||
==================== |
||||
|
||||
Module Contents |
||||
--------------- |
||||
|
||||
.. automodule:: grpc_status.rpc_status |
@ -0,0 +1,110 @@ |
||||
#
|
||||
# Copyright 2018 gRPC authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
|
||||
SYSTEM ?= $(HOST_SYSTEM)
|
||||
CXX = g++
|
||||
CPPFLAGS += `pkg-config --cflags protobuf grpc`
|
||||
CXXFLAGS += -std=c++11
|
||||
ifeq ($(SYSTEM),Darwin) |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-lgrpc++_reflection\
|
||||
-ldl
|
||||
else |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
|
||||
-ldl
|
||||
endif |
||||
PROTOC = protoc
|
||||
GRPC_CPP_PLUGIN = grpc_cpp_plugin
|
||||
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
|
||||
|
||||
PROTOS_PATH = ../../protos
|
||||
|
||||
vpath %.proto $(PROTOS_PATH) |
||||
|
||||
all: system-check greeter_client greeter_server |
||||
|
||||
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o |
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
|
||||
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o |
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
|
||||
.PRECIOUS: %.grpc.pb.cc |
||||
%.grpc.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
|
||||
|
||||
.PRECIOUS: %.pb.cc |
||||
%.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
|
||||
|
||||
clean: |
||||
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
|
||||
|
||||
|
||||
# The following is to test your system and ensure a smoother experience.
|
||||
# They are by no means necessary to actually compile a grpc-enabled software.
|
||||
|
||||
PROTOC_CMD = which $(PROTOC)
|
||||
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
|
||||
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
|
||||
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
|
||||
ifeq ($(HAS_PROTOC),true) |
||||
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
|
||||
endif |
||||
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
|
||||
|
||||
SYSTEM_OK = false
|
||||
ifeq ($(HAS_VALID_PROTOC),true) |
||||
ifeq ($(HAS_PLUGIN),true) |
||||
SYSTEM_OK = true
|
||||
endif |
||||
endif |
||||
|
||||
system-check: |
||||
ifneq ($(HAS_VALID_PROTOC),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have protoc 3.0.0 installed in your path."
|
||||
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
|
||||
@echo "You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to evaluate your version of protoc:"
|
||||
@echo
|
||||
-$(PROTOC) --version
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(HAS_PLUGIN),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
|
||||
@echo "Please install grpc. You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/grpc/grpc"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to detect if you have the plugin:"
|
||||
@echo
|
||||
-which $(GRPC_CPP_PLUGIN)
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(SYSTEM_OK),true) |
||||
@false
|
||||
endif |
@ -0,0 +1,84 @@ |
||||
# gRPC C++ Message Compression Tutorial |
||||
|
||||
### Prerequisite |
||||
Make sure you have run the [hello world example](../helloworld) or understood the basics of gRPC. We will not dive into the details that have been discussed in the hello world example. |
||||
|
||||
### Get the tutorial source code |
||||
|
||||
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: |
||||
|
||||
|
||||
```sh |
||||
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc |
||||
``` |
||||
|
||||
Change your current directory to examples/cpp/compression |
||||
|
||||
```sh |
||||
$ cd examples/cpp/compression/ |
||||
``` |
||||
|
||||
### Generating gRPC code |
||||
|
||||
To generate the client and server side interfaces: |
||||
|
||||
```sh |
||||
$ make helloworld.grpc.pb.cc helloworld.pb.cc |
||||
``` |
||||
Which internally invokes the proto-compiler as: |
||||
|
||||
```sh |
||||
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto |
||||
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto |
||||
``` |
||||
|
||||
### Writing a client and a server |
||||
|
||||
The client and the server can be based on the hello world example. |
||||
|
||||
Additionally, we can configure the compression settings. |
||||
|
||||
In the client, set the default compression algorithm of the channel via the channel arg. |
||||
|
||||
```cpp |
||||
ChannelArguments args; |
||||
// Set the default compression algorithm for the channel. |
||||
args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP); |
||||
GreeterClient greeter(grpc::CreateCustomChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args)); |
||||
``` |
||||
|
||||
Each call's compression configuration can be overwritten by client context. |
||||
|
||||
```cpp |
||||
// Overwrite the call's compression algorithm to DEFLATE. |
||||
context.set_compression_algorithm(GRPC_COMPRESS_DEFLATE); |
||||
``` |
||||
|
||||
In the server, set the default compression algorithm via the server builder. |
||||
|
||||
```cpp |
||||
ServerBuilder builder; |
||||
// Set the default compression algorithm for the server. |
||||
builder.SetDefaultCompressionAlgorithm(GRPC_COMPRESS_GZIP); |
||||
``` |
||||
|
||||
Each call's compression configuration can be overwritten by server context. |
||||
|
||||
```cpp |
||||
// Overwrite the call's compression algorithm to DEFLATE. |
||||
context->set_compression_algorithm(GRPC_COMPRESS_DEFLATE); |
||||
``` |
||||
|
||||
For a working example, refer to [greeter_client.cc](greeter_client.cc) and [greeter_server.cc](greeter_server.cc). |
||||
|
||||
Build and run the (compressing) client and the server by the following commands. |
||||
|
||||
```sh |
||||
make |
||||
./greeter_server |
||||
``` |
||||
|
||||
```sh |
||||
./greeter_client |
||||
``` |
@ -0,0 +1,93 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ChannelArguments; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
class GreeterClient { |
||||
public: |
||||
GreeterClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and presents the response back
|
||||
// from the server.
|
||||
std::string SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// Overwrite the call's compression algorithm to DEFLATE.
|
||||
context.set_compression_algorithm(GRPC_COMPRESS_DEFLATE); |
||||
|
||||
// The actual RPC.
|
||||
Status status = stub_->SayHello(&context, request, &reply); |
||||
|
||||
// Act upon its status.
|
||||
if (status.ok()) { |
||||
return reply.message(); |
||||
} else { |
||||
std::cout << status.error_code() << ": " << status.error_message() |
||||
<< std::endl; |
||||
return "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
ChannelArguments args; |
||||
// Set the default compression algorithm for the channel.
|
||||
args.SetCompressionAlgorithm(GRPC_COMPRESS_GZIP); |
||||
GreeterClient greeter(grpc::CreateCustomChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args)); |
||||
std::string user("world"); |
||||
std::string reply = greeter.SayHello(user); |
||||
std::cout << "Greeter received: " << reply << std::endl; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,76 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service { |
||||
Status SayHello(ServerContext* context, const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
// Overwrite the call's compression algorithm to DEFLATE.
|
||||
context->set_compression_algorithm(GRPC_COMPRESS_DEFLATE); |
||||
std::string prefix("Hello "); |
||||
reply->set_message(prefix + request->name()); |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void RunServer() { |
||||
std::string server_address("0.0.0.0:50051"); |
||||
GreeterServiceImpl service; |
||||
|
||||
ServerBuilder builder; |
||||
// Set the default compression algorithm for the server.
|
||||
builder.SetDefaultCompressionAlgorithm(GRPC_COMPRESS_GZIP); |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
RunServer(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,134 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <map> |
||||
|
||||
#include <grpcpp/support/client_interceptor.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/keyvaluestore.grpc.pb.h" |
||||
#else |
||||
#include "keyvaluestore.grpc.pb.h" |
||||
#endif |
||||
|
||||
// This is a naive implementation of a cache. A new cache is for each call. For
|
||||
// each new key request, the key is first searched in the map and if found, the
|
||||
// interceptor fills in the return value without making a request to the server.
|
||||
// Only if the key is not found in the cache do we make a request.
|
||||
class CachingInterceptor : public grpc::experimental::Interceptor { |
||||
public: |
||||
CachingInterceptor(grpc::experimental::ClientRpcInfo* info) {} |
||||
|
||||
void Intercept( |
||||
::grpc::experimental::InterceptorBatchMethods* methods) override { |
||||
bool hijack = false; |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints:: |
||||
PRE_SEND_INITIAL_METADATA)) { |
||||
// Hijack all calls
|
||||
hijack = true; |
||||
// Create a stream on which this interceptor can make requests
|
||||
stub_ = keyvaluestore::KeyValueStore::NewStub( |
||||
methods->GetInterceptedChannel()); |
||||
stream_ = stub_->GetValues(&context_); |
||||
} |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints::PRE_SEND_MESSAGE)) { |
||||
// We know that clients perform a Read and a Write in a loop, so we don't
|
||||
// need to maintain a list of the responses.
|
||||
std::string requested_key; |
||||
const keyvaluestore::Request* req_msg = |
||||
static_cast<const keyvaluestore::Request*>(methods->GetSendMessage()); |
||||
if (req_msg != nullptr) { |
||||
requested_key = req_msg->key(); |
||||
} else { |
||||
// The non-serialized form would not be available in certain scenarios,
|
||||
// so add a fallback
|
||||
keyvaluestore::Request req_msg; |
||||
auto* buffer = methods->GetSerializedSendMessage(); |
||||
auto copied_buffer = *buffer; |
||||
GPR_ASSERT( |
||||
grpc::SerializationTraits<keyvaluestore::Request>::Deserialize( |
||||
&copied_buffer, &req_msg) |
||||
.ok()); |
||||
requested_key = req_msg.key(); |
||||
} |
||||
|
||||
// Check if the key is present in the map
|
||||
auto search = cached_map_.find(requested_key); |
||||
if (search != cached_map_.end()) { |
||||
std::cout << "Key " << requested_key << "found in map"; |
||||
response_ = search->second; |
||||
} else { |
||||
std::cout << "Key " << requested_key << "not found in cache"; |
||||
// Key was not found in the cache, so make a request
|
||||
keyvaluestore::Request req; |
||||
req.set_key(requested_key); |
||||
stream_->Write(req); |
||||
keyvaluestore::Response resp; |
||||
stream_->Read(&resp); |
||||
response_ = resp.value(); |
||||
// Insert the pair in the cache for future requests
|
||||
cached_map_.insert({requested_key, response_}); |
||||
} |
||||
} |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints::PRE_SEND_CLOSE)) { |
||||
stream_->WritesDone(); |
||||
} |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints::PRE_RECV_MESSAGE)) { |
||||
keyvaluestore::Response* resp = |
||||
static_cast<keyvaluestore::Response*>(methods->GetRecvMessage()); |
||||
resp->set_value(response_); |
||||
} |
||||
if (methods->QueryInterceptionHookPoint( |
||||
grpc::experimental::InterceptionHookPoints::PRE_RECV_STATUS)) { |
||||
auto* status = methods->GetRecvStatus(); |
||||
*status = grpc::Status::OK; |
||||
} |
||||
// One of Hijack or Proceed always needs to be called to make progress.
|
||||
if (hijack) { |
||||
// Hijack is called only once when PRE_SEND_INITIAL_METADATA is present in
|
||||
// the hook points
|
||||
methods->Hijack(); |
||||
} else { |
||||
// Proceed is an indicator that the interceptor is done intercepting the
|
||||
// batch.
|
||||
methods->Proceed(); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
grpc::ClientContext context_; |
||||
std::unique_ptr<keyvaluestore::KeyValueStore::Stub> stub_; |
||||
std::unique_ptr< |
||||
grpc::ClientReaderWriter<keyvaluestore::Request, keyvaluestore::Response>> |
||||
stream_; |
||||
std::map<std::string, std::string> cached_map_; |
||||
std::string response_; |
||||
}; |
||||
|
||||
class CachingInterceptorFactory |
||||
: public grpc::experimental::ClientInterceptorFactoryInterface { |
||||
public: |
||||
grpc::experimental::Interceptor* CreateClientInterceptor( |
||||
grpc::experimental::ClientRpcInfo* info) override { |
||||
return new CachingInterceptor(info); |
||||
} |
||||
}; |
@ -0,0 +1,99 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#include "caching_interceptor.h" |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/keyvaluestore.grpc.pb.h" |
||||
#else |
||||
#include "keyvaluestore.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using keyvaluestore::KeyValueStore; |
||||
using keyvaluestore::Request; |
||||
using keyvaluestore::Response; |
||||
|
||||
class KeyValueStoreClient { |
||||
public: |
||||
KeyValueStoreClient(std::shared_ptr<Channel> channel) |
||||
: stub_(KeyValueStore::NewStub(channel)) {} |
||||
|
||||
// Requests each key in the vector and displays the key and its corresponding
|
||||
// value as a pair
|
||||
void GetValues(const std::vector<std::string>& keys) { |
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
auto stream = stub_->GetValues(&context); |
||||
for (const auto& key : keys) { |
||||
// Key we are sending to the server.
|
||||
Request request; |
||||
request.set_key(key); |
||||
stream->Write(request); |
||||
|
||||
// Get the value for the sent key
|
||||
Response response; |
||||
stream->Read(&response); |
||||
std::cout << key << " : " << response.value() << "\n"; |
||||
} |
||||
stream->WritesDone(); |
||||
Status status = stream->Finish(); |
||||
if (!status.ok()) { |
||||
std::cout << status.error_code() << ": " << status.error_message() |
||||
<< std::endl; |
||||
std::cout << "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<KeyValueStore::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
// In this example, we are using a cache which has been added in as an
|
||||
// interceptor.
|
||||
grpc::ChannelArguments args; |
||||
std::vector< |
||||
std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>> |
||||
interceptor_creators; |
||||
interceptor_creators.push_back(std::unique_ptr<CachingInterceptorFactory>( |
||||
new CachingInterceptorFactory())); |
||||
auto channel = grpc::experimental::CreateCustomChannelWithInterceptors( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args, |
||||
std::move(interceptor_creators)); |
||||
KeyValueStoreClient client(channel); |
||||
std::vector<std::string> keys = {"key1", "key2", "key3", "key4", |
||||
"key5", "key1", "key2", "key4"}; |
||||
client.GetValues(keys); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,97 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/keyvaluestore.grpc.pb.h" |
||||
#else |
||||
#include "keyvaluestore.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::ServerReaderWriter; |
||||
using grpc::Status; |
||||
using keyvaluestore::KeyValueStore; |
||||
using keyvaluestore::Request; |
||||
using keyvaluestore::Response; |
||||
|
||||
struct kv_pair { |
||||
const char* key; |
||||
const char* value; |
||||
}; |
||||
|
||||
static const kv_pair kvs_map[] = { |
||||
{"key1", "value1"}, {"key2", "value2"}, {"key3", "value3"}, |
||||
{"key4", "value4"}, {"key5", "value5"}, |
||||
}; |
||||
|
||||
const char* get_value_from_map(const char* key) { |
||||
for (size_t i = 0; i < sizeof(kvs_map) / sizeof(kv_pair); ++i) { |
||||
if (strcmp(key, kvs_map[i].key) == 0) { |
||||
return kvs_map[i].value; |
||||
} |
||||
} |
||||
return ""; |
||||
} |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class KeyValueStoreServiceImpl final : public KeyValueStore::Service { |
||||
Status GetValues(ServerContext* context, |
||||
ServerReaderWriter<Response, Request>* stream) override { |
||||
Request request; |
||||
while (stream->Read(&request)) { |
||||
Response response; |
||||
response.set_value(get_value_from_map(request.key().c_str())); |
||||
stream->Write(response); |
||||
} |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void RunServer() { |
||||
std::string server_address("0.0.0.0:50051"); |
||||
KeyValueStoreServiceImpl service; |
||||
|
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case, it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
RunServer(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,110 @@ |
||||
#
|
||||
# Copyright 2018 gRPC authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
|
||||
SYSTEM ?= $(HOST_SYSTEM)
|
||||
CXX = g++
|
||||
CPPFLAGS += `pkg-config --cflags protobuf grpc`
|
||||
CXXFLAGS += -std=c++11
|
||||
ifeq ($(SYSTEM),Darwin) |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-lgrpc++_reflection\
|
||||
-ldl
|
||||
else |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
|
||||
-ldl
|
||||
endif |
||||
PROTOC = protoc
|
||||
GRPC_CPP_PLUGIN = grpc_cpp_plugin
|
||||
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
|
||||
|
||||
PROTOS_PATH = ../../protos
|
||||
|
||||
vpath %.proto $(PROTOS_PATH) |
||||
|
||||
all: system-check greeter_client greeter_server |
||||
|
||||
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o |
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
|
||||
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o |
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
|
||||
.PRECIOUS: %.grpc.pb.cc |
||||
%.grpc.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
|
||||
|
||||
.PRECIOUS: %.pb.cc |
||||
%.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
|
||||
|
||||
clean: |
||||
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
|
||||
|
||||
|
||||
# The following is to test your system and ensure a smoother experience.
|
||||
# They are by no means necessary to actually compile a grpc-enabled software.
|
||||
|
||||
PROTOC_CMD = which $(PROTOC)
|
||||
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
|
||||
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
|
||||
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
|
||||
ifeq ($(HAS_PROTOC),true) |
||||
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
|
||||
endif |
||||
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
|
||||
|
||||
SYSTEM_OK = false
|
||||
ifeq ($(HAS_VALID_PROTOC),true) |
||||
ifeq ($(HAS_PLUGIN),true) |
||||
SYSTEM_OK = true
|
||||
endif |
||||
endif |
||||
|
||||
system-check: |
||||
ifneq ($(HAS_VALID_PROTOC),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have protoc 3.0.0 installed in your path."
|
||||
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
|
||||
@echo "You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to evaluate your version of protoc:"
|
||||
@echo
|
||||
-$(PROTOC) --version
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(HAS_PLUGIN),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
|
||||
@echo "Please install grpc. You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/grpc/grpc"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to detect if you have the plugin:"
|
||||
@echo
|
||||
-which $(GRPC_CPP_PLUGIN)
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(SYSTEM_OK),true) |
||||
@false
|
||||
endif |
@ -0,0 +1,64 @@ |
||||
# gRPC C++ Load Balancing Tutorial |
||||
|
||||
### Prerequisite |
||||
Make sure you have run the [hello world example](../helloworld) or understood the basics of gRPC. We will not dive into the details that have been discussed in the hello world example. |
||||
|
||||
### Get the tutorial source code |
||||
|
||||
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: |
||||
|
||||
|
||||
```sh |
||||
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc |
||||
``` |
||||
|
||||
Change your current directory to examples/cpp/load_balancing |
||||
|
||||
```sh |
||||
$ cd examples/cpp/load_balancing/ |
||||
``` |
||||
|
||||
### Generating gRPC code |
||||
|
||||
To generate the client and server side interfaces: |
||||
|
||||
```sh |
||||
$ make helloworld.grpc.pb.cc helloworld.pb.cc |
||||
``` |
||||
Which internally invokes the proto-compiler as: |
||||
|
||||
```sh |
||||
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto |
||||
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto |
||||
``` |
||||
|
||||
### Writing a client and a server |
||||
|
||||
The client and the server can be based on the hello world example. |
||||
|
||||
Additionally, we can configure the load balancing policy. (To see what load balancing policies are available, check out [this folder](https://github.com/grpc/grpc/tree/master/src/core/ext/filters/client_channel/lb_policy).) |
||||
|
||||
In the client, set the load balancing policy of the channel via the channel arg (to, for example, Round Robin). |
||||
|
||||
```cpp |
||||
ChannelArguments args; |
||||
// Set the load balancing policy for the channel. |
||||
args.SetLoadBalancingPolicyName("round_robin"); |
||||
GreeterClient greeter(grpc::CreateCustomChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args)); |
||||
``` |
||||
|
||||
For a working example, refer to [greeter_client.cc](greeter_client.cc) and [greeter_server.cc](greeter_server.cc). |
||||
|
||||
Build and run the client and the server with the following commands. |
||||
|
||||
```sh |
||||
make |
||||
./greeter_server |
||||
``` |
||||
|
||||
```sh |
||||
./greeter_client |
||||
``` |
||||
|
||||
(Note that the case in this example is trivial because there is only one server resolved from the name.) |
@ -0,0 +1,90 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ChannelArguments; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
class GreeterClient { |
||||
public: |
||||
GreeterClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and presents the response back
|
||||
// from the server.
|
||||
std::string SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// The actual RPC.
|
||||
Status status = stub_->SayHello(&context, request, &reply); |
||||
|
||||
// Act upon its status.
|
||||
if (status.ok()) { |
||||
return reply.message(); |
||||
} else { |
||||
std::cout << status.error_code() << ": " << status.error_message() |
||||
<< std::endl; |
||||
return "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
ChannelArguments args; |
||||
// Set the load balancing policy for the channel.
|
||||
args.SetLoadBalancingPolicyName("round_robin"); |
||||
GreeterClient greeter(grpc::CreateCustomChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials(), args)); |
||||
std::string user("world"); |
||||
std::string reply = greeter.SayHello(user); |
||||
std::cout << "Greeter received: " << reply << std::endl; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,72 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service { |
||||
Status SayHello(ServerContext* context, const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
std::string prefix("Hello "); |
||||
reply->set_message(prefix + request->name()); |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void RunServer() { |
||||
std::string server_address("0.0.0.0:50051"); |
||||
GreeterServiceImpl service; |
||||
|
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
RunServer(); |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,96 @@ |
||||
#
|
||||
# Copyright 2018 gRPC authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
|
||||
SYSTEM ?= $(HOST_SYSTEM)
|
||||
CXX = g++
|
||||
CPPFLAGS += `pkg-config --cflags protobuf grpc`
|
||||
CXXFLAGS += -std=c++11
|
||||
ifeq ($(SYSTEM),Darwin) |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-lgrpc++_reflection\
|
||||
-ldl
|
||||
else |
||||
LDFLAGS += -L/usr/local/lib `pkg-config --libs protobuf grpc++ grpc`\
|
||||
-Wl,--no-as-needed -lgrpc++_reflection -Wl,--as-needed\
|
||||
-ldl
|
||||
endif |
||||
PROTOC = protoc
|
||||
GRPC_CPP_PLUGIN = grpc_cpp_plugin
|
||||
GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)`
|
||||
PROTOS_PATH = ../../protos
|
||||
vpath %.proto $(PROTOS_PATH)
|
||||
all: system-check greeter_client greeter_server
|
||||
greeter_client: helloworld.pb.o helloworld.grpc.pb.o greeter_client.o
|
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
greeter_server: helloworld.pb.o helloworld.grpc.pb.o greeter_server.o
|
||||
$(CXX) $^ $(LDFLAGS) -o $@
|
||||
.PRECIOUS: %.grpc.pb.cc
|
||||
%.grpc.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $<
|
||||
.PRECIOUS: %.pb.cc
|
||||
%.pb.cc: %.proto |
||||
$(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $<
|
||||
clean:
|
||||
rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server
|
||||
# The following is to test your system and ensure a smoother experience.
|
||||
# They are by no means necessary to actually compile a grpc-enabled software.
|
||||
PROTOC_CMD = which $(PROTOC)
|
||||
PROTOC_CHECK_CMD = $(PROTOC) --version | grep -q libprotoc.3
|
||||
PLUGIN_CHECK_CMD = which $(GRPC_CPP_PLUGIN)
|
||||
HAS_PROTOC = $(shell $(PROTOC_CMD) > /dev/null && echo true || echo false)
|
||||
ifeq ($(HAS_PROTOC),true) |
||||
HAS_VALID_PROTOC = $(shell $(PROTOC_CHECK_CMD) 2> /dev/null && echo true || echo false)
|
||||
endif |
||||
HAS_PLUGIN = $(shell $(PLUGIN_CHECK_CMD) > /dev/null && echo true || echo false)
|
||||
SYSTEM_OK = false
|
||||
ifeq ($(HAS_VALID_PROTOC),true) |
||||
ifeq ($(HAS_PLUGIN),true) |
||||
SYSTEM_OK = true
|
||||
endif |
||||
endif |
||||
system-check:
|
||||
ifneq ($(HAS_VALID_PROTOC),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have protoc 3.0.0 installed in your path."
|
||||
@echo "Please install Google protocol buffers 3.0.0 and its compiler."
|
||||
@echo "You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/google/protobuf/releases/tag/v3.0.0"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to evaluate your version of protoc:"
|
||||
@echo
|
||||
-$(PROTOC) --version
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(HAS_PLUGIN),true) |
||||
@echo " DEPENDENCY ERROR"
|
||||
@echo
|
||||
@echo "You don't have the grpc c++ protobuf plugin installed in your path."
|
||||
@echo "Please install grpc. You can find it here:"
|
||||
@echo
|
||||
@echo " https://github.com/grpc/grpc"
|
||||
@echo
|
||||
@echo "Here is what I get when trying to detect if you have the plugin:"
|
||||
@echo
|
||||
-which $(GRPC_CPP_PLUGIN)
|
||||
@echo
|
||||
@echo
|
||||
endif |
||||
ifneq ($(SYSTEM_OK),true) |
||||
@false
|
||||
endif |
@ -0,0 +1,66 @@ |
||||
# Metadata Example |
||||
|
||||
## Overview |
||||
|
||||
This example shows you how to add custom headers on the client and server and |
||||
how to access them. |
||||
|
||||
Custom metadata must follow the "Custom-Metadata" format listed in |
||||
https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md, with the |
||||
exception of binary headers, which don't have to be base64 encoded. |
||||
|
||||
### Get the tutorial source code |
||||
The example code for this and our other examples lives in the `examples` directory. Clone this repository to your local machine by running the following command: |
||||
```sh |
||||
$ git clone -b $(curl -L https://grpc.io/release) https://github.com/grpc/grpc |
||||
``` |
||||
Change your current directory to examples/cpp/metadata |
||||
```sh |
||||
$ cd examples/cpp/metadata |
||||
``` |
||||
|
||||
### Generating gRPC code |
||||
To generate the client and server side interfaces: |
||||
```sh |
||||
$ make helloworld.grpc.pb.cc helloworld.pb.cc |
||||
``` |
||||
Which internally invokes the proto-compiler as: |
||||
```sh |
||||
$ protoc -I ../../protos/ --grpc_out=. --plugin=protoc-gen-grpc=grpc_cpp_plugin ../../protos/helloworld.proto |
||||
$ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto |
||||
``` |
||||
### Try it! |
||||
Build client and server: |
||||
|
||||
```sh |
||||
$ make |
||||
``` |
||||
|
||||
Run the server, which will listen on port 50051: |
||||
|
||||
```sh |
||||
$ ./greeter_server |
||||
``` |
||||
|
||||
Run the client (in a different terminal): |
||||
|
||||
```sh |
||||
$ ./greeter_client |
||||
``` |
||||
|
||||
If things go smoothly, you will see in the client terminal: |
||||
|
||||
"Client received initial metadata from server: initial metadata value" |
||||
"Client received trailing metadata from server: trailing metadata value" |
||||
"Client received message: Hello World" |
||||
|
||||
|
||||
And in the server terminal: |
||||
|
||||
"Header key: custom-bin , value: 01234567" |
||||
"Header key: custom-header , value: Custom Value" |
||||
"Header key: user-agent , value: grpc-c++/1.16.0-dev grpc-c/6.0.0-dev (linux; chttp2; gao)" |
||||
|
||||
We did not add the user-agent metadata as a custom header. This shows how |
||||
the gRPC framework adds some headers under the hood that may show up in the |
||||
metadata map. |
@ -0,0 +1,95 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Channel; |
||||
using grpc::ClientContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
class CustomHeaderClient { |
||||
public: |
||||
CustomHeaderClient(std::shared_ptr<Channel> channel) |
||||
: stub_(Greeter::NewStub(channel)) {} |
||||
|
||||
// Assembles the client's payload, sends it and presents the response back
|
||||
// from the server.
|
||||
std::string SayHello(const std::string& user) { |
||||
// Data we are sending to the server.
|
||||
HelloRequest request; |
||||
request.set_name(user); |
||||
|
||||
// Container for the data we expect from the server.
|
||||
HelloReply reply; |
||||
|
||||
// Context for the client. It could be used to convey extra information to
|
||||
// the server and/or tweak certain RPC behaviors.
|
||||
ClientContext context; |
||||
|
||||
// Setting custom metadata to be sent to the server
|
||||
context.AddMetadata("custom-header", "Custom Value"); |
||||
|
||||
// Setting custom binary metadata
|
||||
char bytes[8] = {'\0', '\1', '\2', '\3', |
||||
'\4', '\5', '\6', '\7'}; |
||||
context.AddMetadata("custom-bin", grpc::string(bytes, 8)); |
||||
|
||||
// The actual RPC.
|
||||
Status status = stub_->SayHello(&context, request, &reply); |
||||
|
||||
// Act upon its status.
|
||||
if (status.ok()) { |
||||
std::cout << "Client received initial metadata from server: " << context.GetServerInitialMetadata().find("custom-server-metadata")->second << std::endl; |
||||
std::cout << "Client received trailing metadata from server: " << context.GetServerTrailingMetadata().find("custom-trailing-metadata")->second << std::endl; |
||||
return reply.message(); |
||||
} else { |
||||
std::cout << status.error_code() << ": " << status.error_message() |
||||
<< std::endl; |
||||
return "RPC failed"; |
||||
} |
||||
} |
||||
|
||||
private: |
||||
std::unique_ptr<Greeter::Stub> stub_; |
||||
}; |
||||
|
||||
int main(int argc, char** argv) { |
||||
// Instantiate the client. It requires a channel, out of which the actual RPCs
|
||||
// are created. This channel models a connection to an endpoint (in this case,
|
||||
// localhost at port 50051). We indicate that the channel isn't authenticated
|
||||
// (use of InsecureChannelCredentials()).
|
||||
CustomHeaderClient greeter(grpc::CreateChannel( |
||||
"localhost:50051", grpc::InsecureChannelCredentials())); |
||||
std::string user("world"); |
||||
std::string reply = greeter.SayHello(user); |
||||
std::cout << "Client received message: " << reply << std::endl; |
||||
return 0; |
||||
} |
@ -0,0 +1,94 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2015 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <iostream> |
||||
#include <memory> |
||||
#include <string> |
||||
|
||||
#include <grpcpp/grpcpp.h> |
||||
|
||||
#ifdef BAZEL_BUILD |
||||
#include "examples/protos/helloworld.grpc.pb.h" |
||||
#else |
||||
#include "helloworld.grpc.pb.h" |
||||
#endif |
||||
|
||||
using grpc::Server; |
||||
using grpc::ServerBuilder; |
||||
using grpc::ServerContext; |
||||
using grpc::Status; |
||||
using helloworld::HelloRequest; |
||||
using helloworld::HelloReply; |
||||
using helloworld::Greeter; |
||||
|
||||
// Logic and data behind the server's behavior.
|
||||
class GreeterServiceImpl final : public Greeter::Service { |
||||
Status SayHello(ServerContext* context, const HelloRequest* request, |
||||
HelloReply* reply) override { |
||||
std::string prefix("Hello "); |
||||
|
||||
// Get the client's initial metadata
|
||||
std::cout << "Client metadata: " << std::endl; |
||||
const std::multimap<grpc::string_ref, grpc::string_ref> metadata = context->client_metadata(); |
||||
for (auto iter = metadata.begin(); iter != metadata.end(); ++iter) { |
||||
std::cout << "Header key: " << iter->first << ", value: "; |
||||
// Check for binary value
|
||||
size_t isbin = iter->first.find("-bin"); |
||||
if ((isbin != std::string::npos) && (isbin + 4 == iter->first.size())) { |
||||
std::cout << std::hex; |
||||
for (auto c : iter->second) { |
||||
std::cout << static_cast<unsigned int>(c); |
||||
} |
||||
std::cout << std::dec; |
||||
} else { |
||||
std::cout << iter->second; |
||||
} |
||||
std::cout << std::endl; |
||||
} |
||||
|
||||
context->AddInitialMetadata("custom-server-metadata", "initial metadata value"); |
||||
context->AddTrailingMetadata("custom-trailing-metadata", "trailing metadata value"); |
||||
reply->set_message(prefix + request->name()); |
||||
return Status::OK; |
||||
} |
||||
}; |
||||
|
||||
void RunServer() { |
||||
std::string server_address("0.0.0.0:50051"); |
||||
GreeterServiceImpl service; |
||||
|
||||
ServerBuilder builder; |
||||
// Listen on the given address without any authentication mechanism.
|
||||
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); |
||||
// Register "service" as the instance through which we'll communicate with
|
||||
// clients. In this case it corresponds to an *synchronous* service.
|
||||
builder.RegisterService(&service); |
||||
// Finally assemble the server.
|
||||
std::unique_ptr<Server> server(builder.BuildAndStart()); |
||||
std::cout << "Server listening on " << server_address << std::endl; |
||||
|
||||
// Wait for the server to shutdown. Note that some other thread must be
|
||||
// responsible for shutting down the server for this call to ever return.
|
||||
server->Wait(); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
RunServer(); |
||||
|
||||
return 0; |
||||
} |
@ -1,5 +1,7 @@ |
||||
.vs/ |
||||
bin/ |
||||
obj/ |
||||
packages/ |
||||
*.suo |
||||
*.user |
||||
*.userprefs |
||||
|
@ -1,312 +0,0 @@ |
||||
// <auto-generated> |
||||
// Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
// source: helloworld.proto |
||||
// </auto-generated> |
||||
#pragma warning disable 1591, 0612, 3021 |
||||
#region Designer generated code |
||||
|
||||
using pb = global::Google.Protobuf; |
||||
using pbc = global::Google.Protobuf.Collections; |
||||
using pbr = global::Google.Protobuf.Reflection; |
||||
using scg = global::System.Collections.Generic; |
||||
namespace Helloworld { |
||||
|
||||
/// <summary>Holder for reflection information generated from helloworld.proto</summary> |
||||
public static partial class HelloworldReflection { |
||||
|
||||
#region Descriptor |
||||
/// <summary>File descriptor for helloworld.proto</summary> |
||||
public static pbr::FileDescriptor Descriptor { |
||||
get { return descriptor; } |
||||
} |
||||
private static pbr::FileDescriptor descriptor; |
||||
|
||||
static HelloworldReflection() { |
||||
byte[] descriptorData = global::System.Convert.FromBase64String( |
||||
string.Concat( |
||||
"ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIhwKDEhlbGxvUmVxdWVz", |
||||
"dBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEo", |
||||
"CTJJCgdHcmVldGVyEj4KCFNheUhlbGxvEhguaGVsbG93b3JsZC5IZWxsb1Jl", |
||||
"cXVlc3QaFi5oZWxsb3dvcmxkLkhlbGxvUmVwbHkiAEI2Chtpby5ncnBjLmV4", |
||||
"YW1wbGVzLmhlbGxvd29ybGRCD0hlbGxvV29ybGRQcm90b1ABogIDSExXYgZw", |
||||
"cm90bzM=")); |
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, |
||||
new pbr::FileDescriptor[] { }, |
||||
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { |
||||
new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloRequest), global::Helloworld.HelloRequest.Parser, new[]{ "Name" }, null, null, null), |
||||
new pbr::GeneratedClrTypeInfo(typeof(global::Helloworld.HelloReply), global::Helloworld.HelloReply.Parser, new[]{ "Message" }, null, null, null) |
||||
})); |
||||
} |
||||
#endregion |
||||
|
||||
} |
||||
#region Messages |
||||
/// <summary> |
||||
/// The request message containing the user's name. |
||||
/// </summary> |
||||
public sealed partial class HelloRequest : pb::IMessage<HelloRequest> { |
||||
private static readonly pb::MessageParser<HelloRequest> _parser = new pb::MessageParser<HelloRequest>(() => new HelloRequest()); |
||||
private pb::UnknownFieldSet _unknownFields; |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public static pb::MessageParser<HelloRequest> Parser { get { return _parser; } } |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[0]; } |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public HelloRequest() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public HelloRequest(HelloRequest other) : this() { |
||||
name_ = other.name_; |
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public HelloRequest Clone() { |
||||
return new HelloRequest(this); |
||||
} |
||||
|
||||
/// <summary>Field number for the "name" field.</summary> |
||||
public const int NameFieldNumber = 1; |
||||
private string name_ = ""; |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public string Name { |
||||
get { return name_; } |
||||
set { |
||||
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); |
||||
} |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public override bool Equals(object other) { |
||||
return Equals(other as HelloRequest); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public bool Equals(HelloRequest other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (Name != other.Name) return false; |
||||
return Equals(_unknownFields, other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (Name.Length != 0) hash ^= Name.GetHashCode(); |
||||
if (_unknownFields != null) { |
||||
hash ^= _unknownFields.GetHashCode(); |
||||
} |
||||
return hash; |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public override string ToString() { |
||||
return pb::JsonFormatter.ToDiagnosticString(this); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
if (Name.Length != 0) { |
||||
output.WriteRawTag(10); |
||||
output.WriteString(Name); |
||||
} |
||||
if (_unknownFields != null) { |
||||
_unknownFields.WriteTo(output); |
||||
} |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (Name.Length != 0) { |
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); |
||||
} |
||||
if (_unknownFields != null) { |
||||
size += _unknownFields.CalculateSize(); |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public void MergeFrom(HelloRequest other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
if (other.Name.Length != 0) { |
||||
Name = other.Name; |
||||
} |
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); |
||||
break; |
||||
case 10: { |
||||
Name = input.ReadString(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/// <summary> |
||||
/// The response message containing the greetings |
||||
/// </summary> |
||||
public sealed partial class HelloReply : pb::IMessage<HelloReply> { |
||||
private static readonly pb::MessageParser<HelloReply> _parser = new pb::MessageParser<HelloReply>(() => new HelloReply()); |
||||
private pb::UnknownFieldSet _unknownFields; |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public static pb::MessageParser<HelloReply> Parser { get { return _parser; } } |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public static pbr::MessageDescriptor Descriptor { |
||||
get { return global::Helloworld.HelloworldReflection.Descriptor.MessageTypes[1]; } |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
pbr::MessageDescriptor pb::IMessage.Descriptor { |
||||
get { return Descriptor; } |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public HelloReply() { |
||||
OnConstruction(); |
||||
} |
||||
|
||||
partial void OnConstruction(); |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public HelloReply(HelloReply other) : this() { |
||||
message_ = other.message_; |
||||
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public HelloReply Clone() { |
||||
return new HelloReply(this); |
||||
} |
||||
|
||||
/// <summary>Field number for the "message" field.</summary> |
||||
public const int MessageFieldNumber = 1; |
||||
private string message_ = ""; |
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public string Message { |
||||
get { return message_; } |
||||
set { |
||||
message_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); |
||||
} |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public override bool Equals(object other) { |
||||
return Equals(other as HelloReply); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public bool Equals(HelloReply other) { |
||||
if (ReferenceEquals(other, null)) { |
||||
return false; |
||||
} |
||||
if (ReferenceEquals(other, this)) { |
||||
return true; |
||||
} |
||||
if (Message != other.Message) return false; |
||||
return Equals(_unknownFields, other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public override int GetHashCode() { |
||||
int hash = 1; |
||||
if (Message.Length != 0) hash ^= Message.GetHashCode(); |
||||
if (_unknownFields != null) { |
||||
hash ^= _unknownFields.GetHashCode(); |
||||
} |
||||
return hash; |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public override string ToString() { |
||||
return pb::JsonFormatter.ToDiagnosticString(this); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public void WriteTo(pb::CodedOutputStream output) { |
||||
if (Message.Length != 0) { |
||||
output.WriteRawTag(10); |
||||
output.WriteString(Message); |
||||
} |
||||
if (_unknownFields != null) { |
||||
_unknownFields.WriteTo(output); |
||||
} |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public int CalculateSize() { |
||||
int size = 0; |
||||
if (Message.Length != 0) { |
||||
size += 1 + pb::CodedOutputStream.ComputeStringSize(Message); |
||||
} |
||||
if (_unknownFields != null) { |
||||
size += _unknownFields.CalculateSize(); |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public void MergeFrom(HelloReply other) { |
||||
if (other == null) { |
||||
return; |
||||
} |
||||
if (other.Message.Length != 0) { |
||||
Message = other.Message; |
||||
} |
||||
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); |
||||
} |
||||
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute] |
||||
public void MergeFrom(pb::CodedInputStream input) { |
||||
uint tag; |
||||
while ((tag = input.ReadTag()) != 0) { |
||||
switch(tag) { |
||||
default: |
||||
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); |
||||
break; |
||||
case 10: { |
||||
Message = input.ReadString(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
#endregion |
||||
|
||||
} |
||||
|
||||
#endregion Designer generated code |
@ -1,28 +0,0 @@ |
||||
@rem Copyright 2016 gRPC authors. |
||||
@rem |
||||
@rem Licensed under the Apache License, Version 2.0 (the "License"); |
||||
@rem you may not use this file except in compliance with the License. |
||||
@rem You may obtain a copy of the License at |
||||
@rem |
||||
@rem http://www.apache.org/licenses/LICENSE-2.0 |
||||
@rem |
||||
@rem Unless required by applicable law or agreed to in writing, software |
||||
@rem distributed under the License is distributed on an "AS IS" BASIS, |
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
@rem See the License for the specific language governing permissions and |
||||
@rem limitations under the License. |
||||
|
||||
@rem Generate the C# code for .proto files |
||||
|
||||
setlocal |
||||
|
||||
@rem enter this directory |
||||
cd /d %~dp0 |
||||
|
||||
@rem packages will be available in nuget cache directory once the project is built or after "dotnet restore" |
||||
set PROTOC=%UserProfile%\.nuget\packages\Google.Protobuf.Tools\3.6.1\tools\windows_x64\protoc.exe |
||||
set PLUGIN=%UserProfile%\.nuget\packages\Grpc.Tools\1.14.1\tools\windows_x64\grpc_csharp_plugin.exe |
||||
|
||||
%PROTOC% -I../../protos --csharp_out Greeter ../../protos/helloworld.proto --grpc_out Greeter --plugin=protoc-gen-grpc=%PLUGIN% |
||||
|
||||
endlocal |
@ -1,149 +0,0 @@ |
||||
// <auto-generated> |
||||
// Generated by the protocol buffer compiler. DO NOT EDIT! |
||||
// source: helloworld.proto |
||||
// </auto-generated> |
||||
// Original file comments: |
||||
// Copyright 2015 gRPC authors. |
||||
// |
||||
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||
// you may not use this file except in compliance with the License. |
||||
// You may obtain a copy of the License at |
||||
// |
||||
// http://www.apache.org/licenses/LICENSE-2.0 |
||||
// |
||||
// Unless required by applicable law or agreed to in writing, software |
||||
// distributed under the License is distributed on an "AS IS" BASIS, |
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
// See the License for the specific language governing permissions and |
||||
// limitations under the License. |
||||
// |
||||
#pragma warning disable 0414, 1591 |
||||
#region Designer generated code |
||||
|
||||
using grpc = global::Grpc.Core; |
||||
|
||||
namespace Helloworld { |
||||
/// <summary> |
||||
/// The greeting service definition. |
||||
/// </summary> |
||||
public static partial class Greeter |
||||
{ |
||||
static readonly string __ServiceName = "helloworld.Greeter"; |
||||
|
||||
static readonly grpc::Marshaller<global::Helloworld.HelloRequest> __Marshaller_helloworld_HelloRequest = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloRequest.Parser.ParseFrom); |
||||
static readonly grpc::Marshaller<global::Helloworld.HelloReply> __Marshaller_helloworld_HelloReply = grpc::Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Helloworld.HelloReply.Parser.ParseFrom); |
||||
|
||||
static readonly grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply> __Method_SayHello = new grpc::Method<global::Helloworld.HelloRequest, global::Helloworld.HelloReply>( |
||||
grpc::MethodType.Unary, |
||||
__ServiceName, |
||||
"SayHello", |
||||
__Marshaller_helloworld_HelloRequest, |
||||
__Marshaller_helloworld_HelloReply); |
||||
|
||||
/// <summary>Service descriptor</summary> |
||||
public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor |
||||
{ |
||||
get { return global::Helloworld.HelloworldReflection.Descriptor.Services[0]; } |
||||
} |
||||
|
||||
/// <summary>Base class for server-side implementations of Greeter</summary> |
||||
public abstract partial class GreeterBase |
||||
{ |
||||
/// <summary> |
||||
/// Sends a greeting |
||||
/// </summary> |
||||
/// <param name="request">The request received from the client.</param> |
||||
/// <param name="context">The context of the server-side call handler being invoked.</param> |
||||
/// <returns>The response to send back to the client (wrapped by a task).</returns> |
||||
public virtual global::System.Threading.Tasks.Task<global::Helloworld.HelloReply> SayHello(global::Helloworld.HelloRequest request, grpc::ServerCallContext context) |
||||
{ |
||||
throw new grpc::RpcException(new grpc::Status(grpc::StatusCode.Unimplemented, "")); |
||||
} |
||||
|
||||
} |
||||
|
||||
/// <summary>Client for Greeter</summary> |
||||
public partial class GreeterClient : grpc::ClientBase<GreeterClient> |
||||
{ |
||||
/// <summary>Creates a new client for Greeter</summary> |
||||
/// <param name="channel">The channel to use to make remote calls.</param> |
||||
public GreeterClient(grpc::Channel channel) : base(channel) |
||||
{ |
||||
} |
||||
/// <summary>Creates a new client for Greeter that uses a custom <c>CallInvoker</c>.</summary> |
||||
/// <param name="callInvoker">The callInvoker to use to make remote calls.</param> |
||||
public GreeterClient(grpc::CallInvoker callInvoker) : base(callInvoker) |
||||
{ |
||||
} |
||||
/// <summary>Protected parameterless constructor to allow creation of test doubles.</summary> |
||||
protected GreeterClient() : base() |
||||
{ |
||||
} |
||||
/// <summary>Protected constructor to allow creation of configured clients.</summary> |
||||
/// <param name="configuration">The client configuration.</param> |
||||
protected GreeterClient(ClientBaseConfiguration configuration) : base(configuration) |
||||
{ |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Sends a greeting |
||||
/// </summary> |
||||
/// <param name="request">The request to send to the server.</param> |
||||
/// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> |
||||
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> |
||||
/// <param name="cancellationToken">An optional token for canceling the call.</param> |
||||
/// <returns>The response received from the server.</returns> |
||||
public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) |
||||
{ |
||||
return SayHello(request, new grpc::CallOptions(headers, deadline, cancellationToken)); |
||||
} |
||||
/// <summary> |
||||
/// Sends a greeting |
||||
/// </summary> |
||||
/// <param name="request">The request to send to the server.</param> |
||||
/// <param name="options">The options for the call.</param> |
||||
/// <returns>The response received from the server.</returns> |
||||
public virtual global::Helloworld.HelloReply SayHello(global::Helloworld.HelloRequest request, grpc::CallOptions options) |
||||
{ |
||||
return CallInvoker.BlockingUnaryCall(__Method_SayHello, null, options, request); |
||||
} |
||||
/// <summary> |
||||
/// Sends a greeting |
||||
/// </summary> |
||||
/// <param name="request">The request to send to the server.</param> |
||||
/// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> |
||||
/// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> |
||||
/// <param name="cancellationToken">An optional token for canceling the call.</param> |
||||
/// <returns>The call object.</returns> |
||||
public virtual grpc::AsyncUnaryCall<global::Helloworld.HelloReply> SayHelloAsync(global::Helloworld.HelloRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken)) |
||||
{ |
||||
return SayHelloAsync(request, new grpc::CallOptions(headers, deadline, cancellationToken)); |
||||
} |
||||
/// <summary> |
||||
/// Sends a greeting |
||||
/// </summary> |
||||
/// <param name="request">The request to send to the server.</param> |
||||
/// <param name="options">The options for the call.</param> |
||||
/// <returns>The call object.</returns> |
||||
public virtual grpc::AsyncUnaryCall<global::Helloworld.HelloReply> SayHelloAsync(global::Helloworld.HelloRequest request, grpc::CallOptions options) |
||||
{ |
||||
return CallInvoker.AsyncUnaryCall(__Method_SayHello, null, options, request); |
||||
} |
||||
/// <summary>Creates a new instance of client from given <c>ClientBaseConfiguration</c>.</summary> |
||||
protected override GreeterClient NewInstance(ClientBaseConfiguration configuration) |
||||
{ |
||||
return new GreeterClient(configuration); |
||||
} |
||||
} |
||||
|
||||
/// <summary>Creates service definition that can be registered with a server</summary> |
||||
/// <param name="serviceImpl">An object implementing the server-side handling logic.</param> |
||||
public static grpc::ServerServiceDefinition BindService(GreeterBase serviceImpl) |
||||
{ |
||||
return grpc::ServerServiceDefinition.CreateBuilder() |
||||
.AddMethod(__Method_SayHello, serviceImpl.SayHello).Build(); |
||||
} |
||||
|
||||
} |
||||
} |
||||
#endregion |
@ -1,26 +0,0 @@ |
||||
@rem Copyright 2016 gRPC authors. |
||||
@rem |
||||
@rem Licensed under the Apache License, Version 2.0 (the "License"); |
||||
@rem you may not use this file except in compliance with the License. |
||||
@rem You may obtain a copy of the License at |
||||
@rem |
||||
@rem http://www.apache.org/licenses/LICENSE-2.0 |
||||
@rem |
||||
@rem Unless required by applicable law or agreed to in writing, software |
||||
@rem distributed under the License is distributed on an "AS IS" BASIS, |
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
@rem See the License for the specific language governing permissions and |
||||
@rem limitations under the License. |
||||
|
||||
@rem Generate the C# code for .proto files |
||||
|
||||
setlocal |
||||
|
||||
@rem enter this directory |
||||
cd /d %~dp0 |
||||
|
||||
set TOOLS_PATH=packages\Grpc.Tools.1.14.1\tools\windows_x86 |
||||
|
||||
%TOOLS_PATH%\protoc.exe -I../../protos --csharp_out Greeter ../../protos/helloworld.proto --grpc_out Greeter --plugin=protoc-gen-grpc=%TOOLS_PATH%\grpc_csharp_plugin.exe |
||||
|
||||
endlocal |
@ -0,0 +1,52 @@ |
||||
[Ll]ibrary/ |
||||
[Tt]emp/ |
||||
[Oo]bj/ |
||||
[Bb]uild/ |
||||
[Bb]uilds/ |
||||
[Ll]ogs/ |
||||
|
||||
# Never ignore Asset meta data |
||||
![Aa]ssets/**/*.meta |
||||
|
||||
# Uncomment this line if you wish to ignore the asset store tools plugin |
||||
# [Aa]ssets/AssetStoreTools* |
||||
|
||||
# Visual Studio cache directory |
||||
.vs/ |
||||
|
||||
# Gradle cache directory |
||||
.gradle/ |
||||
|
||||
# Autogenerated VS/MD/Consulo solution and project files |
||||
ExportedObj/ |
||||
.consulo/ |
||||
*.csproj |
||||
*.unityproj |
||||
*.sln |
||||
*.suo |
||||
*.tmp |
||||
*.user |
||||
*.userprefs |
||||
*.pidb |
||||
*.booproj |
||||
*.svd |
||||
*.pdb |
||||
*.mdb |
||||
*.opendb |
||||
*.VC.db |
||||
|
||||
# Unity3D generated meta files |
||||
*.pidb.meta |
||||
*.pdb.meta |
||||
*.mdb.meta |
||||
|
||||
# Unity3D generated file on crash reports |
||||
sysinfo.txt |
||||
|
||||
# Builds |
||||
*.apk |
||||
*.unitypackage |
||||
|
||||
# Crashlytics generated file |
||||
crashlytics-build.properties |
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue