diff --git a/.gitmodules b/.gitmodules index 434d01b3d5f..2d0c0097607 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,10 +8,10 @@ [submodule "third_party/protobuf"] path = third_party/protobuf url = https://github.com/google/protobuf.git - branch = v3.0.0-alpha-3 + branch = v3.0.0-beta-1 [submodule "third_party/gflags"] path = third_party/gflags url = https://github.com/gflags/gflags.git [submodule "third_party/googletest"] path = third_party/googletest - url = git://github.com/google/googletest + url = https://github.com/google/googletest.git diff --git a/BUILD b/BUILD index 30721952515..e399daa38f1 100644 --- a/BUILD +++ b/BUILD @@ -51,6 +51,7 @@ cc_library( "src/core/support/string.h", "src/core/support/string_win32.h", "src/core/support/thd_internal.h", + "src/core/support/time_precise.h", "src/core/support/alloc.c", "src/core/support/cmdline.c", "src/core/support/cpu_iphone.c", @@ -208,7 +209,6 @@ cc_library( "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/statistics/census_interface.h", "src/core/statistics/census_rpc_stats.h", "src/core/surface/byte_buffer_queue.h", @@ -476,7 +476,6 @@ cc_library( "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/statistics/census_interface.h", "src/core/statistics/census_rpc_stats.h", "src/core/surface/byte_buffer_queue.h", @@ -990,6 +989,7 @@ objc_library( "src/core/support/string.h", "src/core/support/string_win32.h", "src/core/support/thd_internal.h", + "src/core/support/time_precise.h", ], includes = [ "include", @@ -1229,7 +1229,6 @@ objc_library( "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/statistics/census_interface.h", "src/core/statistics/census_rpc_stats.h", "src/core/surface/byte_buffer_queue.h", diff --git a/Makefile b/Makefile index 620508c19a4..ff4d51041a9 100644 --- a/Makefile +++ b/Makefile @@ -791,6 +791,7 @@ fling_server: $(BINDIR)/$(CONFIG)/fling_server fling_stream_test: $(BINDIR)/$(CONFIG)/fling_stream_test fling_test: $(BINDIR)/$(CONFIG)/fling_test gen_hpack_tables: $(BINDIR)/$(CONFIG)/gen_hpack_tables +gen_legal_metadata_characters: $(BINDIR)/$(CONFIG)/gen_legal_metadata_characters gpr_cmdline_test: $(BINDIR)/$(CONFIG)/gpr_cmdline_test gpr_env_test: $(BINDIR)/$(CONFIG)/gpr_env_test gpr_file_test: $(BINDIR)/$(CONFIG)/gpr_file_test @@ -874,9 +875,6 @@ interop_client: $(BINDIR)/$(CONFIG)/interop_client interop_server: $(BINDIR)/$(CONFIG)/interop_server interop_test: $(BINDIR)/$(CONFIG)/interop_test mock_test: $(BINDIR)/$(CONFIG)/mock_test -pubsub_client: $(BINDIR)/$(CONFIG)/pubsub_client -pubsub_publisher_test: $(BINDIR)/$(CONFIG)/pubsub_publisher_test -pubsub_subscriber_test: $(BINDIR)/$(CONFIG)/pubsub_subscriber_test qps_driver: $(BINDIR)/$(CONFIG)/qps_driver qps_interarrival_test: $(BINDIR)/$(CONFIG)/qps_interarrival_test qps_openloop_test: $(BINDIR)/$(CONFIG)/qps_openloop_test @@ -1650,8 +1648,8 @@ else $(Q)(cd third_party/openssl ; CC="$(CC) $(PIC_CPPFLAGS) -fvisibility=hidden $(CPPFLAGS_$(CONFIG)) $(OPENSSL_CFLAGS_$(CONFIG)) $(OPENSSL_CFLAGS_EXTRA)" ./config no-asm $(OPENSSL_CONFIG_$(CONFIG))) endif endif - $(Q)$(MAKE) -C third_party/openssl clean - $(Q)(unset CPPFLAGS; $(MAKE) -C third_party/openssl build_crypto build_ssl) + $(Q)$(MAKE) -j 1 -C third_party/openssl clean + $(Q)(unset CPPFLAGS; $(MAKE) -j 1 -C third_party/openssl build_crypto build_ssl) $(Q)mkdir -p $(LIBDIR)/$(CONFIG)/openssl $(Q)cp third_party/openssl/libssl.a third_party/openssl/libcrypto.a $(LIBDIR)/$(CONFIG)/openssl @@ -3384,7 +3382,7 @@ test_python: static_c tools: tools_c tools_cxx -tools_c: privatelibs_c $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/grpc_create_jwt $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 $(BINDIR)/$(CONFIG)/grpc_print_google_default_creds_token $(BINDIR)/$(CONFIG)/grpc_verify_jwt +tools_c: privatelibs_c $(BINDIR)/$(CONFIG)/gen_hpack_tables $(BINDIR)/$(CONFIG)/gen_legal_metadata_characters $(BINDIR)/$(CONFIG)/grpc_create_jwt $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 $(BINDIR)/$(CONFIG)/grpc_print_google_default_creds_token $(BINDIR)/$(CONFIG)/grpc_verify_jwt tools_cxx: privatelibs_cxx @@ -3487,51 +3485,6 @@ $(LIBDIR)/$(CONFIG)/pkgconfig/grpc++_unsecure.pc: $(Q) mkdir -p $(@D) $(Q) echo "$(GRPCXX_UNSECURE_PC_FILE)" | tr , '\n' >$@ -ifeq ($(NO_PROTOC),true) -$(GENDIR)/examples/pubsub/empty.pb.cc: protoc_dep_error -$(GENDIR)/examples/pubsub/empty.grpc.pb.cc: protoc_dep_error -else -$(GENDIR)/examples/pubsub/empty.pb.cc: examples/pubsub/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) - $(E) "[PROTOC] Generating protobuf CC file from $<" - $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< - -$(GENDIR)/examples/pubsub/empty.grpc.pb.cc: examples/pubsub/empty.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) - $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" - $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< -endif - -ifeq ($(NO_PROTOC),true) -$(GENDIR)/examples/pubsub/label.pb.cc: protoc_dep_error -$(GENDIR)/examples/pubsub/label.grpc.pb.cc: protoc_dep_error -else -$(GENDIR)/examples/pubsub/label.pb.cc: examples/pubsub/label.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) - $(E) "[PROTOC] Generating protobuf CC file from $<" - $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< - -$(GENDIR)/examples/pubsub/label.grpc.pb.cc: examples/pubsub/label.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) - $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" - $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< -endif - -ifeq ($(NO_PROTOC),true) -$(GENDIR)/examples/pubsub/pubsub.pb.cc: protoc_dep_error -$(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc: protoc_dep_error -else -$(GENDIR)/examples/pubsub/pubsub.pb.cc: examples/pubsub/pubsub.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) - $(E) "[PROTOC] Generating protobuf CC file from $<" - $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --cpp_out=$(GENDIR) $< - -$(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc: examples/pubsub/pubsub.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) - $(E) "[GRPC] Generating gRPC's protobuf service CC file from $<" - $(Q) mkdir -p `dirname $@` - $(Q) $(PROTOC) --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(BINDIR)/$(CONFIG)/grpc_cpp_plugin $< -endif - ifeq ($(NO_PROTOC),true) $(GENDIR)/test/cpp/qps/perf_db.pb.cc: protoc_dep_error $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc: protoc_dep_error @@ -4791,6 +4744,7 @@ LIBGRPC++_TEST_UTIL_SRC = \ $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc \ test/cpp/util/cli_call.cc \ test/cpp/util/create_test_channel.cc \ + test/cpp/util/string_ref_helper.cc \ test/cpp/util/subprocess.cc \ @@ -4837,6 +4791,7 @@ endif endif $(OBJDIR)/$(CONFIG)/test/cpp/util/cli_call.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/create_test_channel.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc +$(OBJDIR)/$(CONFIG)/test/cpp/util/string_ref_helper.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc $(OBJDIR)/$(CONFIG)/test/cpp/util/subprocess.o: $(GENDIR)/test/cpp/util/messages.pb.cc $(GENDIR)/test/cpp/util/messages.grpc.pb.cc $(GENDIR)/test/cpp/util/echo.pb.cc $(GENDIR)/test/cpp/util/echo.grpc.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.pb.cc $(GENDIR)/test/cpp/util/echo_duplicate.grpc.pb.cc @@ -5200,59 +5155,6 @@ endif $(OBJDIR)/$(CONFIG)/test/cpp/interop/server.o: $(GENDIR)/test/proto/empty.pb.cc $(GENDIR)/test/proto/empty.grpc.pb.cc $(GENDIR)/test/proto/messages.pb.cc $(GENDIR)/test/proto/messages.grpc.pb.cc $(GENDIR)/test/proto/test.pb.cc $(GENDIR)/test/proto/test.grpc.pb.cc -LIBPUBSUB_CLIENT_LIB_SRC = \ - $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc \ - $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc \ - $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc \ - examples/pubsub/publisher.cc \ - examples/pubsub/subscriber.cc \ - - -LIBPUBSUB_CLIENT_LIB_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(LIBPUBSUB_CLIENT_LIB_SRC)))) - -ifeq ($(NO_SECURE),true) - -# You can't build secure libraries if you don't have OpenSSL. - -$(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a: openssl_dep_error - - -else - -ifeq ($(NO_PROTOBUF),true) - -# You can't build a C++ library if you don't have protobuf - a bit overreached, but still okay. - -$(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a: protobuf_dep_error - - -else - -$(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a: $(ZLIB_DEP) $(OPENSSL_DEP) $(PROTOBUF_DEP) $(LIBPUBSUB_CLIENT_LIB_OBJS) - $(E) "[AR] Creating $@" - $(Q) mkdir -p `dirname $@` - $(Q) rm -f $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a - $(Q) $(AR) rcs $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBPUBSUB_CLIENT_LIB_OBJS) -ifeq ($(SYSTEM),Darwin) - $(Q) ranlib $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a -endif - - - - -endif - -endif - -ifneq ($(NO_SECURE),true) -ifneq ($(NO_DEPS),true) --include $(LIBPUBSUB_CLIENT_LIB_OBJS:.o=.dep) -endif -endif -$(OBJDIR)/$(CONFIG)/examples/pubsub/publisher.o: $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc -$(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber.o: $(GENDIR)/examples/pubsub/label.pb.cc $(GENDIR)/examples/pubsub/label.grpc.pb.cc $(GENDIR)/examples/pubsub/empty.pb.cc $(GENDIR)/examples/pubsub/empty.grpc.pb.cc $(GENDIR)/examples/pubsub/pubsub.pb.cc $(GENDIR)/examples/pubsub/pubsub.grpc.pb.cc - - LIBQPS_SRC = \ $(GENDIR)/test/cpp/qps/qpstest.pb.cc $(GENDIR)/test/cpp/qps/qpstest.grpc.pb.cc \ $(GENDIR)/test/cpp/qps/perf_db.pb.cc $(GENDIR)/test/cpp/qps/perf_db.grpc.pb.cc \ @@ -7118,6 +7020,35 @@ endif endif +GEN_LEGAL_METADATA_CHARACTERS_SRC = \ + tools/codegen/core/gen_legal_metadata_characters.c \ + +GEN_LEGAL_METADATA_CHARACTERS_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GEN_LEGAL_METADATA_CHARACTERS_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/gen_legal_metadata_characters: openssl_dep_error + +else + +$(BINDIR)/$(CONFIG)/gen_legal_metadata_characters: $(GEN_LEGAL_METADATA_CHARACTERS_OBJS) + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(GEN_LEGAL_METADATA_CHARACTERS_OBJS) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/gen_legal_metadata_characters + +endif + +$(OBJDIR)/$(CONFIG)/tools/codegen/core/gen_legal_metadata_characters.o: +deps_gen_legal_metadata_characters: $(GEN_LEGAL_METADATA_CHARACTERS_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(GEN_LEGAL_METADATA_CHARACTERS_OBJS:.o=.dep) +endif +endif + + GPR_CMDLINE_TEST_SRC = \ test/core/support/cmdline_test.c \ @@ -8941,16 +8872,16 @@ $(BINDIR)/$(CONFIG)/auth_property_iterator_test: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/auth_property_iterator_test: $(PROTOBUF_DEP) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/auth_property_iterator_test: $(PROTOBUF_DEP) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/auth_property_iterator_test + $(Q) $(LDXX) $(LDFLAGS) $(AUTH_PROPERTY_ITERATOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/auth_property_iterator_test endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/common/auth_property_iterator_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/common/auth_property_iterator_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_auth_property_iterator_test: $(AUTH_PROPERTY_ITERATOR_TEST_OBJS:.o=.dep) ifneq ($(NO_SECURE),true) @@ -9718,126 +9649,6 @@ endif endif -PUBSUB_CLIENT_SRC = \ - examples/pubsub/main.cc \ - -PUBSUB_CLIENT_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_CLIENT_SRC)))) -ifeq ($(NO_SECURE),true) - -# You can't build secure targets if you don't have OpenSSL. - -$(BINDIR)/$(CONFIG)/pubsub_client: openssl_dep_error - -else - - -ifeq ($(NO_PROTOBUF),true) - -# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. - -$(BINDIR)/$(CONFIG)/pubsub_client: protobuf_dep_error - -else - -$(BINDIR)/$(CONFIG)/pubsub_client: $(PROTOBUF_DEP) $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a - $(E) "[LD] Linking $@" - $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_CLIENT_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_client - -endif - -endif - -$(OBJDIR)/$(CONFIG)/examples/pubsub/main.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_config.a -deps_pubsub_client: $(PUBSUB_CLIENT_OBJS:.o=.dep) - -ifneq ($(NO_SECURE),true) -ifneq ($(NO_DEPS),true) --include $(PUBSUB_CLIENT_OBJS:.o=.dep) -endif -endif - - -PUBSUB_PUBLISHER_TEST_SRC = \ - examples/pubsub/publisher_test.cc \ - -PUBSUB_PUBLISHER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_PUBLISHER_TEST_SRC)))) -ifeq ($(NO_SECURE),true) - -# You can't build secure targets if you don't have OpenSSL. - -$(BINDIR)/$(CONFIG)/pubsub_publisher_test: openssl_dep_error - -else - - -ifeq ($(NO_PROTOBUF),true) - -# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. - -$(BINDIR)/$(CONFIG)/pubsub_publisher_test: protobuf_dep_error - -else - -$(BINDIR)/$(CONFIG)/pubsub_publisher_test: $(PROTOBUF_DEP) $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - $(E) "[LD] Linking $@" - $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_PUBLISHER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_publisher_test - -endif - -endif - -$(OBJDIR)/$(CONFIG)/examples/pubsub/publisher_test.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -deps_pubsub_publisher_test: $(PUBSUB_PUBLISHER_TEST_OBJS:.o=.dep) - -ifneq ($(NO_SECURE),true) -ifneq ($(NO_DEPS),true) --include $(PUBSUB_PUBLISHER_TEST_OBJS:.o=.dep) -endif -endif - - -PUBSUB_SUBSCRIBER_TEST_SRC = \ - examples/pubsub/subscriber_test.cc \ - -PUBSUB_SUBSCRIBER_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(PUBSUB_SUBSCRIBER_TEST_SRC)))) -ifeq ($(NO_SECURE),true) - -# You can't build secure targets if you don't have OpenSSL. - -$(BINDIR)/$(CONFIG)/pubsub_subscriber_test: openssl_dep_error - -else - - -ifeq ($(NO_PROTOBUF),true) - -# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.0.0+. - -$(BINDIR)/$(CONFIG)/pubsub_subscriber_test: protobuf_dep_error - -else - -$(BINDIR)/$(CONFIG)/pubsub_subscriber_test: $(PROTOBUF_DEP) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a - $(E) "[LD] Linking $@" - $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(PUBSUB_SUBSCRIBER_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/pubsub_subscriber_test - -endif - -endif - -$(OBJDIR)/$(CONFIG)/examples/pubsub/subscriber_test.o: $(LIBDIR)/$(CONFIG)/libpubsub_client_lib.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a -deps_pubsub_subscriber_test: $(PUBSUB_SUBSCRIBER_TEST_OBJS:.o=.dep) - -ifneq ($(NO_SECURE),true) -ifneq ($(NO_DEPS),true) --include $(PUBSUB_SUBSCRIBER_TEST_OBJS:.o=.dep) -endif -endif - - QPS_DRIVER_SRC = \ test/cpp/qps/qps_driver.cc \ @@ -10151,16 +9962,16 @@ $(BINDIR)/$(CONFIG)/secure_auth_context_test: protobuf_dep_error else -$(BINDIR)/$(CONFIG)/secure_auth_context_test: $(PROTOBUF_DEP) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(BINDIR)/$(CONFIG)/secure_auth_context_test: $(PROTOBUF_DEP) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(E) "[LD] Linking $@" $(Q) mkdir -p `dirname $@` - $(Q) $(LDXX) $(LDFLAGS) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/secure_auth_context_test + $(Q) $(LDXX) $(LDFLAGS) $(SECURE_AUTH_CONTEXT_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/secure_auth_context_test endif endif -$(OBJDIR)/$(CONFIG)/test/cpp/common/secure_auth_context_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a +$(OBJDIR)/$(CONFIG)/test/cpp/common/secure_auth_context_test.o: $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a deps_secure_auth_context_test: $(SECURE_AUTH_CONTEXT_TEST_OBJS:.o=.dep) ifneq ($(NO_SECURE),true) @@ -20612,8 +20423,6 @@ ifneq ($(OPENSSL_DEP),) # This is to ensure the embedded OpenSSL is built beforehand, properly # installing headers to their final destination on the drive. We need this # otherwise parallel compilation will fail if a source is compiled first. -examples/pubsub/publisher.cc: $(OPENSSL_DEP) -examples/pubsub/subscriber.cc: $(OPENSSL_DEP) src/core/httpcli/httpcli_security_connector.c: $(OPENSSL_DEP) src/core/security/base64.c: $(OPENSSL_DEP) src/core/security/client_auth_filter.c: $(OPENSSL_DEP) @@ -20670,6 +20479,7 @@ test/cpp/qps/timer.cc: $(OPENSSL_DEP) test/cpp/util/benchmark_config.cc: $(OPENSSL_DEP) test/cpp/util/cli_call.cc: $(OPENSSL_DEP) test/cpp/util/create_test_channel.cc: $(OPENSSL_DEP) +test/cpp/util/string_ref_helper.cc: $(OPENSSL_DEP) test/cpp/util/subprocess.cc: $(OPENSSL_DEP) test/cpp/util/test_config.cc: $(OPENSSL_DEP) endif diff --git a/README.md b/README.md index f8306298162..ab1004f9d5a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Copyright 2015 Google Inc. #Documentation -You can find more detailed documentation and examples in the [grpc-common repository](http://github.com/grpc/grpc-common). +You can find more detailed documentation and examples in the [doc](doc) and [examples](examples) directories respectively. #Installation @@ -95,7 +95,7 @@ messages are delivered in the order they were sent. #Protocol -The [gRPC protocol](https://github.com/grpc/grpc-common/blob/master/PROTOCOL-HTTP2.md) specifies the abstract requirements for communication between +The [gRPC protocol](doc/PROTOCOL-HTTP2.md) specifies the abstract requirements for communication between clients and servers. A concrete embedding over HTTP/2 completes the picture by fleshing out the details of each of the required operations. diff --git a/build.json b/build.json index 02cee31d082..693b825ef0e 100644 --- a/build.json +++ b/build.json @@ -180,7 +180,6 @@ "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/statistics/census_interface.h", "src/core/statistics/census_rpc_stats.h", "src/core/surface/byte_buffer_queue.h", @@ -403,7 +402,8 @@ "src/core/support/stack_lockfree.h", "src/core/support/string.h", "src/core/support/string_win32.h", - "src/core/support/thd_internal.h" + "src/core/support/thd_internal.h", + "src/core/support/time_precise.h" ], "src": [ "src/core/support/alloc.c", @@ -662,6 +662,7 @@ "headers": [ "test/cpp/util/cli_call.h", "test/cpp/util/create_test_channel.h", + "test/cpp/util/string_ref_helper.h", "test/cpp/util/subprocess.h" ], "src": [ @@ -670,6 +671,7 @@ "test/cpp/util/echo_duplicate.proto", "test/cpp/util/cli_call.cc", "test/cpp/util/create_test_channel.cc", + "test/cpp/util/string_ref_helper.cc", "test/cpp/util/subprocess.cc" ], "deps": [ @@ -810,27 +812,6 @@ "grpc++_test_config" ] }, - { - "name": "pubsub_client_lib", - "build": "do_not_build", - "language": "c++", - "headers": [ - "examples/pubsub/publisher.h", - "examples/pubsub/subscriber.h" - ], - "src": [ - "examples/pubsub/label.proto", - "examples/pubsub/empty.proto", - "examples/pubsub/pubsub.proto", - "examples/pubsub/publisher.cc", - "examples/pubsub/subscriber.cc" - ], - "deps": [ - "grpc++", - "grpc", - "gpr" - ] - }, { "name": "qps", "build": "private", @@ -1147,6 +1128,15 @@ "grpc" ] }, + { + "name": "gen_legal_metadata_characters", + "build": "tool", + "language": "c", + "src": [ + "tools/codegen/core/gen_legal_metadata_characters.c" + ], + "deps": [] + }, { "name": "gpr_cmdline_test", "build": "test", @@ -2017,8 +2007,11 @@ "test/cpp/common/auth_property_iterator_test.cc" ], "deps": [ + "grpc++_test_util", + "grpc_test_util", "grpc++", "grpc", + "gpr_test_util", "gpr" ] }, @@ -2354,58 +2347,6 @@ "gpr" ] }, - { - "name": "pubsub_client", - "build": "do_not_build", - "run": false, - "language": "c++", - "src": [ - "examples/pubsub/main.cc" - ], - "deps": [ - "pubsub_client_lib", - "grpc_test_util", - "grpc++", - "grpc", - "gpr_test_util", - "gpr", - "grpc++_test_config" - ] - }, - { - "name": "pubsub_publisher_test", - "build": "do_not_build", - "language": "c++", - "src": [ - "examples/pubsub/publisher_test.cc" - ], - "deps": [ - "pubsub_client_lib", - "grpc++_test_util", - "grpc_test_util", - "grpc++", - "grpc", - "gpr_test_util", - "gpr" - ] - }, - { - "name": "pubsub_subscriber_test", - "build": "do_not_build", - "language": "c++", - "src": [ - "examples/pubsub/subscriber_test.cc" - ], - "deps": [ - "pubsub_client_lib", - "grpc++_test_util", - "grpc_test_util", - "grpc++", - "grpc", - "gpr_test_util", - "gpr" - ] - }, { "name": "qps_driver", "build": "benchmark", @@ -2569,8 +2510,11 @@ "test/cpp/common/secure_auth_context_test.cc" ], "deps": [ + "grpc++_test_util", + "grpc_test_util", "grpc++", "grpc", + "gpr_test_util", "gpr" ] }, diff --git a/doc/PROTOCOL-HTTP2.md b/doc/PROTOCOL-HTTP2.md new file mode 100644 index 00000000000..d3fbb60d603 --- /dev/null +++ b/doc/PROTOCOL-HTTP2.md @@ -0,0 +1,192 @@ +# gRPC over HTTP2 + +## Introduction +This document serves as a detailed description for an implementation of gRPC carried over HTTP2 draft 17 framing. It assumes familiarity with the HTTP2 specification. + +## Protocol +Production rules are using ABNF syntax. + +### Outline + +The following is the general sequence of message atoms in a GRPC request & response message stream + +* Request → Request-Headers *Delimited-Message EOS +* Response → (Response-Headers *Delimited-Message Trailers) / Trailers-Only + + +### Requests + +* Request → Request-Headers *Delimited-Message EOS + +Request-Headers are delivered as HTTP2 headers in HEADERS + CONTINUATION frames. + +* **Request-Headers** → Call-Definition *Custom-Metadata +* **Call-Definition** → Method Scheme Path TE [Authority] [Timeout] [Content-Type] [Message-Type] [Message-Encoding] [Message-Accept-Encoding] [User-Agent] +* **Method** → “:method POST” +* **Scheme** → “:scheme ” (“http” / “https”) +* **Path** → “:path” {_path identifying method within exposed API_} +* **Authority** → “:authority” {_virtual host name of authority_} +* **TE** → “te” “trailers” # Used to detect incompatible proxies +* **Timeout** → “grpc-timeout” TimeoutValue TimeoutUnit +* **TimeoutValue** → {_positive integer as ASCII string of at most 8 digits_} +* **TimeoutUnit** → Hour / Minute / Second / Millisecond / Microsecond / Nanosecond +* **Hour** → “H” +* **Minute** → “M” +* **Second** → “S” +* **Millisecond** → “m” +* **Microsecond** → “u” +* **Nanosecond** → “n” +* **Content-Type** → “content-type” “application/grpc” [(“+proto” / “+json” / {_custom_})] +* **Content-Coding** → “gzip” / “deflate” / “snappy” / {_custom_} +* **Message-Encoding** → “grpc-encoding” Content-Coding +* **Message-Accept-Encoding** → “grpc-accept-encoding” Content-Coding *("," Content-Coding) +* **User-Agent** → “user-agent” {_structured user-agent string_} +* **Message-Type** → “grpc-message-type” {_type name for message schema_} +* **Custom-Metadata** → Binary-Header / ASCII-Header +* **Binary-Header** → {lowercase ASCII header name ending in “-bin” } {_base64 encoded value_} +* **ASCII-Header** → {lowercase ASCII header name} {_value_} + + +HTTP2 requires that reserved headers, ones starting with “:” appear before all other headers. Additionally implementations should send **Timeout** immediately after the reserved headers and they should send the **Call-Definition** headers before sending **Custom-Metadata**. + +If **Timeout** is omitted a server should assume an infinite timeout. Client implementations are free to send a default minimum timeout based on their deployment requirements. + +**Custom-Metadata** is an arbitrary set of key-value pairs defined by the application layer. Aside from transport limits on the total length of HTTP2 HEADERS the only other constraint is that header names starting with “grpc-” are reserved for future use. + +Note that HTTP2 does not allow arbitrary octet sequences for header values so binary header values must be encoded using Base64 as per https://tools.ietf.org/html/rfc4648#section-4. Implementations MUST accept padded and un-padded values and should emit un-padded values. Applications define binary headers by having their names end with “-bin”. Runtime libraries use this suffix to detect binary headers and properly apply base64 encoding & decoding as headers are sent and received. + +The repeated sequence of **Delimited-Message** items is delivered in DATA frames + +* **Delimited-Message** → Compressed-Flag Message-Length Message +* **Compressed-Flag** → 0 / 1 # encoded as 1 byte unsigned integer +* **Message-Length** → {_length of Message_} # encoded as 4 byte unsigned integer +* **Message** → *{binary octet} + +A **Compressed-Flag** value of 1 indicates that the binary octet sequence of **Message** is compressed using the mechanism declared by the **Message-Encoding** header. A value of 0 indicates that no encoding of **Message** bytes has occurred. Compression contexts are NOT maintained over message boundaries, implementations must create a new context for each message in the stream. If the **Message-Encoding** header is omitted then the **Compressed-Flag** must be 0. + +For requests, **EOS** (end-of-stream) is indicated by the presence of the END_STREAM flag on the last received DATA frame. In scenarios where the **Request** stream needs to be closed but no data remains to be sent implementations MUST send an empty DATA frame with this flag set. + +###Responses + +* **Response** → (Response-Headers *Delimited-Message Trailers) / Trailers-Only +* **Response-Headers** → HTTP-Status [Message-Encoding] [Message-Accept-Encoding] Content-Type *Custom-Metadata +* **Trailers-Only** → HTTP-Status Content-Type Trailers +* **Trailers** → Status [Status-Message] *Custom-Metadata +* **HTTP-Status** → “:status 200” +* **Status** → “grpc-status” +* **Status-Message** → “grpc-message” + +**Response-Headers** & **Trailers-Only** are each delivered in a single HTTP2 HEADERS frame block. Most responses are expected to have both headers and trailers but **Trailers-Only** is permitted for calls that produce an immediate error. Status must be sent in **Trailers** even if the status code is OK. + +For responses end-of-stream is indicated by the presence of the END_STREAM flag on the last received HEADERS frame that carries **Trailers**. + +Implementations should expect broken deployments to send non-200 HTTP status codes in responses as well as a variety of non-GRPC content-types and to omit **Status** & **Status-Message**. Implementations must synthesize a **Status** & **Status-Message** to propagate to the application layer when this occurs. + +####Example + +Sample unary-call showing HTTP2 framing sequence + +**Request** + +``` +HEADERS (flags = END_HEADERS) +:method = POST +:scheme = http +:path = /google.pubsub.v2.PublisherService/CreateTopic +:authority = pubsub.googleapis.com +grpc-timeout = 1S +content-type = application/grpc+proto +grpc-encoding = gzip +authorization = Bearer y235.wef315yfh138vh31hv93hv8h3v + +DATA (flags = END_STREAM) + +``` +**Response** +``` +HEADERS (flags = END_HEADERS) +:status = 200 +grpc-encoding = gzip + +DATA + + +HEADERS (flags = END_STREAM, END_HEADERS) +grpc-status = 0 # OK +trace-proto-bin = jher831yy13JHy3hc +``` +####User Agents + +While the protocol does not require a user-agent to function it is recommended that clients provide a structured user-agent string that provides a basic description of the calling library, version & platform to facilitate issue diagnosis in heterogeneous environments. The following structure is recommended to library developers +``` +User-Agent → “grpc-” Language ?(“-” Variant) “/” Version ?( “ (“ *(AdditionalProperty “;”) “)” ) +``` +E.g. + +``` +grpc-java/1.2.3 +grpc-ruby/1.2.3 +grpc-ruby-jruby/1.3.4 +grpc-java-android/0.9.1 (gingerbread/1.2.4; nexus5; tmobile) +``` +####HTTP2 Transport Mapping + +#####Stream Identification +All GRPC calls need to specify an internal ID. We will use HTTP2 stream-ids as call identifiers in this scheme. NOTE: These id’s are contextual to an open HTTP2 session and will not be unique within a given process that is handling more than one HTTP2 session nor can they be used as GUIDs. + +#####Data Frames +DATA frame boundaries have no relation to **Delimited-Message** boundaries and implementations should make no assumptions about their alignment. + +#####Errors + +When an application or runtime error occurs during an RPC a **Status** and **Status-Message** are delivered in **Trailers**. + +In some cases it is possible that the framing of the message stream has become corrupt and the RPC runtime will choose to use an **RST_STREAM** frame to indicate this state to its peer. RPC runtime implementations should interpret RST_STREAM as immediate full-closure of the stream and should propagate an error up to the calling application layer. + +The following mapping from RST_STREAM error codes to GRPC error codes is applied. + +HTTP2 Code|GRPC Code +----------|----------- +NO_ERROR(0)|INTERNAL - An explicit GRPC status of OK should have been sent but this might be used to aggressively lameduck in some scenarios. +PROTOCOL_ERROR(1)|INTERNAL +INTERNAL_ERROR(2)|INTERNAL +FLOW_CONTROL_ERROR(3)|INTERNAL +SETTINGS_TIMEOUT(4)|INTERNAL +STREAM_CLOSED|No mapping as there is no open stream to propagate to. Implementations should log. +FRAME_SIZE_ERROR|INTERNAL +REFUSED_STREAM|UNAVAILABLE - Indicates that no processing occurred and the request can be retried, possibly elsewhere. +CANCEL(8)|Mapped to call cancellation when sent by a client.Mapped to CANCELLED when sent by a server. Note that servers should only use this mechanism when they need to cancel a call but the payload byte sequence is incomplete. +COMPRESSION_ERROR|INTERNAL +CONNECT_ERROR|INTERNAL +ENHANCE_YOUR_CALM|RESOURCE_EXHAUSTED ...with additional error detail provided by runtime to indicate that the exhausted resource is bandwidth. +INADEQUATE_SECURITY| PERMISSION_DENIED … with additional detail indicating that permission was denied as protocol is not secure enough for call. + + +#####Security + +The HTTP2 specification mandates the use of TLS 1.2 or higher when TLS is used with HTTP2. It also places some additional constraints on the allowed ciphers in deployments to avoid known-problems as well as requiring SNI support. It is also expected that HTTP2 will be used in conjunction with proprietary transport security mechanisms about which the specification can make no meaningful recommendations. + +#####Connection Management +######GOAWAY Frame +Sent by servers to clients to indicate that they will no longer accept any new streams on the associated connections. This frame includes the id of the last successfully accepted stream by the server. Clients should consider any stream initiated after the last successfully accepted stream as UNAVAILABLE and retry the call elsewhere. Clients are free to continue working with the already accepted streams until they complete or the connection is terminated. + +Servers should send GOAWAY before terminating a connection to reliably inform clients which work has been accepted by the server and is being executed. + +######PING Frame +Both clients and servers can send a PING frame that the peer must respond to by precisely echoing what they received. This is used to assert that the connection is still live as well as providing a means to estimate end-to-end latency. If a server initiated PING does not receive a response within the deadline expected by the runtime all outstanding calls on the server will be closed with a CANCELLED status. An expired client initiated PING will cause all calls to be closed with an UNAVAILABLE status. Note that the frequency of PINGs is highly dependent on the network environment, implementations are free to adjust PING frequency based on network and application requirements. + +######Connection failure +If a detectable connection failure occurs on the client all calls will be closed with an UNAVAILABLE status. For servers open calls will be closed with a CANCELLED status. + + +### Appendix A - GRPC for Protobuf + +The service interfaces declared by protobuf are easily mapped onto GRPC by code generation extensions to protoc. The following defines the mapping to be used + + +* **Path** → / Service-Name / {_method name_} +* **Service-Name** → ?( {_proto package name_} "." ) {_service name_} +* **Message-Type** → {_fully qualified proto message name_} +* **Content-Type** → "application/grpc+proto" + + diff --git a/doc/grpc-auth-support.md b/doc/grpc-auth-support.md new file mode 100644 index 00000000000..800fbedd80c --- /dev/null +++ b/doc/grpc-auth-support.md @@ -0,0 +1,289 @@ +#gRPC Authentication support + +gRPC is designed to plug-in a number of authentication mechanisms. This document +provides a quick overview of the various auth mechanisms supported, discusses +the API with some examples, and concludes with a discussion of extensibility. +More documentation and examples are coming soon! + +## Supported auth mechanisms + +###SSL/TLS +gRPC has SSL/TLS integration and promotes the use of SSL/TLS to authenticate the +server, and encrypt all the data exchanged between the client and the server. +Optional mechanisms are available for clients to provide certificates to +accomplish mutual authentication. + +###OAuth 2.0 +gRPC provides a generic mechanism (described below) to attach metadata to +requests and responses. This mechanism can be used to attach OAuth 2.0 Access +Tokens to RPCs being made at a client. Additional support for acquiring Access +Tokens while accessing Google APIs through gRPC is provided for certain auth +flows, demonstrated through code examples below. + +## API +To reduce complexity and minimize API clutter, gRPC works with a unified concept +of a Credentials object. Users construct gRPC credentials using corresponding +bootstrap credentials (e.g., SSL client certs or Service Account Keys), and use +the credentials while creating a gRPC channel to any server. Depending on the +type of credential supplied, the channel uses the credentials during the initial +SSL/TLS handshake with the server, or uses the credential to generate and +attach Access Tokens to each request being made on the channel. + +###SSL/TLS for server authentication and encryption +This is the simplest authentication scenario, where a client just wants to +authenticate the server and encrypt all data. + +```cpp +SslCredentialsOptions ssl_opts; // Options to override SSL params, empty by default +// Create the credentials object by providing service account key in constructor +std::unique_ptr creds = CredentialsFactory::SslCredentials(ssl_opts); +// Create a channel using the credentials created in the previous step +std::shared_ptr channel = CreateChannel(server_name, creds, channel_args); +// Create a stub on the channel +std::unique_ptr stub(Greeter::NewStub(channel)); +// Make actual RPC calls on the stub. +grpc::Status s = stub->sayHello(&context, *request, response); +``` + +For advanced use cases such as modifying the root CA or using client certs, +the corresponding options can be set in the SslCredentialsOptions parameter +passed to the factory method. + + +###Authenticating with Google + +gRPC applications can use a simple API to create a credential that works in various deployment scenarios. + +```cpp +std::unique_ptr creds = CredentialsFactory::GoogleDefaultCredentials(); +// Create a channel, stub and make RPC calls (same as in the previous example) +std::shared_ptr channel = CreateChannel(server_name, creds, channel_args); +std::unique_ptr stub(Greeter::NewStub(channel)); +grpc::Status s = stub->sayHello(&context, *request, response); +``` + +This credential works for applications using Service Accounts as well as for +applications running in [Google Compute Engine (GCE)](https://cloud.google.com/compute/). In the former case, the +service account’s private keys are loaded from the file named in the environment +variable `GOOGLE_APPLICATION_CREDENTIALS`. The +keys are used to generate bearer tokens that are attached to each outgoing RPC +on the corresponding channel. + +For applications running in GCE, a default service account and corresponding +OAuth scopes can be configured during VM setup. At run-time, this credential +handles communication with the authentication systems to obtain OAuth2 access +tokens and attaches them to each outgoing RPC on the corresponding channel. +Extending gRPC to support other authentication mechanisms +The gRPC protocol is designed with a general mechanism for sending metadata +associated with RPC. Clients can send metadata at the beginning of an RPC and +servers can send back metadata at the beginning and end of the RPC. This +provides a natural mechanism to support OAuth2 and other authentication +mechanisms that need attach bearer tokens to individual request. + +In the simplest case, there is a single line of code required on the client +to add a specific token as metadata to an RPC and a corresponding access on +the server to retrieve this piece of metadata. The generation of the token +on the client side and its verification at the server can be done separately. + +A deeper integration can be achieved by plugging in a gRPC credentials implementation for any custom authentication mechanism that needs to attach per-request tokens. gRPC internals also allow switching out SSL/TLS with other encryption mechanisms. + +## Examples + +These authentication mechanisms will be available in all gRPC's supported languages. +The following sections demonstrate how authentication and authorization features described above appear in each language: more languages are coming soon. + +###SSL/TLS for server authentication and encryption (Ruby) +```ruby +# Base case - No encryption +stub = Helloworld::Greeter::Stub.new('localhost:50051') +... + +# With server authentication SSL/TLS +creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file +stub = Helloworld::Greeter::Stub.new('localhost:50051', creds: creds) +``` + +###SSL/TLS for server authentication and encryption (C#) +```csharp +// Base case - No encryption +var channel = new Channel("localhost:50051"); +var client = new Greeter.GreeterClient(channel); +... + +// With server authentication SSL/TLS +var credentials = new SslCredentials(File.ReadAllText("ca.pem")); // Load a CA file +var channel = new Channel("localhost:50051", credentials); +var client = new Greeter.GreeterClient(channel); +``` + +###SSL/TLS for server authentication and encryption (Objective-C) + +The default for Objective-C is to use SSL/TLS, as that's the most common use case when accessing +remote APIs. + +```objective-c +// Base case - With server authentication SSL/TLS +HLWGreeter *client = [[HLWGreeter alloc] initWithHost:@"localhost:50051"]; +// Same as using @"https://localhost:50051". +... + +// No encryption +HLWGreeter *client = [[HLWGreeter alloc] initWithHost:@"http://localhost:50051"]; +// Specifying the HTTP scheme explicitly forces no encryption. +``` + +###SSL/TLS for server authentication and encryption (Python) +```python +# Base case - No encryption +stub = early_adopter_create_GreeterService_stub('localhost', 50051) +... + +# With server authentication SSL/TLS +stub = early_adopter_create_GreeterService_stub( + 'localhost', 50051, secure=True, root_certificates=open('ca.pem').read()) +... +``` +n.b.: the beta API will look different + +###Authenticating with Google (Ruby) +```ruby +# Base case - No encryption/authorization +stub = Helloworld::Greeter::Stub.new('localhost:50051') +... + +# Authenticating with Google +require 'googleauth' # from http://www.rubydoc.info/gems/googleauth/0.1.0 +... +creds = GRPC::Core::Credentials.new(load_certs) # load_certs typically loads a CA roots file +scope = 'https://www.googleapis.com/auth/grpc-testing' +authorization = Google::Auth.get_application_default(scope) +stub = Helloworld::Greeter::Stub.new('localhost:50051', + creds: creds, + update_metadata: authorization.updater_proc) +``` + +###Authenticating with Google (Node.js) + +```node +// Base case - No encryption/authorization +var stub = new helloworld.Greeter('localhost:50051'); +... +// Authenticating with Google +var GoogleAuth = require('google-auth-library'); // from https://www.npmjs.com/package/google-auth-library +... +var creds = grpc.Credentials.createSsl(load_certs); // load_certs typically loads a CA roots file +var scope = 'https://www.googleapis.com/auth/grpc-testing'; +(new GoogleAuth()).getApplicationDefault(function(err, auth) { + if (auth.createScopeRequired()) { + auth = auth.createScoped(scope); + } + var stub = new helloworld.Greeter('localhost:50051', + {credentials: creds}, + grpc.getGoogleAuthDelegate(auth)); +}); +``` + +###Authenticating with Google (C#) +```csharp +// Base case - No encryption/authorization +var channel = new Channel("localhost:50051"); +var client = new Greeter.GreeterClient(channel); +... + +// Authenticating with Google +using Grpc.Auth; // from Grpc.Auth NuGet package +... +var credentials = new SslCredentials(File.ReadAllText("ca.pem")); // Load a CA file +var channel = new Channel("localhost:50051", credentials); + +string scope = "https://www.googleapis.com/auth/grpc-testing"; +var authorization = GoogleCredential.GetApplicationDefault(); +if (authorization.IsCreateScopedRequired) +{ + authorization = credential.CreateScoped(new[] { scope }); +} +var client = new Greeter.GreeterClient(channel, + new StubConfiguration(OAuth2InterceptorFactory.Create(credential))); +``` + +###Authenticating with Google (PHP) +```php +// Base case - No encryption/authorization +$client = new helloworld\GreeterClient( + new Grpc\BaseStub('localhost:50051', [])); +... + +// Authenticating with Google +// the environment variable "GOOGLE_APPLICATION_CREDENTIALS" needs to be set +$scope = "https://www.googleapis.com/auth/grpc-testing"; +$auth = Google\Auth\ApplicationDefaultCredentials::getCredentials($scope); +$opts = [ + 'credentials' => Grpc\Credentials::createSsl(file_get_contents('ca.pem')); + 'update_metadata' => $auth->getUpdateMetadataFunc(), +]; + +$client = new helloworld\GreeterClient( + new Grpc\BaseStub('localhost:50051', $opts)); + +``` + +###Authenticating with Google (Objective-C) + +This example uses the [Google iOS Sign-In library](https://developers.google.com/identity/sign-in/ios/), +but it's easily extrapolated to any other OAuth2 library. + +```objective-c +// Base case - No authentication +[client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) { + ... +}]; + +... + +// Authenticating with Google + +// When signing the user in, ask her for the relevant scopes. +GIDSignIn.sharedInstance.scopes = @[@"https://www.googleapis.com/auth/grpc-testing"]; + +... + +#import + +// Create a not-yet-started RPC. We want to set the request headers on this object before starting +// it. +ProtoRPC *call = + [client RPCToSayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) { + ... + }]; + +// Set the access token to be used. +NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken; +call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]}]; + +// Start the RPC. +[call start]; +``` + +You can see a working example app, with a more detailed explanation, [here](examples/objective-c/auth_sample). + +### Authenticating with Google (Python) +```python +# Base case - No encryption +stub = early_adopter_create_GreeterService_stub('localhost', 50051) +... + +# With server authentication SSL/TLS +import oauth2client.client +credentials = oauth2client.GoogleCredentials.get_application_default() +scope = 'https://www.googleapis.com/auth/grpc-testing' +scoped_credentials = credentials.create_scoped([scope]) +access_token = scoped_credentials.get_access_token().access_token +metadata_transformer = ( + lambda x: [('Authorization', 'Bearer {}'.format(access_token))]) + +stub = early_adopter_create_GreeterService_stub( + 'localhost', 50051, secure=True, root_certificates=open('ca.pem').read(), + metadata_transformer=metadata_transformer) +... +``` +n.b.: the beta API will look different diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md index 84ceaa3081a..98cd5ab4fc3 100644 --- a/doc/interop-test-descriptions.md +++ b/doc/interop-test-descriptions.md @@ -4,7 +4,7 @@ Interoperability Test Case Descriptions Client and server use [test.proto](https://github.com/grpc/grpc/blob/master/test/proto/test.proto) and the [gRPC over HTTP/2 v2 -protocol](https://github.com/grpc/grpc-common/blob/master/PROTOCOL-HTTP2.md). +protocol](doc/PROTOCOL-HTTP2.md). Client ------ @@ -91,6 +91,87 @@ Client asserts: * clients are free to assert that the response payload body contents are zero and comparing the entire response message against a golden response +### large_compressed_unary + +This test verifies compressed unary calls succeed in sending messages. It +sends one unary request for every combination of compression algorithm and +payload type. + +In all scenarios, whether compression was actually performed is determined by +the compression bit in the response's message flags. The response's compression +value indicates which algorithm was used if said compression bit is set. + + +Server features: +* [UnaryCall][] +* [Compressable Payload][] +* [Uncompressable Payload][] +* [Random Payload][] + +Procedure: + 1. Client calls UnaryCall with: + + ``` + { + response_compression: + response_type: COMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + } + ``` + Client asserts: + * call was successful + * response payload type is COMPRESSABLE + * response compression is consistent with the requested one. + * if `response_compression == NONE`, the response MUST NOT have the + compressed message flag set. + * if `response_compression != NONE`, the response MUST have the compressed + message flag set. + * response payload body is 314159 bytes in size + * clients are free to assert that the response payload body contents are + zero and comparing the entire response message against a golden response + + + 2. Client calls UnaryCall with: + ``` + { + response_compression: + response_type: UNCOMPRESSABLE + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + } + ``` + Client asserts: + * call was successful + * response payload type is UNCOMPRESSABLE + * response compression is consistent with the requested one. + * the response MUST NOT have the compressed message flag set. + * response payload body is 314159 bytes in size + * clients are free to assert that the response payload body contents are + identical to the golden uncompressable data at `test/cpp/interop/rnd.dat`. + + + 3. Client calls UnaryCall with: + ``` + { + response_compression: + response_type: RANDOM + response_size: 314159 + payload:{ + body: 271828 bytes of zeros + } + } + ``` + Client asserts: + * call was successful + * response payload type is either COMPRESSABLE or UNCOMPRESSABLE + * the behavior is consistent with the randomly chosen incoming payload type, + as described in their respective sections. + ### client_streaming This test verifies that client-only streaming succeeds. @@ -184,6 +265,112 @@ Client asserts: * clients are free to assert that the response payload body contents are zero and comparing the entire response messages against golden responses +### server_compressed_streaming + +This test verifies that server-only compressed streaming succeeds. + +Server features: +* [StreamingOutputCall][] +* [Compressable Payload][] +* [Uncompressable Payload][] +* [Random Payload][] + + +Procedure: + 1. Client calls StreamingOutputCall with: + + ``` + { + response_compression: + response_type:COMPRESSABLE + response_parameters:{ + size: 31415 + } + response_parameters:{ + size: 9 + } + response_parameters:{ + size: 2653 + } + response_parameters:{ + size: 58979 + } + } + ``` + + Client asserts: + * call was successful + * exactly four responses + * response payloads are COMPRESSABLE + * response compression is consistent with the requested one. + * if `response_compression == NONE`, the response MUST NOT have the + compressed message flag set. + * if `response_compression != NONE`, the response MUST have the compressed + message flag set. + * response payload bodies are sized (in order): 31415, 9, 2653, 58979 + * clients are free to assert that the response payload body contents are + zero and comparing the entire response messages against golden responses + + + 2. Client calls StreamingOutputCall with: + + ``` + { + response_compression: + response_type:UNCOMPRESSABLE + response_parameters:{ + size: 31415 + } + response_parameters:{ + size: 9 + } + response_parameters:{ + size: 2653 + } + response_parameters:{ + size: 58979 + } + } + ``` + + Client asserts: + * call was successful + * exactly four responses + * response payloads are UNCOMPRESSABLE + * response compressions are consistent with the requested one. + * the responses MUST NOT have the compressed message flag set. + * response payload bodies are sized (in order): 31415, 9, 2653, 58979 + * clients are free to assert that the body of the responses are identical to + the golden uncompressable data at `test/cpp/interop/rnd.dat`. + + + 3. Client calls StreamingOutputCall with: + + ``` + { + response_compression: + response_type:RANDOM + response_parameters:{ + size: 31415 + } + response_parameters:{ + size: 9 + } + response_parameters:{ + size: 2653 + } + response_parameters:{ + size: 58979 + } + } + ``` + + Client asserts: + * call was successful + * response payload type is either COMPRESSABLE or UNCOMPRESSABLE + * the behavior is consistent with the randomly chosen incoming payload type, + as described in their respective sections. + ### ping_pong This test verifies that full duplex bidi is supported. @@ -825,6 +1012,21 @@ When the client requests COMPRESSABLE payload, the response includes a payload of the size requested containing all zeros and the payload type is COMPRESSABLE. +### Uncompressable Payload +[Uncompressable Payload]: #uncompressable-payload + +When the client requests UNCOMPRESSABLE payload, the response includes a payload +of the size requested containing uncompressable data and the payload type is +UNCOMPRESSABLE. A 512 kB dump from /dev/urandom is the current golden data, +stored at `test/cpp/interop/rnd.dat` + +### Random Payload +[Random Payload]: #random-payload + +When the client requests RANDOM payload, the response includes either a randomly +chosen COMPRESSABLE or UNCOMPRESSABLE payload. The data and the payload type +will be consistent with this choice. + ### Echo Status [Echo Status]: #echo-status When the client sends a response_status in the request payload, the server closes diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000000..6465115e185 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,450 @@ + +# Getting started + +Welcome to the developer documentation for gRPC, a language-neutral, +platform-neutral remote procedure call (RPC) system developed at Google. + +This document introduces you to gRPC with a quick overview and a simple +Hello World example. You'll find more tutorials and reference docs in this repository - more documentation is coming soon! + + +## Quick start +You can find quick start guides for each language, including installation instructions, examples, and tutorials here: +* [C++](examples/cpp) +* [Java](https://github.com/grpc/grpc-java/tree/master/examples) +* [Go](https://github.com/grpc/grpc-go/tree/master/examples) +* [Ruby](examples/ruby) +* [Node.js](examples/node) +* [Android Java](examples/java/android) +* [Python](examples/python/helloworld) +* [C#](examples/csharp) +* [Objective-C](examples/objective-c/route_guide) +* [PHP](examples/php) + +## What's in this repository? + +The `examples` directory contains documentation, resources, and examples +for all gRPC users. You can find examples and instructions specific to your +favourite language in the relevant subdirectory. + +You can find out about the gRPC source code repositories in +[`grpc`](https://github.com/grpc/grpc). Each repository provides instructions +for building the appropriate libraries for your language. + + +## What is gRPC? + +In gRPC a *client* application can directly call +methods on a *server* application on a different machine as if it was a +local object, making it easier for you to create distributed applications and +services. As in many RPC systems, gRPC is based around the idea of defining +a *service*, specifying the methods that can be called remotely with their +parameters and return types. On the server side, the server implements this +interface and runs a gRPC server to handle client calls. On the client side, +the client has a *stub* that provides exactly the same methods as the server. + + + +gRPC clients and servers can run and talk to each other in a variety of +environments - from servers inside Google to your own desktop - and can +be written in any of gRPC's [supported languages](#quickstart). So, for +example, you can easily create a gRPC server in Java with clients in Go, +Python, or Ruby. In addition, the latest Google APIs will have gRPC versions +of their interfaces, letting you easily build Google functionality into +your applications. + + +### Working with protocol buffers + +By default gRPC uses *protocol buffers*, Google’s +mature open source mechanism for serializing structured data (although it +can be used with other data formats such as JSON). As you'll +see in our example below, you define gRPC services using *proto files*, +with method parameters and return types specified as protocol buffer message +types. You +can find out lots more about protocol buffers in the [Protocol Buffers +documentation](https://developers.google.com/protocol-buffers/docs/overview). + +#### Protocol buffer versions + +While protocol buffers have been available for open source users for some +time, our examples use a new flavour of protocol buffers called proto3, +which has a slightly simplified syntax, some useful new features, and supports +lots more languages. This is currently available as an alpha release in +Java, C++, Java_nano (Android Java), Python, and Ruby from [the protocol buffers Github +repo](https://github.com/google/protobuf/releases), as well as a Go language +generator from [the golang/protobuf Github repo](https://github.com/golang/protobuf), with more languages in development. You can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3), and see +the major differences from the current default version in the [release notes](https://github.com/google/protobuf/releases). More proto3 documentation is coming soon. + +In general, while you *can* use proto2 (the current default protocol buffers version), we recommend that you use proto3 with gRPC as it lets you use the full range of gRPC-supported languages, as well as avoiding compatibility +issues with proto2 clients talking to proto3 servers and vice versa. + + +## Hello gRPC! + +Now that you know a bit more about gRPC, the easiest way to see how it +works is to look at a simple example. Our Hello World walks you through the +construction of a simple gRPC client-server application, showing you how to: + +- Create a protocol buffers schema that defines a simple RPC service with +a single +Hello World method. +- Create a Java server that implements this interface. +- Create a Java client that accesses the Java server. +- Create a Go client that accesses +the same Java server. + +The complete code for the example is available in the `examples` +directory. We use the Git versioning system for source code management: +however, you don't need to know anything about Git to follow along other +than how to install and run a few git commands. + +This is an introductory example rather than a comprehensive tutorial, so +don't worry if you're not a Go or +Java developer - the concepts are similar for all languages, and you can +find more implementations of our Hello World example in other languages (and full tutorials where available) in +the [language-specific folders](#quickstart) in this repository. Complete tutorials and +reference documentation for all gRPC languages are coming soon. + + +### Setup + +This section explains how to set up your local machine to work with +the example code. If you just want to read the example, you can go straight +to the [next step](#servicedef). + +#### Install Git + +You can download and install Git from http://git-scm.com/download. Once +installed you should have access to the git command line tool. The main +commands that you will need to use are: + +- git clone ... : clone a remote repository onto your local machine +- git checkout ... : check out a particular branch or a tagged version of +the code to hack on + +#### Install gRPC + +To build and install gRPC plugins and related tools: +- For Java, see the [Java quick start](https://github.com/grpc/grpc-java). +- For Go, see the [Go quick start](https://github.com/grpc/grpc-go). + +#### Get the source code + +The example code for our Java example lives in the `grpc-java` +GitHub repository. Clone this repository to your local machine by running the +following command: + + +``` +git clone https://github.com/grpc/grpc-java.git +``` + +Change your current directory to grpc-java/examples + +``` +cd grpc-java/examples +``` + + + + +### Defining a service + +The first step in creating our example is to define a *service*: an RPC +service specifies the methods that can be called remotely with their parameters +and return types. As you saw in the +[overview](#protocolbuffers) above, gRPC does this using [protocol +buffers](https://developers.google.com/protocol-buffers/docs/overview). We +use the protocol buffers interface definition language (IDL) to define our +service methods, and define the parameters and return +types as protocol buffer message types. Both the client and the +server use interface code generated from the service definition. + +Here's our example service definition, defined using protocol buffers IDL in +[helloworld.proto](https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto). The `Greeter` +service has one method, `SayHello`, that lets the server receive a single +`HelloRequest` +message from the remote client containing the user's name, then send back +a greeting in a single `HelloReply`. This is the simplest type of RPC you +can specify in gRPC - you can find out about other types in the tutorial for your chosen language. + +```proto +syntax = "proto3"; + +option java_package = "io.grpc.examples"; + +package helloworld; + +// The greeter service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} + +``` + + +### Generating gRPC code + +Once we've defined our service, we use the protocol buffer compiler +`protoc` to generate the special client and server code we need to create +our application - right now we're going to generate Java code, though you +can generate gRPC code in any gRPC-supported language (as you'll see later +in this example). The generated code contains both stub code for clients to +use and an abstract interface for servers to implement, both with the method +defined in our `Greeter` service. + +(If you didn't install the gRPC plugins and protoc on your system and are just reading along with +the example, you can skip this step and move +onto the next one where we examine the generated code.) + +For simplicity, we've provided a [Gradle build file](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle) with our Java examples that runs `protoc` for you with the appropriate plugin, input, and output: + +```shell +../gradlew build +``` + +This generates the following classes from our .proto, which contain all the generated code +we need to create our example: + +- `Helloworld.java`, which +has all the protocol buffer code to populate, serialize, and retrieve our +`HelloRequest` and `HelloReply` message types +- `GreeterGrpc.java`, which contains (along with some other useful code): + - an interface for `Greeter` servers to implement + + ```java + public static interface Greeter { + public void sayHello(io.grpc.examples.Helloworld.HelloRequest request, + io.grpc.stub.StreamObserver responseObserver); + } + ``` + + - _stub_ classes that clients can use to talk to a `Greeter` server. As you can see, they also implement the `Greeter` interface. + + ```java + public static class GreeterStub extends + io.grpc.stub.AbstractStub + implements Greeter { + ... + } + ``` + + +### Writing a server + +Now let's write some code! First we'll create a server application to implement +our service. Note that we're not going to go into a lot of detail about how +to create a server in this section. More detailed information will be in the +tutorial for your chosen language: check if there's one available yet in the relevant [quick start](#quickstart). + +Our server application has two classes: + +- a main server class that hosts the service implementation and allows access over the +network: [HelloWorldServer.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java). + + +- a simple service implementation class [GreeterImpl.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java#L51). + + +#### Service implementation + +[GreeterImpl.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java#L51) +actually implements our `Greeter` service's required behaviour. + +As you can see, the class `GreeterImpl` implements the interface +`GreeterGrpc.Greeter` that we [generated](#generating) from our proto +[IDL](https://github.com/grpc/grpc-java/tree/master/examples/src/main/proto) by implementing the method `sayHello`: + +```java + @Override + public void sayHello(HelloRequest req, StreamObserver responseObserver) { + HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); + responseObserver.onValue(reply); + responseObserver.onCompleted(); + } +``` +- `sayHello` takes two parameters: + - `HelloRequest`: the request + - `StreamObserver`: a response observer, which is + a special interface for the server to call with its response + +To return our response to the client and complete the call: + +1. We construct and populate a `HelloReply` response object with our exciting +message, as specified in our interface definition. +2. We return the `HelloReply` to the client and then specify that we've finished dealing with the RPC. + + +#### Server implementation + +[HelloWorldServer.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java) +shows the other main feature required to provide a gRPC service; making the service +implementation available from the network. + +```java + /* The port on which the server should run */ + private int port = 50051; + private ServerImpl server; + + private void start() throws Exception { + server = NettyServerBuilder.forPort(port) + .addService(GreeterGrpc.bindService(new GreeterImpl())) + .build().start(); + logger.info("Server started, listening on " + port); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + System.err.println("*** shutting down gRPC server since JVM is shutting down"); + HelloWorldServer.this.stop(); + System.err.println("*** server shut down"); + } + }); + } + +``` + +Here we create an appropriate gRPC server, binding the `Greeter` service +implementation that we created to a port. Then we start the server running: the server is now ready to receive +requests from `Greeter` service clients on our specified port. We'll cover +how all this works in a bit more detail in our language-specific documentation. + + +### Writing a client + +Client-side gRPC is pretty simple. In this step, we'll use the generated code +to write a simple client that can access the `Greeter` server we created +in the [previous section](#server). You can see the complete client code in +[HelloWorldClient.java](https://github.com/grpc/grpc-java/blob/master/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java). + +Again, we're not going to go into much detail about how to implement a client; +we'll leave that for the tutorial. + +#### Connecting to the service + +First let's look at how we connect to the `Greeter` server. First we need +to create a gRPC channel, specifying the hostname and port of the server we +want to connect to. Then we use the channel to construct the stub instance. + + +```java + private final ChannelImpl channel; + private final GreeterGrpc.GreeterBlockingStub blockingStub; + + public HelloWorldClient(String host, int port) { + channel = + NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.PLAINTEXT) + .build(); + blockingStub = GreeterGrpc.newBlockingStub(channel); + } + +``` + +In this case, we create a blocking stub. This means that the RPC call waits +for the server to respond, and will either return a response or raise an +exception. gRPC Java has other kinds of stubs that make non-blocking calls +to the server, where the response is returned asynchronously. + +#### Calling an RPC + +Now we can contact the service and obtain a greeting: + +1. We construct and fill in a `HelloRequest` to send to the service. +2. We call the stub's `hello()` RPC with our request and get a `HelloReply` +back, from which we can get our greeting. + + +```java + HelloRequest req = HelloRequest.newBuilder().setName(name).build(); + HelloReply reply = blockingStub.sayHello(req); + +``` + + +### Try it out! + +Our [Gradle build file](https://github.com/grpc/grpc-java/blob/master/examples/build.gradle) simplifies building and running the examples. + +You can build and run the server from the `grpc-java` root folder with: + +```sh +$ ./gradlew :grpc-examples:helloWorldServer +``` + +and in another terminal window confirm that it receives a message. + +```sh +$ ./gradlew :grpc-examples:helloWorldClient +``` + +### Adding another client + +Finally, let's look at one of gRPC's most useful features - interoperability +between code in different languages. So far, we've just looked at Java code +generated from and implementing our `Greeter` service definition. However, +as you'll see if you look at the language-specific subdirectories +in this repository, we've also generated and implemented `Greeter` +in some of gRPC's other supported languages. Each service +and client uses interface code generated from the same proto +that we used for the Java example. + +So, for example, if we visit the [`go` example +directory](https://github.com/grpc/grpc-go/tree/master/examples) and look at the +[`greeter_client`](https://github.com/grpc/grpc-go/blob/master/examples/greeter_client/main.go), +we can see that like the Java client, it connects to a `Greeter` service +at `localhost:50051` and uses a stub to call the `SayHello` method with a +`HelloRequest`: + +```go +const ( + address = "localhost:50051" + defaultName = "world" +) + +func main() { + // Set up a connection to the server. + conn, err := grpc.Dial(address) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := pb.NewGreeterClient(conn) + + // Contact the server and print out its response. + name := defaultName + if len(os.Args) > 1 { + name = os.Args[1] + } + r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: + name}) + if err != nil { + log.Fatalf("could not greet: %v", err) + } + log.Printf("Greeting: %s", r.Message) +} +``` + + +If we run the Java server from earlier in another terminal window, we can +run the Go client and connect to it just like the Java client, even though +it's written in a different language. + +``` +$ greeter_client +``` +## Read more! + +- You can find links to language-specific tutorials, examples, and other docs in each language's [quick start](#quickstart). +- [gRPC Authentication Support](doc/grpc-auth-support.md) introduces authentication support in gRPC with supported mechanisms and examples. diff --git a/examples/cpp/README.md b/examples/cpp/README.md new file mode 100644 index 00000000000..70418b44253 --- /dev/null +++ b/examples/cpp/README.md @@ -0,0 +1,65 @@ +#gRPC in 3 minutes (C++) + +## Installation + +To install gRPC on your system, follow the instructions here: +[https://github.com/grpc/grpc/blob/master/INSTALL](https://github.com/grpc/grpc/blob/master/INSTALL). + +## Hello C++ gRPC! + +Here's how to build and run the C++ implementation of the [Hello World](examples/protos/helloworld.proto) example used in [Getting started](https://github.com/grpc/grpc/tree/master/examples). + +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 https://github.com/grpc/grpc.git +``` + +Change your current directory to examples/cpp/helloworld + +```sh +$ cd examples/cpp/helloworld/ +``` + + +### 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 +``` + +### Client and server implementations + +The client implementation is at [greeter_client.cc](examples/cpp/helloworld/greeter_client.cc). + +The server implementation is at [greeter_server.cc](examples/cpp/helloworld/greeter_server.cc). + +### 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 the "Greeter received: Hello world" in the client side output. + +## Tutorial + +You can find a more detailed tutorial in [gRPC Basics: C++](examples/cpp/cpptutorial.md) diff --git a/examples/cpp/cpptutorial.md b/examples/cpp/cpptutorial.md new file mode 100644 index 00000000000..22be42d500d --- /dev/null +++ b/examples/cpp/cpptutorial.md @@ -0,0 +1,365 @@ +#gRPC Basics: C++ + +This tutorial provides a basic C++ programmer's introduction to working with gRPC. By walking through this example you'll learn how to: + +- Define a service in a .proto file. +- Generate server and client code using the protocol buffer compiler. +- Use the C++ gRPC API to write a simple client and server for your service. + +It assumes that you have read the [Getting started](https://github.com/grpc/grpc/tree/master/examples) guide and are familiar with [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). Note that the example in this tutorial uses the proto3 version of the protocol buffers language, which is currently in alpha release: you can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3) and see the [release notes](https://github.com/google/protobuf/releases) for the new version in the protocol buffers Github repository. + +This isn't a comprehensive guide to using gRPC in C++: more reference documentation is coming soon. + +## Why use gRPC? + +Our example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients. + +With gRPC we can define our service once in a .proto file and implement clients and servers in any of gRPC's supported languages, which in turn can be run in environments ranging from servers inside Google to your own tablet - all the complexity of communication between different languages and environments is handled for you by gRPC. We also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating. + +## Example code and setup + +The example code for our tutorial is in [examples/cpp/route_guide](examples/cpp/route_guide). To download the example, clone this repository by running the following command: +```shell +$ git clone https://github.com/grpc/grpc.git +``` + +Then change your current directory to `examples/cpp/route_guide`: +```shell +$ cd examples/cpp/route_guide +``` + +You also should have the relevant tools installed to generate the server and client interface code - if you don't already, follow the setup instructions in [the C++ quick start guide](examples/cpp). + + +## Defining the service + +Our first step (as you'll know from [Getting started](examples/) is to define the gRPC *service* and the method *request* and *response* types using [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). You can see the complete .proto file in [`examples/protos/route_guide.proto`](examples/protos/route_guide.proto). + +To define a service, you specify a named `service` in your .proto file: + +``` +service RouteGuide { + ... +} +``` + +Then you define `rpc` methods inside your service definition, specifying their request and response types. gRPC lets you define four kinds of service method, all of which are used in the `RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call. +``` + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *server-side streaming RPC* where the client sends a request to the server and gets a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. As you can see in our example, you specify a server-side streaming method by placing the `stream` keyword before the *response* type. +``` + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *client-side streaming RPC* where the client writes a sequence of messages and sends them to the server, again using a provided stream. Once the client has finished writing the messages, it waits for the server to read them all and return its response. You specify a client-side streaming method by placing the `stream` keyword before the *request* type. +``` + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectional streaming RPC* where both sides send a sequence of messages using a read-write stream. The two streams operate independently, so clients and servers can read and write in whatever order they like: for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved. You specify this type of method by placing the `stream` keyword before both the request and the response. +``` + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Our .proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods - for example, here's the `Point` message type: +``` +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + + +## Generating client and server code + +Next we need to generate the gRPC client and server interfaces from our .proto service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC C++ plugin. + +For simplicity, we've provided a [makefile](examples/cpp/route_guide/Makefile) that runs `protoc` for you with the appropriate plugin, input, and output (if you want to run this yourself, make sure you've installed protoc and followed the gRPC code [installation instructions](https://github.com/grpc/grpc/blob/master/INSTALL) first): + +```shell +$ make route_guide.grpc.pb.cc route_guide.pb.cc +``` + +which actually runs: + +```shell +$ protoc -I ../../protos --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` ../../protos/route_guide.proto +$ protoc -I ../../protos --cpp_out=. ../../protos/route_guide.proto +``` + +Running this command generates the following files in your current directory: +- `route_guide.pb.h`, the header which declares your generated message classes +- `route_guide.pb.cc`, which contains the implementation of your message classes +- `route_guide.grpc.pb.h`, the header which declares your generated service classes +- `route_guide.grpc.pb.cc`, which contains the implementation of your service classes + +These contain: +- All the protocol buffer code to populate, serialize, and retrieve our request and response message types +- A class called `RouteGuide` that contains + - a remote interface type (or *stub*) for clients to call with the methods defined in the `RouteGuide` service. + - two abstract interfaces for servers to implement, also with the methods defined in the `RouteGuide` service. + + + +## Creating the server + +First let's look at how we create a `RouteGuide` server. If you're only interested in creating gRPC clients, you can skip this section and go straight to [Creating the client](#client) (though you might find it interesting anyway!). + +There are two parts to making our `RouteGuide` service do its job: +- Implementing the service interface generated from our service definition: doing the actual "work" of our service. +- Running a gRPC server to listen for requests from clients and return the service responses. + +You can find our example `RouteGuide` server in [examples/cpp/route_guide/route_guide_server.cc](examples/cpp/route_guide/route_guide_server.cc). Let's take a closer look at how it works. + +### Implementing RouteGuide + +As you can see, our server has a `RouteGuideImpl` class that implements the generated `RouteGuide::Service` interface: + +```cpp +class RouteGuideImpl final : public RouteGuide::Service { +... +} +``` +In this case we're implementing the *synchronous* version of `RouteGuide`, which provides our default gRPC server behaviour. It's also possible to implement an asynchronous interface, `RouteGuide::AsyncService`, which allows you to further customize your server's threading behaviour, though we won't look at this in this tutorial. + +`RouteGuideImpl` implements all our service methods. Let's look at the simplest type first, `GetFeature`, which just gets a `Point` from the client and returns the corresponding feature information from its database in a `Feature`. + +```cpp + Status GetFeature(ServerContext* context, const Point* point, + Feature* feature) override { + feature->set_name(GetFeatureName(*point, feature_list_)); + feature->mutable_location()->CopyFrom(*point); + return Status::OK; + } +``` + +The method is passed a context object for the RPC, the client's `Point` protocol buffer request, and a `Feature` protocol buffer to fill in with the response information. In the method we populate the `Feature` with the appropriate information, and then `return` with an `OK` status to tell gRPC that we've finished dealing with the RPC and that the `Feature` can be returned to the client. + +Now let's look at something a bit more complicated - a streaming RPC. `ListFeatures` is a server-side streaming RPC, so we need to send back multiple `Feature`s to our client. + +```cpp + Status ListFeatures(ServerContext* context, const Rectangle* rectangle, + ServerWriter* writer) override { + auto lo = rectangle->lo(); + auto hi = rectangle->hi(); + long left = std::min(lo.longitude(), hi.longitude()); + long right = std::max(lo.longitude(), hi.longitude()); + long top = std::max(lo.latitude(), hi.latitude()); + long bottom = std::min(lo.latitude(), hi.latitude()); + for (const Feature& f : feature_list_) { + if (f.location().longitude() >= left && + f.location().longitude() <= right && + f.location().latitude() >= bottom && + f.location().latitude() <= top) { + writer->Write(f); + } + } + return Status::OK; + } +``` + +As you can see, instead of getting simple request and response objects in our method parameters, this time we get a request object (the `Rectangle` in which our client wants to find `Feature`s) and a special `ServerWriter` object. In the method, we populate as many `Feature` objects as we need to return, writing them to the `ServerWriter` using its `Write()` method. Finally, as in our simple RPC, we `return Status::OK` to tell gRPC that we've finished writing responses. + +If you look at the client-side streaming method `RecordRoute` you'll see it's quite similar, except this time we get a `ServerReader` instead of a request object and a single response. We use the `ServerReader`s `Read()` method to repeatedly read in our client's requests to a request object (in this case a `Point`) until there are no more messages: the server needs to check the return value of `Read()` after each call. If `true`, the stream is still good and it can continue reading; if `false` the message stream has ended. + +```cpp +while (stream->Read(&point)) { + ...//process client input +} +``` +Finally, let's look at our bidirectional streaming RPC `RouteChat()`. + +```cpp + Status RouteChat(ServerContext* context, + ServerReaderWriter* stream) override { + std::vector received_notes; + RouteNote note; + while (stream->Read(¬e)) { + for (const RouteNote& n : received_notes) { + if (n.location().latitude() == note.location().latitude() && + n.location().longitude() == note.location().longitude()) { + stream->Write(n); + } + } + received_notes.push_back(note); + } + + return Status::OK; + } +``` + +This time we get a `ServerReaderWriter` that can be used to read *and* write messages. The syntax for reading and writing here is exactly the same as for our client-streaming and server-streaming methods. Although each side will always get the other's messages in the order they were written, both the client and server can read and write in any order — the streams operate completely independently. + +### Starting the server + +Once we've implemented all our methods, we also need to start up a gRPC server so that clients can actually use our service. The following snippet shows how we do this for our `RouteGuide` service: + +```cpp +void RunServer(const std::string& db_path) { + std::string server_address("0.0.0.0:50051"); + RouteGuideImpl service(db_path); + + ServerBuilder builder; + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + server->Wait(); +} +``` +As you can see, we build and start our server using a `ServerBuilder`. To do this, we: + +1. Create an instance of our service implementation class `RouteGuideImpl`. +2. Create an instance of the factory `ServerBuilder` class. +3. Specify the address and port we want to use to listen for client requests using the builder's `AddListeningPort()` method. +4. Register our service implementation with the builder. +5. Call `BuildAndStart()` on the builder to create and start an RPC server for our service. +5. Call `Wait()` on the server to do a blocking wait until process is killed or `Shutdown()` is called. + + +## Creating the client + +In this section, we'll look at creating a C++ client for our `RouteGuide` service. You can see our complete example client code in [examples/cpp/route_guide/route_guide_client.cc](examples/cpp/route_guide/route_guide_client.cc). + +### Creating a stub + +To call service methods, we first need to create a *stub*. + +First we need to create a gRPC *channel* for our stub, specifying the server address and port we want to connect to and any special channel arguments - in our case we'll use the default `ChannelArguments` and no SSL: + +```cpp +grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials(), ChannelArguments()); +``` + +Now we can use the channel to create our stub using the `NewStub` method provided in the `RouteGuide` class we generated from our .proto. + +```cpp + public: + RouteGuideClient(std::shared_ptr channel, const std::string& db) + : stub_(RouteGuide::NewStub(channel)) { + ... + } +``` + +### Calling service methods + +Now let's look at how we call our service methods. Note that in this tutorial we're calling the *blocking/synchronous* versions of each method: this means that the RPC call waits for the server to respond, and will either return a response or raise an exception. + +#### Simple RPC + +Calling the simple RPC `GetFeature` is nearly as straightforward as calling a local method. + +```cpp + Point point; + Feature feature; + point = MakePoint(409146138, -746188906); + GetOneFeature(point, &feature); + +... + + bool GetOneFeature(const Point& point, Feature* feature) { + ClientContext context; + Status status = stub_->GetFeature(&context, point, feature); + ... + } +``` + +As you can see, we create and populate a request protocol buffer object (in our case `Point`), and create a response protocol buffer object for the server to fill in. We also create a `ClientContext` object for our call - you can optionally set RPC configuration values on this object, such as deadlines, though for now we'll use the default settings. Note that you cannot reuse this object between calls. Finally, we call the method on the stub, passing it the context, request, and response. If the method returns `OK`, then we can read the response information from the server from our response object. + +```cpp + std::cout << "Found feature called " << feature->name() << " at " + << feature->location().latitude()/kCoordFactor_ << ", " + << feature->location().longitude()/kCoordFactor_ << std::endl; +``` + +#### Streaming RPCs + +Now let's look at our streaming methods. If you've already read [Creating the server](#server) some of this may look very familiar - streaming RPCs are implemented in a similar way on both sides. Here's where we call the server-side streaming method `ListFeatures`, which returns a stream of geographical `Feature`s: + +```cpp + std::unique_ptr > reader( + stub_->ListFeatures(&context, rect)); + while (reader->Read(&feature)) { + std::cout << "Found feature called " + << feature.name() << " at " + << feature.location().latitude()/kCoordFactor_ << ", " + << feature.location().longitude()/kCoordFactor_ << std::endl; + } + Status status = reader->Finish(); +``` + +Instead of passing the method a context, request, and response, we pass it a context and request and get a `ClientReader` object back. The client can use the `ClientReader` to read the server's responses. We use the `ClientReader`s `Read()` method to repeatedly read in the server's responses to a response protocol buffer object (in this case a `Feature`) until there are no more messages: the client needs to check the return value of `Read()` after each call. If `true`, the stream is still good and it can continue reading; if `false` the message stream has ended. Finally, we call `Finish()` on the stream to complete the call and get our RPC status. + +The client-side streaming method `RecordRoute` is similar, except there we pass the method a context and response object and get back a `ClientWriter`. + +```cpp + std::unique_ptr > writer( + stub_->RecordRoute(&context, &stats)); + for (int i = 0; i < kPoints; i++) { + const Feature& f = feature_list_[feature_distribution(generator)]; + std::cout << "Visiting point " + << f.location().latitude()/kCoordFactor_ << ", " + << f.location().longitude()/kCoordFactor_ << std::endl; + if (!writer->Write(f.location())) { + // Broken stream. + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds( + delay_distribution(generator))); + } + writer->WritesDone(); + Status status = writer->Finish(); + if (status.IsOk()) { + std::cout << "Finished trip with " << stats.point_count() << " points\n" + << "Passed " << stats.feature_count() << " features\n" + << "Travelled " << stats.distance() << " meters\n" + << "It took " << stats.elapsed_time() << " seconds" + << std::endl; + } else { + std::cout << "RecordRoute rpc failed." << std::endl; + } +``` + +Once we've finished writing our client's requests to the stream using `Write()`, we need to call `WritesDone()` on the stream to let gRPC know that we've finished writing, then `Finish()` to complete the call and get our RPC status. If the status is `OK`, our response object that we initially passed to `RecordRoute()` will be populated with the server's response. + +Finally, let's look at our bidirectional streaming RPC `RouteChat()`. In this case, we just pass a context to the method and get back a `ClientReaderWriter`, which we can use to both write and read messages. + +```cpp + std::shared_ptr > stream( + stub_->RouteChat(&context)); +``` + +The syntax for reading and writing here is exactly the same as for our client-streaming and server-streaming methods. Although each side will always get the other's messages in the order they were written, both the client and server can read and write in any order — the streams operate completely independently. + +## Try it out! + +Build client and server: +```shell +$ make +``` +Run the server, which will listen on port 50051: +```shell +$ ./route_guide_server +``` +Run the client (in a different terminal): +```shell +$ ./route_guide_client +``` + diff --git a/examples/cpp/helloworld/Makefile b/examples/cpp/helloworld/Makefile new file mode 100644 index 00000000000..f2093afa055 --- /dev/null +++ b/examples/cpp/helloworld/Makefile @@ -0,0 +1,119 @@ +# +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +CXX = g++ +CPPFLAGS += -I/usr/local/include -pthread +CXXFLAGS += -std=c++11 +LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lgpr -lprotobuf -lpthread -ldl +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_async_client greeter_async_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 $@ + +greeter_async_client: helloworld.pb.o helloworld.grpc.pb.o greeter_async_client.o + $(CXX) $^ $(LDFLAGS) -o $@ + +greeter_async_server: helloworld.pb.o helloworld.grpc.pb.o greeter_async_server.o + $(CXX) $^ $(LDFLAGS) -o $@ + +%.grpc.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + +%.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< + +clean: + rm -f *.o *.pb.cc *.pb.h greeter_client greeter_server greeter_async_client greeter_async_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-alpha-1" + @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 diff --git a/examples/cpp/helloworld/README.md b/examples/cpp/helloworld/README.md new file mode 100644 index 00000000000..641aadd52d3 --- /dev/null +++ b/examples/cpp/helloworld/README.md @@ -0,0 +1,260 @@ +# gRPC C++ Hello World Tutorial + +### Install gRPC +Make sure you have installed gRPC on your system. Follow the instructions here: +[https://github.com/grpc/grpc/blob/master/INSTALL](https://github.com/grpc/grpc/blob/master/INSTALL). + +### 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 https://github.com/grpc/grpc.git +``` + +Change your current directory to examples/cpp/helloworld + +```sh +$ cd examples/cpp/helloworld/ +``` + +### Defining a service + +The first step in creating our example is to define a *service*: an RPC +service specifies the methods that can be called remotely with their parameters +and return types. As you saw in the +[overview](#protocolbuffers) above, gRPC does this using [protocol +buffers](https://developers.google.com/protocol-buffers/docs/overview). We +use the protocol buffers interface definition language (IDL) to define our +service methods, and define the parameters and return +types as protocol buffer message types. Both the client and the +server use interface code generated from the service definition. + +Here's our example service definition, defined using protocol buffers IDL in +[helloworld.proto](examples/protos/helloworld.proto). The `Greeting` +service has one method, `hello`, that lets the server receive a single +`HelloRequest` +message from the remote client containing the user's name, then send back +a greeting in a single `HelloReply`. This is the simplest type of RPC you +can specify in gRPC - we'll look at some other types later in this document. + +``` +syntax = "proto3"; + +option java_package = "ex.grpc"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} + +``` + + +### Generating gRPC code + +Once we've defined our service, we use the protocol buffer compiler +`protoc` to generate the special client and server code we need to create +our application. The generated code contains both stub code for clients to +use and an abstract interface for servers to implement, both with the method +defined in our `Greeting` service. + +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 + +- Create a channel. A channel is a logical connection to an endpoint. A gRPC + channel can be created with the target address, credentials to use and + arguments as follows + + ``` + auto channel = CreateChannel("localhost:50051", InsecureCredentials(), ChannelArguments()); + ``` + +- Create a stub. A stub implements the rpc methods of a service and in the + generated code, a method is provided to created a stub with a channel: + + ``` + auto stub = helloworld::Greeter::NewStub(channel); + ``` + +- Make a unary rpc, with `ClientContext` and request/response proto messages. + + ``` + ClientContext context; + HelloRequest request; + request.set_name("hello"); + HelloReply reply; + Status status = stub->SayHello(&context, request, &reply); + ``` + +- Check returned status and response. + + ``` + if (status.ok()) { + // check reply.message() + } else { + // rpc failed. + } + ``` + +For a working example, refer to [greeter_client.cc](examples/cpp/helloworld/greeter_client.cc). + +### Writing a server + +- Implement the service interface + + ``` + 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; + } + }; + + ``` + +- Build a server exporting the service + + ``` + GreeterServiceImpl service; + ServerBuilder builder; + builder.AddListeningPort("0.0.0.0:50051", grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + std::unique_ptr server(builder.BuildAndStart()); + ``` + +For a working example, refer to [greeter_server.cc](examples/cpp/helloworld/greeter_server.cc). + +### Writing asynchronous client and server + +gRPC uses `CompletionQueue` API for asynchronous operations. The basic work flow +is +- bind a `CompletionQueue` to a rpc call +- do something like a read or write, present with a unique `void*` tag +- call `CompletionQueue::Next` to wait for operations to complete. If a tag + appears, it indicates that the corresponding operation is complete. + +#### Async client + +The channel and stub creation code is the same as the sync client. + +- Initiate the rpc and create a handle for the rpc. Bind the rpc to a + `CompletionQueue`. + + ``` + CompletionQueue cq; + auto rpc = stub->AsyncSayHello(&context, request, &cq); + ``` + +- Ask for reply and final status, with a unique tag + + ``` + Status status; + rpc->Finish(&reply, &status, (void*)1); + ``` + +- Wait for the completion queue to return the next tag. The reply and status are + ready once the tag passed into the corresponding `Finish()` call is returned. + + ``` + void* got_tag; + bool ok = false; + cq.Next(&got_tag, &ok); + if (ok && got_tag == (void*)1) { + // check reply and status + } + ``` + +For a working example, refer to [greeter_async_client.cc](examples/cpp/helloworld/greeter_async_client.cc). + +#### Async server + +The server implementation requests a rpc call with a tag and then wait for the +completion queue to return the tag. The basic flow is + +- Build a server exporting the async service + + ``` + helloworld::Greeter::AsyncService service; + ServerBuilder builder; + builder.AddListeningPort("0.0.0.0:50051", InsecureServerCredentials()); + builder.RegisterAsyncService(&service); + auto cq = builder.AddCompletionQueue(); + auto server = builder.BuildAndStart(); + ``` + +- Request one rpc + + ``` + ServerContext context; + HelloRequest request; + ServerAsyncResponseWriter responder; + service.RequestSayHello(&context, &request, &responder, &cq, &cq, (void*)1); + ``` + +- Wait for the completion queue to return the tag. The context, request and + responder are ready once the tag is retrieved. + + ``` + HelloReply reply; + Status status; + void* got_tag; + bool ok = false; + cq.Next(&got_tag, &ok); + if (ok && got_tag == (void*)1) { + // set reply and status + responder.Finish(reply, status, (void*)2); + } + ``` + +- Wait for the completion queue to return the tag. The rpc is finished when the + tag is back. + + ``` + void* got_tag; + bool ok = false; + cq.Next(&got_tag, &ok); + if (ok && got_tag == (void*)2) { + // clean up + } + ``` + +To handle multiple rpcs, the async server creates an object `CallData` to +maintain the state of each rpc and use the address of it as the unique tag. For +simplicity the server only uses one completion queue for all events, and runs a +main loop in `HandleRpcs` to query the queue. + +For a working example, refer to [greeter_async_server.cc](examples/cpp/helloworld/greeter_async_server.cc). + + + + diff --git a/examples/cpp/helloworld/greeter_async_client.cc b/examples/cpp/helloworld/greeter_async_client.cc new file mode 100644 index 00000000000..d99f89b1359 --- /dev/null +++ b/examples/cpp/helloworld/greeter_async_client.cc @@ -0,0 +1,98 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "helloworld.grpc.pb.h" + +using grpc::Channel; +using grpc::ChannelArguments; +using grpc::ClientAsyncResponseReader; +using grpc::ClientContext; +using grpc::CompletionQueue; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +class GreeterClient { + public: + explicit GreeterClient(std::shared_ptr channel) + : stub_(Greeter::NewStub(channel)) {} + + std::string SayHello(const std::string& user) { + HelloRequest request; + request.set_name(user); + HelloReply reply; + ClientContext context; + CompletionQueue cq; + Status status; + + std::unique_ptr > rpc( + stub_->AsyncSayHello(&context, request, &cq)); + rpc->Finish(&reply, &status, (void*)1); + void* got_tag; + bool ok = false; + cq.Next(&got_tag, &ok); + GPR_ASSERT(ok); + GPR_ASSERT(got_tag == (void*)1); + + if (status.ok()) { + return reply.message(); + } else { + return "Rpc failed"; + } + } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char** argv) { + GreeterClient greeter(grpc::CreateChannel( + "localhost:50051", grpc::InsecureCredentials(), ChannelArguments())); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + + return 0; +} diff --git a/examples/cpp/helloworld/greeter_async_server.cc b/examples/cpp/helloworld/greeter_async_server.cc new file mode 100644 index 00000000000..b8a0dbf0e2e --- /dev/null +++ b/examples/cpp/helloworld/greeter_async_server.cc @@ -0,0 +1,136 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "helloworld.grpc.pb.h" + +using grpc::Server; +using grpc::ServerAsyncResponseWriter; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::ServerCompletionQueue; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +class ServerImpl final { + public: + ~ServerImpl() { + server_->Shutdown(); + cq_->Shutdown(); + } + + // There is no shutdown handling in this code. + void Run() { + std::string server_address("0.0.0.0:50051"); + + ServerBuilder builder; + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterAsyncService(&service_); + cq_ = builder.AddCompletionQueue(); + server_ = builder.BuildAndStart(); + std::cout << "Server listening on " << server_address << std::endl; + + HandleRpcs(); + } + + private: + class CallData { + public: + CallData(Greeter::AsyncService* service, ServerCompletionQueue* cq) + : service_(service), cq_(cq), responder_(&ctx_), status_(CREATE) { + Proceed(); + } + + void Proceed() { + if (status_ == CREATE) { + service_->RequestSayHello(&ctx_, &request_, &responder_, cq_, cq_, + this); + status_ = PROCESS; + } else if (status_ == PROCESS) { + new CallData(service_, cq_); + std::string prefix("Hello "); + reply_.set_message(prefix + request_.name()); + responder_.Finish(reply_, Status::OK, this); + status_ = FINISH; + } else { + delete this; + } + } + + private: + Greeter::AsyncService* service_; + ServerCompletionQueue* cq_; + ServerContext ctx_; + HelloRequest request_; + HelloReply reply_; + ServerAsyncResponseWriter responder_; + enum CallStatus { CREATE, PROCESS, FINISH }; + CallStatus status_; + }; + + // This can be run in multiple threads if needed. + void HandleRpcs() { + new CallData(&service_, cq_.get()); + void* tag; + bool ok; + while (true) { + cq_->Next(&tag, &ok); + GPR_ASSERT(ok); + static_cast(tag)->Proceed(); + } + } + + std::unique_ptr cq_; + Greeter::AsyncService service_; + std::unique_ptr server_; +}; + +int main(int argc, char** argv) { + ServerImpl server; + server.Run(); + + return 0; +} diff --git a/examples/cpp/helloworld/greeter_client.cc b/examples/cpp/helloworld/greeter_client.cc new file mode 100644 index 00000000000..dd0358ac95d --- /dev/null +++ b/examples/cpp/helloworld/greeter_client.cc @@ -0,0 +1,85 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include "helloworld.grpc.pb.h" + +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) + : stub_(Greeter::NewStub(channel)) {} + + std::string SayHello(const std::string& user) { + HelloRequest request; + request.set_name(user); + HelloReply reply; + ClientContext context; + + Status status = stub_->SayHello(&context, request, &reply); + if (status.ok()) { + return reply.message(); + } else { + return "Rpc failed"; + } + } + + private: + std::unique_ptr stub_; +}; + +int main(int argc, char** argv) { + GreeterClient greeter( + grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials(), + ChannelArguments())); + std::string user("world"); + std::string reply = greeter.SayHello(user); + std::cout << "Greeter received: " << reply << std::endl; + + return 0; +} diff --git a/examples/cpp/helloworld/greeter_server.cc b/examples/cpp/helloworld/greeter_server.cc new file mode 100644 index 00000000000..c1efdf563c4 --- /dev/null +++ b/examples/cpp/helloworld/greeter_server.cc @@ -0,0 +1,78 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include "helloworld.grpc.pb.h" + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; +using helloworld::HelloRequest; +using helloworld::HelloReply; +using helloworld::Greeter; + +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; + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + server->Wait(); +} + +int main(int argc, char** argv) { + RunServer(); + + return 0; +} diff --git a/examples/cpp/route_guide/Makefile b/examples/cpp/route_guide/Makefile new file mode 100644 index 00000000000..b906177af35 --- /dev/null +++ b/examples/cpp/route_guide/Makefile @@ -0,0 +1,113 @@ +# +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +CXX = g++ +CPPFLAGS += -I/usr/local/include -pthread +CXXFLAGS += -std=c++11 +LDFLAGS += -L/usr/local/lib -lgrpc++_unsecure -lgrpc -lgpr -lprotobuf -lpthread -ldl +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 route_guide_client route_guide_server + +route_guide_client: route_guide.pb.o route_guide.grpc.pb.o route_guide_client.o helper.o + $(CXX) $^ $(LDFLAGS) -o $@ + +route_guide_server: route_guide.pb.o route_guide.grpc.pb.o route_guide_server.o helper.o + $(CXX) $^ $(LDFLAGS) -o $@ + +%.grpc.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + +%.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< + +clean: + rm -f *.o *.pb.cc *.pb.h route_guide_client route_guide_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-alpha-1" + @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 diff --git a/examples/cpp/route_guide/helper.cc b/examples/cpp/route_guide/helper.cc new file mode 100644 index 00000000000..c2415afdf72 --- /dev/null +++ b/examples/cpp/route_guide/helper.cc @@ -0,0 +1,178 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "route_guide.grpc.pb.h" + +namespace examples { + +std::string GetDbFileContent(int argc, char** argv) { + std::string db_path; + std::string arg_str("--db_path"); + if (argc > 1) { + std::string argv_1 = argv[1]; + size_t start_position = argv_1.find(arg_str); + if (start_position != std::string::npos) { + start_position += arg_str.size(); + if (argv_1[start_position] == ' ' || + argv_1[start_position] == '=') { + db_path = argv_1.substr(start_position + 1); + } + } + } else { + db_path = "route_guide_db.json"; + } + std::ifstream db_file(db_path); + if (!db_file.is_open()) { + std::cout << "Failed to open " << db_path << std::endl; + return ""; + } + std::stringstream db; + db << db_file.rdbuf(); + return db.str(); +} + +// A simple parser for the json db file. It requires the db file to have the +// exact form of [{"location": { "latitude": 123, "longitude": 456}, "name": +// "the name can be empty" }, { ... } ... The spaces will be stripped. +class Parser { + public: + explicit Parser(const std::string& db) : db_(db) { + // Remove all spaces. + db_.erase( + std::remove_if(db_.begin(), db_.end(), isspace), + db_.end()); + if (!Match("[")) { + SetFailedAndReturnFalse(); + } + } + + bool Finished() { + return current_ >= db_.size(); + } + + bool TryParseOne(Feature* feature) { + if (failed_ || Finished() || !Match("{")) { + return SetFailedAndReturnFalse(); + } + if (!Match(location_) || !Match("{") || !Match(latitude_)) { + return SetFailedAndReturnFalse(); + } + long temp = 0; + ReadLong(&temp); + feature->mutable_location()->set_latitude(temp); + if (!Match(",") || !Match(longitude_)) { + return SetFailedAndReturnFalse(); + } + ReadLong(&temp); + feature->mutable_location()->set_longitude(temp); + if (!Match("},") || !Match(name_) || !Match("\"")) { + return SetFailedAndReturnFalse(); + } + size_t name_start = current_; + while (current_ != db_.size() && db_[current_++] != '"') { + } + if (current_ == db_.size()) { + return SetFailedAndReturnFalse(); + } + feature->set_name(db_.substr(name_start, current_-name_start-1)); + if (!Match("},")) { + if (db_[current_ - 1] == ']' && current_ == db_.size()) { + return true; + } + return SetFailedAndReturnFalse(); + } + return true; + } + + private: + + bool SetFailedAndReturnFalse() { + failed_ = true; + return false; + } + + bool Match(const std::string& prefix) { + bool eq = db_.substr(current_, prefix.size()) == prefix; + current_ += prefix.size(); + return eq; + } + + void ReadLong(long* l) { + size_t start = current_; + while (current_ != db_.size() && db_[current_] != ',' && db_[current_] != '}') { + current_++; + } + // It will throw an exception if fails. + *l = std::stol(db_.substr(start, current_ - start)); + } + + bool failed_ = false; + std::string db_; + size_t current_ = 0; + const std::string location_ = "\"location\":"; + const std::string latitude_ = "\"latitude\":"; + const std::string longitude_ = "\"longitude\":"; + const std::string name_ = "\"name\":"; +}; + +void ParseDb(const std::string& db, std::vector* feature_list) { + feature_list->clear(); + std::string db_content(db); + db_content.erase( + std::remove_if(db_content.begin(), db_content.end(), isspace), + db_content.end()); + + Parser parser(db_content); + Feature feature; + while (!parser.Finished()) { + feature_list->push_back(Feature()); + if (!parser.TryParseOne(&feature_list->back())) { + std::cout << "Error parsing the db file"; + feature_list->clear(); + break; + } + } + std::cout << "DB parsed, loaded " << feature_list->size() + << " features." << std::endl; +} + + +} // namespace examples + diff --git a/examples/pubsub/subscriber.h b/examples/cpp/route_guide/helper.h similarity index 68% rename from examples/pubsub/subscriber.h rename to examples/cpp/route_guide/helper.h index c5b1df0d3ec..65c93c1d347 100644 --- a/examples/pubsub/subscriber.h +++ b/examples/cpp/route_guide/helper.h @@ -31,37 +31,20 @@ * */ -#ifndef GRPC_EXAMPLES_PUBSUB_SUBSCRIBER_H -#define GRPC_EXAMPLES_PUBSUB_SUBSCRIBER_H +#ifndef GRPC_COMMON_CPP_ROUTE_GUIDE_HELPER_H_ +#define GRPC_COMMON_CPP_ROUTE_GUIDE_HELPER_H_ -#include +#include +#include -#include "examples/pubsub/pubsub.grpc.pb.h" - -namespace grpc { namespace examples { -namespace pubsub { - -class Subscriber { - public: - Subscriber(std::shared_ptr channel); - void Shutdown(); - - Status CreateSubscription(const grpc::string& topic, - const grpc::string& name); +class Feature; - Status GetSubscription(const grpc::string& name, grpc::string* topic); +std::string GetDbFileContent(int argc, char** argv); - Status DeleteSubscription(const grpc::string& name); +void ParseDb(const std::string& db, std::vector* feature_list); - Status Pull(const grpc::string& name, grpc::string* data); - - private: - std::unique_ptr stub_; -}; - -} // namespace pubsub } // namespace examples -} // namespace grpc -#endif // GRPC_EXAMPLES_PUBSUB_SUBSCRIBER_H +#endif // GRPC_COMMON_CPP_ROUTE_GUIDE_HELPER_H_ + diff --git a/examples/cpp/route_guide/route_guide_client.cc b/examples/cpp/route_guide/route_guide_client.cc new file mode 100644 index 00000000000..814def27f35 --- /dev/null +++ b/examples/cpp/route_guide/route_guide_client.cc @@ -0,0 +1,252 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "helper.h" +#include "route_guide.grpc.pb.h" + +using grpc::Channel; +using grpc::ChannelArguments; +using grpc::ClientContext; +using grpc::ClientReader; +using grpc::ClientReaderWriter; +using grpc::ClientWriter; +using grpc::Status; +using examples::Point; +using examples::Feature; +using examples::Rectangle; +using examples::RouteSummary; +using examples::RouteNote; +using examples::RouteGuide; + +Point MakePoint(long latitude, long longitude) { + Point p; + p.set_latitude(latitude); + p.set_longitude(longitude); + return p; +} + +Feature MakeFeature(const std::string& name, + long latitude, long longitude) { + Feature f; + f.set_name(name); + f.mutable_location()->CopyFrom(MakePoint(latitude, longitude)); + return f; +} + +RouteNote MakeRouteNote(const std::string& message, + long latitude, long longitude) { + RouteNote n; + n.set_message(message); + n.mutable_location()->CopyFrom(MakePoint(latitude, longitude)); + return n; +} + +class RouteGuideClient { + public: + RouteGuideClient(std::shared_ptr channel, const std::string& db) + : stub_(RouteGuide::NewStub(channel)) { + examples::ParseDb(db, &feature_list_); + } + + void GetFeature() { + Point point; + Feature feature; + point = MakePoint(409146138, -746188906); + GetOneFeature(point, &feature); + point = MakePoint(0, 0); + GetOneFeature(point, &feature); + } + + void ListFeatures() { + examples::Rectangle rect; + Feature feature; + ClientContext context; + + rect.mutable_lo()->set_latitude(400000000); + rect.mutable_lo()->set_longitude(-750000000); + rect.mutable_hi()->set_latitude(420000000); + rect.mutable_hi()->set_longitude(-730000000); + std::cout << "Looking for features between 40, -75 and 42, -73" + << std::endl; + + std::unique_ptr > reader( + stub_->ListFeatures(&context, rect)); + while (reader->Read(&feature)) { + std::cout << "Found feature called " + << feature.name() << " at " + << feature.location().latitude()/kCoordFactor_ << ", " + << feature.location().longitude()/kCoordFactor_ << std::endl; + } + Status status = reader->Finish(); + if (status.ok()) { + std::cout << "ListFeatures rpc succeeded." << std::endl; + } else { + std::cout << "ListFeatures rpc failed." << std::endl; + } + } + + void RecordRoute() { + Point point; + RouteSummary stats; + ClientContext context; + const int kPoints = 10; + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + + std::default_random_engine generator(seed); + std::uniform_int_distribution feature_distribution( + 0, feature_list_.size() - 1); + std::uniform_int_distribution delay_distribution( + 500, 1500); + + std::unique_ptr > writer( + stub_->RecordRoute(&context, &stats)); + for (int i = 0; i < kPoints; i++) { + const Feature& f = feature_list_[feature_distribution(generator)]; + std::cout << "Visiting point " + << f.location().latitude()/kCoordFactor_ << ", " + << f.location().longitude()/kCoordFactor_ << std::endl; + if (!writer->Write(f.location())) { + // Broken stream. + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds( + delay_distribution(generator))); + } + writer->WritesDone(); + Status status = writer->Finish(); + if (status.ok()) { + std::cout << "Finished trip with " << stats.point_count() << " points\n" + << "Passed " << stats.feature_count() << " features\n" + << "Travelled " << stats.distance() << " meters\n" + << "It took " << stats.elapsed_time() << " seconds" + << std::endl; + } else { + std::cout << "RecordRoute rpc failed." << std::endl; + } + } + + void RouteChat() { + ClientContext context; + + std::shared_ptr > stream( + stub_->RouteChat(&context)); + + std::thread writer([stream]() { + std::vector notes{ + MakeRouteNote("First message", 0, 0), + MakeRouteNote("Second message", 0, 1), + MakeRouteNote("Third message", 1, 0), + MakeRouteNote("Fourth message", 0, 0)}; + for (const RouteNote& note : notes) { + std::cout << "Sending message " << note.message() + << " at " << note.location().latitude() << ", " + << note.location().longitude() << std::endl; + stream->Write(note); + } + stream->WritesDone(); + }); + + RouteNote server_note; + while (stream->Read(&server_note)) { + std::cout << "Got message " << server_note.message() + << " at " << server_note.location().latitude() << ", " + << server_note.location().longitude() << std::endl; + } + writer.join(); + Status status = stream->Finish(); + if (!status.ok()) { + std::cout << "RouteChat rpc failed." << std::endl; + } + } + + private: + + bool GetOneFeature(const Point& point, Feature* feature) { + ClientContext context; + Status status = stub_->GetFeature(&context, point, feature); + if (!status.ok()) { + std::cout << "GetFeature rpc failed." << std::endl; + return false; + } + if (!feature->has_location()) { + std::cout << "Server returns incomplete feature." << std::endl; + return false; + } + if (feature->name().empty()) { + std::cout << "Found no feature at " + << feature->location().latitude()/kCoordFactor_ << ", " + << feature->location().longitude()/kCoordFactor_ << std::endl; + } else { + std::cout << "Found feature called " << feature->name() << " at " + << feature->location().latitude()/kCoordFactor_ << ", " + << feature->location().longitude()/kCoordFactor_ << std::endl; + } + return true; + } + + const float kCoordFactor_ = 10000000.0; + std::unique_ptr stub_; + std::vector feature_list_; +}; + +int main(int argc, char** argv) { + // Expect only arg: --db_path=path/to/route_guide_db.json. + std::string db = examples::GetDbFileContent(argc, argv); + RouteGuideClient guide( + grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials(), + ChannelArguments()), + db); + + std::cout << "-------------- GetFeature --------------" << std::endl; + guide.GetFeature(); + std::cout << "-------------- ListFeatures --------------" << std::endl; + guide.ListFeatures(); + std::cout << "-------------- RecordRoute --------------" << std::endl; + guide.RecordRoute(); + std::cout << "-------------- RouteChat --------------" << std::endl; + guide.RouteChat(); + + return 0; +} diff --git a/examples/cpp/route_guide/route_guide_db.json b/examples/cpp/route_guide/route_guide_db.json new file mode 100644 index 00000000000..9d6a980ab7d --- /dev/null +++ b/examples/cpp/route_guide/route_guide_db.json @@ -0,0 +1,601 @@ +[{ + "location": { + "latitude": 407838351, + "longitude": -746143763 + }, + "name": "Patriots Path, Mendham, NJ 07945, USA" +}, { + "location": { + "latitude": 408122808, + "longitude": -743999179 + }, + "name": "101 New Jersey 10, Whippany, NJ 07981, USA" +}, { + "location": { + "latitude": 413628156, + "longitude": -749015468 + }, + "name": "U.S. 6, Shohola, PA 18458, USA" +}, { + "location": { + "latitude": 419999544, + "longitude": -740371136 + }, + "name": "5 Conners Road, Kingston, NY 12401, USA" +}, { + "location": { + "latitude": 414008389, + "longitude": -743951297 + }, + "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" +}, { + "location": { + "latitude": 419611318, + "longitude": -746524769 + }, + "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" +}, { + "location": { + "latitude": 406109563, + "longitude": -742186778 + }, + "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" +}, { + "location": { + "latitude": 416802456, + "longitude": -742370183 + }, + "name": "352 South Mountain Road, Wallkill, NY 12589, USA" +}, { + "location": { + "latitude": 412950425, + "longitude": -741077389 + }, + "name": "Bailey Turn Road, Harriman, NY 10926, USA" +}, { + "location": { + "latitude": 412144655, + "longitude": -743949739 + }, + "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" +}, { + "location": { + "latitude": 415736605, + "longitude": -742847522 + }, + "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" +}, { + "location": { + "latitude": 413843930, + "longitude": -740501726 + }, + "name": "162 Merrill Road, Highland Mills, NY 10930, USA" +}, { + "location": { + "latitude": 410873075, + "longitude": -744459023 + }, + "name": "Clinton Road, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 412346009, + "longitude": -744026814 + }, + "name": "16 Old Brook Lane, Warwick, NY 10990, USA" +}, { + "location": { + "latitude": 402948455, + "longitude": -747903913 + }, + "name": "3 Drake Lane, Pennington, NJ 08534, USA" +}, { + "location": { + "latitude": 406337092, + "longitude": -740122226 + }, + "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" +}, { + "location": { + "latitude": 406421967, + "longitude": -747727624 + }, + "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" +}, { + "location": { + "latitude": 416318082, + "longitude": -749677716 + }, + "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" +}, { + "location": { + "latitude": 415301720, + "longitude": -748416257 + }, + "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" +}, { + "location": { + "latitude": 402647019, + "longitude": -747071791 + }, + "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" +}, { + "location": { + "latitude": 412567807, + "longitude": -741058078 + }, + "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" +}, { + "location": { + "latitude": 416855156, + "longitude": -744420597 + }, + "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" +}, { + "location": { + "latitude": 404663628, + "longitude": -744820157 + }, + "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" +}, { + "location": { + "latitude": 407113723, + "longitude": -749746483 + }, + "name": "" +}, { + "location": { + "latitude": 402133926, + "longitude": -743613249 + }, + "name": "" +}, { + "location": { + "latitude": 400273442, + "longitude": -741220915 + }, + "name": "" +}, { + "location": { + "latitude": 411236786, + "longitude": -744070769 + }, + "name": "" +}, { + "location": { + "latitude": 411633782, + "longitude": -746784970 + }, + "name": "211-225 Plains Road, Augusta, NJ 07822, USA" +}, { + "location": { + "latitude": 415830701, + "longitude": -742952812 + }, + "name": "" +}, { + "location": { + "latitude": 413447164, + "longitude": -748712898 + }, + "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" +}, { + "location": { + "latitude": 405047245, + "longitude": -749800722 + }, + "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" +}, { + "location": { + "latitude": 418858923, + "longitude": -746156790 + }, + "name": "" +}, { + "location": { + "latitude": 417951888, + "longitude": -748484944 + }, + "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" +}, { + "location": { + "latitude": 407033786, + "longitude": -743977337 + }, + "name": "26 East 3rd Street, New Providence, NJ 07974, USA" +}, { + "location": { + "latitude": 417548014, + "longitude": -740075041 + }, + "name": "" +}, { + "location": { + "latitude": 410395868, + "longitude": -744972325 + }, + "name": "" +}, { + "location": { + "latitude": 404615353, + "longitude": -745129803 + }, + "name": "" +}, { + "location": { + "latitude": 406589790, + "longitude": -743560121 + }, + "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" +}, { + "location": { + "latitude": 414653148, + "longitude": -740477477 + }, + "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" +}, { + "location": { + "latitude": 405957808, + "longitude": -743255336 + }, + "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" +}, { + "location": { + "latitude": 411733589, + "longitude": -741648093 + }, + "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" +}, { + "location": { + "latitude": 412676291, + "longitude": -742606606 + }, + "name": "1270 Lakes Road, Monroe, NY 10950, USA" +}, { + "location": { + "latitude": 409224445, + "longitude": -748286738 + }, + "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" +}, { + "location": { + "latitude": 406523420, + "longitude": -742135517 + }, + "name": "652 Garden Street, Elizabeth, NJ 07202, USA" +}, { + "location": { + "latitude": 401827388, + "longitude": -740294537 + }, + "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" +}, { + "location": { + "latitude": 410564152, + "longitude": -743685054 + }, + "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 408472324, + "longitude": -740726046 + }, + "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" +}, { + "location": { + "latitude": 412452168, + "longitude": -740214052 + }, + "name": "5 White Oak Lane, Stony Point, NY 10980, USA" +}, { + "location": { + "latitude": 409146138, + "longitude": -746188906 + }, + "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" +}, { + "location": { + "latitude": 404701380, + "longitude": -744781745 + }, + "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 409642566, + "longitude": -746017679 + }, + "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" +}, { + "location": { + "latitude": 408031728, + "longitude": -748645385 + }, + "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" +}, { + "location": { + "latitude": 413700272, + "longitude": -742135189 + }, + "name": "367 Prospect Road, Chester, NY 10918, USA" +}, { + "location": { + "latitude": 404310607, + "longitude": -740282632 + }, + "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" +}, { + "location": { + "latitude": 409319800, + "longitude": -746201391 + }, + "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" +}, { + "location": { + "latitude": 406685311, + "longitude": -742108603 + }, + "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" +}, { + "location": { + "latitude": 419018117, + "longitude": -749142781 + }, + "name": "43 Dreher Road, Roscoe, NY 12776, USA" +}, { + "location": { + "latitude": 412856162, + "longitude": -745148837 + }, + "name": "Swan Street, Pine Island, NY 10969, USA" +}, { + "location": { + "latitude": 416560744, + "longitude": -746721964 + }, + "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" +}, { + "location": { + "latitude": 405314270, + "longitude": -749836354 + }, + "name": "" +}, { + "location": { + "latitude": 414219548, + "longitude": -743327440 + }, + "name": "" +}, { + "location": { + "latitude": 415534177, + "longitude": -742900616 + }, + "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" +}, { + "location": { + "latitude": 406898530, + "longitude": -749127080 + }, + "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" +}, { + "location": { + "latitude": 407586880, + "longitude": -741670168 + }, + "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" +}, { + "location": { + "latitude": 400106455, + "longitude": -742870190 + }, + "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" +}, { + "location": { + "latitude": 400066188, + "longitude": -746793294 + }, + "name": "" +}, { + "location": { + "latitude": 418803880, + "longitude": -744102673 + }, + "name": "40 Mountain Road, Napanoch, NY 12458, USA" +}, { + "location": { + "latitude": 414204288, + "longitude": -747895140 + }, + "name": "" +}, { + "location": { + "latitude": 414777405, + "longitude": -740615601 + }, + "name": "" +}, { + "location": { + "latitude": 415464475, + "longitude": -747175374 + }, + "name": "48 North Road, Forestburgh, NY 12777, USA" +}, { + "location": { + "latitude": 404062378, + "longitude": -746376177 + }, + "name": "" +}, { + "location": { + "latitude": 405688272, + "longitude": -749285130 + }, + "name": "" +}, { + "location": { + "latitude": 400342070, + "longitude": -748788996 + }, + "name": "" +}, { + "location": { + "latitude": 401809022, + "longitude": -744157964 + }, + "name": "" +}, { + "location": { + "latitude": 404226644, + "longitude": -740517141 + }, + "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" +}, { + "location": { + "latitude": 410322033, + "longitude": -747871659 + }, + "name": "" +}, { + "location": { + "latitude": 407100674, + "longitude": -747742727 + }, + "name": "" +}, { + "location": { + "latitude": 418811433, + "longitude": -741718005 + }, + "name": "213 Bush Road, Stone Ridge, NY 12484, USA" +}, { + "location": { + "latitude": 415034302, + "longitude": -743850945 + }, + "name": "" +}, { + "location": { + "latitude": 411349992, + "longitude": -743694161 + }, + "name": "" +}, { + "location": { + "latitude": 404839914, + "longitude": -744759616 + }, + "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 414638017, + "longitude": -745957854 + }, + "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" +}, { + "location": { + "latitude": 412127800, + "longitude": -740173578 + }, + "name": "" +}, { + "location": { + "latitude": 401263460, + "longitude": -747964303 + }, + "name": "" +}, { + "location": { + "latitude": 412843391, + "longitude": -749086026 + }, + "name": "" +}, { + "location": { + "latitude": 418512773, + "longitude": -743067823 + }, + "name": "" +}, { + "location": { + "latitude": 404318328, + "longitude": -740835638 + }, + "name": "42-102 Main Street, Belford, NJ 07718, USA" +}, { + "location": { + "latitude": 419020746, + "longitude": -741172328 + }, + "name": "" +}, { + "location": { + "latitude": 404080723, + "longitude": -746119569 + }, + "name": "" +}, { + "location": { + "latitude": 401012643, + "longitude": -744035134 + }, + "name": "" +}, { + "location": { + "latitude": 404306372, + "longitude": -741079661 + }, + "name": "" +}, { + "location": { + "latitude": 403966326, + "longitude": -748519297 + }, + "name": "" +}, { + "location": { + "latitude": 405002031, + "longitude": -748407866 + }, + "name": "" +}, { + "location": { + "latitude": 409532885, + "longitude": -742200683 + }, + "name": "" +}, { + "location": { + "latitude": 416851321, + "longitude": -742674555 + }, + "name": "" +}, { + "location": { + "latitude": 406411633, + "longitude": -741722051 + }, + "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" +}, { + "location": { + "latitude": 413069058, + "longitude": -744597778 + }, + "name": "261 Van Sickle Road, Goshen, NY 10924, USA" +}, { + "location": { + "latitude": 418465462, + "longitude": -746859398 + }, + "name": "" +}, { + "location": { + "latitude": 411733222, + "longitude": -744228360 + }, + "name": "" +}, { + "location": { + "latitude": 410248224, + "longitude": -747127767 + }, + "name": "3 Hasta Way, Newton, NJ 07860, USA" +}] diff --git a/examples/cpp/route_guide/route_guide_server.cc b/examples/cpp/route_guide/route_guide_server.cc new file mode 100644 index 00000000000..b37539299a3 --- /dev/null +++ b/examples/cpp/route_guide/route_guide_server.cc @@ -0,0 +1,202 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "helper.h" +#include "route_guide.grpc.pb.h" + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::ServerReader; +using grpc::ServerReaderWriter; +using grpc::ServerWriter; +using grpc::Status; +using examples::Point; +using examples::Feature; +using examples::Rectangle; +using examples::RouteSummary; +using examples::RouteNote; +using examples::RouteGuide; +using std::chrono::system_clock; + + +float ConvertToRadians(float num) { + return num * 3.1415926 /180; +} + +float GetDistance(const Point& start, const Point& end) { + const float kCoordFactor = 10000000.0; + float lat_1 = start.latitude() / kCoordFactor; + float lat_2 = end.latitude() / kCoordFactor; + float lon_1 = start.longitude() / kCoordFactor; + float lon_2 = end.longitude() / kCoordFactor; + float lat_rad_1 = ConvertToRadians(lat_1); + float lat_rad_2 = ConvertToRadians(lat_2); + float delta_lat_rad = ConvertToRadians(lat_2-lat_1); + float delta_lon_rad = ConvertToRadians(lon_2-lon_1); + + float a = pow(sin(delta_lat_rad/2), 2) + cos(lat_rad_1) * cos(lat_rad_2) * + pow(sin(delta_lon_rad/2), 2); + float c = 2 * atan2(sqrt(a), sqrt(1-a)); + int R = 6371000; // metres + + return R * c; +} + +std::string GetFeatureName(const Point& point, + const std::vector& feature_list) { + for (const Feature& f : feature_list) { + if (f.location().latitude() == point.latitude() && + f.location().longitude() == point.longitude()) { + return f.name(); + } + } + return ""; +} + +class RouteGuideImpl final : public RouteGuide::Service { + public: + explicit RouteGuideImpl(const std::string& db) { + examples::ParseDb(db, &feature_list_); + } + + Status GetFeature(ServerContext* context, const Point* point, + Feature* feature) override { + feature->set_name(GetFeatureName(*point, feature_list_)); + feature->mutable_location()->CopyFrom(*point); + return Status::OK; + } + + Status ListFeatures(ServerContext* context, + const examples::Rectangle* rectangle, + ServerWriter* writer) override { + auto lo = rectangle->lo(); + auto hi = rectangle->hi(); + long left = (std::min)(lo.longitude(), hi.longitude()); + long right = (std::max)(lo.longitude(), hi.longitude()); + long top = (std::max)(lo.latitude(), hi.latitude()); + long bottom = (std::min)(lo.latitude(), hi.latitude()); + for (const Feature& f : feature_list_) { + if (f.location().longitude() >= left && + f.location().longitude() <= right && + f.location().latitude() >= bottom && + f.location().latitude() <= top) { + writer->Write(f); + } + } + return Status::OK; + } + + Status RecordRoute(ServerContext* context, ServerReader* reader, + RouteSummary* summary) override { + Point point; + int point_count = 0; + int feature_count = 0; + float distance = 0.0; + Point previous; + + system_clock::time_point start_time = system_clock::now(); + while (reader->Read(&point)) { + point_count++; + if (!GetFeatureName(point, feature_list_).empty()) { + feature_count++; + } + if (point_count != 1) { + distance += GetDistance(previous, point); + } + previous = point; + } + system_clock::time_point end_time = system_clock::now(); + summary->set_point_count(point_count); + summary->set_feature_count(feature_count); + summary->set_distance(static_cast(distance)); + auto secs = std::chrono::duration_cast( + end_time - start_time); + summary->set_elapsed_time(secs.count()); + + return Status::OK; + } + + Status RouteChat(ServerContext* context, + ServerReaderWriter* stream) override { + std::vector received_notes; + RouteNote note; + while (stream->Read(¬e)) { + for (const RouteNote& n : received_notes) { + if (n.location().latitude() == note.location().latitude() && + n.location().longitude() == note.location().longitude()) { + stream->Write(n); + } + } + received_notes.push_back(note); + } + + return Status::OK; + } + + private: + + std::vector feature_list_; +}; + +void RunServer(const std::string& db_path) { + std::string server_address("0.0.0.0:50051"); + RouteGuideImpl service(db_path); + + ServerBuilder builder; + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + std::unique_ptr server(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + server->Wait(); +} + +int main(int argc, char** argv) { + // Expect only arg: --db_path=path/to/route_guide_db.json. + std::string db = examples::GetDbFileContent(argc, argv); + RunServer(db); + + return 0; +} diff --git a/examples/csharp/.gitignore b/examples/csharp/.gitignore new file mode 100644 index 00000000000..585000ea2d5 --- /dev/null +++ b/examples/csharp/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +packages/ +*.suo +*.userprefs diff --git a/examples/csharp/.nuget/packages.config b/examples/csharp/.nuget/packages.config new file mode 100644 index 00000000000..b14373069f1 --- /dev/null +++ b/examples/csharp/.nuget/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/csharp/Greeter.sln b/examples/csharp/Greeter.sln new file mode 100644 index 00000000000..9430e94de99 --- /dev/null +++ b/examples/csharp/Greeter.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Greeter", "Greeter\Greeter.csproj", "{724DFC8C-4B57-4C3F-811C-0463BE2A2829}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreeterServer", "GreeterServer\GreeterServer.csproj", "{A7706C84-92D2-4B7A-B779-76B64D2950EC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GreeterClient", "GreeterClient\GreeterClient.csproj", "{ACCF4597-3748-4117-8633-1CB767F8CCC3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{FF1EBE95-F20D-4C27-8A61-D0125F3C8152}" + ProjectSection(SolutionItems) = preProject + .nuget\packages.config = .nuget\packages.config + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {724DFC8C-4B57-4C3F-811C-0463BE2A2829}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {724DFC8C-4B57-4C3F-811C-0463BE2A2829}.Debug|Any CPU.Build.0 = Debug|Any CPU + {724DFC8C-4B57-4C3F-811C-0463BE2A2829}.Release|Any CPU.ActiveCfg = Release|Any CPU + {724DFC8C-4B57-4C3F-811C-0463BE2A2829}.Release|Any CPU.Build.0 = Release|Any CPU + {A7706C84-92D2-4B7A-B779-76B64D2950EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A7706C84-92D2-4B7A-B779-76B64D2950EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A7706C84-92D2-4B7A-B779-76B64D2950EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7706C84-92D2-4B7A-B779-76B64D2950EC}.Release|Any CPU.Build.0 = Release|Any CPU + {ACCF4597-3748-4117-8633-1CB767F8CCC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACCF4597-3748-4117-8633-1CB767F8CCC3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACCF4597-3748-4117-8633-1CB767F8CCC3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACCF4597-3748-4117-8633-1CB767F8CCC3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = Greeter\Greeter.csproj + EndGlobalSection +EndGlobal diff --git a/examples/csharp/Greeter/.gitignore b/examples/csharp/Greeter/.gitignore new file mode 100644 index 00000000000..1746e3269ed --- /dev/null +++ b/examples/csharp/Greeter/.gitignore @@ -0,0 +1,2 @@ +bin +obj diff --git a/examples/csharp/Greeter/Greeter.csproj b/examples/csharp/Greeter/Greeter.csproj new file mode 100644 index 00000000000..b8f965dbd22 --- /dev/null +++ b/examples/csharp/Greeter/Greeter.csproj @@ -0,0 +1,81 @@ + + + + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {724DFC8C-4B57-4C3F-811C-0463BE2A2829} + Library + Greeter + Greeter + v4.5 + 927432a0 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + full + true + bin\Release + prompt + 4 + false + + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll + + + False + ..\packages\Grpc.Core.0.6.0\lib\net45\Grpc.Core.dll + + + + False + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/Greeter/Helloworld.cs b/examples/csharp/Greeter/Helloworld.cs new file mode 100644 index 00000000000..923a4271e98 --- /dev/null +++ b/examples/csharp/Greeter/Helloworld.cs @@ -0,0 +1,617 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: helloworld.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.ProtocolBuffers; +using pbc = global::Google.ProtocolBuffers.Collections; +using pbd = global::Google.ProtocolBuffers.Descriptors; +using scg = global::System.Collections.Generic; +namespace helloworld { + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Helloworld { + + #region Extension registration + public static void RegisterAllExtensions(pb::ExtensionRegistry registry) { + } + #endregion + #region Static variables + internal static pbd::MessageDescriptor internal__static_helloworld_HelloRequest__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable internal__static_helloworld_HelloRequest__FieldAccessorTable; + internal static pbd::MessageDescriptor internal__static_helloworld_HelloReply__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable internal__static_helloworld_HelloReply__FieldAccessorTable; + #endregion + #region Descriptor + public static pbd::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbd::FileDescriptor descriptor; + + static Helloworld() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChBoZWxsb3dvcmxkLnByb3RvEgpoZWxsb3dvcmxkIhwKDEhlbGxvUmVxdWVz", + "dBIMCgRuYW1lGAEgASgJIh0KCkhlbGxvUmVwbHkSDwoHbWVzc2FnZRgBIAEo", + "CTJJCgdHcmVldGVyEj4KCFNheUhlbGxvEhguaGVsbG93b3JsZC5IZWxsb1Jl", + "cXVlc3QaFi5oZWxsb3dvcmxkLkhlbGxvUmVwbHkiAEISChBpby5ncnBjLmV4", + "YW1wbGVz")); + pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) { + descriptor = root; + internal__static_helloworld_HelloRequest__Descriptor = Descriptor.MessageTypes[0]; + internal__static_helloworld_HelloRequest__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable(internal__static_helloworld_HelloRequest__Descriptor, + new string[] { "Name", }); + internal__static_helloworld_HelloReply__Descriptor = Descriptor.MessageTypes[1]; + internal__static_helloworld_HelloReply__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable(internal__static_helloworld_HelloReply__Descriptor, + new string[] { "Message", }); + pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance(); + RegisterAllExtensions(registry); + return registry; + }; + pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbd::FileDescriptor[] { + }, assigner); + } + #endregion + + } + #region Messages + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class HelloRequest : pb::GeneratedMessage { + private HelloRequest() { } + private static readonly HelloRequest defaultInstance = new HelloRequest().MakeReadOnly(); + private static readonly string[] _helloRequestFieldNames = new string[] { "name" }; + private static readonly uint[] _helloRequestFieldTags = new uint[] { 10 }; + public static HelloRequest DefaultInstance { + get { return defaultInstance; } + } + + public override HelloRequest DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override HelloRequest ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::helloworld.Helloworld.internal__static_helloworld_HelloRequest__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::helloworld.Helloworld.internal__static_helloworld_HelloRequest__FieldAccessorTable; } + } + + public const int NameFieldNumber = 1; + private bool hasName; + private string name_ = ""; + public bool HasName { + get { return hasName; } + } + public string Name { + get { return name_; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _helloRequestFieldNames; + if (hasName) { + output.WriteString(1, field_names[0], Name); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasName) { + size += pb::CodedOutputStream.ComputeStringSize(1, Name); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static HelloRequest ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static HelloRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static HelloRequest ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static HelloRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static HelloRequest ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static HelloRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static HelloRequest ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static HelloRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static HelloRequest ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static HelloRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private HelloRequest MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(HelloRequest prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(HelloRequest cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private HelloRequest result; + + private HelloRequest PrepareBuilder() { + if (resultIsReadOnly) { + HelloRequest original = result; + result = new HelloRequest(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override HelloRequest MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::helloworld.HelloRequest.Descriptor; } + } + + public override HelloRequest DefaultInstanceForType { + get { return global::helloworld.HelloRequest.DefaultInstance; } + } + + public override HelloRequest BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is HelloRequest) { + return MergeFrom((HelloRequest) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(HelloRequest other) { + if (other == global::helloworld.HelloRequest.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasName) { + Name = other.Name; + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_helloRequestFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _helloRequestFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 10: { + result.hasName = input.ReadString(ref result.name_); + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasName { + get { return result.hasName; } + } + public string Name { + get { return result.Name; } + set { SetName(value); } + } + public Builder SetName(string value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasName = true; + result.name_ = value; + return this; + } + public Builder ClearName() { + PrepareBuilder(); + result.hasName = false; + result.name_ = ""; + return this; + } + } + static HelloRequest() { + object.ReferenceEquals(global::helloworld.Helloworld.Descriptor, null); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class HelloReply : pb::GeneratedMessage { + private HelloReply() { } + private static readonly HelloReply defaultInstance = new HelloReply().MakeReadOnly(); + private static readonly string[] _helloReplyFieldNames = new string[] { "message" }; + private static readonly uint[] _helloReplyFieldTags = new uint[] { 10 }; + public static HelloReply DefaultInstance { + get { return defaultInstance; } + } + + public override HelloReply DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override HelloReply ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::helloworld.Helloworld.internal__static_helloworld_HelloReply__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::helloworld.Helloworld.internal__static_helloworld_HelloReply__FieldAccessorTable; } + } + + public const int MessageFieldNumber = 1; + private bool hasMessage; + private string message_ = ""; + public bool HasMessage { + get { return hasMessage; } + } + public string Message { + get { return message_; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _helloReplyFieldNames; + if (hasMessage) { + output.WriteString(1, field_names[0], Message); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasMessage) { + size += pb::CodedOutputStream.ComputeStringSize(1, Message); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static HelloReply ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static HelloReply ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static HelloReply ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static HelloReply ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static HelloReply ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static HelloReply ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static HelloReply ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static HelloReply ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static HelloReply ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static HelloReply ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private HelloReply MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(HelloReply prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(HelloReply cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private HelloReply result; + + private HelloReply PrepareBuilder() { + if (resultIsReadOnly) { + HelloReply original = result; + result = new HelloReply(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override HelloReply MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::helloworld.HelloReply.Descriptor; } + } + + public override HelloReply DefaultInstanceForType { + get { return global::helloworld.HelloReply.DefaultInstance; } + } + + public override HelloReply BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is HelloReply) { + return MergeFrom((HelloReply) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(HelloReply other) { + if (other == global::helloworld.HelloReply.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasMessage) { + Message = other.Message; + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_helloReplyFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _helloReplyFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 10: { + result.hasMessage = input.ReadString(ref result.message_); + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasMessage { + get { return result.hasMessage; } + } + public string Message { + get { return result.Message; } + set { SetMessage(value); } + } + public Builder SetMessage(string value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasMessage = true; + result.message_ = value; + return this; + } + public Builder ClearMessage() { + PrepareBuilder(); + result.hasMessage = false; + result.message_ = ""; + return this; + } + } + static HelloReply() { + object.ReferenceEquals(global::helloworld.Helloworld.Descriptor, null); + } + } + + #endregion + +} + +#endregion Designer generated code diff --git a/examples/csharp/Greeter/HelloworldGrpc.cs b/examples/csharp/Greeter/HelloworldGrpc.cs new file mode 100644 index 00000000000..1ca9d2899b3 --- /dev/null +++ b/examples/csharp/Greeter/HelloworldGrpc.cs @@ -0,0 +1,78 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: helloworld.proto +#region Designer generated code + +using System; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; + +namespace helloworld { + public static class Greeter + { + static readonly string __ServiceName = "helloworld.Greeter"; + + static readonly Marshaller __Marshaller_HelloRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::helloworld.HelloRequest.ParseFrom); + static readonly Marshaller __Marshaller_HelloReply = Marshallers.Create((arg) => arg.ToByteArray(), global::helloworld.HelloReply.ParseFrom); + + static readonly Method __Method_SayHello = new Method( + MethodType.Unary, + "SayHello", + __Marshaller_HelloRequest, + __Marshaller_HelloReply); + + // client-side stub interface + public interface IGreeterClient + { + global::helloworld.HelloReply SayHello(global::helloworld.HelloRequest request, CancellationToken token = default(CancellationToken)); + Task SayHelloAsync(global::helloworld.HelloRequest request, CancellationToken token = default(CancellationToken)); + } + + // server-side interface + public interface IGreeter + { + Task SayHello(ServerCallContext context, global::helloworld.HelloRequest request); + } + + // client stub + public class GreeterClient : AbstractStub, IGreeterClient + { + public GreeterClient(Channel channel) : this(channel, StubConfiguration.Default) + { + } + public GreeterClient(Channel channel, StubConfiguration config) : base(channel, config) + { + } + public global::helloworld.HelloReply SayHello(global::helloworld.HelloRequest request, CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_SayHello); + return Calls.BlockingUnaryCall(call, request, token); + } + public Task SayHelloAsync(global::helloworld.HelloRequest request, CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_SayHello); + return Calls.AsyncUnaryCall(call, request, token); + } + } + + // creates service definition that can be registered with a server + public static ServerServiceDefinition BindService(IGreeter serviceImpl) + { + return ServerServiceDefinition.CreateBuilder(__ServiceName) + .AddMethod(__Method_SayHello, serviceImpl.SayHello).Build(); + } + + // creates a new client stub + public static IGreeterClient NewStub(Channel channel) + { + return new GreeterClient(channel); + } + + // creates a new client stub + public static IGreeterClient NewStub(Channel channel, StubConfiguration config) + { + return new GreeterClient(channel, config); + } + } +} +#endregion diff --git a/examples/csharp/Greeter/Properties/AssemblyInfo.cs b/examples/csharp/Greeter/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..b9d0dc264d5 --- /dev/null +++ b/examples/csharp/Greeter/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle("Greeter")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("jtattermusch")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/examples/csharp/Greeter/packages.config b/examples/csharp/Greeter/packages.config new file mode 100644 index 00000000000..5922553bc37 --- /dev/null +++ b/examples/csharp/Greeter/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/Greeter/protos/helloworld.proto b/examples/csharp/Greeter/protos/helloworld.proto new file mode 100644 index 00000000000..e02ebd94e7c --- /dev/null +++ b/examples/csharp/Greeter/protos/helloworld.proto @@ -0,0 +1,52 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// TODO(jtattermusch): as of now, C# protobufs don't officially support +// proto3. +syntax = "proto2"; + +option java_package = "io.grpc.examples"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + optional string name = 1; +} + +// The response message containing the greetings +message HelloReply { + optional string message = 1; +} diff --git a/examples/csharp/GreeterClient/.gitignore b/examples/csharp/GreeterClient/.gitignore new file mode 100644 index 00000000000..1746e3269ed --- /dev/null +++ b/examples/csharp/GreeterClient/.gitignore @@ -0,0 +1,2 @@ +bin +obj diff --git a/examples/csharp/GreeterClient/GreeterClient.csproj b/examples/csharp/GreeterClient/GreeterClient.csproj new file mode 100644 index 00000000000..59b768af018 --- /dev/null +++ b/examples/csharp/GreeterClient/GreeterClient.csproj @@ -0,0 +1,84 @@ + + + + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {ACCF4597-3748-4117-8633-1CB767F8CCC3} + Exe + GreeterClient + GreeterClient + v4.5 + 985ca8be + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + full + true + bin\Release + prompt + 4 + true + + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll + + + False + ..\packages\Grpc.Core.0.6.0\lib\net45\Grpc.Core.dll + + + + False + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll + + + + + + + + + + {724DFC8C-4B57-4C3F-811C-0463BE2A2829} + Greeter + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/GreeterClient/Program.cs b/examples/csharp/GreeterClient/Program.cs new file mode 100644 index 00000000000..61c29762b12 --- /dev/null +++ b/examples/csharp/GreeterClient/Program.cs @@ -0,0 +1,25 @@ +using System; +using Grpc.Core; +using helloworld; + +namespace GreeterClient +{ + class ClientMainClass + { + public static void Main(string[] args) + { + GrpcEnvironment.Initialize(); + + using (Channel channel = new Channel("127.0.0.1:50051")) + { + var client = Greeter.NewStub(channel); + String user = "you"; + + var reply = client.SayHello(new HelloRequest.Builder { Name = user }.Build()); + Console.WriteLine("Greeting: " + reply.Message); + } + + GrpcEnvironment.Shutdown(); + } + } +} diff --git a/examples/csharp/GreeterClient/Properties/AssemblyInfo.cs b/examples/csharp/GreeterClient/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..1422e952d8b --- /dev/null +++ b/examples/csharp/GreeterClient/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle("GreeterClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("jtattermusch")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/examples/csharp/GreeterClient/packages.config b/examples/csharp/GreeterClient/packages.config new file mode 100644 index 00000000000..5922553bc37 --- /dev/null +++ b/examples/csharp/GreeterClient/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/GreeterServer/.gitignore b/examples/csharp/GreeterServer/.gitignore new file mode 100644 index 00000000000..1746e3269ed --- /dev/null +++ b/examples/csharp/GreeterServer/.gitignore @@ -0,0 +1,2 @@ +bin +obj diff --git a/examples/csharp/GreeterServer/GreeterServer.csproj b/examples/csharp/GreeterServer/GreeterServer.csproj new file mode 100644 index 00000000000..cd50d6cd529 --- /dev/null +++ b/examples/csharp/GreeterServer/GreeterServer.csproj @@ -0,0 +1,84 @@ + + + + + + + Debug + AnyCPU + 10.0.0 + 2.0 + {A7706C84-92D2-4B7A-B779-76B64D2950EC} + Exe + GreeterServer + GreeterServer + v4.5 + a1eeb1d8 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + true + + + full + true + bin\Release + prompt + 4 + true + + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll + + + False + ..\packages\Grpc.Core.0.6.0\lib\net45\Grpc.Core.dll + + + + False + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll + + + + + + + + + + {724DFC8C-4B57-4C3F-811C-0463BE2A2829} + Greeter + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/GreeterServer/Program.cs b/examples/csharp/GreeterServer/Program.cs new file mode 100644 index 00000000000..9482797c3b9 --- /dev/null +++ b/examples/csharp/GreeterServer/Program.cs @@ -0,0 +1,37 @@ +using System; +using System.Threading.Tasks; +using Grpc.Core; +using helloworld; + +namespace GreeterServer +{ + class GreeterImpl : Greeter.IGreeter + { + // Server side handler of the SayHello RPC + public Task SayHello(ServerCallContext context, HelloRequest request) + { + var reply = new HelloReply.Builder { Message = "Hello " + request.Name }.Build(); + return Task.FromResult(reply); + } + } + + class ServerMainClass + { + public static void Main(string[] args) + { + GrpcEnvironment.Initialize(); + + Server server = new Server(); + server.AddServiceDefinition(Greeter.BindService(new GreeterImpl())); + int port = server.AddListeningPort("localhost", 50051); + server.Start(); + + Console.WriteLine("Greeter server listening on port " + port); + Console.WriteLine("Press any key to stop the server..."); + Console.ReadKey(); + + server.ShutdownAsync().Wait(); + GrpcEnvironment.Shutdown(); + } + } +} diff --git a/examples/csharp/GreeterServer/Properties/AssemblyInfo.cs b/examples/csharp/GreeterServer/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..f8a8d521d85 --- /dev/null +++ b/examples/csharp/GreeterServer/Properties/AssemblyInfo.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. +[assembly: AssemblyTitle("GreeterServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("jtattermusch")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. +[assembly: AssemblyVersion("1.0.*")] +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/examples/csharp/GreeterServer/packages.config b/examples/csharp/GreeterServer/packages.config new file mode 100644 index 00000000000..5922553bc37 --- /dev/null +++ b/examples/csharp/GreeterServer/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/README.md b/examples/csharp/README.md new file mode 100644 index 00000000000..fcdcc735f9b --- /dev/null +++ b/examples/csharp/README.md @@ -0,0 +1,72 @@ +gRPC in 3 minutes (C#) +======================== + +BACKGROUND +------------- +For this sample, we've already generated the server and client stubs from `helloworld.proto`. +Example projects depend on NuGet packages `Grpc` and `Google.ProtocolBuffers` which have been already added to the project for you. + +PREREQUISITES +------------- +**Windows** +- .NET 4.5+ +- VS 2013 (with NuGet plugin installed) + +**Linux (Mono)** +- Mono +- Monodevelop 5.9 with NuGet Add-in installed (older versions might work) + +**MacOS (Mono)** +- Xamarin Studio (with NuGet plugin installed) + +BUILD +------- + +**Windows** +- Clone this repository. + +- Open solution `Greeter.sln` with Visual Studio + +- Build the solution (this will automatically download NuGet dependencies) + +**Linux (Mono)** +- Clone this repository. + +- Install gRPC C Core using instructions in https://github.com/grpc/homebrew-grpc + +- gRPC C# depends on native shared library `libgrpc_csharp_ext.so`. To make it visible + to Mono runtime, follow instructions in [Using gRPC C# on Linux](https://github.com/grpc/grpc/tree/master/src/csharp#usage-linux-mono) + +- Open solution `Greeter.sln` in MonoDevelop (you need to manually restore dependencies by using `mono nuget.exe restore` if you don't have NuGet add-in) + +- Build the solution. + +**MacOS (Mono)** +- See [Using gRPC C# on MacOS](https://github.com/grpc/grpc/tree/master/src/csharp#usage-macos-mono) for more info + on MacOS support. + +Try it! +------- + +- Run the server + + ``` + > cd GreeterServer/bin/Debug + > GreeterServer.exe + ``` + +- Run the client + + ``` + > cd GreeterClient/bin/Debug + > GreeterClient.exe + ``` + +You can also run the server and client directly from Visual Studio. + +On Linux or Mac, use `mono GreeterServer.exe` and `mono GreeterClient.exe` to run the server and client. + +Tutorial +-------- + +You can find a more detailed tutorial in [gRPC Basics: C#](examples/csharp/route_guide/README.md) diff --git a/examples/csharp/route_guide/.gitignore b/examples/csharp/route_guide/.gitignore new file mode 100644 index 00000000000..585000ea2d5 --- /dev/null +++ b/examples/csharp/route_guide/.gitignore @@ -0,0 +1,5 @@ +bin/ +obj/ +packages/ +*.suo +*.userprefs diff --git a/examples/csharp/route_guide/.nuget/packages.config b/examples/csharp/route_guide/.nuget/packages.config new file mode 100644 index 00000000000..b14373069f1 --- /dev/null +++ b/examples/csharp/route_guide/.nuget/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/csharp/route_guide/README.md b/examples/csharp/route_guide/README.md new file mode 100644 index 00000000000..c3262c9b8ae --- /dev/null +++ b/examples/csharp/route_guide/README.md @@ -0,0 +1,409 @@ +#gRPC Basics: C# # + +This tutorial provides a basic C# programmer's introduction to working with gRPC. By walking through this example you'll learn how to: + +- Define a service in a .proto file. +- Generate server and client code using the protocol buffer compiler. +- Use the C# gRPC API to write a simple client and server for your service. + +It assumes that you have read the [Getting started](https://github.com/grpc/grpc/tree/master/examples) guide and are familiar with [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). Note that the example in this tutorial only uses the proto2 version of the protocol buffers language, as proto3 support for C# is not ready yet (see [protobuf C# README](https://github.com/google/protobuf/tree/master/csharp#proto2--proto3)). + +This isn't a comprehensive guide to using gRPC in C#: more reference documentation is coming soon. + +## Why use gRPC? + +Our example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients. + +With gRPC we can define our service once in a .proto file and implement clients and servers in any of gRPC's supported languages, which in turn can be run in environments ranging from servers inside Google to your own tablet - all the complexity of communication between different languages and environments is handled for you by gRPC. We also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating. + +## Example code and setup + +The example code for our tutorial is in [examples/csharp/route_guide](examples/csharp/route_guide). To download the example, clone this repository by running the following command: +```shell +$ git clone https://github.com/grpc/grpc.git +``` + +All the files for this tutorial are in the directory `examples/csharp/route_guide`. +Open the solution `examples/csharp/route_guide/RouteGuide.sln` from Visual Studio (or Monodevelop on Linux). + +On Windows, you should not need to do anything besides opening the solution. All the needed dependencies will be restored +for you automatically by the `Grpc` NuGet package upon building the solution. + +On Linux (or MacOS), you will first need to install protobuf and gRPC C Core using Linuxbrew (or Homebrew) tool in order to be +able to generate the server and client interface code and run the examples. Follow the instructions for [Linux](https://github.com/grpc/grpc/tree/master/src/csharp#usage-linux-mono) or [MacOS](https://github.com/grpc/grpc/tree/master/src/csharp#usage-macos-mono). + +## Defining the service + +Our first step (as you'll know from [Getting started](https://github.com/grpc/grpc/tree/master/examples)) is to define the gRPC *service* and the method *request* and *response* types using [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). You can see the complete .proto file in [`examples/csharp/route_guide/RouteGuide/protos/route_guide.proto`](examples/csharp/route_guide/RouteGuide/protos/route_guide.proto). + +To define a service, you specify a named `service` in your .proto file: + +```protobuf +service RouteGuide { + ... +} +``` + +Then you define `rpc` methods inside your service definition, specifying their request and response types. gRPC lets you define four kinds of service method, all of which are used in the `RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call. +```protobuf + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *server-side streaming RPC* where the client sends a request to the server and gets a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. As you can see in our example, you specify a server-side streaming method by placing the `stream` keyword before the *response* type. +```protobuf + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *client-side streaming RPC* where the client writes a sequence of messages and sends them to the server, again using a provided stream. Once the client has finished writing the messages, it waits for the server to read them all and return its response. You specify a server-side streaming method by placing the `stream` keyword before the *request* type. +```protobuf + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectional streaming RPC* where both sides send a sequence of messages using a read-write stream. The two streams operate independently, so clients and servers can read and write in whatever order they like: for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved. You specify this type of method by placing the `stream` keyword before both the request and the response. +```protobuf + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Our .proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods - for example, here's the `Point` message type: +```protobuf +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + + +## Generating client and server code + +Next we need to generate the gRPC client and server interfaces from our .proto service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC C# plugin. + +If you want to run this yourself, make sure you've installed protoc and gRPC C# plugin. The instructions vary based on your OS: +- For Windows, the `Grpc.Tools` NuGet package contains the binaries you will need to generate the code. +- For Linux, make sure you've [installed gRPC C Core using Linuxbrew](https://github.com/grpc/grpc/tree/master/src/csharp#usage-linux-mono) +- For MacOS, make sure you've [installed gRPC C Core using Homebrew](https://github.com/grpc/grpc/tree/master/src/csharp#usage-macos-mono) + +Once that's done, the following command can be used to generate the C# code. + +To generate the code on Windows, we use `protoc.exe` and `grpc_csharp_plugin.exe` binaries that are shipped with the `Grpc.Tools` NuGet package under the `tools` directory. +Normally you would need to add the `Grpc.Tools` package to the solution yourself, but in this tutorial it has been already done for you. Following command should be run from the `csharp/route_guide` directory: +``` +> packages\Grpc.Tools.0.5.1\tools\protoc -I RouteGuide/protos --csharp_out=RouteGuide --grpc_out=RouteGuide --plugin=protoc-gen-grpc=packages\Grpc.Tools.0.5.1\tools\grpc_csharp_plugin.exe RouteGuide/protos/route_guide.proto +``` + +On Linux/MacOS, we rely on `protoc` and `grpc_csharp_plugin` being installed by Linuxbrew/Homebrew. Run this command from the route_guide directory: +```shell +$ protoc -I RouteGuide/protos --csharp_out=RouteGuide --grpc_out=RouteGuide --plugin=protoc-gen-grpc=`which grpc_csharp_plugin` RouteGuide/protos/route_guide.proto +``` + +Running one of the previous commands regenerates the following files in the RouteGuide directory: +- `RouteGuide/RouteGuide.cs` defines a namespace `examples` + - This contains all the protocol buffer code to populate, serialize, and retrieve our request and response message types +- `RouteGuide/RouteGuideGrpc.cs`, provides stub and service classes + - an interface `RouteGuide.IRouteGuide` to inherit from when defining RouteGuide service implementations + - a class `RouteGuide.RouteGuideClient` that can be used to access remote RouteGuide instances + + + +## Creating the server + +First let's look at how we create a `RouteGuide` server. If you're only interested in creating gRPC clients, you can skip this section and go straight to [Creating the client](#client) (though you might find it interesting anyway!). + +There are two parts to making our `RouteGuide` service do its job: +- Implementing the service interface generated from our service definition: doing the actual "work" of our service. +- Running a gRPC server to listen for requests from clients and return the service responses. + +You can find our example `RouteGuide` server in [examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs](examples/csharp/route_guide/RouteGuideServer/RouteGuideServerImpl.cs). Let's take a closer look at how it works. + +### Implementing RouteGuide + +As you can see, our server has a `RouteGuideImpl` class that implements the generated `RouteGuide.IRouteGuide`: + +```csharp +// RouteGuideImpl provides an implementation of the RouteGuide service. +public class RouteGuideImpl : RouteGuide.IRouteGuide +``` + +#### Simple RPC + +`RouteGuideImpl` implements all our service methods. Let's look at the simplest type first, `GetFeature`, which just gets a `Point` from the client and returns the corresponding feature information from its database in a `Feature`. + +```csharp + public Task GetFeature(Grpc.Core.ServerCallContext context, Point request) + { + return Task.FromResult(CheckFeature(request)); + } +``` + +The method is passed a context for the RPC (which is empty in the alpha release), the client's `Point` protocol buffer request, and returns a `Feature` protocol buffer. In the method we create the `Feature` with the appropriate information, and then return it. To allow asynchronous +implementation, the method returns `Task` rather than just `Feature`. You are free to perform your computations synchronously and return +the result once you've finished, just as we do in the example. + +#### Server-side streaming RPC + +Now let's look at something a bit more complicated - a streaming RPC. `ListFeatures` is a server-side streaming RPC, so we need to send back multiple `Feature` protocol buffers to our client. + +```csharp + // in RouteGuideImpl + public async Task ListFeatures(Grpc.Core.ServerCallContext context, Rectangle request, + Grpc.Core.IServerStreamWriter responseStream) + { + int left = Math.Min(request.Lo.Longitude, request.Hi.Longitude); + int right = Math.Max(request.Lo.Longitude, request.Hi.Longitude); + int top = Math.Max(request.Lo.Latitude, request.Hi.Latitude); + int bottom = Math.Min(request.Lo.Latitude, request.Hi.Latitude); + + foreach (var feature in features) + { + if (!RouteGuideUtil.Exists(feature)) + { + continue; + } + + int lat = feature.Location.Latitude; + int lon = feature.Location.Longitude; + if (lon >= left && lon <= right && lat >= bottom && lat <= top) + { + await responseStream.WriteAsync(feature); + } + } + } +``` + +As you can see, here the request object is a `Rectangle` in which our client wants to find `Feature`s, but instead of returning a simple response we need to write responses to an asynchronous stream `IServerStreamWriter` using async method `WriteAsync`. + +#### Client-side streaming RPC + +Similarly, the client-side streaming method `RecordRoute` uses an [IAsyncEnumerator](https://github.com/Reactive-Extensions/Rx.NET/blob/master/Ix.NET/Source/System.Interactive.Async/IAsyncEnumerator.cs), to read the stream of requests using the async method `MoveNext` and the `Current` property. + +```csharp + public async Task RecordRoute(Grpc.Core.ServerCallContext context, + Grpc.Core.IAsyncStreamReader requestStream) + { + int pointCount = 0; + int featureCount = 0; + int distance = 0; + Point previous = null; + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + while (await requestStream.MoveNext()) + { + var point = requestStream.Current; + pointCount++; + if (RouteGuideUtil.Exists(CheckFeature(point))) + { + featureCount++; + } + if (previous != null) + { + distance += (int) CalcDistance(previous, point); + } + previous = point; + } + + stopwatch.Stop(); + return RouteSummary.CreateBuilder().SetPointCount(pointCount) + .SetFeatureCount(featureCount).SetDistance(distance) + .SetElapsedTime((int) (stopwatch.ElapsedMilliseconds / 1000)).Build(); + } +``` + +#### Bidirectional streaming RPC + +Finally, let's look at our bidirectional streaming RPC `RouteChat`. + +```csharp + public async Task RouteChat(Grpc.Core.ServerCallContext context, + Grpc.Core.IAsyncStreamReader requestStream, Grpc.Core.IServerStreamWriter responseStream) + { + while (await requestStream.MoveNext()) + { + var note = requestStream.Current; + List notes = GetOrCreateNotes(note.Location); + + List prevNotes; + lock (notes) + { + prevNotes = new List(notes); + } + + foreach (var prevNote in prevNotes) + { + await responseStream.WriteAsync(prevNote); + } + + lock (notes) + { + notes.Add(note); + } + } + } +``` + +Here the method receives both `requestStream` and `responseStream` arguments. Reading the requests is done the same way as in the client-side streaming method `RecordRoute`. Writing the responses is done the same way as in the server-side streaming method `ListFeatures`. + +### Starting the server + +Once we've implemented all our methods, we also need to start up a gRPC server so that clients can actually use our service. The following snippet shows how we do this for our `RouteGuide` service: + +```csharp +var features = RouteGuideUtil.ParseFeatures(RouteGuideUtil.DefaultFeaturesFile); +GrpcEnvironment.Initialize(); + +Server server = new Server(); +server.AddServiceDefinition(RouteGuide.BindService(new RouteGuideImpl(features))); +int port = server.AddListeningPort("localhost", 50052); +server.Start(); + +Console.WriteLine("RouteGuide server listening on port " + port); +Console.WriteLine("Press any key to stop the server..."); +Console.ReadKey(); + +server.ShutdownAsync().Wait(); +GrpcEnvironment.Shutdown(); +``` +As you can see, we build and start our server using `Grpc.Core.Server` class. To do this, we: + +1. Create an instance of `Grpc.Core.Server`. +1. Create an instance of our service implementation class `RouteGuideImpl`. +3. Register our service implementation with the server using the `AddServiceDefinition` method and the generated method `RouteGuide.BindService`. +2. Specify the address and port we want to use to listen for client requests using the `AddListeningPort` method. +4. Call `Start` on the server instance to start an RPC server for our service. + + +## Creating the client + +In this section, we'll look at creating a C# client for our `RouteGuide` service. You can see our complete example client code in [examples/csharp/route_guide/RouteGuideClient/Program.cs](examples/csharp/route_guide/RouteGuideClient/Program.cs). + +### Creating a stub + +To call service methods, we first need to create a *stub*. + +First, we need to create a gRPC client channel that will connect to gRPC server. Then, we use the `RouteGuide.NewStub` method of the `RouteGuide` class generated from our .proto. + +```csharp +GrpcEnvironment.Initialize(); + +using (Channel channel = new Channel("127.0.0.1:50052")) +{ + var client = RouteGuide.NewStub(channel); + + // YOUR CODE GOES HERE +} + +GrpcEnvironment.Shutdown(); +``` + +### Calling service methods + +Now let's look at how we call our service methods. gRPC C# provides asynchronous versions of each of the supported method types. For convenience, +gRPC C# also provides a synchronous method stub, but only for simple (single request/single response) RPCs. + +#### Simple RPC + +Calling the simple RPC `GetFeature` in a synchronous way is nearly as straightforward as calling a local method. + +```csharp +Point request = Point.CreateBuilder().SetLatitude(409146138).SetLongitude(-746188906).Build(); +Feature feature = client.GetFeature(request); +``` + +As you can see, we create and populate a request protocol buffer object (in our case `Point`), and call the desired method on the client object, passing it the request. If the RPC finishes with success, the response protocol buffer (in our case `Feature`) will be returned. Otherwise, an exception of type `RpcException` will be thrown, indicating the status code of the problem. + +Alternatively, if you are in async context, you can call an asynchronous version of the method (and use `await` keyword to await the result): +```csharp +Point request = Point.CreateBuilder().SetLatitude(409146138).SetLongitude(-746188906).Build(); +Feature feature = await client.GetFeatureAsync(request); +``` + +#### Streaming RPCs + +Now let's look at our streaming methods. If you've already read [Creating the server](#server) some of this may look very familiar - streaming RPCs are implemented in a similar way on both sides. The difference with respect to simple call is that the client methods return an instance of a call object, that provides access to request/response streams and/or asynchronous result (depending on the streaming type you are using). + +Here's where we call the server-side streaming method `ListFeatures`, which has property `ReponseStream` of type `IAsyncEnumerator` + +```csharp +using (var call = client.ListFeatures(request)) +{ + while (await call.ResponseStream.MoveNext()) + { + Feature feature = call.ResponseStream.Current; + Console.WriteLine("Received " + feature.ToString()); + } +} +``` + +The client-side streaming method `RecordRoute` is similar, except we use the property `RequestStream` to write the requests one by one using `WriteAsync` and eventually signal that no more request will be send using `CompleteAsync`. The method result can be obtained through the property +`Result`. +```csharp +using (var call = client.RecordRoute()) +{ + foreach (var point in points) + { + await call.RequestStream.WriteAsync(point); + } + await call.RequestStream.CompleteAsync(); + + RouteSummary summary = await call.Result; +} +``` + +Finally, let's look at our bidirectional streaming RPC `RouteChat`. In this case, we write the request to `RequestStream` and receive the responses from `ResponseStream`. As you can see from the example, the streams are independent of each other. + +```csharp + using (var call = client.RouteChat()) + { + var responseReaderTask = Task.Run(async () => + { + while (await call.ResponseStream.MoveNext()) + { + var note = call.ResponseStream.Current; + Console.WriteLine("Received " + note); + } + }); + + foreach (RouteNote request in requests) + { + await call.RequestStream.WriteAsync(request); + } + await call.RequestStream.CompleteAsync(); + await responseReaderTask; +} +``` + +## Try it out! + +Build client and server: + +Open the solution `examples/csharp/route_guide/RouteGuide.sln` from Visual Studio (or Monodevelop on Linux) and hit "Build". + +Run the server, which will listen on port 50052: +``` +> cd RouteGuideServer/bin/Debug +> RouteGuideServer.exe +``` + +Run the client (in a different terminal): +``` +> cd RouteGuideClient/bin/Debug +> RouteGuideClient.exe +``` + +You can also run the server and client directly from Visual Studio. + +On Linux or Mac, use `mono RouteGuideServer.exe` and `mono RouteGuideClient.exe` to run the server and client. diff --git a/examples/csharp/route_guide/RouteGuide.sln b/examples/csharp/route_guide/RouteGuide.sln new file mode 100644 index 00000000000..0b79fdc5ca7 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.31101.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RouteGuide", "RouteGuide\RouteGuide.csproj", "{49954D9C-5F17-4662-96B2-73BE833DD81A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RouteGuideClient", "RouteGuideClient\RouteGuideClient.csproj", "{D47BE663-4DE3-4206-B7A8-EA3FA066DADC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RouteGuideServer", "RouteGuideServer\RouteGuideServer.csproj", "{4B7C7794-BE24-4477-ACE7-18259EB73D27}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{2F6B184B-A576-4F21-AF2E-27E73D1FC96E}" + ProjectSection(SolutionItems) = preProject + .nuget\packages.config = .nuget\packages.config + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {49954D9C-5F17-4662-96B2-73BE833DD81A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {49954D9C-5F17-4662-96B2-73BE833DD81A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {49954D9C-5F17-4662-96B2-73BE833DD81A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {49954D9C-5F17-4662-96B2-73BE833DD81A}.Release|Any CPU.Build.0 = Release|Any CPU + {D47BE663-4DE3-4206-B7A8-EA3FA066DADC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D47BE663-4DE3-4206-B7A8-EA3FA066DADC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D47BE663-4DE3-4206-B7A8-EA3FA066DADC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D47BE663-4DE3-4206-B7A8-EA3FA066DADC}.Release|Any CPU.Build.0 = Release|Any CPU + {4B7C7794-BE24-4477-ACE7-18259EB73D27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4B7C7794-BE24-4477-ACE7-18259EB73D27}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4B7C7794-BE24-4477-ACE7-18259EB73D27}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4B7C7794-BE24-4477-ACE7-18259EB73D27}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/csharp/route_guide/RouteGuide/Properties/AssemblyInfo.cs b/examples/csharp/route_guide/RouteGuide/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..9c3441e42f4 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RouteGuide")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RouteGuide")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ef6b85bc-ac27-46de-8714-a658236cc6fb")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/examples/csharp/route_guide/RouteGuide/RouteGuide.cs b/examples/csharp/route_guide/RouteGuide/RouteGuide.cs new file mode 100644 index 00000000000..80508bcd3fd --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide/RouteGuide.cs @@ -0,0 +1,1873 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: route_guide.proto +#pragma warning disable 1591, 0612, 3021 +#region Designer generated code + +using pb = global::Google.ProtocolBuffers; +using pbc = global::Google.ProtocolBuffers.Collections; +using pbd = global::Google.ProtocolBuffers.Descriptors; +using scg = global::System.Collections.Generic; +namespace examples { + + namespace Proto { + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class RouteGuide { + + #region Extension registration + public static void RegisterAllExtensions(pb::ExtensionRegistry registry) { + } + #endregion + #region Static variables + internal static pbd::MessageDescriptor internal__static_examples_Point__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable internal__static_examples_Point__FieldAccessorTable; + internal static pbd::MessageDescriptor internal__static_examples_Rectangle__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable internal__static_examples_Rectangle__FieldAccessorTable; + internal static pbd::MessageDescriptor internal__static_examples_Feature__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable internal__static_examples_Feature__FieldAccessorTable; + internal static pbd::MessageDescriptor internal__static_examples_RouteNote__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable internal__static_examples_RouteNote__FieldAccessorTable; + internal static pbd::MessageDescriptor internal__static_examples_RouteSummary__Descriptor; + internal static pb::FieldAccess.FieldAccessorTable internal__static_examples_RouteSummary__FieldAccessorTable; + #endregion + #region Descriptor + public static pbd::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbd::FileDescriptor descriptor; + + static RouteGuide() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChFyb3V0ZV9ndWlkZS5wcm90bxIIZXhhbXBsZXMiLAoFUG9pbnQSEAoIbGF0", + "aXR1ZGUYASABKAUSEQoJbG9uZ2l0dWRlGAIgASgFIkUKCVJlY3RhbmdsZRIb", + "CgJsbxgBIAEoCzIPLmV4YW1wbGVzLlBvaW50EhsKAmhpGAIgASgLMg8uZXhh", + "bXBsZXMuUG9pbnQiOgoHRmVhdHVyZRIMCgRuYW1lGAEgASgJEiEKCGxvY2F0", + "aW9uGAIgASgLMg8uZXhhbXBsZXMuUG9pbnQiPwoJUm91dGVOb3RlEiEKCGxv", + "Y2F0aW9uGAEgASgLMg8uZXhhbXBsZXMuUG9pbnQSDwoHbWVzc2FnZRgCIAEo", + "CSJiCgxSb3V0ZVN1bW1hcnkSEwoLcG9pbnRfY291bnQYASABKAUSFQoNZmVh", + "dHVyZV9jb3VudBgCIAEoBRIQCghkaXN0YW5jZRgDIAEoBRIUCgxlbGFwc2Vk", + "X3RpbWUYBCABKAUy9QEKClJvdXRlR3VpZGUSMgoKR2V0RmVhdHVyZRIPLmV4", + "YW1wbGVzLlBvaW50GhEuZXhhbXBsZXMuRmVhdHVyZSIAEjoKDExpc3RGZWF0", + "dXJlcxITLmV4YW1wbGVzLlJlY3RhbmdsZRoRLmV4YW1wbGVzLkZlYXR1cmUi", + "ADABEjoKC1JlY29yZFJvdXRlEg8uZXhhbXBsZXMuUG9pbnQaFi5leGFtcGxl", + "cy5Sb3V0ZVN1bW1hcnkiACgBEjsKCVJvdXRlQ2hhdBITLmV4YW1wbGVzLlJv", + "dXRlTm90ZRoTLmV4YW1wbGVzLlJvdXRlTm90ZSIAKAEwAQ==")); + pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) { + descriptor = root; + internal__static_examples_Point__Descriptor = Descriptor.MessageTypes[0]; + internal__static_examples_Point__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable(internal__static_examples_Point__Descriptor, + new string[] { "Latitude", "Longitude", }); + internal__static_examples_Rectangle__Descriptor = Descriptor.MessageTypes[1]; + internal__static_examples_Rectangle__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable(internal__static_examples_Rectangle__Descriptor, + new string[] { "Lo", "Hi", }); + internal__static_examples_Feature__Descriptor = Descriptor.MessageTypes[2]; + internal__static_examples_Feature__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable(internal__static_examples_Feature__Descriptor, + new string[] { "Name", "Location", }); + internal__static_examples_RouteNote__Descriptor = Descriptor.MessageTypes[3]; + internal__static_examples_RouteNote__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable(internal__static_examples_RouteNote__Descriptor, + new string[] { "Location", "Message", }); + internal__static_examples_RouteSummary__Descriptor = Descriptor.MessageTypes[4]; + internal__static_examples_RouteSummary__FieldAccessorTable = + new pb::FieldAccess.FieldAccessorTable(internal__static_examples_RouteSummary__Descriptor, + new string[] { "PointCount", "FeatureCount", "Distance", "ElapsedTime", }); + pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance(); + RegisterAllExtensions(registry); + return registry; + }; + pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbd::FileDescriptor[] { + }, assigner); + } + #endregion + + } + } + #region Messages + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Point : pb::GeneratedMessage { + private Point() { } + private static readonly Point defaultInstance = new Point().MakeReadOnly(); + private static readonly string[] _pointFieldNames = new string[] { "latitude", "longitude" }; + private static readonly uint[] _pointFieldTags = new uint[] { 8, 16 }; + public static Point DefaultInstance { + get { return defaultInstance; } + } + + public override Point DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override Point ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::examples.Proto.RouteGuide.internal__static_examples_Point__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::examples.Proto.RouteGuide.internal__static_examples_Point__FieldAccessorTable; } + } + + public const int LatitudeFieldNumber = 1; + private bool hasLatitude; + private int latitude_; + public bool HasLatitude { + get { return hasLatitude; } + } + public int Latitude { + get { return latitude_; } + } + + public const int LongitudeFieldNumber = 2; + private bool hasLongitude; + private int longitude_; + public bool HasLongitude { + get { return hasLongitude; } + } + public int Longitude { + get { return longitude_; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _pointFieldNames; + if (hasLatitude) { + output.WriteInt32(1, field_names[0], Latitude); + } + if (hasLongitude) { + output.WriteInt32(2, field_names[1], Longitude); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasLatitude) { + size += pb::CodedOutputStream.ComputeInt32Size(1, Latitude); + } + if (hasLongitude) { + size += pb::CodedOutputStream.ComputeInt32Size(2, Longitude); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static Point ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static Point ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static Point ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static Point ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static Point ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static Point ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static Point ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static Point ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static Point ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static Point ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private Point MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(Point prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(Point cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private Point result; + + private Point PrepareBuilder() { + if (resultIsReadOnly) { + Point original = result; + result = new Point(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override Point MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::examples.Point.Descriptor; } + } + + public override Point DefaultInstanceForType { + get { return global::examples.Point.DefaultInstance; } + } + + public override Point BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is Point) { + return MergeFrom((Point) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(Point other) { + if (other == global::examples.Point.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasLatitude) { + Latitude = other.Latitude; + } + if (other.HasLongitude) { + Longitude = other.Longitude; + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_pointFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _pointFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 8: { + result.hasLatitude = input.ReadInt32(ref result.latitude_); + break; + } + case 16: { + result.hasLongitude = input.ReadInt32(ref result.longitude_); + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasLatitude { + get { return result.hasLatitude; } + } + public int Latitude { + get { return result.Latitude; } + set { SetLatitude(value); } + } + public Builder SetLatitude(int value) { + PrepareBuilder(); + result.hasLatitude = true; + result.latitude_ = value; + return this; + } + public Builder ClearLatitude() { + PrepareBuilder(); + result.hasLatitude = false; + result.latitude_ = 0; + return this; + } + + public bool HasLongitude { + get { return result.hasLongitude; } + } + public int Longitude { + get { return result.Longitude; } + set { SetLongitude(value); } + } + public Builder SetLongitude(int value) { + PrepareBuilder(); + result.hasLongitude = true; + result.longitude_ = value; + return this; + } + public Builder ClearLongitude() { + PrepareBuilder(); + result.hasLongitude = false; + result.longitude_ = 0; + return this; + } + } + static Point() { + object.ReferenceEquals(global::examples.Proto.RouteGuide.Descriptor, null); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Rectangle : pb::GeneratedMessage { + private Rectangle() { } + private static readonly Rectangle defaultInstance = new Rectangle().MakeReadOnly(); + private static readonly string[] _rectangleFieldNames = new string[] { "hi", "lo" }; + private static readonly uint[] _rectangleFieldTags = new uint[] { 18, 10 }; + public static Rectangle DefaultInstance { + get { return defaultInstance; } + } + + public override Rectangle DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override Rectangle ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::examples.Proto.RouteGuide.internal__static_examples_Rectangle__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::examples.Proto.RouteGuide.internal__static_examples_Rectangle__FieldAccessorTable; } + } + + public const int LoFieldNumber = 1; + private bool hasLo; + private global::examples.Point lo_; + public bool HasLo { + get { return hasLo; } + } + public global::examples.Point Lo { + get { return lo_ ?? global::examples.Point.DefaultInstance; } + } + + public const int HiFieldNumber = 2; + private bool hasHi; + private global::examples.Point hi_; + public bool HasHi { + get { return hasHi; } + } + public global::examples.Point Hi { + get { return hi_ ?? global::examples.Point.DefaultInstance; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _rectangleFieldNames; + if (hasLo) { + output.WriteMessage(1, field_names[1], Lo); + } + if (hasHi) { + output.WriteMessage(2, field_names[0], Hi); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasLo) { + size += pb::CodedOutputStream.ComputeMessageSize(1, Lo); + } + if (hasHi) { + size += pb::CodedOutputStream.ComputeMessageSize(2, Hi); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static Rectangle ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static Rectangle ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static Rectangle ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static Rectangle ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static Rectangle ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static Rectangle ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static Rectangle ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static Rectangle ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static Rectangle ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static Rectangle ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private Rectangle MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(Rectangle prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(Rectangle cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private Rectangle result; + + private Rectangle PrepareBuilder() { + if (resultIsReadOnly) { + Rectangle original = result; + result = new Rectangle(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override Rectangle MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::examples.Rectangle.Descriptor; } + } + + public override Rectangle DefaultInstanceForType { + get { return global::examples.Rectangle.DefaultInstance; } + } + + public override Rectangle BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is Rectangle) { + return MergeFrom((Rectangle) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(Rectangle other) { + if (other == global::examples.Rectangle.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasLo) { + MergeLo(other.Lo); + } + if (other.HasHi) { + MergeHi(other.Hi); + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_rectangleFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _rectangleFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 10: { + global::examples.Point.Builder subBuilder = global::examples.Point.CreateBuilder(); + if (result.hasLo) { + subBuilder.MergeFrom(Lo); + } + input.ReadMessage(subBuilder, extensionRegistry); + Lo = subBuilder.BuildPartial(); + break; + } + case 18: { + global::examples.Point.Builder subBuilder = global::examples.Point.CreateBuilder(); + if (result.hasHi) { + subBuilder.MergeFrom(Hi); + } + input.ReadMessage(subBuilder, extensionRegistry); + Hi = subBuilder.BuildPartial(); + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasLo { + get { return result.hasLo; } + } + public global::examples.Point Lo { + get { return result.Lo; } + set { SetLo(value); } + } + public Builder SetLo(global::examples.Point value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasLo = true; + result.lo_ = value; + return this; + } + public Builder SetLo(global::examples.Point.Builder builderForValue) { + pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); + PrepareBuilder(); + result.hasLo = true; + result.lo_ = builderForValue.Build(); + return this; + } + public Builder MergeLo(global::examples.Point value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + if (result.hasLo && + result.lo_ != global::examples.Point.DefaultInstance) { + result.lo_ = global::examples.Point.CreateBuilder(result.lo_).MergeFrom(value).BuildPartial(); + } else { + result.lo_ = value; + } + result.hasLo = true; + return this; + } + public Builder ClearLo() { + PrepareBuilder(); + result.hasLo = false; + result.lo_ = null; + return this; + } + + public bool HasHi { + get { return result.hasHi; } + } + public global::examples.Point Hi { + get { return result.Hi; } + set { SetHi(value); } + } + public Builder SetHi(global::examples.Point value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasHi = true; + result.hi_ = value; + return this; + } + public Builder SetHi(global::examples.Point.Builder builderForValue) { + pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); + PrepareBuilder(); + result.hasHi = true; + result.hi_ = builderForValue.Build(); + return this; + } + public Builder MergeHi(global::examples.Point value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + if (result.hasHi && + result.hi_ != global::examples.Point.DefaultInstance) { + result.hi_ = global::examples.Point.CreateBuilder(result.hi_).MergeFrom(value).BuildPartial(); + } else { + result.hi_ = value; + } + result.hasHi = true; + return this; + } + public Builder ClearHi() { + PrepareBuilder(); + result.hasHi = false; + result.hi_ = null; + return this; + } + } + static Rectangle() { + object.ReferenceEquals(global::examples.Proto.RouteGuide.Descriptor, null); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Feature : pb::GeneratedMessage { + private Feature() { } + private static readonly Feature defaultInstance = new Feature().MakeReadOnly(); + private static readonly string[] _featureFieldNames = new string[] { "location", "name" }; + private static readonly uint[] _featureFieldTags = new uint[] { 18, 10 }; + public static Feature DefaultInstance { + get { return defaultInstance; } + } + + public override Feature DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override Feature ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::examples.Proto.RouteGuide.internal__static_examples_Feature__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::examples.Proto.RouteGuide.internal__static_examples_Feature__FieldAccessorTable; } + } + + public const int NameFieldNumber = 1; + private bool hasName; + private string name_ = ""; + public bool HasName { + get { return hasName; } + } + public string Name { + get { return name_; } + } + + public const int LocationFieldNumber = 2; + private bool hasLocation; + private global::examples.Point location_; + public bool HasLocation { + get { return hasLocation; } + } + public global::examples.Point Location { + get { return location_ ?? global::examples.Point.DefaultInstance; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _featureFieldNames; + if (hasName) { + output.WriteString(1, field_names[1], Name); + } + if (hasLocation) { + output.WriteMessage(2, field_names[0], Location); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasName) { + size += pb::CodedOutputStream.ComputeStringSize(1, Name); + } + if (hasLocation) { + size += pb::CodedOutputStream.ComputeMessageSize(2, Location); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static Feature ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static Feature ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static Feature ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static Feature ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static Feature ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static Feature ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static Feature ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static Feature ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static Feature ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static Feature ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private Feature MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(Feature prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(Feature cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private Feature result; + + private Feature PrepareBuilder() { + if (resultIsReadOnly) { + Feature original = result; + result = new Feature(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override Feature MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::examples.Feature.Descriptor; } + } + + public override Feature DefaultInstanceForType { + get { return global::examples.Feature.DefaultInstance; } + } + + public override Feature BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is Feature) { + return MergeFrom((Feature) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(Feature other) { + if (other == global::examples.Feature.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasName) { + Name = other.Name; + } + if (other.HasLocation) { + MergeLocation(other.Location); + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_featureFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _featureFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 10: { + result.hasName = input.ReadString(ref result.name_); + break; + } + case 18: { + global::examples.Point.Builder subBuilder = global::examples.Point.CreateBuilder(); + if (result.hasLocation) { + subBuilder.MergeFrom(Location); + } + input.ReadMessage(subBuilder, extensionRegistry); + Location = subBuilder.BuildPartial(); + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasName { + get { return result.hasName; } + } + public string Name { + get { return result.Name; } + set { SetName(value); } + } + public Builder SetName(string value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasName = true; + result.name_ = value; + return this; + } + public Builder ClearName() { + PrepareBuilder(); + result.hasName = false; + result.name_ = ""; + return this; + } + + public bool HasLocation { + get { return result.hasLocation; } + } + public global::examples.Point Location { + get { return result.Location; } + set { SetLocation(value); } + } + public Builder SetLocation(global::examples.Point value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasLocation = true; + result.location_ = value; + return this; + } + public Builder SetLocation(global::examples.Point.Builder builderForValue) { + pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); + PrepareBuilder(); + result.hasLocation = true; + result.location_ = builderForValue.Build(); + return this; + } + public Builder MergeLocation(global::examples.Point value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + if (result.hasLocation && + result.location_ != global::examples.Point.DefaultInstance) { + result.location_ = global::examples.Point.CreateBuilder(result.location_).MergeFrom(value).BuildPartial(); + } else { + result.location_ = value; + } + result.hasLocation = true; + return this; + } + public Builder ClearLocation() { + PrepareBuilder(); + result.hasLocation = false; + result.location_ = null; + return this; + } + } + static Feature() { + object.ReferenceEquals(global::examples.Proto.RouteGuide.Descriptor, null); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class RouteNote : pb::GeneratedMessage { + private RouteNote() { } + private static readonly RouteNote defaultInstance = new RouteNote().MakeReadOnly(); + private static readonly string[] _routeNoteFieldNames = new string[] { "location", "message" }; + private static readonly uint[] _routeNoteFieldTags = new uint[] { 10, 18 }; + public static RouteNote DefaultInstance { + get { return defaultInstance; } + } + + public override RouteNote DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override RouteNote ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::examples.Proto.RouteGuide.internal__static_examples_RouteNote__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::examples.Proto.RouteGuide.internal__static_examples_RouteNote__FieldAccessorTable; } + } + + public const int LocationFieldNumber = 1; + private bool hasLocation; + private global::examples.Point location_; + public bool HasLocation { + get { return hasLocation; } + } + public global::examples.Point Location { + get { return location_ ?? global::examples.Point.DefaultInstance; } + } + + public const int MessageFieldNumber = 2; + private bool hasMessage; + private string message_ = ""; + public bool HasMessage { + get { return hasMessage; } + } + public string Message { + get { return message_; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _routeNoteFieldNames; + if (hasLocation) { + output.WriteMessage(1, field_names[0], Location); + } + if (hasMessage) { + output.WriteString(2, field_names[1], Message); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasLocation) { + size += pb::CodedOutputStream.ComputeMessageSize(1, Location); + } + if (hasMessage) { + size += pb::CodedOutputStream.ComputeStringSize(2, Message); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static RouteNote ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static RouteNote ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static RouteNote ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static RouteNote ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static RouteNote ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static RouteNote ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static RouteNote ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static RouteNote ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static RouteNote ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static RouteNote ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private RouteNote MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(RouteNote prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(RouteNote cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private RouteNote result; + + private RouteNote PrepareBuilder() { + if (resultIsReadOnly) { + RouteNote original = result; + result = new RouteNote(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override RouteNote MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::examples.RouteNote.Descriptor; } + } + + public override RouteNote DefaultInstanceForType { + get { return global::examples.RouteNote.DefaultInstance; } + } + + public override RouteNote BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is RouteNote) { + return MergeFrom((RouteNote) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(RouteNote other) { + if (other == global::examples.RouteNote.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasLocation) { + MergeLocation(other.Location); + } + if (other.HasMessage) { + Message = other.Message; + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_routeNoteFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _routeNoteFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 10: { + global::examples.Point.Builder subBuilder = global::examples.Point.CreateBuilder(); + if (result.hasLocation) { + subBuilder.MergeFrom(Location); + } + input.ReadMessage(subBuilder, extensionRegistry); + Location = subBuilder.BuildPartial(); + break; + } + case 18: { + result.hasMessage = input.ReadString(ref result.message_); + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasLocation { + get { return result.hasLocation; } + } + public global::examples.Point Location { + get { return result.Location; } + set { SetLocation(value); } + } + public Builder SetLocation(global::examples.Point value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasLocation = true; + result.location_ = value; + return this; + } + public Builder SetLocation(global::examples.Point.Builder builderForValue) { + pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); + PrepareBuilder(); + result.hasLocation = true; + result.location_ = builderForValue.Build(); + return this; + } + public Builder MergeLocation(global::examples.Point value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + if (result.hasLocation && + result.location_ != global::examples.Point.DefaultInstance) { + result.location_ = global::examples.Point.CreateBuilder(result.location_).MergeFrom(value).BuildPartial(); + } else { + result.location_ = value; + } + result.hasLocation = true; + return this; + } + public Builder ClearLocation() { + PrepareBuilder(); + result.hasLocation = false; + result.location_ = null; + return this; + } + + public bool HasMessage { + get { return result.hasMessage; } + } + public string Message { + get { return result.Message; } + set { SetMessage(value); } + } + public Builder SetMessage(string value) { + pb::ThrowHelper.ThrowIfNull(value, "value"); + PrepareBuilder(); + result.hasMessage = true; + result.message_ = value; + return this; + } + public Builder ClearMessage() { + PrepareBuilder(); + result.hasMessage = false; + result.message_ = ""; + return this; + } + } + static RouteNote() { + object.ReferenceEquals(global::examples.Proto.RouteGuide.Descriptor, null); + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class RouteSummary : pb::GeneratedMessage { + private RouteSummary() { } + private static readonly RouteSummary defaultInstance = new RouteSummary().MakeReadOnly(); + private static readonly string[] _routeSummaryFieldNames = new string[] { "distance", "elapsed_time", "feature_count", "point_count" }; + private static readonly uint[] _routeSummaryFieldTags = new uint[] { 24, 32, 16, 8 }; + public static RouteSummary DefaultInstance { + get { return defaultInstance; } + } + + public override RouteSummary DefaultInstanceForType { + get { return DefaultInstance; } + } + + protected override RouteSummary ThisMessage { + get { return this; } + } + + public static pbd::MessageDescriptor Descriptor { + get { return global::examples.Proto.RouteGuide.internal__static_examples_RouteSummary__Descriptor; } + } + + protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { + get { return global::examples.Proto.RouteGuide.internal__static_examples_RouteSummary__FieldAccessorTable; } + } + + public const int PointCountFieldNumber = 1; + private bool hasPointCount; + private int pointCount_; + public bool HasPointCount { + get { return hasPointCount; } + } + public int PointCount { + get { return pointCount_; } + } + + public const int FeatureCountFieldNumber = 2; + private bool hasFeatureCount; + private int featureCount_; + public bool HasFeatureCount { + get { return hasFeatureCount; } + } + public int FeatureCount { + get { return featureCount_; } + } + + public const int DistanceFieldNumber = 3; + private bool hasDistance; + private int distance_; + public bool HasDistance { + get { return hasDistance; } + } + public int Distance { + get { return distance_; } + } + + public const int ElapsedTimeFieldNumber = 4; + private bool hasElapsedTime; + private int elapsedTime_; + public bool HasElapsedTime { + get { return hasElapsedTime; } + } + public int ElapsedTime { + get { return elapsedTime_; } + } + + public override bool IsInitialized { + get { + return true; + } + } + + public override void WriteTo(pb::ICodedOutputStream output) { + CalcSerializedSize(); + string[] field_names = _routeSummaryFieldNames; + if (hasPointCount) { + output.WriteInt32(1, field_names[3], PointCount); + } + if (hasFeatureCount) { + output.WriteInt32(2, field_names[2], FeatureCount); + } + if (hasDistance) { + output.WriteInt32(3, field_names[0], Distance); + } + if (hasElapsedTime) { + output.WriteInt32(4, field_names[1], ElapsedTime); + } + UnknownFields.WriteTo(output); + } + + private int memoizedSerializedSize = -1; + public override int SerializedSize { + get { + int size = memoizedSerializedSize; + if (size != -1) return size; + return CalcSerializedSize(); + } + } + + private int CalcSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasPointCount) { + size += pb::CodedOutputStream.ComputeInt32Size(1, PointCount); + } + if (hasFeatureCount) { + size += pb::CodedOutputStream.ComputeInt32Size(2, FeatureCount); + } + if (hasDistance) { + size += pb::CodedOutputStream.ComputeInt32Size(3, Distance); + } + if (hasElapsedTime) { + size += pb::CodedOutputStream.ComputeInt32Size(4, ElapsedTime); + } + size += UnknownFields.SerializedSize; + memoizedSerializedSize = size; + return size; + } + public static RouteSummary ParseFrom(pb::ByteString data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static RouteSummary ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static RouteSummary ParseFrom(byte[] data) { + return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); + } + public static RouteSummary ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); + } + public static RouteSummary ParseFrom(global::System.IO.Stream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static RouteSummary ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + public static RouteSummary ParseDelimitedFrom(global::System.IO.Stream input) { + return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); + } + public static RouteSummary ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { + return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); + } + public static RouteSummary ParseFrom(pb::ICodedInputStream input) { + return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); + } + public static RouteSummary ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + } + private RouteSummary MakeReadOnly() { + return this; + } + + public static Builder CreateBuilder() { return new Builder(); } + public override Builder ToBuilder() { return CreateBuilder(this); } + public override Builder CreateBuilderForType() { return new Builder(); } + public static Builder CreateBuilder(RouteSummary prototype) { + return new Builder(prototype); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class Builder : pb::GeneratedBuilder { + protected override Builder ThisBuilder { + get { return this; } + } + public Builder() { + result = DefaultInstance; + resultIsReadOnly = true; + } + internal Builder(RouteSummary cloneFrom) { + result = cloneFrom; + resultIsReadOnly = true; + } + + private bool resultIsReadOnly; + private RouteSummary result; + + private RouteSummary PrepareBuilder() { + if (resultIsReadOnly) { + RouteSummary original = result; + result = new RouteSummary(); + resultIsReadOnly = false; + MergeFrom(original); + } + return result; + } + + public override bool IsInitialized { + get { return result.IsInitialized; } + } + + protected override RouteSummary MessageBeingBuilt { + get { return PrepareBuilder(); } + } + + public override Builder Clear() { + result = DefaultInstance; + resultIsReadOnly = true; + return this; + } + + public override Builder Clone() { + if (resultIsReadOnly) { + return new Builder(result); + } else { + return new Builder().MergeFrom(result); + } + } + + public override pbd::MessageDescriptor DescriptorForType { + get { return global::examples.RouteSummary.Descriptor; } + } + + public override RouteSummary DefaultInstanceForType { + get { return global::examples.RouteSummary.DefaultInstance; } + } + + public override RouteSummary BuildPartial() { + if (resultIsReadOnly) { + return result; + } + resultIsReadOnly = true; + return result.MakeReadOnly(); + } + + public override Builder MergeFrom(pb::IMessage other) { + if (other is RouteSummary) { + return MergeFrom((RouteSummary) other); + } else { + base.MergeFrom(other); + return this; + } + } + + public override Builder MergeFrom(RouteSummary other) { + if (other == global::examples.RouteSummary.DefaultInstance) return this; + PrepareBuilder(); + if (other.HasPointCount) { + PointCount = other.PointCount; + } + if (other.HasFeatureCount) { + FeatureCount = other.FeatureCount; + } + if (other.HasDistance) { + Distance = other.Distance; + } + if (other.HasElapsedTime) { + ElapsedTime = other.ElapsedTime; + } + this.MergeUnknownFields(other.UnknownFields); + return this; + } + + public override Builder MergeFrom(pb::ICodedInputStream input) { + return MergeFrom(input, pb::ExtensionRegistry.Empty); + } + + public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { + PrepareBuilder(); + pb::UnknownFieldSet.Builder unknownFields = null; + uint tag; + string field_name; + while (input.ReadTag(out tag, out field_name)) { + if(tag == 0 && field_name != null) { + int field_ordinal = global::System.Array.BinarySearch(_routeSummaryFieldNames, field_name, global::System.StringComparer.Ordinal); + if(field_ordinal >= 0) + tag = _routeSummaryFieldTags[field_ordinal]; + else { + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + continue; + } + } + switch (tag) { + case 0: { + throw pb::InvalidProtocolBufferException.InvalidTag(); + } + default: { + if (pb::WireFormat.IsEndGroupTag(tag)) { + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + if (unknownFields == null) { + unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); + } + ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); + break; + } + case 8: { + result.hasPointCount = input.ReadInt32(ref result.pointCount_); + break; + } + case 16: { + result.hasFeatureCount = input.ReadInt32(ref result.featureCount_); + break; + } + case 24: { + result.hasDistance = input.ReadInt32(ref result.distance_); + break; + } + case 32: { + result.hasElapsedTime = input.ReadInt32(ref result.elapsedTime_); + break; + } + } + } + + if (unknownFields != null) { + this.UnknownFields = unknownFields.Build(); + } + return this; + } + + + public bool HasPointCount { + get { return result.hasPointCount; } + } + public int PointCount { + get { return result.PointCount; } + set { SetPointCount(value); } + } + public Builder SetPointCount(int value) { + PrepareBuilder(); + result.hasPointCount = true; + result.pointCount_ = value; + return this; + } + public Builder ClearPointCount() { + PrepareBuilder(); + result.hasPointCount = false; + result.pointCount_ = 0; + return this; + } + + public bool HasFeatureCount { + get { return result.hasFeatureCount; } + } + public int FeatureCount { + get { return result.FeatureCount; } + set { SetFeatureCount(value); } + } + public Builder SetFeatureCount(int value) { + PrepareBuilder(); + result.hasFeatureCount = true; + result.featureCount_ = value; + return this; + } + public Builder ClearFeatureCount() { + PrepareBuilder(); + result.hasFeatureCount = false; + result.featureCount_ = 0; + return this; + } + + public bool HasDistance { + get { return result.hasDistance; } + } + public int Distance { + get { return result.Distance; } + set { SetDistance(value); } + } + public Builder SetDistance(int value) { + PrepareBuilder(); + result.hasDistance = true; + result.distance_ = value; + return this; + } + public Builder ClearDistance() { + PrepareBuilder(); + result.hasDistance = false; + result.distance_ = 0; + return this; + } + + public bool HasElapsedTime { + get { return result.hasElapsedTime; } + } + public int ElapsedTime { + get { return result.ElapsedTime; } + set { SetElapsedTime(value); } + } + public Builder SetElapsedTime(int value) { + PrepareBuilder(); + result.hasElapsedTime = true; + result.elapsedTime_ = value; + return this; + } + public Builder ClearElapsedTime() { + PrepareBuilder(); + result.hasElapsedTime = false; + result.elapsedTime_ = 0; + return this; + } + } + static RouteSummary() { + object.ReferenceEquals(global::examples.Proto.RouteGuide.Descriptor, null); + } + } + + #endregion + +} + +#endregion Designer generated code diff --git a/examples/csharp/route_guide/RouteGuide/RouteGuide.csproj b/examples/csharp/route_guide/RouteGuide/RouteGuide.csproj new file mode 100644 index 00000000000..8358974aac0 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide/RouteGuide.csproj @@ -0,0 +1,101 @@ + + + + + + + + Debug + AnyCPU + {49954D9C-5F17-4662-96B2-73BE833DD81A} + Library + Properties + RouteGuide + RouteGuide + v4.5 + 512 + 214cccda + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll + + + False + ..\packages\Grpc.Core.0.6.0\lib\net45\Grpc.Core.dll + + + False + ..\packages\Newtonsoft.Json.7.0.1-beta2\lib\net45\Newtonsoft.Json.dll + + + + False + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + + ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/route_guide/RouteGuide/RouteGuideGrpc.cs b/examples/csharp/route_guide/RouteGuide/RouteGuideGrpc.cs new file mode 100644 index 00000000000..c4b3900dca3 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide/RouteGuideGrpc.cs @@ -0,0 +1,123 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: route_guide.proto +#region Designer generated code + +using System; +using System.Threading; +using System.Threading.Tasks; +using Grpc.Core; + +namespace examples { + public static class RouteGuide + { + static readonly string __ServiceName = "examples.RouteGuide"; + + static readonly Marshaller __Marshaller_Point = Marshallers.Create((arg) => arg.ToByteArray(), global::examples.Point.ParseFrom); + static readonly Marshaller __Marshaller_Feature = Marshallers.Create((arg) => arg.ToByteArray(), global::examples.Feature.ParseFrom); + static readonly Marshaller __Marshaller_Rectangle = Marshallers.Create((arg) => arg.ToByteArray(), global::examples.Rectangle.ParseFrom); + static readonly Marshaller __Marshaller_RouteSummary = Marshallers.Create((arg) => arg.ToByteArray(), global::examples.RouteSummary.ParseFrom); + static readonly Marshaller __Marshaller_RouteNote = Marshallers.Create((arg) => arg.ToByteArray(), global::examples.RouteNote.ParseFrom); + + static readonly Method __Method_GetFeature = new Method( + MethodType.Unary, + "GetFeature", + __Marshaller_Point, + __Marshaller_Feature); + + static readonly Method __Method_ListFeatures = new Method( + MethodType.ServerStreaming, + "ListFeatures", + __Marshaller_Rectangle, + __Marshaller_Feature); + + static readonly Method __Method_RecordRoute = new Method( + MethodType.ClientStreaming, + "RecordRoute", + __Marshaller_Point, + __Marshaller_RouteSummary); + + static readonly Method __Method_RouteChat = new Method( + MethodType.DuplexStreaming, + "RouteChat", + __Marshaller_RouteNote, + __Marshaller_RouteNote); + + // client-side stub interface + public interface IRouteGuideClient + { + global::examples.Feature GetFeature(global::examples.Point request, CancellationToken token = default(CancellationToken)); + Task GetFeatureAsync(global::examples.Point request, CancellationToken token = default(CancellationToken)); + AsyncServerStreamingCall ListFeatures(global::examples.Rectangle request, CancellationToken token = default(CancellationToken)); + AsyncClientStreamingCall RecordRoute(CancellationToken token = default(CancellationToken)); + AsyncDuplexStreamingCall RouteChat(CancellationToken token = default(CancellationToken)); + } + + // server-side interface + public interface IRouteGuide + { + Task GetFeature(ServerCallContext context, global::examples.Point request); + Task ListFeatures(ServerCallContext context, global::examples.Rectangle request, IServerStreamWriter responseStream); + Task RecordRoute(ServerCallContext context, IAsyncStreamReader requestStream); + Task RouteChat(ServerCallContext context, IAsyncStreamReader requestStream, IServerStreamWriter responseStream); + } + + // client stub + public class RouteGuideClient : AbstractStub, IRouteGuideClient + { + public RouteGuideClient(Channel channel) : this(channel, StubConfiguration.Default) + { + } + public RouteGuideClient(Channel channel, StubConfiguration config) : base(channel, config) + { + } + public global::examples.Feature GetFeature(global::examples.Point request, CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_GetFeature); + return Calls.BlockingUnaryCall(call, request, token); + } + public Task GetFeatureAsync(global::examples.Point request, CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_GetFeature); + return Calls.AsyncUnaryCall(call, request, token); + } + public AsyncServerStreamingCall ListFeatures(global::examples.Rectangle request, CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_ListFeatures); + return Calls.AsyncServerStreamingCall(call, request, token); + } + public AsyncClientStreamingCall RecordRoute(CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_RecordRoute); + return Calls.AsyncClientStreamingCall(call, token); + } + public AsyncDuplexStreamingCall RouteChat(CancellationToken token = default(CancellationToken)) + { + var call = CreateCall(__ServiceName, __Method_RouteChat); + return Calls.AsyncDuplexStreamingCall(call, token); + } + } + + // creates service definition that can be registered with a server + public static ServerServiceDefinition BindService(IRouteGuide serviceImpl) + { + return ServerServiceDefinition.CreateBuilder(__ServiceName) + .AddMethod(__Method_GetFeature, serviceImpl.GetFeature) + .AddMethod(__Method_ListFeatures, serviceImpl.ListFeatures) + .AddMethod(__Method_RecordRoute, serviceImpl.RecordRoute) + .AddMethod(__Method_RouteChat, serviceImpl.RouteChat).Build(); + } + + // creates a new client stub + public static IRouteGuideClient NewStub(Channel channel) + { + return new RouteGuideClient(channel); + } + + // creates a new client stub + public static IRouteGuideClient NewStub(Channel channel, StubConfiguration config) + { + return new RouteGuideClient(channel, config); + } + } +} +#endregion diff --git a/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs new file mode 100644 index 00000000000..6fb8b1e28ab --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide/RouteGuideUtil.cs @@ -0,0 +1,67 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace examples +{ + public static class RouteGuideUtil + { + public const string DefaultFeaturesFile = "route_guide_db.json"; + + private const double CoordFactor = 1e7; + + /// + /// Indicates whether the given feature exists (i.e. has a valid name). + /// + public static bool Exists(Feature feature) + { + return feature != null && (feature.Name.Length != 0); + } + + public static double GetLatitude(Point point) + { + return point.Latitude / CoordFactor; + } + + public static double GetLongitude(Point point) + { + return point.Longitude / CoordFactor; + } + + /// + /// Parses features from a JSON file. + /// + public static List ParseFeatures(string filename) + { + var features = new List(); + var jsonFeatures = JsonConvert.DeserializeObject>(File.ReadAllText(filename)); + + + foreach(var jsonFeature in jsonFeatures) + { + features.Add(Feature.CreateBuilder().SetName(jsonFeature.name).SetLocation( + Point.CreateBuilder() + .SetLongitude(jsonFeature.location.longitude) + .SetLatitude(jsonFeature.location.latitude).Build()).Build()); + } + return features; + } + + private class JsonFeature + { + public string name; + public JsonLocation location; + } + + private class JsonLocation + { + public int longitude; + public int latitude; + } + } +} diff --git a/examples/csharp/route_guide/RouteGuide/packages.config b/examples/csharp/route_guide/RouteGuide/packages.config new file mode 100644 index 00000000000..79abe0aa655 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/route_guide/RouteGuide/protos/route_guide.proto b/examples/csharp/route_guide/RouteGuide/protos/route_guide.proto new file mode 100644 index 00000000000..f4110b5515b --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide/protos/route_guide.proto @@ -0,0 +1,123 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// TODO(jtattermusch): as of now, C# protobufs don't officially support +// proto3. +syntax = "proto2"; + +package examples; + +// Interface exported by the server. +service RouteGuide { + // A simple RPC. + // + // Obtains the feature at a given position. + // + // A feature with an empty name is returned if there's no feature at the given + // position. + rpc GetFeature(Point) returns (Feature) {} + + // A server-to-client streaming RPC. + // + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} + + // A client-to-server streaming RPC. + // + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} + + // A Bidirectional streaming RPC. + // + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +} + +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + optional int32 latitude = 1; + optional int32 longitude = 2; +} + +// A latitude-longitude rectangle, represented as two diagonally opposite +// points "lo" and "hi". +message Rectangle { + // One corner of the rectangle. + optional Point lo = 1; + + // The other corner of the rectangle. + optional Point hi = 2; +} + +// A feature names something at a given point. +// +// If a feature could not be named, the name is empty. +message Feature { + // The name of the feature. + optional string name = 1; + + // The point where the feature is detected. + optional Point location = 2; +} + +// A RouteNote is a message sent while at a given point. +message RouteNote { + // The location from which the message is sent. + optional Point location = 1; + + // The message to be sent. + optional string message = 2; +} + +// A RouteSummary is received in response to a RecordRoute rpc. +// +// It contains the number of individual points received, the number of +// detected features, and the total distance covered as the cumulative sum of +// the distance between each point. +message RouteSummary { + // The number of points received. + optional int32 point_count = 1; + + // The number of known features passed while traversing the route. + optional int32 feature_count = 2; + + // The distance covered in metres. + optional int32 distance = 3; + + // The duration of the traversal in seconds. + optional int32 elapsed_time = 4; +} diff --git a/examples/csharp/route_guide/RouteGuide/route_guide_db.json b/examples/csharp/route_guide/RouteGuide/route_guide_db.json new file mode 100644 index 00000000000..209f0162593 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuide/route_guide_db.json @@ -0,0 +1,601 @@ +[{ + "location": { + "latitude": 407838351, + "longitude": -746143763 + }, + "name": "Patriots Path, Mendham, NJ 07945, USA" +}, { + "location": { + "latitude": 408122808, + "longitude": -743999179 + }, + "name": "101 New Jersey 10, Whippany, NJ 07981, USA" +}, { + "location": { + "latitude": 413628156, + "longitude": -749015468 + }, + "name": "U.S. 6, Shohola, PA 18458, USA" +}, { + "location": { + "latitude": 419999544, + "longitude": -740371136 + }, + "name": "5 Conners Road, Kingston, NY 12401, USA" +}, { + "location": { + "latitude": 414008389, + "longitude": -743951297 + }, + "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" +}, { + "location": { + "latitude": 419611318, + "longitude": -746524769 + }, + "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" +}, { + "location": { + "latitude": 406109563, + "longitude": -742186778 + }, + "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" +}, { + "location": { + "latitude": 416802456, + "longitude": -742370183 + }, + "name": "352 South Mountain Road, Wallkill, NY 12589, USA" +}, { + "location": { + "latitude": 412950425, + "longitude": -741077389 + }, + "name": "Bailey Turn Road, Harriman, NY 10926, USA" +}, { + "location": { + "latitude": 412144655, + "longitude": -743949739 + }, + "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" +}, { + "location": { + "latitude": 415736605, + "longitude": -742847522 + }, + "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" +}, { + "location": { + "latitude": 413843930, + "longitude": -740501726 + }, + "name": "162 Merrill Road, Highland Mills, NY 10930, USA" +}, { + "location": { + "latitude": 410873075, + "longitude": -744459023 + }, + "name": "Clinton Road, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 412346009, + "longitude": -744026814 + }, + "name": "16 Old Brook Lane, Warwick, NY 10990, USA" +}, { + "location": { + "latitude": 402948455, + "longitude": -747903913 + }, + "name": "3 Drake Lane, Pennington, NJ 08534, USA" +}, { + "location": { + "latitude": 406337092, + "longitude": -740122226 + }, + "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" +}, { + "location": { + "latitude": 406421967, + "longitude": -747727624 + }, + "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" +}, { + "location": { + "latitude": 416318082, + "longitude": -749677716 + }, + "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" +}, { + "location": { + "latitude": 415301720, + "longitude": -748416257 + }, + "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" +}, { + "location": { + "latitude": 402647019, + "longitude": -747071791 + }, + "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" +}, { + "location": { + "latitude": 412567807, + "longitude": -741058078 + }, + "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" +}, { + "location": { + "latitude": 416855156, + "longitude": -744420597 + }, + "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" +}, { + "location": { + "latitude": 404663628, + "longitude": -744820157 + }, + "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" +}, { + "location": { + "latitude": 407113723, + "longitude": -749746483 + }, + "name": "" +}, { + "location": { + "latitude": 402133926, + "longitude": -743613249 + }, + "name": "" +}, { + "location": { + "latitude": 400273442, + "longitude": -741220915 + }, + "name": "" +}, { + "location": { + "latitude": 411236786, + "longitude": -744070769 + }, + "name": "" +}, { + "location": { + "latitude": 411633782, + "longitude": -746784970 + }, + "name": "211-225 Plains Road, Augusta, NJ 07822, USA" +}, { + "location": { + "latitude": 415830701, + "longitude": -742952812 + }, + "name": "" +}, { + "location": { + "latitude": 413447164, + "longitude": -748712898 + }, + "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" +}, { + "location": { + "latitude": 405047245, + "longitude": -749800722 + }, + "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" +}, { + "location": { + "latitude": 418858923, + "longitude": -746156790 + }, + "name": "" +}, { + "location": { + "latitude": 417951888, + "longitude": -748484944 + }, + "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" +}, { + "location": { + "latitude": 407033786, + "longitude": -743977337 + }, + "name": "26 East 3rd Street, New Providence, NJ 07974, USA" +}, { + "location": { + "latitude": 417548014, + "longitude": -740075041 + }, + "name": "" +}, { + "location": { + "latitude": 410395868, + "longitude": -744972325 + }, + "name": "" +}, { + "location": { + "latitude": 404615353, + "longitude": -745129803 + }, + "name": "" +}, { + "location": { + "latitude": 406589790, + "longitude": -743560121 + }, + "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" +}, { + "location": { + "latitude": 414653148, + "longitude": -740477477 + }, + "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" +}, { + "location": { + "latitude": 405957808, + "longitude": -743255336 + }, + "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" +}, { + "location": { + "latitude": 411733589, + "longitude": -741648093 + }, + "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" +}, { + "location": { + "latitude": 412676291, + "longitude": -742606606 + }, + "name": "1270 Lakes Road, Monroe, NY 10950, USA" +}, { + "location": { + "latitude": 409224445, + "longitude": -748286738 + }, + "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" +}, { + "location": { + "latitude": 406523420, + "longitude": -742135517 + }, + "name": "652 Garden Street, Elizabeth, NJ 07202, USA" +}, { + "location": { + "latitude": 401827388, + "longitude": -740294537 + }, + "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" +}, { + "location": { + "latitude": 410564152, + "longitude": -743685054 + }, + "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 408472324, + "longitude": -740726046 + }, + "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" +}, { + "location": { + "latitude": 412452168, + "longitude": -740214052 + }, + "name": "5 White Oak Lane, Stony Point, NY 10980, USA" +}, { + "location": { + "latitude": 409146138, + "longitude": -746188906 + }, + "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" +}, { + "location": { + "latitude": 404701380, + "longitude": -744781745 + }, + "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 409642566, + "longitude": -746017679 + }, + "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" +}, { + "location": { + "latitude": 408031728, + "longitude": -748645385 + }, + "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" +}, { + "location": { + "latitude": 413700272, + "longitude": -742135189 + }, + "name": "367 Prospect Road, Chester, NY 10918, USA" +}, { + "location": { + "latitude": 404310607, + "longitude": -740282632 + }, + "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" +}, { + "location": { + "latitude": 409319800, + "longitude": -746201391 + }, + "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" +}, { + "location": { + "latitude": 406685311, + "longitude": -742108603 + }, + "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" +}, { + "location": { + "latitude": 419018117, + "longitude": -749142781 + }, + "name": "43 Dreher Road, Roscoe, NY 12776, USA" +}, { + "location": { + "latitude": 412856162, + "longitude": -745148837 + }, + "name": "Swan Street, Pine Island, NY 10969, USA" +}, { + "location": { + "latitude": 416560744, + "longitude": -746721964 + }, + "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" +}, { + "location": { + "latitude": 405314270, + "longitude": -749836354 + }, + "name": "" +}, { + "location": { + "latitude": 414219548, + "longitude": -743327440 + }, + "name": "" +}, { + "location": { + "latitude": 415534177, + "longitude": -742900616 + }, + "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" +}, { + "location": { + "latitude": 406898530, + "longitude": -749127080 + }, + "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" +}, { + "location": { + "latitude": 407586880, + "longitude": -741670168 + }, + "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" +}, { + "location": { + "latitude": 400106455, + "longitude": -742870190 + }, + "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" +}, { + "location": { + "latitude": 400066188, + "longitude": -746793294 + }, + "name": "" +}, { + "location": { + "latitude": 418803880, + "longitude": -744102673 + }, + "name": "40 Mountain Road, Napanoch, NY 12458, USA" +}, { + "location": { + "latitude": 414204288, + "longitude": -747895140 + }, + "name": "" +}, { + "location": { + "latitude": 414777405, + "longitude": -740615601 + }, + "name": "" +}, { + "location": { + "latitude": 415464475, + "longitude": -747175374 + }, + "name": "48 North Road, Forestburgh, NY 12777, USA" +}, { + "location": { + "latitude": 404062378, + "longitude": -746376177 + }, + "name": "" +}, { + "location": { + "latitude": 405688272, + "longitude": -749285130 + }, + "name": "" +}, { + "location": { + "latitude": 400342070, + "longitude": -748788996 + }, + "name": "" +}, { + "location": { + "latitude": 401809022, + "longitude": -744157964 + }, + "name": "" +}, { + "location": { + "latitude": 404226644, + "longitude": -740517141 + }, + "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" +}, { + "location": { + "latitude": 410322033, + "longitude": -747871659 + }, + "name": "" +}, { + "location": { + "latitude": 407100674, + "longitude": -747742727 + }, + "name": "" +}, { + "location": { + "latitude": 418811433, + "longitude": -741718005 + }, + "name": "213 Bush Road, Stone Ridge, NY 12484, USA" +}, { + "location": { + "latitude": 415034302, + "longitude": -743850945 + }, + "name": "" +}, { + "location": { + "latitude": 411349992, + "longitude": -743694161 + }, + "name": "" +}, { + "location": { + "latitude": 404839914, + "longitude": -744759616 + }, + "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 414638017, + "longitude": -745957854 + }, + "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" +}, { + "location": { + "latitude": 412127800, + "longitude": -740173578 + }, + "name": "" +}, { + "location": { + "latitude": 401263460, + "longitude": -747964303 + }, + "name": "" +}, { + "location": { + "latitude": 412843391, + "longitude": -749086026 + }, + "name": "" +}, { + "location": { + "latitude": 418512773, + "longitude": -743067823 + }, + "name": "" +}, { + "location": { + "latitude": 404318328, + "longitude": -740835638 + }, + "name": "42-102 Main Street, Belford, NJ 07718, USA" +}, { + "location": { + "latitude": 419020746, + "longitude": -741172328 + }, + "name": "" +}, { + "location": { + "latitude": 404080723, + "longitude": -746119569 + }, + "name": "" +}, { + "location": { + "latitude": 401012643, + "longitude": -744035134 + }, + "name": "" +}, { + "location": { + "latitude": 404306372, + "longitude": -741079661 + }, + "name": "" +}, { + "location": { + "latitude": 403966326, + "longitude": -748519297 + }, + "name": "" +}, { + "location": { + "latitude": 405002031, + "longitude": -748407866 + }, + "name": "" +}, { + "location": { + "latitude": 409532885, + "longitude": -742200683 + }, + "name": "" +}, { + "location": { + "latitude": 416851321, + "longitude": -742674555 + }, + "name": "" +}, { + "location": { + "latitude": 406411633, + "longitude": -741722051 + }, + "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" +}, { + "location": { + "latitude": 413069058, + "longitude": -744597778 + }, + "name": "261 Van Sickle Road, Goshen, NY 10924, USA" +}, { + "location": { + "latitude": 418465462, + "longitude": -746859398 + }, + "name": "" +}, { + "location": { + "latitude": 411733222, + "longitude": -744228360 + }, + "name": "" +}, { + "location": { + "latitude": 410248224, + "longitude": -747127767 + }, + "name": "3 Hasta Way, Newton, NJ 07860, USA" +}] \ No newline at end of file diff --git a/examples/csharp/route_guide/RouteGuideClient/App.config b/examples/csharp/route_guide/RouteGuideClient/App.config new file mode 100644 index 00000000000..8e15646352e --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideClient/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/examples/csharp/route_guide/RouteGuideClient/Program.cs b/examples/csharp/route_guide/RouteGuideClient/Program.cs new file mode 100644 index 00000000000..0352c780201 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideClient/Program.cs @@ -0,0 +1,223 @@ +using Grpc.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace examples +{ + class Program + { + /// + /// Sample client code that makes gRPC calls to the server. + /// + public class RouteGuideClient + { + readonly RouteGuide.IRouteGuideClient client; + + public RouteGuideClient(RouteGuide.IRouteGuideClient client) + { + this.client = client; + } + + /// + /// Blocking unary call example. Calls GetFeature and prints the response. + /// + public void GetFeature(int lat, int lon) + { + try + { + Log("*** GetFeature: lat={0} lon={1}", lat, lon); + + Point request = Point.CreateBuilder().SetLatitude(lat).SetLongitude(lon).Build(); + + Feature feature = client.GetFeature(request); + if (RouteGuideUtil.Exists(feature)) + { + Log("Found feature called \"{0}\" at {1}, {2}", + feature.Name, + RouteGuideUtil.GetLatitude(feature.Location), + RouteGuideUtil.GetLongitude(feature.Location)); + } + else + { + Log("Found no feature at {0}, {1}", + RouteGuideUtil.GetLatitude(feature.Location), + RouteGuideUtil.GetLongitude(feature.Location)); + } + } + catch (RpcException e) + { + Log("RPC failed " + e); + throw e; + } + } + + + /// + /// Server-streaming example. Calls listFeatures with a rectangle of interest. Prints each response feature as it arrives. + /// + public async Task ListFeatures(int lowLat, int lowLon, int hiLat, int hiLon) + { + try + { + Log("*** ListFeatures: lowLat={0} lowLon={1} hiLat={2} hiLon={3}", lowLat, lowLon, hiLat, + hiLon); + + Rectangle request = + Rectangle.CreateBuilder() + .SetLo(Point.CreateBuilder().SetLatitude(lowLat).SetLongitude(lowLon).Build()) + .SetHi(Point.CreateBuilder().SetLatitude(hiLat).SetLongitude(hiLon).Build()).Build(); + + using (var call = client.ListFeatures(request)) + { + StringBuilder responseLog = new StringBuilder("Result: "); + + while (await call.ResponseStream.MoveNext()) + { + Feature feature = call.ResponseStream.Current; + responseLog.Append(feature.ToString()); + } + Log(responseLog.ToString()); + } + } + catch (RpcException e) + { + Log("RPC failed " + e); + throw e; + } + } + + /// + /// Client-streaming example. Sends numPoints randomly chosen points from features + /// with a variable delay in between. Prints the statistics when they are sent from the server. + /// + public async Task RecordRoute(List features, int numPoints) + { + try + { + Log("*** RecordRoute"); + using (var call = client.RecordRoute()) + { + // Send numPoints points randomly selected from the features list. + StringBuilder numMsg = new StringBuilder(); + Random rand = new Random(); + for (int i = 0; i < numPoints; ++i) + { + int index = rand.Next(features.Count); + Point point = features[index].Location; + Log("Visiting point {0}, {1}", RouteGuideUtil.GetLatitude(point), + RouteGuideUtil.GetLongitude(point)); + + await call.RequestStream.WriteAsync(point); + + // A bit of delay before sending the next one. + await Task.Delay(rand.Next(1000) + 500); + } + await call.RequestStream.CompleteAsync(); + + RouteSummary summary = await call.Result; + Log("Finished trip with {0} points. Passed {1} features. " + + "Travelled {2} meters. It took {3} seconds.", summary.PointCount, + summary.FeatureCount, summary.Distance, summary.ElapsedTime); + + Log("Finished RecordRoute"); + } + } + catch (RpcException e) + { + Log("RPC failed", e); + throw e; + } + } + + /// + /// Bi-directional streaming example. Send some chat messages, and print any + /// chat messages that are sent from the server. + /// + public async Task RouteChat() + { + try + { + Log("*** RouteChat"); + var requests = + new List { NewNote("First message", 0, 0), NewNote("Second message", 0, 1), NewNote("Third message", 1, 0), NewNote("Fourth message", 1, 1) }; + + using (var call = client.RouteChat()) + { + var responseReaderTask = Task.Run(async () => + { + while (await call.ResponseStream.MoveNext()) + { + var note = call.ResponseStream.Current; + Log("Got message \"{0}\" at {1}, {2}", note.Message, + note.Location.Latitude, note.Location.Longitude); + } + }); + + foreach (RouteNote request in requests) + { + Log("Sending message \"{0}\" at {1}, {2}", request.Message, + request.Location.Latitude, request.Location.Longitude); + + await call.RequestStream.WriteAsync(request); + } + await call.RequestStream.CompleteAsync(); + await responseReaderTask; + + Log("Finished RouteChat"); + } + } + catch (RpcException e) + { + Log("RPC failed", e); + throw e; + } + } + + private void Log(string s, params object[] args) + { + Console.WriteLine(string.Format(s, args)); + } + + private void Log(string s) + { + Console.WriteLine(s); + } + + private RouteNote NewNote(string message, int lat, int lon) + { + return RouteNote.CreateBuilder().SetMessage(message).SetLocation( + Point.CreateBuilder().SetLatitude(lat).SetLongitude(lat).Build()).Build(); + } + } + + static void Main(string[] args) + { + GrpcEnvironment.Initialize(); + + using (Channel channel = new Channel("127.0.0.1:50052")) + { + var client = new RouteGuideClient(RouteGuide.NewStub(channel)); + + // Looking for a valid feature + client.GetFeature(409146138, -746188906); + + // Feature missing. + client.GetFeature(0, 0); + + // Looking for features between 40, -75 and 42, -73. + client.ListFeatures(400000000, -750000000, 420000000, -730000000).Wait(); + + // Record a few randomly selected points from the features file. + client.RecordRoute(RouteGuideUtil.ParseFeatures(RouteGuideUtil.DefaultFeaturesFile), 10).Wait(); + + // Send and receive some notes. + client.RouteChat().Wait(); + } + + GrpcEnvironment.Shutdown(); + } + } +} diff --git a/examples/csharp/route_guide/RouteGuideClient/Properties/AssemblyInfo.cs b/examples/csharp/route_guide/RouteGuideClient/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..a17e164a788 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideClient/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RouteGuideClient")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RouteGuideClient")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("914644eb-47cd-4a37-9fba-5e62dd432333")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/examples/csharp/route_guide/RouteGuideClient/RouteGuideClient.csproj b/examples/csharp/route_guide/RouteGuideClient/RouteGuideClient.csproj new file mode 100644 index 00000000000..78034a9145e --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideClient/RouteGuideClient.csproj @@ -0,0 +1,100 @@ + + + + + + + + Debug + AnyCPU + {D47BE663-4DE3-4206-B7A8-EA3FA066DADC} + Exe + Properties + RouteGuideClient + RouteGuideClient + v4.5 + 512 + 794416d0 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll + + + False + ..\packages\Grpc.Core.0.6.0\lib\net45\Grpc.Core.dll + + + + False + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + + ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll + + + + + + + + + + + + + + + + + + {49954d9c-5f17-4662-96b2-73be833dd81a} + RouteGuide + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/route_guide/RouteGuideClient/packages.config b/examples/csharp/route_guide/RouteGuideClient/packages.config new file mode 100644 index 00000000000..5922553bc37 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideClient/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/route_guide/RouteGuideServer/App.config b/examples/csharp/route_guide/RouteGuideServer/App.config new file mode 100644 index 00000000000..8e15646352e --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideServer/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/examples/csharp/route_guide/RouteGuideServer/Program.cs b/examples/csharp/route_guide/RouteGuideServer/Program.cs new file mode 100644 index 00000000000..e00b4d67238 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideServer/Program.cs @@ -0,0 +1,30 @@ +using Grpc.Core; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace examples +{ + class Program + { + static void Main(string[] args) + { + var features = RouteGuideUtil.ParseFeatures(RouteGuideUtil.DefaultFeaturesFile); + GrpcEnvironment.Initialize(); + + Server server = new Server(); + server.AddServiceDefinition(RouteGuide.BindService(new RouteGuideImpl(features))); + int port = server.AddListeningPort("localhost", 50052); + server.Start(); + + Console.WriteLine("RouteGuide server listening on port " + port); + Console.WriteLine("Press any key to stop the server..."); + Console.ReadKey(); + + server.ShutdownAsync().Wait(); + GrpcEnvironment.Shutdown(); + } + } +} diff --git a/examples/csharp/route_guide/RouteGuideServer/Properties/AssemblyInfo.cs b/examples/csharp/route_guide/RouteGuideServer/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..a161b1d6027 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideServer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RouteGuideServer")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RouteGuideServer")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("908bdeef-05cc-42bf-9498-c4c573df8925")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs b/examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs new file mode 100644 index 00000000000..0bdf386fc33 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideServer/RouteGuideImpl.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace examples +{ + /// + /// Example implementation of RouteGuide server. + /// + public class RouteGuideImpl : RouteGuide.IRouteGuide + { + readonly List features; + private readonly ConcurrentDictionary> routeNotes = + new ConcurrentDictionary>(); + + public RouteGuideImpl(List features) + { + this.features = features; + } + + /// + /// Gets the feature at the requested point. If no feature at that location + /// exists, an unnammed feature is returned at the provided location. + /// + public Task GetFeature(Grpc.Core.ServerCallContext context, Point request) + { + return Task.FromResult(CheckFeature(request)); + } + + /// + /// Gets all features contained within the given bounding rectangle. + /// + public async Task ListFeatures(Grpc.Core.ServerCallContext context, Rectangle request, Grpc.Core.IServerStreamWriter responseStream) + { + int left = Math.Min(request.Lo.Longitude, request.Hi.Longitude); + int right = Math.Max(request.Lo.Longitude, request.Hi.Longitude); + int top = Math.Max(request.Lo.Latitude, request.Hi.Latitude); + int bottom = Math.Min(request.Lo.Latitude, request.Hi.Latitude); + + foreach (var feature in features) + { + if (!RouteGuideUtil.Exists(feature)) + { + continue; + } + + int lat = feature.Location.Latitude; + int lon = feature.Location.Longitude; + if (lon >= left && lon <= right && lat >= bottom && lat <= top) + { + await responseStream.WriteAsync(feature); + } + } + } + + /// + /// Gets a stream of points, and responds with statistics about the "trip": number of points, + /// number of known features visited, total distance traveled, and total time spent. + /// + public async Task RecordRoute(Grpc.Core.ServerCallContext context, Grpc.Core.IAsyncStreamReader requestStream) + { + int pointCount = 0; + int featureCount = 0; + int distance = 0; + Point previous = null; + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + while (await requestStream.MoveNext()) + { + var point = requestStream.Current; + pointCount++; + if (RouteGuideUtil.Exists(CheckFeature(point))) + { + featureCount++; + } + if (previous != null) + { + distance += (int) CalcDistance(previous, point); + } + previous = point; + } + + stopwatch.Stop(); + return RouteSummary.CreateBuilder().SetPointCount(pointCount) + .SetFeatureCount(featureCount).SetDistance(distance) + .SetElapsedTime((int) (stopwatch.ElapsedMilliseconds / 1000)).Build(); + } + + /// + /// Receives a stream of message/location pairs, and responds with a stream of all previous + /// messages at each of those locations. + /// + public async Task RouteChat(Grpc.Core.ServerCallContext context, Grpc.Core.IAsyncStreamReader requestStream, Grpc.Core.IServerStreamWriter responseStream) + { + while (await requestStream.MoveNext()) + { + var note = requestStream.Current; + List notes = GetOrCreateNotes(note.Location); + + List prevNotes; + lock (notes) + { + prevNotes = new List(notes); + } + + foreach (var prevNote in prevNotes) + { + await responseStream.WriteAsync(prevNote); + } + + lock (notes) + { + notes.Add(note); + } + } + } + + + /// + /// Get the notes list for the given location. If missing, create it. + /// + private List GetOrCreateNotes(Point location) + { + List notes = new List(); + routeNotes.TryAdd(location, notes); + return routeNotes[location]; + } + + /// + /// Gets the feature at the given point. + /// + /// the location to check + /// The feature object at the point Note that an empty name indicates no feature. + private Feature CheckFeature(Point location) + { + foreach (var feature in features) + { + if (feature.Location.Latitude == location.Latitude + && feature.Location.Longitude == location.Longitude) + { + return feature; + } + } + + // No feature was found, return an unnamed feature. + return Feature.CreateBuilder().SetName("").SetLocation(location).Build(); + } + + /// + /// Calculate the distance between two points using the "haversine" formula. + /// This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. + /// + /// the starting point + /// the end point + /// the distance between the points in meters + private static double CalcDistance(Point start, Point end) + { + double lat1 = RouteGuideUtil.GetLatitude(start); + double lat2 = RouteGuideUtil.GetLatitude(end); + double lon1 = RouteGuideUtil.GetLongitude(start); + double lon2 = RouteGuideUtil.GetLongitude(end); + int r = 6371000; // metres + double φ1 = ToRadians(lat1); + double φ2 = ToRadians(lat2); + double Δφ = ToRadians(lat2 - lat1); + double Δλ = ToRadians(lon2 - lon1); + + double a = Math.Sin(Δφ / 2) * Math.Sin(Δφ / 2) + Math.Cos(φ1) * Math.Cos(φ2) * Math.Sin(Δλ / 2) * Math.Sin(Δλ / 2); + double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); + + return r * c; + } + + private static double ToRadians(double val) + { + return (Math.PI / 180) * val; + } + } +} diff --git a/examples/csharp/route_guide/RouteGuideServer/RouteGuideServer.csproj b/examples/csharp/route_guide/RouteGuideServer/RouteGuideServer.csproj new file mode 100644 index 00000000000..9ac1cfbf4d8 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideServer/RouteGuideServer.csproj @@ -0,0 +1,101 @@ + + + + + + + + Debug + AnyCPU + {4B7C7794-BE24-4477-ACE7-18259EB73D27} + Exe + Properties + RouteGuideServer + RouteGuideServer + v4.5 + 512 + 74781d8b + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll + + + ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll + + + False + ..\packages\Grpc.Core.0.6.0\lib\net45\Grpc.Core.dll + + + + False + ..\packages\System.Collections.Immutable.1.1.36\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + + + + ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll + + + + + + + + + + + + + + + + + + + {49954d9c-5f17-4662-96b2-73be833dd81a} + RouteGuide + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/csharp/route_guide/RouteGuideServer/packages.config b/examples/csharp/route_guide/RouteGuideServer/packages.config new file mode 100644 index 00000000000..5922553bc37 --- /dev/null +++ b/examples/csharp/route_guide/RouteGuideServer/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/node/.gitignore b/examples/node/.gitignore new file mode 100644 index 00000000000..3d06f5db7b3 --- /dev/null +++ b/examples/node/.gitignore @@ -0,0 +1,3 @@ +*~ +node_modules +npm-debug.log \ No newline at end of file diff --git a/examples/node/README.md b/examples/node/README.md new file mode 100644 index 00000000000..045fe51ede9 --- /dev/null +++ b/examples/node/README.md @@ -0,0 +1,60 @@ +gRPC in 3 minutes (Node.js) +=========================== + +PREREQUISITES +------------- + +- `node`: This requires Node 10.x or greater. +- [homebrew][] on Mac OS X, [linuxbrew][] on Linux. These simplify the installation of the gRPC C core. + +INSTALL +------- + - On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. Run the following command to install gRPC Node.js. + + ```sh + $ curl -fsSL https://goo.gl/getgrpc | bash -s nodejs + ``` + This will download and run the [gRPC install script][], then install the latest version of gRPC Nodejs npm package. + - Clone this repository + + ```sh + $ git clone https://github.com/grpc/grpc.git + ``` + + - Install this package's dependencies + + ```sh + $ cd examples/node + $ npm install + ``` + +TRY IT! +------- + + - Run the server + + ```sh + $ # from this directory (grpc_common/node). + $ node ./greeter_server.js & + ``` + + - Run the client + + ```sh + $ # from this directory + $ node ./greeter_client.js + ``` + +NOTE +---- +This directory has a copy of `helloworld.proto` because it currently depends on +some Protocol Buffer 2.0 syntax that is deprecated in Protocol Buffer 3.0. + +TUTORIAL +-------- +You can find a more detailed tutorial in [gRPC Basics: Node.js][] + +[homebrew]:http://brew.sh +[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation +[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install +[gRPC Basics: Node.js]:https://github.com/grpc/grpc/blob/master/examples/node/route_guide/README.md diff --git a/examples/node/greeter_client.js b/examples/node/greeter_client.js new file mode 100644 index 00000000000..ab7050ab213 --- /dev/null +++ b/examples/node/greeter_client.js @@ -0,0 +1,52 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var PROTO_PATH = __dirname + '/helloworld.proto'; + +var grpc = require('grpc'); +var hello_proto = grpc.load(PROTO_PATH).helloworld; + +function main() { + var client = new hello_proto.Greeter('localhost:50051'); + var user; + if (process.argv.length >= 3) { + user = process.argv[2]; + } else { + user = 'world'; + } + client.sayHello({name: user}, function(err, response) { + console.log('Greeting:', response.message); + }); +} + +main(); diff --git a/examples/node/greeter_server.js b/examples/node/greeter_server.js new file mode 100644 index 00000000000..2fb95f0f90e --- /dev/null +++ b/examples/node/greeter_server.js @@ -0,0 +1,63 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +var PROTO_PATH = __dirname + '/helloworld.proto'; + +var grpc = require('grpc'); +var hello_proto = grpc.load(PROTO_PATH).helloworld; + +var Server = grpc.buildServer([hello_proto.Greeter.service]); + +/** + * Implements the SayHello RPC method. + */ +function sayHello(call, callback) { + callback(null, {message: 'Hello ' + call.request.name}); +} + +/** + * Starts an RPC server that receives requests for the Greeter service at the + * sample server port + */ +function main() { + var server = new Server({ + "helloworld.Greeter": { + sayHello: sayHello + } + }); + + server.bind('0.0.0.0:50051'); + server.listen(); +} + +main(); diff --git a/examples/node/helloworld.proto b/examples/node/helloworld.proto new file mode 100644 index 00000000000..a52c947f895 --- /dev/null +++ b/examples/node/helloworld.proto @@ -0,0 +1,50 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "ex.grpc"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + optional string name = 1; +} + +// The response message containing the greetings +message HelloReply { + optional string message = 1; +} diff --git a/examples/node/package.json b/examples/node/package.json new file mode 100644 index 00000000000..caf539518f1 --- /dev/null +++ b/examples/node/package.json @@ -0,0 +1,10 @@ +{ + "name": "grpc-demo", + "version": "0.5.0", + "dependencies": { + "async": "^0.9.0", + "grpc": "~0.9.0", + "minimist": "^1.1.0", + "underscore": "^1.8.2" + } +} diff --git a/examples/node/route_guide/README.md b/examples/node/route_guide/README.md new file mode 100644 index 00000000000..2efc5a5da52 --- /dev/null +++ b/examples/node/route_guide/README.md @@ -0,0 +1,362 @@ +#gRPC Basics: Node.js + +This tutorial provides a basic Node.js programmer's introduction to working with gRPC. By walking through this example you'll learn how to: + +- Define a service in a .proto file. +- Use the Node.js gRPC API to write a simple client and server for your service. + +It assumes that you have read the [Getting started](https://github.com/grpc/grpc/tree/master/examples) guide and are familiar with [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). Note that the example in this tutorial uses the proto3 version of the protocol buffers language, which is currently in alpha release:you can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3) and see the [release notes](https://github.com/google/protobuf/releases) for the new version in the protocol buffers Github repository. + +This isn't a comprehensive guide to using gRPC in Node.js: more reference documentation is coming soon. + +## Why use gRPC? + +Our example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients. + +With gRPC we can define our service once in a .proto file and implement clients and servers in any of gRPC's supported languages, which in turn can be run in environments ranging from servers inside Google to your own tablet - all the complexity of communication between different languages and environments is handled for you by gRPC. We also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating. + +## Example code and setup + +The example code for our tutorial is in [examples/node/route_guide](examples/node/route_guide). To download the example, clone this repository by running the following command: +```shell +$ git clone https://github.com/grpc/grpc.git +``` + +Then change your current directory to `examples/node/route_guide`: +```shell +$ cd examples/node/route_guide +``` + +You also should have the relevant tools installed to generate the server and client interface code - if you don't already, follow the setup instructions in [the Node.js quick start guide](examples/node). + + +## Defining the service + +Our first step (as you'll know from [Getting started](https://github.com/grpc/grpc/tree/master/examples)) is to define the gRPC *service* and the method *request* and *response* types using [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). You can see the complete .proto file in [`examples/protos/route_guide.proto`](examples/protos/route_guide.proto). + +To define a service, you specify a named `service` in your .proto file: + +```protobuf +service RouteGuide { + ... +} +``` + +Then you define `rpc` methods inside your service definition, specifying their request and response types. gRPC lets you define four kinds of service method, all of which are used in the `RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call. +```protobuf + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *server-side streaming RPC* where the client sends a request to the server and gets a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. As you can see in our example, you specify a server-side streaming method by placing the `stream` keyword before the *response* type. +```protobuf + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *client-side streaming RPC* where the client writes a sequence of messages and sends them to the server, again using a provided stream. Once the client has finished writing the messages, it waits for the server to read them all and return its response. You specify a server-side streaming method by placing the `stream` keyword before the *request* type. +```protobuf + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectional streaming RPC* where both sides send a sequence of messages using a read-write stream. The two streams operate independently, so clients and servers can read and write in whatever order they like: for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved. You specify this type of method by placing the `stream` keyword before both the request and the response. +```protobuf + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Our .proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods - for example, here's the `Point` message type: +```protobuf +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + + +## Loading service descriptors from proto files + +The Node.js library dynamically generates service descriptors and client stub definitions from `.proto` files loaded at runtime. + +To load a `.proto` file, simply `require` the gRPC library, then use its `load()` method: + +```node +var grpc = require('grpc'); +var protoDescriptor = grpc.load(__dirname + '/route_guide.proto'); +// The protoDescriptor object has the full package hierarchy +var example = protoDescriptor.examples; +``` + +Once you've done this, the stub constructor is in the `examples` namespace (`protoDescriptor.examples.RouteGuide`) and the service descriptor (which is used to create a server) is a property of the stub (`protoDescriptor.examples.RouteGuide.service`); + + +## Creating the server + +First let's look at how we create a `RouteGuide` server. If you're only interested in creating gRPC clients, you can skip this section and go straight to [Creating the client](#client) (though you might find it interesting anyway!). + +There are two parts to making our `RouteGuide` service do its job: +- Implementing the service interface generated from our service definition: doing the actual "work" of our service. +- Running a gRPC server to listen for requests from clients and return the service responses. + +You can find our example `RouteGuide` server in [examples/node/route_guide/route_guide_server.js](examples/node/route_guide/route_guide_server.js). Let's take a closer look at how it works. + +### Implementing RouteGuide + +As you can see, our server has a `Server` constructor generated from the `RouteGuide.service` descriptor object + +```node +var Server = grpc.buildServer([examples.RouteGuide.service]); +``` +In this case we're implementing the *asynchronous* version of `RouteGuide`, which provides our default gRPC server behaviour. + +The functions in `route_guide_server.js` implement all our service methods. Let's look at the simplest type first, `getFeature`, which just gets a `Point` from the client and returns the corresponding feature information from its database in a `Feature`. + +```node +function checkFeature(point) { + var feature; + // Check if there is already a feature object for the given point + for (var i = 0; i < feature_list.length; i++) { + feature = feature_list[i]; + if (feature.location.latitude === point.latitude && + feature.location.longitude === point.longitude) { + return feature; + } + } + var name = ''; + feature = { + name: name, + location: point + }; + return feature; +} +function getFeature(call, callback) { + callback(null, checkFeature(call.request)); +} +``` + +The method is passed a call object for the RPC, which has the `Point` parameter as a property, and a callback to which we can pass our returned `Feature`. In the method body we populate a `Feature` corresponding to the given point and pass it to the callback, with a null first parameter to indicate that there is no error. + +Now let's look at something a bit more complicated - a streaming RPC. `listFeatures` is a server-side streaming RPC, so we need to send back multiple `Feature`s to our client. + +```node +function listFeatures(call) { + var lo = call.request.lo; + var hi = call.request.hi; + var left = _.min([lo.longitude, hi.longitude]); + var right = _.max([lo.longitude, hi.longitude]); + var top = _.max([lo.latitude, hi.latitude]); + var bottom = _.min([lo.latitude, hi.latitude]); + // For each feature, check if it is in the given bounding box + _.each(feature_list, function(feature) { + if (feature.name === '') { + return; + } + if (feature.location.longitude >= left && + feature.location.longitude <= right && + feature.location.latitude >= bottom && + feature.location.latitude <= top) { + call.write(feature); + } + }); + call.end(); +} +``` + +As you can see, instead of getting the call object and callback in our method parameters, this time we get a `call` object that implements the `Writable` interface. In the method, we create as many `Feature` objects as we need to return, writing them to the `call` using its `write()` method. Finally, we call `call.end()` to indicate that we have sent all messages. + +If you look at the client-side streaming method `RecordRoute` you'll see it's quite similar to the unary call, except this time the `call` parameter implements the `Reader` interface. The `call`'s `'data'` event fires every time there is new data, and the `'end'` event fires when all data has been read. Like the unary case, we respond by calling the callback + +```node +call.on('data', function(point) { + // Process user data +}); +call.on('end', function() { + callback(null, result); +}); +``` + +Finally, let's look at our bidirectional streaming RPC `RouteChat()`. + +```node +function routeChat(call) { + call.on('data', function(note) { + var key = pointKey(note.location); + /* For each note sent, respond with all previous notes that correspond to + * the same point */ + if (route_notes.hasOwnProperty(key)) { + _.each(route_notes[key], function(note) { + call.write(note); + }); + } else { + route_notes[key] = []; + } + // Then add the new note to the list + route_notes[key].push(JSON.parse(JSON.stringify(note))); + }); + call.on('end', function() { + call.end(); + }); +} +``` + +This time we get a `call` implementing `Duplex` that can be used to read *and* write messages. The syntax for reading and writing here is exactly the same as for our client-streaming and server-streaming methods. Although each side will always get the other's messages in the order they were written, both the client and server can read and write in any order — the streams operate completely independently. + +### Starting the server + +Once we've implemented all our methods, we also need to start up a gRPC server so that clients can actually use our service. The following snippet shows how we do this for our `RouteGuide` service: + +```node +function getServer() { + return new Server({ + 'examples.RouteGuide' : { + getFeature: getFeature, + listFeatures: listFeatures, + recordRoute: recordRoute, + routeChat: routeChat + } + }); +} +var routeServer = getServer(); +routeServer.bind('0.0.0.0:50051'); +routeServer.listen(); +``` + +As you can see, we build and start our server with the following steps: + + 1. Create a `Server` constructor from the `RouteGuide` service descriptor. + 2. Implement the service methods. + 3. Create an instance of the server by calling the `Server` constructor with the method implementations. + 4. Specify the address and port we want to use to listen for client requests using the instance's `bind()` method. + 5. Call `listen()` on the instance to start the RPC server. + + +## Creating the client + +In this section, we'll look at creating a Node.js client for our `RouteGuide` service. You can see our complete example client code in [examples/node/route_guide/route_guide_client.js](examples/node/route_guide/route_guide_client.js). + +### Creating a stub + +To call service methods, we first need to create a *stub*. To do this, we just need to call the RouteGuide stub constructor, specifying the server address and port. + +```node +new example.RouteGuide('localhost:50051'); +``` + +### Calling service methods + +Now let's look at how we call our service methods. Note that all of these methods are asynchronous: they use either events or callbacks to retrieve results. + +#### Simple RPC + +Calling the simple RPC `GetFeature` is nearly as straightforward as calling a local asynchronous method. + +```node +var point = {latitude: 409146138, longitude: -746188906}; +stub.getFeature(point, function(err, feature) { + if (err) { + // process error + } else { + // process feature + } +}); +``` + +As you can see, we create and populate a request object. Finally, we call the method on the stub, passing it the request and callback. If there is no error, then we can read the response information from the server from our response object. + +```node + console.log('Found feature called "' + feature.name + '" at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); +``` + +#### Streaming RPCs + +Now let's look at our streaming methods. If you've already read [Creating the server](#server) some of this may look very familiar - streaming RPCs are implemented in a similar way on both sides. Here's where we call the server-side streaming method `ListFeatures`, which returns a stream of geographical `Feature`s: + +```node +var call = client.listFeatures(rectangle); + call.on('data', function(feature) { + console.log('Found feature called "' + feature.name + '" at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + }); + call.on('end', function() { + // The server has finished sending + }); + call.on('status', function(status) { + // process status + }); +``` + +Instead of passing the method a request and callback, we pass it a request and get a `Readable` stream object back. The client can use the `Readable`'s `'data'` event to read the server's responses. This event fires with each `Feature` message object until there are no more messages: the `'end'` event indicates that the call is done. Finally, the status event fires when the server sends the status. + +The client-side streaming method `RecordRoute` is similar, except there we pass the method a callback and get back a `Writable`. + +```node + var call = client.recordRoute(function(error, stats) { + if (error) { + callback(error); + } + console.log('Finished trip with', stats.point_count, 'points'); + console.log('Passed', stats.feature_count, 'features'); + console.log('Travelled', stats.distance, 'meters'); + console.log('It took', stats.elapsed_time, 'seconds'); + }); + function pointSender(lat, lng) { + return function(callback) { + console.log('Visiting point ' + lat/COORD_FACTOR + ', ' + + lng/COORD_FACTOR); + call.write({ + latitude: lat, + longitude: lng + }); + _.delay(callback, _.random(500, 1500)); + }; + } + var point_senders = []; + for (var i = 0; i < num_points; i++) { + var rand_point = feature_list[_.random(0, feature_list.length - 1)]; + point_senders[i] = pointSender(rand_point.location.latitude, + rand_point.location.longitude); + } + async.series(point_senders, function() { + call.end(); + }); +``` + +Once we've finished writing our client's requests to the stream using `write()`, we need to call `end()` on the stream to let gRPC know that we've finished writing. If the status is `OK`, the `stats` object will be populated with the server's response. + +Finally, let's look at our bidirectional streaming RPC `routeChat()`. In this case, we just pass a context to the method and get back a `Duplex` stream object, which we can use to both write and read messages. + +```node +var call = client.routeChat(); +``` + +The syntax for reading and writing here is exactly the same as for our client-streaming and server-streaming methods. Although each side will always get the other's messages in the order they were written, both the client and server can read and write in any order — the streams operate completely independently. + +## Try it out! + +Build client and server: +```shell +$ npm install +``` +Run the server, which will listen on port 50051: +```shell +$ node ./route_guide_server.js --db_path=route_guide_db.json +``` +Run the client (in a different terminal): +```shell +$ node ./route_guide_client.js --db_path=route_guide_db.json +``` diff --git a/examples/node/route_guide/route_guide.proto b/examples/node/route_guide/route_guide.proto new file mode 100644 index 00000000000..442112823e5 --- /dev/null +++ b/examples/node/route_guide/route_guide.proto @@ -0,0 +1,120 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "io.grpc.examples"; + +package examples; + +// Interface exported by the server. +service RouteGuide { + // A simple RPC. + // + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} + + // A server-to-client streaming RPC. + // + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} + + // A client-to-server streaming RPC. + // + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} + + // A Bidirectional streaming RPC. + // + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +} + +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + optional int32 latitude = 1; + optional int32 longitude = 2; +} + +// A latitude-longitude rectangle, represented as two diagonally opposite +// points "lo" and "hi". +message Rectangle { + // One corner of the rectangle. + optional Point lo = 1; + + // The other corner of the rectangle. + optional Point hi = 2; +} + +// A feature names something at a given point. +// +// If a feature could not be named, the name is empty. +message Feature { + // The name of the feature. + optional string name = 1; + + // The point where the feature is detected. + optional Point location = 2; +} + +// A RouteNote is a message sent while at a given point. +message RouteNote { + // The location from which the message is sent. + optional Point location = 1; + + // The message to be sent. + optional string message = 2; +} + +// A RouteSummary is received in response to a RecordRoute rpc. +// +// It contains the number of individual points received, the number of +// detected features, and the total distance covered as the cumulative sum of +// the distance between each point. +message RouteSummary { + // The number of points received. + optional int32 point_count = 1; + + // The number of known features passed while traversing the route. + optional int32 feature_count = 2; + + // The distance covered in metres. + optional int32 distance = 3; + + // The duration of the traversal in seconds. + optional int32 elapsed_time = 4; +} diff --git a/examples/node/route_guide/route_guide_client.js b/examples/node/route_guide/route_guide_client.js new file mode 100644 index 00000000000..60c47a429d6 --- /dev/null +++ b/examples/node/route_guide/route_guide_client.js @@ -0,0 +1,231 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +var async = require('async'); +var fs = require('fs'); +var parseArgs = require('minimist'); +var path = require('path'); +var _ = require('underscore'); +var grpc = require('grpc'); +var examples = grpc.load(__dirname + '/route_guide.proto').examples; +var client = new examples.RouteGuide('localhost:50051'); + +var COORD_FACTOR = 1e7; + +/** + * Run the getFeature demo. Calls getFeature with a point known to have a + * feature and a point known not to have a feature. + * @param {function} callback Called when this demo is complete + */ +function runGetFeature(callback) { + var next = _.after(2, callback); + function featureCallback(error, feature) { + if (error) { + callback(error); + } + if (feature.name === '') { + console.log('Found no feature at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + } else { + console.log('Found feature called "' + feature.name + '" at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + } + next(); + } + var point1 = { + latitude: 409146138, + longitude: -746188906 + }; + var point2 = { + latitude: 0, + longitude: 0 + }; + client.getFeature(point1, featureCallback); + client.getFeature(point2, featureCallback); +} + +/** + * Run the listFeatures demo. Calls listFeatures with a rectangle containing all + * of the features in the pre-generated database. Prints each response as it + * comes in. + * @param {function} callback Called when this demo is complete + */ +function runListFeatures(callback) { + var rectangle = { + lo: { + latitude: 400000000, + longitude: -750000000 + }, + hi: { + latitude: 420000000, + longitude: -730000000 + } + }; + console.log('Looking for features between 40, -75 and 42, -73'); + var call = client.listFeatures(rectangle); + call.on('data', function(feature) { + console.log('Found feature called "' + feature.name + '" at ' + + feature.location.latitude/COORD_FACTOR + ', ' + + feature.location.longitude/COORD_FACTOR); + }); + call.on('end', callback); +} + +/** + * Run the recordRoute demo. Sends several randomly chosen points from the + * pre-generated feature database with a variable delay in between. Prints the + * statistics when they are sent from the server. + * @param {function} callback Called when this demo is complete + */ +function runRecordRoute(callback) { + var argv = parseArgs(process.argv, { + string: 'db_path' + }); + fs.readFile(path.resolve(argv.db_path), function(err, data) { + if (err) callback(err); + var feature_list = JSON.parse(data); + + var num_points = 10; + var call = client.recordRoute(function(error, stats) { + if (error) { + callback(error); + } + console.log('Finished trip with', stats.point_count, 'points'); + console.log('Passed', stats.feature_count, 'features'); + console.log('Travelled', stats.distance, 'meters'); + console.log('It took', stats.elapsed_time, 'seconds'); + callback(); + }); + /** + * Constructs a function that asynchronously sends the given point and then + * delays sending its callback + * @param {number} lat The latitude to send + * @param {number} lng The longitude to send + * @return {function(function)} The function that sends the point + */ + function pointSender(lat, lng) { + /** + * Sends the point, then calls the callback after a delay + * @param {function} callback Called when complete + */ + return function(callback) { + console.log('Visiting point ' + lat/COORD_FACTOR + ', ' + + lng/COORD_FACTOR); + call.write({ + latitude: lat, + longitude: lng + }); + _.delay(callback, _.random(500, 1500)); + }; + } + var point_senders = []; + for (var i = 0; i < num_points; i++) { + var rand_point = feature_list[_.random(0, feature_list.length - 1)]; + point_senders[i] = pointSender(rand_point.location.latitude, + rand_point.location.longitude); + } + async.series(point_senders, function() { + call.end(); + }); + }); +} + +/** + * Run the routeChat demo. Send some chat messages, and print any chat messages + * that are sent from the server. + * @param {function} callback Called when the demo is complete + */ +function runRouteChat(callback) { + var call = client.routeChat(); + call.on('data', function(note) { + console.log('Got message "' + note.message + '" at ' + + note.location.latitude + ', ' + note.location.longitude); + }); + + call.on('end', callback); + + var notes = [{ + location: { + latitude: 0, + longitude: 0 + }, + message: 'First message' + }, { + location: { + latitude: 0, + longitude: 1 + }, + message: 'Second message' + }, { + location: { + latitude: 1, + longitude: 0 + }, + message: 'Third message' + }, { + location: { + latitude: 0, + longitude: 0 + }, + message: 'Fourth message' + }]; + for (var i = 0; i < notes.length; i++) { + var note = notes[i]; + console.log('Sending message "' + note.message + '" at ' + + note.location.latitude + ', ' + note.location.longitude); + call.write(note); + } + call.end(); +} + +/** + * Run all of the demos in order + */ +function main() { + async.series([ + runGetFeature, + runListFeatures, + runRecordRoute, + runRouteChat + ]); +} + +if (require.main === module) { + main(); +} + +exports.runGetFeature = runGetFeature; + +exports.runListFeatures = runListFeatures; + +exports.runRecordRoute = runRecordRoute; + +exports.runRouteChat = runRouteChat; diff --git a/examples/node/route_guide/route_guide_db.json b/examples/node/route_guide/route_guide_db.json new file mode 100644 index 00000000000..9d6a980ab7d --- /dev/null +++ b/examples/node/route_guide/route_guide_db.json @@ -0,0 +1,601 @@ +[{ + "location": { + "latitude": 407838351, + "longitude": -746143763 + }, + "name": "Patriots Path, Mendham, NJ 07945, USA" +}, { + "location": { + "latitude": 408122808, + "longitude": -743999179 + }, + "name": "101 New Jersey 10, Whippany, NJ 07981, USA" +}, { + "location": { + "latitude": 413628156, + "longitude": -749015468 + }, + "name": "U.S. 6, Shohola, PA 18458, USA" +}, { + "location": { + "latitude": 419999544, + "longitude": -740371136 + }, + "name": "5 Conners Road, Kingston, NY 12401, USA" +}, { + "location": { + "latitude": 414008389, + "longitude": -743951297 + }, + "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" +}, { + "location": { + "latitude": 419611318, + "longitude": -746524769 + }, + "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" +}, { + "location": { + "latitude": 406109563, + "longitude": -742186778 + }, + "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" +}, { + "location": { + "latitude": 416802456, + "longitude": -742370183 + }, + "name": "352 South Mountain Road, Wallkill, NY 12589, USA" +}, { + "location": { + "latitude": 412950425, + "longitude": -741077389 + }, + "name": "Bailey Turn Road, Harriman, NY 10926, USA" +}, { + "location": { + "latitude": 412144655, + "longitude": -743949739 + }, + "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" +}, { + "location": { + "latitude": 415736605, + "longitude": -742847522 + }, + "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" +}, { + "location": { + "latitude": 413843930, + "longitude": -740501726 + }, + "name": "162 Merrill Road, Highland Mills, NY 10930, USA" +}, { + "location": { + "latitude": 410873075, + "longitude": -744459023 + }, + "name": "Clinton Road, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 412346009, + "longitude": -744026814 + }, + "name": "16 Old Brook Lane, Warwick, NY 10990, USA" +}, { + "location": { + "latitude": 402948455, + "longitude": -747903913 + }, + "name": "3 Drake Lane, Pennington, NJ 08534, USA" +}, { + "location": { + "latitude": 406337092, + "longitude": -740122226 + }, + "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" +}, { + "location": { + "latitude": 406421967, + "longitude": -747727624 + }, + "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" +}, { + "location": { + "latitude": 416318082, + "longitude": -749677716 + }, + "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" +}, { + "location": { + "latitude": 415301720, + "longitude": -748416257 + }, + "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" +}, { + "location": { + "latitude": 402647019, + "longitude": -747071791 + }, + "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" +}, { + "location": { + "latitude": 412567807, + "longitude": -741058078 + }, + "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" +}, { + "location": { + "latitude": 416855156, + "longitude": -744420597 + }, + "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" +}, { + "location": { + "latitude": 404663628, + "longitude": -744820157 + }, + "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" +}, { + "location": { + "latitude": 407113723, + "longitude": -749746483 + }, + "name": "" +}, { + "location": { + "latitude": 402133926, + "longitude": -743613249 + }, + "name": "" +}, { + "location": { + "latitude": 400273442, + "longitude": -741220915 + }, + "name": "" +}, { + "location": { + "latitude": 411236786, + "longitude": -744070769 + }, + "name": "" +}, { + "location": { + "latitude": 411633782, + "longitude": -746784970 + }, + "name": "211-225 Plains Road, Augusta, NJ 07822, USA" +}, { + "location": { + "latitude": 415830701, + "longitude": -742952812 + }, + "name": "" +}, { + "location": { + "latitude": 413447164, + "longitude": -748712898 + }, + "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" +}, { + "location": { + "latitude": 405047245, + "longitude": -749800722 + }, + "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" +}, { + "location": { + "latitude": 418858923, + "longitude": -746156790 + }, + "name": "" +}, { + "location": { + "latitude": 417951888, + "longitude": -748484944 + }, + "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" +}, { + "location": { + "latitude": 407033786, + "longitude": -743977337 + }, + "name": "26 East 3rd Street, New Providence, NJ 07974, USA" +}, { + "location": { + "latitude": 417548014, + "longitude": -740075041 + }, + "name": "" +}, { + "location": { + "latitude": 410395868, + "longitude": -744972325 + }, + "name": "" +}, { + "location": { + "latitude": 404615353, + "longitude": -745129803 + }, + "name": "" +}, { + "location": { + "latitude": 406589790, + "longitude": -743560121 + }, + "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" +}, { + "location": { + "latitude": 414653148, + "longitude": -740477477 + }, + "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" +}, { + "location": { + "latitude": 405957808, + "longitude": -743255336 + }, + "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" +}, { + "location": { + "latitude": 411733589, + "longitude": -741648093 + }, + "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" +}, { + "location": { + "latitude": 412676291, + "longitude": -742606606 + }, + "name": "1270 Lakes Road, Monroe, NY 10950, USA" +}, { + "location": { + "latitude": 409224445, + "longitude": -748286738 + }, + "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" +}, { + "location": { + "latitude": 406523420, + "longitude": -742135517 + }, + "name": "652 Garden Street, Elizabeth, NJ 07202, USA" +}, { + "location": { + "latitude": 401827388, + "longitude": -740294537 + }, + "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" +}, { + "location": { + "latitude": 410564152, + "longitude": -743685054 + }, + "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 408472324, + "longitude": -740726046 + }, + "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" +}, { + "location": { + "latitude": 412452168, + "longitude": -740214052 + }, + "name": "5 White Oak Lane, Stony Point, NY 10980, USA" +}, { + "location": { + "latitude": 409146138, + "longitude": -746188906 + }, + "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" +}, { + "location": { + "latitude": 404701380, + "longitude": -744781745 + }, + "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 409642566, + "longitude": -746017679 + }, + "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" +}, { + "location": { + "latitude": 408031728, + "longitude": -748645385 + }, + "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" +}, { + "location": { + "latitude": 413700272, + "longitude": -742135189 + }, + "name": "367 Prospect Road, Chester, NY 10918, USA" +}, { + "location": { + "latitude": 404310607, + "longitude": -740282632 + }, + "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" +}, { + "location": { + "latitude": 409319800, + "longitude": -746201391 + }, + "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" +}, { + "location": { + "latitude": 406685311, + "longitude": -742108603 + }, + "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" +}, { + "location": { + "latitude": 419018117, + "longitude": -749142781 + }, + "name": "43 Dreher Road, Roscoe, NY 12776, USA" +}, { + "location": { + "latitude": 412856162, + "longitude": -745148837 + }, + "name": "Swan Street, Pine Island, NY 10969, USA" +}, { + "location": { + "latitude": 416560744, + "longitude": -746721964 + }, + "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" +}, { + "location": { + "latitude": 405314270, + "longitude": -749836354 + }, + "name": "" +}, { + "location": { + "latitude": 414219548, + "longitude": -743327440 + }, + "name": "" +}, { + "location": { + "latitude": 415534177, + "longitude": -742900616 + }, + "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" +}, { + "location": { + "latitude": 406898530, + "longitude": -749127080 + }, + "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" +}, { + "location": { + "latitude": 407586880, + "longitude": -741670168 + }, + "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" +}, { + "location": { + "latitude": 400106455, + "longitude": -742870190 + }, + "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" +}, { + "location": { + "latitude": 400066188, + "longitude": -746793294 + }, + "name": "" +}, { + "location": { + "latitude": 418803880, + "longitude": -744102673 + }, + "name": "40 Mountain Road, Napanoch, NY 12458, USA" +}, { + "location": { + "latitude": 414204288, + "longitude": -747895140 + }, + "name": "" +}, { + "location": { + "latitude": 414777405, + "longitude": -740615601 + }, + "name": "" +}, { + "location": { + "latitude": 415464475, + "longitude": -747175374 + }, + "name": "48 North Road, Forestburgh, NY 12777, USA" +}, { + "location": { + "latitude": 404062378, + "longitude": -746376177 + }, + "name": "" +}, { + "location": { + "latitude": 405688272, + "longitude": -749285130 + }, + "name": "" +}, { + "location": { + "latitude": 400342070, + "longitude": -748788996 + }, + "name": "" +}, { + "location": { + "latitude": 401809022, + "longitude": -744157964 + }, + "name": "" +}, { + "location": { + "latitude": 404226644, + "longitude": -740517141 + }, + "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" +}, { + "location": { + "latitude": 410322033, + "longitude": -747871659 + }, + "name": "" +}, { + "location": { + "latitude": 407100674, + "longitude": -747742727 + }, + "name": "" +}, { + "location": { + "latitude": 418811433, + "longitude": -741718005 + }, + "name": "213 Bush Road, Stone Ridge, NY 12484, USA" +}, { + "location": { + "latitude": 415034302, + "longitude": -743850945 + }, + "name": "" +}, { + "location": { + "latitude": 411349992, + "longitude": -743694161 + }, + "name": "" +}, { + "location": { + "latitude": 404839914, + "longitude": -744759616 + }, + "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 414638017, + "longitude": -745957854 + }, + "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" +}, { + "location": { + "latitude": 412127800, + "longitude": -740173578 + }, + "name": "" +}, { + "location": { + "latitude": 401263460, + "longitude": -747964303 + }, + "name": "" +}, { + "location": { + "latitude": 412843391, + "longitude": -749086026 + }, + "name": "" +}, { + "location": { + "latitude": 418512773, + "longitude": -743067823 + }, + "name": "" +}, { + "location": { + "latitude": 404318328, + "longitude": -740835638 + }, + "name": "42-102 Main Street, Belford, NJ 07718, USA" +}, { + "location": { + "latitude": 419020746, + "longitude": -741172328 + }, + "name": "" +}, { + "location": { + "latitude": 404080723, + "longitude": -746119569 + }, + "name": "" +}, { + "location": { + "latitude": 401012643, + "longitude": -744035134 + }, + "name": "" +}, { + "location": { + "latitude": 404306372, + "longitude": -741079661 + }, + "name": "" +}, { + "location": { + "latitude": 403966326, + "longitude": -748519297 + }, + "name": "" +}, { + "location": { + "latitude": 405002031, + "longitude": -748407866 + }, + "name": "" +}, { + "location": { + "latitude": 409532885, + "longitude": -742200683 + }, + "name": "" +}, { + "location": { + "latitude": 416851321, + "longitude": -742674555 + }, + "name": "" +}, { + "location": { + "latitude": 406411633, + "longitude": -741722051 + }, + "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" +}, { + "location": { + "latitude": 413069058, + "longitude": -744597778 + }, + "name": "261 Van Sickle Road, Goshen, NY 10924, USA" +}, { + "location": { + "latitude": 418465462, + "longitude": -746859398 + }, + "name": "" +}, { + "location": { + "latitude": 411733222, + "longitude": -744228360 + }, + "name": "" +}, { + "location": { + "latitude": 410248224, + "longitude": -747127767 + }, + "name": "3 Hasta Way, Newton, NJ 07860, USA" +}] diff --git a/examples/node/route_guide/route_guide_server.js b/examples/node/route_guide/route_guide_server.js new file mode 100644 index 00000000000..5dd84126543 --- /dev/null +++ b/examples/node/route_guide/route_guide_server.js @@ -0,0 +1,249 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +var fs = require('fs'); +var parseArgs = require('minimist'); +var path = require('path'); +var _ = require('underscore'); +var grpc = require('grpc'); +var examples = grpc.load(__dirname + '/route_guide.proto').examples; + +var Server = grpc.buildServer([examples.RouteGuide.service]); + +var COORD_FACTOR = 1e7; + +/** + * For simplicity, a point is a record type that looks like + * {latitude: number, longitude: number}, and a feature is a record type that + * looks like {name: string, location: point}. feature objects with name==='' + * are points with no feature. + */ + +/** + * List of feature objects at points that have been requested so far. + */ +var feature_list = []; + +/** + * Get a feature object at the given point, or creates one if it does not exist. + * @param {point} point The point to check + * @return {feature} The feature object at the point. Note that an empty name + * indicates no feature + */ +function checkFeature(point) { + var feature; + // Check if there is already a feature object for the given point + for (var i = 0; i < feature_list.length; i++) { + feature = feature_list[i]; + if (feature.location.latitude === point.latitude && + feature.location.longitude === point.longitude) { + return feature; + } + } + var name = ''; + feature = { + name: name, + location: point + }; + return feature; +} + +/** + * getFeature request handler. Gets a request with a point, and responds with a + * feature object indicating whether there is a feature at that point. + * @param {EventEmitter} call Call object for the handler to process + * @param {function(Error, feature)} callback Response callback + */ +function getFeature(call, callback) { + callback(null, checkFeature(call.request)); +} + +/** + * listFeatures request handler. Gets a request with two points, and responds + * with a stream of all features in the bounding box defined by those points. + * @param {Writable} call Writable stream for responses with an additional + * request property for the request value. + */ +function listFeatures(call) { + var lo = call.request.lo; + var hi = call.request.hi; + var left = _.min([lo.longitude, hi.longitude]); + var right = _.max([lo.longitude, hi.longitude]); + var top = _.max([lo.latitude, hi.latitude]); + var bottom = _.min([lo.latitude, hi.latitude]); + // For each feature, check if it is in the given bounding box + _.each(feature_list, function(feature) { + if (feature.name === '') { + return; + } + if (feature.location.longitude >= left && + feature.location.longitude <= right && + feature.location.latitude >= bottom && + feature.location.latitude <= top) { + call.write(feature); + } + }); + call.end(); +} + +/** + * Calculate the distance between two points using the "haversine" formula. + * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. + * @param start The starting point + * @param end The end point + * @return The distance between the points in meters + */ +function getDistance(start, end) { + function toRadians(num) { + return num * Math.PI / 180; + } + var lat1 = start.latitude / COORD_FACTOR; + var lat2 = end.latitude / COORD_FACTOR; + var lon1 = start.longitude / COORD_FACTOR; + var lon2 = end.longitude / COORD_FACTOR; + var R = 6371000; // metres + var φ1 = toRadians(lat1); + var φ2 = toRadians(lat2); + var Δφ = toRadians(lat2-lat1); + var Δλ = toRadians(lon2-lon1); + + var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + + Math.cos(φ1) * Math.cos(φ2) * + Math.sin(Δλ/2) * Math.sin(Δλ/2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + + return R * c; +} + +/** + * recordRoute handler. Gets a stream of points, and responds with statistics + * about the "trip": number of points, number of known features visited, total + * distance traveled, and total time spent. + * @param {Readable} call The request point stream. + * @param {function(Error, routeSummary)} callback The callback to pass the + * response to + */ +function recordRoute(call, callback) { + var point_count = 0; + var feature_count = 0; + var distance = 0; + var previous = null; + // Start a timer + var start_time = process.hrtime(); + call.on('data', function(point) { + point_count += 1; + if (checkFeature(point).name !== '') { + feature_count += 1; + } + /* For each point after the first, add the incremental distance from the + * previous point to the total distance value */ + if (previous != null) { + distance += getDistance(previous, point); + } + previous = point; + }); + call.on('end', function() { + callback(null, { + point_count: point_count, + feature_count: feature_count, + // Cast the distance to an integer + distance: distance|0, + // End the timer + elapsed_time: process.hrtime(start_time)[0] + }); + }); +} + +var route_notes = {}; + +/** + * Turn the point into a dictionary key. + * @param {point} point The point to use + * @return {string} The key for an object + */ +function pointKey(point) { + return point.latitude + ' ' + point.longitude; +} + +/** + * routeChat handler. Receives a stream of message/location pairs, and responds + * with a stream of all previous messages at each of those locations. + * @param {Duplex} call The stream for incoming and outgoing messages + */ +function routeChat(call) { + call.on('data', function(note) { + var key = pointKey(note.location); + /* For each note sent, respond with all previous notes that correspond to + * the same point */ + if (route_notes.hasOwnProperty(key)) { + _.each(route_notes[key], function(note) { + call.write(note); + }); + } else { + route_notes[key] = []; + } + // Then add the new note to the list + route_notes[key].push(JSON.parse(JSON.stringify(note))); + }); + call.on('end', function() { + call.end(); + }); +} + +/** + * Get a new server with the handler functions in this file bound to the methods + * it serves. + * @return {Server} The new server object + */ +function getServer() { + return new Server({ + 'examples.RouteGuide' : { + getFeature: getFeature, + listFeatures: listFeatures, + recordRoute: recordRoute, + routeChat: routeChat + } + }); +} + +if (require.main === module) { + // If this is run as a script, start a server on an unused port + var routeServer = getServer(); + routeServer.bind('0.0.0.0:50051'); + var argv = parseArgs(process.argv, { + string: 'db_path' + }); + fs.readFile(path.resolve(argv.db_path), function(err, data) { + if (err) throw err; + feature_list = JSON.parse(data); + routeServer.listen(); + }); +} + +exports.getServer = getServer; diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj new file mode 100644 index 00000000000..51a39c578c7 --- /dev/null +++ b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.pbxproj @@ -0,0 +1,366 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 63E1E9821B28CB2100EF0978 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9811B28CB2100EF0978 /* main.m */; }; + 63E1E9851B28CB2100EF0978 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9841B28CB2100EF0978 /* AppDelegate.m */; }; + 63E1E9881B28CB2100EF0978 /* SelectUserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */; }; + 63E1E98B1B28CB2100EF0978 /* MakeRPCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */; }; + 63E1E98E1B28CB2100EF0978 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 63E1E98C1B28CB2100EF0978 /* Main.storyboard */; }; + 63E1E9901B28CB2100EF0978 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 63E1E98F1B28CB2100EF0978 /* Images.xcassets */; }; + 63F5DE481B28F5C100CDD07E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */; }; + 832213142AB24DB816D02635 /* libPods-AuthSample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 63E1E97C1B28CB2100EF0978 /* AuthSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AuthSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 63E1E9801B28CB2100EF0978 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 63E1E9811B28CB2100EF0978 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 63E1E9831B28CB2100EF0978 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 63E1E9841B28CB2100EF0978 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 63E1E9861B28CB2100EF0978 /* SelectUserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SelectUserViewController.h; sourceTree = ""; }; + 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SelectUserViewController.m; sourceTree = ""; }; + 63E1E9891B28CB2100EF0978 /* MakeRPCViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MakeRPCViewController.h; sourceTree = ""; }; + 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MakeRPCViewController.m; sourceTree = ""; }; + 63E1E98D1B28CB2100EF0978 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 63E1E98F1B28CB2100EF0978 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; + A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AuthSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample.debug.xcconfig"; sourceTree = ""; }; + B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AuthSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample.release.xcconfig"; sourceTree = ""; }; + F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AuthSample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 63E1E9791B28CB2000EF0978 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 832213142AB24DB816D02635 /* libPods-AuthSample.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 021FA0E0B3F5D3D477DDAC10 /* Pods */ = { + isa = PBXGroup; + children = ( + A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */, + B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 4F443572636F3D60F26E870D /* Frameworks */ = { + isa = PBXGroup; + children = ( + F217A6ECA7F5BD1D5FB5071B /* libPods-AuthSample.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 63E1E9731B28CB2000EF0978 = { + isa = PBXGroup; + children = ( + 63E1E97E1B28CB2100EF0978 /* AuthSample */, + 63E1E97D1B28CB2100EF0978 /* Products */, + 021FA0E0B3F5D3D477DDAC10 /* Pods */, + 4F443572636F3D60F26E870D /* Frameworks */, + ); + sourceTree = ""; + }; + 63E1E97D1B28CB2100EF0978 /* Products */ = { + isa = PBXGroup; + children = ( + 63E1E97C1B28CB2100EF0978 /* AuthSample.app */, + ); + name = Products; + sourceTree = ""; + }; + 63E1E97E1B28CB2100EF0978 /* AuthSample */ = { + isa = PBXGroup; + children = ( + 63E1E9861B28CB2100EF0978 /* SelectUserViewController.h */, + 63E1E9871B28CB2100EF0978 /* SelectUserViewController.m */, + 63E1E9891B28CB2100EF0978 /* MakeRPCViewController.h */, + 63E1E98A1B28CB2100EF0978 /* MakeRPCViewController.m */, + 63E1E97F1B28CB2100EF0978 /* Supporting Files */, + ); + name = AuthSample; + sourceTree = SOURCE_ROOT; + }; + 63E1E97F1B28CB2100EF0978 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 63E1E98C1B28CB2100EF0978 /* Main.storyboard */, + 63F5DE471B28F5C100CDD07E /* GoogleService-Info.plist */, + 63E1E98F1B28CB2100EF0978 /* Images.xcassets */, + 63E1E9801B28CB2100EF0978 /* Info.plist */, + 63E1E9831B28CB2100EF0978 /* AppDelegate.h */, + 63E1E9841B28CB2100EF0978 /* AppDelegate.m */, + 63E1E9811B28CB2100EF0978 /* main.m */, + ); + name = "Supporting Files"; + path = Misc; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 63E1E97B1B28CB2000EF0978 /* AuthSample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 63E1E9A21B28CB2100EF0978 /* Build configuration list for PBXNativeTarget "AuthSample" */; + buildPhases = ( + DAABBA7B5788A39108D7CA83 /* Check Pods Manifest.lock */, + 63E1E9781B28CB2000EF0978 /* Sources */, + 63E1E9791B28CB2000EF0978 /* Frameworks */, + 63E1E97A1B28CB2000EF0978 /* Resources */, + AEFCCC69DD59CE8F6EB769D7 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = AuthSample; + productName = AuthSample; + productReference = 63E1E97C1B28CB2100EF0978 /* AuthSample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 63E1E9741B28CB2000EF0978 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = gRPC; + TargetAttributes = { + 63E1E97B1B28CB2000EF0978 = { + CreatedOnToolsVersion = 6.3.1; + }; + }; + }; + buildConfigurationList = 63E1E9771B28CB2000EF0978 /* Build configuration list for PBXProject "AuthSample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 63E1E9731B28CB2000EF0978; + productRefGroup = 63E1E97D1B28CB2100EF0978 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 63E1E97B1B28CB2000EF0978 /* AuthSample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 63E1E97A1B28CB2000EF0978 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 63E1E98E1B28CB2100EF0978 /* Main.storyboard in Resources */, + 63E1E9901B28CB2100EF0978 /* Images.xcassets in Resources */, + 63F5DE481B28F5C100CDD07E /* GoogleService-Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + AEFCCC69DD59CE8F6EB769D7 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-AuthSample/Pods-AuthSample-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + DAABBA7B5788A39108D7CA83 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 63E1E9781B28CB2000EF0978 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 63E1E98B1B28CB2100EF0978 /* MakeRPCViewController.m in Sources */, + 63E1E9851B28CB2100EF0978 /* AppDelegate.m in Sources */, + 63E1E9881B28CB2100EF0978 /* SelectUserViewController.m in Sources */, + 63E1E9821B28CB2100EF0978 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 63E1E98C1B28CB2100EF0978 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 63E1E98D1B28CB2100EF0978 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 63E1E9A01B28CB2100EF0978 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 63E1E9A11B28CB2100EF0978 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 63E1E9A31B28CB2100EF0978 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = A387D6CECBCF2EAF2983033A /* Pods-AuthSample.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Misc/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 63E1E9A41B28CB2100EF0978 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = B444176735DA81FBE4B8B80C /* Pods-AuthSample.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Misc/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 63E1E9771B28CB2000EF0978 /* Build configuration list for PBXProject "AuthSample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 63E1E9A01B28CB2100EF0978 /* Debug */, + 63E1E9A11B28CB2100EF0978 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 63E1E9A21B28CB2100EF0978 /* Build configuration list for PBXNativeTarget "AuthSample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 63E1E9A31B28CB2100EF0978 /* Debug */, + 63E1E9A41B28CB2100EF0978 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 63E1E9741B28CB2000EF0978 /* Project object */; +} diff --git a/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000000..39b57a4b332 --- /dev/null +++ b/examples/objective-c/auth_sample/AuthSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/objective-c/auth_sample/AuthTestService.podspec b/examples/objective-c/auth_sample/AuthTestService.podspec new file mode 100644 index 00000000000..9f2a2cc361b --- /dev/null +++ b/examples/objective-c/auth_sample/AuthTestService.podspec @@ -0,0 +1,35 @@ +Pod::Spec.new do |s| + s.name = "AuthTestService" + s.version = "0.0.1" + s.license = "New BSD" + + s.ios.deployment_target = "6.0" + s.osx.deployment_target = "10.8" + + # Base directory where the .proto files are. + src = "../../protos" + + # Directory where the generated files will be place. + dir = "Pods/" + s.name + + # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. + s.prepare_command = <<-CMD + mkdir -p #{dir} + protoc -I #{src} --objc_out=#{dir} --objcgrpc_out=#{dir} #{src}/auth_sample.proto + CMD + + s.subspec "Messages" do |ms| + ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}" + ms.header_mappings_dir = dir + ms.requires_arc = false + ms.dependency "Protobuf", "~> 3.0.0-alpha-3" + end + + s.subspec "Services" do |ss| + ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}" + ss.header_mappings_dir = dir + ss.requires_arc = true + ss.dependency "gRPC", "~> 0.6" + ss.dependency "#{s.name}/Messages" + end +end diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.h b/examples/objective-c/auth_sample/MakeRPCViewController.h new file mode 100644 index 00000000000..c75a8b3180f --- /dev/null +++ b/examples/objective-c/auth_sample/MakeRPCViewController.h @@ -0,0 +1,40 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + +extern NSString * const kTestScope; + +@interface MakeRPCViewController : UIViewController +@property(weak, nonatomic) IBOutlet UILabel *mainLabel; +@end diff --git a/examples/objective-c/auth_sample/MakeRPCViewController.m b/examples/objective-c/auth_sample/MakeRPCViewController.m new file mode 100644 index 00000000000..366bc9deea9 --- /dev/null +++ b/examples/objective-c/auth_sample/MakeRPCViewController.m @@ -0,0 +1,100 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "MakeRPCViewController.h" + +#import +#import +#include +#import + +NSString * const kTestScope = @"https://www.googleapis.com/auth/xapi.zoo"; + +static NSString * const kTestHostAddress = @"grpc-test.sandbox.google.com"; + +// Category for RPC errors to create the descriptions as we want them to appear on our view. +@interface NSError (AuthSample) +- (NSString *)UIDescription; +@end + +@implementation NSError (AuthSample) +- (NSString *)UIDescription { + if (self.code == GRPC_STATUS_UNAUTHENTICATED) { + // Authentication error. OAuth2 specifies we'll receive a challenge header. + // |userInfo[kGRPCStatusMetadataKey]| is the dictionary of response metadata. + NSString *challengeHeader = self.userInfo[kGRPCStatusMetadataKey][@"www-authenticate"] ?: @""; + return [@"Invalid credentials. Server challenge:\n" stringByAppendingString:challengeHeader]; + } else { + // Any other error. + return [NSString stringWithFormat:@"Unexpected RPC error %li: %@", + (long)self.code, self.localizedDescription]; + } +} +@end + +@implementation MakeRPCViewController + +- (void)viewWillAppear:(BOOL)animated { + + // Create a service client and a proto request as usual. + AUTHTestService *client = [[AUTHTestService alloc] initWithHost:kTestHostAddress]; + + AUTHRequest *request = [AUTHRequest message]; + request.fillUsername = YES; + request.fillOauthScope = YES; + + // Create a not-yet-started RPC. We want to set the request headers on this object before starting + // it. + ProtoRPC *call = + [client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) { + if (response) { + // This test server responds with the email and scope of the access token it receives. + self.mainLabel.text = [NSString stringWithFormat:@"Used scope: %@ on behalf of user %@", + response.oauthScope, response.username]; + + } else { + self.mainLabel.text = error.UIDescription; + } + }]; + + // Set the access token to be used. + NSString *accessToken = GIDSignIn.sharedInstance.currentUser.authentication.accessToken; + call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]; + + // Start the RPC. + [call start]; + + self.mainLabel.text = @"Waiting for RPC to complete..."; +} + +@end diff --git a/examples/objective-c/auth_sample/Misc/AppDelegate.h b/examples/objective-c/auth_sample/Misc/AppDelegate.h new file mode 100644 index 00000000000..102e7f3adea --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/AppDelegate.h @@ -0,0 +1,38 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end diff --git a/examples/objective-c/auth_sample/Misc/AppDelegate.m b/examples/objective-c/auth_sample/Misc/AppDelegate.m new file mode 100644 index 00000000000..798d342938b --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/AppDelegate.m @@ -0,0 +1,61 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "AppDelegate.h" + +#import + +@implementation AppDelegate + +// As instructed in https://developers.google.com/identity/sign-in/ios/sign-in +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + NSError* configureError; + [GGLContext.sharedInstance configureWithError: &configureError]; + NSAssert(!configureError, @"Error configuring Google services: %@", configureError); + + return YES; +} + +// As instructed in https://developers.google.com/identity/sign-in/ios/sign-in +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation { + // This will properly handle the URL that the application receives at the end of the + // authentication process. + return [GIDSignIn.sharedInstance handleURL:url + sourceApplication:sourceApplication + annotation:annotation]; +} + +@end diff --git a/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard b/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard new file mode 100644 index 00000000000..fb29c124e28 --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/Base.lproj/Main.storyboard @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist new file mode 100644 index 00000000000..86909d84a31 --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/GoogleService-Info.plist @@ -0,0 +1,10 @@ + + + + + CLIENT_ID + 15087385131-lh9bpkiai9nls53uadju0if6k7un3uih.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih + + \ No newline at end of file diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..36d2c80d889 --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json new file mode 100644 index 00000000000..33a745102c8 --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "first.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf new file mode 100644 index 00000000000..47d911dea64 Binary files /dev/null and b/examples/objective-c/auth_sample/Misc/Images.xcassets/first.imageset/first.pdf differ diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json new file mode 100644 index 00000000000..03bd9c927f4 --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "second.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf new file mode 100644 index 00000000000..401614e288b Binary files /dev/null and b/examples/objective-c/auth_sample/Misc/Images.xcassets/second.imageset/second.pdf differ diff --git a/examples/objective-c/auth_sample/Misc/Info.plist b/examples/objective-c/auth_sample/Misc/Info.plist new file mode 100644 index 00000000000..fc292507c7d --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/Info.plist @@ -0,0 +1,80 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + io.grpc.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + REVERSED_CLIENT_ID + CFBundleURLSchemes + + com.googleusercontent.apps.15087385131-lh9bpkiai9nls53uadju0if6k7un3uih + + + + CFBundleTypeRole + Editor + CFBundleURLName + BUNDLE_ID + CFBundleURLSchemes + + io.grpc.AuthSample + + + + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + Main + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/examples/objective-c/auth_sample/Misc/main.m b/examples/objective-c/auth_sample/Misc/main.m new file mode 100644 index 00000000000..81e9d44e542 --- /dev/null +++ b/examples/objective-c/auth_sample/Misc/main.m @@ -0,0 +1,41 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/examples/objective-c/auth_sample/Podfile b/examples/objective-c/auth_sample/Podfile new file mode 100644 index 00000000000..dd4fd558c0e --- /dev/null +++ b/examples/objective-c/auth_sample/Podfile @@ -0,0 +1,10 @@ +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '8.0' + +target 'AuthSample' do + # Depend on the generated AuthTestService library. + pod 'AuthTestService', :path => '.' + + # Depend on Google's OAuth2 library + pod 'Google/SignIn' +end diff --git a/examples/objective-c/auth_sample/README.md b/examples/objective-c/auth_sample/README.md new file mode 100644 index 00000000000..3dbe7e334cc --- /dev/null +++ b/examples/objective-c/auth_sample/README.md @@ -0,0 +1,189 @@ +#OAuth2 on gRPC: Objective-C + +This example application demostrates how to use OAuth2 on gRPC to make authenticated API calls on +behalf of a user. By walking through it you'll learn how to use the Objective-C gRPC API to: + +- Initialize and configure a remote call object before the RPC is started. +- Set request metadata elements on a call, which are semantically equivalent to HTTP request +headers. +- Read response metadata from a call, which is equivalent to HTTP response headers and trailers. + +It assumes you know the basics on how to make gRPC API calls using the Objective-C client library, +as shown in the [Hello World](examples/objective-c/helloworld) +or [Route Guide](examples/objective-c/route_guide) tutorials, +and are familiar with OAuth2 concepts like _access token_. + +- [Example code and setup](#setup) +- [Try it out!](#try) +- [Create an RPC object and start it later](#rpc-object) +- [Set request metadata of a call: Authorization header with an access token](#request-metadata) +- [Get response metadata of a call: Auth challenge header](#response-metadata) + + +## Example code and setup + +The example code for our tutorial is in [examples/objective-c/auth_sample](examples/objective-c/auth_sample). +To download the example, clone this repository by running the following command: +```shell +$ git clone https://github.com/grpc/grpc.git +``` + +Then change your current directory to `examples/objective-c/auth_sample`: +```shell +$ cd examples/objective-c/auth_sample +``` + +Our example is a simple application with two views. The first one lets a user sign in and out using +the OAuth2 flow of Google's [iOS SignIn library](https://developers.google.com/identity/sign-in/ios/). +(Google's library is used in this example because the test gRPC service we are going to call expects +Google account credentials, but neither gRPC nor the Objective-C client library is tied to any +specific OAuth2 provider). The second view makes a gRPC request to the test server, using the +access token obtained by the first view. + +Note: OAuth2 libraries need the application to register and obtain an ID from the identity provider +(in the case of this example app, Google). The app's XCode project is configured using that ID, so +you shouldn't copy this project "as is" for your own app: it would result in your app being +identified in the consent screen as "gRPC-AuthSample", and not having access to real Google +services. Instead, configure your own XCode project following the [instructions here](https://developers.google.com/identity/sign-in/ios/). + +As with the other examples, you also should have [Cocoapods](https://cocoapods.org/#install) +installed, as well as the relevant tools to generate the client library code. You can obtain the +latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc). + + + +## Try it out! + +To try the sample app, first have Cocoapods generate and install the client library for our .proto +files: + +```shell +$ pod install +``` + +(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet +on your computer's cache). + +Finally, open the XCode workspace created by Cocoapods, and run the app. + +The first view, `SelectUserViewController.h/m`, asks you to sign in with your Google account, and to +give the "gRPC-AuthSample" app the following permissions: + +- View your email address. +- View your basic profile info. +- "Test scope for access to the Zoo service". + +This last permission, corresponding to the scope `https://www.googleapis.com/auth/xapi.zoo` doesn't +grant any real capability: it's only used for testing. You can log out at any time. + +The second view, `MakeRPCViewController.h/m`, makes a gRPC request to a test server at +https://grpc-test.sandbox.google.com, sending the access token along with the request. The test +service simply validates the token and writes in its response which user it belongs to, and which +scopes it gives access to. (The client application already knows those two values; it's a way to +verify that everything went as expected). + +The next sections guide you step-by-step through how the gRPC call in `MakeRPCViewController` is +performed. + + +## Create an RPC object and start it later + +The other basic tutorials show how to invoke an RPC by calling an asynchronous method in a generated +client object. This shows how to initialize an object that represents the RPC, and configure it +before starting the network request. + +Assume you have a proto service definition like this: + +```protobuf +option objc_class_prefix = "AUTH"; + +service TestService { + rpc UnaryCall(Request) returns (Response); +} +``` + +A `unaryCallWithRequest:handler:` method, with which you're already familiar, is generated for the +`AUTHTestService` class: + +```objective-c +[client unaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) { + ... +}]; +``` + +In addition, an `RPCToUnaryCallWithRequest:handler:` method is generated, which returns a +not-yet-started RPC object: + +```objective-c +#import + +ProtoRPC *call = + [client RPCToUnaryCallWithRequest:request handler:^(AUTHResponse *response, NSError *error) { + ... + }]; +``` + +The RPC represented by this object can be started at any later time like this: + +```objective-c +[call start]; +``` + + +## Set request metadata of a call: Authorization header with an access token + +The `ProtoRPC` class has a `requestMetadata` property (inherited from `GRPCCall`) defined like this: + +```objective-c +- (NSMutableDictionary *)requestMetadata; // nonatomic +- (void)setRequestMetadata:(NSDictionary *)requestMetadata; // nonatomic, copy +``` + +Setting it to a dictionary of metadata keys and values will have them sent on the wire when the call +is started. gRPC metadata are pieces of information about the call sent by the client to the server +(and vice versa). They take the form of key-value pairs and are essentially opaque to gRPC itself. + +```objective-c +call.requestMetadata = @{@"My-Header": @"Value for this header", + @"Another-Header": @"Its value"}; +``` + +For convenience, the property is initialized with an empty `NSMutableDictionary`, so that request +metadata elements can be set like this: + +```objective-c +call.requestMetadata[@"My-Header"] = @"Value for this header"; +``` + +If you have an access token, OAuth2 specifies it is to be sent in this format: + +```objective-c +call.requestMetadata[@"Authorization"] = [@"Bearer " stringByAppendingString:accessToken]; +``` + + +## Get response metadata of a call: Auth challenge header + +The `ProtoRPC` class also inherits a `responseMetadata` property, analogous to the request metadata +we just looked at. It's defined like this: + +```objective-c +@property(atomic, readonly) NSDictionary *responseMetadata; +``` + +To access OAuth2's authentication challenge header you write: + +```objective-c +call.responseMetadata[@"www-authenticate"] +``` + +Note that, as gRPC metadata elements are mapped to HTTP/2 headers (or trailers), the keys of the +response metadata are always ASCII strings in lowercase. + +Many uses cases of response metadata are getting more details about an RPC error. For convenience, +when a `NSError` instance is passed to an RPC handler block, the response metadata dictionary can +also be accessed this way: + +```objective-c +error.userInfo[kGRPCStatusMetadataKey] +``` diff --git a/examples/objective-c/auth_sample/SelectUserViewController.h b/examples/objective-c/auth_sample/SelectUserViewController.h new file mode 100644 index 00000000000..eb3c2cf5f04 --- /dev/null +++ b/examples/objective-c/auth_sample/SelectUserViewController.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import +#import + +@interface SelectUserViewController : UIViewController +@property(weak, nonatomic) IBOutlet GIDSignInButton *signInButton; +@property(weak, nonatomic) IBOutlet UIButton *signOutButton; +@property(weak, nonatomic) IBOutlet UILabel *mainLabel; +@property(weak, nonatomic) IBOutlet UILabel *subLabel; +@end diff --git a/examples/objective-c/auth_sample/SelectUserViewController.m b/examples/objective-c/auth_sample/SelectUserViewController.m new file mode 100644 index 00000000000..954c531f3fb --- /dev/null +++ b/examples/objective-c/auth_sample/SelectUserViewController.m @@ -0,0 +1,86 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "SelectUserViewController.h" + +#import "MakeRPCViewController.h" + +@implementation SelectUserViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.signOutButton.layer.cornerRadius = 5; + self.signOutButton.hidden = YES; + + // As instructed in https://developers.google.com/identity/sign-in/ios/sign-in + GIDSignIn *signIn = GIDSignIn.sharedInstance; + signIn.delegate = self; + signIn.uiDelegate = self; + + // As instructed in https://developers.google.com/identity/sign-in/ios/additional-scopes + if (![signIn.scopes containsObject:kTestScope]) { + signIn.scopes = [signIn.scopes arrayByAddingObject:kTestScope]; + } + + [signIn signInSilently]; +} + +- (void)signIn:(GIDSignIn *)signIn +didSignInForUser:(GIDGoogleUser *)user + withError:(NSError *)error { + if (error) { + // The user probably cancelled the sign-in flow. + return; + } + + self.mainLabel.text = [NSString stringWithFormat:@"User: %@", user.profile.email]; + NSString *scopes = [user.accessibleScopes componentsJoinedByString:@", "]; + scopes = scopes.length ? scopes : @"(none)"; + self.subLabel.text = [NSString stringWithFormat:@"Scopes: %@", scopes]; + + self.signInButton.hidden = YES; + self.signOutButton.hidden = NO; +} + +- (IBAction)didTapSignOut { + [GIDSignIn.sharedInstance signOut]; + + self.mainLabel.text = @"Please sign in."; + self.subLabel.text = @""; + + self.signInButton.hidden = NO; + self.signOutButton.hidden = YES; +} + +@end diff --git a/examples/objective-c/helloworld/HelloWorld.podspec b/examples/objective-c/helloworld/HelloWorld.podspec new file mode 100644 index 00000000000..ae009a688c6 --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld.podspec @@ -0,0 +1,35 @@ +Pod::Spec.new do |s| + s.name = "HelloWorld" + s.version = "0.0.1" + s.license = "New BSD" + + s.ios.deployment_target = "6.0" + s.osx.deployment_target = "10.8" + + # Base directory where the .proto files are. + src = "../../protos" + + # Directory where the generated files will be place. + dir = "Pods/" + s.name + + # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. + s.prepare_command = <<-CMD + mkdir -p #{dir} + protoc -I #{src} --objc_out=#{dir} --objcgrpc_out=#{dir} #{src}/helloworld.proto + CMD + + s.subspec "Messages" do |ms| + ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}" + ms.header_mappings_dir = dir + ms.requires_arc = false + ms.dependency "Protobuf", "~> 3.0.0-alpha-3" + end + + s.subspec "Services" do |ss| + ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}" + ss.header_mappings_dir = dir + ss.requires_arc = true + ss.dependency "gRPC", "~> 0.6" + ss.dependency "#{s.name}/Messages" + end +end diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj new file mode 100644 index 00000000000..702ad3ff8b2 --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.pbxproj @@ -0,0 +1,349 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 5E3690661B2A23800040F884 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3690651B2A23800040F884 /* main.m */; }; + 5E3690691B2A23800040F884 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E3690681B2A23800040F884 /* AppDelegate.m */; }; + 5E36906C1B2A23800040F884 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E36906B1B2A23800040F884 /* ViewController.m */; }; + 5E36906F1B2A23800040F884 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5E36906D1B2A23800040F884 /* Main.storyboard */; }; + 5E3690711B2A23800040F884 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5E3690701B2A23800040F884 /* Images.xcassets */; }; + EF61CF6AE2536A31D47F0E63 /* libPods-HelloWorld.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B4E1F55F8A2EC95A0E7EE88 /* libPods-HelloWorld.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.release.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.release.xcconfig"; sourceTree = ""; }; + 5E3690601B2A23800040F884 /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 5E3690641B2A23800040F884 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 5E3690651B2A23800040F884 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 5E3690671B2A23800040F884 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 5E3690681B2A23800040F884 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 5E36906B1B2A23800040F884 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; + 5E36906E1B2A23800040F884 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 5E3690701B2A23800040F884 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 6B4E1F55F8A2EC95A0E7EE88 /* libPods-HelloWorld.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-HelloWorld.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + DBDE3E48389499064CD664B8 /* Pods-HelloWorld.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HelloWorld.debug.xcconfig"; path = "Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld.debug.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5E36905D1B2A23800040F884 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + EF61CF6AE2536A31D47F0E63 /* libPods-HelloWorld.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5E3690571B2A23800040F884 = { + isa = PBXGroup; + children = ( + 5E3690651B2A23800040F884 /* main.m */, + 5E3690621B2A23800040F884 /* HelloWorld */, + 5E3690611B2A23800040F884 /* Products */, + BD9CE6458E7C4FF49A1DF69F /* Pods */, + 66CEC7120220DDD2221DD075 /* Frameworks */, + ); + sourceTree = ""; + }; + 5E3690611B2A23800040F884 /* Products */ = { + isa = PBXGroup; + children = ( + 5E3690601B2A23800040F884 /* HelloWorld.app */, + ); + name = Products; + sourceTree = ""; + }; + 5E3690621B2A23800040F884 /* HelloWorld */ = { + isa = PBXGroup; + children = ( + 5E3690631B2A23800040F884 /* Supporting Files */, + ); + path = HelloWorld; + sourceTree = ""; + }; + 5E3690631B2A23800040F884 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 5E3690701B2A23800040F884 /* Images.xcassets */, + 5E36906D1B2A23800040F884 /* Main.storyboard */, + 5E36906B1B2A23800040F884 /* ViewController.m */, + 5E3690681B2A23800040F884 /* AppDelegate.m */, + 5E3690671B2A23800040F884 /* AppDelegate.h */, + 5E3690641B2A23800040F884 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 66CEC7120220DDD2221DD075 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6B4E1F55F8A2EC95A0E7EE88 /* libPods-HelloWorld.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + BD9CE6458E7C4FF49A1DF69F /* Pods */ = { + isa = PBXGroup; + children = ( + DBDE3E48389499064CD664B8 /* Pods-HelloWorld.debug.xcconfig */, + 0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5E36905F1B2A23800040F884 /* HelloWorld */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5E3690831B2A23810040F884 /* Build configuration list for PBXNativeTarget "HelloWorld" */; + buildPhases = ( + ACF9162361FB8F24C70657DE /* Check Pods Manifest.lock */, + 5E36905C1B2A23800040F884 /* Sources */, + 5E36905D1B2A23800040F884 /* Frameworks */, + 5E36905E1B2A23800040F884 /* Resources */, + 4C7D815378D98AB3BFC1A7D5 /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = HelloWorld; + productName = HelloWorld; + productReference = 5E3690601B2A23800040F884 /* HelloWorld.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 5E3690581B2A23800040F884 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0620; + ORGANIZATIONNAME = Google; + TargetAttributes = { + 5E36905F1B2A23800040F884 = { + CreatedOnToolsVersion = 6.2; + }; + }; + }; + buildConfigurationList = 5E36905B1B2A23800040F884 /* Build configuration list for PBXProject "HelloWorld" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 5E3690571B2A23800040F884; + productRefGroup = 5E3690611B2A23800040F884 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 5E36905F1B2A23800040F884 /* HelloWorld */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5E36905E1B2A23800040F884 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E36906F1B2A23800040F884 /* Main.storyboard in Resources */, + 5E3690711B2A23800040F884 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 4C7D815378D98AB3BFC1A7D5 /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-HelloWorld/Pods-HelloWorld-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + ACF9162361FB8F24C70657DE /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5E36905C1B2A23800040F884 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5E36906C1B2A23800040F884 /* ViewController.m in Sources */, + 5E3690691B2A23800040F884 /* AppDelegate.m in Sources */, + 5E3690661B2A23800040F884 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 5E36906D1B2A23800040F884 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5E36906E1B2A23800040F884 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 5E3690811B2A23810040F884 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 5E3690821B2A23810040F884 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 5E3690841B2A23810040F884 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = DBDE3E48389499064CD664B8 /* Pods-HelloWorld.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = HelloWorld/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 5E3690851B2A23810040F884 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 0C432EF610DB15C0F47A66BB /* Pods-HelloWorld.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = HelloWorld/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5E36905B1B2A23800040F884 /* Build configuration list for PBXProject "HelloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E3690811B2A23810040F884 /* Debug */, + 5E3690821B2A23810040F884 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5E3690831B2A23810040F884 /* Build configuration list for PBXNativeTarget "HelloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5E3690841B2A23810040F884 /* Debug */, + 5E3690851B2A23810040F884 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 5E3690581B2A23800040F884 /* Project object */; +} diff --git a/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000000..174a04ecb8f --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/objective-c/helloworld/HelloWorld/AppDelegate.h b/examples/objective-c/helloworld/HelloWorld/AppDelegate.h new file mode 100644 index 00000000000..102e7f3adea --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld/AppDelegate.h @@ -0,0 +1,38 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end diff --git a/examples/objective-c/helloworld/HelloWorld/AppDelegate.m b/examples/objective-c/helloworld/HelloWorld/AppDelegate.m new file mode 100644 index 00000000000..a38e36651ed --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld/AppDelegate.m @@ -0,0 +1,37 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "AppDelegate.h" + +@implementation AppDelegate +@end diff --git a/examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard b/examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard new file mode 100644 index 00000000000..f56d2f3bb56 --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld/Base.lproj/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..36d2c80d889 --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/objective-c/helloworld/HelloWorld/Info.plist b/examples/objective-c/helloworld/HelloWorld/Info.plist new file mode 100644 index 00000000000..1078fff7235 --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + Google.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + Main + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/examples/objective-c/helloworld/HelloWorld/ViewController.m b/examples/objective-c/helloworld/HelloWorld/ViewController.m new file mode 100644 index 00000000000..090fd936892 --- /dev/null +++ b/examples/objective-c/helloworld/HelloWorld/ViewController.m @@ -0,0 +1,40 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + +@interface ViewController : UIViewController +@end + +@implementation ViewController +@end diff --git a/examples/objective-c/helloworld/Podfile b/examples/objective-c/helloworld/Podfile new file mode 100644 index 00000000000..2934ebc2c8a --- /dev/null +++ b/examples/objective-c/helloworld/Podfile @@ -0,0 +1,7 @@ +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '8.0' + +target 'HelloWorld' do + # Depend on the generated HelloWorld library. + pod 'HelloWorld', :path => '.' +end diff --git a/examples/objective-c/helloworld/README.md b/examples/objective-c/helloworld/README.md new file mode 100644 index 00000000000..3b852f857fd --- /dev/null +++ b/examples/objective-c/helloworld/README.md @@ -0,0 +1,56 @@ +#gRPC in 3 minutes (Objective-C) + +## Installation + +To run this example you should have [Cocoapods](https://cocoapods.org/#install) installed, as well +as the relevant tools to generate the client library code (and a server in another language, for +testing). You can obtain the latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc). + +## Hello Objective-C gRPC! + +Here's how to build and run the Objective-C implementation of the [Hello World](examples/protos/helloworld.proto) +example used in [Getting started](https://github.com/grpc/grpc/tree/master/examples). + +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 https://github.com/grpc/grpc.git +``` + +Change your current directory to `examples/objective-c/helloworld` + +```sh +$ cd examples/objective-c/helloworld +``` + +### Try it! +To try the sample app, we need a gRPC server running locally. Let's compile and run, for example, +the C++ server in this repository: + +```shell +$ pushd ../../cpp/helloworld +$ make +$ ./greeter_server & +$ popd +``` + +Now have Cocoapods generate and install the client library for our .proto files: + +```shell +$ pod install +``` + +(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet +on your computer's cache.) + +Finally, open the XCode workspace created by Cocoapods, and run the app. You can check the calling +code in `main.m` and see the results in XCode's log console. + +The code sends a `HLWHelloRequest` containing the string "Objective-C" to a local server. The server +responds with a `HLWHelloResponse`, which contains a string that is then output to the log. + +## Tutorial + +You can find a more detailed tutorial in [gRPC Basics: Objective-C](examples/objective-c/route_guide/README.md). diff --git a/examples/objective-c/helloworld/main.m b/examples/objective-c/helloworld/main.m new file mode 100644 index 00000000000..458580be302 --- /dev/null +++ b/examples/objective-c/helloworld/main.m @@ -0,0 +1,51 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import +#import "AppDelegate.h" + +#import + +static NSString * const kHostAddress = @"http://localhost:50051"; + +int main(int argc, char * argv[]) { + @autoreleasepool { + HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress]; + HLWHelloRequest *request = [HLWHelloRequest message]; + request.name = @"Objective-C"; + [client sayHelloWithRequest:request handler:^(HLWHelloReply *response, NSError *error) { + NSLog(@"%@", response.message); + }]; + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/examples/objective-c/route_guide/Misc/AppDelegate.h b/examples/objective-c/route_guide/Misc/AppDelegate.h new file mode 100644 index 00000000000..102e7f3adea --- /dev/null +++ b/examples/objective-c/route_guide/Misc/AppDelegate.h @@ -0,0 +1,38 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import + +@interface AppDelegate : UIResponder +@property (strong, nonatomic) UIWindow *window; +@end diff --git a/examples/objective-c/route_guide/Misc/AppDelegate.m b/examples/objective-c/route_guide/Misc/AppDelegate.m new file mode 100644 index 00000000000..a38e36651ed --- /dev/null +++ b/examples/objective-c/route_guide/Misc/AppDelegate.m @@ -0,0 +1,37 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import "AppDelegate.h" + +@implementation AppDelegate +@end diff --git a/examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard b/examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard new file mode 100644 index 00000000000..9bf9498d62c --- /dev/null +++ b/examples/objective-c/route_guide/Misc/Base.lproj/Main.storyboard @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json b/examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..36d2c80d889 --- /dev/null +++ b/examples/objective-c/route_guide/Misc/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json b/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json new file mode 100644 index 00000000000..33a745102c8 --- /dev/null +++ b/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "first.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf b/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf new file mode 100644 index 00000000000..47d911dea64 Binary files /dev/null and b/examples/objective-c/route_guide/Misc/Images.xcassets/first.imageset/first.pdf differ diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json b/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json new file mode 100644 index 00000000000..03bd9c927f4 --- /dev/null +++ b/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "second.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf b/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf new file mode 100644 index 00000000000..401614e288b Binary files /dev/null and b/examples/objective-c/route_guide/Misc/Images.xcassets/second.imageset/second.pdf differ diff --git a/examples/objective-c/route_guide/Misc/Info.plist b/examples/objective-c/route_guide/Misc/Info.plist new file mode 100644 index 00000000000..33ad4800f69 --- /dev/null +++ b/examples/objective-c/route_guide/Misc/Info.plist @@ -0,0 +1,57 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + gRPC.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + Main + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UIStatusBarTintParameters + + UINavigationBar + + Style + UIBarStyleDefault + Translucent + + + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/examples/objective-c/route_guide/Misc/main.m b/examples/objective-c/route_guide/Misc/main.m new file mode 100644 index 00000000000..fb701005d1d --- /dev/null +++ b/examples/objective-c/route_guide/Misc/main.m @@ -0,0 +1,41 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/examples/objective-c/route_guide/Podfile b/examples/objective-c/route_guide/Podfile new file mode 100644 index 00000000000..a97f4146858 --- /dev/null +++ b/examples/objective-c/route_guide/Podfile @@ -0,0 +1,7 @@ +source 'https://github.com/CocoaPods/Specs.git' +platform :ios, '8.0' + +target 'RouteGuideClient' do + # Depend on the generated RouteGuide library. + pod 'RouteGuide', :path => '.' +end diff --git a/examples/objective-c/route_guide/README.md b/examples/objective-c/route_guide/README.md new file mode 100644 index 00000000000..dd20a07995b --- /dev/null +++ b/examples/objective-c/route_guide/README.md @@ -0,0 +1,360 @@ +#gRPC Basics: Objective-C + +This tutorial provides a basic Objective-C programmer's introduction to working with gRPC. By +walking through this example you'll learn how to: + +- Define a service in a .proto file. +- Generate client code using the protocol buffer compiler. +- Use the Objective-C gRPC API to write a simple client for your service. + +It assumes a passing familiarity with [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). +Note that the example in this tutorial uses the proto3 version of the protocol buffers language, +which is currently in alpha release: you can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3) +and see the [release notes](https://github.com/google/protobuf/releases) for the new version in the +protocol buffers Github repository. + +This isn't a comprehensive guide to using gRPC in Objective-C: more reference documentation is +coming soon. + +- [Why use gRPC?](#why-grpc) +- [Example code and setup](#setup) +- [Try it out!](#try) +- [Defining the service](#proto) +- [Generating client code](#protoc) +- [Creating the client](#client) + + +## Why use gRPC? + +With gRPC you can define your service once in a .proto file and implement clients and servers in any +of gRPC's supported languages, which in turn can be run in environments ranging from servers inside +Google to your own tablet - all the complexity of communication between different languages and +environments is handled for you by gRPC. You also get all the advantages of working with protocol +buffers, including efficient serialization, a simple IDL, and easy interface updating. + +gRPC and proto3 are specially suited for mobile clients: gRPC is implemented on top of HTTP/2, which +results in network bandwidth savings over using HTTP/1.1. Serialization and parsing of the proto +binary format is more efficient than the equivalent JSON, resulting in CPU and battery savings. And +proto3 uses a runtime that has been optimized over the years at Google to keep code size to a +minimum. The latter is important in Objective-C, because the ability of the compiler to strip unused +code is limited by the dynamic nature of the language. + + + +## Example code and setup + +The example code for our tutorial is in [examples/objective-c/route_guide](examples/objective-c/route_guide). +To download the example, clone this repository by running the following command: +```shell +$ git clone https://github.com/grpc/grpc.git +``` + +Then change your current directory to `examples/objective-c/route_guide`: +```shell +$ cd examples/objective-c/route_guide +``` + +Our example is a simple route mapping application that lets clients get information about features +on their route, create a summary of their route, and exchange route information such as traffic +updates with the server and other clients. + +You also should have [Cocoapods](https://cocoapods.org/#install) installed, as well as the relevant +tools to generate the client library code (and a server in another language, for testing). You can +obtain the latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc). + + + +## Try it out! + +To try the sample app, we need a gRPC server running locally. Let's compile and run, for example, +the C++ server in this repository: + +```shell +$ pushd ../../cpp/route_guide +$ make +$ ./route_guide_server & +$ popd +``` + +Now have Cocoapods generate and install the client library for our .proto files: + +```shell +$ pod install +``` + +(This might have to compile OpenSSL, which takes around 15 minutes if Cocoapods doesn't have it yet +on your computer's cache). + +Finally, open the XCode workspace created by Cocoapods, and run the app. You can check the calling +code in `ViewControllers.m` and see the results in XCode's log console. + +The next sections guide you step-by-step through how this proto service is defined, how to generate +a client library from it, and how to create an app that uses that library. + + + +## Defining the service + +First let's look at how the service we're using is defined. A gRPC *service* and its method +*request* and *response* types using [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). +You can see the complete .proto file for our example in [`examples/protos/route_guide.proto`](examples/protos/route_guide.proto). + +To define a service, you specify a named `service` in your .proto file: + +```protobuf +service RouteGuide { + ... +} +``` + +Then you define `rpc` methods inside your service definition, specifying their request and response +types. Protocol buffers let you define four kinds of service method, all of which are used in the +`RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server and receives a response later, just +like a normal remote procedure call. +```protobuf + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *response-streaming RPC* where the client sends a request to the server and gets back a stream +of response messages. You specify a response-streaming method by placing the `stream` keyword before +the *response* type. +```protobuf + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *request-streaming RPC* where the client sends a sequence of messages to the server. Once the +client has finished writing the messages, it waits for the server to read them all and return its +response. You specify a request-streaming method by placing the `stream` keyword before the +*request* type. +```protobuf + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectional streaming RPC* where both sides send a sequence of messages to the other. The two +streams operate independently, so clients and servers can read and write in whatever order they +like: for example, the server could wait to receive all the client messages before writing its +responses, or it could alternately read a message then write a message, or some other combination of +reads and writes. The order of messages in each stream is preserved. You specify this type of method +by placing the `stream` keyword before both the request and the response. +```protobuf + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Our .proto file also contains protocol buffer message type definitions for all the request and +response types used in our service methods - for example, here's the `Point` message type: +```protobuf +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + +You can specify a prefix to be used for your generated classes by adding the `objc_class_prefix` +option at the top of the file. For example: +```protobuf +option objc_class_prefix = "RTG"; +``` + + + +## Generating client code + +Next we need to generate the gRPC client interfaces from our .proto service definition. We do this +using the protocol buffer compiler (`protoc`) with a special gRPC Objective-C plugin. + +For simplicity, we've provided a [Podspec file](examples/objective-c/route_guide/RouteGuide.podspec) +that runs `protoc` for you with the appropriate plugin, input, and output, and describes how to +compile the generated files. You just need to run in this directory (`examples/objective-c/route_guide`): + +```shell +$ pod install +``` + +which, before installing the generated library in the XCode project of this sample, runs: + +```shell +$ protoc -I ../../protos --objc_out=Pods/RouteGuide --objcgrpc_out=Pods/RouteGuide ../../protos/route_guide.proto +``` + +Running this command generates the following files under `Pods/RouteGuide/`: +- `RouteGuide.pbobjc.h`, the header which declares your generated message classes. +- `RouteGuide.pbobjc.m`, which contains the implementation of your message classes. +- `RouteGuide.pbrpc.h`, the header which declares your generated service classes. +- `RouteGuide.pbrpc.m`, which contains the implementation of your service classes. + +These contain: +- All the protocol buffer code to populate, serialize, and retrieve our request and response message +types. +- A class called `RTGRouteGuide` that lets clients call the methods defined in the `RouteGuide` +service. + +You can also use the provided Podspec file to generate client code from any other proto service +definition; just replace the name (matching the file name), version, and other metadata. + + + +## Creating the client + +In this section, we'll look at creating an Objective-C client for our `RouteGuide` service. You can +see our complete example client code in [examples/objective-c/route_guide/ViewControllers.m](examples/objective-c/route_guide/ViewControllers.m). +(Note: In your apps, for maintainability and readability reasons, you shouldn't put all of your view +controllers in a single file; it's done here only to simplify the learning process). + +### Constructing a client object + +To call service methods, we first need to create a client object, an instance of the generated +`RTGRouteGuide` class. The designated initializer of the class expects a `NSString *` with the +server address and port we want to connect to: + +```objective-c +#import + +static NSString * const kHostAddress = @"http://localhost:50051"; + +... + +RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; +``` + +Notice that we've specified the HTTP scheme in the host address. This is because the server we will +be using to test our client doesn't use [TLS](http://en.wikipedia.org/wiki/Transport_Layer_Security). +This is fine because it will be running locally on our development machine. The most common case, +though, is connecting with a gRPC server on the internet, running gRPC over TLS. For that case, the +HTTPS scheme can be specified (or no scheme at all, as HTTPS is the default value). The default +value of the port is that of the scheme selected: 443 for HTTPS and 80 for HTTP. + + +### Calling service methods + +Now let's look at how we call our service methods. As you will see, all these methods are +asynchronous, so you can call them from the main thread of your app without worrying about freezing +your UI or the OS killing your app. + +#### Simple RPC + +Calling the simple RPC `GetFeature` is nearly as straightforward as calling any other asynchronous +method on Cocoa. + +```objective-c +RTGPoint *point = [RTGPoint message]; +point.latitude = 40E7; +point.longitude = -74E7; + +[client getFeatureWithRequest:point handler:^(RTGFeature *response, NSError *error) { + if (response) { + // Successful response received + } else { + // RPC error + } +}]; +``` + +As you can see, we create and populate a request protocol buffer object (in our case `RTGPoint`). +Then, we call the method on the client object, passing it the request, and a block to handle the +response (or any RPC error). If the RPC finishes successfully, the handler block is called with a +`nil` error argument, and we can read the response information from the server from the response +argument. If, instead, some RPC error happens, the handler block is called with a `nil` response +argument, and we can read the details of the problem from the error argument. + +```objective-c +NSLog(@"Found feature called %@ at %@.", response.name, response.location); +``` + +#### Streaming RPCs + +Now let's look at our streaming methods. Here's where we call the response-streaming method +`ListFeatures`, which results in our client receiving a stream of geographical `RTGFeature`s: + +```objective-c +[client listFeaturesWithRequest:rectangle + eventHandler:^(BOOL done, RTGFeature *response, NSError *error) { + if (response) { + // Element of the stream of responses received + } else if (error) { + // RPC error; the stream is over. + } + if (done) { + // The stream is over (all the responses were received, or an error occured). Do any cleanup. + } +}]; +``` + +Notice how the signature of the `eventHandler` block now includes a `BOOL done` parameter. The +`eventHandler` block can be called any number of times; only on the last call is the `done` argument +value set to `YES`. If an error occurs, the RPC finishes and the block is called with the arguments +`(YES, nil, error)`. + +The request-streaming method `RecordRoute` expects a stream of `RTGPoint`s from the cient. This +stream is passed to the method as an object of class `GRXWriter`. The simplest way to create one is +to initialize one from a `NSArray` object: + + +```objective-c +#import + +... + +RTGPoint *point1 = [RTGPoint message]; +point.latitude = 40E7; +point.longitude = -74E7; + +RTGPoint *point2 = [RTGPoint message]; +point.latitude = 40E7; +point.longitude = -74E7; + +GRXWriter *locationsWriter = [GRXWriter writerWithContainer:@[point1, point2]]; + +[client recordRouteWithRequestsWriter:locationsWriter + handler:^(RTGRouteSummary *response, NSError *error) { + if (response) { + NSLog(@"Finished trip with %i points", response.pointCount); + NSLog(@"Passed %i features", response.featureCount); + NSLog(@"Travelled %i meters", response.distance); + NSLog(@"It took %i seconds", response.elapsedTime); + } else { + NSLog(@"RPC error: %@", error); + } +}]; + +``` + +The `GRXWriter` class is generic enough to allow for asynchronous streams, streams of future values, +or even infinite streams. + +Finally, let's look at our bidirectional streaming RPC `RouteChat()`. The way to call a +bidirectional streaming RPC is just a combination of how to call request-streaming RPCs and +response-streaming RPCs. + +```objective-c +[client routeChatWithRequestsWriter:notesWriter + eventHandler:^(BOOL done, RTGRouteNote *note, NSError *error) { + if (note) { + NSLog(@"Got message %@ at %@", note.message, note.location); + } else if (error) { + NSLog(@"RPC error: %@", error); + } + if (done) { + NSLog(@"Chat ended."); + } +}]; +``` + +The semantics for the handler block and the `GRXWriter` argument here are exactly the same as for +our request-streaming and response-streaming methods. Although both client and server will always +get the other's messages in the order they were written, the two streams operate completely +independently. diff --git a/examples/objective-c/route_guide/RouteGuide.podspec b/examples/objective-c/route_guide/RouteGuide.podspec new file mode 100644 index 00000000000..7b99a6c6a77 --- /dev/null +++ b/examples/objective-c/route_guide/RouteGuide.podspec @@ -0,0 +1,35 @@ +Pod::Spec.new do |s| + s.name = "RouteGuide" + s.version = "0.0.1" + s.license = "New BSD" + + s.ios.deployment_target = "6.0" + s.osx.deployment_target = "10.8" + + # Base directory where the .proto files are. + src = "../../protos" + + # Directory where the generated files will be place. + dir = "Pods/" + s.name + + # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients. + s.prepare_command = <<-CMD + mkdir -p #{dir} + protoc -I #{src} --objc_out=#{dir} --objcgrpc_out=#{dir} #{src}/route_guide.proto + CMD + + s.subspec "Messages" do |ms| + ms.source_files = "#{dir}/*.pbobjc.{h,m}", "#{dir}/**/*.pbobjc.{h,m}" + ms.header_mappings_dir = dir + ms.requires_arc = false + ms.dependency "Protobuf", "~> 3.0.0-alpha-3" + end + + s.subspec "Services" do |ss| + ss.source_files = "#{dir}/*.pbrpc.{h,m}", "#{dir}/**/*.pbrpc.{h,m}" + ss.header_mappings_dir = dir + ss.requires_arc = true + ss.dependency "gRPC", "~> 0.6" + ss.dependency "#{s.name}/Messages" + end +end diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj new file mode 100644 index 00000000000..6ab6b27a1b5 --- /dev/null +++ b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.pbxproj @@ -0,0 +1,366 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 124E20A2FC8EAE54460D4ED2 /* libPods-RouteGuideClient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 71CEE03D66D40FC37264D6E4 /* libPods-RouteGuideClient.a */; }; + 632527831B1D0396003073D9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 632527821B1D0396003073D9 /* main.m */; }; + 632527861B1D0396003073D9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 632527851B1D0396003073D9 /* AppDelegate.m */; }; + 6325278F1B1D0396003073D9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6325278D1B1D0396003073D9 /* Main.storyboard */; }; + 632527911B1D0396003073D9 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 632527901B1D0396003073D9 /* Images.xcassets */; }; + 6367B55B1B223AFA008861F5 /* route_guide_db.json in Resources */ = {isa = PBXBuildFile; fileRef = 6367B55A1B223AFA008861F5 /* route_guide_db.json */; }; + 63A6015C1B1DAB5000FA5B86 /* ViewControllers.m in Sources */ = {isa = PBXBuildFile; fileRef = 63A6015B1B1DAB5000FA5B86 /* ViewControllers.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 6325277D1B1D0396003073D9 /* RouteGuideClient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RouteGuideClient.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 632527811B1D0396003073D9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 632527821B1D0396003073D9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 632527841B1D0396003073D9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; + 632527851B1D0396003073D9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 6325278E1B1D0396003073D9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 632527901B1D0396003073D9 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 6367B55A1B223AFA008861F5 /* route_guide_db.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = route_guide_db.json; sourceTree = ""; }; + 63A6015B1B1DAB5000FA5B86 /* ViewControllers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewControllers.m; sourceTree = ""; }; + 71CEE03D66D40FC37264D6E4 /* libPods-RouteGuideClient.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-RouteGuideClient.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + ADA4C647BAE906F79AD9A45E /* Pods-RouteGuideClient.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RouteGuideClient.debug.xcconfig"; path = "Pods/Target Support Files/Pods-RouteGuideClient/Pods-RouteGuideClient.debug.xcconfig"; sourceTree = ""; }; + C83C5A54D1A4EA07569F1AED /* Pods-RouteGuideClient.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RouteGuideClient.release.xcconfig"; path = "Pods/Target Support Files/Pods-RouteGuideClient/Pods-RouteGuideClient.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 6325277A1B1D0395003073D9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 124E20A2FC8EAE54460D4ED2 /* libPods-RouteGuideClient.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 56849C29DC376BF4B902CD77 /* Pods */ = { + isa = PBXGroup; + children = ( + ADA4C647BAE906F79AD9A45E /* Pods-RouteGuideClient.debug.xcconfig */, + C83C5A54D1A4EA07569F1AED /* Pods-RouteGuideClient.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 631C63891B1DBC41001295D5 /* Misc */ = { + isa = PBXGroup; + children = ( + 632527841B1D0396003073D9 /* AppDelegate.h */, + 632527851B1D0396003073D9 /* AppDelegate.m */, + 632527901B1D0396003073D9 /* Images.xcassets */, + 632527801B1D0396003073D9 /* Supporting Files */, + ); + path = Misc; + sourceTree = ""; + }; + 632527741B1D0395003073D9 = { + isa = PBXGroup; + children = ( + 6325277F1B1D0396003073D9 /* RouteGuideClient */, + 6325277E1B1D0396003073D9 /* Products */, + 56849C29DC376BF4B902CD77 /* Pods */, + 7482B8A18481F7B13ADE4530 /* Frameworks */, + ); + sourceTree = ""; + }; + 6325277E1B1D0396003073D9 /* Products */ = { + isa = PBXGroup; + children = ( + 6325277D1B1D0396003073D9 /* RouteGuideClient.app */, + ); + name = Products; + sourceTree = ""; + }; + 6325277F1B1D0396003073D9 /* RouteGuideClient */ = { + isa = PBXGroup; + children = ( + 63A6015B1B1DAB5000FA5B86 /* ViewControllers.m */, + 6367B55A1B223AFA008861F5 /* route_guide_db.json */, + 6325278D1B1D0396003073D9 /* Main.storyboard */, + 631C63891B1DBC41001295D5 /* Misc */, + ); + name = RouteGuideClient; + sourceTree = SOURCE_ROOT; + }; + 632527801B1D0396003073D9 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 632527811B1D0396003073D9 /* Info.plist */, + 632527821B1D0396003073D9 /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 7482B8A18481F7B13ADE4530 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 71CEE03D66D40FC37264D6E4 /* libPods-RouteGuideClient.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 6325277C1B1D0395003073D9 /* RouteGuideClient */ = { + isa = PBXNativeTarget; + buildConfigurationList = 632527A31B1D0396003073D9 /* Build configuration list for PBXNativeTarget "RouteGuideClient" */; + buildPhases = ( + C6FC30AD2376EC04317237C5 /* Check Pods Manifest.lock */, + 632527791B1D0395003073D9 /* Sources */, + 6325277A1B1D0395003073D9 /* Frameworks */, + 6325277B1B1D0395003073D9 /* Resources */, + FFE0BCF30339E7A50A989EAB /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RouteGuideClient; + productName = RouteGuideClient; + productReference = 6325277D1B1D0396003073D9 /* RouteGuideClient.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 632527751B1D0395003073D9 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0630; + ORGANIZATIONNAME = gRPC; + TargetAttributes = { + 6325277C1B1D0395003073D9 = { + CreatedOnToolsVersion = 6.3.1; + }; + }; + }; + buildConfigurationList = 632527781B1D0395003073D9 /* Build configuration list for PBXProject "RouteGuideClient" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 632527741B1D0395003073D9; + productRefGroup = 6325277E1B1D0396003073D9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 6325277C1B1D0395003073D9 /* RouteGuideClient */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 6325277B1B1D0395003073D9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6325278F1B1D0396003073D9 /* Main.storyboard in Resources */, + 632527911B1D0396003073D9 /* Images.xcassets in Resources */, + 6367B55B1B223AFA008861F5 /* route_guide_db.json in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + C6FC30AD2376EC04317237C5 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + FFE0BCF30339E7A50A989EAB /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-RouteGuideClient/Pods-RouteGuideClient-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 632527791B1D0395003073D9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 632527861B1D0396003073D9 /* AppDelegate.m in Sources */, + 632527831B1D0396003073D9 /* main.m in Sources */, + 63A6015C1B1DAB5000FA5B86 /* ViewControllers.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 6325278D1B1D0396003073D9 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 6325278E1B1D0396003073D9 /* Base */, + ); + name = Main.storyboard; + path = Misc; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 632527A11B1D0396003073D9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 632527A21B1D0396003073D9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 632527A41B1D0396003073D9 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = ADA4C647BAE906F79AD9A45E /* Pods-RouteGuideClient.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Misc/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 632527A51B1D0396003073D9 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C83C5A54D1A4EA07569F1AED /* Pods-RouteGuideClient.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + INFOPLIST_FILE = Misc/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 632527781B1D0395003073D9 /* Build configuration list for PBXProject "RouteGuideClient" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 632527A11B1D0396003073D9 /* Debug */, + 632527A21B1D0396003073D9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 632527A31B1D0396003073D9 /* Build configuration list for PBXNativeTarget "RouteGuideClient" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 632527A41B1D0396003073D9 /* Debug */, + 632527A51B1D0396003073D9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 632527751B1D0395003073D9 /* Project object */; +} diff --git a/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000000..f208589e441 --- /dev/null +++ b/examples/objective-c/route_guide/RouteGuideClient.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/examples/objective-c/route_guide/ViewControllers.m b/examples/objective-c/route_guide/ViewControllers.m new file mode 100644 index 00000000000..cfc3338bcac --- /dev/null +++ b/examples/objective-c/route_guide/ViewControllers.m @@ -0,0 +1,228 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#import +#import +#import +#import + +static NSString * const kHostAddress = @"http://localhost:50051"; + +// Category to override RTGPoint's description. +@interface RTGPoint (Description) +- (NSString *)description; +@end + +@implementation RTGPoint (Description) +- (NSString *)description { + NSString *verticalDirection = self.latitude >= 0 ? @"N" : @"S"; + NSString *horizontalDirection = self.longitude >= 0 ? @"E" : @"W"; + return [NSString stringWithFormat:@"%.02f%@ %.02f%@", + abs(self.latitude) / 1E7f, verticalDirection, + abs(self.longitude) / 1E7f, horizontalDirection]; +} +@end + +// Category to give RTGRouteNote a convenience constructor. +@interface RTGRouteNote (Constructors) ++ (instancetype)noteWithMessage:(NSString *)message + latitude:(float)latitude + longitude:(float)longitude; +@end + +@implementation RTGRouteNote (Constructors) ++ (instancetype)noteWithMessage:(NSString *)message + latitude:(float)latitude + longitude:(float)longitude { + RTGRouteNote *note = [self message]; + note.message = message; + note.location.latitude = (int32_t) latitude * 1E7; + note.location.longitude = (int32_t) longitude * 1E7; + return note; +} +@end + + +#pragma mark Demo: Get Feature + +// Run the getFeature demo. Calls getFeature with a point known to have a feature and a point known +// not to have a feature. + +@interface GetFeatureViewController : UIViewController +@end + +@implementation GetFeatureViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; + + void (^handler)(RTGFeature *response, NSError *error) = ^(RTGFeature *response, NSError *error) { + if (response.name.length) { + NSLog(@"Found feature called %@ at %@.", response.name, response.location); + } else if (response) { + NSLog(@"Found no features at %@", response.location); + } else { + NSLog(@"RPC error: %@", error); + } + }; + + RTGPoint *point = [RTGPoint message]; + point.latitude = 409146138; + point.longitude = -746188906; + + [client getFeatureWithRequest:point handler:handler]; + [client getFeatureWithRequest:[RTGPoint message] handler:handler]; +} + +@end + + +#pragma mark Demo: List Features + +// Run the listFeatures demo. Calls listFeatures with a rectangle containing all of the features in +// the pre-generated database. Prints each response as it comes in. + +@interface ListFeaturesViewController : UIViewController +@end + +@implementation ListFeaturesViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; + + RTGRectangle *rectangle = [RTGRectangle message]; + rectangle.lo.latitude = 405E6; + rectangle.lo.longitude = -750E6; + rectangle.hi.latitude = 410E6; + rectangle.hi.longitude = -745E6; + + NSLog(@"Looking for features between %@ and %@", rectangle.lo, rectangle.hi); + [client listFeaturesWithRequest:rectangle + eventHandler:^(BOOL done, RTGFeature *response, NSError *error) { + if (response) { + NSLog(@"Found feature at %@ called %@.", response.location, response.name); + } else if (error) { + NSLog(@"RPC error: %@", error); + } + }]; +} + +@end + + +#pragma mark Demo: Record Route + +// Run the recordRoute demo. Sends several randomly chosen points from the pre-generated feature +// database with a variable delay in between. Prints the statistics when they are sent from the +// server. + +@interface RecordRouteViewController : UIViewController +@end + +@implementation RecordRouteViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + NSString *dataBasePath = [NSBundle.mainBundle pathForResource:@"route_guide_db" + ofType:@"json"]; + NSData *dataBaseContent = [NSData dataWithContentsOfFile:dataBasePath]; + NSArray *features = [NSJSONSerialization JSONObjectWithData:dataBaseContent options:0 error:NULL]; + + GRXWriter *locations = [[GRXWriter writerWithContainer:features] map:^id(id feature) { + RTGPoint *location = [RTGPoint message]; + location.longitude = [((NSNumber *) feature[@"location"][@"longitude"]) intValue]; + location.latitude = [((NSNumber *) feature[@"location"][@"latitude"]) intValue]; + NSLog(@"Visiting point %@", location); + return location; + }]; + + RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; + + [client recordRouteWithRequestsWriter:locations handler:^(RTGRouteSummary *response, NSError *error) { + if (response) { + NSLog(@"Finished trip with %i points", response.pointCount); + NSLog(@"Passed %i features", response.featureCount); + NSLog(@"Travelled %i meters", response.distance); + NSLog(@"It took %i seconds", response.elapsedTime); + } else { + NSLog(@"RPC error: %@", error); + } + }]; +} + +@end + + +#pragma mark Demo: Route Chat + +// Run the routeChat demo. Send some chat messages, and print any chat messages that are sent from +// the server. + +@interface RouteChatViewController : UIViewController +@end + +@implementation RouteChatViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + NSArray *notes = @[[RTGRouteNote noteWithMessage:@"First message" latitude:0 longitude:0], + [RTGRouteNote noteWithMessage:@"Second message" latitude:0 longitude:1], + [RTGRouteNote noteWithMessage:@"Third message" latitude:1 longitude:0], + [RTGRouteNote noteWithMessage:@"Fourth message" latitude:0 longitude:0]]; + GRXWriter *notesWriter = [[GRXWriter writerWithContainer:notes] map:^id(RTGRouteNote *note) { + NSLog(@"Sending message %@ at %@", note.message, note.location); + return note; + }]; + + RTGRouteGuide *client = [[RTGRouteGuide alloc] initWithHost:kHostAddress]; + + [client routeChatWithRequestsWriter:notesWriter + eventHandler:^(BOOL done, RTGRouteNote *note, NSError *error) { + if (note) { + NSLog(@"Got message %@ at %@", note.message, note.location); + } else if (error) { + NSLog(@"RPC error: %@", error); + } + if (done) { + NSLog(@"Chat ended."); + } + }]; +} + +@end diff --git a/examples/objective-c/route_guide/route_guide_db.json b/examples/objective-c/route_guide/route_guide_db.json new file mode 100644 index 00000000000..9caebaa433c --- /dev/null +++ b/examples/objective-c/route_guide/route_guide_db.json @@ -0,0 +1,121 @@ +[{ + "location": { + "latitude": 407838351, + "longitude": -746143763 + }, + "name": "Patriots Path, Mendham, NJ 07945, USA" +}, { + "location": { + "latitude": 408122808, + "longitude": -743999179 + }, + "name": "101 New Jersey 10, Whippany, NJ 07981, USA" +}, { + "location": { + "latitude": 413628156, + "longitude": -749015468 + }, + "name": "U.S. 6, Shohola, PA 18458, USA" +}, { + "location": { + "latitude": 419999544, + "longitude": -740371136 + }, + "name": "5 Conners Road, Kingston, NY 12401, USA" +}, { + "location": { + "latitude": 414008389, + "longitude": -743951297 + }, + "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" +}, { + "location": { + "latitude": 419611318, + "longitude": -746524769 + }, + "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" +}, { + "location": { + "latitude": 406109563, + "longitude": -742186778 + }, + "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" +}, { + "location": { + "latitude": 416802456, + "longitude": -742370183 + }, + "name": "352 South Mountain Road, Wallkill, NY 12589, USA" +}, { + "location": { + "latitude": 412950425, + "longitude": -741077389 + }, + "name": "Bailey Turn Road, Harriman, NY 10926, USA" +}, { + "location": { + "latitude": 412144655, + "longitude": -743949739 + }, + "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" +}, { + "location": { + "latitude": 404306372, + "longitude": -741079661 + }, + "name": "" +}, { + "location": { + "latitude": 403966326, + "longitude": -748519297 + }, + "name": "" +}, { + "location": { + "latitude": 405002031, + "longitude": -748407866 + }, + "name": "" +}, { + "location": { + "latitude": 409532885, + "longitude": -742200683 + }, + "name": "" +}, { + "location": { + "latitude": 416851321, + "longitude": -742674555 + }, + "name": "" +}, { + "location": { + "latitude": 406411633, + "longitude": -741722051 + }, + "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" +}, { + "location": { + "latitude": 413069058, + "longitude": -744597778 + }, + "name": "261 Van Sickle Road, Goshen, NY 10924, USA" +}, { + "location": { + "latitude": 418465462, + "longitude": -746859398 + }, + "name": "" +}, { + "location": { + "latitude": 411733222, + "longitude": -744228360 + }, + "name": "" +}, { + "location": { + "latitude": 410248224, + "longitude": -747127767 + }, + "name": "3 Hasta Way, Newton, NJ 07860, USA" +}] diff --git a/examples/php/.gitignore b/examples/php/.gitignore new file mode 100644 index 00000000000..d8a7996ab38 --- /dev/null +++ b/examples/php/.gitignore @@ -0,0 +1,2 @@ +composer.lock +vendor/ diff --git a/examples/php/README.md b/examples/php/README.md new file mode 100644 index 00000000000..5c327f10faf --- /dev/null +++ b/examples/php/README.md @@ -0,0 +1,64 @@ +gRPC in 3 minutes (PHP) +=========================== + +PREREQUISITES +------------- + +This requires PHP 5.5 or greater. + +INSTALL +------- + - On Mac OS X, install [homebrew][]. On Linux, install [linuxbrew][]. Run the following command to install gRPC. + + ```sh + $ curl -fsSL https://goo.gl/getgrpc | bash -s php + ``` + This will download and run the [gRPC install script][] and compile the gRPC PHP extension. + + - Clone this repository + + ```sh + $ git clone https://github.com/grpc/grpc.git + ``` + + - Install composer + + ``` + $ cd examples/php + $ curl -sS https://getcomposer.org/installer | php + $ php composer.phar install + ``` + +TRY IT! +------- + + - Run the server + + Please follow the instruction in [Node][] to run the server + ``` + $ cd examples/node + $ nodejs greeter_server.js + ``` + + - Run the client + + ``` + $ cd examples/php + $ ./run_greeter_client.sh + ``` + +NOTE +---- + +This directory has a copy of `helloworld.proto` because it currently depends on +some Protocol Buffer 2.0 syntax. There is no proto3 support for PHP yet. + +TUTORIAL +-------- + +Coming soon + +[homebrew]:http://brew.sh +[linuxbrew]:https://github.com/Homebrew/linuxbrew#installation +[gRPC install script]:https://raw.githubusercontent.com/grpc/homebrew-grpc/master/scripts/install +[Node]:https://github.com/grpc/grpc/tree/master/examples/node diff --git a/examples/php/composer.json b/examples/php/composer.json new file mode 100644 index 00000000000..f0ce3a2aff4 --- /dev/null +++ b/examples/php/composer.json @@ -0,0 +1,17 @@ +{ + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/stanley-cheung/Protobuf-PHP" + } + ], + "name": "grpc/grpc-demo", + "description": "gRPC example for PHP", + "minimum-stability": "dev", + "require": { + "php": ">=5.5.0", + "datto/protobuf-php": "dev-master", + "google/auth": "dev-master", + "grpc/grpc": "dev-master" + } +} diff --git a/examples/php/greeter_client.php b/examples/php/greeter_client.php new file mode 100644 index 00000000000..8ae19ae46c5 --- /dev/null +++ b/examples/php/greeter_client.php @@ -0,0 +1,49 @@ +setName($name); + list($reply, $status) = $client->SayHello($request)->wait(); + $message = $reply->getMessage(); + return $message; +} + +$name = !empty($argv[1]) ? $argv[1] : 'world'; +print(greet($name)."\n"); diff --git a/examples/php/helloworld.php b/examples/php/helloworld.php new file mode 100644 index 00000000000..22da3d3970f --- /dev/null +++ b/examples/php/helloworld.php @@ -0,0 +1,160 @@ +number = 1; + $f->name = "name"; + $f->type = \DrSlump\Protobuf::TYPE_STRING; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $descriptor->addField($f); + + foreach (self::$__extensions as $cb) { + $descriptor->addField($cb(), true); + } + + return $descriptor; + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasName(){ + return $this->_has(1); + } + + /** + * Clear value + * + * @return \helloworld\HelloRequest + */ + public function clearName(){ + return $this->_clear(1); + } + + /** + * Get value + * + * @return string + */ + public function getName(){ + return $this->_get(1); + } + + /** + * Set value + * + * @param string $value + * @return \helloworld\HelloRequest + */ + public function setName( $value){ + return $this->_set(1, $value); + } + } +} + +namespace helloworld { + + class HelloReply extends \DrSlump\Protobuf\Message { + + /** @var string */ + public $message = null; + + + /** @var \Closure[] */ + protected static $__extensions = array(); + + public static function descriptor() + { + $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'helloworld.HelloReply'); + + // OPTIONAL STRING message = 1 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 1; + $f->name = "message"; + $f->type = \DrSlump\Protobuf::TYPE_STRING; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $descriptor->addField($f); + + foreach (self::$__extensions as $cb) { + $descriptor->addField($cb(), true); + } + + return $descriptor; + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasMessage(){ + return $this->_has(1); + } + + /** + * Clear value + * + * @return \helloworld\HelloReply + */ + public function clearMessage(){ + return $this->_clear(1); + } + + /** + * Get value + * + * @return string + */ + public function getMessage(){ + return $this->_get(1); + } + + /** + * Set value + * + * @param string $value + * @return \helloworld\HelloReply + */ + public function setMessage( $value){ + return $this->_set(1, $value); + } + } +} + +namespace helloworld { + + class GreeterClient{ + + private $rpc_impl; + + public function __construct($rpc_impl) { + $this->rpc_impl = $rpc_impl; + } + /** + * @param helloworld\HelloRequest $input + */ + public function SayHello(\helloworld\HelloRequest $argument, $metadata = array()) { + return $this->rpc_impl->_simpleRequest('/helloworld.Greeter/SayHello', $argument, '\helloworld\HelloReply::deserialize', $metadata); + } + } +} diff --git a/examples/php/helloworld.proto b/examples/php/helloworld.proto new file mode 100644 index 00000000000..ad8f7a15249 --- /dev/null +++ b/examples/php/helloworld.proto @@ -0,0 +1,50 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto2"; + +option java_package = "ex.grpc"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + optional string name = 1; +} + +// The response message containing the greetings +message HelloReply { + optional string message = 1; +} diff --git a/examples/php/route_guide/README.md b/examples/php/route_guide/README.md new file mode 100644 index 00000000000..e5230ae4e43 --- /dev/null +++ b/examples/php/route_guide/README.md @@ -0,0 +1,262 @@ +#gRPC Basics: PHP + +This tutorial provides a basic PHP programmer's introduction to working with gRPC. By walking through this example you'll learn how to: + +- Define a service in a .proto file. +- Generate client code using the protocol buffer compiler. +- Use the PHP gRPC API to write a simple client for your service. + +It assumes a passing familiarity with [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). Note that the example in this tutorial uses the proto2 version of the protocol buffers language. + +Also note that currently you can only create clients in PHP for gRPC services - you can find out how to create gRPC servers in our other tutorials, e.g. [Node.js](examples/node/route_guide). + +This isn't a comprehensive guide to using gRPC in PHP: more reference documentation is coming soon. + +- [Why use gRPC?](#why-grpc) +- [Example code and setup](#setup) +- [Try it out!](#try) +- [Defining the service](#proto) +- [Generating client code](#protoc) +- [Creating the client](#client) + + + +## Why use gRPC? + +With gRPC you can define your service once in a .proto file and implement clients and servers in any of gRPC's supported languages, which in turn can be run in environments ranging from servers inside Google to your own tablet - all the complexity of communication between different languages and environments is handled for you by gRPC. You also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating. + + + +## Example code and setup + +The example code for our tutorial is in [examples/php/route_guide](examples/php/route_guide). To download the example, clone this repository by running the following command: +```shell +$ git clone https://github.com/grpc/grpc.git +``` + +Then change your current directory to `examples/php/route_guide`: +```shell +$ cd examples/php/route_guide +``` + +Our example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients. + +You also should have the relevant tools installed to generate the client interface code (and a server in another language, for testing). You can obtain the latter by following [these setup instructions](https://github.com/grpc/homebrew-grpc). + + + +## Try it out! + +To try the sample app, we need a gRPC server running locally. Let's compile and run, for example, the Node.js server in this repository: + +```shell +$ cd ../../node +$ npm install +$ cd route_guide +$ nodejs ./route_guide_server.js --db_path=route_guide_db.json +``` + +Run the PHP client (in a different terminal): + +```shell +$ ./run_route_guide_client.sh +``` + +The next sections guide you step-by-step through how this proto service is defined, how to generate a client library from it, and how to create a client stub that uses that library. + + + +## Defining the service + +First let's look at how the service we're using is defined. A gRPC *service* and its method *request* and *response* types using [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). You can see the complete .proto file for our example in [`examples/protos/route_guide.proto`](examples/protos/route_guide.proto). + +To define a service, you specify a named `service` in your .proto file: + +```protobuf +service RouteGuide { + ... +} +``` + +Then you define `rpc` methods inside your service definition, specifying their request and response types. Protocol buffers let you define four kinds of service method, all of which are used in the `RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server and receives a response later, just like a normal remote procedure call. +```protobuf + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *response-streaming RPC* where the client sends a request to the server and gets back a stream of response messages. You specify a response-streaming method by placing the `stream` keyword before the *response* type. +```protobuf + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *request-streaming RPC* where the client sends a sequence of messages to the server. Once the client has finished writing the messages, it waits for the server to read them all and return its response. You specify a request-streaming method by placing the `stream` keyword before the *request* type. +```protobuf + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectional streaming RPC* where both sides send a sequence of messages to the other. The two streams operate independently, so clients and servers can read and write in whatever order they like: for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved. You specify this type of method by placing the `stream` keyword before both the request and the response. +```protobuf + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Our .proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods - for example, here's the `Point` message type: +```protobuf +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + + + +## Generating client code + +The PHP client stub implementation of the proto files can be generated by the [`protoc-gen-php`](https://github.com/datto/protobuf-php) tool. To install the tool: + +```sh +$ cd examples/php +$ php composer.phar install +$ cd vendor/datto/protobuf-php +$ gem install rake ronn +$ rake pear:package version=1.0 +$ sudo pear install Protobuf-1.0.tgz +``` + +To generate the client stub implementation .php file: + +```sh +$ cd php/route_guide +$ protoc-gen-php -i . -o . ./route_guide.proto +``` + +A `route_guide.php` file will be generated in the `php/route_guide` directory. You do not need to modify the file. + +To load the generated client stub file, simply `require` it in your PHP application: + +```php +require dirname(__FILE__) . '/route_guide.php'; +``` + +The file contains: +- All the protocol buffer code to populate, serialize, and retrieve our request and response message types. +- A class called `examples\RouteGuideClient` that lets clients call the methods defined in the `RouteGuide` service. + + + +## Creating the client + +In this section, we'll look at creating a PHP client for our `RouteGuide` service. You can see our complete example client code in [examples/php/route_guide/route_guide_client.php](examples/php/route_guide/route_guide_client.php). + +### Constructing a client object + +To call service methods, we first need to create a client object, an instance of the generated `RouteGuideClient` class. The constructor of the class expects the server address and port we want to connect to: + +```php +$client = new examples\RouteGuideClient(new Grpc\BaseStub('localhost:50051', [])); +``` + +### Calling service methods + +Now let's look at how we call our service methods. + +#### Simple RPC + +Calling the simple RPC `GetFeature` is nearly as straightforward as calling a local asynchronous method. + +```php + $point = new examples\Point(); + $point->setLatitude(409146138); + $point->setLongitude(-746188906); + list($feature, $status) = $client->GetFeature($point)->wait(); +``` + +As you can see, we create and populate a request object, i.e. an `examples\Point` object. Then, we call the method on the stub, passing it the request object. If there is no error, then we can read the response information from the server from our response object, i.e. an `examples\Feature` object. + +```php + print sprintf("Found %s \n at %f, %f\n", $feature->getName(), + $feature->getLocation()->getLatitude() / COORD_FACTOR, + $feature->getLocation()->getLongitude() / COORD_FACTOR); +``` + +#### Streaming RPCs + +Now let's look at our streaming methods. Here's where we call the server-side streaming method `ListFeatures`, which returns a stream of geographical `Feature`s: + +```php + $lo_point = new examples\Point(); + $hi_point = new examples\Point(); + + $lo_point->setLatitude(400000000); + $lo_point->setLongitude(-750000000); + $hi_point->setLatitude(420000000); + $hi_point->setLongitude(-730000000); + + $rectangle = new examples\Rectangle(); + $rectangle->setLo($lo_point); + $rectangle->setHi($hi_point); + + $call = $client->ListFeatures($rectangle); + // an iterator over the server streaming responses + $features = $call->responses(); + foreach ($features as $feature) { + // process each feature + } // the loop will end when the server indicates there is no more responses to be sent. +``` + +The `$call->responses()` method call returns an iterator. When the server sends a response, a `$feature` object will be returned in the `foreach` loop, until the server indiciates that there will be no more responses to be sent. + +The client-side streaming method `RecordRoute` is similar, except there we pass the method an iterator and get back a `examples\RouteSummary`. + +```php + $points_iter = function($db) { + for ($i = 0; $i < $num_points; $i++) { + $point = new examples\Point(); + $point->setLatitude($lat); + $point->setLongitude($long); + yield $point; + } + }; + // $points_iter is an iterator simulating client streaming + list($route_summary, $status) = + $client->RecordRoute($points_iter($db))->wait(); +``` + +Finally, let's look at our bidirectional streaming RPC `routeChat()`. In this case, we just pass a context to the method and get back a `BidiStreamingCall` stream object, which we can use to both write and read messages. + +```php +$call = $client->RouteChat(); +``` + +To write messages from the client: + +```php + foreach ($notes as $n) { + $route_note = new examples\RouteNote(); + $call->write($route_note); + } + $call->writesDone(); +``` + +To read messages from the server: + +```php + while ($route_note_reply = $call->read()) { + // process $route_note_reply + } +``` + +Each side will always get the other's messages in the order they were written, both the client and server can read and write in any order — the streams operate completely independently. diff --git a/examples/php/route_guide/route_guide.php b/examples/php/route_guide/route_guide.php new file mode 100644 index 00000000000..a836e03b55b --- /dev/null +++ b/examples/php/route_guide/route_guide.php @@ -0,0 +1,731 @@ +number = 1; + $f->name = "latitude"; + $f->type = \DrSlump\Protobuf::TYPE_INT32; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->default = 0; + $descriptor->addField($f); + + // OPTIONAL INT32 longitude = 2 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 2; + $f->name = "longitude"; + $f->type = \DrSlump\Protobuf::TYPE_INT32; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->default = 0; + $descriptor->addField($f); + + foreach (self::$__extensions as $cb) { + $descriptor->addField($cb(), true); + } + + return $descriptor; + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasLatitude(){ + return $this->_has(1); + } + + /** + * Clear value + * + * @return \examples\Point + */ + public function clearLatitude(){ + return $this->_clear(1); + } + + /** + * Get value + * + * @return int + */ + public function getLatitude(){ + return $this->_get(1); + } + + /** + * Set value + * + * @param int $value + * @return \examples\Point + */ + public function setLatitude( $value){ + return $this->_set(1, $value); + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasLongitude(){ + return $this->_has(2); + } + + /** + * Clear value + * + * @return \examples\Point + */ + public function clearLongitude(){ + return $this->_clear(2); + } + + /** + * Get value + * + * @return int + */ + public function getLongitude(){ + return $this->_get(2); + } + + /** + * Set value + * + * @param int $value + * @return \examples\Point + */ + public function setLongitude( $value){ + return $this->_set(2, $value); + } + } +} + +namespace examples { + + class Rectangle extends \DrSlump\Protobuf\Message { + + /** @var \examples\Point */ + public $lo = null; + + /** @var \examples\Point */ + public $hi = null; + + + /** @var \Closure[] */ + protected static $__extensions = array(); + + public static function descriptor() + { + $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'examples.Rectangle'); + + // OPTIONAL MESSAGE lo = 1 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 1; + $f->name = "lo"; + $f->type = \DrSlump\Protobuf::TYPE_MESSAGE; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->reference = '\examples\Point'; + $descriptor->addField($f); + + // OPTIONAL MESSAGE hi = 2 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 2; + $f->name = "hi"; + $f->type = \DrSlump\Protobuf::TYPE_MESSAGE; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->reference = '\examples\Point'; + $descriptor->addField($f); + + foreach (self::$__extensions as $cb) { + $descriptor->addField($cb(), true); + } + + return $descriptor; + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasLo(){ + return $this->_has(1); + } + + /** + * Clear value + * + * @return \examples\Rectangle + */ + public function clearLo(){ + return $this->_clear(1); + } + + /** + * Get value + * + * @return \examples\Point + */ + public function getLo(){ + return $this->_get(1); + } + + /** + * Set value + * + * @param \examples\Point $value + * @return \examples\Rectangle + */ + public function setLo(\examples\Point $value){ + return $this->_set(1, $value); + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasHi(){ + return $this->_has(2); + } + + /** + * Clear value + * + * @return \examples\Rectangle + */ + public function clearHi(){ + return $this->_clear(2); + } + + /** + * Get value + * + * @return \examples\Point + */ + public function getHi(){ + return $this->_get(2); + } + + /** + * Set value + * + * @param \examples\Point $value + * @return \examples\Rectangle + */ + public function setHi(\examples\Point $value){ + return $this->_set(2, $value); + } + } +} + +namespace examples { + + class Feature extends \DrSlump\Protobuf\Message { + + /** @var string */ + public $name = null; + + /** @var \examples\Point */ + public $location = null; + + + /** @var \Closure[] */ + protected static $__extensions = array(); + + public static function descriptor() + { + $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'examples.Feature'); + + // OPTIONAL STRING name = 1 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 1; + $f->name = "name"; + $f->type = \DrSlump\Protobuf::TYPE_STRING; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $descriptor->addField($f); + + // OPTIONAL MESSAGE location = 2 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 2; + $f->name = "location"; + $f->type = \DrSlump\Protobuf::TYPE_MESSAGE; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->reference = '\examples\Point'; + $descriptor->addField($f); + + foreach (self::$__extensions as $cb) { + $descriptor->addField($cb(), true); + } + + return $descriptor; + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasName(){ + return $this->_has(1); + } + + /** + * Clear value + * + * @return \examples\Feature + */ + public function clearName(){ + return $this->_clear(1); + } + + /** + * Get value + * + * @return string + */ + public function getName(){ + return $this->_get(1); + } + + /** + * Set value + * + * @param string $value + * @return \examples\Feature + */ + public function setName( $value){ + return $this->_set(1, $value); + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasLocation(){ + return $this->_has(2); + } + + /** + * Clear value + * + * @return \examples\Feature + */ + public function clearLocation(){ + return $this->_clear(2); + } + + /** + * Get value + * + * @return \examples\Point + */ + public function getLocation(){ + return $this->_get(2); + } + + /** + * Set value + * + * @param \examples\Point $value + * @return \examples\Feature + */ + public function setLocation(\examples\Point $value){ + return $this->_set(2, $value); + } + } +} + +namespace examples { + + class RouteNote extends \DrSlump\Protobuf\Message { + + /** @var \examples\Point */ + public $location = null; + + /** @var string */ + public $message = null; + + + /** @var \Closure[] */ + protected static $__extensions = array(); + + public static function descriptor() + { + $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'examples.RouteNote'); + + // OPTIONAL MESSAGE location = 1 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 1; + $f->name = "location"; + $f->type = \DrSlump\Protobuf::TYPE_MESSAGE; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->reference = '\examples\Point'; + $descriptor->addField($f); + + // OPTIONAL STRING message = 2 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 2; + $f->name = "message"; + $f->type = \DrSlump\Protobuf::TYPE_STRING; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $descriptor->addField($f); + + foreach (self::$__extensions as $cb) { + $descriptor->addField($cb(), true); + } + + return $descriptor; + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasLocation(){ + return $this->_has(1); + } + + /** + * Clear value + * + * @return \examples\RouteNote + */ + public function clearLocation(){ + return $this->_clear(1); + } + + /** + * Get value + * + * @return \examples\Point + */ + public function getLocation(){ + return $this->_get(1); + } + + /** + * Set value + * + * @param \examples\Point $value + * @return \examples\RouteNote + */ + public function setLocation(\examples\Point $value){ + return $this->_set(1, $value); + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasMessage(){ + return $this->_has(2); + } + + /** + * Clear value + * + * @return \examples\RouteNote + */ + public function clearMessage(){ + return $this->_clear(2); + } + + /** + * Get value + * + * @return string + */ + public function getMessage(){ + return $this->_get(2); + } + + /** + * Set value + * + * @param string $value + * @return \examples\RouteNote + */ + public function setMessage( $value){ + return $this->_set(2, $value); + } + } +} + +namespace examples { + + class RouteSummary extends \DrSlump\Protobuf\Message { + + /** @var int */ + public $point_count = 0; + + /** @var int */ + public $feature_count = 0; + + /** @var int */ + public $distance = 0; + + /** @var int */ + public $elapsed_time = 0; + + + /** @var \Closure[] */ + protected static $__extensions = array(); + + public static function descriptor() + { + $descriptor = new \DrSlump\Protobuf\Descriptor(__CLASS__, 'examples.RouteSummary'); + + // OPTIONAL INT32 point_count = 1 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 1; + $f->name = "point_count"; + $f->type = \DrSlump\Protobuf::TYPE_INT32; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->default = 0; + $descriptor->addField($f); + + // OPTIONAL INT32 feature_count = 2 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 2; + $f->name = "feature_count"; + $f->type = \DrSlump\Protobuf::TYPE_INT32; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->default = 0; + $descriptor->addField($f); + + // OPTIONAL INT32 distance = 3 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 3; + $f->name = "distance"; + $f->type = \DrSlump\Protobuf::TYPE_INT32; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->default = 0; + $descriptor->addField($f); + + // OPTIONAL INT32 elapsed_time = 4 + $f = new \DrSlump\Protobuf\Field(); + $f->number = 4; + $f->name = "elapsed_time"; + $f->type = \DrSlump\Protobuf::TYPE_INT32; + $f->rule = \DrSlump\Protobuf::RULE_OPTIONAL; + $f->default = 0; + $descriptor->addField($f); + + foreach (self::$__extensions as $cb) { + $descriptor->addField($cb(), true); + } + + return $descriptor; + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasPointCount(){ + return $this->_has(1); + } + + /** + * Clear value + * + * @return \examples\RouteSummary + */ + public function clearPointCount(){ + return $this->_clear(1); + } + + /** + * Get value + * + * @return int + */ + public function getPointCount(){ + return $this->_get(1); + } + + /** + * Set value + * + * @param int $value + * @return \examples\RouteSummary + */ + public function setPointCount( $value){ + return $this->_set(1, $value); + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasFeatureCount(){ + return $this->_has(2); + } + + /** + * Clear value + * + * @return \examples\RouteSummary + */ + public function clearFeatureCount(){ + return $this->_clear(2); + } + + /** + * Get value + * + * @return int + */ + public function getFeatureCount(){ + return $this->_get(2); + } + + /** + * Set value + * + * @param int $value + * @return \examples\RouteSummary + */ + public function setFeatureCount( $value){ + return $this->_set(2, $value); + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasDistance(){ + return $this->_has(3); + } + + /** + * Clear value + * + * @return \examples\RouteSummary + */ + public function clearDistance(){ + return $this->_clear(3); + } + + /** + * Get value + * + * @return int + */ + public function getDistance(){ + return $this->_get(3); + } + + /** + * Set value + * + * @param int $value + * @return \examples\RouteSummary + */ + public function setDistance( $value){ + return $this->_set(3, $value); + } + + /** + * Check if has a value + * + * @return boolean + */ + public function hasElapsedTime(){ + return $this->_has(4); + } + + /** + * Clear value + * + * @return \examples\RouteSummary + */ + public function clearElapsedTime(){ + return $this->_clear(4); + } + + /** + * Get value + * + * @return int + */ + public function getElapsedTime(){ + return $this->_get(4); + } + + /** + * Set value + * + * @param int $value + * @return \examples\RouteSummary + */ + public function setElapsedTime( $value){ + return $this->_set(4, $value); + } + } +} + +namespace examples { + + class RouteGuideClient{ + + private $rpc_impl; + + public function __construct($rpc_impl) { + $this->rpc_impl = $rpc_impl; + } + /** + * @param examples\Point $input + */ + public function GetFeature(\examples\Point $argument, $metadata = array()) { + return $this->rpc_impl->_simpleRequest('/examples.RouteGuide/GetFeature', $argument, '\examples\Feature::deserialize', $metadata); + } + /** + * @param examples\Rectangle $input + */ + public function ListFeatures($argument, $metadata = array()) { + return $this->rpc_impl->_serverStreamRequest('/examples.RouteGuide/ListFeatures', $argument, '\examples\Feature::deserialize', $metadata); + } + /** + * @param examples\Point $input + */ + public function RecordRoute($arguments, $metadata = array()) { + return $this->rpc_impl->_clientStreamRequest('/examples.RouteGuide/RecordRoute', $arguments, '\examples\RouteSummary::deserialize', $metadata); + } + /** + * @param examples\RouteNote $input + */ + public function RouteChat($metadata = array()) { + return $this->rpc_impl->_bidiRequest('/examples.RouteGuide/RouteChat', '\examples\RouteNote::deserialize', $metadata); + } + } +} diff --git a/examples/php/route_guide/route_guide.proto b/examples/php/route_guide/route_guide.proto new file mode 100644 index 00000000000..0947184dbbd --- /dev/null +++ b/examples/php/route_guide/route_guide.proto @@ -0,0 +1,120 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto2"; + +option java_package = "io.grpc.examples"; + +package examples; + +// Interface exported by the server. +service RouteGuide { + // A simple RPC. + // + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} + + // A server-to-client streaming RPC. + // + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} + + // A client-to-server streaming RPC. + // + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} + + // A Bidirectional streaming RPC. + // + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +} + +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + optional int32 latitude = 1 [default = 0]; + optional int32 longitude = 2 [default = 0]; +} + +// A latitude-longitude rectangle, represented as two diagonally opposite +// points "lo" and "hi". +message Rectangle { + // One corner of the rectangle. + optional Point lo = 1; + + // The other corner of the rectangle. + optional Point hi = 2; +} + +// A feature names something at a given point. +// +// If a feature could not be named, the name is empty. +message Feature { + // The name of the feature. + optional string name = 1; + + // The point where the feature is detected. + optional Point location = 2; +} + +// A RouteNote is a message sent while at a given point. +message RouteNote { + // The location from which the message is sent. + optional Point location = 1; + + // The message to be sent. + optional string message = 2; +} + +// A RouteSummary is received in response to a RecordRoute rpc. +// +// It contains the number of individual points received, the number of +// detected features, and the total distance covered as the cumulative sum of +// the distance between each point. +message RouteSummary { + // The number of points received. + optional int32 point_count = 1 [default = 0]; + + // The number of known features passed while traversing the route. + optional int32 feature_count = 2 [default = 0]; + + // The distance covered in metres. + optional int32 distance = 3 [default = 0]; + + // The duration of the traversal in seconds. + optional int32 elapsed_time = 4 [default = 0]; +} diff --git a/examples/php/route_guide/route_guide_client.php b/examples/php/route_guide/route_guide_client.php new file mode 100644 index 00000000000..6d9ae58b66c --- /dev/null +++ b/examples/php/route_guide/route_guide_client.php @@ -0,0 +1,205 @@ +getName(); + if (!$name) { + $name_str = "no feature"; + } else { + $name_str = "feature called $name"; + } + print sprintf("Found %s \n at %f, %f\n", $name_str, + $feature->getLocation()->getLatitude() / COORD_FACTOR, + $feature->getLocation()->getLongitude() / COORD_FACTOR); +} + +/** + * Run the getFeature demo. Calls getFeature with a point known to have a + * feature and a point known not to have a feature. + */ +function runGetFeature() { + print "Running GetFeature...\n"; + global $client; + + $point = new examples\Point(); + $points = array( + array(409146138, -746188906), + array(0, 0), + ); + + foreach ($points as $p) { + $point->setLatitude($p[0]); + $point->setLongitude($p[1]); + // make a unary grpc call + list($feature, $status) = $client->GetFeature($point)->wait(); + printFeature($feature); + } +} + +/** + * Run the listFeatures demo. Calls listFeatures with a rectangle + * containing all of the features in the pre-generated + * database. Prints each response as it comes in. + */ +function runListFeatures() { + print "Running ListFeatures...\n"; + global $client; + + $lo_point = new examples\Point(); + $hi_point = new examples\Point(); + + $lo_point->setLatitude(400000000); + $lo_point->setLongitude(-750000000); + $hi_point->setLatitude(420000000); + $hi_point->setLongitude(-730000000); + + $rectangle = new examples\Rectangle(); + $rectangle->setLo($lo_point); + $rectangle->setHi($hi_point); + + $call = $client->ListFeatures($rectangle); + // an iterator over the server streaming responses + $features = $call->responses(); + foreach ($features as $feature) { + printFeature($feature); + } +} + +/** + * Run the recordRoute demo. Sends several randomly chosen points from the + * pre-generated feature database with a variable delay in between. Prints + * the statistics when they are sent from the server. + */ +function runRecordRoute() { + print "Running RecordRoute...\n"; + global $client, $argv; + + $db = json_decode(file_get_contents($argv[1]), true); + $points_iter = function($db) { + $num_points_in_db = count($db); + $num_points = 10; + for ($i = 0; $i < $num_points; $i++) { + $point = new examples\Point(); + $index = rand(0, $num_points_in_db - 1); + $lat = $db[$index]['location']['latitude']; + $long = $db[$index]['location']['longitude']; + $feature_name = $db[$index]['name']; + $point->setLatitude($lat); + $point->setLongitude($long); + print sprintf("Visiting point %f, %f,\n with feature name: %s\n", + $lat / COORD_FACTOR, $long / COORD_FACTOR, + $feature_name ? $feature_name : ''); + usleep(rand(300000, 800000)); + yield $point; + } + }; + // $points_iter is an iterator simulating client streaming + list($route_summary, $status) = + $client->RecordRoute($points_iter($db))->wait(); + print sprintf("Finished trip with %d points\nPassed %d features\n". + "Travelled %d meters\nIt took %d seconds\n", + $route_summary->getPointCount(), + $route_summary->getFeatureCount(), + $route_summary->getDistance(), + $route_summary->getElapsedTime()); +} + +/** + * Run the routeChat demo. Send some chat messages, and print any chat + * messages that are sent from the server. + */ +function runRouteChat() { + print "Running RouteChat...\n"; + global $client; + + // start the bidirectional streaming call + $call = $client->RouteChat(); + + $notes = array( + array(1, 1, 'first message'), + array(1, 2, 'second message'), + array(2, 1, 'third message'), + array(1, 1, 'fourth message'), + array(1, 1, 'fifth message'), + ); + + foreach ($notes as $n) { + $point = new examples\Point(); + $point->setLatitude($lat = $n[0]); + $point->setLongitude($long = $n[1]); + + $route_note = new examples\RouteNote(); + $route_note->setLocation($point); + $route_note->setMessage($message = $n[2]); + + print sprintf("Sending message: '%s' at (%d, %d)\n", + $message, $lat, $long); + // send a bunch of messages to the server + $call->write($route_note); + } + $call->writesDone(); + + // read from the server until there's no more + while ($route_note_reply = $call->read()) { + print sprintf("Previous left message at (%d, %d): '%s'\n", + $route_note_reply->getLocation()->getLatitude(), + $route_note_reply->getLocation()->getLongitude(), + $route_note_reply->getMessage()); + } +} + +/** + * Run all of the demos in order + */ +function main() { + runGetFeature(); + runListFeatures(); + runRecordRoute(); + runRouteChat(); +} + +if (empty($argv[1])) { + print "Usage: php -d extension=grpc.so route_guide_client.php " . + "\n"; + exit(1); +} +main(); diff --git a/examples/php/route_guide/run_route_guide_client.sh b/examples/php/route_guide/run_route_guide_client.sh new file mode 100755 index 00000000000..e5ca07796be --- /dev/null +++ b/examples/php/route_guide/run_route_guide_client.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set -e +cd $(dirname $0) +command -v brew >/dev/null 2>&1 && \ + extension_dir="-d extension_dir="`brew --prefix`/opt/grpc-php +php $extension_dir -d extension=grpc.so \ + route_guide_client.php ../../node/route_guide/route_guide_db.json diff --git a/examples/php/run_greeter_client.sh b/examples/php/run_greeter_client.sh new file mode 100755 index 00000000000..2906de9af89 --- /dev/null +++ b/examples/php/run_greeter_client.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +set -e +cd $(dirname $0) +command -v brew >/dev/null 2>&1 && \ + extension_dir="-d extension_dir="`brew --prefix`/opt/grpc-php +php $extension_dir -d extension=grpc.so greeter_client.php $1 diff --git a/examples/protos/README.md b/examples/protos/README.md new file mode 100644 index 00000000000..48df7c8943e --- /dev/null +++ b/examples/protos/README.md @@ -0,0 +1,8 @@ +# Example protos + +## Contents + +- [helloworld.proto] + - The simple example used in the overview. +- [route_guide.proto] + - An example service described in detail in the tutorial. diff --git a/examples/protos/auth_sample.proto b/examples/protos/auth_sample.proto new file mode 100644 index 00000000000..a49caca657e --- /dev/null +++ b/examples/protos/auth_sample.proto @@ -0,0 +1,57 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +package grpc.testing; + +option objc_class_prefix = "AUTH"; + +// Unary request. +message Request { + // Whether Response should include username. + bool fill_username = 4; + + // Whether Response should include OAuth scope. + bool fill_oauth_scope = 5; +} + +// Unary response, as configured by the request. +message Response { + // The user the request came from, for verifying authentication was + // successful. + string username = 2; + // OAuth scope. + string oauth_scope = 3; +} + +service TestService { + // One request followed by one response. + rpc UnaryCall(Request) returns (Response); +} diff --git a/examples/protos/hellostreamingworld.proto b/examples/protos/hellostreamingworld.proto new file mode 100644 index 00000000000..bd5af3b2d5b --- /dev/null +++ b/examples/protos/hellostreamingworld.proto @@ -0,0 +1,54 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "ex.grpc"; +option objc_class_prefix = "HSW"; + +package hellostreamingworld; + +// The greeting service definition. +service MultiGreeter { + // Sends multiple greetings + rpc sayHello (HelloRequest) returns (stream HelloReply) {} +} + +// The request message containing the user's name and how many greetings +// they want. +message HelloRequest { + string name = 1; + string num_greetings = 2; +} + +// A response message containing a greeting +message HelloReply { + string message = 1; +} + diff --git a/examples/protos/helloworld.proto b/examples/protos/helloworld.proto new file mode 100644 index 00000000000..7d58870a708 --- /dev/null +++ b/examples/protos/helloworld.proto @@ -0,0 +1,51 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "io.grpc.examples"; +option objc_class_prefix = "HLW"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/examples/protos/route_guide.proto b/examples/protos/route_guide.proto new file mode 100644 index 00000000000..bfde5f1ead6 --- /dev/null +++ b/examples/protos/route_guide.proto @@ -0,0 +1,124 @@ +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +syntax = "proto3"; + +option java_package = "ex.grpc"; +option objc_class_prefix = "RTG"; + +package examples; + +// Interface exported by the server. +service RouteGuide { + // A simple RPC. + // + // Obtains the feature at a given position. + // + // A feature with an empty name is returned if there's no feature at the given + // position. + rpc GetFeature(Point) returns (Feature) {} + + // A server-to-client streaming RPC. + // + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} + + // A client-to-server streaming RPC. + // + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} + + // A Bidirectional streaming RPC. + // + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +} + +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} + +// A latitude-longitude rectangle, represented as two diagonally opposite +// points "lo" and "hi". +message Rectangle { + // One corner of the rectangle. + Point lo = 1; + + // The other corner of the rectangle. + Point hi = 2; +} + +// A feature names something at a given point. +// +// If a feature could not be named, the name is empty. +message Feature { + // The name of the feature. + string name = 1; + + // The point where the feature is detected. + Point location = 2; +} + +// A RouteNote is a message sent while at a given point. +message RouteNote { + // The location from which the message is sent. + Point location = 1; + + // The message to be sent. + string message = 2; +} + +// A RouteSummary is received in response to a RecordRoute rpc. +// +// It contains the number of individual points received, the number of +// detected features, and the total distance covered as the cumulative sum of +// the distance between each point. +message RouteSummary { + // The number of points received. + int32 point_count = 1; + + // The number of known features passed while traversing the route. + int32 feature_count = 2; + + // The distance covered in metres. + int32 distance = 3; + + // The duration of the traversal in seconds. + int32 elapsed_time = 4; +} diff --git a/examples/pubsub/README b/examples/pubsub/README deleted file mode 100644 index 36fcb084834..00000000000 --- a/examples/pubsub/README +++ /dev/null @@ -1,22 +0,0 @@ -NOTE: This example does not build and is being updated. -Experimental example code, likely to change. -Users should not attempt to run this code till this warning is removed. - -C++ Client implementation for Cloud Pub/Sub service -(https://developers.google.com/apis-explorer/#p/pubsub/v1beta1/). - -"Google Cloud Pub/Sub" API needs to be enabled at -https://console.developers.google.com/project to open the access for a client. -Select the project name, select the "APIs" under "APIs & auth", and turn -on "Google Cloud Pub/Sub" API. - -To run the client from Google Compute Engine (GCE), the GCE instance needs to -be created with scope "https://www.googleapis.com/auth/cloud-platform" as below: - -gcloud compute instances create instance-name - --image debian-7 --scopes https://www.googleapis.com/auth/cloud-platform - - -To run the client: -make pubsub_client -bins/opt/pubsub_client --project_id="your project id" diff --git a/examples/pubsub/main.cc b/examples/pubsub/main.cc deleted file mode 100644 index 32102dcb5cd..00000000000 --- a/examples/pubsub/main.cc +++ /dev/null @@ -1,146 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "examples/pubsub/publisher.h" -#include "examples/pubsub/subscriber.h" -#include "test/cpp/util/test_config.h" - -DEFINE_int32(server_port, 443, "Server port."); -DEFINE_string(server_host, "pubsub-staging.googleapis.com", - "Server host to connect to"); -DEFINE_string(project_id, "", "GCE project id such as stoked-keyword-656"); - -namespace { - -const char kTopic[] = "testtopics"; -const char kSubscriptionName[] = "testsubscription"; -const char kMessageData[] = "Test Data"; - -} // namespace - -int main(int argc, char** argv) { - grpc::testing::InitTest(&argc, &argv, true); - gpr_log(GPR_INFO, "Start PUBSUB client"); - - std::ostringstream ss; - - ss << FLAGS_server_host << ":" << FLAGS_server_port; - - std::shared_ptr creds = grpc::GoogleDefaultCredentials(); - std::shared_ptr channel = - grpc::CreateChannel(ss.str(), creds, grpc::ChannelArguments()); - - grpc::examples::pubsub::Publisher publisher(channel); - grpc::examples::pubsub::Subscriber subscriber(channel); - - GPR_ASSERT(FLAGS_project_id != ""); - ss.str(""); - ss << "/topics/" << FLAGS_project_id << "/" << kTopic; - grpc::string topic = ss.str(); - - ss.str(""); - ss << FLAGS_project_id << "/" << kSubscriptionName; - grpc::string subscription_name = ss.str(); - - // Clean up test topic and subcription if they exist before. - grpc::string subscription_topic; - if (subscriber.GetSubscription(subscription_name, &subscription_topic) - .IsOk()) { - subscriber.DeleteSubscription(subscription_name); - } - - if (publisher.GetTopic(topic).IsOk()) publisher.DeleteTopic(topic); - - grpc::Status s = publisher.CreateTopic(topic); - gpr_log(GPR_INFO, "Create topic returns code %d, %s", s.code(), - s.details().c_str()); - GPR_ASSERT(s.IsOk()); - - s = publisher.GetTopic(topic); - gpr_log(GPR_INFO, "Get topic returns code %d, %s", s.code(), - s.details().c_str()); - GPR_ASSERT(s.IsOk()); - - std::vector topics; - s = publisher.ListTopics(FLAGS_project_id, &topics); - gpr_log(GPR_INFO, "List topic returns code %d, %s", s.code(), - s.details().c_str()); - bool topic_found = false; - for (unsigned int i = 0; i < topics.size(); i++) { - if (topics[i] == topic) topic_found = true; - gpr_log(GPR_INFO, "topic: %s", topics[i].c_str()); - } - GPR_ASSERT(s.IsOk()); - GPR_ASSERT(topic_found); - - s = subscriber.CreateSubscription(topic, subscription_name); - gpr_log(GPR_INFO, "create subscrption returns code %d, %s", s.code(), - s.details().c_str()); - GPR_ASSERT(s.IsOk()); - - s = publisher.Publish(topic, kMessageData); - gpr_log(GPR_INFO, "Publish %s returns code %d, %s", kMessageData, s.code(), - s.details().c_str()); - GPR_ASSERT(s.IsOk()); - - grpc::string data; - s = subscriber.Pull(subscription_name, &data); - gpr_log(GPR_INFO, "Pull %s", data.c_str()); - - s = subscriber.DeleteSubscription(subscription_name); - gpr_log(GPR_INFO, "Delete subscription returns code %d, %s", s.code(), - s.details().c_str()); - GPR_ASSERT(s.IsOk()); - - s = publisher.DeleteTopic(topic); - gpr_log(GPR_INFO, "Delete topic returns code %d, %s", s.code(), - s.details().c_str()); - GPR_ASSERT(s.IsOk()); - - subscriber.Shutdown(); - publisher.Shutdown(); - return 0; -} diff --git a/examples/pubsub/publisher.cc b/examples/pubsub/publisher.cc deleted file mode 100644 index fd38ca92ed9..00000000000 --- a/examples/pubsub/publisher.cc +++ /dev/null @@ -1,121 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include - -#include "examples/pubsub/publisher.h" - -using tech::pubsub::Topic; -using tech::pubsub::DeleteTopicRequest; -using tech::pubsub::GetTopicRequest; -using tech::pubsub::PublisherService; -using tech::pubsub::ListTopicsRequest; -using tech::pubsub::ListTopicsResponse; -using tech::pubsub::PublishRequest; -using tech::pubsub::PubsubMessage; - -namespace grpc { -namespace examples { -namespace pubsub { - -Publisher::Publisher(std::shared_ptr channel) - : stub_(PublisherService::NewStub(channel)) {} - -void Publisher::Shutdown() { stub_.reset(); } - -Status Publisher::CreateTopic(const grpc::string& topic) { - Topic request; - Topic response; - request.set_name(topic); - ClientContext context; - - return stub_->CreateTopic(&context, request, &response); -} - -Status Publisher::ListTopics(const grpc::string& project_id, - std::vector* topics) { - ListTopicsRequest request; - ListTopicsResponse response; - ClientContext context; - - std::ostringstream ss; - ss << "cloud.googleapis.com/project in (/projects/" << project_id << ")"; - request.set_query(ss.str()); - - Status s = stub_->ListTopics(&context, request, &response); - - tech::pubsub::Topic topic; - for (int i = 0; i < response.topic_size(); i++) { - topic = response.topic(i); - topics->push_back(topic.name()); - } - - return s; -} - -Status Publisher::GetTopic(const grpc::string& topic) { - GetTopicRequest request; - Topic response; - ClientContext context; - - request.set_topic(topic); - - return stub_->GetTopic(&context, request, &response); -} - -Status Publisher::DeleteTopic(const grpc::string& topic) { - DeleteTopicRequest request; - proto2::Empty response; - ClientContext context; - - request.set_topic(topic); - - return stub_->DeleteTopic(&context, request, &response); -} - -Status Publisher::Publish(const grpc::string& topic, const grpc::string& data) { - PublishRequest request; - proto2::Empty response; - ClientContext context; - - request.mutable_message()->set_data(data); - request.set_topic(topic); - - return stub_->Publish(&context, request, &response); -} - -} // namespace pubsub -} // namespace examples -} // namespace grpc diff --git a/examples/pubsub/publisher_test.cc b/examples/pubsub/publisher_test.cc deleted file mode 100644 index c2eb295ef27..00000000000 --- a/examples/pubsub/publisher_test.cc +++ /dev/null @@ -1,153 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "examples/pubsub/publisher.h" -#include "test/core/util/port.h" -#include "test/core/util/test_config.h" - -using grpc::Channel; - -namespace grpc { -namespace testing { -namespace { - -const char kProjectId[] = "project id"; -const char kTopic[] = "test topic"; -const char kMessageData[] = "test message data"; - -class PublisherServiceImpl : public tech::pubsub::PublisherService::Service { - public: - Status CreateTopic(::grpc::ServerContext* context, - const ::tech::pubsub::Topic* request, - ::tech::pubsub::Topic* response) GRPC_OVERRIDE { - EXPECT_EQ(request->name(), kTopic); - return Status::OK; - } - - Status Publish(ServerContext* context, - const ::tech::pubsub::PublishRequest* request, - ::proto2::Empty* response) GRPC_OVERRIDE { - EXPECT_EQ(request->message().data(), kMessageData); - return Status::OK; - } - - Status GetTopic(ServerContext* context, - const ::tech::pubsub::GetTopicRequest* request, - ::tech::pubsub::Topic* response) GRPC_OVERRIDE { - EXPECT_EQ(request->topic(), kTopic); - return Status::OK; - } - - Status ListTopics( - ServerContext* context, const ::tech::pubsub::ListTopicsRequest* request, - ::tech::pubsub::ListTopicsResponse* response) GRPC_OVERRIDE { - std::ostringstream ss; - ss << "cloud.googleapis.com/project in (/projects/" << kProjectId << ")"; - EXPECT_EQ(request->query(), ss.str()); - response->add_topic()->set_name(kTopic); - return Status::OK; - } - - Status DeleteTopic(ServerContext* context, - const ::tech::pubsub::DeleteTopicRequest* request, - ::proto2::Empty* response) GRPC_OVERRIDE { - EXPECT_EQ(request->topic(), kTopic); - return Status::OK; - } -}; - -class PublisherTest : public ::testing::Test { - protected: - // Setup a server and a client for PublisherService. - void SetUp() GRPC_OVERRIDE { - int port = grpc_pick_unused_port_or_die(); - server_address_ << "localhost:" << port; - ServerBuilder builder; - builder.AddListeningPort(server_address_.str(), - grpc::InsecureServerCredentials()); - builder.RegisterService(&service_); - server_ = builder.BuildAndStart(); - - channel_ = CreateChannel(server_address_.str(), grpc::InsecureCredentials(), - ChannelArguments()); - - publisher_.reset(new grpc::examples::pubsub::Publisher(channel_)); - } - - void TearDown() GRPC_OVERRIDE { - server_->Shutdown(); - publisher_->Shutdown(); - } - - std::ostringstream server_address_; - std::unique_ptr server_; - PublisherServiceImpl service_; - - std::shared_ptr channel_; - - std::unique_ptr publisher_; -}; - -TEST_F(PublisherTest, TestPublisher) { - EXPECT_TRUE(publisher_->CreateTopic(kTopic).IsOk()); - - EXPECT_TRUE(publisher_->Publish(kTopic, kMessageData).IsOk()); - - EXPECT_TRUE(publisher_->GetTopic(kTopic).IsOk()); - - std::vector topics; - EXPECT_TRUE(publisher_->ListTopics(kProjectId, &topics).IsOk()); - EXPECT_EQ(topics.size(), static_cast(1)); - EXPECT_EQ(topics[0], kTopic); -} - -} // namespace -} // namespace testing -} // namespace grpc - -int main(int argc, char** argv) { - grpc_test_init(argc, argv); - ::testing::InitGoogleTest(&argc, argv); - gpr_log(GPR_INFO, "Start test ..."); - int result = RUN_ALL_TESTS(); - return result; -} diff --git a/examples/pubsub/subscriber.cc b/examples/pubsub/subscriber.cc deleted file mode 100644 index 0818f501db8..00000000000 --- a/examples/pubsub/subscriber.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include - -#include "examples/pubsub/subscriber.h" - -using tech::pubsub::Topic; -using tech::pubsub::DeleteTopicRequest; -using tech::pubsub::GetTopicRequest; -using tech::pubsub::SubscriberService; -using tech::pubsub::ListTopicsRequest; -using tech::pubsub::ListTopicsResponse; -using tech::pubsub::PublishRequest; -using tech::pubsub::PubsubMessage; - -namespace grpc { -namespace examples { -namespace pubsub { - -Subscriber::Subscriber(std::shared_ptr channel) - : stub_(SubscriberService::NewStub(channel)) {} - -void Subscriber::Shutdown() { stub_.reset(); } - -Status Subscriber::CreateSubscription(const grpc::string& topic, - const grpc::string& name) { - tech::pubsub::Subscription request; - tech::pubsub::Subscription response; - ClientContext context; - - request.set_topic(topic); - request.set_name(name); - - return stub_->CreateSubscription(&context, request, &response); -} - -Status Subscriber::GetSubscription(const grpc::string& name, - grpc::string* topic) { - tech::pubsub::GetSubscriptionRequest request; - tech::pubsub::Subscription response; - ClientContext context; - - request.set_subscription(name); - - Status s = stub_->GetSubscription(&context, request, &response); - *topic = response.topic(); - return s; -} - -Status Subscriber::DeleteSubscription(const grpc::string& name) { - tech::pubsub::DeleteSubscriptionRequest request; - proto2::Empty response; - ClientContext context; - - request.set_subscription(name); - - return stub_->DeleteSubscription(&context, request, &response); -} - -Status Subscriber::Pull(const grpc::string& name, grpc::string* data) { - tech::pubsub::PullRequest request; - tech::pubsub::PullResponse response; - ClientContext context; - - request.set_subscription(name); - Status s = stub_->Pull(&context, request, &response); - if (s.IsOk()) { - tech::pubsub::PubsubEvent event = response.pubsub_event(); - if (event.has_message()) { - *data = event.message().data(); - } - tech::pubsub::AcknowledgeRequest ack; - proto2::Empty empty; - ClientContext ack_context; - ack.set_subscription(name); - ack.add_ack_id(response.ack_id()); - stub_->Acknowledge(&ack_context, ack, &empty); - } - return s; -} - -} // namespace pubsub -} // namespace examples -} // namespace grpc diff --git a/examples/pubsub/subscriber_test.cc b/examples/pubsub/subscriber_test.cc deleted file mode 100644 index c5a077f407c..00000000000 --- a/examples/pubsub/subscriber_test.cc +++ /dev/null @@ -1,152 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "examples/pubsub/subscriber.h" -#include "test/core/util/port.h" -#include "test/core/util/test_config.h" - -namespace grpc { -namespace testing { -namespace { - -const char kTopic[] = "test topic"; -const char kSubscriptionName[] = "subscription name"; -const char kData[] = "Message data"; - -class SubscriberServiceImpl : public tech::pubsub::SubscriberService::Service { - public: - Status CreateSubscription( - ServerContext* context, const tech::pubsub::Subscription* request, - tech::pubsub::Subscription* response) GRPC_OVERRIDE { - EXPECT_EQ(request->topic(), kTopic); - EXPECT_EQ(request->name(), kSubscriptionName); - return Status::OK; - } - - Status GetSubscription(ServerContext* context, - const tech::pubsub::GetSubscriptionRequest* request, - tech::pubsub::Subscription* response) GRPC_OVERRIDE { - EXPECT_EQ(request->subscription(), kSubscriptionName); - response->set_topic(kTopic); - return Status::OK; - } - - Status DeleteSubscription( - ServerContext* context, - const tech::pubsub::DeleteSubscriptionRequest* request, - proto2::Empty* response) GRPC_OVERRIDE { - EXPECT_EQ(request->subscription(), kSubscriptionName); - return Status::OK; - } - - Status Pull(ServerContext* context, const tech::pubsub::PullRequest* request, - tech::pubsub::PullResponse* response) GRPC_OVERRIDE { - EXPECT_EQ(request->subscription(), kSubscriptionName); - response->set_ack_id("1"); - response->mutable_pubsub_event()->mutable_message()->set_data(kData); - return Status::OK; - } - - Status Acknowledge(ServerContext* context, - const tech::pubsub::AcknowledgeRequest* request, - proto2::Empty* response) GRPC_OVERRIDE { - return Status::OK; - } -}; - -class SubscriberTest : public ::testing::Test { - protected: - // Setup a server and a client for SubscriberService. - void SetUp() GRPC_OVERRIDE { - int port = grpc_pick_unused_port_or_die(); - server_address_ << "localhost:" << port; - ServerBuilder builder; - builder.AddListeningPort(server_address_.str(), - grpc::InsecureServerCredentials()); - builder.RegisterService(&service_); - server_ = builder.BuildAndStart(); - - channel_ = CreateChannel(server_address_.str(), grpc::InsecureCredentials(), - ChannelArguments()); - - subscriber_.reset(new grpc::examples::pubsub::Subscriber(channel_)); - } - - void TearDown() GRPC_OVERRIDE { - server_->Shutdown(); - subscriber_->Shutdown(); - } - - std::ostringstream server_address_; - std::unique_ptr server_; - SubscriberServiceImpl service_; - - std::shared_ptr channel_; - - std::unique_ptr subscriber_; -}; - -TEST_F(SubscriberTest, TestSubscriber) { - EXPECT_TRUE( - subscriber_->CreateSubscription(kTopic, kSubscriptionName).IsOk()); - - grpc::string topic; - EXPECT_TRUE(subscriber_->GetSubscription(kSubscriptionName, &topic).IsOk()); - EXPECT_EQ(topic, kTopic); - - grpc::string data; - EXPECT_TRUE(subscriber_->Pull(kSubscriptionName, &data).IsOk()); - - EXPECT_TRUE(subscriber_->DeleteSubscription(kSubscriptionName).IsOk()); -} - -} // namespace -} // namespace testing -} // namespace grpc - -int main(int argc, char** argv) { - grpc_test_init(argc, argv); - ::testing::InitGoogleTest(&argc, argv); - gpr_log(GPR_INFO, "Start test ..."); - int result = RUN_ALL_TESTS(); - return result; -} diff --git a/examples/python/helloworld/.gitignore b/examples/python/helloworld/.gitignore new file mode 100644 index 00000000000..0d20b6487c6 --- /dev/null +++ b/examples/python/helloworld/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/examples/python/helloworld/README.md b/examples/python/helloworld/README.md new file mode 100644 index 00000000000..d199c401ecf --- /dev/null +++ b/examples/python/helloworld/README.md @@ -0,0 +1,116 @@ +# gRPC Python Hello World + +This is a quick introduction with a simple example and installation instructions: for a more complete tutorial see [gRPC Basics: Python](examples/python/route_guide). + +### Install gRPC +Make sure you have built gRPC Python from source on your system. Follow the instructions here: +[https://github.com/grpc/grpc/blob/master/src/python/README.md](https://github.com/grpc/grpc/blob/master/src/python/README.md). + +This gives you a python virtual environment with installed gRPC Python +in GRPC_ROOT/python2.7_virtual_environment. GRPC_ROOT is the path to which you +have cloned the [gRPC git repo](https://github.com/grpc/grpc). + +### Get the source code + +The example code for our Hello World and our other examples live in the `examples` +directory. Clone this repository to your local machine by running the +following command: + + +```sh +$ git clone https://github.com/grpc/grpc.git +``` + +Change your current directory to examples/python/helloworld + +```sh +$ cd examples/python/helloworld/ +``` + +### Defining a service + +The first step in creating our example is to define a *service*: an RPC +service specifies the methods that can be called remotely with their parameters +and return types. As you saw in the +[overview](#protocolbuffers) above, gRPC does this using [protocol +buffers](https://developers.google.com/protocol-buffers/docs/overview). We +use the protocol buffers interface definition language (IDL) to define our +service methods, and define the parameters and return +types as protocol buffer message types. Both the client and the +server use interface code generated from the service definition. + +Here's our example service definition. The `Greeting` +service has one method, `hello`, that lets the server receive a single +`HelloRequest` +message from the remote client containing the user's name, then send back +a greeting in a single `HelloReply`. This is the simplest type of RPC you +can specify in gRPC. + +``` +syntax = "proto3"; + +option java_package = "io.grpc.examples"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} + +``` + + +### Generating gRPC code + +Once we've defined our service, we use the protocol buffer compiler +`protoc` to generate the special client and server code we need to create +our application. The generated code contains both stub code for clients to +use and an abstract interface for servers to implement, both with the method +defined in our `Greeting` service. + +To generate the client and server side interfaces: + +```sh +$ ./run_codegen.sh +``` +Which internally invokes the proto-compiler as: + +```sh +$ protoc -I ../../protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../../protos/helloworld.proto +``` + +Optionally, you can just skip the code generation step as the generated python module has already +been generated for you (helloworld_pb2.py). + +### The client + +Client-side code can be found in [greeter_client.py](examples/python/helloworld/greeter_client.py). + +You can run the client using: + +```sh +$ ./run_client.sh +``` + + +### The server + +Server side code can be found in [greeter_server.py](examples/python/helloworld/greeter_server.py). + +You can run the server using: + +```sh +$ ./run_server.sh +``` diff --git a/examples/python/helloworld/greeter_client.py b/examples/python/helloworld/greeter_client.py new file mode 100755 index 00000000000..370ce467703 --- /dev/null +++ b/examples/python/helloworld/greeter_client.py @@ -0,0 +1,44 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The Python implementation of the GRPC helloworld.Greeter client.""" + +import helloworld_pb2 + +_TIMEOUT_SECONDS = 10 + + +def run(): + with helloworld_pb2.early_adopter_create_Greeter_stub('localhost', 50051) as stub: + response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS) + print "Greeter client received: " + response.message + + +if __name__ == '__main__': + run() diff --git a/examples/python/helloworld/greeter_server.py b/examples/python/helloworld/greeter_server.py new file mode 100644 index 00000000000..81353666b10 --- /dev/null +++ b/examples/python/helloworld/greeter_server.py @@ -0,0 +1,56 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The Python implementation of the GRPC helloworld.Greeter server.""" + +import time + +import helloworld_pb2 + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +class Greeter(helloworld_pb2.EarlyAdopterGreeterServicer): + + def SayHello(self, request, context): + return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name) + + +def serve(): + server = helloworld_pb2.early_adopter_create_Greeter_server( + Greeter(), 50051, None, None) + server.start() + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + server.stop() + +if __name__ == '__main__': + serve() diff --git a/examples/python/helloworld/run_client.sh b/examples/python/helloworld/run_client.sh new file mode 100755 index 00000000000..095e6bc2f0e --- /dev/null +++ b/examples/python/helloworld/run_client.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This is where you have cloned out the https://github.com/grpc/grpc repository +# And built gRPC Python. +# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS +GRPC_ROOT=~/github/grpc + +$GRPC_ROOT/python2.7_virtual_environment/bin/python greeter_client.py diff --git a/examples/python/helloworld/run_codegen.sh b/examples/python/helloworld/run_codegen.sh new file mode 100755 index 00000000000..4d826c79466 --- /dev/null +++ b/examples/python/helloworld/run_codegen.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Runs the protoc with gRPC plugin to generate protocol messages and gRPC stubs. +protoc -I ../../protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../../protos/helloworld.proto diff --git a/examples/python/helloworld/run_server.sh b/examples/python/helloworld/run_server.sh new file mode 100755 index 00000000000..13b009e6cc7 --- /dev/null +++ b/examples/python/helloworld/run_server.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# This is where you have cloned out the https://github.com/grpc/grpc repository +# And built gRPC Python. +# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS +GRPC_ROOT=~/github/grpc + +$GRPC_ROOT/python2.7_virtual_environment/bin/python greeter_server.py + diff --git a/examples/python/route_guide/.gitignore b/examples/python/route_guide/.gitignore new file mode 100644 index 00000000000..0d20b6487c6 --- /dev/null +++ b/examples/python/route_guide/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/examples/python/route_guide/README.md b/examples/python/route_guide/README.md new file mode 100644 index 00000000000..dc97892ea58 --- /dev/null +++ b/examples/python/route_guide/README.md @@ -0,0 +1,303 @@ +#gRPC Basics: Python + +This tutorial provides a basic Python programmer's introduction to working with gRPC. By walking through this example you'll learn how to: + +- Define a service in a .proto file. +- Generate server and client code using the protocol buffer compiler. +- Use the Python gRPC API to write a simple client and server for your service. + +It assumes that you have read the [Getting started](https://github.com/grpc/grpc/tree/master/examples) guide and are familiar with [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). Note that the example in this tutorial uses the proto3 version of the protocol buffers language, which is currently in alpha release:you can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3) and see the [release notes](https://github.com/google/protobuf/releases) for the new version in the protocol buffers Github repository. + +This isn't a comprehensive guide to using gRPC in Python: more reference documentation is coming soon. + + +## Why use gRPC? + +This example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients. + +With gRPC you can define your service once in a .proto file and implement clients and servers in any of gRPC's supported languages, which in turn can be run in environments ranging from servers inside Google to your own tablet, with all the complexity of communication between different languages and environments is handled for you by gRPC. You also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating. + +## Example code and setup + +The example code for this tutorial is in [examples/python/route_guide](examples/python/route_guide). To download the example, clone this repository by running the following command: +```shell +$ git clone https://github.com/grpc/grpc.git +``` + +Then change your current directory to `examples/python/route_guide`: +```shell +$ cd examples/python/route_guide +``` + +You also should have the relevant tools installed to generate the server and client interface code - if you don't already, follow the setup instructions in [the Python quick start guide](examples/python). + +## Defining the service + +Your first step (as you'll know from [Getting started](https://github.com/grpc/grpc/tree/master/examples)) is to define the gRPC *service* and the method *request* and *response* types using [protocol buffers](https://developers.google.com/protocol-buffers/docs/overview). You can see the complete .proto file in [`examples/protos/route_guide.proto`](examples/protos/route_guide.proto). + +To define a service, you specify a named `service` in your .proto file: + +```protobuf +service RouteGuide { + // (Method definitions not shown) +} +``` + +Then you define `rpc` methods inside your service definition, specifying their request and response types. gRPC lets you define four kinds of service method, all of which are used in the `RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call. +```protobuf + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *response-streaming RPC* where the client sends a request to the server and gets a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. As you can see in the example, you specify a response-streaming method by placing the `stream` keyword before the *response* type. +```protobuf + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *request-streaming RPC* where the client writes a sequence of messages and sends them to the server, again using a provided stream. Once the client has finished writing the messages, it waits for the server to read them all and return its response. You specify a request-streaming method by placing the `stream` keyword before the *request* type. +```protobuf + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectionally-streaming RPC* where both sides send a sequence of messages using a read-write stream. The two streams operate independently, so clients and servers can read and write in whatever order they like: for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved. You specify this type of method by placing the `stream` keyword before both the request and the response. +```protobuf + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Your .proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods - for example, here's the `Point` message type: +```protobuf +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + +## Generating client and server code + +Next you need to generate the gRPC client and server interfaces from your .proto service definition. You do this using the protocol buffer compiler `protoc` with a special gRPC Python plugin. Make sure you've installed protoc and followed the gRPC Python plugin [installation instructions](https://github.com/grpc/grpc/blob/master/INSTALL) first): + +With `protoc` and the gRPC Python plugin installed, use the following command to generate the Python code: + +```shell +$ protoc -I ../../protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` ../../protos/route_guide.proto +``` + +Note that as we've already provided a version of the generated code in the example repository, running this command regenerates the appropriate file rather than creates a new one. The generated code file is called `route_guide_pb2.py` and contains: +- classes for the messages defined in route_guide.proto +- abstract classes for the service defined in route_guide.proto + - `EarlyAdopterRouteGuideServicer`, which defines the interface for implementations of the RouteGuide service + - `EarlyAdopterRouteGuideServer`, which may be started and stopped + - `EarlyAdopterRouteGuideStub`, which can be used by clients to invoke RouteGuide RPCs +- functions for application use + - `early_adopter_create_RouteGuide_server`, which creates a gRPC server given an `EarlyAdopterRouteGuideServicer` object + - `early_adopter_create_RouteGuide_stub`, which can be used by clients to create a stub object + + +## Creating the server + +First let's look at how you create a `RouteGuide` server. If you're only interested in creating gRPC clients, you can skip this section and go straight to [Creating the client](#client) (though you might find it interesting anyway!). + +Creating and running a `RouteGuide` server breaks down into two work items: +- Implementing the servicer interface generated from our service definition with functions that perform the actual "work" of the service. +- Running a gRPC server to listen for requests from clients and transmit responses. + +You can find the example `RouteGuide` server in [examples/python/route_guide/route_guide_server.py](examples/python/route_guide/route_guide_server.py). + +### Implementing RouteGuide + +`route_guide_server.py` has a `RouteGuideServicer` class that implements the generated interface `route_guide_pb2.EarlyAdopterRouteGuideServicer`: + +```python +# RouteGuideServicer provides an implementation of the methods of the RouteGuide service. +class RouteGuideServicer(route_guide_pb2.EarlyAdopterRouteGuideServicer): +``` + +`RouteGuideServicer` implements all the `RouteGuide` service methods. + +#### Simple RPC + +Let's look at the simplest type first, `GetFeature`, which just gets a `Point` from the client and returns the corresponding feature information from its database in a `Feature`. + +```python + def GetFeature(self, request, context): + feature = get_feature(self.db, request) + if feature is None: + return route_guide_pb2.Feature(name="", location=request) + else: + return feature +``` + +The method is passed a `route_guide_pb2.Point` request for the RPC, and an `RpcContext` object that provides RPC-specific information such as timeout limits. It returns a `route_guide_pb2.Feature` response. + +#### Response-streaming RPC + +Now let's look at the next method. `ListFeatures` is a response-streaming RPC that sends multiple `Feature`s to the client. + +```python + def ListFeatures(self, request, context): + left = min(request.lo.longitude, request.hi.longitude) + right = max(request.lo.longitude, request.hi.longitude) + top = max(request.lo.latitude, request.hi.latitude) + bottom = min(request.lo.latitude, request.hi.latitude) + for feature in self.db: + if (feature.location.longitude >= left and + feature.location.longitude <= right and + feature.location.latitude >= bottom and + feature.location.latitude <= top): + yield feature +``` + +Here the request message is a `route_guide_pb2.Rectangle` within which the client wants to find `Feature`s. Instead of returning a single response the method yields zero or more responses. + +#### Request-streaming RPC + +The request-streaming method `RecordRoute` uses an [iterator](https://docs.python.org/2/library/stdtypes.html#iterator-types) of request values and returns a single response value. + +```python + def RecordRoute(self, request_iterator, context): + point_count = 0 + feature_count = 0 + distance = 0.0 + prev_point = None + + start_time = time.time() + for point in request_iterator: + point_count += 1 + if get_feature(self.db, point): + feature_count += 1 + if prev_point: + distance += get_distance(prev_point, point) + prev_point = point + + elapsed_time = time.time() - start_time + return route_guide_pb2.RouteSummary(point_count=point_count, + feature_count=feature_count, + distance=int(distance), + elapsed_time=int(elapsed_time)) +``` + +#### Bidirectional streaming RPC + +Lastly let's look at the bidirectionally-streaming method `RouteChat`. + +```python + def RouteChat(self, request_iterator, context): + prev_notes = [] + for new_note in request_iterator: + for prev_note in prev_notes: + if prev_note.location == new_note.location: + yield prev_note + prev_notes.append(new_note) +``` + +This method's semantics are a combination of those of the request-streaming method and the response-streaming method. It is passed an iterator of request values and is itself an iterator of response values. + +### Starting the server + +Once you have implemented all the `RouteGuide` methods, the next step is to start up a gRPC server so that clients can actually use your service: + +```python +def serve(): + server = route_guide_pb2.early_adopter_create_RouteGuide_server( + RouteGuideServicer(), 50051, None, None) + server.start() +``` + +Because `start()` does not block you may need to sleep-loop if there is nothing else for your code to do while serving. + + +## Creating the client + +You can see the complete example client code in [examples/python/route_guide/route_guide_client.py](examples/python/route_guide/route_guide_client.py). + +### Creating a stub + +To call service methods, we first need to create a *stub*. + +We use the `early_adopter_create_RouteGuide_stub` function of the `route_guide_pb2` module, generated from our .proto. + +```python +stub = RouteGuide::Stub.new('localhost', 50051) +``` + +The returned object implements all the methods defined by the `EarlyAdopterRouteGuideStub` interface, and is also a [context manager](https://docs.python.org/2/library/stdtypes.html#typecontextmanager). All RPCs invoked on the stub must be invoked within the stub's context, so it is common for stubs to be created and used with a [with statement](https://docs.python.org/2/reference/compound_stmts.html#the-with-statement): + +```python +with route_guide_pb2.early_adopter_create_RouteGuide_stub('localhost', 50051) as stub: +``` + +### Calling service methods + +For RPC methods that return a single response ("response-unary" methods), gRPC Python supports both synchronous (blocking) and asynchronous (non-blocking) control flow semantics. For response-streaming RPC methods, calls immediately return an iterator of response values. Calls to that iterator's `next()` method block until the response to be yielded from the iterator becomes available. + +#### Simple RPC + +A synchronous call to the simple RPC `GetFeature` is nearly as straightforward as calling a local method. The RPC call waits for the server to respond, and will either return a response or raise an exception: + +```python +feature = stub.GetFeature(point, timeout_in_seconds) +``` + +An asynchronous call to `GetFeature` is similar, but like calling a local method asynchronously in a thread pool: + +```python +feature_future = stub.GetFeature.async(point, timeout_in_seconds) +feature = feature_future.result() +``` + +#### Response-streaming RPC + +Calling the response-streaming `ListFeatures` is similar to working with sequence types: + +```python +for feature in stub.ListFeatures(rectangle, timeout_in_seconds): +``` + +#### Request-streaming RPC + +Calling the request-streaming `RecordRoute` is similar to passing a sequence to a local method. Like the simple RPC above that also returns a single response, it can be called synchronously or asynchronously: + +```python +route_summary = stub.RecordRoute(point_sequence, timeout_in_seconds) +``` + +```python +route_summary_future = stub.RecordRoute.async(point_sequence, timeout_in_seconds) +route_summary = route_summary_future.result() +``` + +#### Bidirectional streaming RPC + +Calling the bidirectionally-streaming `RouteChat` has (as is the case on the service-side) a combination of the request-streaming and response-streaming semantics: + +```python +for received_route_note in stub.RouteChat(sent_routes, timeout_in_seconds): +``` + +## Try it out! + +Run the server, which will listen on port 50051: + +```shell +$ python route_guide_server.py +``` + +Run the client (in a different terminal): + +```shell +$ python route_guide_client.py +``` diff --git a/examples/python/route_guide/route_guide_client.py b/examples/python/route_guide/route_guide_client.py new file mode 100755 index 00000000000..078231543e1 --- /dev/null +++ b/examples/python/route_guide/route_guide_client.py @@ -0,0 +1,130 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The Python implementation of the gRPC route guide client.""" + +import random +import time + +import route_guide_pb2 +import route_guide_resources + +_TIMEOUT_SECONDS = 30 + + +def make_route_note(message, latitude, longitude): + return route_guide_pb2.RouteNote( + message=message, + location=route_guide_pb2.Point(latitude=latitude, longitude=longitude)) + + +def guide_get_one_feature(stub, point): + feature = stub.GetFeature(point, _TIMEOUT_SECONDS) + if not feature.location: + print "Server returned incomplete feature" + return + + if feature.name: + print "Feature called %s at %s" % (feature.name, feature.location) + else: + print "Found no feature at %s" % feature.location + + +def guide_get_feature(stub): + guide_get_one_feature(stub, route_guide_pb2.Point(latitude=409146138, longitude=-746188906)) + guide_get_one_feature(stub, route_guide_pb2.Point(latitude=0, longitude=0)) + + +def guide_list_features(stub): + rect = route_guide_pb2.Rectangle( + lo=route_guide_pb2.Point( + latitude=400000000, longitude = -750000000), + hi=route_guide_pb2.Point( + latitude = 420000000, longitude = -730000000)) + print "Looking for features between 40, -75 and 42, -73" + + features = stub.ListFeatures(rect, _TIMEOUT_SECONDS) + + for feature in features: + print "Feature called %s at %s" % (feature.name, feature.location) + + +def generate_route(feature_list): + for _ in range(0, 10): + random_feature = feature_list[random.randint(0, len(feature_list) - 1)] + print "Visiting point %s" % random_feature.location + yield random_feature.location + time.sleep(random.uniform(0.5, 1.5)) + + +def guide_record_route(stub): + feature_list = route_guide_resources.read_route_guide_database() + + route_iter = generate_route(feature_list) + route_summary = stub.RecordRoute(route_iter, _TIMEOUT_SECONDS) + print "Finished trip with %s points " % route_summary.point_count + print "Passed %s features " % route_summary.feature_count + print "Travelled %s meters " % route_summary.distance + print "It took %s seconds " % route_summary.elapsed_time + + +def generate_messages(): + messages = [ + make_route_note("First message", 0, 0), + make_route_note("Second message", 0, 1), + make_route_note("Third message", 1, 0), + make_route_note("Fourth message", 0, 0), + make_route_note("Fifth message", 1, 0), + ] + for msg in messages: + print "Sending %s at %s" % (msg.message, msg.location) + yield msg + time.sleep(random.uniform(0.5, 1.0)) + + +def guide_route_chat(stub): + responses = stub.RouteChat(generate_messages(), _TIMEOUT_SECONDS) + for response in responses: + print "Received message %s at %s" % (response.message, response.location) + + +def run(): + with route_guide_pb2.early_adopter_create_RouteGuide_stub('localhost', 50051) as stub: + print "-------------- GetFeature --------------" + guide_get_feature(stub) + print "-------------- ListFeatures --------------" + guide_list_features(stub) + print "-------------- RecordRoute --------------" + guide_record_route(stub) + print "-------------- RouteChat --------------" + guide_route_chat(stub) + + +if __name__ == '__main__': + run() diff --git a/examples/python/route_guide/route_guide_db.json b/examples/python/route_guide/route_guide_db.json new file mode 100644 index 00000000000..9d6a980ab7d --- /dev/null +++ b/examples/python/route_guide/route_guide_db.json @@ -0,0 +1,601 @@ +[{ + "location": { + "latitude": 407838351, + "longitude": -746143763 + }, + "name": "Patriots Path, Mendham, NJ 07945, USA" +}, { + "location": { + "latitude": 408122808, + "longitude": -743999179 + }, + "name": "101 New Jersey 10, Whippany, NJ 07981, USA" +}, { + "location": { + "latitude": 413628156, + "longitude": -749015468 + }, + "name": "U.S. 6, Shohola, PA 18458, USA" +}, { + "location": { + "latitude": 419999544, + "longitude": -740371136 + }, + "name": "5 Conners Road, Kingston, NY 12401, USA" +}, { + "location": { + "latitude": 414008389, + "longitude": -743951297 + }, + "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" +}, { + "location": { + "latitude": 419611318, + "longitude": -746524769 + }, + "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" +}, { + "location": { + "latitude": 406109563, + "longitude": -742186778 + }, + "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" +}, { + "location": { + "latitude": 416802456, + "longitude": -742370183 + }, + "name": "352 South Mountain Road, Wallkill, NY 12589, USA" +}, { + "location": { + "latitude": 412950425, + "longitude": -741077389 + }, + "name": "Bailey Turn Road, Harriman, NY 10926, USA" +}, { + "location": { + "latitude": 412144655, + "longitude": -743949739 + }, + "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" +}, { + "location": { + "latitude": 415736605, + "longitude": -742847522 + }, + "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" +}, { + "location": { + "latitude": 413843930, + "longitude": -740501726 + }, + "name": "162 Merrill Road, Highland Mills, NY 10930, USA" +}, { + "location": { + "latitude": 410873075, + "longitude": -744459023 + }, + "name": "Clinton Road, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 412346009, + "longitude": -744026814 + }, + "name": "16 Old Brook Lane, Warwick, NY 10990, USA" +}, { + "location": { + "latitude": 402948455, + "longitude": -747903913 + }, + "name": "3 Drake Lane, Pennington, NJ 08534, USA" +}, { + "location": { + "latitude": 406337092, + "longitude": -740122226 + }, + "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" +}, { + "location": { + "latitude": 406421967, + "longitude": -747727624 + }, + "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" +}, { + "location": { + "latitude": 416318082, + "longitude": -749677716 + }, + "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" +}, { + "location": { + "latitude": 415301720, + "longitude": -748416257 + }, + "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" +}, { + "location": { + "latitude": 402647019, + "longitude": -747071791 + }, + "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" +}, { + "location": { + "latitude": 412567807, + "longitude": -741058078 + }, + "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" +}, { + "location": { + "latitude": 416855156, + "longitude": -744420597 + }, + "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" +}, { + "location": { + "latitude": 404663628, + "longitude": -744820157 + }, + "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" +}, { + "location": { + "latitude": 407113723, + "longitude": -749746483 + }, + "name": "" +}, { + "location": { + "latitude": 402133926, + "longitude": -743613249 + }, + "name": "" +}, { + "location": { + "latitude": 400273442, + "longitude": -741220915 + }, + "name": "" +}, { + "location": { + "latitude": 411236786, + "longitude": -744070769 + }, + "name": "" +}, { + "location": { + "latitude": 411633782, + "longitude": -746784970 + }, + "name": "211-225 Plains Road, Augusta, NJ 07822, USA" +}, { + "location": { + "latitude": 415830701, + "longitude": -742952812 + }, + "name": "" +}, { + "location": { + "latitude": 413447164, + "longitude": -748712898 + }, + "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" +}, { + "location": { + "latitude": 405047245, + "longitude": -749800722 + }, + "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" +}, { + "location": { + "latitude": 418858923, + "longitude": -746156790 + }, + "name": "" +}, { + "location": { + "latitude": 417951888, + "longitude": -748484944 + }, + "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" +}, { + "location": { + "latitude": 407033786, + "longitude": -743977337 + }, + "name": "26 East 3rd Street, New Providence, NJ 07974, USA" +}, { + "location": { + "latitude": 417548014, + "longitude": -740075041 + }, + "name": "" +}, { + "location": { + "latitude": 410395868, + "longitude": -744972325 + }, + "name": "" +}, { + "location": { + "latitude": 404615353, + "longitude": -745129803 + }, + "name": "" +}, { + "location": { + "latitude": 406589790, + "longitude": -743560121 + }, + "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" +}, { + "location": { + "latitude": 414653148, + "longitude": -740477477 + }, + "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" +}, { + "location": { + "latitude": 405957808, + "longitude": -743255336 + }, + "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" +}, { + "location": { + "latitude": 411733589, + "longitude": -741648093 + }, + "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" +}, { + "location": { + "latitude": 412676291, + "longitude": -742606606 + }, + "name": "1270 Lakes Road, Monroe, NY 10950, USA" +}, { + "location": { + "latitude": 409224445, + "longitude": -748286738 + }, + "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" +}, { + "location": { + "latitude": 406523420, + "longitude": -742135517 + }, + "name": "652 Garden Street, Elizabeth, NJ 07202, USA" +}, { + "location": { + "latitude": 401827388, + "longitude": -740294537 + }, + "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" +}, { + "location": { + "latitude": 410564152, + "longitude": -743685054 + }, + "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 408472324, + "longitude": -740726046 + }, + "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" +}, { + "location": { + "latitude": 412452168, + "longitude": -740214052 + }, + "name": "5 White Oak Lane, Stony Point, NY 10980, USA" +}, { + "location": { + "latitude": 409146138, + "longitude": -746188906 + }, + "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" +}, { + "location": { + "latitude": 404701380, + "longitude": -744781745 + }, + "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 409642566, + "longitude": -746017679 + }, + "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" +}, { + "location": { + "latitude": 408031728, + "longitude": -748645385 + }, + "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" +}, { + "location": { + "latitude": 413700272, + "longitude": -742135189 + }, + "name": "367 Prospect Road, Chester, NY 10918, USA" +}, { + "location": { + "latitude": 404310607, + "longitude": -740282632 + }, + "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" +}, { + "location": { + "latitude": 409319800, + "longitude": -746201391 + }, + "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" +}, { + "location": { + "latitude": 406685311, + "longitude": -742108603 + }, + "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" +}, { + "location": { + "latitude": 419018117, + "longitude": -749142781 + }, + "name": "43 Dreher Road, Roscoe, NY 12776, USA" +}, { + "location": { + "latitude": 412856162, + "longitude": -745148837 + }, + "name": "Swan Street, Pine Island, NY 10969, USA" +}, { + "location": { + "latitude": 416560744, + "longitude": -746721964 + }, + "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" +}, { + "location": { + "latitude": 405314270, + "longitude": -749836354 + }, + "name": "" +}, { + "location": { + "latitude": 414219548, + "longitude": -743327440 + }, + "name": "" +}, { + "location": { + "latitude": 415534177, + "longitude": -742900616 + }, + "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" +}, { + "location": { + "latitude": 406898530, + "longitude": -749127080 + }, + "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" +}, { + "location": { + "latitude": 407586880, + "longitude": -741670168 + }, + "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" +}, { + "location": { + "latitude": 400106455, + "longitude": -742870190 + }, + "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" +}, { + "location": { + "latitude": 400066188, + "longitude": -746793294 + }, + "name": "" +}, { + "location": { + "latitude": 418803880, + "longitude": -744102673 + }, + "name": "40 Mountain Road, Napanoch, NY 12458, USA" +}, { + "location": { + "latitude": 414204288, + "longitude": -747895140 + }, + "name": "" +}, { + "location": { + "latitude": 414777405, + "longitude": -740615601 + }, + "name": "" +}, { + "location": { + "latitude": 415464475, + "longitude": -747175374 + }, + "name": "48 North Road, Forestburgh, NY 12777, USA" +}, { + "location": { + "latitude": 404062378, + "longitude": -746376177 + }, + "name": "" +}, { + "location": { + "latitude": 405688272, + "longitude": -749285130 + }, + "name": "" +}, { + "location": { + "latitude": 400342070, + "longitude": -748788996 + }, + "name": "" +}, { + "location": { + "latitude": 401809022, + "longitude": -744157964 + }, + "name": "" +}, { + "location": { + "latitude": 404226644, + "longitude": -740517141 + }, + "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" +}, { + "location": { + "latitude": 410322033, + "longitude": -747871659 + }, + "name": "" +}, { + "location": { + "latitude": 407100674, + "longitude": -747742727 + }, + "name": "" +}, { + "location": { + "latitude": 418811433, + "longitude": -741718005 + }, + "name": "213 Bush Road, Stone Ridge, NY 12484, USA" +}, { + "location": { + "latitude": 415034302, + "longitude": -743850945 + }, + "name": "" +}, { + "location": { + "latitude": 411349992, + "longitude": -743694161 + }, + "name": "" +}, { + "location": { + "latitude": 404839914, + "longitude": -744759616 + }, + "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 414638017, + "longitude": -745957854 + }, + "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" +}, { + "location": { + "latitude": 412127800, + "longitude": -740173578 + }, + "name": "" +}, { + "location": { + "latitude": 401263460, + "longitude": -747964303 + }, + "name": "" +}, { + "location": { + "latitude": 412843391, + "longitude": -749086026 + }, + "name": "" +}, { + "location": { + "latitude": 418512773, + "longitude": -743067823 + }, + "name": "" +}, { + "location": { + "latitude": 404318328, + "longitude": -740835638 + }, + "name": "42-102 Main Street, Belford, NJ 07718, USA" +}, { + "location": { + "latitude": 419020746, + "longitude": -741172328 + }, + "name": "" +}, { + "location": { + "latitude": 404080723, + "longitude": -746119569 + }, + "name": "" +}, { + "location": { + "latitude": 401012643, + "longitude": -744035134 + }, + "name": "" +}, { + "location": { + "latitude": 404306372, + "longitude": -741079661 + }, + "name": "" +}, { + "location": { + "latitude": 403966326, + "longitude": -748519297 + }, + "name": "" +}, { + "location": { + "latitude": 405002031, + "longitude": -748407866 + }, + "name": "" +}, { + "location": { + "latitude": 409532885, + "longitude": -742200683 + }, + "name": "" +}, { + "location": { + "latitude": 416851321, + "longitude": -742674555 + }, + "name": "" +}, { + "location": { + "latitude": 406411633, + "longitude": -741722051 + }, + "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" +}, { + "location": { + "latitude": 413069058, + "longitude": -744597778 + }, + "name": "261 Van Sickle Road, Goshen, NY 10924, USA" +}, { + "location": { + "latitude": 418465462, + "longitude": -746859398 + }, + "name": "" +}, { + "location": { + "latitude": 411733222, + "longitude": -744228360 + }, + "name": "" +}, { + "location": { + "latitude": 410248224, + "longitude": -747127767 + }, + "name": "3 Hasta Way, Newton, NJ 07860, USA" +}] diff --git a/examples/python/route_guide/route_guide_pb2.py b/examples/python/route_guide/route_guide_pb2.py new file mode 100644 index 00000000000..2a4532bb750 --- /dev/null +++ b/examples/python/route_guide/route_guide_pb2.py @@ -0,0 +1,370 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: route_guide.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='route_guide.proto', + package='', + serialized_pb=_b('\n\x11route_guide.proto\",\n\x05Point\x12\x10\n\x08latitude\x18\x01 \x01(\x05\x12\x11\n\tlongitude\x18\x02 \x01(\x05\"3\n\tRectangle\x12\x12\n\x02lo\x18\x01 \x01(\x0b\x32\x06.Point\x12\x12\n\x02hi\x18\x02 \x01(\x0b\x32\x06.Point\"1\n\x07\x46\x65\x61ture\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x18\n\x08location\x18\x02 \x01(\x0b\x32\x06.Point\"6\n\tRouteNote\x12\x18\n\x08location\x18\x01 \x01(\x0b\x32\x06.Point\x12\x0f\n\x07message\x18\x02 \x01(\t\"b\n\x0cRouteSummary\x12\x13\n\x0bpoint_count\x18\x01 \x01(\x05\x12\x15\n\rfeature_count\x18\x02 \x01(\x05\x12\x10\n\x08\x64istance\x18\x03 \x01(\x05\x12\x14\n\x0c\x65lapsed_time\x18\x04 \x01(\x05\x32\xad\x01\n\nRouteGuide\x12 \n\nGetFeature\x12\x06.Point\x1a\x08.Feature\"\x00\x12(\n\x0cListFeatures\x12\n.Rectangle\x1a\x08.Feature\"\x00\x30\x01\x12(\n\x0bRecordRoute\x12\x06.Point\x1a\r.RouteSummary\"\x00(\x01\x12)\n\tRouteChat\x12\n.RouteNote\x1a\n.RouteNote\"\x00(\x01\x30\x01') +) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + + + + +_POINT = _descriptor.Descriptor( + name='Point', + full_name='Point', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='latitude', full_name='Point.latitude', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='longitude', full_name='Point.longitude', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=21, + serialized_end=65, +) + + +_RECTANGLE = _descriptor.Descriptor( + name='Rectangle', + full_name='Rectangle', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='lo', full_name='Rectangle.lo', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='hi', full_name='Rectangle.hi', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=67, + serialized_end=118, +) + + +_FEATURE = _descriptor.Descriptor( + name='Feature', + full_name='Feature', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='Feature.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='location', full_name='Feature.location', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=120, + serialized_end=169, +) + + +_ROUTENOTE = _descriptor.Descriptor( + name='RouteNote', + full_name='RouteNote', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='location', full_name='RouteNote.location', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='message', full_name='RouteNote.message', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=171, + serialized_end=225, +) + + +_ROUTESUMMARY = _descriptor.Descriptor( + name='RouteSummary', + full_name='RouteSummary', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='point_count', full_name='RouteSummary.point_count', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='feature_count', full_name='RouteSummary.feature_count', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='distance', full_name='RouteSummary.distance', index=2, + number=3, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='elapsed_time', full_name='RouteSummary.elapsed_time', index=3, + number=4, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + options=None, + is_extendable=False, + extension_ranges=[], + oneofs=[ + ], + serialized_start=227, + serialized_end=325, +) + +_RECTANGLE.fields_by_name['lo'].message_type = _POINT +_RECTANGLE.fields_by_name['hi'].message_type = _POINT +_FEATURE.fields_by_name['location'].message_type = _POINT +_ROUTENOTE.fields_by_name['location'].message_type = _POINT +DESCRIPTOR.message_types_by_name['Point'] = _POINT +DESCRIPTOR.message_types_by_name['Rectangle'] = _RECTANGLE +DESCRIPTOR.message_types_by_name['Feature'] = _FEATURE +DESCRIPTOR.message_types_by_name['RouteNote'] = _ROUTENOTE +DESCRIPTOR.message_types_by_name['RouteSummary'] = _ROUTESUMMARY + +Point = _reflection.GeneratedProtocolMessageType('Point', (_message.Message,), dict( + DESCRIPTOR = _POINT, + __module__ = 'route_guide_pb2' + # @@protoc_insertion_point(class_scope:Point) + )) +_sym_db.RegisterMessage(Point) + +Rectangle = _reflection.GeneratedProtocolMessageType('Rectangle', (_message.Message,), dict( + DESCRIPTOR = _RECTANGLE, + __module__ = 'route_guide_pb2' + # @@protoc_insertion_point(class_scope:Rectangle) + )) +_sym_db.RegisterMessage(Rectangle) + +Feature = _reflection.GeneratedProtocolMessageType('Feature', (_message.Message,), dict( + DESCRIPTOR = _FEATURE, + __module__ = 'route_guide_pb2' + # @@protoc_insertion_point(class_scope:Feature) + )) +_sym_db.RegisterMessage(Feature) + +RouteNote = _reflection.GeneratedProtocolMessageType('RouteNote', (_message.Message,), dict( + DESCRIPTOR = _ROUTENOTE, + __module__ = 'route_guide_pb2' + # @@protoc_insertion_point(class_scope:RouteNote) + )) +_sym_db.RegisterMessage(RouteNote) + +RouteSummary = _reflection.GeneratedProtocolMessageType('RouteSummary', (_message.Message,), dict( + DESCRIPTOR = _ROUTESUMMARY, + __module__ = 'route_guide_pb2' + # @@protoc_insertion_point(class_scope:RouteSummary) + )) +_sym_db.RegisterMessage(RouteSummary) + + +import abc +from grpc._adapter import fore +from grpc._adapter import rear +from grpc.framework.assembly import implementations +from grpc.framework.assembly import utilities +class EarlyAdopterRouteGuideServicer(object): + """""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def GetFeature(self, request): + raise NotImplementedError() + @abc.abstractmethod + def ListFeatures(self, request): + raise NotImplementedError() + @abc.abstractmethod + def RecordRoute(self, request_iterator): + raise NotImplementedError() + @abc.abstractmethod + def RouteChat(self, request_iterator): + raise NotImplementedError() +class EarlyAdopterRouteGuideServer(object): + """""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def start(self): + raise NotImplementedError() + @abc.abstractmethod + def stop(self): + raise NotImplementedError() +class EarlyAdopterRouteGuideStub(object): + """""" + __metaclass__ = abc.ABCMeta + @abc.abstractmethod + def GetFeature(self, request): + raise NotImplementedError() + GetFeature.async = None + @abc.abstractmethod + def ListFeatures(self, request): + raise NotImplementedError() + ListFeatures.async = None + @abc.abstractmethod + def RecordRoute(self, request_iterator): + raise NotImplementedError() + RecordRoute.async = None + @abc.abstractmethod + def RouteChat(self, request_iterator): + raise NotImplementedError() + RouteChat.async = None +def early_adopter_create_RouteGuide_server(servicer, port, root_certificates, key_chain_pairs): + method_implementations = { + "GetFeature": utilities.unary_unary_inline(servicer.GetFeature), + "ListFeatures": utilities.unary_stream_inline(servicer.ListFeatures), + "RecordRoute": utilities.stream_unary_inline(servicer.RecordRoute), + "RouteChat": utilities.stream_stream_inline(servicer.RouteChat), + } + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + request_deserializers = { + "GetFeature": route_guide_pb2.Point.FromString, + "ListFeatures": route_guide_pb2.Rectangle.FromString, + "RecordRoute": route_guide_pb2.Point.FromString, + "RouteChat": route_guide_pb2.RouteNote.FromString, + } + response_serializers = { + "GetFeature": lambda x: x.SerializeToString(), + "ListFeatures": lambda x: x.SerializeToString(), + "RecordRoute": lambda x: x.SerializeToString(), + "RouteChat": lambda x: x.SerializeToString(), + } + link = fore.activated_fore_link(port, request_deserializers, response_serializers, root_certificates, key_chain_pairs) + return implementations.assemble_service(method_implementations, link) +def early_adopter_create_RouteGuide_stub(host, port): + method_implementations = { + "GetFeature": utilities.unary_unary_inline(None), + "ListFeatures": utilities.unary_stream_inline(None), + "RecordRoute": utilities.stream_unary_inline(None), + "RouteChat": utilities.stream_stream_inline(None), + } + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + import route_guide_pb2 + response_deserializers = { + "GetFeature": route_guide_pb2.Feature.FromString, + "ListFeatures": route_guide_pb2.Feature.FromString, + "RecordRoute": route_guide_pb2.RouteSummary.FromString, + "RouteChat": route_guide_pb2.RouteNote.FromString, + } + request_serializers = { + "GetFeature": lambda x: x.SerializeToString(), + "ListFeatures": lambda x: x.SerializeToString(), + "RecordRoute": lambda x: x.SerializeToString(), + "RouteChat": lambda x: x.SerializeToString(), + } + link = rear.activated_rear_link(host, port, request_serializers, response_deserializers) + return implementations.assemble_dynamic_inline_stub(method_implementations, link) +# @@protoc_insertion_point(module_scope) diff --git a/examples/python/route_guide/route_guide_resources.py b/examples/python/route_guide/route_guide_resources.py new file mode 100755 index 00000000000..30c7711019f --- /dev/null +++ b/examples/python/route_guide/route_guide_resources.py @@ -0,0 +1,53 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Common resources used in the gRPC route guide example.""" + +import json + +import route_guide_pb2 + + +def read_route_guide_database(): + """Reads the route guide database. + + Returns: + The full contents of the route guide database as a sequence of + route_guide_pb2.Features. + """ + feature_list = [] + with open("route_guide_db.json") as route_guide_db_file: + for item in json.load(route_guide_db_file): + feature = route_guide_pb2.Feature( + name=item["name"], + location=route_guide_pb2.Point( + latitude=item["location"]["latitude"], + longitude=item["location"]["longitude"])) + feature_list.append(feature) + return feature_list diff --git a/examples/python/route_guide/route_guide_server.py b/examples/python/route_guide/route_guide_server.py new file mode 100644 index 00000000000..44bbacf5f32 --- /dev/null +++ b/examples/python/route_guide/route_guide_server.py @@ -0,0 +1,134 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""The Python implementation of the gRPC route guide server.""" + +import time +import math + +import route_guide_pb2 +import route_guide_resources + +_ONE_DAY_IN_SECONDS = 60 * 60 * 24 + + +def get_feature(feature_db, point): + """Returns Feature at given location or None.""" + for feature in feature_db: + if feature.location == point: + return feature + return None + + +def get_distance(start, end): + """Distance between two points.""" + coord_factor = 10000000.0 + lat_1 = start.latitude / coord_factor + lat_2 = end.latitude / coord_factor + lon_1 = start.latitude / coord_factor + lon_2 = end.longitude / coord_factor + lat_rad_1 = math.radians(lat_1) + lat_rad_2 = math.radians(lat_2) + delta_lat_rad = math.radians(lat_2 - lat_1) + delta_lon_rad = math.radians(lon_2 - lon_1) + + a = (pow(math.sin(delta_lat_rad / 2), 2) + + (math.cos(lat_rad_1) * math.cos(lat_rad_2) * + pow(math.sin(delta_lon_rad / 2), 2))) + c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) + R = 6371000; # metres + return R * c; + +class RouteGuideServicer(route_guide_pb2.EarlyAdopterRouteGuideServicer): + """Provides methods that implement functionality of route guide server.""" + + def __init__(self): + self.db = route_guide_resources.read_route_guide_database() + + def GetFeature(self, request, context): + feature = get_feature(self.db, request) + if feature is None: + return route_guide_pb2.Feature(name="", location=request) + else: + return feature + + def ListFeatures(self, request, context): + left = min(request.lo.longitude, request.hi.longitude) + right = max(request.lo.longitude, request.hi.longitude) + top = max(request.lo.latitude, request.hi.latitude) + bottom = min(request.lo.latitude, request.hi.latitude) + for feature in self.db: + if (feature.location.longitude >= left and + feature.location.longitude <= right and + feature.location.latitude >= bottom and + feature.location.latitude <= top): + yield feature + + def RecordRoute(self, request_iterator, context): + point_count = 0 + feature_count = 0 + distance = 0.0 + prev_point = None + + start_time = time.time() + for point in request_iterator: + point_count += 1 + if get_feature(self.db, point): + feature_count += 1 + if prev_point: + distance += get_distance(prev_point, point) + prev_point = point + + elapsed_time = time.time() - start_time + return route_guide_pb2.RouteSummary(point_count=point_count, + feature_count=feature_count, + distance=int(distance), + elapsed_time=int(elapsed_time)) + + def RouteChat(self, request_iterator, context): + prev_notes = [] + for new_note in request_iterator: + for prev_note in prev_notes: + if prev_note.location == new_note.location: + yield prev_note + prev_notes.append(new_note) + + +def serve(): + server = route_guide_pb2.early_adopter_create_RouteGuide_server( + RouteGuideServicer(), 50051, None, None) + server.start() + try: + while True: + time.sleep(_ONE_DAY_IN_SECONDS) + except KeyboardInterrupt: + server.stop() + +if __name__ == '__main__': + serve() diff --git a/examples/python/route_guide/run_client.sh b/examples/python/route_guide/run_client.sh new file mode 100755 index 00000000000..d2552c2858c --- /dev/null +++ b/examples/python/route_guide/run_client.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This is where you have cloned out the https://github.com/grpc/grpc repository +# And built gRPC Python. +# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS +GRPC_ROOT=~/github/grpc + +$GRPC_ROOT/python2.7_virtual_environment/bin/python -B route_guide_client.py diff --git a/examples/python/route_guide/run_codegen.sh b/examples/python/route_guide/run_codegen.sh new file mode 100755 index 00000000000..689e0978de6 --- /dev/null +++ b/examples/python/route_guide/run_codegen.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# Runs the protoc with gRPC plugin to generate protocol messages and gRPC stubs. +protoc -I . --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` route_guide.proto diff --git a/examples/python/route_guide/run_server.sh b/examples/python/route_guide/run_server.sh new file mode 100755 index 00000000000..8f759250c85 --- /dev/null +++ b/examples/python/route_guide/run_server.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# This is where you have cloned out the https://github.com/grpc/grpc repository +# And built gRPC Python. +# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS +GRPC_ROOT=~/github/grpc + +$GRPC_ROOT/python2.7_virtual_environment/bin/python -B route_guide_server.py diff --git a/examples/ruby/.gitignore b/examples/ruby/.gitignore new file mode 100644 index 00000000000..62fcb4fa943 --- /dev/null +++ b/examples/ruby/.gitignore @@ -0,0 +1,15 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +*.bundle +*.so +*.o +*.a +mkmf.log +vendor diff --git a/examples/ruby/Gemfile b/examples/ruby/Gemfile new file mode 100644 index 00000000000..65d3f0ad4ae --- /dev/null +++ b/examples/ruby/Gemfile @@ -0,0 +1,6 @@ +# -*- ruby -*- +# encoding: utf-8 + +source 'https://rubygems.org/' + +gem 'grpc', :git => 'https://github.com/grpc/grpc.git', :submodules => true, glob: 'src/ruby/*.gemspec' diff --git a/examples/ruby/README.md b/examples/ruby/README.md new file mode 100644 index 00000000000..dc21f5dd49d --- /dev/null +++ b/examples/ruby/README.md @@ -0,0 +1,61 @@ +gRPC in 3 minutes (Ruby) +======================== + +BACKGROUND +------------- +For this sample, we've already generated the server and client stubs from [helloworld.proto][] + +PREREQUISITES +------------- + +- Ruby 2.x +This requires Ruby 2.x, as the gRPC API surface uses keyword args. +If you don't have that installed locally, you can use [RVM][] to use Ruby 2.x for testing without upgrading the version of Ruby on your whole system. +RVM is also useful if you don't have the necessary privileges to update your system's Ruby. + + ```sh + $ # RVM installation as specified at https://rvm.io/rvm/install + $ gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 + $ \curl -sSL https://get.rvm.io | bash -s stable --ruby=ruby-2 + $ + $ # follow the instructions to ensure that your're using the latest stable version of Ruby + $ # and that the rvm command is installed + ``` +- *N.B* Make sure your run `source $HOME/.rvm/scripts/rvm` as instructed to complete the set-up of RVM. + +INSTALL +------- + +- Clone this repository +- Use bundler to install the example package's dependencies + + ```sh + $ # from this directory + $ gem install bundler # if you don't already have bundler available + $ bundle install + ``` + +Try it! +------- + +- Run the server + + ```sh + $ # from this directory + $ bundle exec ./greeter_server.rb & + ``` + +- Run the client + + ```sh + $ # from this directory + $ bundle exec ./greeter_client.rb + ``` + +Tutorial +-------- + +You can find a more detailed tutorial in [gRPC Basics: Ruby](examples/ruby/route_guide/README.md) + +[helloworld.proto]:examples/protos/helloworld.proto +[RVM]:https://www.rvm.io/ diff --git a/examples/ruby/greeter_client.rb b/examples/ruby/greeter_client.rb new file mode 100755 index 00000000000..e6cb4bad33e --- /dev/null +++ b/examples/ruby/greeter_client.rb @@ -0,0 +1,50 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Sample app that connects to a Greeter service. +# +# Usage: $ path/to/greeter_client.rb + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(this_dir, 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'helloworld_services' + +def main + stub = Helloworld::Greeter::Stub.new('localhost:50051') + user = ARGV.size > 0 ? ARGV[0] : 'world' + message = stub.say_hello(Helloworld::HelloRequest.new(name: user)).message + p "Greeting: #{message}" +end + +main diff --git a/examples/ruby/greeter_server.rb b/examples/ruby/greeter_server.rb new file mode 100755 index 00000000000..d4f9cf7d0f8 --- /dev/null +++ b/examples/ruby/greeter_server.rb @@ -0,0 +1,60 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Sample gRPC server that implements the Greeter::Helloworld service. +# +# Usage: $ path/to/greeter_server.rb + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(this_dir, 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'helloworld_services' + +# GreeterServer is simple server that implements the Helloworld Greeter server. +class GreeterServer < Helloworld::Greeter::Service + # say_hello implements the SayHello rpc method. + def say_hello(hello_req, _unused_call) + Helloworld::HelloReply.new(message: "Hello #{hello_req.name}") + end +end + +# main starts an RpcServer that receives requests to GreeterServer at the sample +# server port. +def main + s = GRPC::RpcServer.new + s.add_http2_port('0.0.0.0:50051') + s.handle(GreeterServer) + s.run +end + +main diff --git a/examples/ruby/grpc-demo.gemspec b/examples/ruby/grpc-demo.gemspec new file mode 100644 index 00000000000..2cc1eb8f41f --- /dev/null +++ b/examples/ruby/grpc-demo.gemspec @@ -0,0 +1,23 @@ +# -*- ruby -*- +# encoding: utf-8 + +Gem::Specification.new do |s| + s.name = 'grpc-demo' + s.version = '0.5.0' + s.authors = ['gRPC Authors'] + s.email = 'temiola@google.com' + s.homepage = 'https://github.com/grpc/grpc' + s.summary = 'gRPC Ruby overview sample' + s.description = 'Simple demo of using gRPC from Ruby' + + s.files = `git ls-files -- ruby/*`.split("\n") + s.executables = `git ls-files -- ruby/greeter*.rb ruby/route_guide/*.rb`.split("\n").map do |f| + File.basename(f) + end + s.require_paths = ['lib'] + s.platform = Gem::Platform::RUBY + + s.add_dependency 'grpc', '~> 0.6' + + s.add_development_dependency 'bundler', '~> 1.7' +end diff --git a/examples/ruby/lib/helloworld.rb b/examples/ruby/lib/helloworld.rb new file mode 100644 index 00000000000..82bdd78e2a4 --- /dev/null +++ b/examples/ruby/lib/helloworld.rb @@ -0,0 +1,18 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: helloworld.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "helloworld.HelloRequest" do + optional :name, :string, 1 + end + add_message "helloworld.HelloReply" do + optional :message, :string, 1 + end +end + +module Helloworld + HelloRequest = Google::Protobuf::DescriptorPool.generated_pool.lookup("helloworld.HelloRequest").msgclass + HelloReply = Google::Protobuf::DescriptorPool.generated_pool.lookup("helloworld.HelloReply").msgclass +end diff --git a/examples/ruby/lib/helloworld_services.rb b/examples/ruby/lib/helloworld_services.rb new file mode 100644 index 00000000000..7da45ebc6b2 --- /dev/null +++ b/examples/ruby/lib/helloworld_services.rb @@ -0,0 +1,24 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# Source: helloworld.proto for package 'helloworld' + +require 'grpc' +require 'helloworld' + +module Helloworld + module Greeter + + # TODO: add proto service documentation here + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'helloworld.Greeter' + + rpc :SayHello, HelloRequest, HelloReply + end + + Stub = Service.rpc_stub_class + end +end diff --git a/examples/ruby/lib/route_guide.rb b/examples/ruby/lib/route_guide.rb new file mode 100644 index 00000000000..98bac8395ce --- /dev/null +++ b/examples/ruby/lib/route_guide.rb @@ -0,0 +1,37 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: route_guide.proto + +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_message "examples.Point" do + optional :latitude, :int32, 1 + optional :longitude, :int32, 2 + end + add_message "examples.Rectangle" do + optional :lo, :message, 1, "examples.Point" + optional :hi, :message, 2, "examples.Point" + end + add_message "examples.Feature" do + optional :name, :string, 1 + optional :location, :message, 2, "examples.Point" + end + add_message "examples.RouteNote" do + optional :location, :message, 1, "examples.Point" + optional :message, :string, 2 + end + add_message "examples.RouteSummary" do + optional :point_count, :int32, 1 + optional :feature_count, :int32, 2 + optional :distance, :int32, 3 + optional :elapsed_time, :int32, 4 + end +end + +module Examples + Point = Google::Protobuf::DescriptorPool.generated_pool.lookup("examples.Point").msgclass + Rectangle = Google::Protobuf::DescriptorPool.generated_pool.lookup("examples.Rectangle").msgclass + Feature = Google::Protobuf::DescriptorPool.generated_pool.lookup("examples.Feature").msgclass + RouteNote = Google::Protobuf::DescriptorPool.generated_pool.lookup("examples.RouteNote").msgclass + RouteSummary = Google::Protobuf::DescriptorPool.generated_pool.lookup("examples.RouteSummary").msgclass +end diff --git a/examples/ruby/lib/route_guide_services.rb b/examples/ruby/lib/route_guide_services.rb new file mode 100644 index 00000000000..6e07653c425 --- /dev/null +++ b/examples/ruby/lib/route_guide_services.rb @@ -0,0 +1,27 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# Source: route_guide.proto for package 'examples' + +require 'grpc' +require 'route_guide' + +module Examples + module RouteGuide + + # TODO: add proto service documentation here + class Service + + include GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'examples.RouteGuide' + + rpc :GetFeature, Point, Feature + rpc :ListFeatures, Rectangle, stream(Feature) + rpc :RecordRoute, stream(Point), RouteSummary + rpc :RouteChat, stream(RouteNote), stream(RouteNote) + end + + Stub = Service.rpc_stub_class + end +end diff --git a/examples/ruby/route_guide/README.md b/examples/ruby/route_guide/README.md new file mode 100644 index 00000000000..c7231fb43f3 --- /dev/null +++ b/examples/ruby/route_guide/README.md @@ -0,0 +1,285 @@ +#gRPC Basics: Ruby + +This tutorial provides a basic Ruby programmer's introduction to working with gRPC. By walking through this example you'll learn how to: + +- Define a service in a .proto file. +- Generate server and client code using the protocol buffer compiler. +- Use the Ruby gRPC API to write a simple client and server for your service. + +It assumes that you have read the [Getting started](https://github.com/grpc/grpc/tree/master/examples) guide and are familiar with [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). Note that the example in this tutorial uses the proto3 version of the protocol buffers language, which is currently in alpha release:you can find out more in the [proto3 language guide](https://developers.google.com/protocol-buffers/docs/proto3) and see the [release notes](https://github.com/google/protobuf/releases) for the new version in the protocol buffers Github repository. + +This isn't a comprehensive guide to using gRPC in Ruby: more reference documentation is coming soon. + +## Why use gRPC? + +Our example is a simple route mapping application that lets clients get information about features on their route, create a summary of their route, and exchange route information such as traffic updates with the server and other clients. + +With gRPC we can define our service once in a .proto file and implement clients and servers in any of gRPC's supported languages, which in turn can be run in environments ranging from servers inside Google to your own tablet - all the complexity of communication between different languages and environments is handled for you by gRPC. We also get all the advantages of working with protocol buffers, including efficient serialization, a simple IDL, and easy interface updating. + +## Example code and setup + +The example code for our tutorial is in [examples/ruby/route_guide](examples/ruby/route_guide). To download the example, clone this repository by running the following command: +```shell +$ git clone https://github.com/grpc/grpc.git +``` + +Then change your current directory to `examples/ruby/route_guide`: +```shell +$ cd examples/ruby/route_guide +``` + +You also should have the relevant tools installed to generate the server and client interface code - if you don't already, follow the setup instructions in [the Ruby quick start guide](examples/ruby). + + +## Defining the service + +Our first step (as you'll know from [Getting started](https://github.com/grpc/grpc/tree/master/examples)) is to define the gRPC *service* and the method *request* and *response* types using [protocol buffers] (https://developers.google.com/protocol-buffers/docs/overview). You can see the complete .proto file in [`examples/protos/route_guide.proto`](examples/protos/route_guide.proto). + +To define a service, you specify a named `service` in your .proto file: + +```protobuf +service RouteGuide { + ... +} +``` + +Then you define `rpc` methods inside your service definition, specifying their request and response types. gRPC lets you define four kinds of service method, all of which are used in the `RouteGuide` service: + +- A *simple RPC* where the client sends a request to the server using the stub and waits for a response to come back, just like a normal function call. +```protobuf + // Obtains the feature at a given position. + rpc GetFeature(Point) returns (Feature) {} +``` + +- A *server-side streaming RPC* where the client sends a request to the server and gets a stream to read a sequence of messages back. The client reads from the returned stream until there are no more messages. As you can see in our example, you specify a server-side streaming method by placing the `stream` keyword before the *response* type. +```protobuf + // Obtains the Features available within the given Rectangle. Results are + // streamed rather than returned at once (e.g. in a response message with a + // repeated field), as the rectangle may cover a large area and contain a + // huge number of features. + rpc ListFeatures(Rectangle) returns (stream Feature) {} +``` + +- A *client-side streaming RPC* where the client writes a sequence of messages and sends them to the server, again using a provided stream. Once the client has finished writing the messages, it waits for the server to read them all and return its response. You specify a server-side streaming method by placing the `stream` keyword before the *request* type. +```protobuf + // Accepts a stream of Points on a route being traversed, returning a + // RouteSummary when traversal is completed. + rpc RecordRoute(stream Point) returns (RouteSummary) {} +``` + +- A *bidirectional streaming RPC* where both sides send a sequence of messages using a read-write stream. The two streams operate independently, so clients and servers can read and write in whatever order they like: for example, the server could wait to receive all the client messages before writing its responses, or it could alternately read a message then write a message, or some other combination of reads and writes. The order of messages in each stream is preserved. You specify this type of method by placing the `stream` keyword before both the request and the response. +```protobuf + // Accepts a stream of RouteNotes sent while a route is being traversed, + // while receiving other RouteNotes (e.g. from other users). + rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} +``` + +Our .proto file also contains protocol buffer message type definitions for all the request and response types used in our service methods - for example, here's the `Point` message type: +```protobuf +// Points are represented as latitude-longitude pairs in the E7 representation +// (degrees multiplied by 10**7 and rounded to the nearest integer). +// Latitudes should be in the range +/- 90 degrees and longitude should be in +// the range +/- 180 degrees (inclusive). +message Point { + int32 latitude = 1; + int32 longitude = 2; +} +``` + + +## Generating client and server code + +Next we need to generate the gRPC client and server interfaces from our .proto service definition. We do this using the protocol buffer compiler `protoc` with a special gRPC Ruby plugin. + +If you want to run this yourself, make sure you've installed protoc and followed the gRPC Ruby plugin [installation instructions](https://github.com/grpc/grpc/blob/master/INSTALL) first): + +Once that's done, the following command can be used to generate the ruby code. + +```shell +$ protoc -I ../../protos --ruby_out=lib --grpc_out=lib --plugin=protoc-gen-grpc=`which grpc_ruby_plugin` ../../protos/route_guide.proto +``` + +Running this command regenerates the following files in the lib directory: +- `lib/route_guide.pb` defines a module `Examples::RouteGuide` + - This contain all the protocol buffer code to populate, serialize, and retrieve our request and response message types +- `lib/route_guide_services.pb`, extends `Examples::RouteGuide` with stub and service classes + - a class `Service` for use as a base class when defining RouteGuide service implementations + - a class `Stub` that can be used to access remote RouteGuide instances + + + +## Creating the server + +First let's look at how we create a `RouteGuide` server. If you're only interested in creating gRPC clients, you can skip this section and go straight to [Creating the client](#client) (though you might find it interesting anyway!). + +There are two parts to making our `RouteGuide` service do its job: +- Implementing the service interface generated from our service definition: doing the actual "work" of our service. +- Running a gRPC server to listen for requests from clients and return the service responses. + +You can find our example `RouteGuide` server in [examples/ruby/route_guide/route_guide_server.rb](examples/ruby/route_guide/route_guide_server.rb). Let's take a closer look at how it works. + +### Implementing RouteGuide + +As you can see, our server has a `ServerImpl` class that extends the generated `RouteGuide::Service`: + +```ruby +# ServerImpl provides an implementation of the RouteGuide service. +class ServerImpl < RouteGuide::Service +``` + +`ServerImpl` implements all our service methods. Let's look at the simplest type first, `GetFeature`, which just gets a `Point` from the client and returns the corresponding feature information from its database in a `Feature`. + +```ruby + def get_feature(point, _call) + name = @feature_db[{ + 'longitude' => point.longitude, + 'latitude' => point.latitude }] || '' + Feature.new(location: point, name: name) + end +``` + +The method is passed a _call for the RPC, the client's `Point` protocol buffer request, and returns a `Feature` protocol buffer. In the method we create the `Feature` with the appropriate information, and then `return` it. + +Now let's look at something a bit more complicated - a streaming RPC. `ListFeatures` is a server-side streaming RPC, so we need to send back multiple `Feature`s to our client. + +```ruby +# in ServerImpl + + def list_features(rectangle, _call) + RectangleEnum.new(@feature_db, rectangle).each + end +``` + +As you can see, here the request object is a `Rectangle` in which our client wants to find `Feature`s, but instead of returning a simple response we need to return an [Enumerator](http://ruby-doc.org//core-2.2.0/Enumerator.html) that yields the responses. In the method, we use a helper class `RectangleEnum`, to act as an Enumerator implementation. + +Similarly, the client-side streaming method `record_route` uses an [Enumerable](http://ruby-doc.org//core-2.2.0/Enumerable.html), but here it's obtained from the call object, which we've ignored in the earlier examples. `call.each_remote_read` yields each message sent by the client in turn. + +```ruby + call.each_remote_read do |point| + ... + end +``` +Finally, let's look at our bidirectional streaming RPC `route_chat`. + +```ruby + def route_chat(notes) + q = EnumeratorQueue.new(self) + t = Thread.new do + begin + notes.each do |n| + ... + end + end + q = EnumeratorQueue.new(self) + ... + return q.each_item + end +``` + +Here the method receives an [Enumerable](http://ruby-doc.org//core-2.2.0/Enumerable.html), but also returns an [Enumerator](http://ruby-doc.org//core-2.2.0/Enumerator.html) that yields the responses. The implementation demonstrates how to set these up so that the requests and responses can be handled concurrently. Although each side will always get the other's messages in the order they were written, both the client and server can read and write in any order — the streams operate completely independently. + +### Starting the server + +Once we've implemented all our methods, we also need to start up a gRPC server so that clients can actually use our service. The following snippet shows how we do this for our `RouteGuide` service: + +```ruby + s = GRPC::RpcServer.new + s.add_http2_port(port) + logger.info("... running insecurely on #{port}") + s.handle(ServerImpl.new(feature_db)) + s.run +``` +As you can see, we build and start our server using a `GRPC::RpcServer`. To do this, we: + +1. Create an instance of our service implementation class `ServerImpl`. +2. Specify the address and port we want to use to listen for client requests using the builder's `add_http2_port` method. +3. Register our service implementation with the `GRPC::RpcServer`. +4. Call `run` on the`GRPC::RpcServer` to create and start an RPC server for our service. + + +## Creating the client + +In this section, we'll look at creating a Ruby client for our `RouteGuide` service. You can see our complete example client code in [examples/ruby/route_guide/route_guide_client.rb](examples/ruby/route_guide/route_guide_client.rb). + +### Creating a stub + +To call service methods, we first need to create a *stub*. + +We use the `Stub` class of the `RouteGuide` module generated from our .proto. + +```ruby + stub = RouteGuide::Stub.new('localhost:50051') +``` + +### Calling service methods + +Now let's look at how we call our service methods. Note that the gRPC Ruby only provides *blocking/synchronous* versions of each method: this means that the RPC call waits for the server to respond, and will either return a response or raise an exception. + +#### Simple RPC + +Calling the simple RPC `GetFeature` is nearly as straightforward as calling a local method. + +```ruby +GET_FEATURE_POINTS = [ + Point.new(latitude: 409_146_138, longitude: -746_188_906), + Point.new(latitude: 0, longitude: 0) +] +.. + GET_FEATURE_POINTS.each do |pt| + resp = stub.get_feature(pt) + ... + p "- found '#{resp.name}' at #{pt.inspect}" + end +``` + +As you can see, we create and populate a request protocol buffer object (in our case `Point`), and create a response protocol buffer object for the server to fill in. Finally, we call the method on the stub, passing it the context, request, and response. If the method returns `OK`, then we can read the response information from the server from our response object. + + +#### Streaming RPCs + +Now let's look at our streaming methods. If you've already read [Creating the server](#server) some of this may look very familiar - streaming RPCs are implemented in a similar way on both sides. Here's where we call the server-side streaming method `list_features`, which returns an `Enumerable` of `Features` + +```ruby + resps = stub.list_features(LIST_FEATURES_RECT) + resps.each do |r| + p "- found '#{r.name}' at #{r.location.inspect}" + end +``` + +The client-side streaming method `record_route` is similar, except there we pass the server an `Enumerable`. + +```ruby + ... + reqs = RandomRoute.new(features, points_on_route) + resp = stub.record_route(reqs.each, deadline) + ... +``` + +Finally, let's look at our bidirectional streaming RPC `route_chat`. In this case, we pass `Enumerable` to the method and get back an `Enumerable`. + +```ruby + resps = stub.route_chat(ROUTE_CHAT_NOTES) + resps.each { |r| p "received #{r.inspect}" } +``` + +Although it's not shown well by this example, each enumerable is independent of the other - both the client and server can read and write in any order — the streams operate completely independently. + +## Try it out! + +Build client and server: + +```shell +$ # from examples/ruby +$ gem install bundler && bundle install +``` +Run the server, which will listen on port 50051: +```shell +$ # from examples/ruby +$ bundle exec route_guide/route_guide_server.rb ../node/route_guide/route_guide_db.json & +``` +Run the client (in a different terminal): +```shell +$ # from examples/ruby +$ bundle exec route_guide/route_guide_client.rb ../node/route_guide/route_guide_db.json & +``` + diff --git a/examples/ruby/route_guide/route_guide_client.rb b/examples/ruby/route_guide/route_guide_client.rb new file mode 100755 index 00000000000..181623a68ac --- /dev/null +++ b/examples/ruby/route_guide/route_guide_client.rb @@ -0,0 +1,165 @@ +#!/usr/bin/env ruby + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Sample app that connects to a Route Guide service. +# +# Usage: $ path/to/route_guide_client.rb path/to/route_guide_db.json & + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(File.dirname(this_dir), 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'route_guide_services' + +include Examples + +GET_FEATURE_POINTS = [ + Point.new(latitude: 409_146_138, longitude: -746_188_906), + Point.new(latitude: 0, longitude: 0) +] + +# runs a GetFeature rpc. +# +# - once with a point known to be present in the sample route database +# - once with a point that is not in the sample database +def run_get_feature(stub) + p 'GetFeature' + p '----------' + GET_FEATURE_POINTS.each do |pt| + resp = stub.get_feature(pt) + if resp.name != '' + p "- found '#{resp.name}' at #{pt.inspect}" + else + p "- found nothing at #{pt.inspect}" + end + end +end + +LIST_FEATURES_RECT = Rectangle.new( + lo: Point.new(latitude: 400_000_000, longitude: -750_000_000), + hi: Point.new(latitude: 420_000_000, longitude: -730_000_000)) + +# runs a ListFeatures rpc. +# +# - the rectangle to chosen to include most of the known features +# in the sample db. +def run_list_features(stub) + p 'ListFeatures' + p '------------' + resps = stub.list_features(LIST_FEATURES_RECT) + resps.each do |r| + p "- found '#{r.name}' at #{r.location.inspect}" + end +end + +# RandomRoute provides an Enumerable that yields a random 'route' of points +# from a list of Features. +class RandomRoute + def initialize(features, size) + @features = features + @size = size + end + + # yields a point, waiting between 0 and 1 seconds between each yield + # + # @return an Enumerable that yields a random point + def each + return enum_for(:each) unless block_given? + @size.times do + json_feature = @features[rand(0..@features.length)] + next if json_feature.nil? + location = json_feature['location'] + pt = Point.new( + Hash[location.each_pair.map { |k, v| [k.to_sym, v] }]) + p "- next point is #{pt.inspect}" + yield pt + sleep(rand(0..1)) + end + end +end + +# runs a RecordRoute rpc. +# +# - the rectangle to chosen to include most of the known features +# in the sample db. +def run_record_route(stub, features) + p 'RecordRoute' + p '-----------' + points_on_route = 10 # arbitrary + deadline = points_on_route # as delay b/w each is max 1 second + reqs = RandomRoute.new(features, points_on_route) + resp = stub.record_route(reqs.each, deadline) + p "summary: #{resp.inspect}" +end + +ROUTE_CHAT_NOTES = [ + RouteNote.new(message: 'doh - a deer', + location: Point.new(latitude: 0, longitude: 0)), + RouteNote.new(message: 'ray - a drop of golden sun', + location: Point.new(latitude: 0, longitude: 1)), + RouteNote.new(message: 'me - the name I call myself', + location: Point.new(latitude: 1, longitude: 0)), + RouteNote.new(message: 'fa - a longer way to run', + location: Point.new(latitude: 1, longitude: 1)), + RouteNote.new(message: 'soh - with needle and a thread', + location: Point.new(latitude: 0, longitude: 1)) +] + +# runs a RouteChat rpc. +# +# sends a canned set of route notes and prints out the responses. +def run_route_chat(stub) + p 'Route Chat' + p '----------' + # TODO: decouple sending and receiving, i.e have the response enumerator run + # on its own thread. + resps = stub.route_chat(ROUTE_CHAT_NOTES) + resps.each { |r| p "received #{r.inspect}" } +end + +def main + stub = RouteGuide::Stub.new('localhost:50051') + run_get_feature(stub) + run_list_features(stub) + run_route_chat(stub) + if ARGV.length == 0 + p 'no feature database; skipping record_route' + exit + end + raw_data = [] + File.open(ARGV[0]) do |f| + raw_data = MultiJson.load(f.read) + end + run_record_route(stub, raw_data) +end + +main diff --git a/examples/ruby/route_guide/route_guide_server.rb b/examples/ruby/route_guide/route_guide_server.rb new file mode 100755 index 00000000000..2b2b8084ef9 --- /dev/null +++ b/examples/ruby/route_guide/route_guide_server.rb @@ -0,0 +1,211 @@ +#!/usr/bin/env ruby +# -*- coding: utf-8 -*- + +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Sample app that connects to a Route Guide service. +# +# Usage: $ path/to/route_guide_server.rb path/to/route_guide_db.json & + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(File.dirname(this_dir), 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'multi_json' +require 'route_guide_services' + +include Examples +COORD_FACTOR = 1e7 +RADIUS = 637_100 + +# Determines the distance between two points. +def calculate_distance(point_a, point_b) + to_radians = proc { |x| x * Math::PI / 180 } + lat_a = point_a.latitude / COORD_FACTOR + lat_b = point_b.latitude / COORD_FACTOR + long_a = point_a.longitude / COORD_FACTOR + long_b = point_b.longitude / COORD_FACTOR + φ1 = to_radians.call(lat_a) + φ2 = to_radians.call(lat_b) + Δφ = to_radians.call(lat_a - lat_b) + Δλ = to_radians.call(long_a - long_b) + a = Math.sin(Δφ / 2)**2 + + Math.cos(φ1) * Math.cos(φ2) + + Math.sin(Δλ / 2)**2 + (2 * RADIUS * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))).to_i +end + +# RectangleEnum provides an Enumerator of the points in a feature_db within a +# given Rectangle. +class RectangleEnum + # @param [Hash] feature_db + # @param [Rectangle] bounds + def initialize(feature_db, bounds) + @feature_db = feature_db + @bounds = bounds + lats = [@bounds.lo.latitude, @bounds.hi.latitude] + longs = [@bounds.lo.longitude, @bounds.hi.longitude] + @lo_lat, @hi_lat = lats.min, lats.max + @lo_long, @hi_long = longs.min, longs.max + end + + # in? determines if location lies within the bounds of this instances + # Rectangle. + def in?(location) + location['longitude'] >= @lo_long && + location['longitude'] <= @hi_long && + location['latitude'] >= @lo_lat && + location['latitude'] <= @hi_lat + end + + # each yields the features in the instances feature_db that lie within the + # instance rectangle. + def each + return enum_for(:each) unless block_given? + @feature_db.each_pair do |location, name| + next unless in?(location) + next if name.nil? || name == '' + pt = Point.new( + Hash[location.each_pair.map { |k, v| [k.to_sym, v] }]) + yield Feature.new(location: pt, name: name) + end + end +end + +# A EnumeratorQueue wraps a Queue to yield the items added to it. +class EnumeratorQueue + extend Forwardable + def_delegators :@q, :push + + def initialize(sentinel) + @q = Queue.new + @sentinel = sentinel + @received_notes = {} + end + + def each_item + return enum_for(:each_item) unless block_given? + loop do + r = @q.pop + break if r.equal?(@sentinel) + fail r if r.is_a? Exception + yield r + end + end +end + +# ServerImpl provides an implementation of the RouteGuide service. +class ServerImpl < RouteGuide::Service + # @param [Hash] feature_db {location => name} + def initialize(feature_db) + @feature_db = feature_db + @received_notes = Hash.new { |h, k| h[k] = [] } + end + + def get_feature(point, _call) + name = @feature_db[{ + 'longitude' => point.longitude, + 'latitude' => point.latitude }] || '' + Feature.new(location: point, name: name) + end + + def list_features(rectangle, _call) + RectangleEnum.new(@feature_db, rectangle).each + end + + def record_route(call) + started, elapsed_time = 0, 0 + distance, count, features, last = 0, 0, 0, nil + call.each_remote_read do |point| + count += 1 + name = @feature_db[{ + 'longitude' => point.longitude, + 'latitude' => point.latitude }] || '' + features += 1 unless name == '' + if last.nil? + last = point + started = Time.now.to_i + next + end + elapsed_time = Time.now.to_i - started + distance += calculate_distance(point, last) + last = point + end + RouteSummary.new(point_count: count, + feature_count: features, + distance: distance, + elapsed_time: elapsed_time) + end + + def route_chat(notes) + q = EnumeratorQueue.new(self) + # run a separate thread that processes the incoming requests + t = Thread.new do + begin + notes.each do |n| + key = { + 'latitude' => n.location.latitude, + 'longitude' => n.location.longitude + } + earlier_msgs = @received_notes[key] + @received_notes[key] << n.message + # send back the earlier messages at this point + earlier_msgs.each do |r| + q.push(RouteNote.new(location: n.location, message: r)) + end + end + q.push(self) # signal completion + rescue StandardError => e + q.push(e) # signal completion via an error + end + end + q.each_item + end +end + +def main + if ARGV.length == 0 + fail 'Please specify the path to the route_guide json database' + end + raw_data = [] + File.open(ARGV[0]) do |f| + raw_data = MultiJson.load(f.read) + end + feature_db = Hash[raw_data.map { |x| [x['location'], x['name']] }] + port = '0.0.0.0:50051' + s = GRPC::RpcServer.new + s.add_http2_port(port) + GRPC.logger.info("... running insecurely on #{port}") + s.handle(ServerImpl.new(feature_db)) + s.run +end + +main diff --git a/gRPC.podspec b/gRPC.podspec index 28a4ad45e0d..79315f65c06 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -68,6 +68,7 @@ Pod::Spec.new do |s| 'src/core/support/grpc_string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', + 'src/core/support/time_precise.h', 'grpc/support/alloc.h', 'grpc/support/atm.h', 'grpc/support/atm_gcc_atomic.h', @@ -210,7 +211,6 @@ Pod::Spec.new do |s| 'src/core/json/json_reader.h', 'src/core/json/json_writer.h', 'src/core/profiling/timers.h', - 'src/core/profiling/timers_preciseclock.h', 'src/core/statistics/census_interface.h', 'src/core/statistics/census_rpc_stats.h', 'src/core/surface/byte_buffer_queue.h', @@ -403,6 +403,7 @@ Pod::Spec.new do |s| 'src/core/support/string.h', 'src/core/support/string_win32.h', 'src/core/support/thd_internal.h', + 'src/core/support/time_precise.h', 'src/core/security/auth_filters.h', 'src/core/security/base64.h', 'src/core/security/credentials.h', @@ -481,7 +482,6 @@ Pod::Spec.new do |s| 'src/core/json/json_reader.h', 'src/core/json/json_writer.h', 'src/core/profiling/timers.h', - 'src/core/profiling/timers_preciseclock.h', 'src/core/statistics/census_interface.h', 'src/core/statistics/census_rpc_stats.h', 'src/core/surface/byte_buffer_queue.h', diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h index ee28f360cbe..62e5260a180 100644 --- a/include/grpc++/client_context.h +++ b/include/grpc++/client_context.h @@ -45,6 +45,7 @@ #include #include #include +#include #include struct census_context; @@ -138,12 +139,14 @@ class ClientContext { void AddMetadata(const grpc::string& meta_key, const grpc::string& meta_value); - const std::multimap& GetServerInitialMetadata() { + const std::multimap& + GetServerInitialMetadata() { GPR_ASSERT(initial_metadata_received_); return recv_initial_metadata_; } - const std::multimap& GetServerTrailingMetadata() { + const std::multimap& + GetServerTrailingMetadata() { // TODO(yangg) check finished return trailing_metadata_; } @@ -234,8 +237,8 @@ class ClientContext { mutable std::shared_ptr auth_context_; struct census_context* census_context_; std::multimap send_initial_metadata_; - std::multimap recv_initial_metadata_; - std::multimap trailing_metadata_; + std::multimap recv_initial_metadata_; + std::multimap trailing_metadata_; grpc_call* propagate_from_call_; PropagationOptions propagation_options_; diff --git a/include/grpc++/create_channel.h b/include/grpc++/create_channel.h index 0e559ac53e4..916f3b0b97c 100644 --- a/include/grpc++/create_channel.h +++ b/include/grpc++/create_channel.h @@ -44,6 +44,12 @@ namespace grpc { // If creds does not hold an object or is invalid, a lame channel is returned. std::shared_ptr CreateChannel( + const grpc::string& target, const std::shared_ptr& creds); + +// For advanced use and testing ONLY. Override default channel arguments only +// if necessary. +// If creds does not hold an object or is invalid, a lame channel is returned. +std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args); diff --git a/include/grpc++/credentials.h b/include/grpc++/credentials.h index 71e1f00f15a..d623bcef604 100644 --- a/include/grpc++/credentials.h +++ b/include/grpc++/credentials.h @@ -57,7 +57,7 @@ class Credentials : public GrpcLibrary { virtual SecureCredentials* AsSecureCredentials() = 0; private: - friend std::shared_ptr CreateChannel( + friend std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args); diff --git a/include/grpc++/impl/call.h b/include/grpc++/impl/call.h index e5da6c9e2af..fca56030479 100644 --- a/include/grpc++/impl/call.h +++ b/include/grpc++/impl/call.h @@ -54,8 +54,9 @@ namespace grpc { class ByteBuffer; class Call; -void FillMetadataMap(grpc_metadata_array* arr, - std::multimap* metadata); +void FillMetadataMap( + grpc_metadata_array* arr, + std::multimap* metadata); grpc_metadata* FillMetadataArray( const std::multimap& metadata); @@ -418,7 +419,7 @@ class CallOpRecvInitialMetadata { } private: - std::multimap* recv_initial_metadata_; + std::multimap* recv_initial_metadata_; grpc_metadata_array recv_initial_metadata_arr_; }; @@ -461,7 +462,7 @@ class CallOpClientRecvStatus { } private: - std::multimap* recv_trailing_metadata_; + std::multimap* recv_trailing_metadata_; Status* recv_status_; grpc_metadata_array recv_trailing_metadata_arr_; grpc_status_code status_code_; diff --git a/include/grpc++/server_context.h b/include/grpc++/server_context.h index ce3cb47a237..4b17a280471 100644 --- a/include/grpc++/server_context.h +++ b/include/grpc++/server_context.h @@ -41,6 +41,7 @@ #include #include #include +#include #include struct gpr_timespec; @@ -103,7 +104,7 @@ class ServerContext { bool IsCancelled() const; - const std::multimap& client_metadata() { + const std::multimap& client_metadata() { return client_metadata_; } @@ -185,7 +186,7 @@ class ServerContext { CompletionQueue* cq_; bool sent_initial_metadata_; mutable std::shared_ptr auth_context_; - std::multimap client_metadata_; + std::multimap client_metadata_; std::multimap initial_metadata_; std::multimap trailing_metadata_; diff --git a/include/grpc++/support/auth_context.h b/include/grpc++/support/auth_context.h index f4f2dcf5bbd..67e3e66c05b 100644 --- a/include/grpc++/support/auth_context.h +++ b/include/grpc++/support/auth_context.h @@ -38,6 +38,7 @@ #include #include +#include struct grpc_auth_context; struct grpc_auth_property; @@ -46,7 +47,7 @@ struct grpc_auth_property_iterator; namespace grpc { class SecureAuthContext; -typedef std::pair AuthProperty; +typedef std::pair AuthProperty; class AuthPropertyIterator : public std::iterator { @@ -78,11 +79,11 @@ class AuthContext { // A peer identity, in general is one or more properties (in which case they // have the same name). - virtual std::vector GetPeerIdentity() const = 0; + virtual std::vector GetPeerIdentity() const = 0; virtual grpc::string GetPeerIdentityPropertyName() const = 0; // Returns all the property values with the given name. - virtual std::vector FindPropertyValues( + virtual std::vector FindPropertyValues( const grpc::string& name) const = 0; // Iteration over all the properties. diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h index 0ec39a9b0a6..2bc1fecefeb 100644 --- a/include/grpc++/support/string_ref.h +++ b/include/grpc++/support/string_ref.h @@ -31,10 +31,11 @@ * */ -#ifndef GRPCXX_STRING_REF_H -#define GRPCXX_STRING_REF_H +#ifndef GRPCXX_SUPPORT_STRING_REF_H +#define GRPCXX_SUPPORT_STRING_REF_H #include +#include #include @@ -43,6 +44,8 @@ namespace grpc { // This class is a non owning reference to a string. // It should be a strict subset of the upcoming std::string_ref. See: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html +// The constexpr is dropped or replaced with const for legacy compiler +// compatibility. class string_ref { public: // types @@ -50,22 +53,22 @@ class string_ref { typedef std::reverse_iterator const_reverse_iterator; // constants - static constexpr size_t npos = size_t(-1); + const static size_t npos = size_t(-1); // construct/copy. - constexpr string_ref() : data_(nullptr), length_(0) {} - constexpr string_ref(const string_ref& other) + string_ref() : data_(nullptr), length_(0) {} + string_ref(const string_ref& other) : data_(other.data_), length_(other.length_) {} string_ref& operator=(const string_ref& rhs); string_ref(const char* s); - constexpr string_ref(const char* s, size_t l) : data_(s), length_(l) {} + string_ref(const char* s, size_t l) : data_(s), length_(l) {} string_ref(const grpc::string& s) : data_(s.data()), length_(s.length()) {} // iterators - constexpr const_iterator begin() const { return data_; } - constexpr const_iterator end() const { return data_ + length_; } - constexpr const_iterator cbegin() const { return data_; } - constexpr const_iterator cend() const { return data_ + length_; } + const_iterator begin() const { return data_; } + const_iterator end() const { return data_ + length_; } + const_iterator cbegin() const { return data_; } + const_iterator cend() const { return data_ + length_; } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } @@ -80,10 +83,10 @@ class string_ref { } // capacity - constexpr size_t size() const { return length_; } - constexpr size_t length() const { return length_; } - constexpr size_t max_size() const { return length_; } - constexpr bool empty() const { return length_ == 0; } + size_t size() const { return length_; } + size_t length() const { return length_; } + size_t max_size() const { return length_; } + bool empty() const { return length_ == 0; } // element access const char* data() const { return data_; } @@ -95,9 +98,7 @@ class string_ref { size_t find(string_ref s) const; size_t find(char c) const; - // Defined as constexpr in n3442 but C++11 constexpr semantics do not allow - // the implementation of this function to comply. - /* constrexpr */ string_ref substr(size_t pos, size_t n = npos) const; + string_ref substr(size_t pos, size_t n = npos) const; private: const char* data_; @@ -112,8 +113,8 @@ bool operator>(string_ref x, string_ref y); bool operator<=(string_ref x, string_ref y); bool operator>=(string_ref x, string_ref y); -} // namespace grpc - -#endif // GRPCXX_STRING_REF_H +std::ostream& operator<<(std::ostream& stream, const string_ref& string); +} // namespace grpc +#endif // GRPCXX_SUPPORT_STRING_REF_H diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index 101fc88d8f6..a75f3563127 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -134,6 +134,14 @@ typedef struct { /** Secondary user agent: goes at the end of the user-agent metadata sent on each request */ #define GRPC_ARG_SECONDARY_USER_AGENT_STRING "grpc.secondary_user_agent" +/* The caller of the secure_channel_create functions may override the target + name used for SSL host name checking using this channel argument which is of + type GRPC_ARG_STRING. This *should* be used for testing only. + If this argument is not specified, the name used for SSL host name checking + will be the target parameter (assuming that the secure channel is an SSL + channel). If this parameter is specified and the underlying is not an SSL + channel, it will just be ignored. */ +#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override" /** Connectivity state of a channel. */ typedef enum { @@ -206,8 +214,7 @@ typedef struct grpc_metadata { /** The following fields are reserved for grpc internal use. There is no need to initialize them, and they will be set to garbage - during - calls to grpc. */ + during calls to grpc. */ struct { void *obfuscated[4]; } internal_data; diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 7f8f4d4a053..6ee6933207f 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -89,16 +89,18 @@ typedef struct { key and certificate chain. This parameter can be NULL if the client does not have such a key/cert pair. */ grpc_credentials *grpc_ssl_credentials_create( - const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair); + const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, + void *reserved); /* Creates a composite credentials object. */ grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, - grpc_credentials *creds2); + grpc_credentials *creds2, + void *reserved); /* Creates a compute engine credentials object. WARNING: Do NOT use this credentials to connect to a non-google service as this could result in an oauth2 token leak. */ -grpc_credentials *grpc_compute_engine_credentials_create(void); +grpc_credentials *grpc_compute_engine_credentials_create(void *reserved); extern const gpr_timespec grpc_max_auth_token_lifetime; @@ -112,7 +114,8 @@ extern const gpr_timespec grpc_max_auth_token_lifetime; account credentials. It should not exceed grpc_max_auth_token_lifetime or will be cropped to this value. */ grpc_credentials *grpc_service_account_credentials_create( - const char *json_key, const char *scope, gpr_timespec token_lifetime); + const char *json_key, const char *scope, gpr_timespec token_lifetime, + void *reserved); /* Creates a JWT credentials object. May return NULL if the input is invalid. - json_key is the JSON key string containing the client's private key. @@ -120,7 +123,7 @@ grpc_credentials *grpc_service_account_credentials_create( this credentials. It should not exceed grpc_max_auth_token_lifetime or will be cropped to this value. */ grpc_credentials *grpc_service_account_jwt_access_credentials_create( - const char *json_key, gpr_timespec token_lifetime); + const char *json_key, gpr_timespec token_lifetime, void *reserved); /* Creates an Oauth2 Refresh Token credentials object. May return NULL if the input is invalid. @@ -129,32 +132,25 @@ grpc_credentials *grpc_service_account_jwt_access_credentials_create( - json_refresh_token is the JSON string containing the refresh token itself along with a client_id and client_secret. */ grpc_credentials *grpc_refresh_token_credentials_create( - const char *json_refresh_token); + const char *json_refresh_token, void *reserved); /* Creates an Oauth2 Access Token credentials with an access token that was aquired by an out of band mechanism. */ grpc_credentials *grpc_access_token_credentials_create( - const char *access_token); + const char *access_token, void *reserved); /* Creates an IAM credentials object. */ grpc_credentials *grpc_iam_credentials_create(const char *authorization_token, - const char *authority_selector); + const char *authority_selector, + void *reserved); /* --- Secure channel creation. --- */ -/* The caller of the secure_channel_create functions may override the target - name used for SSL host name checking using this channel argument which is of - type GRPC_ARG_STRING. This *should* be used for testing only. - If this argument is not specified, the name used for SSL host name checking - will be the target parameter (assuming that the secure channel is an SSL - channel). If this parameter is specified and the underlying is not an SSL - channel, it will just be ignored. */ -#define GRPC_SSL_TARGET_NAME_OVERRIDE_ARG "grpc.ssl_target_name_override" - /* Creates a secure channel using the passed-in credentials. */ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, const char *target, - const grpc_channel_args *args); + const grpc_channel_args *args, + void *reserved); /* --- grpc_server_credentials object. --- @@ -180,7 +176,7 @@ void grpc_server_credentials_release(grpc_server_credentials *creds); NULL. */ grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, - size_t num_key_cert_pairs, int force_client_auth); + size_t num_key_cert_pairs, int force_client_auth, void *reserved); /* --- Server-side secure ports. --- */ diff --git a/include/grpc/support/time.h b/include/grpc/support/time.h index 4ef9c764592..f8ed893bc02 100644 --- a/include/grpc/support/time.h +++ b/include/grpc/support/time.h @@ -52,6 +52,9 @@ typedef enum { /* Realtime clock. May jump forwards or backwards. Settable by the system administrator. Has its epoch at 0:00:00 UTC 1 Jan 1970. */ GPR_CLOCK_REALTIME, + /* CPU cycle time obtained by rdtsc instruction on x86 platforms. Epoch + undefined. Degrades to GPR_CLOCK_REALTIME on other platforms. */ + GPR_CLOCK_PRECISE, /* Unmeasurable clock type: no base, created by taking the difference between two times */ GPR_TIMESPAN diff --git a/src/compiler/csharp_generator.cc b/src/compiler/csharp_generator.cc index 9432bdda96b..51d8d982e2d 100644 --- a/src/compiler/csharp_generator.cc +++ b/src/compiler/csharp_generator.cc @@ -35,10 +35,16 @@ #include #include +#include "src/compiler/csharp_generator.h" #include "src/compiler/config.h" #include "src/compiler/csharp_generator_helpers.h" #include "src/compiler/csharp_generator.h" + +using google::protobuf::compiler::csharp::GetFileNamespace; +using google::protobuf::compiler::csharp::GetClassName; +using google::protobuf::compiler::csharp::GetUmbrellaClassName; +using google::protobuf::SimpleItoa; using grpc::protobuf::FileDescriptor; using grpc::protobuf::Descriptor; using grpc::protobuf::ServiceDescriptor; @@ -55,47 +61,10 @@ using grpc_generator::StringReplace; using std::map; using std::vector; + namespace grpc_csharp_generator { namespace { -// TODO(jtattermusch): make GetFileNamespace part of libprotoc public API. -// NOTE: Implementation needs to match exactly to GetFileNamespace -// defined in csharp_helpers.h in protoc csharp plugin. -// We cannot reference it directly because google3 protobufs -// don't have a csharp protoc plugin. -std::string GetFileNamespace(const FileDescriptor* file) { - if (file->options().has_csharp_namespace()) { - return file->options().csharp_namespace(); - } - return file->package(); -} - -std::string ToCSharpName(const std::string& name, const FileDescriptor* file) { - std::string result = GetFileNamespace(file); - if (result != "") { - result += '.'; - } - std::string classname; - if (file->package().empty()) { - classname = name; - } else { - // Strip the proto package from full_name since we've replaced it with - // the C# namespace. - classname = name.substr(file->package().size() + 1); - } - result += StringReplace(classname, ".", ".Types.", false); - return "global::" + result; -} - -// TODO(jtattermusch): make GetClassName part of libprotoc public API. -// NOTE: Implementation needs to match exactly to GetClassName -// defined in csharp_helpers.h in protoc csharp plugin. -// We cannot reference it directly because google3 protobufs -// don't have a csharp protoc plugin. -std::string GetClassName(const Descriptor* message) { - return ToCSharpName(message->full_name(), message->file()); -} - std::string GetServiceClassName(const ServiceDescriptor* service) { return service->name(); } @@ -229,7 +198,7 @@ void GenerateMarshallerFields(Printer* out, const ServiceDescriptor *service) { for (size_t i = 0; i < used_messages.size(); i++) { const Descriptor *message = used_messages[i]; out->Print( - "static readonly Marshaller<$type$> $fieldname$ = Marshallers.Create((arg) => arg.ToByteArray(), $type$.ParseFrom);\n", + "static readonly Marshaller<$type$> $fieldname$ = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), $type$.Parser.ParseFrom);\n", "fieldname", GetMarshallerFieldName(message), "type", GetClassName(message)); } @@ -258,6 +227,16 @@ void GenerateStaticMethodField(Printer* out, const MethodDescriptor *method) { out->Outdent(); } +void GenerateServiceDescriptorProperty(Printer* out, const ServiceDescriptor *service) { + out->Print("// service descriptor\n"); + out->Print("public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor\n"); + out->Print("{\n"); + out->Print(" get { return $umbrella$.Descriptor.Services[$index$]; }\n", + "umbrella", GetUmbrellaClassName(service->file()), "index", SimpleItoa(service->index())); + out->Print("}\n"); + out->Print("\n"); +} + void GenerateClientInterface(Printer* out, const ServiceDescriptor *service) { out->Print("// client interface\n"); out->Print("public interface $name$\n", "name", @@ -504,6 +483,7 @@ void GenerateService(Printer* out, const ServiceDescriptor *service) { for (int i = 0; i < service->method_count(); i++) { GenerateStaticMethodField(out, service->method(i)); } + GenerateServiceDescriptorProperty(out, service); GenerateClientInterface(out, service); GenerateServerInterface(out, service); GenerateClientStub(out, service); @@ -539,7 +519,6 @@ grpc::string GetServices(const FileDescriptor *file) { out.Print("using System.Threading;\n"); out.Print("using System.Threading.Tasks;\n"); out.Print("using Grpc.Core;\n"); - // TODO(jtattermusch): add using for protobuf message classes out.Print("\n"); out.Print("namespace $namespace$ {\n", "namespace", GetFileNamespace(file)); diff --git a/src/compiler/csharp_generator.h b/src/compiler/csharp_generator.h index ec537d3f1d2..67e3ee30b54 100644 --- a/src/compiler/csharp_generator.h +++ b/src/compiler/csharp_generator.h @@ -36,6 +36,11 @@ #include "src/compiler/config.h" +using namespace std; + +#include +#include + namespace grpc_csharp_generator { grpc::string GetServices(const grpc::protobuf::FileDescriptor *file); diff --git a/src/core/census/grpc_filter.c b/src/core/census/grpc_filter.c index 45b5656e3c2..e01c9a2ad4b 100644 --- a/src/core/census/grpc_filter.c +++ b/src/core/census/grpc_filter.c @@ -41,6 +41,7 @@ #include "src/core/channel/noop_filter.h" #include "src/core/statistics/census_interface.h" #include "src/core/statistics/census_rpc_stats.h" +#include #include #include #include diff --git a/src/core/census/grpc_filter.h b/src/core/census/grpc_filter.h index 1453c05d286..b3de3adc947 100644 --- a/src/core/census/grpc_filter.h +++ b/src/core/census/grpc_filter.h @@ -31,8 +31,8 @@ * */ -#ifndef GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H -#define GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H +#ifndef GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H +#define GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H #include "src/core/channel/channel_stack.h" @@ -41,4 +41,4 @@ extern const grpc_channel_filter grpc_client_census_filter; extern const grpc_channel_filter grpc_server_census_filter; -#endif /* GRPC_INTERNAL_CORE_CHANNEL_CENSUS_FILTER_H */ +#endif /* GRPC_INTERNAL_CORE_CENSUS_GRPC_FILTER_H */ diff --git a/src/core/channel/compress_filter.h b/src/core/channel/compress_filter.h index 0917e81ca43..415459bca60 100644 --- a/src/core/channel/compress_filter.h +++ b/src/core/channel/compress_filter.h @@ -36,7 +36,7 @@ #include "src/core/channel/channel_stack.h" -#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "internal:grpc-encoding-request" +#define GRPC_COMPRESS_REQUEST_ALGORITHM_KEY "grpc-internal-encoding-request" /** Compression filter for outgoing data. * diff --git a/src/core/channel/http_client_filter.c b/src/core/channel/http_client_filter.c index 48c623d3591..2b61d33c29d 100644 --- a/src/core/channel/http_client_filter.c +++ b/src/core/channel/http_client_filter.c @@ -45,7 +45,6 @@ typedef struct call_data { grpc_linked_mdelem content_type; grpc_linked_mdelem user_agent; int sent_initial_metadata; - int sent_authority; int got_initial_metadata; grpc_stream_op_buffer *recv_ops; @@ -64,7 +63,6 @@ typedef struct channel_data { grpc_mdelem *scheme; grpc_mdelem *content_type; grpc_mdelem *status; - grpc_mdelem *default_authority; /** complete user agent mdelem */ grpc_mdelem *user_agent; } channel_data; @@ -103,7 +101,6 @@ static void hc_on_recv(void *user_data, int success) { static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) { grpc_call_element *elem = user_data; - call_data *calld = elem->call_data; channel_data *channeld = elem->channel_data; /* eat the things we'd like to set ourselves */ if (md->key == channeld->method->key) return NULL; @@ -111,10 +108,6 @@ static grpc_mdelem *client_strip_filter(void *user_data, grpc_mdelem *md) { if (md->key == channeld->te_trailers->key) return NULL; if (md->key == channeld->content_type->key) return NULL; if (md->key == channeld->user_agent->key) return NULL; - if (channeld->default_authority && - channeld->default_authority->key == md->key) { - calld->sent_authority = 1; - } return md; } @@ -138,11 +131,6 @@ static void hc_mutate_op(grpc_call_element *elem, GRPC_MDELEM_REF(channeld->method)); grpc_metadata_batch_add_head(&op->data.metadata, &calld->scheme, GRPC_MDELEM_REF(channeld->scheme)); - if (channeld->default_authority && !calld->sent_authority) { - grpc_metadata_batch_add_head( - &op->data.metadata, &calld->authority, - GRPC_MDELEM_REF(channeld->default_authority)); - } grpc_metadata_batch_add_tail(&op->data.metadata, &calld->te_trailers, GRPC_MDELEM_REF(channeld->te_trailers)); grpc_metadata_batch_add_tail(&op->data.metadata, &calld->content_type, @@ -175,7 +163,6 @@ static void init_call_elem(grpc_call_element *elem, call_data *calld = elem->call_data; calld->sent_initial_metadata = 0; calld->got_initial_metadata = 0; - calld->sent_authority = 0; calld->on_done_recv = NULL; grpc_iomgr_closure_init(&calld->hc_on_recv, hc_on_recv, elem); if (initial_op) hc_mutate_op(elem, initial_op); @@ -257,8 +244,6 @@ static grpc_mdstr *user_agent_from_args(grpc_mdctx *mdctx, static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, const grpc_channel_args *channel_args, grpc_mdctx *mdctx, int is_first, int is_last) { - size_t i; - /* grab pointers to our data from the channel element */ channel_data *channeld = elem->channel_data; @@ -267,21 +252,6 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master, path */ GPR_ASSERT(!is_last); - channeld->default_authority = NULL; - if (channel_args) { - for (i = 0; i < channel_args->num_args; i++) { - if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) { - if (channel_args->args[i].type != GRPC_ARG_STRING) { - gpr_log(GPR_ERROR, "%s: must be an string", - GRPC_ARG_DEFAULT_AUTHORITY); - } else { - channeld->default_authority = grpc_mdelem_from_strings( - mdctx, ":authority", channel_args->args[i].value.string); - } - } - } - } - /* initialize members */ channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers"); channeld->method = grpc_mdelem_from_strings(mdctx, ":method", "POST"); @@ -306,9 +276,6 @@ static void destroy_channel_elem(grpc_channel_element *elem) { GRPC_MDELEM_UNREF(channeld->content_type); GRPC_MDELEM_UNREF(channeld->status); GRPC_MDELEM_UNREF(channeld->user_agent); - if (channeld->default_authority) { - GRPC_MDELEM_UNREF(channeld->default_authority); - } } const grpc_channel_filter grpc_http_client_filter = { diff --git a/src/core/client_config/resolver_factory.c b/src/core/client_config/resolver_factory.c index 6721977e21a..5b859a8d10b 100644 --- a/src/core/client_config/resolver_factory.c +++ b/src/core/client_config/resolver_factory.c @@ -45,6 +45,12 @@ void grpc_resolver_factory_unref(grpc_resolver_factory *factory) { grpc_resolver *grpc_resolver_factory_create_resolver( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory) { - if (!factory) return NULL; + if (factory == NULL) return NULL; return factory->vtable->create_resolver(factory, uri, subchannel_factory); } + +char *grpc_resolver_factory_get_default_authority( + grpc_resolver_factory *factory, grpc_uri *uri) { + if (factory == NULL) return NULL; + return factory->vtable->get_default_authority(factory, uri); +} diff --git a/src/core/client_config/resolver_factory.h b/src/core/client_config/resolver_factory.h index c5d85499c6e..e243b23988a 100644 --- a/src/core/client_config/resolver_factory.h +++ b/src/core/client_config/resolver_factory.h @@ -51,9 +51,16 @@ struct grpc_resolver_factory_vtable { void (*ref)(grpc_resolver_factory *factory); void (*unref)(grpc_resolver_factory *factory); + /** Implementation of grpc_resolver_factory_create_resolver */ grpc_resolver *(*create_resolver)( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory); + + /** Implementation of grpc_resolver_factory_get_default_authority */ + char *(*get_default_authority)(grpc_resolver_factory *factory, grpc_uri *uri); + + /** URI scheme that this factory implements */ + const char *scheme; }; void grpc_resolver_factory_ref(grpc_resolver_factory *resolver); @@ -64,4 +71,9 @@ grpc_resolver *grpc_resolver_factory_create_resolver( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory); +/** Return a (freshly allocated with gpr_malloc) string representing + the default authority to use for this scheme. */ +char *grpc_resolver_factory_get_default_authority( + grpc_resolver_factory *factory, grpc_uri *uri); + #endif /* GRPC_INTERNAL_CORE_CONFIG_RESOLVER_FACTORY_H */ diff --git a/src/core/client_config/resolver_registry.c b/src/core/client_config/resolver_registry.c index 16be2da9940..37979b3b86c 100644 --- a/src/core/client_config/resolver_registry.c +++ b/src/core/client_config/resolver_registry.c @@ -41,41 +41,33 @@ #define MAX_RESOLVERS 10 -typedef struct { - char *scheme; - grpc_resolver_factory *factory; -} registered_resolver; - -static registered_resolver g_all_of_the_resolvers[MAX_RESOLVERS]; +static grpc_resolver_factory *g_all_of_the_resolvers[MAX_RESOLVERS]; static int g_number_of_resolvers = 0; -static char *g_default_resolver_scheme; +static char *g_default_resolver_prefix; -void grpc_resolver_registry_init(const char *default_resolver_scheme) { +void grpc_resolver_registry_init(const char *default_resolver_prefix) { g_number_of_resolvers = 0; - g_default_resolver_scheme = gpr_strdup(default_resolver_scheme); + g_default_resolver_prefix = gpr_strdup(default_resolver_prefix); } void grpc_resolver_registry_shutdown(void) { int i; for (i = 0; i < g_number_of_resolvers; i++) { - gpr_free(g_all_of_the_resolvers[i].scheme); - grpc_resolver_factory_unref(g_all_of_the_resolvers[i].factory); + grpc_resolver_factory_unref(g_all_of_the_resolvers[i]); } - gpr_free(g_default_resolver_scheme); + gpr_free(g_default_resolver_prefix); } -void grpc_register_resolver_type(const char *scheme, - grpc_resolver_factory *factory) { +void grpc_register_resolver_type(grpc_resolver_factory *factory) { int i; for (i = 0; i < g_number_of_resolvers; i++) { - GPR_ASSERT(0 != strcmp(scheme, g_all_of_the_resolvers[i].scheme)); + GPR_ASSERT(0 != strcmp(factory->vtable->scheme, + g_all_of_the_resolvers[i]->vtable->scheme)); } GPR_ASSERT(g_number_of_resolvers != MAX_RESOLVERS); - g_all_of_the_resolvers[g_number_of_resolvers].scheme = gpr_strdup(scheme); grpc_resolver_factory_ref(factory); - g_all_of_the_resolvers[g_number_of_resolvers].factory = factory; - g_number_of_resolvers++; + g_all_of_the_resolvers[g_number_of_resolvers++] = factory; } static grpc_resolver_factory *lookup_factory(grpc_uri *uri) { @@ -85,40 +77,57 @@ static grpc_resolver_factory *lookup_factory(grpc_uri *uri) { if (!uri) return NULL; for (i = 0; i < g_number_of_resolvers; i++) { - if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i].scheme)) { - return g_all_of_the_resolvers[i].factory; + if (0 == strcmp(uri->scheme, g_all_of_the_resolvers[i]->vtable->scheme)) { + return g_all_of_the_resolvers[i]; } } return NULL; } -grpc_resolver *grpc_resolver_create( - const char *name, grpc_subchannel_factory *subchannel_factory) { - grpc_uri *uri; +static grpc_resolver_factory *resolve_factory(const char *target, + grpc_uri **uri) { char *tmp; grpc_resolver_factory *factory = NULL; - grpc_resolver *resolver; - - uri = grpc_uri_parse(name, 1); - factory = lookup_factory(uri); - if (factory == NULL && g_default_resolver_scheme != NULL) { - grpc_uri_destroy(uri); - gpr_asprintf(&tmp, "%s%s", g_default_resolver_scheme, name); - uri = grpc_uri_parse(tmp, 1); - factory = lookup_factory(uri); - if (factory == NULL) { - grpc_uri_destroy(grpc_uri_parse(name, 0)); - grpc_uri_destroy(grpc_uri_parse(tmp, 0)); - gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", name, tmp); + + GPR_ASSERT(uri != NULL); + *uri = grpc_uri_parse(target, 1); + factory = lookup_factory(*uri); + if (factory == NULL) { + if (g_default_resolver_prefix != NULL) { + grpc_uri_destroy(*uri); + gpr_asprintf(&tmp, "%s%s", g_default_resolver_prefix, target); + *uri = grpc_uri_parse(tmp, 1); + factory = lookup_factory(*uri); + if (factory == NULL) { + grpc_uri_destroy(grpc_uri_parse(target, 0)); + grpc_uri_destroy(grpc_uri_parse(tmp, 0)); + gpr_log(GPR_ERROR, "don't know how to resolve '%s' or '%s'", target, + tmp); + } + gpr_free(tmp); + } else { + grpc_uri_destroy(grpc_uri_parse(target, 0)); + gpr_log(GPR_ERROR, "don't know how to resolve '%s'", target); } - gpr_free(tmp); - } else if (factory == NULL) { - grpc_uri_destroy(grpc_uri_parse(name, 0)); - gpr_log(GPR_ERROR, "don't know how to resolve '%s'", name); } - resolver = + return factory; +} + +grpc_resolver *grpc_resolver_create( + const char *target, grpc_subchannel_factory *subchannel_factory) { + grpc_uri *uri = NULL; + grpc_resolver_factory *factory = resolve_factory(target, &uri); + grpc_resolver *resolver = grpc_resolver_factory_create_resolver(factory, uri, subchannel_factory); grpc_uri_destroy(uri); return resolver; } + +char *grpc_get_default_authority(const char *target) { + grpc_uri *uri = NULL; + grpc_resolver_factory *factory = resolve_factory(target, &uri); + char *authority = grpc_resolver_factory_get_default_authority(factory, uri); + grpc_uri_destroy(uri); + return authority; +} diff --git a/src/core/client_config/resolver_registry.h b/src/core/client_config/resolver_registry.h index 31aa47620ab..5a7193b7ae2 100644 --- a/src/core/client_config/resolver_registry.h +++ b/src/core/client_config/resolver_registry.h @@ -44,19 +44,22 @@ void grpc_resolver_registry_shutdown(void); If \a priority is greater than zero, then the resolver will be eligible to resolve names that are passed in with no scheme. Higher priority resolvers will be tried before lower priority schemes. */ -void grpc_register_resolver_type(const char *scheme, - grpc_resolver_factory *factory); +void grpc_register_resolver_type(grpc_resolver_factory *factory); -/** Create a resolver given \a name. - First tries to parse \a name as a URI. If this succeeds, tries +/** Create a resolver given \a target. + First tries to parse \a target as a URI. If this succeeds, tries to locate a registered resolver factory based on the URI scheme. If parsing or location fails, prefixes default_prefix from - grpc_resolver_registry_init to name, and tries again (if default_prefix + grpc_resolver_registry_init to target, and tries again (if default_prefix was not NULL). If a resolver factory was found, use it to instantiate a resolver and return it. If a resolver factory was not found, return NULL. */ grpc_resolver *grpc_resolver_create( - const char *name, grpc_subchannel_factory *subchannel_factory); + const char *target, grpc_subchannel_factory *subchannel_factory); + +/** Given a target, return a (freshly allocated with gpr_malloc) string + representing the default authority to pass from a client. */ +char *grpc_get_default_authority(const char *target); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_RESOLVER_REGISTRY_H */ diff --git a/src/core/client_config/resolvers/dns_resolver.c b/src/core/client_config/resolvers/dns_resolver.c index 7b35b7902f7..84643c464a9 100644 --- a/src/core/client_config/resolvers/dns_resolver.c +++ b/src/core/client_config/resolvers/dns_resolver.c @@ -203,9 +203,6 @@ static grpc_resolver *dns_create( grpc_subchannel_factory *subchannel_factory) { dns_resolver *r; const char *path = uri->path; - grpc_arg default_host_arg; - char *host; - char *port; if (0 != strcmp(uri->authority, "")) { gpr_log(GPR_ERROR, "authority based uri's not supported"); @@ -214,17 +211,6 @@ static grpc_resolver *dns_create( if (path[0] == '/') ++path; - gpr_split_host_port(path, &host, &port); - - default_host_arg.type = GRPC_ARG_STRING; - default_host_arg.key = GRPC_ARG_DEFAULT_AUTHORITY; - default_host_arg.value.string = host; - subchannel_factory = grpc_subchannel_factory_add_channel_arg( - subchannel_factory, &default_host_arg); - - gpr_free(host); - gpr_free(port); - r = gpr_malloc(sizeof(dns_resolver)); memset(r, 0, sizeof(*r)); gpr_ref_init(&r->refs, 1); @@ -233,6 +219,7 @@ static grpc_resolver *dns_create( r->name = gpr_strdup(path); r->default_port = gpr_strdup(default_port); r->subchannel_factory = subchannel_factory; + grpc_subchannel_factory_ref(subchannel_factory); r->lb_policy_factory = lb_policy_factory; return &r->base; } @@ -252,8 +239,16 @@ static grpc_resolver *dns_factory_create_resolver( subchannel_factory); } +char *dns_factory_get_default_host_name(grpc_resolver_factory *factory, + grpc_uri *uri) { + const char *path = uri->path; + if (path[0] == '/') ++path; + return gpr_strdup(path); +} + static const grpc_resolver_factory_vtable dns_factory_vtable = { - dns_factory_ref, dns_factory_unref, dns_factory_create_resolver}; + dns_factory_ref, dns_factory_unref, dns_factory_create_resolver, + dns_factory_get_default_host_name, "dns"}; static grpc_resolver_factory dns_resolver_factory = {&dns_factory_vtable}; grpc_resolver_factory *grpc_dns_resolver_factory_create() { diff --git a/src/core/client_config/resolvers/sockaddr_resolver.c b/src/core/client_config/resolvers/sockaddr_resolver.c index 84198739081..0d8540a5665 100644 --- a/src/core/client_config/resolvers/sockaddr_resolver.c +++ b/src/core/client_config/resolvers/sockaddr_resolver.c @@ -166,8 +166,29 @@ static int parse_unix(grpc_uri *uri, struct sockaddr_storage *addr, int *len) { return 1; } + +static char *unix_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return gpr_strdup("localhost"); +} #endif +static char *ip_get_default_authority(grpc_uri *uri) { + const char *path = uri->path; + if (path[0] == '/') ++path; + return gpr_strdup(path); +} + +static char *ipv4_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return ip_get_default_authority(uri); +} + +static char *ipv6_get_default_authority(grpc_resolver_factory *factory, + grpc_uri *uri) { + return ip_get_default_authority(uri); +} + static int parse_ipv4(grpc_uri *uri, struct sockaddr_storage *addr, int *len) { const char *host_port = uri->path; char *host; @@ -313,20 +334,20 @@ static void sockaddr_factory_ref(grpc_resolver_factory *factory) {} static void sockaddr_factory_unref(grpc_resolver_factory *factory) {} -#define DECL_FACTORY(name) \ - static grpc_resolver *name##_factory_create_resolver( \ - grpc_resolver_factory *factory, grpc_uri *uri, \ - grpc_subchannel_factory *subchannel_factory) { \ - return sockaddr_create(uri, grpc_create_pick_first_lb_policy, \ - subchannel_factory, parse_##name); \ - } \ - static const grpc_resolver_factory_vtable name##_factory_vtable = { \ - sockaddr_factory_ref, sockaddr_factory_unref, \ - name##_factory_create_resolver}; \ - static grpc_resolver_factory name##_resolver_factory = { \ - &name##_factory_vtable}; \ - grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \ - return &name##_resolver_factory; \ +#define DECL_FACTORY(name) \ + static grpc_resolver *name##_factory_create_resolver( \ + grpc_resolver_factory *factory, grpc_uri *uri, \ + grpc_subchannel_factory *subchannel_factory) { \ + return sockaddr_create(uri, grpc_create_pick_first_lb_policy, \ + subchannel_factory, parse_##name); \ + } \ + static const grpc_resolver_factory_vtable name##_factory_vtable = { \ + sockaddr_factory_ref, sockaddr_factory_unref, \ + name##_factory_create_resolver, name##_get_default_authority, #name}; \ + static grpc_resolver_factory name##_resolver_factory = { \ + &name##_factory_vtable}; \ + grpc_resolver_factory *grpc_##name##_resolver_factory_create() { \ + return &name##_resolver_factory; \ } #ifdef GPR_POSIX_SOCKET diff --git a/src/core/client_config/resolvers/zookeeper_resolver.c b/src/core/client_config/resolvers/zookeeper_resolver.c index acb2ba136e9..da399f99548 100644 --- a/src/core/client_config/resolvers/zookeeper_resolver.c +++ b/src/core/client_config/resolvers/zookeeper_resolver.c @@ -467,8 +467,7 @@ static grpc_resolver *zookeeper_create( } static void zookeeper_plugin_init() { - grpc_register_resolver_type("zookeeper", - grpc_zookeeper_resolver_factory_create()); + grpc_register_resolver_type(grpc_zookeeper_resolver_factory_create()); } void grpc_zookeeper_register() { @@ -483,6 +482,11 @@ static void zookeeper_factory_ref(grpc_resolver_factory *factory) {} static void zookeeper_factory_unref(grpc_resolver_factory *factory) {} +static char *zookeeper_factory_get_default_hostname( + grpc_resolver_factory *factory, grpc_uri *uri) { + return NULL; +} + static grpc_resolver *zookeeper_factory_create_resolver( grpc_resolver_factory *factory, grpc_uri *uri, grpc_subchannel_factory *subchannel_factory) { @@ -492,7 +496,8 @@ static grpc_resolver *zookeeper_factory_create_resolver( static const grpc_resolver_factory_vtable zookeeper_factory_vtable = { zookeeper_factory_ref, zookeeper_factory_unref, - zookeeper_factory_create_resolver}; + zookeeper_factory_create_resolver, zookeeper_factory_get_default_hostname, + "zookeeper"}; static grpc_resolver_factory zookeeper_resolver_factory = { &zookeeper_factory_vtable}; diff --git a/src/core/profiling/basic_timers.c b/src/core/profiling/basic_timers.c index ae37f584ebb..4b6a0d2f56b 100644 --- a/src/core/profiling/basic_timers.c +++ b/src/core/profiling/basic_timers.c @@ -36,7 +36,6 @@ #ifdef GRPC_BASIC_PROFILER #include "src/core/profiling/timers.h" -#include "src/core/profiling/timers_preciseclock.h" #include #include @@ -53,7 +52,7 @@ typedef enum { } marker_type; typedef struct grpc_timer_entry { - grpc_precise_clock tm; + gpr_timespec tm; int tag; const char* tagstr; marker_type type; @@ -71,9 +70,8 @@ static void log_report() { int i; for (i = 0; i < count; i++) { grpc_timer_entry* entry = &(log[i]); - printf("GRPC_LAT_PROF " GRPC_PRECISE_CLOCK_FORMAT - " %p %c %d(%s) %p %s %d\n", - GRPC_PRECISE_CLOCK_PRINTF_ARGS(&entry->tm), + printf("GRPC_LAT_PROF %ld.%09d %p %c %d(%s) %p %s %d\n", + entry->tm.tv_sec, entry->tm.tv_nsec, (void*)(gpr_intptr)gpr_thd_currentid(), entry->type, entry->tag, entry->tagstr, entry->id, entry->file, entry->line); } @@ -93,7 +91,7 @@ static void grpc_timers_log_add(int tag, const char* tagstr, marker_type type, entry = &log[count++]; - grpc_precise_clock_now(&entry->tm); + entry->tm = gpr_now(GPR_CLOCK_PRECISE); entry->tag = tag; entry->tagstr = tagstr; entry->type = type; diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c index 8e63978b82f..f3ecfd0e60e 100644 --- a/src/core/security/client_auth_filter.c +++ b/src/core/security/client_auth_filter.c @@ -153,7 +153,8 @@ static void send_security_metadata(grpc_call_element *elem, } if (channel_creds_has_md && call_creds_has_md) { - calld->creds = grpc_composite_credentials_create(channel_creds, ctx->creds); + calld->creds = + grpc_composite_credentials_create(channel_creds, ctx->creds, NULL); if (calld->creds == NULL) { bubble_up_error(elem, GRPC_STATUS_INVALID_ARGUMENT, "Incompatible credentials set on channel and call."); diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index 8852cab3e78..362d5f4b6ff 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -298,8 +298,10 @@ static void ssl_build_server_config( } grpc_credentials *grpc_ssl_credentials_create( - const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair) { + const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, + void *reserved) { grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials)); + GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_ssl_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_SSL; c->base.vtable = &ssl_vtable; @@ -310,9 +312,11 @@ grpc_credentials *grpc_ssl_credentials_create( grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, - size_t num_key_cert_pairs, int force_client_auth) { + size_t num_key_cert_pairs, int force_client_auth, void *reserved) { grpc_ssl_server_credentials *c = gpr_malloc(sizeof(grpc_ssl_server_credentials)); + GPR_ASSERT(reserved == NULL); + memset(c, 0, sizeof(grpc_ssl_credentials)); memset(c, 0, sizeof(grpc_ssl_server_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_SSL; c->base.vtable = &ssl_server_vtable; @@ -430,7 +434,8 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key( } grpc_credentials *grpc_service_account_jwt_access_credentials_create( - const char *json_key, gpr_timespec token_lifetime) { + const char *json_key, gpr_timespec token_lifetime, void *reserved) { + GPR_ASSERT(reserved == NULL); return grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key_create_from_string(json_key), token_lifetime); } @@ -635,9 +640,10 @@ static void compute_engine_fetch_oauth2( metadata_req); } -grpc_credentials *grpc_compute_engine_credentials_create(void) { +grpc_credentials *grpc_compute_engine_credentials_create(void *reserved) { grpc_oauth2_token_fetcher_credentials *c = gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials)); + GPR_ASSERT(reserved == NULL); init_oauth2_token_fetcher(c, compute_engine_fetch_oauth2); c->base.vtable = &compute_engine_vtable; return &c->base; @@ -693,10 +699,11 @@ static void service_account_fetch_oauth2( } grpc_credentials *grpc_service_account_credentials_create( - const char *json_key, const char *scope, gpr_timespec token_lifetime) { + const char *json_key, const char *scope, gpr_timespec token_lifetime, + void *reserved) { grpc_service_account_credentials *c; grpc_auth_json_key key = grpc_auth_json_key_create_from_string(json_key); - + GPR_ASSERT(reserved == NULL); if (scope == NULL || (strlen(scope) == 0) || !grpc_auth_json_key_is_valid(&key)) { gpr_log(GPR_ERROR, @@ -766,7 +773,8 @@ grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token( } grpc_credentials *grpc_refresh_token_credentials_create( - const char *json_refresh_token) { + const char *json_refresh_token, void *reserved) { + GPR_ASSERT(reserved == NULL); return grpc_refresh_token_credentials_create_from_auth_refresh_token( grpc_auth_refresh_token_create_from_string(json_refresh_token)); } @@ -867,11 +875,12 @@ static grpc_credentials_vtable access_token_vtable = { access_token_has_request_metadata_only, access_token_get_request_metadata, NULL}; -grpc_credentials *grpc_access_token_credentials_create( - const char *access_token) { +grpc_credentials *grpc_access_token_credentials_create(const char *access_token, + void *reserved) { grpc_access_token_credentials *c = gpr_malloc(sizeof(grpc_access_token_credentials)); char *token_md_value; + GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_access_token_credentials)); c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2; c->base.vtable = &access_token_vtable; @@ -1101,12 +1110,14 @@ static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) { } grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1, - grpc_credentials *creds2) { + grpc_credentials *creds2, + void *reserved) { size_t i; size_t creds_array_byte_size; grpc_credentials_array creds1_array; grpc_credentials_array creds2_array; grpc_composite_credentials *c; + GPR_ASSERT(reserved == NULL); GPR_ASSERT(creds1 != NULL); GPR_ASSERT(creds2 != NULL); c = gpr_malloc(sizeof(grpc_composite_credentials)); @@ -1209,8 +1220,10 @@ static grpc_credentials_vtable iam_vtable = { iam_get_request_metadata, NULL}; grpc_credentials *grpc_iam_credentials_create(const char *token, - const char *authority_selector) { + const char *authority_selector, + void *reserved) { grpc_iam_credentials *c; + GPR_ASSERT(reserved == NULL); GPR_ASSERT(token != NULL); GPR_ASSERT(authority_selector != NULL); c = gpr_malloc(sizeof(grpc_iam_credentials)); diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c index 3631de867af..f9aa5187ce6 100644 --- a/src/core/security/google_default_credentials.c +++ b/src/core/security/google_default_credentials.c @@ -194,7 +194,7 @@ grpc_credentials *grpc_google_default_credentials_create(void) { int need_compute_engine_creds = is_stack_running_on_compute_engine(); compute_engine_detection_done = 1; if (need_compute_engine_creds) { - result = grpc_compute_engine_credentials_create(); + result = grpc_compute_engine_credentials_create(NULL); } } @@ -202,9 +202,9 @@ end: if (!serving_cached_credentials && result != NULL) { /* Blend with default ssl credentials and add a global reference so that it can be cached and re-served. */ - grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL); + grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); default_credentials = grpc_credentials_ref( - grpc_composite_credentials_create(ssl_creds, result)); + grpc_composite_credentials_create(ssl_creds, result, NULL)); GPR_ASSERT(default_credentials != NULL); grpc_credentials_unref(ssl_creds); grpc_credentials_unref(result); diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c index 629781da8a2..b68239f8f58 100644 --- a/src/core/support/log_win32.c +++ b/src/core/support/log_win32.c @@ -81,10 +81,18 @@ void gpr_log(const char *file, int line, gpr_log_severity severity, /* Simple starter implementation */ void gpr_default_log(gpr_log_func_args *args) { + char *final_slash; + const char *display_file; char time_buffer[64]; gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME); struct tm tm; + final_slash = strrchr(args->file, '\\'); + if (final_slash == NULL) + display_file = args->file; + else + display_file = final_slash + 1; + if (localtime_s(&tm, &now.tv_sec)) { strcpy(time_buffer, "error:localtime"); } else if (0 == @@ -94,7 +102,7 @@ void gpr_default_log(gpr_log_func_args *args) { fprintf(stderr, "%s%s.%09u %5lu %s:%d] %s\n", gpr_log_severity_string(args->severity), time_buffer, - (int)(now.tv_nsec), GetCurrentThreadId(), args->file, args->line, + (int)(now.tv_nsec), GetCurrentThreadId(), display_file, args->line, args->message); } diff --git a/src/core/support/time_posix.c b/src/core/support/time_posix.c index 841485c4b4a..a2744002437 100644 --- a/src/core/support/time_posix.c +++ b/src/core/support/time_posix.c @@ -32,6 +32,7 @@ */ #include +#include #ifdef GPR_POSIX_TIME @@ -66,8 +67,14 @@ void gpr_time_init(void) {} gpr_timespec gpr_now(gpr_clock_type clock) { struct timespec now; GPR_ASSERT(clock != GPR_TIMESPAN); - clock_gettime(clockid_for_gpr_clock[clock], &now); - return gpr_from_timespec(now, clock); + if (clock == GPR_CLOCK_PRECISE) { + gpr_timespec ret; + gpr_precise_clock_now(&ret); + return ret; + } else { + clock_gettime(clockid_for_gpr_clock[clock], &now); + return gpr_from_timespec(now, clock); + } } #else /* For some reason Apple's OSes haven't implemented clock_gettime. */ @@ -104,6 +111,9 @@ gpr_timespec gpr_now(gpr_clock_type clock) { now.tv_sec = now_dbl * 1e-9; now.tv_nsec = now_dbl - now.tv_sec * 1e9; break; + case GPR_CLOCK_PRECISE: + gpr_precise_clock_now(&now); + break; case GPR_TIMESPAN: abort(); } diff --git a/src/core/profiling/timers_preciseclock.h b/src/core/support/time_precise.h similarity index 65% rename from src/core/profiling/timers_preciseclock.h rename to src/core/support/time_precise.h index 5c251b47e6f..574ebb84489 100644 --- a/src/core/profiling/timers_preciseclock.h +++ b/src/core/support/time_precise.h @@ -31,65 +31,63 @@ * */ -#ifndef GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H -#define GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H +#ifndef GRPC_CORE_SUPPORT_TIME_PRECISE_H_ +#define GRPC_CORE_SUPPORT_TIME_PRECISE_H_ #include #include #include #ifdef GRPC_TIMERS_RDTSC -typedef long long int grpc_precise_clock; #if defined(__i386__) -static void grpc_precise_clock_now(grpc_precise_clock *clk) { - grpc_precise_clock ret; +static void gpr_get_cycle_counter(long long int *clk) { + long long int ret; __asm__ volatile("rdtsc" : "=A"(ret)); *clk = ret; } // ---------------------------------------------------------------- #elif defined(__x86_64__) || defined(__amd64__) -static void grpc_precise_clock_now(grpc_precise_clock *clk) { +static void gpr_get_cycle_counter(long long int *clk) { unsigned long long low, high; __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); *clk = (high << 32) | low; } #endif + static gpr_once precise_clock_init = GPR_ONCE_INIT; -static double cycles_per_second = 0.0; -static void grpc_precise_clock_init() { +static long long cycles_per_second = 0; +static void gpr_precise_clock_init() { time_t start = time(NULL); - grpc_precise_clock start_time; - grpc_precise_clock end_time; + gpr_precise_clock start_cycle; + gpr_precise_clock end_cycle; while (time(NULL) == start) ; - grpc_precise_clock_now(&start_time); + gpr_get_cycle_counter(&start_cycle); while (time(NULL) == start + 1) ; - grpc_precise_clock_now(&end_time); - cycles_per_second = end_time - start_time; + gpr_get_cycle_counter(&end_cycle); + cycles_per_second = end_cycle - start_cycle; } + static double grpc_precise_clock_scaling_factor() { gpr_once_init(&precise_clock_init, grpc_precise_clock_init); return 1e6 / cycles_per_second; } -#define GRPC_PRECISE_CLOCK_FORMAT "%f" -#define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \ - (*(clk)*grpc_precise_clock_scaling_factor()) -#else -typedef struct grpc_precise_clock grpc_precise_clock; -struct grpc_precise_clock { - gpr_timespec clock; -}; -static void grpc_precise_clock_now(grpc_precise_clock* clk) { - clk->clock = gpr_now(GPR_CLOCK_REALTIME); + +static void gpr_precise_clock_now(gpr_timespec *clk) { + long long int counter; + gpr_get_cycle_counter(&counter); + clk->clock = GPR_CLOCK_REALTIME; + clk->tv_sec = counter / cycles_per_second; + clk->tv_nsec = counter % cycles_per_second; } -#define GRPC_PRECISE_CLOCK_FORMAT "%ld.%09d" -#define GRPC_PRECISE_CLOCK_PRINTF_ARGS(clk) \ - (clk)->clock.tv_sec, (clk)->clock.tv_nsec -static void grpc_precise_clock_print(const grpc_precise_clock* clk, FILE* fp) { - fprintf(fp, "%ld.%09d", clk->clock.tv_sec, clk->clock.tv_nsec); + +#else /* GRPC_TIMERS_RDTSC */ +static void gpr_precise_clock_now(gpr_timespec *clk) { + *clk = gpr_now(GPR_CLOCK_REALTIME); + clk->clock_type = GPR_CLOCK_PRECISE; } #endif /* GRPC_TIMERS_RDTSC */ -#endif /* GRPC_CORE_PROFILING_TIMERS_PRECISECLOCK_H */ +#endif /* GRPC_CORE_SUPPORT_TIME_PRECISE_ */ diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c index 7f64c80e276..f794855429b 100644 --- a/src/core/support/time_win32.c +++ b/src/core/support/time_win32.c @@ -38,6 +38,7 @@ #ifdef GPR_WIN32 #include +#include #include static LARGE_INTEGER g_start_time; @@ -68,6 +69,9 @@ gpr_timespec gpr_now(gpr_clock_type clock) { now_tv.tv_sec = (time_t)now_dbl; now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9); break; + case GPR_CLOCK_PRECISE: + gpr_precise_clock_now(&now_tv); + break; } return now_tv; } diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 33f277da46d..4426bbbce9f 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -1046,10 +1046,11 @@ static int prepare_application_metadata(grpc_call *call, size_t count, (const gpr_uint8 *)md->value, md->value_length, 1); if (!grpc_mdstr_is_legal_header(l->md->key)) { - gpr_log(GPR_ERROR, "attempt to send invalid metadata key"); + gpr_log(GPR_ERROR, "attempt to send invalid metadata key: %s", + grpc_mdstr_as_c_string(l->md->key)); return 0; } else if (!grpc_mdstr_is_bin_suffixed(l->md->key) && - !grpc_mdstr_is_legal_header(l->md->value)) { + !grpc_mdstr_is_legal_nonbin_header(l->md->value)) { gpr_log(GPR_ERROR, "attempt to send invalid metadata value"); return 0; } diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c index e50251566d5..586402e21c3 100644 --- a/src/core/surface/channel.c +++ b/src/core/surface/channel.c @@ -40,6 +40,7 @@ #include #include +#include "src/core/client_config/resolver_registry.h" #include "src/core/iomgr/iomgr.h" #include "src/core/support/string.h" #include "src/core/surface/call.h" @@ -70,6 +71,7 @@ struct grpc_channel { grpc_mdstr *grpc_message_string; grpc_mdstr *path_string; grpc_mdstr *authority_string; + grpc_mdelem *default_authority; /** mdelem for grpc-status: 0 thru grpc-status: 2 */ grpc_mdelem *grpc_status_elem[NUM_CACHED_STATUS_ELEMS]; @@ -134,10 +136,47 @@ grpc_channel *grpc_channel_create_from_filters( } else { channel->max_message_length = args->args[i].value.integer; } + } else if (0 == strcmp(args->args[i].key, GRPC_ARG_DEFAULT_AUTHORITY)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "%s: must be an string", + GRPC_ARG_DEFAULT_AUTHORITY); + } else { + if (channel->default_authority) { + /* setting this takes precedence over anything else */ + GRPC_MDELEM_UNREF(channel->default_authority); + } + channel->default_authority = grpc_mdelem_from_strings( + mdctx, ":authority", args->args[i].value.string); + } + } else if (0 == + strcmp(args->args[i].key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG)) { + if (args->args[i].type != GRPC_ARG_STRING) { + gpr_log(GPR_ERROR, "%s: must be an string", + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); + } else { + if (channel->default_authority) { + /* other ways of setting this (notably ssl) take precedence */ + gpr_log(GPR_ERROR, "%s: default host already set some other way", + GRPC_ARG_DEFAULT_AUTHORITY); + } else { + channel->default_authority = grpc_mdelem_from_strings( + mdctx, ":authority", args->args[i].value.string); + } + } } } } + if (channel->is_client && channel->default_authority == NULL && + target != NULL) { + char *default_authority = grpc_get_default_authority(target); + if (default_authority) { + channel->default_authority = grpc_mdelem_from_strings( + channel->metadata_context, ":authority", default_authority); + } + gpr_free(default_authority); + } + grpc_channel_stack_init(filters, num_filters, channel, args, channel->metadata_context, CHANNEL_STACK_FROM_CHANNEL(channel)); @@ -161,6 +200,8 @@ static grpc_call *grpc_channel_create_call_internal( send_metadata[num_metadata++] = path_mdelem; if (authority_mdelem != NULL) { send_metadata[num_metadata++] = authority_mdelem; + } else if (channel->default_authority != NULL) { + send_metadata[num_metadata++] = GRPC_MDELEM_REF(channel->default_authority); } return grpc_call_create(channel, parent_call, propagation_mask, cq, NULL, @@ -251,6 +292,9 @@ static void destroy_channel(void *p, int ok) { } gpr_free(rc); } + if (channel->default_authority != NULL) { + GRPC_MDELEM_UNREF(channel->default_authority); + } grpc_mdctx_unref(channel->metadata_context); gpr_mu_destroy(&channel->registered_call_mu); gpr_free(channel->target); diff --git a/src/core/surface/init.c b/src/core/surface/init.c index d9044549f21..0d48cd42d72 100644 --- a/src/core/surface/init.c +++ b/src/core/surface/init.c @@ -86,11 +86,11 @@ void grpc_init(void) { if (++g_initializations == 1) { gpr_time_init(); grpc_resolver_registry_init("dns:///"); - grpc_register_resolver_type("dns", grpc_dns_resolver_factory_create()); - grpc_register_resolver_type("ipv4", grpc_ipv4_resolver_factory_create()); - grpc_register_resolver_type("ipv6", grpc_ipv6_resolver_factory_create()); + grpc_register_resolver_type(grpc_dns_resolver_factory_create()); + grpc_register_resolver_type(grpc_ipv4_resolver_factory_create()); + grpc_register_resolver_type(grpc_ipv6_resolver_factory_create()); #ifdef GPR_POSIX_SOCKET - grpc_register_resolver_type("unix", grpc_unix_resolver_factory_create()); + grpc_register_resolver_type(grpc_unix_resolver_factory_create()); #endif grpc_register_tracer("channel", &grpc_trace_channel); grpc_register_tracer("surface", &grpc_surface_trace); diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index eccee246980..35b60bdbefc 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -185,7 +185,8 @@ static const grpc_subchannel_factory_vtable subchannel_factory_vtable = { - perform handshakes */ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, const char *target, - const grpc_channel_args *args) { + const grpc_channel_args *args, + void *reserved) { grpc_channel *channel; grpc_arg connector_arg; grpc_channel_args *args_copy; @@ -198,6 +199,7 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds, const grpc_channel_filter *filters[MAX_FILTERS]; int n = 0; + GPR_ASSERT(reserved == NULL); if (grpc_find_security_connector_in_args(args) != NULL) { gpr_log(GPR_ERROR, "Cannot set security context in channel args."); return grpc_lame_client_channel_create( diff --git a/src/core/transport/chttp2/stream_lists.c b/src/core/transport/chttp2/stream_lists.c index 38c6052f9c4..781db7b0d69 100644 --- a/src/core/transport/chttp2/stream_lists.c +++ b/src/core/transport/chttp2/stream_lists.c @@ -177,8 +177,10 @@ int grpc_chttp2_list_pop_writable_stream( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_WRITABLE); - *stream_global = &stream->global; - *stream_writing = &stream->writing; + if (r != 0) { + *stream_global = &stream->global; + *stream_writing = &stream->writing; + } return r; } @@ -210,7 +212,9 @@ int grpc_chttp2_list_pop_writing_stream( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, GRPC_CHTTP2_LIST_WRITING); - *stream_writing = &stream->writing; + if (r != 0) { + *stream_writing = &stream->writing; + } return r; } @@ -230,8 +234,10 @@ int grpc_chttp2_list_pop_written_stream( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_WRITING(transport_writing), &stream, GRPC_CHTTP2_LIST_WRITTEN); - *stream_global = &stream->global; - *stream_writing = &stream->writing; + if (r != 0) { + *stream_global = &stream->global; + *stream_writing = &stream->writing; + } return r; } @@ -251,8 +257,10 @@ int grpc_chttp2_list_pop_parsing_seen_stream( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_PARSING(transport_parsing), &stream, GRPC_CHTTP2_LIST_PARSING_SEEN); - *stream_global = &stream->global; - *stream_parsing = &stream->parsing; + if (r != 0) { + *stream_global = &stream->global; + *stream_parsing = &stream->parsing; + } return r; } @@ -270,7 +278,9 @@ int grpc_chttp2_list_pop_waiting_for_concurrency( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_WAITING_FOR_CONCURRENCY); - *stream_global = &stream->global; + if (r != 0) { + *stream_global = &stream->global; + } return r; } @@ -288,7 +298,9 @@ int grpc_chttp2_list_pop_closed_waiting_for_parsing( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_CLOSED_WAITING_FOR_PARSING); - *stream_global = &stream->global; + if (r != 0) { + *stream_global = &stream->global; + } return r; } @@ -306,7 +318,9 @@ int grpc_chttp2_list_pop_cancelled_waiting_for_writing( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_CANCELLED_WAITING_FOR_WRITING); - *stream_global = &stream->global; + if (r != 0) { + *stream_global = &stream->global; + } return r; } @@ -326,8 +340,10 @@ int grpc_chttp2_list_pop_incoming_window_updated( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_INCOMING_WINDOW_UPDATED); - *stream_global = &stream->global; - *stream_parsing = &stream->parsing; + if (r != 0) { + *stream_global = &stream->global; + *stream_parsing = &stream->parsing; + } return r; } @@ -353,7 +369,9 @@ int grpc_chttp2_list_pop_read_write_state_changed( grpc_chttp2_stream *stream; int r = stream_list_pop(TRANSPORT_FROM_GLOBAL(transport_global), &stream, GRPC_CHTTP2_LIST_READ_WRITE_STATE_CHANGED); - *stream_global = &stream->global; + if (r != 0) { + *stream_global = &stream->global; + } return r; } diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c index f92e87e9ddd..61638764a61 100644 --- a/src/core/transport/metadata.c +++ b/src/core/transport/metadata.c @@ -681,16 +681,34 @@ void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, void grpc_mdctx_unlock(grpc_mdctx *ctx) { unlock(ctx); } -int grpc_mdstr_is_legal_header(grpc_mdstr *s) { - /* TODO(ctiller): consider caching this, or computing it on construction */ +static int conforms_to(grpc_mdstr *s, const gpr_uint8 *legal_bits) { const gpr_uint8 *p = GPR_SLICE_START_PTR(s->slice); const gpr_uint8 *e = GPR_SLICE_END_PTR(s->slice); for (; p != e; p++) { - if (*p < 32 || *p > 126) return 0; + int idx = *p; + int byte = idx / 8; + int bit = idx % 8; + if ((legal_bits[byte] & (1 << bit)) == 0) return 0; } return 1; } +int grpc_mdstr_is_legal_header(grpc_mdstr *s) { + static const gpr_uint8 legal_header_bits[256 / 8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0x03, 0x00, 0x00, 0x00, + 0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return conforms_to(s, legal_header_bits); +} + +int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s) { + static const gpr_uint8 legal_header_bits[256 / 8] = { + 0x00, 0x00, 0x00, 0x00, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return conforms_to(s, legal_header_bits); +} + int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s) { /* TODO(ctiller): consider caching this */ return grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(s->slice), diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h index a7af49ba555..eb17747be74 100644 --- a/src/core/transport/metadata.h +++ b/src/core/transport/metadata.h @@ -154,6 +154,7 @@ void grpc_mdelem_unref(grpc_mdelem *md); const char *grpc_mdstr_as_c_string(grpc_mdstr *s); int grpc_mdstr_is_legal_header(grpc_mdstr *s); +int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s); int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s); /* Batch mode metadata functions. diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index 8c571cbbaad..1dac9600170 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -44,6 +44,11 @@ namespace grpc { class ChannelArguments; std::shared_ptr CreateChannel( + const grpc::string& target, const std::shared_ptr& creds) { + return CreateCustomChannel(target, creds, ChannelArguments()); +} + +std::shared_ptr CreateCustomChannel( const grpc::string& target, const std::shared_ptr& creds, const ChannelArguments& args) { ChannelArguments cp_args = args; @@ -57,4 +62,5 @@ std::shared_ptr CreateChannel( NULL, GRPC_STATUS_INVALID_ARGUMENT, "Invalid credentials.")); } + } // namespace grpc diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc index f368f2590a4..e0642469b49 100644 --- a/src/cpp/client/secure_credentials.cc +++ b/src/cpp/client/secure_credentials.cc @@ -46,7 +46,8 @@ std::shared_ptr SecureCredentials::CreateChannel( args.SetChannelArgs(&channel_args); return CreateChannelInternal( args.GetSslTargetNameOverride(), - grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args)); + grpc_secure_channel_create(c_creds_, target.c_str(), &channel_args, + nullptr)); } bool SecureCredentials::ApplyToCall(grpc_call* call) { @@ -75,14 +76,14 @@ std::shared_ptr SslCredentials( grpc_credentials* c_creds = grpc_ssl_credentials_create( options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(), - options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair); + options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr); return WrapCredentials(c_creds); } // Builds credentials for use when running in GCE std::shared_ptr ComputeEngineCredentials() { GrpcLibrary init; // To call grpc_init(). - return WrapCredentials(grpc_compute_engine_credentials_create()); + return WrapCredentials(grpc_compute_engine_credentials_create(nullptr)); } // Builds service account credentials. @@ -99,7 +100,7 @@ std::shared_ptr ServiceAccountCredentials( gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN); return WrapCredentials(grpc_service_account_credentials_create( - json_key.c_str(), scope.c_str(), lifetime)); + json_key.c_str(), scope.c_str(), lifetime, nullptr)); } // Builds JWT credentials. @@ -114,15 +115,15 @@ std::shared_ptr ServiceAccountJWTAccessCredentials( gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN); return WrapCredentials(grpc_service_account_jwt_access_credentials_create( - json_key.c_str(), lifetime)); + json_key.c_str(), lifetime, nullptr)); } // Builds refresh token credentials. std::shared_ptr RefreshTokenCredentials( const grpc::string& json_refresh_token) { GrpcLibrary init; // To call grpc_init(). - return WrapCredentials( - grpc_refresh_token_credentials_create(json_refresh_token.c_str())); + return WrapCredentials(grpc_refresh_token_credentials_create( + json_refresh_token.c_str(), nullptr)); } // Builds access token credentials. @@ -130,7 +131,7 @@ std::shared_ptr AccessTokenCredentials( const grpc::string& access_token) { GrpcLibrary init; // To call grpc_init(). return WrapCredentials( - grpc_access_token_credentials_create(access_token.c_str())); + grpc_access_token_credentials_create(access_token.c_str(), nullptr)); } // Builds IAM credentials. @@ -139,7 +140,7 @@ std::shared_ptr IAMCredentials( const grpc::string& authority_selector) { GrpcLibrary init; // To call grpc_init(). return WrapCredentials(grpc_iam_credentials_create( - authorization_token.c_str(), authority_selector.c_str())); + authorization_token.c_str(), authority_selector.c_str(), nullptr)); } // Combines two credentials objects into a composite credentials. @@ -154,7 +155,7 @@ std::shared_ptr CompositeCredentials( SecureCredentials* s2 = creds2->AsSecureCredentials(); if (s1 && s2) { return WrapCredentials(grpc_composite_credentials_create( - s1->GetRawCreds(), s2->GetRawCreds())); + s1->GetRawCreds(), s2->GetRawCreds(), nullptr)); } return nullptr; } diff --git a/src/cpp/common/auth_property_iterator.cc b/src/cpp/common/auth_property_iterator.cc index 5ccf8cf72c1..fa6da9d7a8d 100644 --- a/src/cpp/common/auth_property_iterator.cc +++ b/src/cpp/common/auth_property_iterator.cc @@ -77,9 +77,9 @@ bool AuthPropertyIterator::operator!=(const AuthPropertyIterator& rhs) const { } const AuthProperty AuthPropertyIterator::operator*() { - return std::make_pair( - grpc::string(property_->name), - grpc::string(property_->value, property_->value_length)); + return std::pair( + property_->name, + grpc::string_ref(property_->value, property_->value_length)); } } // namespace grpc diff --git a/src/cpp/common/call.cc b/src/cpp/common/call.cc index 16aa2c9fb9d..5b87c2a8067 100644 --- a/src/cpp/common/call.cc +++ b/src/cpp/common/call.cc @@ -41,13 +41,14 @@ namespace grpc { -void FillMetadataMap(grpc_metadata_array* arr, - std::multimap* metadata) { +void FillMetadataMap( + grpc_metadata_array* arr, + std::multimap* metadata) { for (size_t i = 0; i < arr->count; i++) { // TODO(yangg) handle duplicates? - metadata->insert(std::pair( - arr->metadata[i].key, - grpc::string(arr->metadata[i].value, arr->metadata[i].value_length))); + metadata->insert(std::pair( + arr->metadata[i].key, grpc::string_ref(arr->metadata[i].value, + arr->metadata[i].value_length))); } grpc_metadata_array_destroy(arr); grpc_metadata_array_init(arr); diff --git a/src/cpp/common/secure_auth_context.cc b/src/cpp/common/secure_auth_context.cc index 87d7bab75c6..b18a8537c99 100644 --- a/src/cpp/common/secure_auth_context.cc +++ b/src/cpp/common/secure_auth_context.cc @@ -41,15 +41,16 @@ SecureAuthContext::SecureAuthContext(grpc_auth_context* ctx) : ctx_(ctx) {} SecureAuthContext::~SecureAuthContext() { grpc_auth_context_release(ctx_); } -std::vector SecureAuthContext::GetPeerIdentity() const { +std::vector SecureAuthContext::GetPeerIdentity() const { if (!ctx_) { - return std::vector(); + return std::vector(); } grpc_auth_property_iterator iter = grpc_auth_context_peer_identity(ctx_); - std::vector identity; + std::vector identity; const grpc_auth_property* property = nullptr; while ((property = grpc_auth_property_iterator_next(&iter))) { - identity.push_back(grpc::string(property->value, property->value_length)); + identity.push_back( + grpc::string_ref(property->value, property->value_length)); } return identity; } @@ -62,17 +63,17 @@ grpc::string SecureAuthContext::GetPeerIdentityPropertyName() const { return name == nullptr ? "" : name; } -std::vector SecureAuthContext::FindPropertyValues( +std::vector SecureAuthContext::FindPropertyValues( const grpc::string& name) const { if (!ctx_) { - return std::vector(); + return std::vector(); } grpc_auth_property_iterator iter = grpc_auth_context_find_properties_by_name(ctx_, name.c_str()); const grpc_auth_property* property = nullptr; - std::vector values; + std::vector values; while ((property = grpc_auth_property_iterator_next(&iter))) { - values.push_back(grpc::string(property->value, property->value_length)); + values.push_back(grpc::string_ref(property->value, property->value_length)); } return values; } diff --git a/src/cpp/common/secure_auth_context.h b/src/cpp/common/secure_auth_context.h index 01b71261898..7f622b890b4 100644 --- a/src/cpp/common/secure_auth_context.h +++ b/src/cpp/common/secure_auth_context.h @@ -46,12 +46,12 @@ class SecureAuthContext GRPC_FINAL : public AuthContext { ~SecureAuthContext() GRPC_OVERRIDE; - std::vector GetPeerIdentity() const GRPC_OVERRIDE; + std::vector GetPeerIdentity() const GRPC_OVERRIDE; grpc::string GetPeerIdentityPropertyName() const GRPC_OVERRIDE; - std::vector FindPropertyValues(const grpc::string& name) const - GRPC_OVERRIDE; + std::vector FindPropertyValues( + const grpc::string& name) const GRPC_OVERRIDE; AuthPropertyIterator begin() const GRPC_OVERRIDE; diff --git a/src/cpp/server/secure_server_credentials.cc b/src/cpp/server/secure_server_credentials.cc index f203cf7f495..5bce9ca8b2c 100644 --- a/src/cpp/server/secure_server_credentials.cc +++ b/src/cpp/server/secure_server_credentials.cc @@ -52,7 +52,7 @@ std::shared_ptr SslServerCredentials( grpc_server_credentials* c_creds = grpc_ssl_server_credentials_create( options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(), &pem_key_cert_pairs[0], pem_key_cert_pairs.size(), - options.force_client_auth); + options.force_client_auth, nullptr); return std::shared_ptr( new SecureServerCredentials(c_creds)); } diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc index 66cd27cc339..bb83c7d887b 100644 --- a/src/cpp/server/server.cc +++ b/src/cpp/server/server.cc @@ -439,11 +439,12 @@ Server::BaseAsyncRequest::~BaseAsyncRequest() {} bool Server::BaseAsyncRequest::FinalizeResult(void** tag, bool* status) { if (*status) { for (size_t i = 0; i < initial_metadata_array_.count; i++) { - context_->client_metadata_.insert(std::make_pair( - grpc::string(initial_metadata_array_.metadata[i].key), - grpc::string(initial_metadata_array_.metadata[i].value, - initial_metadata_array_.metadata[i].value + - initial_metadata_array_.metadata[i].value_length))); + context_->client_metadata_.insert( + std::pair( + initial_metadata_array_.metadata[i].key, + grpc::string_ref( + initial_metadata_array_.metadata[i].value, + initial_metadata_array_.metadata[i].value_length))); } } grpc_metadata_array_destroy(&initial_metadata_array_); diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index acc163d6b5d..8193e70660d 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -136,10 +136,9 @@ ServerContext::ServerContext(gpr_timespec deadline, grpc_metadata* metadata, cq_(nullptr), sent_initial_metadata_(false) { for (size_t i = 0; i < metadata_count; i++) { - client_metadata_.insert(std::make_pair( - grpc::string(metadata[i].key), - grpc::string(metadata[i].value, - metadata[i].value + metadata[i].value_length))); + client_metadata_.insert(std::pair( + metadata[i].key, + grpc::string_ref(metadata[i].value, metadata[i].value_length))); } } diff --git a/src/cpp/util/string_ref.cc b/src/cpp/util/string_ref.cc index 8483e8c2eea..9adc0920135 100644 --- a/src/cpp/util/string_ref.cc +++ b/src/cpp/util/string_ref.cc @@ -39,7 +39,7 @@ namespace grpc { -constexpr size_t string_ref::npos; +const size_t string_ref::npos; string_ref& string_ref::operator=(const string_ref& rhs) { data_ = rhs.data_; @@ -80,7 +80,7 @@ size_t string_ref::find(string_ref s) const { } size_t string_ref::find(char c) const { - auto it = std::find_if(cbegin(), cend(), [c](char cc) { return cc == c; }); + auto it = std::find(cbegin(), cend(), c); return it == cend() ? npos : std::distance(cbegin(), it); } @@ -108,4 +108,8 @@ bool operator>=(string_ref x, string_ref y) { return x.compare(y) >= 0; } +std::ostream& operator<<(std::ostream& out, const string_ref& string) { + return out << grpc::string(string.begin(), string.end()); +} + } // namespace grpc diff --git a/src/csharp/.gitignore b/src/csharp/.gitignore index 48365e32a59..deac55029ee 100644 --- a/src/csharp/.gitignore +++ b/src/csharp/.gitignore @@ -4,6 +4,9 @@ StyleCop.Cache test-results packages Grpc.v12.suo +Grpc.sdf + TestResult.xml /TestResults +.vs/ *.nupkg diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj index b571fe90259..f730936062d 100644 --- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj +++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj @@ -64,6 +64,7 @@ Version.cs + diff --git a/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs new file mode 100644 index 00000000000..83707e0c6da --- /dev/null +++ b/src/csharp/Grpc.Core.Tests/MarshallingErrorsTest.cs @@ -0,0 +1,176 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using Grpc.Core; +using Grpc.Core.Internal; +using Grpc.Core.Utils; +using NUnit.Framework; + +namespace Grpc.Core.Tests +{ + public class MarshallingErrorsTest + { + const string Host = "127.0.0.1"; + + MockServiceHelper helper; + Server server; + Channel channel; + + [SetUp] + public void Init() + { + var marshaller = new Marshaller( + (str) => + { + if (str == "UNSERIALIZABLE_VALUE") + { + // Google.Protobuf throws exception inherited from IOException + throw new IOException("Error serializing the message."); + } + return System.Text.Encoding.UTF8.GetBytes(str); + }, + (payload) => + { + var s = System.Text.Encoding.UTF8.GetString(payload); + if (s == "UNPARSEABLE_VALUE") + { + // Google.Protobuf throws exception inherited from IOException + throw new IOException("Error parsing the message."); + } + return s; + }); + helper = new MockServiceHelper(Host, marshaller); + server = helper.GetServer(); + server.Start(); + channel = helper.GetChannel(); + } + + [TearDown] + public void Cleanup() + { + channel.ShutdownAsync().Wait(); + server.ShutdownAsync().Wait(); + } + + [Test] + public void ResponseParsingError_UnaryResponse() + { + helper.UnaryHandler = new UnaryServerMethod((request, context) => + { + return Task.FromResult("UNPARSEABLE_VALUE"); + }); + + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "REQUEST")); + Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); + } + + [Test] + public void ResponseParsingError_StreamingResponse() + { + helper.ServerStreamingHandler = new ServerStreamingServerMethod(async (request, responseStream, context) => + { + await responseStream.WriteAsync("UNPARSEABLE_VALUE"); + await Task.Delay(10000); + }); + + var call = Calls.AsyncServerStreamingCall(helper.CreateServerStreamingCall(), "REQUEST"); + var ex = Assert.Throws(async () => await call.ResponseStream.MoveNext()); + Assert.AreEqual(StatusCode.Internal, ex.Status.StatusCode); + } + + [Test] + public void RequestParsingError_UnaryRequest() + { + helper.UnaryHandler = new UnaryServerMethod((request, context) => + { + return Task.FromResult("RESPONSE"); + }); + + var ex = Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNPARSEABLE_VALUE")); + // Spec doesn't define the behavior. With the current implementation server handler throws exception which results in StatusCode.Unknown. + Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); + } + + [Test] + public async Task RequestParsingError_StreamingRequest() + { + helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => + { + Assert.Throws(async () => await requestStream.MoveNext()); + return "RESPONSE"; + }); + + var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); + await call.RequestStream.WriteAsync("UNPARSEABLE_VALUE"); + + Assert.AreEqual("RESPONSE", await call); + } + + [Test] + public void RequestSerializationError_BlockingUnary() + { + Assert.Throws(() => Calls.BlockingUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE")); + } + + [Test] + public void RequestSerializationError_AsyncUnary() + { + Assert.Throws(async () => await Calls.AsyncUnaryCall(helper.CreateUnaryCall(), "UNSERIALIZABLE_VALUE")); + } + + [Test] + public async Task RequestSerializationError_ClientStreaming() + { + helper.ClientStreamingHandler = new ClientStreamingServerMethod(async (requestStream, context) => + { + CollectionAssert.AreEqual(new [] {"A", "B"}, await requestStream.ToListAsync()); + return "RESPONSE"; + }); + var call = Calls.AsyncClientStreamingCall(helper.CreateClientStreamingCall()); + await call.RequestStream.WriteAsync("A"); + Assert.Throws(async () => await call.RequestStream.WriteAsync("UNSERIALIZABLE_VALUE")); + await call.RequestStream.WriteAsync("B"); + await call.RequestStream.CompleteAsync(); + + Assert.AreEqual("RESPONSE", await call); + } + } +} diff --git a/src/csharp/Grpc.Core.Tests/MetadataTest.cs b/src/csharp/Grpc.Core.Tests/MetadataTest.cs index c00f945d6a7..ddeb7d09260 100644 --- a/src/csharp/Grpc.Core.Tests/MetadataTest.cs +++ b/src/csharp/Grpc.Core.Tests/MetadataTest.cs @@ -74,6 +74,17 @@ namespace Grpc.Core.Tests Assert.AreEqual("[Entry: key=abc-bin, valueBytes=System.Byte[]]", entry.ToString()); } + [Test] + public void AsciiEntry_KeyValidity() + { + new Metadata.Entry("ABC", "XYZ"); + new Metadata.Entry("0123456789abc", "XYZ"); + new Metadata.Entry("-abc", "XYZ"); + new Metadata.Entry("a_bc_", "XYZ"); + Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc[", "xyz")); + Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc/", "xyz")); + } + [Test] public void Entry_ConstructionPreconditions() { diff --git a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs index bb69648d8bf..765732c7687 100644 --- a/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs +++ b/src/csharp/Grpc.Core.Tests/MockServiceHelper.cs @@ -50,37 +50,14 @@ namespace Grpc.Core.Tests { public const string ServiceName = "tests.Test"; - public static readonly Method UnaryMethod = new Method( - MethodType.Unary, - ServiceName, - "Unary", - Marshallers.StringMarshaller, - Marshallers.StringMarshaller); - - public static readonly Method ClientStreamingMethod = new Method( - MethodType.ClientStreaming, - ServiceName, - "ClientStreaming", - Marshallers.StringMarshaller, - Marshallers.StringMarshaller); - - public static readonly Method ServerStreamingMethod = new Method( - MethodType.ServerStreaming, - ServiceName, - "ServerStreaming", - Marshallers.StringMarshaller, - Marshallers.StringMarshaller); - - public static readonly Method DuplexStreamingMethod = new Method( - MethodType.DuplexStreaming, - ServiceName, - "DuplexStreaming", - Marshallers.StringMarshaller, - Marshallers.StringMarshaller); - readonly string host; readonly ServerServiceDefinition serviceDefinition; + readonly Method unaryMethod; + readonly Method clientStreamingMethod; + readonly Method serverStreamingMethod; + readonly Method duplexStreamingMethod; + UnaryServerMethod unaryHandler; ClientStreamingServerMethod clientStreamingHandler; ServerStreamingServerMethod serverStreamingHandler; @@ -89,15 +66,44 @@ namespace Grpc.Core.Tests Server server; Channel channel; - public MockServiceHelper(string host = null) + public MockServiceHelper(string host = null, Marshaller marshaller = null) { this.host = host ?? "localhost"; + marshaller = marshaller ?? Marshallers.StringMarshaller; + + unaryMethod = new Method( + MethodType.Unary, + ServiceName, + "Unary", + marshaller, + marshaller); + + clientStreamingMethod = new Method( + MethodType.ClientStreaming, + ServiceName, + "ClientStreaming", + marshaller, + marshaller); + + serverStreamingMethod = new Method( + MethodType.ServerStreaming, + ServiceName, + "ServerStreaming", + marshaller, + marshaller); + + duplexStreamingMethod = new Method( + MethodType.DuplexStreaming, + ServiceName, + "DuplexStreaming", + marshaller, + marshaller); serviceDefinition = ServerServiceDefinition.CreateBuilder(ServiceName) - .AddMethod(UnaryMethod, (request, context) => unaryHandler(request, context)) - .AddMethod(ClientStreamingMethod, (requestStream, context) => clientStreamingHandler(requestStream, context)) - .AddMethod(ServerStreamingMethod, (request, responseStream, context) => serverStreamingHandler(request, responseStream, context)) - .AddMethod(DuplexStreamingMethod, (requestStream, responseStream, context) => duplexStreamingHandler(requestStream, responseStream, context)) + .AddMethod(unaryMethod, (request, context) => unaryHandler(request, context)) + .AddMethod(clientStreamingMethod, (requestStream, context) => clientStreamingHandler(requestStream, context)) + .AddMethod(serverStreamingMethod, (request, responseStream, context) => serverStreamingHandler(request, responseStream, context)) + .AddMethod(duplexStreamingMethod, (requestStream, responseStream, context) => duplexStreamingHandler(requestStream, responseStream, context)) .Build(); var defaultStatus = new Status(StatusCode.Unknown, "Default mock implementation. Please provide your own."); @@ -155,22 +161,22 @@ namespace Grpc.Core.Tests public CallInvocationDetails CreateUnaryCall(CallOptions options = default(CallOptions)) { - return new CallInvocationDetails(channel, UnaryMethod, options); + return new CallInvocationDetails(channel, unaryMethod, options); } public CallInvocationDetails CreateClientStreamingCall(CallOptions options = default(CallOptions)) { - return new CallInvocationDetails(channel, ClientStreamingMethod, options); + return new CallInvocationDetails(channel, clientStreamingMethod, options); } public CallInvocationDetails CreateServerStreamingCall(CallOptions options = default(CallOptions)) { - return new CallInvocationDetails(channel, ServerStreamingMethod, options); + return new CallInvocationDetails(channel, serverStreamingMethod, options); } public CallInvocationDetails CreateDuplexStreamingCall(CallOptions options = default(CallOptions)) { - return new CallInvocationDetails(channel, DuplexStreamingMethod, options); + return new CallInvocationDetails(channel, duplexStreamingMethod, options); } public string Host diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs index be5d611a538..e3b00781c62 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs @@ -322,6 +322,11 @@ namespace Grpc.Core.Internal details.Channel.RemoveCallReference(this); } + protected override bool IsClient + { + get { return true; } + } + private void Initialize(CompletionQueueSafeHandle cq) { var call = CreateNativeCall(cq); @@ -376,9 +381,17 @@ namespace Grpc.Core.Internal /// private void HandleUnaryResponse(bool success, ClientSideStatus receivedStatus, byte[] receivedMessage, Metadata responseHeaders) { + TResponse msg = default(TResponse); + var deserializeException = success ? TryDeserialize(receivedMessage, out msg) : null; + lock (myLock) { finished = true; + + if (deserializeException != null && receivedStatus.Status.StatusCode == StatusCode.OK) + { + receivedStatus = new ClientSideStatus(DeserializeResponseFailureStatus, receivedStatus.Trailers); + } finishedStatus = receivedStatus; ReleaseResourcesIfPossible(); @@ -394,10 +407,6 @@ namespace Grpc.Core.Internal return; } - // TODO: handle deserialization error - TResponse msg; - TryDeserialize(receivedMessage, out msg); - unaryResponseTcs.SetResult(msg); } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs index 4d203946449..3e2c57c9b5b 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs @@ -33,10 +33,12 @@ using System; using System.Diagnostics; +using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; + using Grpc.Core.Internal; using Grpc.Core.Logging; using Grpc.Core.Utils; @@ -50,6 +52,7 @@ namespace Grpc.Core.Internal internal abstract class AsyncCallBase { static readonly ILogger Logger = GrpcEnvironment.Logger.ForType>(); + protected static readonly Status DeserializeResponseFailureStatus = new Status(StatusCode.Internal, "Failed to deserialize response message."); readonly Func serializer; readonly Func deserializer; @@ -100,11 +103,10 @@ namespace Grpc.Core.Internal /// /// Requests cancelling the call with given status. /// - public void CancelWithStatus(Status status) + protected void CancelWithStatus(Status status) { lock (myLock) { - Preconditions.CheckState(started); cancelRequested = true; if (!disposed) @@ -177,6 +179,11 @@ namespace Grpc.Core.Internal return false; } + protected abstract bool IsClient + { + get; + } + private void ReleaseResources() { if (call != null) @@ -224,33 +231,31 @@ namespace Grpc.Core.Internal return serializer(msg); } - protected bool TrySerialize(TWrite msg, out byte[] payload) + protected Exception TrySerialize(TWrite msg, out byte[] payload) { try { payload = serializer(msg); - return true; + return null; } catch (Exception e) { - Logger.Error(e, "Exception occured while trying to serialize message"); payload = null; - return false; + return e; } } - protected bool TryDeserialize(byte[] payload, out TRead msg) + protected Exception TryDeserialize(byte[] payload, out TRead msg) { try { msg = deserializer(payload); - return true; + return null; } catch (Exception e) { - Logger.Error(e, "Exception occured while trying to deserialize message."); msg = default(TRead); - return false; + return e; } } @@ -319,6 +324,9 @@ namespace Grpc.Core.Internal /// protected void HandleReadFinished(bool success, byte[] receivedMessage) { + TRead msg = default(TRead); + var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null; + AsyncCompletionDelegate origCompletionDelegate = null; lock (myLock) { @@ -331,23 +339,23 @@ namespace Grpc.Core.Internal readingDone = true; } + if (deserializeException != null && IsClient) + { + readingDone = true; + CancelWithStatus(DeserializeResponseFailureStatus); + } + ReleaseResourcesIfPossible(); } - // TODO: handle the case when error occured... + // TODO: handle the case when success==false - if (receivedMessage != null) - { - // TODO: handle deserialization error - TRead msg; - TryDeserialize(receivedMessage, out msg); - - FireCompletion(origCompletionDelegate, msg, null); - } - else + if (deserializeException != null && !IsClient) { - FireCompletion(origCompletionDelegate, default(TRead), null); + FireCompletion(origCompletionDelegate, default(TRead), new IOException("Failed to deserialize request message.", deserializeException)); + return; } + FireCompletion(origCompletionDelegate, msg, null); } } } \ No newline at end of file diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 5c47251030e..46ca4593493 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -169,6 +169,11 @@ namespace Grpc.Core.Internal } } + protected override bool IsClient + { + get { return false; } + } + protected override void CheckReadingAllowed() { base.CheckReadingAllowed(); diff --git a/src/csharp/Grpc.Core/Marshaller.cs b/src/csharp/Grpc.Core/Marshaller.cs index f38cb0863ff..3493d2d38f0 100644 --- a/src/csharp/Grpc.Core/Marshaller.cs +++ b/src/csharp/Grpc.Core/Marshaller.cs @@ -39,7 +39,7 @@ namespace Grpc.Core /// /// Encapsulates the logic for serializing and deserializing messages. /// - public struct Marshaller + public class Marshaller { readonly Func serializer; readonly Func deserializer; diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs index 99fe0b5478a..21bdf4f1145 100644 --- a/src/csharp/Grpc.Core/Metadata.cs +++ b/src/csharp/Grpc.Core/Metadata.cs @@ -33,8 +33,10 @@ using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; +using System.Globalization; using System.Runtime.InteropServices; using System.Text; +using System.Text.RegularExpressions; using Grpc.Core.Utils; @@ -188,6 +190,7 @@ namespace Grpc.Core public struct Entry { private static readonly Encoding Encoding = Encoding.ASCII; + private static readonly Regex ValidKeyRegex = new Regex("^[a-z0-9_-]+$"); readonly string key; readonly string value; @@ -320,7 +323,10 @@ namespace Grpc.Core private static string NormalizeKey(string key) { - return Preconditions.CheckNotNull(key, "key").ToLower(); + var normalized = Preconditions.CheckNotNull(key, "key").ToLower(CultureInfo.InvariantCulture); + Preconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized), + "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens."); + return normalized; } } } diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index b6dbd3b49c0..eda821bc312 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -39,8 +39,8 @@ namespace Grpc.Core public static class VersionInfo { /// - /// Current version of gRPC + /// Current version of gRPC C# /// - public const string CurrentVersion = "0.6.1"; + public const string CurrentVersion = "0.7.0"; } } diff --git a/src/csharp/Grpc.Examples.MathClient/MathClient.cs b/src/csharp/Grpc.Examples.MathClient/MathClient.cs index abd95cb905e..01e4a80babc 100644 --- a/src/csharp/Grpc.Examples.MathClient/MathClient.cs +++ b/src/csharp/Grpc.Examples.MathClient/MathClient.cs @@ -33,7 +33,7 @@ using System.Runtime.InteropServices; using System.Threading; using Grpc.Core; -namespace math +namespace Math { class MathClient { diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs index 26bef646ec4..6e974a08710 100644 --- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs +++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs @@ -34,7 +34,7 @@ using System.Runtime.InteropServices; using System.Threading; using Grpc.Core; -namespace math +namespace Math { class MainClass { diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj index 9a8f780b245..c4c1ee6d006 100644 --- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj +++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj @@ -37,13 +37,14 @@ C:\keys\Grpc.snk + + False + ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll + ..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - ..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll - False ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 36c1c947bd0..e2975b5da93 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -40,7 +40,7 @@ using Grpc.Core; using Grpc.Core.Utils; using NUnit.Framework; -namespace math.Tests +namespace Math.Tests { /// /// Math client talks to local math server. @@ -75,7 +75,7 @@ namespace math.Tests [Test] public void Div1() { - DivReply response = client.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()); + DivReply response = client.Div(new DivArgs { Dividend = 10, Divisor = 3 }); Assert.AreEqual(3, response.Quotient); Assert.AreEqual(1, response.Remainder); } @@ -83,7 +83,7 @@ namespace math.Tests [Test] public void Div2() { - DivReply response = client.Div(new DivArgs.Builder { Dividend = 0, Divisor = 1 }.Build()); + DivReply response = client.Div(new DivArgs { Dividend = 0, Divisor = 1 }); Assert.AreEqual(0, response.Quotient); Assert.AreEqual(0, response.Remainder); } @@ -91,14 +91,14 @@ namespace math.Tests [Test] public void DivByZero() { - var ex = Assert.Throws(() => client.Div(new DivArgs.Builder { Dividend = 0, Divisor = 0 }.Build())); + var ex = Assert.Throws(() => client.Div(new DivArgs { Dividend = 0, Divisor = 0 })); Assert.AreEqual(StatusCode.Unknown, ex.Status.StatusCode); } [Test] public async Task DivAsync() { - DivReply response = await client.DivAsync(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()); + DivReply response = await client.DivAsync(new DivArgs { Dividend = 10, Divisor = 3 }); Assert.AreEqual(3, response.Quotient); Assert.AreEqual(1, response.Remainder); } @@ -106,7 +106,7 @@ namespace math.Tests [Test] public async Task Fib() { - using (var call = client.Fib(new FibArgs.Builder { Limit = 6 }.Build())) + using (var call = client.Fib(new FibArgs { Limit = 6 })) { var responses = await call.ResponseStream.ToListAsync(); CollectionAssert.AreEqual(new List { 1, 1, 2, 3, 5, 8 }, @@ -119,8 +119,7 @@ namespace math.Tests { var cts = new CancellationTokenSource(); - using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), - cancellationToken: cts.Token)) + using (var call = client.Fib(new FibArgs { Limit = 0 }, cancellationToken: cts.Token)) { List responses = new List(); @@ -147,7 +146,7 @@ namespace math.Tests [Test] public async Task FibWithDeadline() { - using (var call = client.Fib(new FibArgs.Builder { Limit = 0 }.Build(), + using (var call = client.Fib(new FibArgs { Limit = 0 }, deadline: DateTime.UtcNow.AddMilliseconds(500))) { var ex = Assert.Throws(async () => await call.ResponseStream.ToListAsync()); @@ -163,8 +162,7 @@ namespace math.Tests { using (var call = client.Sum()) { - var numbers = new List { 10, 20, 30 }.ConvertAll( - n => Num.CreateBuilder().SetNum_(n).Build()); + var numbers = new List { 10, 20, 30 }.ConvertAll(n => new Num { Num_ = n }); await call.RequestStream.WriteAllAsync(numbers); var result = await call.ResponseAsync; @@ -177,9 +175,9 @@ namespace math.Tests { var divArgsList = new List { - new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(), - new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(), - new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build() + new DivArgs { Dividend = 10, Divisor = 3 }, + new DivArgs { Dividend = 100, Divisor = 21 }, + new DivArgs { Dividend = 7, Divisor = 2 } }; using (var call = client.DivMany()) diff --git a/src/csharp/Grpc.Examples.Tests/packages.config b/src/csharp/Grpc.Examples.Tests/packages.config index cc6e9af40f6..7266fa1763c 100644 --- a/src/csharp/Grpc.Examples.Tests/packages.config +++ b/src/csharp/Grpc.Examples.Tests/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/csharp/Grpc.Examples/Grpc.Examples.csproj b/src/csharp/Grpc.Examples/Grpc.Examples.csproj index c1aa40500e4..55462e02fd5 100644 --- a/src/csharp/Grpc.Examples/Grpc.Examples.csproj +++ b/src/csharp/Grpc.Examples/Grpc.Examples.csproj @@ -37,11 +37,12 @@ C:\keys\Grpc.snk + + False + ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll + - - ..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll - ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll diff --git a/src/csharp/Grpc.Examples/Math.cs b/src/csharp/Grpc.Examples/Math.cs index 75b1e9dbc2a..d0e1ee8aae5 100644 --- a/src/csharp/Grpc.Examples/Math.cs +++ b/src/csharp/Grpc.Examples/Math.cs @@ -1,80 +1,46 @@ -// Generated by ProtoGen, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT! +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: math.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code -using pb = global::Google.ProtocolBuffers; -using pbc = global::Google.ProtocolBuffers.Collections; -using pbd = global::Google.ProtocolBuffers.Descriptors; +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace math { +namespace Math { namespace Proto { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Math { - #region Extension registration - public static void RegisterAllExtensions(pb::ExtensionRegistry registry) { - } - #endregion - #region Static variables - internal static pbd::MessageDescriptor internal__static_math_DivArgs__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_math_DivArgs__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_math_DivReply__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_math_DivReply__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_math_FibArgs__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_math_FibArgs__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_math_Num__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_math_Num__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_math_FibReply__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_math_FibReply__FieldAccessorTable; - #endregion #region Descriptor - public static pbd::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor { get { return descriptor; } } - private static pbd::FileDescriptor descriptor; + private static pbr::FileDescriptor descriptor; static Math() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "CgptYXRoLnByb3RvEgRtYXRoIiwKB0RpdkFyZ3MSEAoIZGl2aWRlbmQYASAB", - "KAMSDwoHZGl2aXNvchgCIAEoAyIvCghEaXZSZXBseRIQCghxdW90aWVudBgB", - "IAEoAxIRCglyZW1haW5kZXIYAiABKAMiGAoHRmliQXJncxINCgVsaW1pdBgB", - "IAEoAyISCgNOdW0SCwoDbnVtGAEgASgDIhkKCEZpYlJlcGx5Eg0KBWNvdW50", - "GAEgASgDMqQBCgRNYXRoEiYKA0RpdhINLm1hdGguRGl2QXJncxoOLm1hdGgu", - "RGl2UmVwbHkiABIuCgdEaXZNYW55Eg0ubWF0aC5EaXZBcmdzGg4ubWF0aC5E", - "aXZSZXBseSIAKAEwARIjCgNGaWISDS5tYXRoLkZpYkFyZ3MaCS5tYXRoLk51", - "bSIAMAESHwoDU3VtEgkubWF0aC5OdW0aCS5tYXRoLk51bSIAKAE=")); - pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) { - descriptor = root; - internal__static_math_DivArgs__Descriptor = Descriptor.MessageTypes[0]; - internal__static_math_DivArgs__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_math_DivArgs__Descriptor, - new string[] { "Dividend", "Divisor", }); - internal__static_math_DivReply__Descriptor = Descriptor.MessageTypes[1]; - internal__static_math_DivReply__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_math_DivReply__Descriptor, - new string[] { "Quotient", "Remainder", }); - internal__static_math_FibArgs__Descriptor = Descriptor.MessageTypes[2]; - internal__static_math_FibArgs__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_math_FibArgs__Descriptor, - new string[] { "Limit", }); - internal__static_math_Num__Descriptor = Descriptor.MessageTypes[3]; - internal__static_math_Num__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_math_Num__Descriptor, - new string[] { "Num_", }); - internal__static_math_FibReply__Descriptor = Descriptor.MessageTypes[4]; - internal__static_math_FibReply__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_math_FibReply__Descriptor, - new string[] { "Count", }); - pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance(); - RegisterAllExtensions(registry); - return registry; - }; - pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, - new pbd::FileDescriptor[] { - }, assigner); + "CgptYXRoLnByb3RvEgRtYXRoIiwKB0RpdkFyZ3MSEAoIZGl2aWRlbmQYASAB", + "KAMSDwoHZGl2aXNvchgCIAEoAyIvCghEaXZSZXBseRIQCghxdW90aWVudBgB", + "IAEoAxIRCglyZW1haW5kZXIYAiABKAMiGAoHRmliQXJncxINCgVsaW1pdBgB", + "IAEoAyISCgNOdW0SCwoDbnVtGAEgASgDIhkKCEZpYlJlcGx5Eg0KBWNvdW50", + "GAEgASgDMqQBCgRNYXRoEiYKA0RpdhINLm1hdGguRGl2QXJncxoOLm1hdGgu", + "RGl2UmVwbHkiABIuCgdEaXZNYW55Eg0ubWF0aC5EaXZBcmdzGg4ubWF0aC5E", + "aXZSZXBseSIAKAEwARIjCgNGaWISDS5tYXRoLkZpYkFyZ3MaCS5tYXRoLk51", + "bSIAMAESHwoDU3VtEgkubWF0aC5OdW0aCS5tYXRoLk51bSIAKAFiBnByb3Rv", + "Mw==")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { + new pbr::GeneratedCodeInfo(typeof(global::Math.DivArgs), new[]{ "Dividend", "Divisor" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Math.DivReply), new[]{ "Quotient", "Remainder" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Math.FibArgs), new[]{ "Limit" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Math.Num), new[]{ "Num_" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Math.FibReply), new[]{ "Count" }, null, null, null) + })); } #endregion @@ -82,1448 +48,567 @@ namespace math { } #region Messages [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class DivArgs : pb::GeneratedMessage { - private DivArgs() { } - private static readonly DivArgs defaultInstance = new DivArgs().MakeReadOnly(); - private static readonly string[] _divArgsFieldNames = new string[] { "dividend", "divisor" }; - private static readonly uint[] _divArgsFieldTags = new uint[] { 8, 16 }; - public static DivArgs DefaultInstance { - get { return defaultInstance; } + public sealed partial class DivArgs : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DivArgs()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Math.Proto.Math.Descriptor.MessageTypes[0]; } } - public override DivArgs DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override DivArgs ThisMessage { - get { return this; } + public DivArgs() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::math.Proto.Math.internal__static_math_DivArgs__Descriptor; } + partial void OnConstruction(); + + public DivArgs(DivArgs other) : this() { + dividend_ = other.dividend_; + divisor_ = other.divisor_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::math.Proto.Math.internal__static_math_DivArgs__FieldAccessorTable; } + public DivArgs Clone() { + return new DivArgs(this); } public const int DividendFieldNumber = 1; - private bool hasDividend; private long dividend_; - public bool HasDividend { - get { return hasDividend; } - } public long Dividend { get { return dividend_; } + set { + dividend_ = value; + } } public const int DivisorFieldNumber = 2; - private bool hasDivisor; private long divisor_; - public bool HasDivisor { - get { return hasDivisor; } - } public long Divisor { get { return divisor_; } + set { + divisor_ = value; + } } - public override bool IsInitialized { - get { - return true; - } + public override bool Equals(object other) { + return Equals(other as DivArgs); } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _divArgsFieldNames; - if (hasDividend) { - output.WriteInt64(1, field_names[0], Dividend); + public bool Equals(DivArgs other) { + if (ReferenceEquals(other, null)) { + return false; } - if (hasDivisor) { - output.WriteInt64(2, field_names[1], Divisor); + if (ReferenceEquals(other, this)) { + return true; } - UnknownFields.WriteTo(output); + if (Dividend != other.Dividend) return false; + if (Divisor != other.Divisor) return false; + return true; } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasDividend) { - size += pb::CodedOutputStream.ComputeInt64Size(1, Dividend); - } - if (hasDivisor) { - size += pb::CodedOutputStream.ComputeInt64Size(2, Divisor); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; - } + public override int GetHashCode() { + int hash = 1; + if (Dividend != 0L) hash ^= Dividend.GetHashCode(); + if (Divisor != 0L) hash ^= Divisor.GetHashCode(); + return hash; } - public static DivArgs ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static DivArgs ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static DivArgs ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static DivArgs ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static DivArgs ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static DivArgs ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - public static DivArgs ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static DivArgs ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static DivArgs ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static DivArgs ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private DivArgs MakeReadOnly() { - return this; - } - - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(DivArgs prototype) { - return new Builder(prototype); - } - - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(DivArgs cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private DivArgs result; - - private DivArgs PrepareBuilder() { - if (resultIsReadOnly) { - DivArgs original = result; - result = new DivArgs(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - public override bool IsInitialized { - get { return result.IsInitialized; } + public void WriteTo(pb::CodedOutputStream output) { + if (Dividend != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Dividend); } - - protected override DivArgs MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::math.DivArgs.Descriptor; } + if (Divisor != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Divisor); } + } - public override DivArgs DefaultInstanceForType { - get { return global::math.DivArgs.DefaultInstance; } + public int CalculateSize() { + int size = 0; + if (Dividend != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Dividend); } - - public override DivArgs BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + if (Divisor != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Divisor); } + return size; + } - public override Builder MergeFrom(pb::IMessage other) { - if (other is DivArgs) { - return MergeFrom((DivArgs) other); - } else { - base.MergeFrom(other); - return this; - } + public void MergeFrom(DivArgs other) { + if (other == null) { + return; } - - public override Builder MergeFrom(DivArgs other) { - if (other == global::math.DivArgs.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasDividend) { - Dividend = other.Dividend; - } - if (other.HasDivisor) { - Divisor = other.Divisor; - } - this.MergeUnknownFields(other.UnknownFields); - return this; + if (other.Dividend != 0L) { + Dividend = other.Dividend; } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); + if (other.Divisor != 0L) { + Divisor = other.Divisor; } + } - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_divArgsFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _divArgsFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Dividend = input.ReadInt64(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - result.hasDividend = input.ReadInt64(ref result.dividend_); - break; - } - case 16: { - result.hasDivisor = input.ReadInt64(ref result.divisor_); - break; - } + case 16: { + Divisor = input.ReadInt64(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasDividend { - get { return result.hasDividend; } - } - public long Dividend { - get { return result.Dividend; } - set { SetDividend(value); } } - public Builder SetDividend(long value) { - PrepareBuilder(); - result.hasDividend = true; - result.dividend_ = value; - return this; - } - public Builder ClearDividend() { - PrepareBuilder(); - result.hasDividend = false; - result.dividend_ = 0L; - return this; - } - - public bool HasDivisor { - get { return result.hasDivisor; } - } - public long Divisor { - get { return result.Divisor; } - set { SetDivisor(value); } - } - public Builder SetDivisor(long value) { - PrepareBuilder(); - result.hasDivisor = true; - result.divisor_ = value; - return this; - } - public Builder ClearDivisor() { - PrepareBuilder(); - result.hasDivisor = false; - result.divisor_ = 0L; - return this; - } - } - static DivArgs() { - object.ReferenceEquals(global::math.Proto.Math.Descriptor, null); } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class DivReply : pb::GeneratedMessage { - private DivReply() { } - private static readonly DivReply defaultInstance = new DivReply().MakeReadOnly(); - private static readonly string[] _divReplyFieldNames = new string[] { "quotient", "remainder" }; - private static readonly uint[] _divReplyFieldTags = new uint[] { 8, 16 }; - public static DivReply DefaultInstance { - get { return defaultInstance; } + public sealed partial class DivReply : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new DivReply()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Math.Proto.Math.Descriptor.MessageTypes[1]; } } - public override DivReply DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override DivReply ThisMessage { - get { return this; } + public DivReply() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::math.Proto.Math.internal__static_math_DivReply__Descriptor; } + partial void OnConstruction(); + + public DivReply(DivReply other) : this() { + quotient_ = other.quotient_; + remainder_ = other.remainder_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::math.Proto.Math.internal__static_math_DivReply__FieldAccessorTable; } + public DivReply Clone() { + return new DivReply(this); } public const int QuotientFieldNumber = 1; - private bool hasQuotient; private long quotient_; - public bool HasQuotient { - get { return hasQuotient; } - } public long Quotient { get { return quotient_; } + set { + quotient_ = value; + } } public const int RemainderFieldNumber = 2; - private bool hasRemainder; private long remainder_; - public bool HasRemainder { - get { return hasRemainder; } - } public long Remainder { get { return remainder_; } - } - - public override bool IsInitialized { - get { - return true; + set { + remainder_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _divReplyFieldNames; - if (hasQuotient) { - output.WriteInt64(1, field_names[0], Quotient); - } - if (hasRemainder) { - output.WriteInt64(2, field_names[1], Remainder); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as DivReply); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasQuotient) { - size += pb::CodedOutputStream.ComputeInt64Size(1, Quotient); - } - if (hasRemainder) { - size += pb::CodedOutputStream.ComputeInt64Size(2, Remainder); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(DivReply other) { + if (ReferenceEquals(other, null)) { + return false; } + if (ReferenceEquals(other, this)) { + return true; + } + if (Quotient != other.Quotient) return false; + if (Remainder != other.Remainder) return false; + return true; } - public static DivReply ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static DivReply ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static DivReply ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static DivReply ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static DivReply ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static DivReply ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static DivReply ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static DivReply ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static DivReply ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static DivReply ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private DivReply MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (Quotient != 0L) hash ^= Quotient.GetHashCode(); + if (Remainder != 0L) hash ^= Remainder.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(DivReply prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(DivReply cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private DivReply result; - - private DivReply PrepareBuilder() { - if (resultIsReadOnly) { - DivReply original = result; - result = new DivReply(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override DivReply MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } + public void WriteTo(pb::CodedOutputStream output) { + if (Quotient != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Quotient); } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::math.DivReply.Descriptor; } + if (Remainder != 0L) { + output.WriteRawTag(16); + output.WriteInt64(Remainder); } + } - public override DivReply DefaultInstanceForType { - get { return global::math.DivReply.DefaultInstance; } + public int CalculateSize() { + int size = 0; + if (Quotient != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Quotient); } - - public override DivReply BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + if (Remainder != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Remainder); } + return size; + } - public override Builder MergeFrom(pb::IMessage other) { - if (other is DivReply) { - return MergeFrom((DivReply) other); - } else { - base.MergeFrom(other); - return this; - } + public void MergeFrom(DivReply other) { + if (other == null) { + return; } - - public override Builder MergeFrom(DivReply other) { - if (other == global::math.DivReply.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasQuotient) { - Quotient = other.Quotient; - } - if (other.HasRemainder) { - Remainder = other.Remainder; - } - this.MergeUnknownFields(other.UnknownFields); - return this; + if (other.Quotient != 0L) { + Quotient = other.Quotient; } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); + if (other.Remainder != 0L) { + Remainder = other.Remainder; } + } - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_divReplyFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _divReplyFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Quotient = input.ReadInt64(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - result.hasQuotient = input.ReadInt64(ref result.quotient_); - break; - } - case 16: { - result.hasRemainder = input.ReadInt64(ref result.remainder_); - break; - } + case 16: { + Remainder = input.ReadInt64(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasQuotient { - get { return result.hasQuotient; } - } - public long Quotient { - get { return result.Quotient; } - set { SetQuotient(value); } - } - public Builder SetQuotient(long value) { - PrepareBuilder(); - result.hasQuotient = true; - result.quotient_ = value; - return this; - } - public Builder ClearQuotient() { - PrepareBuilder(); - result.hasQuotient = false; - result.quotient_ = 0L; - return this; - } - - public bool HasRemainder { - get { return result.hasRemainder; } - } - public long Remainder { - get { return result.Remainder; } - set { SetRemainder(value); } - } - public Builder SetRemainder(long value) { - PrepareBuilder(); - result.hasRemainder = true; - result.remainder_ = value; - return this; } - public Builder ClearRemainder() { - PrepareBuilder(); - result.hasRemainder = false; - result.remainder_ = 0L; - return this; - } - } - static DivReply() { - object.ReferenceEquals(global::math.Proto.Math.Descriptor, null); } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class FibArgs : pb::GeneratedMessage { - private FibArgs() { } - private static readonly FibArgs defaultInstance = new FibArgs().MakeReadOnly(); - private static readonly string[] _fibArgsFieldNames = new string[] { "limit" }; - private static readonly uint[] _fibArgsFieldTags = new uint[] { 8 }; - public static FibArgs DefaultInstance { - get { return defaultInstance; } + public sealed partial class FibArgs : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FibArgs()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Math.Proto.Math.Descriptor.MessageTypes[2]; } } - public override FibArgs DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override FibArgs ThisMessage { - get { return this; } + public FibArgs() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::math.Proto.Math.internal__static_math_FibArgs__Descriptor; } + partial void OnConstruction(); + + public FibArgs(FibArgs other) : this() { + limit_ = other.limit_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::math.Proto.Math.internal__static_math_FibArgs__FieldAccessorTable; } + public FibArgs Clone() { + return new FibArgs(this); } public const int LimitFieldNumber = 1; - private bool hasLimit; private long limit_; - public bool HasLimit { - get { return hasLimit; } - } public long Limit { get { return limit_; } - } - - public override bool IsInitialized { - get { - return true; + set { + limit_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _fibArgsFieldNames; - if (hasLimit) { - output.WriteInt64(1, field_names[0], Limit); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as FibArgs); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasLimit) { - size += pb::CodedOutputStream.ComputeInt64Size(1, Limit); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(FibArgs other) { + if (ReferenceEquals(other, null)) { + return false; } + if (ReferenceEquals(other, this)) { + return true; + } + if (Limit != other.Limit) return false; + return true; } - public static FibArgs ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static FibArgs ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static FibArgs ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static FibArgs ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static FibArgs ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static FibArgs ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static FibArgs ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static FibArgs ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static FibArgs ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static FibArgs ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private FibArgs MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (Limit != 0L) hash ^= Limit.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(FibArgs prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(FibArgs cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private FibArgs result; - - private FibArgs PrepareBuilder() { - if (resultIsReadOnly) { - FibArgs original = result; - result = new FibArgs(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override FibArgs MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::math.FibArgs.Descriptor; } - } - - public override FibArgs DefaultInstanceForType { - get { return global::math.FibArgs.DefaultInstance; } + public void WriteTo(pb::CodedOutputStream output) { + if (Limit != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Limit); } + } - public override FibArgs BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); - } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is FibArgs) { - return MergeFrom((FibArgs) other); - } else { - base.MergeFrom(other); - return this; - } + public int CalculateSize() { + int size = 0; + if (Limit != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Limit); } + return size; + } - public override Builder MergeFrom(FibArgs other) { - if (other == global::math.FibArgs.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasLimit) { - Limit = other.Limit; - } - this.MergeUnknownFields(other.UnknownFields); - return this; + public void MergeFrom(FibArgs other) { + if (other == null) { + return; } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); + if (other.Limit != 0L) { + Limit = other.Limit; } + } - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_fibArgsFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _fibArgsFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Limit = input.ReadInt64(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - result.hasLimit = input.ReadInt64(ref result.limit_); - break; - } - } - } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); } - return this; - } - - - public bool HasLimit { - get { return result.hasLimit; } - } - public long Limit { - get { return result.Limit; } - set { SetLimit(value); } - } - public Builder SetLimit(long value) { - PrepareBuilder(); - result.hasLimit = true; - result.limit_ = value; - return this; } - public Builder ClearLimit() { - PrepareBuilder(); - result.hasLimit = false; - result.limit_ = 0L; - return this; - } - } - static FibArgs() { - object.ReferenceEquals(global::math.Proto.Math.Descriptor, null); } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Num : pb::GeneratedMessage { - private Num() { } - private static readonly Num defaultInstance = new Num().MakeReadOnly(); - private static readonly string[] _numFieldNames = new string[] { "num" }; - private static readonly uint[] _numFieldTags = new uint[] { 8 }; - public static Num DefaultInstance { - get { return defaultInstance; } + public sealed partial class Num : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Num()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Math.Proto.Math.Descriptor.MessageTypes[3]; } } - public override Num DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override Num ThisMessage { - get { return this; } + public Num() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::math.Proto.Math.internal__static_math_Num__Descriptor; } + partial void OnConstruction(); + + public Num(Num other) : this() { + num_ = other.num_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::math.Proto.Math.internal__static_math_Num__FieldAccessorTable; } + public Num Clone() { + return new Num(this); } public const int Num_FieldNumber = 1; - private bool hasNum_; private long num_; - public bool HasNum_ { - get { return hasNum_; } - } public long Num_ { get { return num_; } - } - - public override bool IsInitialized { - get { - return true; + set { + num_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _numFieldNames; - if (hasNum_) { - output.WriteInt64(1, field_names[0], Num_); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as Num); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasNum_) { - size += pb::CodedOutputStream.ComputeInt64Size(1, Num_); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(Num other) { + if (ReferenceEquals(other, null)) { + return false; } + if (ReferenceEquals(other, this)) { + return true; + } + if (Num_ != other.Num_) return false; + return true; } - public static Num ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static Num ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static Num ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static Num ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static Num ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static Num ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static Num ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static Num ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static Num ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static Num ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private Num MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (Num_ != 0L) hash ^= Num_.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(Num prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(Num cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private Num result; - - private Num PrepareBuilder() { - if (resultIsReadOnly) { - Num original = result; - result = new Num(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override Num MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::math.Num.Descriptor; } - } - - public override Num DefaultInstanceForType { - get { return global::math.Num.DefaultInstance; } - } - - public override Num BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + public void WriteTo(pb::CodedOutputStream output) { + if (Num_ != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Num_); } + } - public override Builder MergeFrom(pb::IMessage other) { - if (other is Num) { - return MergeFrom((Num) other); - } else { - base.MergeFrom(other); - return this; - } + public int CalculateSize() { + int size = 0; + if (Num_ != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Num_); } + return size; + } - public override Builder MergeFrom(Num other) { - if (other == global::math.Num.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasNum_) { - Num_ = other.Num_; - } - this.MergeUnknownFields(other.UnknownFields); - return this; + public void MergeFrom(Num other) { + if (other == null) { + return; } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); + if (other.Num_ != 0L) { + Num_ = other.Num_; } + } - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_numFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _numFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } - } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - result.hasNum_ = input.ReadInt64(ref result.num_); - break; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Num_ = input.ReadInt64(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasNum_ { - get { return result.hasNum_; } - } - public long Num_ { - get { return result.Num_; } - set { SetNum_(value); } - } - public Builder SetNum_(long value) { - PrepareBuilder(); - result.hasNum_ = true; - result.num_ = value; - return this; - } - public Builder ClearNum_() { - PrepareBuilder(); - result.hasNum_ = false; - result.num_ = 0L; - return this; } } - static Num() { - object.ReferenceEquals(global::math.Proto.Math.Descriptor, null); - } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class FibReply : pb::GeneratedMessage { - private FibReply() { } - private static readonly FibReply defaultInstance = new FibReply().MakeReadOnly(); - private static readonly string[] _fibReplyFieldNames = new string[] { "count" }; - private static readonly uint[] _fibReplyFieldTags = new uint[] { 8 }; - public static FibReply DefaultInstance { - get { return defaultInstance; } + public sealed partial class FibReply : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new FibReply()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Math.Proto.Math.Descriptor.MessageTypes[4]; } } - public override FibReply DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override FibReply ThisMessage { - get { return this; } + public FibReply() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::math.Proto.Math.internal__static_math_FibReply__Descriptor; } + partial void OnConstruction(); + + public FibReply(FibReply other) : this() { + count_ = other.count_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::math.Proto.Math.internal__static_math_FibReply__FieldAccessorTable; } + public FibReply Clone() { + return new FibReply(this); } public const int CountFieldNumber = 1; - private bool hasCount; private long count_; - public bool HasCount { - get { return hasCount; } - } public long Count { get { return count_; } - } - - public override bool IsInitialized { - get { - return true; + set { + count_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _fibReplyFieldNames; - if (hasCount) { - output.WriteInt64(1, field_names[0], Count); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as FibReply); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasCount) { - size += pb::CodedOutputStream.ComputeInt64Size(1, Count); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(FibReply other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; } + if (Count != other.Count) return false; + return true; } - public static FibReply ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static FibReply ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static FibReply ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static FibReply ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static FibReply ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static FibReply ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static FibReply ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static FibReply ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static FibReply ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static FibReply ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private FibReply MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (Count != 0L) hash ^= Count.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(FibReply prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(FibReply cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private FibReply result; - - private FibReply PrepareBuilder() { - if (resultIsReadOnly) { - FibReply original = result; - result = new FibReply(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override FibReply MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::math.FibReply.Descriptor; } - } - - public override FibReply DefaultInstanceForType { - get { return global::math.FibReply.DefaultInstance; } - } - - public override FibReply BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + public void WriteTo(pb::CodedOutputStream output) { + if (Count != 0L) { + output.WriteRawTag(8); + output.WriteInt64(Count); } + } - public override Builder MergeFrom(pb::IMessage other) { - if (other is FibReply) { - return MergeFrom((FibReply) other); - } else { - base.MergeFrom(other); - return this; - } + public int CalculateSize() { + int size = 0; + if (Count != 0L) { + size += 1 + pb::CodedOutputStream.ComputeInt64Size(Count); } + return size; + } - public override Builder MergeFrom(FibReply other) { - if (other == global::math.FibReply.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasCount) { - Count = other.Count; - } - this.MergeUnknownFields(other.UnknownFields); - return this; + public void MergeFrom(FibReply other) { + if (other == null) { + return; } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); + if (other.Count != 0L) { + Count = other.Count; } + } - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_fibReplyFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _fibReplyFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } - } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - result.hasCount = input.ReadInt64(ref result.count_); - break; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Count = input.ReadInt64(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; } - - - public bool HasCount { - get { return result.hasCount; } - } - public long Count { - get { return result.Count; } - set { SetCount(value); } - } - public Builder SetCount(long value) { - PrepareBuilder(); - result.hasCount = true; - result.count_ = value; - return this; - } - public Builder ClearCount() { - PrepareBuilder(); - result.hasCount = false; - result.count_ = 0L; - return this; - } - } - static FibReply() { - object.ReferenceEquals(global::math.Proto.Math.Descriptor, null); } - } - #endregion + } - #region Services - /* - * Service generation is now disabled by default, use the following option to enable: - * option (google.protobuf.csharp_file_options).service_generator_type = GENERIC; - */ #endregion } diff --git a/src/csharp/Grpc.Examples/MathExamples.cs b/src/csharp/Grpc.Examples/MathExamples.cs index dc1bf439950..8009ccbbfa1 100644 --- a/src/csharp/Grpc.Examples/MathExamples.cs +++ b/src/csharp/Grpc.Examples/MathExamples.cs @@ -34,25 +34,25 @@ using System.Collections.Generic; using System.Threading.Tasks; using Grpc.Core.Utils; -namespace math +namespace Math { public static class MathExamples { public static void DivExample(Math.IMathClient client) { - DivReply result = client.Div(new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build()); + DivReply result = client.Div(new DivArgs { Dividend = 10, Divisor = 3 }); Console.WriteLine("Div Result: " + result); } public static async Task DivAsyncExample(Math.IMathClient client) { - DivReply result = await client.DivAsync(new DivArgs.Builder { Dividend = 4, Divisor = 5 }.Build()); + DivReply result = await client.DivAsync(new DivArgs { Dividend = 4, Divisor = 5 }); Console.WriteLine("DivAsync Result: " + result); } public static async Task FibExample(Math.IMathClient client) { - using (var call = client.Fib(new FibArgs.Builder { Limit = 5 }.Build())) + using (var call = client.Fib(new FibArgs { Limit = 5 })) { List result = await call.ResponseStream.ToListAsync(); Console.WriteLine("Fib Result: " + string.Join("|", result)); @@ -63,9 +63,9 @@ namespace math { var numbers = new List { - new Num.Builder { Num_ = 1 }.Build(), - new Num.Builder { Num_ = 2 }.Build(), - new Num.Builder { Num_ = 3 }.Build() + new Num { Num_ = 1 }, + new Num { Num_ = 2 }, + new Num { Num_ = 3 } }; using (var call = client.Sum()) @@ -79,9 +79,9 @@ namespace math { var divArgsList = new List { - new DivArgs.Builder { Dividend = 10, Divisor = 3 }.Build(), - new DivArgs.Builder { Dividend = 100, Divisor = 21 }.Build(), - new DivArgs.Builder { Dividend = 7, Divisor = 2 }.Build() + new DivArgs { Dividend = 10, Divisor = 3 }, + new DivArgs { Dividend = 100, Divisor = 21 }, + new DivArgs { Dividend = 7, Divisor = 2 } }; using (var call = client.DivMany()) { @@ -94,9 +94,9 @@ namespace math { var numbers = new List { - new Num.Builder { Num_ = 1 }.Build(), - new Num.Builder { Num_ = 2 }.Build(), - new Num.Builder { Num_ = 3 }.Build() + new Num { Num_ = 1 }, + new Num { Num_ = 2 }, + new Num { Num_ = 3 } }; Num sum; @@ -106,7 +106,7 @@ namespace math sum = await sumCall.ResponseAsync; } - DivReply result = await client.DivAsync(new DivArgs.Builder { Dividend = sum.Num_, Divisor = numbers.Count }.Build()); + DivReply result = await client.DivAsync(new DivArgs { Dividend = sum.Num_, Divisor = numbers.Count }); Console.WriteLine("Avg Result: " + result); } } diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs index 4941ff35f72..175d110f764 100644 --- a/src/csharp/Grpc.Examples/MathGrpc.cs +++ b/src/csharp/Grpc.Examples/MathGrpc.cs @@ -7,66 +7,72 @@ using System.Threading; using System.Threading.Tasks; using Grpc.Core; -namespace math { +namespace Math { public static class Math { static readonly string __ServiceName = "math.Math"; - static readonly Marshaller __Marshaller_DivArgs = Marshallers.Create((arg) => arg.ToByteArray(), global::math.DivArgs.ParseFrom); - static readonly Marshaller __Marshaller_DivReply = Marshallers.Create((arg) => arg.ToByteArray(), global::math.DivReply.ParseFrom); - static readonly Marshaller __Marshaller_FibArgs = Marshallers.Create((arg) => arg.ToByteArray(), global::math.FibArgs.ParseFrom); - static readonly Marshaller __Marshaller_Num = Marshallers.Create((arg) => arg.ToByteArray(), global::math.Num.ParseFrom); + static readonly Marshaller __Marshaller_DivArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivArgs.Parser.ParseFrom); + static readonly Marshaller __Marshaller_DivReply = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.DivReply.Parser.ParseFrom); + static readonly Marshaller __Marshaller_FibArgs = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.FibArgs.Parser.ParseFrom); + static readonly Marshaller __Marshaller_Num = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Math.Num.Parser.ParseFrom); - static readonly Method __Method_Div = new Method( + static readonly Method __Method_Div = new Method( MethodType.Unary, __ServiceName, "Div", __Marshaller_DivArgs, __Marshaller_DivReply); - static readonly Method __Method_DivMany = new Method( + static readonly Method __Method_DivMany = new Method( MethodType.DuplexStreaming, __ServiceName, "DivMany", __Marshaller_DivArgs, __Marshaller_DivReply); - static readonly Method __Method_Fib = new Method( + static readonly Method __Method_Fib = new Method( MethodType.ServerStreaming, __ServiceName, "Fib", __Marshaller_FibArgs, __Marshaller_Num); - static readonly Method __Method_Sum = new Method( + static readonly Method __Method_Sum = new Method( MethodType.ClientStreaming, __ServiceName, "Sum", __Marshaller_Num, __Marshaller_Num); + // service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Math.Proto.Math.Descriptor.Services[0]; } + } + // client interface public interface IMathClient { - global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - global::math.DivReply Div(global::math.DivArgs request, CallOptions options); - AsyncUnaryCall DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncUnaryCall DivAsync(global::math.DivArgs request, CallOptions options); - AsyncDuplexStreamingCall DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall DivMany(CallOptions options); - AsyncServerStreamingCall Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncServerStreamingCall Fib(global::math.FibArgs request, CallOptions options); - AsyncClientStreamingCall Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncClientStreamingCall Sum(CallOptions options); + global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options); + AsyncUnaryCall DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall DivAsync(global::Math.DivArgs request, CallOptions options); + AsyncDuplexStreamingCall DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall DivMany(CallOptions options); + AsyncServerStreamingCall Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncServerStreamingCall Fib(global::Math.FibArgs request, CallOptions options); + AsyncClientStreamingCall Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncClientStreamingCall Sum(CallOptions options); } // server-side interface public interface IMath { - Task Div(global::math.DivArgs request, ServerCallContext context); - Task DivMany(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); - Task Fib(global::math.FibArgs request, IServerStreamWriter responseStream, ServerCallContext context); - Task Sum(IAsyncStreamReader requestStream, ServerCallContext context); + Task Div(global::Math.DivArgs request, ServerCallContext context); + Task DivMany(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); + Task Fib(global::Math.FibArgs request, IServerStreamWriter responseStream, ServerCallContext context); + Task Sum(IAsyncStreamReader requestStream, ServerCallContext context); } // client stub @@ -75,52 +81,52 @@ namespace math { public MathClient(Channel channel) : base(channel) { } - public global::math.DivReply Div(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public global::Math.DivReply Div(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken)); return Calls.BlockingUnaryCall(call, request); } - public global::math.DivReply Div(global::math.DivArgs request, CallOptions options) + public global::Math.DivReply Div(global::Math.DivArgs request, CallOptions options) { var call = CreateCall(__Method_Div, options); return Calls.BlockingUnaryCall(call, request); } - public AsyncUnaryCall DivAsync(global::math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall DivAsync(global::Math.DivArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Div, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncUnaryCall(call, request); } - public AsyncUnaryCall DivAsync(global::math.DivArgs request, CallOptions options) + public AsyncUnaryCall DivAsync(global::Math.DivArgs request, CallOptions options) { var call = CreateCall(__Method_Div, options); return Calls.AsyncUnaryCall(call, request); } - public AsyncDuplexStreamingCall DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall DivMany(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_DivMany, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncDuplexStreamingCall(call); } - public AsyncDuplexStreamingCall DivMany(CallOptions options) + public AsyncDuplexStreamingCall DivMany(CallOptions options) { var call = CreateCall(__Method_DivMany, options); return Calls.AsyncDuplexStreamingCall(call); } - public AsyncServerStreamingCall Fib(global::math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncServerStreamingCall Fib(global::Math.FibArgs request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Fib, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncServerStreamingCall(call, request); } - public AsyncServerStreamingCall Fib(global::math.FibArgs request, CallOptions options) + public AsyncServerStreamingCall Fib(global::Math.FibArgs request, CallOptions options) { var call = CreateCall(__Method_Fib, options); return Calls.AsyncServerStreamingCall(call, request); } - public AsyncClientStreamingCall Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncClientStreamingCall Sum(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_Sum, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncClientStreamingCall(call); } - public AsyncClientStreamingCall Sum(CallOptions options) + public AsyncClientStreamingCall Sum(CallOptions options) { var call = CreateCall(__Method_Sum, options); return Calls.AsyncClientStreamingCall(call); diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs index 7b2684615c6..71dc655e46d 100644 --- a/src/csharp/Grpc.Examples/MathServiceImpl.cs +++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs @@ -38,7 +38,7 @@ using System.Threading.Tasks; using Grpc.Core; using Grpc.Core.Utils; -namespace math +namespace Math { /// /// Implementation of MathService server @@ -79,7 +79,7 @@ namespace math { sum += num.Num_; }); - return Num.CreateBuilder().SetNum_(sum).Build(); + return new Num { Num_ = sum }; } public async Task DivMany(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) @@ -91,13 +91,13 @@ namespace math { long quotient = args.Dividend / args.Divisor; long remainder = args.Dividend % args.Divisor; - return new DivReply.Builder { Quotient = quotient, Remainder = remainder }.Build(); + return new DivReply { Quotient = quotient, Remainder = remainder }; } static IEnumerable FibInternal(long n) { long a = 1; - yield return new Num.Builder { Num_ = a }.Build(); + yield return new Num { Num_ = a }; long b = 1; for (long i = 0; i < n - 1; i++) @@ -105,7 +105,7 @@ namespace math long temp = a; a = b; b = temp + b; - yield return new Num.Builder { Num_ = a }.Build(); + yield return new Num { Num_ = a }; } } } diff --git a/src/csharp/Grpc.Examples/packages.config b/src/csharp/Grpc.Examples/packages.config index 4c8d60fa62a..adf8da2363d 100644 --- a/src/csharp/Grpc.Examples/packages.config +++ b/src/csharp/Grpc.Examples/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/csharp/Grpc.Examples/proto/math.proto b/src/csharp/Grpc.Examples/proto/math.proto index 5485d580c32..311e148c021 100644 --- a/src/csharp/Grpc.Examples/proto/math.proto +++ b/src/csharp/Grpc.Examples/proto/math.proto @@ -28,30 +28,30 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -syntax = "proto2"; +syntax = "proto3"; package math; message DivArgs { - optional int64 dividend = 1; - optional int64 divisor = 2; + int64 dividend = 1; + int64 divisor = 2; } message DivReply { - optional int64 quotient = 1; - optional int64 remainder = 2; + int64 quotient = 1; + int64 remainder = 2; } message FibArgs { - optional int64 limit = 1; + int64 limit = 1; } message Num { - optional int64 num = 1; + int64 num = 1; } message FibReply { - optional int64 count = 1; + int64 count = 1; } service Math { diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj index c922ddfb9e7..396dc43a021 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj +++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj @@ -37,11 +37,9 @@ C:\keys\Grpc.snk - - ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll - - - ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll + + False + ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll ..\packages\NUnit.2.6.4\lib\nunit.framework.dll diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs index 80c35fb1977..6c3a53bec05 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs +++ b/src/csharp/Grpc.HealthCheck.Tests/HealthClientServerTest.cs @@ -81,14 +81,14 @@ namespace Grpc.HealthCheck.Tests { serviceImpl.SetStatus("", "", HealthCheckResponse.Types.ServingStatus.SERVING); - var response = client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("").Build()); + var response = client.Check(new HealthCheckRequest { Host = "", Service = "" }); Assert.AreEqual(HealthCheckResponse.Types.ServingStatus.SERVING, response.Status); } [Test] public void ServiceDoesntExist() { - Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => client.Check(HealthCheckRequest.CreateBuilder().SetHost("").SetService("nonexistent.service").Build())); + Assert.Throws(Is.TypeOf(typeof(RpcException)).And.Property("Status").Property("StatusCode").EqualTo(StatusCode.NotFound), () => client.Check(new HealthCheckRequest { Host = "", Service = "nonexistent.service" })); } // TODO(jtattermusch): add test with timeout once timeouts are supported diff --git a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs index c4caa3b57aa..2097c0dc8cf 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs +++ b/src/csharp/Grpc.HealthCheck.Tests/HealthServiceImplTest.cs @@ -101,7 +101,7 @@ namespace Grpc.HealthCheck.Tests private static HealthCheckResponse.Types.ServingStatus GetStatusHelper(HealthServiceImpl impl, string host, string service) { - return impl.Check(HealthCheckRequest.CreateBuilder().SetHost(host).SetService(service).Build(), null).Result.Status; + return impl.Check(new HealthCheckRequest { Host = host, Service = service }, null).Result.Status; } } } diff --git a/src/csharp/Grpc.HealthCheck.Tests/packages.config b/src/csharp/Grpc.HealthCheck.Tests/packages.config index 050c4eaed67..40ffb852031 100644 --- a/src/csharp/Grpc.HealthCheck.Tests/packages.config +++ b/src/csharp/Grpc.HealthCheck.Tests/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj index 0b7a7b91c6b..8fce5d39aab 100644 --- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj @@ -38,11 +38,9 @@ C:\keys\Grpc.snk - - ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.dll - - - ..\packages\Google.ProtocolBuffers.2.4.1.555\lib\net40\Google.ProtocolBuffers.Serialization.dll + + False + ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec index acdfba42c81..66386288df1 100644 --- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.nuspec @@ -14,7 +14,7 @@ Copyright 2015, Google Inc. gRPC health check - + diff --git a/src/csharp/Grpc.HealthCheck/Health.cs b/src/csharp/Grpc.HealthCheck/Health.cs index 361382d4bd6..570e274544e 100644 --- a/src/csharp/Grpc.HealthCheck/Health.cs +++ b/src/csharp/Grpc.HealthCheck/Health.cs @@ -3,9 +3,9 @@ #pragma warning disable 1591, 0612, 3021 #region Designer generated code -using pb = global::Google.ProtocolBuffers; -using pbc = global::Google.ProtocolBuffers.Collections; -using pbd = global::Google.ProtocolBuffers.Descriptors; +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; namespace Grpc.Health.V1Alpha { @@ -14,21 +14,11 @@ namespace Grpc.Health.V1Alpha { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Health { - #region Extension registration - public static void RegisterAllExtensions(pb::ExtensionRegistry registry) { - } - #endregion - #region Static variables - internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable; - #endregion #region Descriptor - public static pbd::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor { get { return descriptor; } } - private static pbd::FileDescriptor descriptor; + private static pbr::FileDescriptor descriptor; static Health() { byte[] descriptorData = global::System.Convert.FromBase64String( @@ -41,24 +31,13 @@ namespace Grpc.Health.V1Alpha { "EAESDwoLTk9UX1NFUlZJTkcQAjJkCgZIZWFsdGgSWgoFQ2hlY2sSJy5ncnBj", "LmhlYWx0aC52MWFscGhhLkhlYWx0aENoZWNrUmVxdWVzdBooLmdycGMuaGVh", "bHRoLnYxYWxwaGEuSGVhbHRoQ2hlY2tSZXNwb25zZUIWqgITR3JwYy5IZWFs", - "dGguVjFBbHBoYQ==")); - pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) { - descriptor = root; - internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor = Descriptor.MessageTypes[0]; - internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor, - new string[] { "Host", "Service", }); - internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor = Descriptor.MessageTypes[1]; - internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor, - new string[] { "Status", }); - pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance(); - RegisterAllExtensions(registry); - return registry; - }; - pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, - new pbd::FileDescriptor[] { - }, assigner); + "dGguVjFBbHBoYWIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1Alpha.HealthCheckRequest), new[]{ "Host", "Service" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Health.V1Alpha.HealthCheckResponse), new[]{ "Status" }, null, new[]{ typeof(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus) }, null) + })); } #endregion @@ -66,618 +45,245 @@ namespace Grpc.Health.V1Alpha { } #region Messages [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class HealthCheckRequest : pb::GeneratedMessage { - private HealthCheckRequest() { } - private static readonly HealthCheckRequest defaultInstance = new HealthCheckRequest().MakeReadOnly(); - private static readonly string[] _healthCheckRequestFieldNames = new string[] { "host", "service" }; - private static readonly uint[] _healthCheckRequestFieldTags = new uint[] { 10, 18 }; - public static HealthCheckRequest DefaultInstance { - get { return defaultInstance; } + public sealed partial class HealthCheckRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HealthCheckRequest()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.MessageTypes[0]; } } - public override HealthCheckRequest DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override HealthCheckRequest ThisMessage { - get { return this; } + public HealthCheckRequest() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__Descriptor; } + partial void OnConstruction(); + + public HealthCheckRequest(HealthCheckRequest other) : this() { + host_ = other.host_; + service_ = other.service_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckRequest__FieldAccessorTable; } + public HealthCheckRequest Clone() { + return new HealthCheckRequest(this); } public const int HostFieldNumber = 1; - private bool hasHost; private string host_ = ""; - public bool HasHost { - get { return hasHost; } - } public string Host { get { return host_; } + set { + host_ = pb::Preconditions.CheckNotNull(value, "value"); + } } public const int ServiceFieldNumber = 2; - private bool hasService; private string service_ = ""; - public bool HasService { - get { return hasService; } - } public string Service { get { return service_; } - } - - public override bool IsInitialized { - get { - return true; - } - } - - public override void WriteTo(pb::ICodedOutputStream output) { - CalcSerializedSize(); - string[] field_names = _healthCheckRequestFieldNames; - if (hasHost) { - output.WriteString(1, field_names[0], Host); - } - if (hasService) { - output.WriteString(2, field_names[1], Service); + set { + service_ = pb::Preconditions.CheckNotNull(value, "value"); } - UnknownFields.WriteTo(output); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - return CalcSerializedSize(); - } + public override bool Equals(object other) { + return Equals(other as HealthCheckRequest); } - private int CalcSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasHost) { - size += pb::CodedOutputStream.ComputeStringSize(1, Host); + public bool Equals(HealthCheckRequest other) { + if (ReferenceEquals(other, null)) { + return false; } - if (hasService) { - size += pb::CodedOutputStream.ComputeStringSize(2, Service); + if (ReferenceEquals(other, this)) { + return true; } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; - } - public static HealthCheckRequest ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static HealthCheckRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static HealthCheckRequest ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static HealthCheckRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static HealthCheckRequest ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static HealthCheckRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static HealthCheckRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static HealthCheckRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private HealthCheckRequest MakeReadOnly() { - return this; + if (Host != other.Host) return false; + if (Service != other.Service) return false; + return true; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(HealthCheckRequest prototype) { - return new Builder(prototype); + public override int GetHashCode() { + int hash = 1; + if (Host.Length != 0) hash ^= Host.GetHashCode(); + if (Service.Length != 0) hash ^= Service.GetHashCode(); + return hash; } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(HealthCheckRequest cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private HealthCheckRequest result; - - private HealthCheckRequest PrepareBuilder() { - if (resultIsReadOnly) { - HealthCheckRequest original = result; - result = new HealthCheckRequest(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override HealthCheckRequest MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } + public void WriteTo(pb::CodedOutputStream output) { + if (Host.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Host); } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.Descriptor; } + if (Service.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Service); } + } - public override HealthCheckRequest DefaultInstanceForType { - get { return global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance; } + public int CalculateSize() { + int size = 0; + if (Host.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Host); } - - public override HealthCheckRequest BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + if (Service.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Service); } + return size; + } - public override Builder MergeFrom(pb::IMessage other) { - if (other is HealthCheckRequest) { - return MergeFrom((HealthCheckRequest) other); - } else { - base.MergeFrom(other); - return this; - } + public void MergeFrom(HealthCheckRequest other) { + if (other == null) { + return; } - - public override Builder MergeFrom(HealthCheckRequest other) { - if (other == global::Grpc.Health.V1Alpha.HealthCheckRequest.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasHost) { - Host = other.Host; - } - if (other.HasService) { - Service = other.Service; - } - this.MergeUnknownFields(other.UnknownFields); - return this; + if (other.Host.Length != 0) { + Host = other.Host; } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); + if (other.Service.Length != 0) { + Service = other.Service; } + } - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_healthCheckRequestFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _healthCheckRequestFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + Host = input.ReadString(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 10: { - result.hasHost = input.ReadString(ref result.host_); - break; - } - case 18: { - result.hasService = input.ReadString(ref result.service_); - break; - } + case 18: { + Service = input.ReadString(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasHost { - get { return result.hasHost; } - } - public string Host { - get { return result.Host; } - set { SetHost(value); } - } - public Builder SetHost(string value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasHost = true; - result.host_ = value; - return this; - } - public Builder ClearHost() { - PrepareBuilder(); - result.hasHost = false; - result.host_ = ""; - return this; - } - - public bool HasService { - get { return result.hasService; } - } - public string Service { - get { return result.Service; } - set { SetService(value); } } - public Builder SetService(string value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasService = true; - result.service_ = value; - return this; - } - public Builder ClearService() { - PrepareBuilder(); - result.hasService = false; - result.service_ = ""; - return this; - } - } - static HealthCheckRequest() { - object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null); } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class HealthCheckResponse : pb::GeneratedMessage { - private HealthCheckResponse() { } - private static readonly HealthCheckResponse defaultInstance = new HealthCheckResponse().MakeReadOnly(); - private static readonly string[] _healthCheckResponseFieldNames = new string[] { "status" }; - private static readonly uint[] _healthCheckResponseFieldTags = new uint[] { 8 }; - public static HealthCheckResponse DefaultInstance { - get { return defaultInstance; } - } + public sealed partial class HealthCheckResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new HealthCheckResponse()); + public static pb::MessageParser Parser { get { return _parser; } } - public override HealthCheckResponse DefaultInstanceForType { - get { return DefaultInstance; } + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.MessageTypes[1]; } } - protected override HealthCheckResponse ThisMessage { - get { return this; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - public static pbd::MessageDescriptor Descriptor { - get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__Descriptor; } + public HealthCheckResponse() { + OnConstruction(); } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::Grpc.Health.V1Alpha.Proto.Health.internal__static_grpc_health_v1alpha_HealthCheckResponse__FieldAccessorTable; } - } + partial void OnConstruction(); - #region Nested types - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public static partial class Types { - public enum ServingStatus { - UNKNOWN = 0, - SERVING = 1, - NOT_SERVING = 2, - } + public HealthCheckResponse(HealthCheckResponse other) : this() { + status_ = other.status_; + } + public HealthCheckResponse Clone() { + return new HealthCheckResponse(this); } - #endregion public const int StatusFieldNumber = 1; - private bool hasStatus; private global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN; - public bool HasStatus { - get { return hasStatus; } - } public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status { get { return status_; } - } - - public override bool IsInitialized { - get { - return true; + set { + status_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - CalcSerializedSize(); - string[] field_names = _healthCheckResponseFieldNames; - if (hasStatus) { - output.WriteEnum(1, field_names[0], (int) Status, Status); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as HealthCheckResponse); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - return CalcSerializedSize(); + public bool Equals(HealthCheckResponse other) { + if (ReferenceEquals(other, null)) { + return false; } - } - - private int CalcSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasStatus) { - size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Status); + if (ReferenceEquals(other, this)) { + return true; } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; - } - public static HealthCheckResponse ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static HealthCheckResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static HealthCheckResponse ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static HealthCheckResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static HealthCheckResponse ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static HealthCheckResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static HealthCheckResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static HealthCheckResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private HealthCheckResponse MakeReadOnly() { - return this; + if (Status != other.Status) return false; + return true; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(HealthCheckResponse prototype) { - return new Builder(prototype); + public override int GetHashCode() { + int hash = 1; + if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) hash ^= Status.GetHashCode(); + return hash; } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(HealthCheckResponse cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private HealthCheckResponse result; - - private HealthCheckResponse PrepareBuilder() { - if (resultIsReadOnly) { - HealthCheckResponse original = result; - result = new HealthCheckResponse(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override HealthCheckResponse MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.Descriptor; } - } - - public override HealthCheckResponse DefaultInstanceForType { - get { return global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance; } - } + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); + } - public override HealthCheckResponse BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + public void WriteTo(pb::CodedOutputStream output) { + if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { + output.WriteRawTag(8); + output.WriteEnum((int) Status); } + } - public override Builder MergeFrom(pb::IMessage other) { - if (other is HealthCheckResponse) { - return MergeFrom((HealthCheckResponse) other); - } else { - base.MergeFrom(other); - return this; - } + public int CalculateSize() { + int size = 0; + if (Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status); } + return size; + } - public override Builder MergeFrom(HealthCheckResponse other) { - if (other == global::Grpc.Health.V1Alpha.HealthCheckResponse.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasStatus) { - Status = other.Status; - } - this.MergeUnknownFields(other.UnknownFields); - return this; + public void MergeFrom(HealthCheckResponse other) { + if (other == null) { + return; } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); + if (other.Status != global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN) { + Status = other.Status; } + } - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_healthCheckResponseFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _healthCheckResponseFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + status_ = (global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus) input.ReadEnum(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - object unknown; - if(input.ReadEnum(ref result.status_, out unknown)) { - result.hasStatus = true; - } else if(unknown is int) { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - unknownFields.MergeVarintField(1, (ulong)(int)unknown); - } - break; - } - } - } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); } - return this; } + } - - public bool HasStatus { - get { return result.hasStatus; } - } - public global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus Status { - get { return result.Status; } - set { SetStatus(value); } - } - public Builder SetStatus(global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus value) { - PrepareBuilder(); - result.hasStatus = true; - result.status_ = value; - return this; - } - public Builder ClearStatus() { - PrepareBuilder(); - result.hasStatus = false; - result.status_ = global::Grpc.Health.V1Alpha.HealthCheckResponse.Types.ServingStatus.UNKNOWN; - return this; + #region Nested types + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Types { + public enum ServingStatus { + UNKNOWN = 0, + SERVING = 1, + NOT_SERVING = 2, } + } - static HealthCheckResponse() { - object.ReferenceEquals(global::Grpc.Health.V1Alpha.Proto.Health.Descriptor, null); - } + #endregion + } #endregion diff --git a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs index 0dabc91f7c2..da721ce5f6a 100644 --- a/src/csharp/Grpc.HealthCheck/HealthGrpc.cs +++ b/src/csharp/Grpc.HealthCheck/HealthGrpc.cs @@ -12,8 +12,8 @@ namespace Grpc.Health.V1Alpha { { static readonly string __ServiceName = "grpc.health.v1alpha.Health"; - static readonly Marshaller __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckRequest.ParseFrom); - static readonly Marshaller __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::Grpc.Health.V1Alpha.HealthCheckResponse.ParseFrom); + static readonly Marshaller __Marshaller_HealthCheckRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1Alpha.HealthCheckRequest.Parser.ParseFrom); + static readonly Marshaller __Marshaller_HealthCheckResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Health.V1Alpha.HealthCheckResponse.Parser.ParseFrom); static readonly Method __Method_Check = new Method( MethodType.Unary, @@ -22,6 +22,12 @@ namespace Grpc.Health.V1Alpha { __Marshaller_HealthCheckRequest, __Marshaller_HealthCheckResponse); + // service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Grpc.Health.V1Alpha.Proto.Health.Descriptor.Services[0]; } + } + // client interface public interface IHealthClient { diff --git a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs index 8c04b43a86e..26c6445c357 100644 --- a/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs +++ b/src/csharp/Grpc.HealthCheck/HealthServiceImpl.cs @@ -105,8 +105,8 @@ namespace Grpc.HealthCheck { lock (myLock) { - var host = request.HasHost ? request.Host : ""; - var service = request.HasService ? request.Service : ""; + var host = request.Host; + var service = request.Service; HealthCheckResponse.Types.ServingStatus status; if (!statusMap.TryGetValue(CreateKey(host, service), out status)) @@ -114,7 +114,7 @@ namespace Grpc.HealthCheck // TODO(jtattermusch): returning specific status from server handler is not supported yet. throw new RpcException(new Status(StatusCode.NotFound, "")); } - return Task.FromResult(HealthCheckResponse.CreateBuilder().SetStatus(status).Build()); + return Task.FromResult(new HealthCheckResponse { Status = status }); } } diff --git a/src/csharp/Grpc.HealthCheck/packages.config b/src/csharp/Grpc.HealthCheck/packages.config index 094a30981e4..cafff6123a3 100644 --- a/src/csharp/Grpc.HealthCheck/packages.config +++ b/src/csharp/Grpc.HealthCheck/packages.config @@ -1,5 +1,5 @@  - + \ No newline at end of file diff --git a/src/csharp/Grpc.HealthCheck/proto/health.proto b/src/csharp/Grpc.HealthCheck/proto/health.proto index 08df7e104e1..01aa3fcf577 100644 --- a/src/csharp/Grpc.HealthCheck/proto/health.proto +++ b/src/csharp/Grpc.HealthCheck/proto/health.proto @@ -28,14 +28,14 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // TODO(jtattermusch): switch to proto3 once C# supports that. -syntax = "proto2"; +syntax = "proto3"; package grpc.health.v1alpha; option csharp_namespace = "Grpc.Health.V1Alpha"; message HealthCheckRequest { - optional string host = 1; - optional string service = 2; + string host = 1; + string service = 2; } message HealthCheckResponse { @@ -44,7 +44,7 @@ message HealthCheckResponse { SERVING = 1; NOT_SERVING = 2; } - optional ServingStatus status = 1; + ServingStatus status = 1; } service Health { diff --git a/src/csharp/Grpc.IntegrationTesting/Empty.cs b/src/csharp/Grpc.IntegrationTesting/Empty.cs index 7169ee2a4a5..28c28c9afd5 100644 --- a/src/csharp/Grpc.IntegrationTesting/Empty.cs +++ b/src/csharp/Grpc.IntegrationTesting/Empty.cs @@ -1,47 +1,34 @@ -// Generated by ProtoGen, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT! +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: empty.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code -using pb = global::Google.ProtocolBuffers; -using pbc = global::Google.ProtocolBuffers.Collections; -using pbd = global::Google.ProtocolBuffers.Descriptors; +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace grpc.testing { +namespace Grpc.Testing { namespace Proto { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Empty { - #region Extension registration - public static void RegisterAllExtensions(pb::ExtensionRegistry registry) { - } - #endregion - #region Static variables - internal static pbd::MessageDescriptor internal__static_grpc_testing_Empty__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_Empty__FieldAccessorTable; - #endregion #region Descriptor - public static pbd::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor { get { return descriptor; } } - private static pbd::FileDescriptor descriptor; + private static pbr::FileDescriptor descriptor; static Empty() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5")); - pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) { - descriptor = root; - internal__static_grpc_testing_Empty__Descriptor = Descriptor.MessageTypes[0]; - internal__static_grpc_testing_Empty__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_Empty__Descriptor, - new string[] { }); - return null; - }; - pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, - new pbd::FileDescriptor[] { - }, assigner); + "CgtlbXB0eS5wcm90bxIMZ3JwYy50ZXN0aW5nIgcKBUVtcHR5YgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Empty), null, null, null, null) + })); } #endregion @@ -49,230 +36,79 @@ namespace grpc.testing { } #region Messages [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Empty : pb::GeneratedMessage { - private Empty() { } - private static readonly Empty defaultInstance = new Empty().MakeReadOnly(); - private static readonly string[] _emptyFieldNames = new string[] { }; - private static readonly uint[] _emptyFieldTags = new uint[] { }; - public static Empty DefaultInstance { - get { return defaultInstance; } - } + public sealed partial class Empty : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Empty()); + public static pb::MessageParser Parser { get { return _parser; } } - public override Empty DefaultInstanceForType { - get { return DefaultInstance; } + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Proto.Empty.Descriptor.MessageTypes[0]; } } - protected override Empty ThisMessage { - get { return this; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Proto.Empty.internal__static_grpc_testing_Empty__Descriptor; } + public Empty() { + OnConstruction(); } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Proto.Empty.internal__static_grpc_testing_Empty__FieldAccessorTable; } - } + partial void OnConstruction(); - public override bool IsInitialized { - get { - return true; - } + public Empty(Empty other) : this() { } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _emptyFieldNames; - UnknownFields.WriteTo(output); + public Empty Clone() { + return new Empty(this); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; + public override bool Equals(object other) { + return Equals(other as Empty); + } - size = 0; - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(Empty other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; } + return true; } - public static Empty ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static Empty ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static Empty ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static Empty ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static Empty ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static Empty ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static Empty ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static Empty ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static Empty ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static Empty ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private Empty MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(Empty prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(Empty cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private Empty result; - - private Empty PrepareBuilder() { - if (resultIsReadOnly) { - Empty original = result; - result = new Empty(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override Empty MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.Empty.Descriptor; } - } - - public override Empty DefaultInstanceForType { - get { return global::grpc.testing.Empty.DefaultInstance; } - } - - public override Empty BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); - } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is Empty) { - return MergeFrom((Empty) other); - } else { - base.MergeFrom(other); - return this; - } - } + public void WriteTo(pb::CodedOutputStream output) { + } - public override Builder MergeFrom(Empty other) { - if (other == global::grpc.testing.Empty.DefaultInstance) return this; - PrepareBuilder(); - this.MergeUnknownFields(other.UnknownFields); - return this; - } + public int CalculateSize() { + int size = 0; + return size; + } - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); + public void MergeFrom(Empty other) { + if (other == null) { + return; } + } - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_emptyFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _emptyFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } - } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - } - } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; } - return this; } - - } - static Empty() { - object.ReferenceEquals(global::grpc.testing.Proto.Empty.Descriptor, null); } + } #endregion diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj index 2020a76d396..a5945be922b 100644 --- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj +++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj @@ -54,6 +54,10 @@ False ..\packages\Google.Apis.Core.1.9.3\lib\portable-net40+sl50+win+wpa81+wp80\Google.Apis.Core.dll + + False + ..\packages\Google.Protobuf.3.0.0-alpha4\lib\portable-net45+netcore45+wpa81+wp8\Google.Protobuf.dll + False ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll @@ -74,22 +78,11 @@ ..\packages\NUnit.2.6.4\lib\nunit.framework.dll - - ..\packages\Google.ProtocolBuffers.2.4.1.521\lib\net40\Google.ProtocolBuffers.dll - ..\packages\Ix-Async.1.2.3\lib\net45\System.Interactive.Async.dll - - False - ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll - - - False - ..\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll - @@ -106,6 +99,7 @@ + diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs index 24c22273fb4..8343e54122c 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClient.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClient.cs @@ -38,13 +38,11 @@ using System.Threading; using System.Threading.Tasks; using Google.Apis.Auth.OAuth2; -using Google.ProtocolBuffers; - -using grpc.testing; +using Google.Protobuf; using Grpc.Auth; using Grpc.Core; using Grpc.Core.Utils; - +using Grpc.Testing; using NUnit.Framework; namespace Grpc.IntegrationTesting @@ -183,7 +181,7 @@ namespace Grpc.IntegrationTesting public static void RunEmptyUnary(TestService.ITestServiceClient client) { Console.WriteLine("running empty_unary"); - var response = client.EmptyCall(Empty.DefaultInstance); + var response = client.EmptyCall(new Empty()); Assert.IsNotNull(response); Console.WriteLine("Passed!"); } @@ -191,11 +189,12 @@ namespace Grpc.IntegrationTesting public static void RunLargeUnary(TestService.ITestServiceClient client) { Console.WriteLine("running large_unary"); - var request = SimpleRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .SetResponseSize(314159) - .SetPayload(CreateZerosPayload(271828)) - .Build(); + var request = new SimpleRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseSize = 314159, + Payload = CreateZerosPayload(271828) + }; var response = client.UnaryCall(request); @@ -208,7 +207,7 @@ namespace Grpc.IntegrationTesting { Console.WriteLine("running client_streaming"); - var bodySizes = new List { 27182, 8, 1828, 45904 }.ConvertAll((size) => StreamingInputCallRequest.CreateBuilder().SetPayload(CreateZerosPayload(size)).Build()); + var bodySizes = new List { 27182, 8, 1828, 45904 }.ConvertAll((size) => new StreamingInputCallRequest { Payload = CreateZerosPayload(size) }); using (var call = client.StreamingInputCall()) { @@ -226,11 +225,11 @@ namespace Grpc.IntegrationTesting var bodySizes = new List { 31415, 9, 2653, 58979 }; - var request = StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddRangeResponseParameters(bodySizes.ConvertAll( - (size) => ResponseParameters.CreateBuilder().SetSize(size).Build())) - .Build(); + var request = new StreamingOutputCallRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseParameters = { bodySizes.ConvertAll((size) => new ResponseParameters { Size = size }) } + }; using (var call = client.StreamingOutputCall(request)) { @@ -250,37 +249,45 @@ namespace Grpc.IntegrationTesting using (var call = client.FullDuplexCall()) { - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415)) - .SetPayload(CreateZerosPayload(27182)).Build()); + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseParameters = { new ResponseParameters { Size = 31415 } }, + Payload = CreateZerosPayload(27182) + }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); Assert.AreEqual(31415, call.ResponseStream.Current.Payload.Body.Length); - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(9)) - .SetPayload(CreateZerosPayload(8)).Build()); + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseParameters = { new ResponseParameters { Size = 9 } }, + Payload = CreateZerosPayload(8) + }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); Assert.AreEqual(9, call.ResponseStream.Current.Payload.Body.Length); - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(2653)) - .SetPayload(CreateZerosPayload(1828)).Build()); + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseParameters = { new ResponseParameters { Size = 2653 } }, + Payload = CreateZerosPayload(1828) + }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); Assert.AreEqual(2653, call.ResponseStream.Current.Payload.Body.Length); - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(58979)) - .SetPayload(CreateZerosPayload(45904)).Build()); + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseParameters = { new ResponseParameters { Size = 58979 } }, + Payload = CreateZerosPayload(45904) + }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); @@ -313,13 +320,14 @@ namespace Grpc.IntegrationTesting credential = credential.CreateScoped(new[] { AuthScope }); client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); - var request = SimpleRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .SetResponseSize(314159) - .SetPayload(CreateZerosPayload(271828)) - .SetFillUsername(true) - .SetFillOauthScope(true) - .Build(); + var request = new SimpleRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseSize = 314159, + Payload = CreateZerosPayload(271828), + FillUsername = true, + FillOauthScope = true + }; var response = client.UnaryCall(request); @@ -337,13 +345,14 @@ namespace Grpc.IntegrationTesting Assert.IsFalse(credential.IsCreateScopedRequired); client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); - var request = SimpleRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .SetResponseSize(314159) - .SetPayload(CreateZerosPayload(271828)) - .SetFillUsername(true) - .SetFillOauthScope(true) - .Build(); + var request = new SimpleRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseSize = 314159, + Payload = CreateZerosPayload(271828), + FillUsername = true, + FillOauthScope = true + }; var response = client.UnaryCall(request); @@ -362,13 +371,14 @@ namespace Grpc.IntegrationTesting Assert.IsTrue(credential.IsCreateScopedRequired); client.HeaderInterceptor = AuthInterceptors.FromCredential(credential); - var request = SimpleRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .SetResponseSize(314159) - .SetPayload(CreateZerosPayload(271828)) - .SetFillUsername(true) - .SetFillOauthScope(true) - .Build(); + var request = new SimpleRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseSize = 314159, + Payload = CreateZerosPayload(271828), + FillUsername = true, + FillOauthScope = true + }; var response = client.UnaryCall(request); @@ -386,10 +396,11 @@ namespace Grpc.IntegrationTesting client.HeaderInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); - var request = SimpleRequest.CreateBuilder() - .SetFillUsername(true) - .SetFillOauthScope(true) - .Build(); + var request = new SimpleRequest + { + FillUsername = true, + FillOauthScope = true + }; var response = client.UnaryCall(request); @@ -406,10 +417,11 @@ namespace Grpc.IntegrationTesting string oauth2Token = await credential.GetAccessTokenForRequestAsync(); var headerInterceptor = AuthInterceptors.FromAccessToken(oauth2Token); - var request = SimpleRequest.CreateBuilder() - .SetFillUsername(true) - .SetFillOauthScope(true) - .Build(); + var request = new SimpleRequest + { + FillUsername = true, + FillOauthScope = true + }; var headers = new Metadata(); headerInterceptor(null, "", headers); @@ -444,10 +456,12 @@ namespace Grpc.IntegrationTesting var cts = new CancellationTokenSource(); using (var call = client.FullDuplexCall(cancellationToken: cts.Token)) { - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetResponseType(PayloadType.COMPRESSABLE) - .AddResponseParameters(ResponseParameters.CreateBuilder().SetSize(31415)) - .SetPayload(CreateZerosPayload(27182)).Build()); + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest + { + ResponseType = PayloadType.COMPRESSABLE, + ResponseParameters = { new ResponseParameters { Size = 31415 } }, + Payload = CreateZerosPayload(27182) + }); Assert.IsTrue(await call.ResponseStream.MoveNext()); Assert.AreEqual(PayloadType.COMPRESSABLE, call.ResponseStream.Current.Payload.Type); @@ -470,8 +484,7 @@ namespace Grpc.IntegrationTesting { try { - await call.RequestStream.WriteAsync(StreamingOutputCallRequest.CreateBuilder() - .SetPayload(CreateZerosPayload(27182)).Build()); + await call.RequestStream.WriteAsync(new StreamingOutputCallRequest { Payload = CreateZerosPayload(27182) }); } catch (InvalidOperationException) { @@ -488,12 +501,12 @@ namespace Grpc.IntegrationTesting public static void RunBenchmarkEmptyUnary(TestService.ITestServiceClient client) { BenchmarkUtil.RunBenchmark(10000, 10000, - () => { client.EmptyCall(Empty.DefaultInstance); }); + () => { client.EmptyCall(new Empty()); }); } private static Payload CreateZerosPayload(int size) { - return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build(); + return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; } private static ClientOptions ParseArguments(string[] args) diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs index f3158aeb453..7bc17a207f9 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs @@ -36,9 +36,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; -using grpc.testing; using Grpc.Core; using Grpc.Core.Utils; +using Grpc.Testing; using NUnit.Framework; namespace Grpc.IntegrationTesting diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs index 0cc8b2cde1d..718278f30a6 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs @@ -37,10 +37,9 @@ using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; using System.Threading.Tasks; -using Google.ProtocolBuffers; -using grpc.testing; using Grpc.Core; using Grpc.Core.Utils; +using Grpc.Testing; using NUnit.Framework; namespace Grpc.IntegrationTesting diff --git a/src/csharp/Grpc.IntegrationTesting/Messages.cs b/src/csharp/Grpc.IntegrationTesting/Messages.cs index 386f377f08b..a3cbb7d76eb 100644 --- a/src/csharp/Grpc.IntegrationTesting/Messages.cs +++ b/src/csharp/Grpc.IntegrationTesting/Messages.cs @@ -1,106 +1,58 @@ -// Generated by ProtoGen, Version=2.4.1.521, Culture=neutral, PublicKeyToken=17b3b1f090c3ea48. DO NOT EDIT! +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: messages.proto #pragma warning disable 1591, 0612, 3021 #region Designer generated code -using pb = global::Google.ProtocolBuffers; -using pbc = global::Google.ProtocolBuffers.Collections; -using pbd = global::Google.ProtocolBuffers.Descriptors; +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; using scg = global::System.Collections.Generic; -namespace grpc.testing { +namespace Grpc.Testing { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Messages { - #region Extension registration - public static void RegisterAllExtensions(pb::ExtensionRegistry registry) { - } - #endregion - #region Static variables - internal static pbd::MessageDescriptor internal__static_grpc_testing_Payload__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_Payload__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_grpc_testing_SimpleRequest__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_SimpleRequest__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_grpc_testing_SimpleResponse__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_SimpleResponse__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_grpc_testing_StreamingInputCallRequest__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_StreamingInputCallRequest__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_grpc_testing_StreamingInputCallResponse__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_StreamingInputCallResponse__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_grpc_testing_ResponseParameters__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_ResponseParameters__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_grpc_testing_StreamingOutputCallRequest__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_StreamingOutputCallRequest__FieldAccessorTable; - internal static pbd::MessageDescriptor internal__static_grpc_testing_StreamingOutputCallResponse__Descriptor; - internal static pb::FieldAccess.FieldAccessorTable internal__static_grpc_testing_StreamingOutputCallResponse__FieldAccessorTable; - #endregion #region Descriptor - public static pbd::FileDescriptor Descriptor { + public static pbr::FileDescriptor Descriptor { get { return descriptor; } } - private static pbd::FileDescriptor descriptor; + private static pbr::FileDescriptor descriptor; static Messages() { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( - "Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE", - "dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5", - "GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB", - "KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6", - "ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv", - "YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl", - "GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n", - "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0", - "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK", - "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl", - "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf", - "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo", - "BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs", - "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu", - "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu", - "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg", - "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0", - "Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu", - "UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V", - "TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRAC")); - pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) { - descriptor = root; - internal__static_grpc_testing_Payload__Descriptor = Descriptor.MessageTypes[0]; - internal__static_grpc_testing_Payload__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_Payload__Descriptor, - new string[] { "Type", "Body", }); - internal__static_grpc_testing_SimpleRequest__Descriptor = Descriptor.MessageTypes[1]; - internal__static_grpc_testing_SimpleRequest__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_SimpleRequest__Descriptor, - new string[] { "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope", }); - internal__static_grpc_testing_SimpleResponse__Descriptor = Descriptor.MessageTypes[2]; - internal__static_grpc_testing_SimpleResponse__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_SimpleResponse__Descriptor, - new string[] { "Payload", "Username", "OauthScope", }); - internal__static_grpc_testing_StreamingInputCallRequest__Descriptor = Descriptor.MessageTypes[3]; - internal__static_grpc_testing_StreamingInputCallRequest__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_StreamingInputCallRequest__Descriptor, - new string[] { "Payload", }); - internal__static_grpc_testing_StreamingInputCallResponse__Descriptor = Descriptor.MessageTypes[4]; - internal__static_grpc_testing_StreamingInputCallResponse__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_StreamingInputCallResponse__Descriptor, - new string[] { "AggregatedPayloadSize", }); - internal__static_grpc_testing_ResponseParameters__Descriptor = Descriptor.MessageTypes[5]; - internal__static_grpc_testing_ResponseParameters__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_ResponseParameters__Descriptor, - new string[] { "Size", "IntervalUs", }); - internal__static_grpc_testing_StreamingOutputCallRequest__Descriptor = Descriptor.MessageTypes[6]; - internal__static_grpc_testing_StreamingOutputCallRequest__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_StreamingOutputCallRequest__Descriptor, - new string[] { "ResponseType", "ResponseParameters", "Payload", }); - internal__static_grpc_testing_StreamingOutputCallResponse__Descriptor = Descriptor.MessageTypes[7]; - internal__static_grpc_testing_StreamingOutputCallResponse__FieldAccessorTable = - new pb::FieldAccess.FieldAccessorTable(internal__static_grpc_testing_StreamingOutputCallResponse__Descriptor, - new string[] { "Payload", }); - return null; - }; - pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, - new pbd::FileDescriptor[] { - }, assigner); + "Cg5tZXNzYWdlcy5wcm90bxIMZ3JwYy50ZXN0aW5nIkAKB1BheWxvYWQSJwoE", + "dHlwZRgBIAEoDjIZLmdycGMudGVzdGluZy5QYXlsb2FkVHlwZRIMCgRib2R5", + "GAIgASgMIrEBCg1TaW1wbGVSZXF1ZXN0EjAKDXJlc3BvbnNlX3R5cGUYASAB", + "KA4yGS5ncnBjLnRlc3RpbmcuUGF5bG9hZFR5cGUSFQoNcmVzcG9uc2Vfc2l6", + "ZRgCIAEoBRImCgdwYXlsb2FkGAMgASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxv", + "YWQSFQoNZmlsbF91c2VybmFtZRgEIAEoCBIYChBmaWxsX29hdXRoX3Njb3Bl", + "GAUgASgIIl8KDlNpbXBsZVJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5n", + "cnBjLnRlc3RpbmcuUGF5bG9hZBIQCgh1c2VybmFtZRgCIAEoCRITCgtvYXV0", + "aF9zY29wZRgDIAEoCSJDChlTdHJlYW1pbmdJbnB1dENhbGxSZXF1ZXN0EiYK", + "B3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3RpbmcuUGF5bG9hZCI9ChpTdHJl", + "YW1pbmdJbnB1dENhbGxSZXNwb25zZRIfChdhZ2dyZWdhdGVkX3BheWxvYWRf", + "c2l6ZRgBIAEoBSI3ChJSZXNwb25zZVBhcmFtZXRlcnMSDAoEc2l6ZRgBIAEo", + "BRITCgtpbnRlcnZhbF91cxgCIAEoBSK1AQoaU3RyZWFtaW5nT3V0cHV0Q2Fs", + "bFJlcXVlc3QSMAoNcmVzcG9uc2VfdHlwZRgBIAEoDjIZLmdycGMudGVzdGlu", + "Zy5QYXlsb2FkVHlwZRI9ChNyZXNwb25zZV9wYXJhbWV0ZXJzGAIgAygLMiAu", + "Z3JwYy50ZXN0aW5nLlJlc3BvbnNlUGFyYW1ldGVycxImCgdwYXlsb2FkGAMg", + "ASgLMhUuZ3JwYy50ZXN0aW5nLlBheWxvYWQiRQobU3RyZWFtaW5nT3V0cHV0", + "Q2FsbFJlc3BvbnNlEiYKB3BheWxvYWQYASABKAsyFS5ncnBjLnRlc3Rpbmcu", + "UGF5bG9hZCo/CgtQYXlsb2FkVHlwZRIQCgxDT01QUkVTU0FCTEUQABISCg5V", + "TkNPTVBSRVNTQUJMRRABEgoKBlJBTkRPTRACYgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedCodeInfo(new[] {typeof(global::Grpc.Testing.PayloadType), }, new pbr::GeneratedCodeInfo[] { + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.Payload), new[]{ "Type", "Body" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleRequest), new[]{ "ResponseType", "ResponseSize", "Payload", "FillUsername", "FillOauthScope" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.SimpleResponse), new[]{ "Payload", "Username", "OauthScope" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallRequest), new[]{ "Payload" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingInputCallResponse), new[]{ "AggregatedPayloadSize" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.ResponseParameters), new[]{ "Size", "IntervalUs" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallRequest), new[]{ "ResponseType", "ResponseParameters", "Payload" }, null, null, null), + new pbr::GeneratedCodeInfo(typeof(global::Grpc.Testing.StreamingOutputCallResponse), new[]{ "Payload" }, null, null, null) + })); } #endregion @@ -116,2772 +68,1101 @@ namespace grpc.testing { #region Messages [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Payload : pb::GeneratedMessage { - private Payload() { } - private static readonly Payload defaultInstance = new Payload().MakeReadOnly(); - private static readonly string[] _payloadFieldNames = new string[] { "body", "type" }; - private static readonly uint[] _payloadFieldTags = new uint[] { 18, 8 }; - public static Payload DefaultInstance { - get { return defaultInstance; } + public sealed partial class Payload : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Payload()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[0]; } } - public override Payload DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override Payload ThisMessage { - get { return this; } + public Payload() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_Payload__Descriptor; } + partial void OnConstruction(); + + public Payload(Payload other) : this() { + type_ = other.type_; + body_ = other.body_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_Payload__FieldAccessorTable; } + public Payload Clone() { + return new Payload(this); } public const int TypeFieldNumber = 1; - private bool hasType; - private global::grpc.testing.PayloadType type_ = global::grpc.testing.PayloadType.COMPRESSABLE; - public bool HasType { - get { return hasType; } - } - public global::grpc.testing.PayloadType Type { + private global::Grpc.Testing.PayloadType type_ = global::Grpc.Testing.PayloadType.COMPRESSABLE; + public global::Grpc.Testing.PayloadType Type { get { return type_; } + set { + type_ = value; + } } public const int BodyFieldNumber = 2; - private bool hasBody; private pb::ByteString body_ = pb::ByteString.Empty; - public bool HasBody { - get { return hasBody; } - } public pb::ByteString Body { get { return body_; } - } - - public override bool IsInitialized { - get { - return true; + set { + body_ = pb::Preconditions.CheckNotNull(value, "value"); } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _payloadFieldNames; - if (hasType) { - output.WriteEnum(1, field_names[1], (int) Type, Type); - } - if (hasBody) { - output.WriteBytes(2, field_names[0], Body); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as Payload); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasType) { - size += pb::CodedOutputStream.ComputeEnumSize(1, (int) Type); - } - if (hasBody) { - size += pb::CodedOutputStream.ComputeBytesSize(2, Body); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(Payload other) { + if (ReferenceEquals(other, null)) { + return false; } + if (ReferenceEquals(other, this)) { + return true; + } + if (Type != other.Type) return false; + if (Body != other.Body) return false; + return true; } - public static Payload ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static Payload ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static Payload ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static Payload ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static Payload ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static Payload ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static Payload ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static Payload ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static Payload ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static Payload ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private Payload MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= Type.GetHashCode(); + if (Body.Length != 0) hash ^= Body.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(Payload prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(Payload cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private Payload result; - - private Payload PrepareBuilder() { - if (resultIsReadOnly) { - Payload original = result; - result = new Payload(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } + public void WriteTo(pb::CodedOutputStream output) { + if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + output.WriteRawTag(8); + output.WriteEnum((int) Type); } - - protected override Payload MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; + if (Body.Length != 0) { + output.WriteRawTag(18); + output.WriteBytes(Body); } + } - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } + public int CalculateSize() { + int size = 0; + if (Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.Payload.Descriptor; } + if (Body.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeBytesSize(Body); } + return size; + } - public override Payload DefaultInstanceForType { - get { return global::grpc.testing.Payload.DefaultInstance; } + public void MergeFrom(Payload other) { + if (other == null) { + return; } - - public override Payload BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + if (other.Type != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + Type = other.Type; } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is Payload) { - return MergeFrom((Payload) other); - } else { - base.MergeFrom(other); - return this; - } + if (other.Body.Length != 0) { + Body = other.Body; } + } - public override Builder MergeFrom(Payload other) { - if (other == global::grpc.testing.Payload.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasType) { - Type = other.Type; - } - if (other.HasBody) { - Body = other.Body; - } - this.MergeUnknownFields(other.UnknownFields); - return this; - } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); - } - - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_payloadFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _payloadFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + type_ = (global::Grpc.Testing.PayloadType) input.ReadEnum(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - object unknown; - if(input.ReadEnum(ref result.type_, out unknown)) { - result.hasType = true; - } else if(unknown is int) { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - unknownFields.MergeVarintField(1, (ulong)(int)unknown); - } - break; - } - case 18: { - result.hasBody = input.ReadBytes(ref result.body_); - break; - } + case 18: { + Body = input.ReadBytes(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasType { - get { return result.hasType; } - } - public global::grpc.testing.PayloadType Type { - get { return result.Type; } - set { SetType(value); } - } - public Builder SetType(global::grpc.testing.PayloadType value) { - PrepareBuilder(); - result.hasType = true; - result.type_ = value; - return this; - } - public Builder ClearType() { - PrepareBuilder(); - result.hasType = false; - result.type_ = global::grpc.testing.PayloadType.COMPRESSABLE; - return this; - } - - public bool HasBody { - get { return result.hasBody; } - } - public pb::ByteString Body { - get { return result.Body; } - set { SetBody(value); } - } - public Builder SetBody(pb::ByteString value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasBody = true; - result.body_ = value; - return this; - } - public Builder ClearBody() { - PrepareBuilder(); - result.hasBody = false; - result.body_ = pb::ByteString.Empty; - return this; } } - static Payload() { - object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null); - } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class SimpleRequest : pb::GeneratedMessage { - private SimpleRequest() { } - private static readonly SimpleRequest defaultInstance = new SimpleRequest().MakeReadOnly(); - private static readonly string[] _simpleRequestFieldNames = new string[] { "fill_oauth_scope", "fill_username", "payload", "response_size", "response_type" }; - private static readonly uint[] _simpleRequestFieldTags = new uint[] { 40, 32, 26, 16, 8 }; - public static SimpleRequest DefaultInstance { - get { return defaultInstance; } + public sealed partial class SimpleRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SimpleRequest()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[1]; } } - public override SimpleRequest DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override SimpleRequest ThisMessage { - get { return this; } + public SimpleRequest() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_SimpleRequest__Descriptor; } + partial void OnConstruction(); + + public SimpleRequest(SimpleRequest other) : this() { + responseType_ = other.responseType_; + responseSize_ = other.responseSize_; + Payload = other.payload_ != null ? other.Payload.Clone() : null; + fillUsername_ = other.fillUsername_; + fillOauthScope_ = other.fillOauthScope_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_SimpleRequest__FieldAccessorTable; } + public SimpleRequest Clone() { + return new SimpleRequest(this); } public const int ResponseTypeFieldNumber = 1; - private bool hasResponseType; - private global::grpc.testing.PayloadType responseType_ = global::grpc.testing.PayloadType.COMPRESSABLE; - public bool HasResponseType { - get { return hasResponseType; } - } - public global::grpc.testing.PayloadType ResponseType { + private global::Grpc.Testing.PayloadType responseType_ = global::Grpc.Testing.PayloadType.COMPRESSABLE; + public global::Grpc.Testing.PayloadType ResponseType { get { return responseType_; } + set { + responseType_ = value; + } } public const int ResponseSizeFieldNumber = 2; - private bool hasResponseSize; private int responseSize_; - public bool HasResponseSize { - get { return hasResponseSize; } - } public int ResponseSize { get { return responseSize_; } + set { + responseSize_ = value; + } } public const int PayloadFieldNumber = 3; - private bool hasPayload; - private global::grpc.testing.Payload payload_; - public bool HasPayload { - get { return hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; } + private global::Grpc.Testing.Payload payload_; + public global::Grpc.Testing.Payload Payload { + get { return payload_; } + set { + payload_ = value; + } } public const int FillUsernameFieldNumber = 4; - private bool hasFillUsername; private bool fillUsername_; - public bool HasFillUsername { - get { return hasFillUsername; } - } public bool FillUsername { get { return fillUsername_; } + set { + fillUsername_ = value; + } } public const int FillOauthScopeFieldNumber = 5; - private bool hasFillOauthScope; private bool fillOauthScope_; - public bool HasFillOauthScope { - get { return hasFillOauthScope; } - } public bool FillOauthScope { get { return fillOauthScope_; } - } - - public override bool IsInitialized { - get { - return true; + set { + fillOauthScope_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _simpleRequestFieldNames; - if (hasResponseType) { - output.WriteEnum(1, field_names[4], (int) ResponseType, ResponseType); - } - if (hasResponseSize) { - output.WriteInt32(2, field_names[3], ResponseSize); - } - if (hasPayload) { - output.WriteMessage(3, field_names[2], Payload); - } - if (hasFillUsername) { - output.WriteBool(4, field_names[1], FillUsername); - } - if (hasFillOauthScope) { - output.WriteBool(5, field_names[0], FillOauthScope); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as SimpleRequest); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasResponseType) { - size += pb::CodedOutputStream.ComputeEnumSize(1, (int) ResponseType); - } - if (hasResponseSize) { - size += pb::CodedOutputStream.ComputeInt32Size(2, ResponseSize); - } - if (hasPayload) { - size += pb::CodedOutputStream.ComputeMessageSize(3, Payload); - } - if (hasFillUsername) { - size += pb::CodedOutputStream.ComputeBoolSize(4, FillUsername); - } - if (hasFillOauthScope) { - size += pb::CodedOutputStream.ComputeBoolSize(5, FillOauthScope); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(SimpleRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; } + if (ResponseType != other.ResponseType) return false; + if (ResponseSize != other.ResponseSize) return false; + if (!object.Equals(Payload, other.Payload)) return false; + if (FillUsername != other.FillUsername) return false; + if (FillOauthScope != other.FillOauthScope) return false; + return true; } - public static SimpleRequest ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static SimpleRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static SimpleRequest ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static SimpleRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static SimpleRequest ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static SimpleRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static SimpleRequest ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static SimpleRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static SimpleRequest ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static SimpleRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private SimpleRequest MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode(); + if (ResponseSize != 0) hash ^= ResponseSize.GetHashCode(); + if (payload_ != null) hash ^= Payload.GetHashCode(); + if (FillUsername != false) hash ^= FillUsername.GetHashCode(); + if (FillOauthScope != false) hash ^= FillOauthScope.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(SimpleRequest prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } + public void WriteTo(pb::CodedOutputStream output) { + if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + output.WriteRawTag(8); + output.WriteEnum((int) ResponseType); } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; + if (ResponseSize != 0) { + output.WriteRawTag(16); + output.WriteInt32(ResponseSize); } - internal Builder(SimpleRequest cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; + if (payload_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Payload); } - - private bool resultIsReadOnly; - private SimpleRequest result; - - private SimpleRequest PrepareBuilder() { - if (resultIsReadOnly) { - SimpleRequest original = result; - result = new SimpleRequest(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; + if (FillUsername != false) { + output.WriteRawTag(32); + output.WriteBool(FillUsername); } - - public override bool IsInitialized { - get { return result.IsInitialized; } + if (FillOauthScope != false) { + output.WriteRawTag(40); + output.WriteBool(FillOauthScope); } + } - protected override SimpleRequest MessageBeingBuilt { - get { return PrepareBuilder(); } + public int CalculateSize() { + int size = 0; + if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseType); } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; + if (ResponseSize != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(ResponseSize); } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } + if (payload_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.SimpleRequest.Descriptor; } + if (FillUsername != false) { + size += 1 + 1; } - - public override SimpleRequest DefaultInstanceForType { - get { return global::grpc.testing.SimpleRequest.DefaultInstance; } + if (FillOauthScope != false) { + size += 1 + 1; } + return size; + } - public override SimpleRequest BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + public void MergeFrom(SimpleRequest other) { + if (other == null) { + return; } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is SimpleRequest) { - return MergeFrom((SimpleRequest) other); - } else { - base.MergeFrom(other); - return this; + if (other.ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + ResponseType = other.ResponseType; + } + if (other.ResponseSize != 0) { + ResponseSize = other.ResponseSize; + } + if (other.payload_ != null) { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); } + Payload.MergeFrom(other.Payload); + } + if (other.FillUsername != false) { + FillUsername = other.FillUsername; + } + if (other.FillOauthScope != false) { + FillOauthScope = other.FillOauthScope; } + } - public override Builder MergeFrom(SimpleRequest other) { - if (other == global::grpc.testing.SimpleRequest.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasResponseType) { - ResponseType = other.ResponseType; - } - if (other.HasResponseSize) { - ResponseSize = other.ResponseSize; - } - if (other.HasPayload) { - MergePayload(other.Payload); - } - if (other.HasFillUsername) { - FillUsername = other.FillUsername; - } - if (other.HasFillOauthScope) { - FillOauthScope = other.FillOauthScope; - } - this.MergeUnknownFields(other.UnknownFields); - return this; - } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); - } - - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_simpleRequestFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _simpleRequestFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + responseType_ = (global::Grpc.Testing.PayloadType) input.ReadEnum(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - object unknown; - if(input.ReadEnum(ref result.responseType_, out unknown)) { - result.hasResponseType = true; - } else if(unknown is int) { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - unknownFields.MergeVarintField(1, (ulong)(int)unknown); - } - break; - } - case 16: { - result.hasResponseSize = input.ReadInt32(ref result.responseSize_); - break; - } - case 26: { - global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder(); - if (result.hasPayload) { - subBuilder.MergeFrom(Payload); - } - input.ReadMessage(subBuilder, extensionRegistry); - Payload = subBuilder.BuildPartial(); - break; - } - case 32: { - result.hasFillUsername = input.ReadBool(ref result.fillUsername_); - break; - } - case 40: { - result.hasFillOauthScope = input.ReadBool(ref result.fillOauthScope_); - break; + case 16: { + ResponseSize = input.ReadInt32(); + break; + } + case 26: { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); } + input.ReadMessage(payload_); + break; + } + case 32: { + FillUsername = input.ReadBool(); + break; + } + case 40: { + FillOauthScope = input.ReadBool(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasResponseType { - get { return result.hasResponseType; } - } - public global::grpc.testing.PayloadType ResponseType { - get { return result.ResponseType; } - set { SetResponseType(value); } - } - public Builder SetResponseType(global::grpc.testing.PayloadType value) { - PrepareBuilder(); - result.hasResponseType = true; - result.responseType_ = value; - return this; - } - public Builder ClearResponseType() { - PrepareBuilder(); - result.hasResponseType = false; - result.responseType_ = global::grpc.testing.PayloadType.COMPRESSABLE; - return this; - } - - public bool HasResponseSize { - get { return result.hasResponseSize; } - } - public int ResponseSize { - get { return result.ResponseSize; } - set { SetResponseSize(value); } - } - public Builder SetResponseSize(int value) { - PrepareBuilder(); - result.hasResponseSize = true; - result.responseSize_ = value; - return this; - } - public Builder ClearResponseSize() { - PrepareBuilder(); - result.hasResponseSize = false; - result.responseSize_ = 0; - return this; - } - - public bool HasPayload { - get { return result.hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return result.Payload; } - set { SetPayload(value); } - } - public Builder SetPayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = value; - return this; - } - public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) { - pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = builderForValue.Build(); - return this; - } - public Builder MergePayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - if (result.hasPayload && - result.payload_ != global::grpc.testing.Payload.DefaultInstance) { - result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial(); - } else { - result.payload_ = value; - } - result.hasPayload = true; - return this; - } - public Builder ClearPayload() { - PrepareBuilder(); - result.hasPayload = false; - result.payload_ = null; - return this; - } - - public bool HasFillUsername { - get { return result.hasFillUsername; } - } - public bool FillUsername { - get { return result.FillUsername; } - set { SetFillUsername(value); } - } - public Builder SetFillUsername(bool value) { - PrepareBuilder(); - result.hasFillUsername = true; - result.fillUsername_ = value; - return this; - } - public Builder ClearFillUsername() { - PrepareBuilder(); - result.hasFillUsername = false; - result.fillUsername_ = false; - return this; - } - - public bool HasFillOauthScope { - get { return result.hasFillOauthScope; } - } - public bool FillOauthScope { - get { return result.FillOauthScope; } - set { SetFillOauthScope(value); } - } - public Builder SetFillOauthScope(bool value) { - PrepareBuilder(); - result.hasFillOauthScope = true; - result.fillOauthScope_ = value; - return this; - } - public Builder ClearFillOauthScope() { - PrepareBuilder(); - result.hasFillOauthScope = false; - result.fillOauthScope_ = false; - return this; } } - static SimpleRequest() { - object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null); - } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class SimpleResponse : pb::GeneratedMessage { - private SimpleResponse() { } - private static readonly SimpleResponse defaultInstance = new SimpleResponse().MakeReadOnly(); - private static readonly string[] _simpleResponseFieldNames = new string[] { "oauth_scope", "payload", "username" }; - private static readonly uint[] _simpleResponseFieldTags = new uint[] { 26, 10, 18 }; - public static SimpleResponse DefaultInstance { - get { return defaultInstance; } + public sealed partial class SimpleResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new SimpleResponse()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[2]; } } - public override SimpleResponse DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override SimpleResponse ThisMessage { - get { return this; } + public SimpleResponse() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_SimpleResponse__Descriptor; } + partial void OnConstruction(); + + public SimpleResponse(SimpleResponse other) : this() { + Payload = other.payload_ != null ? other.Payload.Clone() : null; + username_ = other.username_; + oauthScope_ = other.oauthScope_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_SimpleResponse__FieldAccessorTable; } + public SimpleResponse Clone() { + return new SimpleResponse(this); } public const int PayloadFieldNumber = 1; - private bool hasPayload; - private global::grpc.testing.Payload payload_; - public bool HasPayload { - get { return hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; } + private global::Grpc.Testing.Payload payload_; + public global::Grpc.Testing.Payload Payload { + get { return payload_; } + set { + payload_ = value; + } } public const int UsernameFieldNumber = 2; - private bool hasUsername; private string username_ = ""; - public bool HasUsername { - get { return hasUsername; } - } public string Username { get { return username_; } + set { + username_ = pb::Preconditions.CheckNotNull(value, "value"); + } } public const int OauthScopeFieldNumber = 3; - private bool hasOauthScope; private string oauthScope_ = ""; - public bool HasOauthScope { - get { return hasOauthScope; } - } public string OauthScope { get { return oauthScope_; } - } - - public override bool IsInitialized { - get { - return true; + set { + oauthScope_ = pb::Preconditions.CheckNotNull(value, "value"); } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _simpleResponseFieldNames; - if (hasPayload) { - output.WriteMessage(1, field_names[1], Payload); - } - if (hasUsername) { - output.WriteString(2, field_names[2], Username); - } - if (hasOauthScope) { - output.WriteString(3, field_names[0], OauthScope); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as SimpleResponse); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasPayload) { - size += pb::CodedOutputStream.ComputeMessageSize(1, Payload); - } - if (hasUsername) { - size += pb::CodedOutputStream.ComputeStringSize(2, Username); - } - if (hasOauthScope) { - size += pb::CodedOutputStream.ComputeStringSize(3, OauthScope); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(SimpleResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; } + if (!object.Equals(Payload, other.Payload)) return false; + if (Username != other.Username) return false; + if (OauthScope != other.OauthScope) return false; + return true; } - public static SimpleResponse ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static SimpleResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static SimpleResponse ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static SimpleResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static SimpleResponse ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static SimpleResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static SimpleResponse ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static SimpleResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static SimpleResponse ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static SimpleResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private SimpleResponse MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (payload_ != null) hash ^= Payload.GetHashCode(); + if (Username.Length != 0) hash ^= Username.GetHashCode(); + if (OauthScope.Length != 0) hash ^= OauthScope.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(SimpleResponse prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } + public void WriteTo(pb::CodedOutputStream output) { + if (payload_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Payload); } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; + if (Username.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Username); } - internal Builder(SimpleResponse cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; + if (OauthScope.Length != 0) { + output.WriteRawTag(26); + output.WriteString(OauthScope); } + } - private bool resultIsReadOnly; - private SimpleResponse result; - - private SimpleResponse PrepareBuilder() { - if (resultIsReadOnly) { - SimpleResponse original = result; - result = new SimpleResponse(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; + public int CalculateSize() { + int size = 0; + if (payload_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } - - public override bool IsInitialized { - get { return result.IsInitialized; } + if (Username.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Username); } - - protected override SimpleResponse MessageBeingBuilt { - get { return PrepareBuilder(); } + if (OauthScope.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(OauthScope); } + return size; + } - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; + public void MergeFrom(SimpleResponse other) { + if (other == null) { + return; } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); + if (other.payload_ != null) { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); } + Payload.MergeFrom(other.Payload); } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.SimpleResponse.Descriptor; } - } - - public override SimpleResponse DefaultInstanceForType { - get { return global::grpc.testing.SimpleResponse.DefaultInstance; } - } - - public override SimpleResponse BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + if (other.Username.Length != 0) { + Username = other.Username; } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is SimpleResponse) { - return MergeFrom((SimpleResponse) other); - } else { - base.MergeFrom(other); - return this; - } + if (other.OauthScope.Length != 0) { + OauthScope = other.OauthScope; } + } - public override Builder MergeFrom(SimpleResponse other) { - if (other == global::grpc.testing.SimpleResponse.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasPayload) { - MergePayload(other.Payload); - } - if (other.HasUsername) { - Username = other.Username; - } - if (other.HasOauthScope) { - OauthScope = other.OauthScope; - } - this.MergeUnknownFields(other.UnknownFields); - return this; - } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); - } - - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_simpleResponseFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _simpleResponseFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); } + input.ReadMessage(payload_); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 10: { - global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder(); - if (result.hasPayload) { - subBuilder.MergeFrom(Payload); - } - input.ReadMessage(subBuilder, extensionRegistry); - Payload = subBuilder.BuildPartial(); - break; - } - case 18: { - result.hasUsername = input.ReadString(ref result.username_); - break; - } - case 26: { - result.hasOauthScope = input.ReadString(ref result.oauthScope_); - break; - } + case 18: { + Username = input.ReadString(); + break; + } + case 26: { + OauthScope = input.ReadString(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasPayload { - get { return result.hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return result.Payload; } - set { SetPayload(value); } - } - public Builder SetPayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = value; - return this; - } - public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) { - pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = builderForValue.Build(); - return this; - } - public Builder MergePayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - if (result.hasPayload && - result.payload_ != global::grpc.testing.Payload.DefaultInstance) { - result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial(); - } else { - result.payload_ = value; - } - result.hasPayload = true; - return this; - } - public Builder ClearPayload() { - PrepareBuilder(); - result.hasPayload = false; - result.payload_ = null; - return this; - } - - public bool HasUsername { - get { return result.hasUsername; } - } - public string Username { - get { return result.Username; } - set { SetUsername(value); } - } - public Builder SetUsername(string value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasUsername = true; - result.username_ = value; - return this; - } - public Builder ClearUsername() { - PrepareBuilder(); - result.hasUsername = false; - result.username_ = ""; - return this; - } - - public bool HasOauthScope { - get { return result.hasOauthScope; } - } - public string OauthScope { - get { return result.OauthScope; } - set { SetOauthScope(value); } - } - public Builder SetOauthScope(string value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasOauthScope = true; - result.oauthScope_ = value; - return this; - } - public Builder ClearOauthScope() { - PrepareBuilder(); - result.hasOauthScope = false; - result.oauthScope_ = ""; - return this; } } - static SimpleResponse() { - object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null); - } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class StreamingInputCallRequest : pb::GeneratedMessage { - private StreamingInputCallRequest() { } - private static readonly StreamingInputCallRequest defaultInstance = new StreamingInputCallRequest().MakeReadOnly(); - private static readonly string[] _streamingInputCallRequestFieldNames = new string[] { "payload" }; - private static readonly uint[] _streamingInputCallRequestFieldTags = new uint[] { 10 }; - public static StreamingInputCallRequest DefaultInstance { - get { return defaultInstance; } + public sealed partial class StreamingInputCallRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamingInputCallRequest()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[3]; } } - public override StreamingInputCallRequest DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override StreamingInputCallRequest ThisMessage { - get { return this; } + public StreamingInputCallRequest() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingInputCallRequest__Descriptor; } + partial void OnConstruction(); + + public StreamingInputCallRequest(StreamingInputCallRequest other) : this() { + Payload = other.payload_ != null ? other.Payload.Clone() : null; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingInputCallRequest__FieldAccessorTable; } + public StreamingInputCallRequest Clone() { + return new StreamingInputCallRequest(this); } public const int PayloadFieldNumber = 1; - private bool hasPayload; - private global::grpc.testing.Payload payload_; - public bool HasPayload { - get { return hasPayload; } + private global::Grpc.Testing.Payload payload_; + public global::Grpc.Testing.Payload Payload { + get { return payload_; } + set { + payload_ = value; + } } - public global::grpc.testing.Payload Payload { - get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; } + + public override bool Equals(object other) { + return Equals(other as StreamingInputCallRequest); } - public override bool IsInitialized { - get { + public bool Equals(StreamingInputCallRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { return true; } + if (!object.Equals(Payload, other.Payload)) return false; + return true; } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _streamingInputCallRequestFieldNames; - if (hasPayload) { - output.WriteMessage(1, field_names[0], Payload); - } - UnknownFields.WriteTo(output); + public override int GetHashCode() { + int hash = 1; + if (payload_ != null) hash ^= Payload.GetHashCode(); + return hash; } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasPayload) { - size += pb::CodedOutputStream.ComputeMessageSize(1, Payload); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; - } + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - public static StreamingInputCallRequest ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static StreamingInputCallRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static StreamingInputCallRequest ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static StreamingInputCallRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static StreamingInputCallRequest ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static StreamingInputCallRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static StreamingInputCallRequest ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static StreamingInputCallRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static StreamingInputCallRequest ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static StreamingInputCallRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private StreamingInputCallRequest MakeReadOnly() { - return this; + public void WriteTo(pb::CodedOutputStream output) { + if (payload_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Payload); + } } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(StreamingInputCallRequest prototype) { - return new Builder(prototype); + public int CalculateSize() { + int size = 0; + if (payload_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); + } + return size; } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; + public void MergeFrom(StreamingInputCallRequest other) { + if (other == null) { + return; } - internal Builder(StreamingInputCallRequest cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; + if (other.payload_ != null) { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); + } + Payload.MergeFrom(other.Payload); } + } - private bool resultIsReadOnly; - private StreamingInputCallRequest result; - - private StreamingInputCallRequest PrepareBuilder() { - if (resultIsReadOnly) { - StreamingInputCallRequest original = result; - result = new StreamingInputCallRequest(); - resultIsReadOnly = false; - MergeFrom(original); + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); + } + input.ReadMessage(payload_); + break; + } } - return result; } + } - public override bool IsInitialized { - get { return result.IsInitialized; } - } + } - protected override StreamingInputCallRequest MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.StreamingInputCallRequest.Descriptor; } - } - - public override StreamingInputCallRequest DefaultInstanceForType { - get { return global::grpc.testing.StreamingInputCallRequest.DefaultInstance; } - } - - public override StreamingInputCallRequest BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); - } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is StreamingInputCallRequest) { - return MergeFrom((StreamingInputCallRequest) other); - } else { - base.MergeFrom(other); - return this; - } - } - - public override Builder MergeFrom(StreamingInputCallRequest other) { - if (other == global::grpc.testing.StreamingInputCallRequest.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasPayload) { - MergePayload(other.Payload); - } - this.MergeUnknownFields(other.UnknownFields); - return this; - } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); - } - - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_streamingInputCallRequestFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _streamingInputCallRequestFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } - } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 10: { - global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder(); - if (result.hasPayload) { - subBuilder.MergeFrom(Payload); - } - input.ReadMessage(subBuilder, extensionRegistry); - Payload = subBuilder.BuildPartial(); - break; - } - } - } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class StreamingInputCallResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamingInputCallResponse()); + public static pb::MessageParser Parser { get { return _parser; } } - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasPayload { - get { return result.hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return result.Payload; } - set { SetPayload(value); } - } - public Builder SetPayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = value; - return this; - } - public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) { - pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = builderForValue.Build(); - return this; - } - public Builder MergePayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - if (result.hasPayload && - result.payload_ != global::grpc.testing.Payload.DefaultInstance) { - result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial(); - } else { - result.payload_ = value; - } - result.hasPayload = true; - return this; - } - public Builder ClearPayload() { - PrepareBuilder(); - result.hasPayload = false; - result.payload_ = null; - return this; - } - } - static StreamingInputCallRequest() { - object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null); + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[4]; } } - } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class StreamingInputCallResponse : pb::GeneratedMessage { - private StreamingInputCallResponse() { } - private static readonly StreamingInputCallResponse defaultInstance = new StreamingInputCallResponse().MakeReadOnly(); - private static readonly string[] _streamingInputCallResponseFieldNames = new string[] { "aggregated_payload_size" }; - private static readonly uint[] _streamingInputCallResponseFieldTags = new uint[] { 8 }; - public static StreamingInputCallResponse DefaultInstance { - get { return defaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - public override StreamingInputCallResponse DefaultInstanceForType { - get { return DefaultInstance; } + public StreamingInputCallResponse() { + OnConstruction(); } - protected override StreamingInputCallResponse ThisMessage { - get { return this; } - } + partial void OnConstruction(); - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingInputCallResponse__Descriptor; } + public StreamingInputCallResponse(StreamingInputCallResponse other) : this() { + aggregatedPayloadSize_ = other.aggregatedPayloadSize_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingInputCallResponse__FieldAccessorTable; } + public StreamingInputCallResponse Clone() { + return new StreamingInputCallResponse(this); } public const int AggregatedPayloadSizeFieldNumber = 1; - private bool hasAggregatedPayloadSize; private int aggregatedPayloadSize_; - public bool HasAggregatedPayloadSize { - get { return hasAggregatedPayloadSize; } - } public int AggregatedPayloadSize { get { return aggregatedPayloadSize_; } - } - - public override bool IsInitialized { - get { - return true; + set { + aggregatedPayloadSize_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _streamingInputCallResponseFieldNames; - if (hasAggregatedPayloadSize) { - output.WriteInt32(1, field_names[0], AggregatedPayloadSize); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as StreamingInputCallResponse); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasAggregatedPayloadSize) { - size += pb::CodedOutputStream.ComputeInt32Size(1, AggregatedPayloadSize); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(StreamingInputCallResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; } + if (AggregatedPayloadSize != other.AggregatedPayloadSize) return false; + return true; } - public static StreamingInputCallResponse ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static StreamingInputCallResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static StreamingInputCallResponse ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static StreamingInputCallResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static StreamingInputCallResponse ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static StreamingInputCallResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static StreamingInputCallResponse ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static StreamingInputCallResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static StreamingInputCallResponse ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static StreamingInputCallResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private StreamingInputCallResponse MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (AggregatedPayloadSize != 0) hash ^= AggregatedPayloadSize.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(StreamingInputCallResponse prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(StreamingInputCallResponse cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private StreamingInputCallResponse result; - - private StreamingInputCallResponse PrepareBuilder() { - if (resultIsReadOnly) { - StreamingInputCallResponse original = result; - result = new StreamingInputCallResponse(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override StreamingInputCallResponse MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.StreamingInputCallResponse.Descriptor; } + public void WriteTo(pb::CodedOutputStream output) { + if (AggregatedPayloadSize != 0) { + output.WriteRawTag(8); + output.WriteInt32(AggregatedPayloadSize); } + } - public override StreamingInputCallResponse DefaultInstanceForType { - get { return global::grpc.testing.StreamingInputCallResponse.DefaultInstance; } + public int CalculateSize() { + int size = 0; + if (AggregatedPayloadSize != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(AggregatedPayloadSize); } + return size; + } - public override StreamingInputCallResponse BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + public void MergeFrom(StreamingInputCallResponse other) { + if (other == null) { + return; } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is StreamingInputCallResponse) { - return MergeFrom((StreamingInputCallResponse) other); - } else { - base.MergeFrom(other); - return this; - } + if (other.AggregatedPayloadSize != 0) { + AggregatedPayloadSize = other.AggregatedPayloadSize; } + } - public override Builder MergeFrom(StreamingInputCallResponse other) { - if (other == global::grpc.testing.StreamingInputCallResponse.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasAggregatedPayloadSize) { - AggregatedPayloadSize = other.AggregatedPayloadSize; - } - this.MergeUnknownFields(other.UnknownFields); - return this; - } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); - } - - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_streamingInputCallResponseFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _streamingInputCallResponseFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } - } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - result.hasAggregatedPayloadSize = input.ReadInt32(ref result.aggregatedPayloadSize_); - break; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + AggregatedPayloadSize = input.ReadInt32(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasAggregatedPayloadSize { - get { return result.hasAggregatedPayloadSize; } - } - public int AggregatedPayloadSize { - get { return result.AggregatedPayloadSize; } - set { SetAggregatedPayloadSize(value); } - } - public Builder SetAggregatedPayloadSize(int value) { - PrepareBuilder(); - result.hasAggregatedPayloadSize = true; - result.aggregatedPayloadSize_ = value; - return this; - } - public Builder ClearAggregatedPayloadSize() { - PrepareBuilder(); - result.hasAggregatedPayloadSize = false; - result.aggregatedPayloadSize_ = 0; - return this; } } - static StreamingInputCallResponse() { - object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null); - } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class ResponseParameters : pb::GeneratedMessage { - private ResponseParameters() { } - private static readonly ResponseParameters defaultInstance = new ResponseParameters().MakeReadOnly(); - private static readonly string[] _responseParametersFieldNames = new string[] { "interval_us", "size" }; - private static readonly uint[] _responseParametersFieldTags = new uint[] { 16, 8 }; - public static ResponseParameters DefaultInstance { - get { return defaultInstance; } + public sealed partial class ResponseParameters : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new ResponseParameters()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[5]; } } - public override ResponseParameters DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override ResponseParameters ThisMessage { - get { return this; } + public ResponseParameters() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_ResponseParameters__Descriptor; } + partial void OnConstruction(); + + public ResponseParameters(ResponseParameters other) : this() { + size_ = other.size_; + intervalUs_ = other.intervalUs_; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_ResponseParameters__FieldAccessorTable; } + public ResponseParameters Clone() { + return new ResponseParameters(this); } public const int SizeFieldNumber = 1; - private bool hasSize; private int size_; - public bool HasSize { - get { return hasSize; } - } public int Size { get { return size_; } + set { + size_ = value; + } } public const int IntervalUsFieldNumber = 2; - private bool hasIntervalUs; private int intervalUs_; - public bool HasIntervalUs { - get { return hasIntervalUs; } - } public int IntervalUs { get { return intervalUs_; } - } - - public override bool IsInitialized { - get { - return true; + set { + intervalUs_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _responseParametersFieldNames; - if (hasSize) { - output.WriteInt32(1, field_names[1], Size); - } - if (hasIntervalUs) { - output.WriteInt32(2, field_names[0], IntervalUs); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as ResponseParameters); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasSize) { - size += pb::CodedOutputStream.ComputeInt32Size(1, Size); - } - if (hasIntervalUs) { - size += pb::CodedOutputStream.ComputeInt32Size(2, IntervalUs); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(ResponseParameters other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; } + if (Size != other.Size) return false; + if (IntervalUs != other.IntervalUs) return false; + return true; } - public static ResponseParameters ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static ResponseParameters ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static ResponseParameters ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static ResponseParameters ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static ResponseParameters ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static ResponseParameters ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static ResponseParameters ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static ResponseParameters ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static ResponseParameters ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static ResponseParameters ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private ResponseParameters MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (Size != 0) hash ^= Size.GetHashCode(); + if (IntervalUs != 0) hash ^= IntervalUs.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(ResponseParameters prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(ResponseParameters cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private ResponseParameters result; - - private ResponseParameters PrepareBuilder() { - if (resultIsReadOnly) { - ResponseParameters original = result; - result = new ResponseParameters(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; + public void WriteTo(pb::CodedOutputStream output) { + if (Size != 0) { + output.WriteRawTag(8); + output.WriteInt32(Size); } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override ResponseParameters MessageBeingBuilt { - get { return PrepareBuilder(); } + if (IntervalUs != 0) { + output.WriteRawTag(16); + output.WriteInt32(IntervalUs); } + } - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; + public int CalculateSize() { + int size = 0; + if (Size != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(Size); } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.ResponseParameters.Descriptor; } + if (IntervalUs != 0) { + size += 1 + pb::CodedOutputStream.ComputeInt32Size(IntervalUs); } + return size; + } - public override ResponseParameters DefaultInstanceForType { - get { return global::grpc.testing.ResponseParameters.DefaultInstance; } + public void MergeFrom(ResponseParameters other) { + if (other == null) { + return; } - - public override ResponseParameters BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + if (other.Size != 0) { + Size = other.Size; } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is ResponseParameters) { - return MergeFrom((ResponseParameters) other); - } else { - base.MergeFrom(other); - return this; - } + if (other.IntervalUs != 0) { + IntervalUs = other.IntervalUs; } + } - public override Builder MergeFrom(ResponseParameters other) { - if (other == global::grpc.testing.ResponseParameters.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasSize) { - Size = other.Size; - } - if (other.HasIntervalUs) { - IntervalUs = other.IntervalUs; - } - this.MergeUnknownFields(other.UnknownFields); - return this; - } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); - } - - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_responseParametersFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _responseParametersFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + Size = input.ReadInt32(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - result.hasSize = input.ReadInt32(ref result.size_); - break; - } - case 16: { - result.hasIntervalUs = input.ReadInt32(ref result.intervalUs_); - break; - } + case 16: { + IntervalUs = input.ReadInt32(); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasSize { - get { return result.hasSize; } - } - public int Size { - get { return result.Size; } - set { SetSize(value); } - } - public Builder SetSize(int value) { - PrepareBuilder(); - result.hasSize = true; - result.size_ = value; - return this; - } - public Builder ClearSize() { - PrepareBuilder(); - result.hasSize = false; - result.size_ = 0; - return this; - } - - public bool HasIntervalUs { - get { return result.hasIntervalUs; } - } - public int IntervalUs { - get { return result.IntervalUs; } - set { SetIntervalUs(value); } - } - public Builder SetIntervalUs(int value) { - PrepareBuilder(); - result.hasIntervalUs = true; - result.intervalUs_ = value; - return this; } - public Builder ClearIntervalUs() { - PrepareBuilder(); - result.hasIntervalUs = false; - result.intervalUs_ = 0; - return this; - } - } - static ResponseParameters() { - object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null); } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class StreamingOutputCallRequest : pb::GeneratedMessage { - private StreamingOutputCallRequest() { } - private static readonly StreamingOutputCallRequest defaultInstance = new StreamingOutputCallRequest().MakeReadOnly(); - private static readonly string[] _streamingOutputCallRequestFieldNames = new string[] { "payload", "response_parameters", "response_type" }; - private static readonly uint[] _streamingOutputCallRequestFieldTags = new uint[] { 26, 18, 8 }; - public static StreamingOutputCallRequest DefaultInstance { - get { return defaultInstance; } + public sealed partial class StreamingOutputCallRequest : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamingOutputCallRequest()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[6]; } } - public override StreamingOutputCallRequest DefaultInstanceForType { - get { return DefaultInstance; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - protected override StreamingOutputCallRequest ThisMessage { - get { return this; } + public StreamingOutputCallRequest() { + OnConstruction(); } - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingOutputCallRequest__Descriptor; } + partial void OnConstruction(); + + public StreamingOutputCallRequest(StreamingOutputCallRequest other) : this() { + responseType_ = other.responseType_; + responseParameters_ = other.responseParameters_.Clone(); + Payload = other.payload_ != null ? other.Payload.Clone() : null; } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingOutputCallRequest__FieldAccessorTable; } + public StreamingOutputCallRequest Clone() { + return new StreamingOutputCallRequest(this); } public const int ResponseTypeFieldNumber = 1; - private bool hasResponseType; - private global::grpc.testing.PayloadType responseType_ = global::grpc.testing.PayloadType.COMPRESSABLE; - public bool HasResponseType { - get { return hasResponseType; } - } - public global::grpc.testing.PayloadType ResponseType { + private global::Grpc.Testing.PayloadType responseType_ = global::Grpc.Testing.PayloadType.COMPRESSABLE; + public global::Grpc.Testing.PayloadType ResponseType { get { return responseType_; } + set { + responseType_ = value; + } } public const int ResponseParametersFieldNumber = 2; - private pbc::PopsicleList responseParameters_ = new pbc::PopsicleList(); - public scg::IList ResponseParametersList { + private static readonly pb::FieldCodec _repeated_responseParameters_codec + = pb::FieldCodec.ForMessage(18, global::Grpc.Testing.ResponseParameters.Parser); + private readonly pbc::RepeatedField responseParameters_ = new pbc::RepeatedField(); + public pbc::RepeatedField ResponseParameters { get { return responseParameters_; } } - public int ResponseParametersCount { - get { return responseParameters_.Count; } - } - public global::grpc.testing.ResponseParameters GetResponseParameters(int index) { - return responseParameters_[index]; - } public const int PayloadFieldNumber = 3; - private bool hasPayload; - private global::grpc.testing.Payload payload_; - public bool HasPayload { - get { return hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; } - } - - public override bool IsInitialized { - get { - return true; + private global::Grpc.Testing.Payload payload_; + public global::Grpc.Testing.Payload Payload { + get { return payload_; } + set { + payload_ = value; } } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _streamingOutputCallRequestFieldNames; - if (hasResponseType) { - output.WriteEnum(1, field_names[2], (int) ResponseType, ResponseType); - } - if (responseParameters_.Count > 0) { - output.WriteMessageArray(2, field_names[1], responseParameters_); - } - if (hasPayload) { - output.WriteMessage(3, field_names[0], Payload); - } - UnknownFields.WriteTo(output); + public override bool Equals(object other) { + return Equals(other as StreamingOutputCallRequest); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasResponseType) { - size += pb::CodedOutputStream.ComputeEnumSize(1, (int) ResponseType); - } - foreach (global::grpc.testing.ResponseParameters element in ResponseParametersList) { - size += pb::CodedOutputStream.ComputeMessageSize(2, element); - } - if (hasPayload) { - size += pb::CodedOutputStream.ComputeMessageSize(3, Payload); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(StreamingOutputCallRequest other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; } + if (ResponseType != other.ResponseType) return false; + if(!responseParameters_.Equals(other.responseParameters_)) return false; + if (!object.Equals(Payload, other.Payload)) return false; + return true; } - public static StreamingOutputCallRequest ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static StreamingOutputCallRequest ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static StreamingOutputCallRequest ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static StreamingOutputCallRequest ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static StreamingOutputCallRequest ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static StreamingOutputCallRequest ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static StreamingOutputCallRequest ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static StreamingOutputCallRequest ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static StreamingOutputCallRequest ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static StreamingOutputCallRequest ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private StreamingOutputCallRequest MakeReadOnly() { - responseParameters_.MakeReadOnly(); - return this; + public override int GetHashCode() { + int hash = 1; + if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) hash ^= ResponseType.GetHashCode(); + hash ^= responseParameters_.GetHashCode(); + if (payload_ != null) hash ^= Payload.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(StreamingOutputCallRequest prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(StreamingOutputCallRequest cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private StreamingOutputCallRequest result; - - private StreamingOutputCallRequest PrepareBuilder() { - if (resultIsReadOnly) { - StreamingOutputCallRequest original = result; - result = new StreamingOutputCallRequest(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; + public void WriteTo(pb::CodedOutputStream output) { + if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + output.WriteRawTag(8); + output.WriteEnum((int) ResponseType); } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override StreamingOutputCallRequest MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; + responseParameters_.WriteTo(output, _repeated_responseParameters_codec); + if (payload_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Payload); } + } - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } + public int CalculateSize() { + int size = 0; + if (ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) ResponseType); } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.StreamingOutputCallRequest.Descriptor; } + size += responseParameters_.CalculateSize(_repeated_responseParameters_codec); + if (payload_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } + return size; + } - public override StreamingOutputCallRequest DefaultInstanceForType { - get { return global::grpc.testing.StreamingOutputCallRequest.DefaultInstance; } + public void MergeFrom(StreamingOutputCallRequest other) { + if (other == null) { + return; } - - public override StreamingOutputCallRequest BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + if (other.ResponseType != global::Grpc.Testing.PayloadType.COMPRESSABLE) { + ResponseType = other.ResponseType; } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is StreamingOutputCallRequest) { - return MergeFrom((StreamingOutputCallRequest) other); - } else { - base.MergeFrom(other); - return this; + responseParameters_.Add(other.responseParameters_); + if (other.payload_ != null) { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); } + Payload.MergeFrom(other.Payload); } + } - public override Builder MergeFrom(StreamingOutputCallRequest other) { - if (other == global::grpc.testing.StreamingOutputCallRequest.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasResponseType) { - ResponseType = other.ResponseType; - } - if (other.responseParameters_.Count != 0) { - result.responseParameters_.Add(other.responseParameters_); - } - if (other.HasPayload) { - MergePayload(other.Payload); - } - this.MergeUnknownFields(other.UnknownFields); - return this; - } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); - } - - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_streamingOutputCallRequestFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _streamingOutputCallRequestFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; - } + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 8: { + responseType_ = (global::Grpc.Testing.PayloadType) input.ReadEnum(); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 8: { - object unknown; - if(input.ReadEnum(ref result.responseType_, out unknown)) { - result.hasResponseType = true; - } else if(unknown is int) { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - unknownFields.MergeVarintField(1, (ulong)(int)unknown); - } - break; - } - case 18: { - input.ReadMessageArray(tag, field_name, result.responseParameters_, global::grpc.testing.ResponseParameters.DefaultInstance, extensionRegistry); - break; - } - case 26: { - global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder(); - if (result.hasPayload) { - subBuilder.MergeFrom(Payload); - } - input.ReadMessage(subBuilder, extensionRegistry); - Payload = subBuilder.BuildPartial(); - break; + case 18: { + responseParameters_.AddEntriesFrom(input, _repeated_responseParameters_codec); + break; + } + case 26: { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); } + input.ReadMessage(payload_); + break; } } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - - - public bool HasResponseType { - get { return result.hasResponseType; } - } - public global::grpc.testing.PayloadType ResponseType { - get { return result.ResponseType; } - set { SetResponseType(value); } - } - public Builder SetResponseType(global::grpc.testing.PayloadType value) { - PrepareBuilder(); - result.hasResponseType = true; - result.responseType_ = value; - return this; - } - public Builder ClearResponseType() { - PrepareBuilder(); - result.hasResponseType = false; - result.responseType_ = global::grpc.testing.PayloadType.COMPRESSABLE; - return this; - } - - public pbc::IPopsicleList ResponseParametersList { - get { return PrepareBuilder().responseParameters_; } - } - public int ResponseParametersCount { - get { return result.ResponseParametersCount; } - } - public global::grpc.testing.ResponseParameters GetResponseParameters(int index) { - return result.GetResponseParameters(index); - } - public Builder SetResponseParameters(int index, global::grpc.testing.ResponseParameters value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.responseParameters_[index] = value; - return this; - } - public Builder SetResponseParameters(int index, global::grpc.testing.ResponseParameters.Builder builderForValue) { - pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); - PrepareBuilder(); - result.responseParameters_[index] = builderForValue.Build(); - return this; - } - public Builder AddResponseParameters(global::grpc.testing.ResponseParameters value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.responseParameters_.Add(value); - return this; - } - public Builder AddResponseParameters(global::grpc.testing.ResponseParameters.Builder builderForValue) { - pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); - PrepareBuilder(); - result.responseParameters_.Add(builderForValue.Build()); - return this; - } - public Builder AddRangeResponseParameters(scg::IEnumerable values) { - PrepareBuilder(); - result.responseParameters_.Add(values); - return this; - } - public Builder ClearResponseParameters() { - PrepareBuilder(); - result.responseParameters_.Clear(); - return this; - } - - public bool HasPayload { - get { return result.hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return result.Payload; } - set { SetPayload(value); } - } - public Builder SetPayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = value; - return this; - } - public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) { - pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = builderForValue.Build(); - return this; - } - public Builder MergePayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - if (result.hasPayload && - result.payload_ != global::grpc.testing.Payload.DefaultInstance) { - result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial(); - } else { - result.payload_ = value; - } - result.hasPayload = true; - return this; } - public Builder ClearPayload() { - PrepareBuilder(); - result.hasPayload = false; - result.payload_ = null; - return this; - } - } - static StreamingOutputCallRequest() { - object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null); } + } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class StreamingOutputCallResponse : pb::GeneratedMessage { - private StreamingOutputCallResponse() { } - private static readonly StreamingOutputCallResponse defaultInstance = new StreamingOutputCallResponse().MakeReadOnly(); - private static readonly string[] _streamingOutputCallResponseFieldNames = new string[] { "payload" }; - private static readonly uint[] _streamingOutputCallResponseFieldTags = new uint[] { 10 }; - public static StreamingOutputCallResponse DefaultInstance { - get { return defaultInstance; } - } + public sealed partial class StreamingOutputCallResponse : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new StreamingOutputCallResponse()); + public static pb::MessageParser Parser { get { return _parser; } } - public override StreamingOutputCallResponse DefaultInstanceForType { - get { return DefaultInstance; } + public static pbr::MessageDescriptor Descriptor { + get { return global::Grpc.Testing.Messages.Descriptor.MessageTypes[7]; } } - protected override StreamingOutputCallResponse ThisMessage { - get { return this; } + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } } - public static pbd::MessageDescriptor Descriptor { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingOutputCallResponse__Descriptor; } + public StreamingOutputCallResponse() { + OnConstruction(); } - protected override pb::FieldAccess.FieldAccessorTable InternalFieldAccessors { - get { return global::grpc.testing.Messages.internal__static_grpc_testing_StreamingOutputCallResponse__FieldAccessorTable; } - } + partial void OnConstruction(); - public const int PayloadFieldNumber = 1; - private bool hasPayload; - private global::grpc.testing.Payload payload_; - public bool HasPayload { - get { return hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return payload_ ?? global::grpc.testing.Payload.DefaultInstance; } + public StreamingOutputCallResponse(StreamingOutputCallResponse other) : this() { + Payload = other.payload_ != null ? other.Payload.Clone() : null; } - public override bool IsInitialized { - get { - return true; - } + public StreamingOutputCallResponse Clone() { + return new StreamingOutputCallResponse(this); } - public override void WriteTo(pb::ICodedOutputStream output) { - int size = SerializedSize; - string[] field_names = _streamingOutputCallResponseFieldNames; - if (hasPayload) { - output.WriteMessage(1, field_names[0], Payload); + public const int PayloadFieldNumber = 1; + private global::Grpc.Testing.Payload payload_; + public global::Grpc.Testing.Payload Payload { + get { return payload_; } + set { + payload_ = value; } - UnknownFields.WriteTo(output); } - private int memoizedSerializedSize = -1; - public override int SerializedSize { - get { - int size = memoizedSerializedSize; - if (size != -1) return size; + public override bool Equals(object other) { + return Equals(other as StreamingOutputCallResponse); + } - size = 0; - if (hasPayload) { - size += pb::CodedOutputStream.ComputeMessageSize(1, Payload); - } - size += UnknownFields.SerializedSize; - memoizedSerializedSize = size; - return size; + public bool Equals(StreamingOutputCallResponse other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; } + if (!object.Equals(Payload, other.Payload)) return false; + return true; } - public static StreamingOutputCallResponse ParseFrom(pb::ByteString data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static StreamingOutputCallResponse ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static StreamingOutputCallResponse ParseFrom(byte[] data) { - return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed(); - } - public static StreamingOutputCallResponse ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed(); - } - public static StreamingOutputCallResponse ParseFrom(global::System.IO.Stream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static StreamingOutputCallResponse ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - public static StreamingOutputCallResponse ParseDelimitedFrom(global::System.IO.Stream input) { - return CreateBuilder().MergeDelimitedFrom(input).BuildParsed(); - } - public static StreamingOutputCallResponse ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) { - return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed(); - } - public static StreamingOutputCallResponse ParseFrom(pb::ICodedInputStream input) { - return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed(); - } - public static StreamingOutputCallResponse ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed(); - } - private StreamingOutputCallResponse MakeReadOnly() { - return this; + public override int GetHashCode() { + int hash = 1; + if (payload_ != null) hash ^= Payload.GetHashCode(); + return hash; } - public static Builder CreateBuilder() { return new Builder(); } - public override Builder ToBuilder() { return CreateBuilder(this); } - public override Builder CreateBuilderForType() { return new Builder(); } - public static Builder CreateBuilder(StreamingOutputCallResponse prototype) { - return new Builder(prototype); + public override string ToString() { + return pb::JsonFormatter.Default.Format(this); } - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - public sealed partial class Builder : pb::GeneratedBuilder { - protected override Builder ThisBuilder { - get { return this; } - } - public Builder() { - result = DefaultInstance; - resultIsReadOnly = true; - } - internal Builder(StreamingOutputCallResponse cloneFrom) { - result = cloneFrom; - resultIsReadOnly = true; - } - - private bool resultIsReadOnly; - private StreamingOutputCallResponse result; - - private StreamingOutputCallResponse PrepareBuilder() { - if (resultIsReadOnly) { - StreamingOutputCallResponse original = result; - result = new StreamingOutputCallResponse(); - resultIsReadOnly = false; - MergeFrom(original); - } - return result; - } - - public override bool IsInitialized { - get { return result.IsInitialized; } - } - - protected override StreamingOutputCallResponse MessageBeingBuilt { - get { return PrepareBuilder(); } - } - - public override Builder Clear() { - result = DefaultInstance; - resultIsReadOnly = true; - return this; - } - - public override Builder Clone() { - if (resultIsReadOnly) { - return new Builder(result); - } else { - return new Builder().MergeFrom(result); - } - } - - public override pbd::MessageDescriptor DescriptorForType { - get { return global::grpc.testing.StreamingOutputCallResponse.Descriptor; } + public void WriteTo(pb::CodedOutputStream output) { + if (payload_ != null) { + output.WriteRawTag(10); + output.WriteMessage(Payload); } + } - public override StreamingOutputCallResponse DefaultInstanceForType { - get { return global::grpc.testing.StreamingOutputCallResponse.DefaultInstance; } + public int CalculateSize() { + int size = 0; + if (payload_ != null) { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Payload); } + return size; + } - public override StreamingOutputCallResponse BuildPartial() { - if (resultIsReadOnly) { - return result; - } - resultIsReadOnly = true; - return result.MakeReadOnly(); + public void MergeFrom(StreamingOutputCallResponse other) { + if (other == null) { + return; } - - public override Builder MergeFrom(pb::IMessage other) { - if (other is StreamingOutputCallResponse) { - return MergeFrom((StreamingOutputCallResponse) other); - } else { - base.MergeFrom(other); - return this; + if (other.payload_ != null) { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); } + Payload.MergeFrom(other.Payload); } + } - public override Builder MergeFrom(StreamingOutputCallResponse other) { - if (other == global::grpc.testing.StreamingOutputCallResponse.DefaultInstance) return this; - PrepareBuilder(); - if (other.HasPayload) { - MergePayload(other.Payload); - } - this.MergeUnknownFields(other.UnknownFields); - return this; - } - - public override Builder MergeFrom(pb::ICodedInputStream input) { - return MergeFrom(input, pb::ExtensionRegistry.Empty); - } - - public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) { - PrepareBuilder(); - pb::UnknownFieldSet.Builder unknownFields = null; - uint tag; - string field_name; - while (input.ReadTag(out tag, out field_name)) { - if(tag == 0 && field_name != null) { - int field_ordinal = global::System.Array.BinarySearch(_streamingOutputCallResponseFieldNames, field_name, global::System.StringComparer.Ordinal); - if(field_ordinal >= 0) - tag = _streamingOutputCallResponseFieldTags[field_ordinal]; - else { - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - continue; + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + if (payload_ == null) { + payload_ = new global::Grpc.Testing.Payload(); } + input.ReadMessage(payload_); + break; } - switch (tag) { - case 0: { - throw pb::InvalidProtocolBufferException.InvalidTag(); - } - default: { - if (pb::WireFormat.IsEndGroupTag(tag)) { - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); - } - return this; - } - if (unknownFields == null) { - unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields); - } - ParseUnknownField(input, unknownFields, extensionRegistry, tag, field_name); - break; - } - case 10: { - global::grpc.testing.Payload.Builder subBuilder = global::grpc.testing.Payload.CreateBuilder(); - if (result.hasPayload) { - subBuilder.MergeFrom(Payload); - } - input.ReadMessage(subBuilder, extensionRegistry); - Payload = subBuilder.BuildPartial(); - break; - } - } - } - - if (unknownFields != null) { - this.UnknownFields = unknownFields.Build(); } - return this; - } - - - public bool HasPayload { - get { return result.hasPayload; } - } - public global::grpc.testing.Payload Payload { - get { return result.Payload; } - set { SetPayload(value); } - } - public Builder SetPayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = value; - return this; - } - public Builder SetPayload(global::grpc.testing.Payload.Builder builderForValue) { - pb::ThrowHelper.ThrowIfNull(builderForValue, "builderForValue"); - PrepareBuilder(); - result.hasPayload = true; - result.payload_ = builderForValue.Build(); - return this; - } - public Builder MergePayload(global::grpc.testing.Payload value) { - pb::ThrowHelper.ThrowIfNull(value, "value"); - PrepareBuilder(); - if (result.hasPayload && - result.payload_ != global::grpc.testing.Payload.DefaultInstance) { - result.payload_ = global::grpc.testing.Payload.CreateBuilder(result.payload_).MergeFrom(value).BuildPartial(); - } else { - result.payload_ = value; - } - result.hasPayload = true; - return this; - } - public Builder ClearPayload() { - PrepareBuilder(); - result.hasPayload = false; - result.payload_ = null; - return this; } } - static StreamingOutputCallResponse() { - object.ReferenceEquals(global::grpc.testing.Messages.Descriptor, null); - } + } #endregion diff --git a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs index 842795374fd..37b2518c21e 100644 --- a/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/SslCredentialsTest.cs @@ -37,9 +37,9 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using grpc.testing; using Grpc.Core; using Grpc.Core.Utils; +using Grpc.Testing; using NUnit.Framework; namespace Grpc.IntegrationTesting @@ -92,7 +92,7 @@ namespace Grpc.IntegrationTesting [Test] public void AuthenticatedClientAndServer() { - var response = client.UnaryCall(SimpleRequest.CreateBuilder().SetResponseSize(10).Build()); + var response = client.UnaryCall(new SimpleRequest { ResponseSize = 10 }); Assert.AreEqual(10, response.Payload.Body.Length); } } diff --git a/src/csharp/Grpc.IntegrationTesting/Test.cs b/src/csharp/Grpc.IntegrationTesting/Test.cs new file mode 100644 index 00000000000..466ec57d3dc --- /dev/null +++ b/src/csharp/Grpc.IntegrationTesting/Test.cs @@ -0,0 +1,48 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: test.proto +#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 Grpc.Testing { + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public static partial class Test { + + #region Descriptor + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static Test() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Cgp0ZXN0LnByb3RvEgxncnBjLnRlc3RpbmcaC2VtcHR5LnByb3RvGg5tZXNz", + "YWdlcy5wcm90bzK7BAoLVGVzdFNlcnZpY2USNQoJRW1wdHlDYWxsEhMuZ3Jw", + "Yy50ZXN0aW5nLkVtcHR5GhMuZ3JwYy50ZXN0aW5nLkVtcHR5EkYKCVVuYXJ5", + "Q2FsbBIbLmdycGMudGVzdGluZy5TaW1wbGVSZXF1ZXN0GhwuZ3JwYy50ZXN0", + "aW5nLlNpbXBsZVJlc3BvbnNlEmwKE1N0cmVhbWluZ091dHB1dENhbGwSKC5n", + "cnBjLnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlcXVlc3QaKS5ncnBj", + "LnRlc3RpbmcuU3RyZWFtaW5nT3V0cHV0Q2FsbFJlc3BvbnNlMAESaQoSU3Ry", + "ZWFtaW5nSW5wdXRDYWxsEicuZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ0lucHV0", + "Q2FsbFJlcXVlc3QaKC5ncnBjLnRlc3RpbmcuU3RyZWFtaW5nSW5wdXRDYWxs", + "UmVzcG9uc2UoARJpCg5GdWxsRHVwbGV4Q2FsbBIoLmdycGMudGVzdGluZy5T", + "dHJlYW1pbmdPdXRwdXRDYWxsUmVxdWVzdBopLmdycGMudGVzdGluZy5TdHJl", + "YW1pbmdPdXRwdXRDYWxsUmVzcG9uc2UoATABEmkKDkhhbGZEdXBsZXhDYWxs", + "EiguZ3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXF1ZXN0Giku", + "Z3JwYy50ZXN0aW5nLlN0cmVhbWluZ091dHB1dENhbGxSZXNwb25zZSgBMAFi", + "BnByb3RvMw==")); + descriptor = pbr::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData, + new pbr::FileDescriptor[] { global::Grpc.Testing.Proto.Empty.Descriptor, global::Grpc.Testing.Messages.Descriptor, }, + new pbr::GeneratedCodeInfo(null, null)); + } + #endregion + + } +} + +#endregion Designer generated code diff --git a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs index da0b7fb910b..7a48d6e92ed 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestCredentials.cs @@ -37,8 +37,6 @@ using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; using System.Threading.Tasks; -using Google.ProtocolBuffers; -using grpc.testing; using Grpc.Core; using Grpc.Core.Utils; using NUnit.Framework; diff --git a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs index 697acb53d8d..f63e1484759 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestGrpc.cs @@ -7,91 +7,97 @@ using System.Threading; using System.Threading.Tasks; using Grpc.Core; -namespace grpc.testing { +namespace Grpc.Testing { public static class TestService { static readonly string __ServiceName = "grpc.testing.TestService"; - static readonly Marshaller __Marshaller_Empty = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.Empty.ParseFrom); - static readonly Marshaller __Marshaller_SimpleRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.SimpleRequest.ParseFrom); - static readonly Marshaller __Marshaller_SimpleResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.SimpleResponse.ParseFrom); - static readonly Marshaller __Marshaller_StreamingOutputCallRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.StreamingOutputCallRequest.ParseFrom); - static readonly Marshaller __Marshaller_StreamingOutputCallResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.StreamingOutputCallResponse.ParseFrom); - static readonly Marshaller __Marshaller_StreamingInputCallRequest = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.StreamingInputCallRequest.ParseFrom); - static readonly Marshaller __Marshaller_StreamingInputCallResponse = Marshallers.Create((arg) => arg.ToByteArray(), global::grpc.testing.StreamingInputCallResponse.ParseFrom); + static readonly Marshaller __Marshaller_Empty = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.Empty.Parser.ParseFrom); + static readonly Marshaller __Marshaller_SimpleRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleRequest.Parser.ParseFrom); + static readonly Marshaller __Marshaller_SimpleResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.SimpleResponse.Parser.ParseFrom); + static readonly Marshaller __Marshaller_StreamingOutputCallRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallRequest.Parser.ParseFrom); + static readonly Marshaller __Marshaller_StreamingOutputCallResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingOutputCallResponse.Parser.ParseFrom); + static readonly Marshaller __Marshaller_StreamingInputCallRequest = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallRequest.Parser.ParseFrom); + static readonly Marshaller __Marshaller_StreamingInputCallResponse = Marshallers.Create((arg) => global::Google.Protobuf.MessageExtensions.ToByteArray(arg), global::Grpc.Testing.StreamingInputCallResponse.Parser.ParseFrom); - static readonly Method __Method_EmptyCall = new Method( + static readonly Method __Method_EmptyCall = new Method( MethodType.Unary, __ServiceName, "EmptyCall", __Marshaller_Empty, __Marshaller_Empty); - static readonly Method __Method_UnaryCall = new Method( + static readonly Method __Method_UnaryCall = new Method( MethodType.Unary, __ServiceName, "UnaryCall", __Marshaller_SimpleRequest, __Marshaller_SimpleResponse); - static readonly Method __Method_StreamingOutputCall = new Method( + static readonly Method __Method_StreamingOutputCall = new Method( MethodType.ServerStreaming, __ServiceName, "StreamingOutputCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); - static readonly Method __Method_StreamingInputCall = new Method( + static readonly Method __Method_StreamingInputCall = new Method( MethodType.ClientStreaming, __ServiceName, "StreamingInputCall", __Marshaller_StreamingInputCallRequest, __Marshaller_StreamingInputCallResponse); - static readonly Method __Method_FullDuplexCall = new Method( + static readonly Method __Method_FullDuplexCall = new Method( MethodType.DuplexStreaming, __ServiceName, "FullDuplexCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); - static readonly Method __Method_HalfDuplexCall = new Method( + static readonly Method __Method_HalfDuplexCall = new Method( MethodType.DuplexStreaming, __ServiceName, "HalfDuplexCall", __Marshaller_StreamingOutputCallRequest, __Marshaller_StreamingOutputCallResponse); + // service descriptor + public static global::Google.Protobuf.Reflection.ServiceDescriptor Descriptor + { + get { return global::Grpc.Testing.Test.Descriptor.Services[0]; } + } + // client interface public interface ITestServiceClient { - global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options); - AsyncUnaryCall EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncUnaryCall EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options); - global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options); - AsyncUnaryCall UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncUnaryCall UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options); - AsyncServerStreamingCall StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncServerStreamingCall StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options); - AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncClientStreamingCall StreamingInputCall(CallOptions options); - AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall FullDuplexCall(CallOptions options); - AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); - AsyncDuplexStreamingCall HalfDuplexCall(CallOptions options); + global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options); + AsyncUnaryCall EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options); + global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options); + AsyncUnaryCall UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncUnaryCall UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options); + AsyncServerStreamingCall StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncServerStreamingCall StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options); + AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncClientStreamingCall StreamingInputCall(CallOptions options); + AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall FullDuplexCall(CallOptions options); + AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)); + AsyncDuplexStreamingCall HalfDuplexCall(CallOptions options); } // server-side interface public interface ITestService { - Task EmptyCall(global::grpc.testing.Empty request, ServerCallContext context); - Task UnaryCall(global::grpc.testing.SimpleRequest request, ServerCallContext context); - Task StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, IServerStreamWriter responseStream, ServerCallContext context); - Task StreamingInputCall(IAsyncStreamReader requestStream, ServerCallContext context); - Task FullDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); - Task HalfDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); + Task EmptyCall(global::Grpc.Testing.Empty request, ServerCallContext context); + Task UnaryCall(global::Grpc.Testing.SimpleRequest request, ServerCallContext context); + Task StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, IServerStreamWriter responseStream, ServerCallContext context); + Task StreamingInputCall(IAsyncStreamReader requestStream, ServerCallContext context); + Task FullDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); + Task HalfDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context); } // client stub @@ -100,82 +106,82 @@ namespace grpc.testing { public TestServiceClient(Channel channel) : base(channel) { } - public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.BlockingUnaryCall(call, request); } - public global::grpc.testing.Empty EmptyCall(global::grpc.testing.Empty request, CallOptions options) + public global::Grpc.Testing.Empty EmptyCall(global::Grpc.Testing.Empty request, CallOptions options) { var call = CreateCall(__Method_EmptyCall, options); return Calls.BlockingUnaryCall(call, request); } - public AsyncUnaryCall EmptyCallAsync(global::grpc.testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall EmptyCallAsync(global::Grpc.Testing.Empty request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_EmptyCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncUnaryCall(call, request); } - public AsyncUnaryCall EmptyCallAsync(global::grpc.testing.Empty request, CallOptions options) + public AsyncUnaryCall EmptyCallAsync(global::Grpc.Testing.Empty request, CallOptions options) { var call = CreateCall(__Method_EmptyCall, options); return Calls.AsyncUnaryCall(call, request); } - public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.BlockingUnaryCall(call, request); } - public global::grpc.testing.SimpleResponse UnaryCall(global::grpc.testing.SimpleRequest request, CallOptions options) + public global::Grpc.Testing.SimpleResponse UnaryCall(global::Grpc.Testing.SimpleRequest request, CallOptions options) { var call = CreateCall(__Method_UnaryCall, options); return Calls.BlockingUnaryCall(call, request); } - public AsyncUnaryCall UnaryCallAsync(global::grpc.testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncUnaryCall UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_UnaryCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncUnaryCall(call, request); } - public AsyncUnaryCall UnaryCallAsync(global::grpc.testing.SimpleRequest request, CallOptions options) + public AsyncUnaryCall UnaryCallAsync(global::Grpc.Testing.SimpleRequest request, CallOptions options) { var call = CreateCall(__Method_UnaryCall, options); return Calls.AsyncUnaryCall(call, request); } - public AsyncServerStreamingCall StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncServerStreamingCall StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_StreamingOutputCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncServerStreamingCall(call, request); } - public AsyncServerStreamingCall StreamingOutputCall(global::grpc.testing.StreamingOutputCallRequest request, CallOptions options) + public AsyncServerStreamingCall StreamingOutputCall(global::Grpc.Testing.StreamingOutputCallRequest request, CallOptions options) { var call = CreateCall(__Method_StreamingOutputCall, options); return Calls.AsyncServerStreamingCall(call, request); } - public AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncClientStreamingCall StreamingInputCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_StreamingInputCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncClientStreamingCall(call); } - public AsyncClientStreamingCall StreamingInputCall(CallOptions options) + public AsyncClientStreamingCall StreamingInputCall(CallOptions options) { var call = CreateCall(__Method_StreamingInputCall, options); return Calls.AsyncClientStreamingCall(call); } - public AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall FullDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_FullDuplexCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncDuplexStreamingCall(call); } - public AsyncDuplexStreamingCall FullDuplexCall(CallOptions options) + public AsyncDuplexStreamingCall FullDuplexCall(CallOptions options) { var call = CreateCall(__Method_FullDuplexCall, options); return Calls.AsyncDuplexStreamingCall(call); } - public AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) + public AsyncDuplexStreamingCall HalfDuplexCall(Metadata headers = null, DateTime? deadline = null, CancellationToken cancellationToken = default(CancellationToken)) { var call = CreateCall(__Method_HalfDuplexCall, new CallOptions(headers, deadline, cancellationToken)); return Calls.AsyncDuplexStreamingCall(call); } - public AsyncDuplexStreamingCall HalfDuplexCall(CallOptions options) + public AsyncDuplexStreamingCall HalfDuplexCall(CallOptions options) { var call = CreateCall(__Method_HalfDuplexCall, options); return Calls.AsyncDuplexStreamingCall(call); diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs index ceebd5dd8c1..c5bfcf08c0c 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs @@ -35,11 +35,11 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Google.ProtocolBuffers; +using Google.Protobuf; using Grpc.Core; using Grpc.Core.Utils; -namespace grpc.testing +namespace Grpc.Testing { /// /// Implementation of TestService server @@ -48,22 +48,20 @@ namespace grpc.testing { public Task EmptyCall(Empty request, ServerCallContext context) { - return Task.FromResult(Empty.DefaultInstance); + return Task.FromResult(new Empty()); } public Task UnaryCall(SimpleRequest request, ServerCallContext context) { - var response = SimpleResponse.CreateBuilder() - .SetPayload(CreateZerosPayload(request.ResponseSize)).Build(); + var response = new SimpleResponse { Payload = CreateZerosPayload(request.ResponseSize) }; return Task.FromResult(response); } public async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter responseStream, ServerCallContext context) { - foreach (var responseParam in request.ResponseParametersList) + foreach (var responseParam in request.ResponseParameters) { - var response = StreamingOutputCallResponse.CreateBuilder() - .SetPayload(CreateZerosPayload(responseParam.Size)).Build(); + var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) }; await responseStream.WriteAsync(response); } } @@ -75,17 +73,16 @@ namespace grpc.testing { sum += request.Payload.Body.Length; }); - return StreamingInputCallResponse.CreateBuilder().SetAggregatedPayloadSize(sum).Build(); + return new StreamingInputCallResponse { AggregatedPayloadSize = sum }; } public async Task FullDuplexCall(IAsyncStreamReader requestStream, IServerStreamWriter responseStream, ServerCallContext context) { await requestStream.ForEachAsync(async request => { - foreach (var responseParam in request.ResponseParametersList) + foreach (var responseParam in request.ResponseParameters) { - var response = StreamingOutputCallResponse.CreateBuilder() - .SetPayload(CreateZerosPayload(responseParam.Size)).Build(); + var response = new StreamingOutputCallResponse { Payload = CreateZerosPayload(responseParam.Size) }; await responseStream.WriteAsync(response); } }); @@ -98,7 +95,7 @@ namespace grpc.testing private static Payload CreateZerosPayload(int size) { - return Payload.CreateBuilder().SetBody(ByteString.CopyFrom(new byte[size])).Build(); + return new Payload { Body = ByteString.CopyFrom(new byte[size]) }; } } } diff --git a/src/csharp/Grpc.IntegrationTesting/packages.config b/src/csharp/Grpc.IntegrationTesting/packages.config index 0867b091b92..8dfded1964f 100644 --- a/src/csharp/Grpc.IntegrationTesting/packages.config +++ b/src/csharp/Grpc.IntegrationTesting/packages.config @@ -3,6 +3,7 @@ + diff --git a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto b/src/csharp/Grpc.IntegrationTesting/proto/empty.proto index 4295a0a960c..6d0eb937d67 100644 --- a/src/csharp/Grpc.IntegrationTesting/proto/empty.proto +++ b/src/csharp/Grpc.IntegrationTesting/proto/empty.proto @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -syntax = "proto2"; +syntax = "proto3"; package grpc.testing; diff --git a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto b/src/csharp/Grpc.IntegrationTesting/proto/messages.proto index 65a81404652..7df85e3c136 100644 --- a/src/csharp/Grpc.IntegrationTesting/proto/messages.proto +++ b/src/csharp/Grpc.IntegrationTesting/proto/messages.proto @@ -30,7 +30,7 @@ // Message definitions to be used by integration test service definitions. -syntax = "proto2"; +syntax = "proto3"; package grpc.testing; @@ -49,46 +49,46 @@ enum PayloadType { // A block of data, to simply increase gRPC message size. message Payload { // The type of data in body. - optional PayloadType type = 1; + PayloadType type = 1; // Primary contents of payload. - optional bytes body = 2; + bytes body = 2; } // Unary request. message SimpleRequest { // Desired payload type in the response from the server. // If response_type is RANDOM, server randomly chooses one from other formats. - optional PayloadType response_type = 1; + PayloadType response_type = 1; // Desired payload size in the response from the server. // If response_type is COMPRESSABLE, this denotes the size before compression. - optional int32 response_size = 2; + int32 response_size = 2; // Optional input payload sent along with the request. - optional Payload payload = 3; + Payload payload = 3; // Whether SimpleResponse should include username. - optional bool fill_username = 4; + bool fill_username = 4; // Whether SimpleResponse should include OAuth scope. - optional bool fill_oauth_scope = 5; + bool fill_oauth_scope = 5; } // Unary response, as configured by the request. message SimpleResponse { // Payload to increase message size. - optional Payload payload = 1; + Payload payload = 1; // The user the request came from, for verifying authentication was // successful when the client expected it. - optional string username = 2; + string username = 2; // OAuth scope. - optional string oauth_scope = 3; + string oauth_scope = 3; } // Client-streaming request. message StreamingInputCallRequest { // Optional input payload sent along with the request. - optional Payload payload = 1; + Payload payload = 1; // Not expecting any payload from the response. } @@ -96,18 +96,18 @@ message StreamingInputCallRequest { // Client-streaming response. message StreamingInputCallResponse { // Aggregated size of payloads received from the client. - optional int32 aggregated_payload_size = 1; + int32 aggregated_payload_size = 1; } // Configuration for a particular response. message ResponseParameters { // Desired payload sizes in responses from the server. // If response_type is COMPRESSABLE, this denotes the size before compression. - optional int32 size = 1; + int32 size = 1; // Desired interval between consecutive responses in the response stream in // microseconds. - optional int32 interval_us = 2; + int32 interval_us = 2; } // Server-streaming request. @@ -116,17 +116,17 @@ message StreamingOutputCallRequest { // If response_type is RANDOM, the payload from each response in the stream // might be of different types. This is to simulate a mixed type of payload // stream. - optional PayloadType response_type = 1; + PayloadType response_type = 1; // Configuration for each expected response message. repeated ResponseParameters response_parameters = 2; // Optional input payload sent along with the request. - optional Payload payload = 3; + Payload payload = 3; } // Server-streaming response, as configured by the request and parameters. message StreamingOutputCallResponse { // Payload to increase response size. - optional Payload payload = 1; + Payload payload = 1; } diff --git a/src/csharp/Grpc.IntegrationTesting/proto/test.proto b/src/csharp/Grpc.IntegrationTesting/proto/test.proto index 927a3a83aa2..f9e0d2a0396 100644 --- a/src/csharp/Grpc.IntegrationTesting/proto/test.proto +++ b/src/csharp/Grpc.IntegrationTesting/proto/test.proto @@ -30,7 +30,7 @@ // An integration test service that covers all the method signature permutations // of unary/streaming requests/responses. -syntax = "proto2"; +syntax = "proto3"; import "empty.proto"; import "messages.proto"; diff --git a/src/csharp/Grpc.Tools.nuspec b/src/csharp/Grpc.Tools.nuspec index eabf5dc7dbc..48a7b1f3af2 100644 --- a/src/csharp/Grpc.Tools.nuspec +++ b/src/csharp/Grpc.Tools.nuspec @@ -4,19 +4,18 @@ Grpc.Tools gRPC C# Tools Tools for C# implementation of gRPC - an RPC library and framework - Precompiled Windows binaries for generating protocol buffer messages and gRPC client/server code + Precompiled Windows binary for generating gRPC client/server code $version$ Google Inc. grpc-packages https://github.com/grpc/grpc/blob/master/LICENSE https://github.com/grpc/grpc false - protoc.exe - protocol buffer compiler v3.0.0-alpha-3; grpc_csharp_plugin.exe - gRPC C# protoc plugin version $version$ + grpc_csharp_plugin.exe - gRPC C# protoc plugin version $version$ Copyright 2015, Google Inc. gRPC RPC Protocol HTTP/2 - - + diff --git a/src/csharp/README.md b/src/csharp/README.md index bb5e165986d..30523b3bd28 100644 --- a/src/csharp/README.md +++ b/src/csharp/README.md @@ -19,7 +19,7 @@ Usage: Windows That will also pull all the transitive dependencies (including the native libraries that gRPC C# is internally using). -- Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp. +- Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp. Usage: Linux (Mono) -------------- @@ -50,7 +50,7 @@ Usage: Linux (Mono) - Add NuGet package `Grpc` as a dependency (Project -> Add NuGet packages). -- Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp. +- Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp. Usage: MacOS (Mono) -------------- @@ -73,7 +73,7 @@ Usage: MacOS (Mono) - *You will be able to build your project in Xamarin Studio, but to run or test it, you will need to run it under 64-bit version of Mono.* -- Helloworld project example can be found in https://github.com/grpc/grpc-common/tree/master/csharp. +- Helloworld project example can be found in https://github.com/grpc/grpc/tree/master/examples/csharp. Building: Windows ----------------- diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat index 8a11d014307..255b7469ab6 100644 --- a/src/csharp/build_packages.bat +++ b/src/csharp/build_packages.bat @@ -1,8 +1,9 @@ @rem Builds gRPC NuGet packages @rem Current package versions -set VERSION=0.6.1 -set CORE_VERSION=0.10.1 +set VERSION=0.7.0 +set CORE_VERSION=0.11.0 +set PROTOBUF_VERSION=3.0.0-alpha4 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe @@ -14,10 +15,12 @@ endlocal @call buildall.bat BUILD_SIGNED || goto :error +@call ..\..\vsprojects\build_plugins.bat || goto :error + %NUGET% pack ..\..\vsprojects\nuget_package\grpc.native.csharp_ext.nuspec -Version %CORE_VERSION% || goto :error %NUGET% pack Grpc.Auth\Grpc.Auth.nuspec -Symbols -Version %VERSION% || goto :error %NUGET% pack Grpc.Core\Grpc.Core.nuspec -Symbols -Version %VERSION% -Properties GrpcNativeCsharpExtVersion=%CORE_VERSION% || goto :error -%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% || goto :error +%NUGET% pack Grpc.HealthCheck\Grpc.HealthCheck.nuspec -Symbols -Version %VERSION% -Properties ProtobufVersion=%PROTOBUF_VERSION% || goto :error %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% || goto :error %NUGET% pack Grpc.nuspec -Version %VERSION% || goto :error diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c index 489e219c492..70c0fbcc503 100644 --- a/src/csharp/ext/grpc_csharp_ext.c +++ b/src/csharp/ext/grpc_csharp_ext.c @@ -837,11 +837,11 @@ grpcsharp_ssl_credentials_create(const char *pem_root_certs, if (key_cert_pair_cert_chain || key_cert_pair_private_key) { key_cert_pair.cert_chain = key_cert_pair_cert_chain; key_cert_pair.private_key = key_cert_pair_private_key; - return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair); + return grpc_ssl_credentials_create(pem_root_certs, &key_cert_pair, NULL); } else { GPR_ASSERT(!key_cert_pair_cert_chain); GPR_ASSERT(!key_cert_pair_private_key); - return grpc_ssl_credentials_create(pem_root_certs, NULL); + return grpc_ssl_credentials_create(pem_root_certs, NULL, NULL); } } @@ -852,7 +852,7 @@ GPR_EXPORT void GPR_CALLTYPE grpcsharp_credentials_release(grpc_credentials *cre GPR_EXPORT grpc_channel *GPR_CALLTYPE grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target, const grpc_channel_args *args) { - return grpc_secure_channel_create(creds, target, args); + return grpc_secure_channel_create(creds, target, args, NULL); } GPR_EXPORT grpc_server_credentials *GPR_CALLTYPE @@ -876,7 +876,7 @@ grpcsharp_ssl_server_credentials_create( } creds = grpc_ssl_server_credentials_create(pem_root_certs, key_cert_pairs, num_key_cert_pairs, - force_client_auth); + force_client_auth, NULL); gpr_free(key_cert_pairs); return creds; } diff --git a/src/csharp/generate_proto_csharp.sh b/src/csharp/generate_proto_csharp.sh index 7c3ba709220..a17f45b5874 100755 --- a/src/csharp/generate_proto_csharp.sh +++ b/src/csharp/generate_proto_csharp.sh @@ -38,11 +38,11 @@ EXAMPLES_DIR=Grpc.Examples INTEROP_DIR=Grpc.IntegrationTesting HEALTHCHECK_DIR=Grpc.HealthCheck -$PROTOC --plugin=$PLUGIN --grpc_out=$EXAMPLES_DIR \ +$PROTOC --plugin=$PLUGIN --csharp_out=$EXAMPLES_DIR --grpc_out=$EXAMPLES_DIR \ -I $EXAMPLES_DIR/proto $EXAMPLES_DIR/proto/math.proto -$PROTOC --plugin=$PLUGIN --grpc_out=$INTEROP_DIR \ - -I $INTEROP_DIR/proto $INTEROP_DIR/proto/test.proto +$PROTOC --plugin=$PLUGIN --csharp_out=$INTEROP_DIR --grpc_out=$INTEROP_DIR \ + -I $INTEROP_DIR/proto $INTEROP_DIR/proto/*.proto -$PROTOC --plugin=$PLUGIN --grpc_out=$HEALTHCHECK_DIR \ +$PROTOC --plugin=$PLUGIN --csharp_out=$HEALTHCHECK_DIR --grpc_out=$HEALTHCHECK_DIR \ -I $HEALTHCHECK_DIR/proto $HEALTHCHECK_DIR/proto/health.proto diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc index a61c8300997..9aed96bbf5a 100644 --- a/src/node/ext/channel.cc +++ b/src/node/ext/channel.cc @@ -161,7 +161,7 @@ NAN_METHOD(Channel::New) { NULL); } else { wrapped_channel = - grpc_secure_channel_create(creds, *host, channel_args_ptr); + grpc_secure_channel_create(creds, *host, channel_args_ptr, NULL); } if (channel_args_ptr != NULL) { free(channel_args_ptr->args); diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc index 21d61f1a7fd..85a823a1085 100644 --- a/src/node/ext/credentials.cc +++ b/src/node/ext/credentials.cc @@ -156,7 +156,8 @@ NAN_METHOD(Credentials::CreateSsl) { "createSSl's third argument must be a Buffer if provided"); } grpc_credentials *creds = grpc_ssl_credentials_create( - root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair); + root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair, + NULL); if (creds == NULL) { NanReturnNull(); } @@ -176,7 +177,7 @@ NAN_METHOD(Credentials::CreateComposite) { Credentials *creds1 = ObjectWrap::Unwrap(args[0]->ToObject()); Credentials *creds2 = ObjectWrap::Unwrap(args[1]->ToObject()); grpc_credentials *creds = grpc_composite_credentials_create( - creds1->wrapped_credentials, creds2->wrapped_credentials); + creds1->wrapped_credentials, creds2->wrapped_credentials, NULL); if (creds == NULL) { NanReturnNull(); } @@ -185,7 +186,7 @@ NAN_METHOD(Credentials::CreateComposite) { NAN_METHOD(Credentials::CreateGce) { NanScope(); - grpc_credentials *creds = grpc_compute_engine_credentials_create(); + grpc_credentials *creds = grpc_compute_engine_credentials_create(NULL); if (creds == NULL) { NanReturnNull(); } @@ -202,8 +203,8 @@ NAN_METHOD(Credentials::CreateIam) { } NanUtf8String auth_token(args[0]); NanUtf8String auth_selector(args[1]); - grpc_credentials *creds = grpc_iam_credentials_create(*auth_token, - *auth_selector); + grpc_credentials *creds = + grpc_iam_credentials_create(*auth_token, *auth_selector, NULL); if (creds == NULL) { NanReturnNull(); } diff --git a/src/node/ext/server.cc b/src/node/ext/server.cc index 01217bce797..32a8ff55b12 100644 --- a/src/node/ext/server.cc +++ b/src/node/ext/server.cc @@ -120,7 +120,7 @@ Server::Server(grpc_server *server) : wrapped_server(server) { Server::~Server() { this->ShutdownServer(); grpc_completion_queue_shutdown(this->shutdown_queue); - grpc_server_destroy(wrapped_server); + grpc_server_destroy(this->wrapped_server); grpc_completion_queue_destroy(this->shutdown_queue); } @@ -139,8 +139,11 @@ void Server::Init(Handle exports) { NanSetPrototypeTemplate(tpl, "start", NanNew(Start)->GetFunction()); - NanSetPrototypeTemplate(tpl, "shutdown", - NanNew(Shutdown)->GetFunction()); + NanSetPrototypeTemplate(tpl, "tryShutdown", + NanNew(TryShutdown)->GetFunction()); + NanSetPrototypeTemplate( + tpl, "forceShutdown", + NanNew(ForceShutdown)->GetFunction()); NanAssignPersistent(fun_tpl, tpl); Handle ctr = tpl->GetFunction(); @@ -153,14 +156,12 @@ bool Server::HasInstance(Handle val) { } void Server::ShutdownServer() { - if (this->wrapped_server != NULL) { - grpc_server_shutdown_and_notify(this->wrapped_server, - this->shutdown_queue, - NULL); - grpc_completion_queue_pluck(this->shutdown_queue, NULL, - gpr_inf_future(GPR_CLOCK_REALTIME), NULL); - this->wrapped_server = NULL; - } + grpc_server_shutdown_and_notify(this->wrapped_server, + this->shutdown_queue, + NULL); + grpc_server_cancel_all_calls(this->wrapped_server); + grpc_completion_queue_pluck(this->shutdown_queue, NULL, + gpr_inf_future(GPR_CLOCK_REALTIME), NULL); } NAN_METHOD(Server::New) { @@ -222,9 +223,6 @@ NAN_METHOD(Server::RequestCall) { return NanThrowTypeError("requestCall can only be called on a Server"); } Server *server = ObjectWrap::Unwrap(args.This()); - if (server->wrapped_server == NULL) { - return NanThrowError("requestCall cannot be called on a shut down Server"); - } NewCallOp *op = new NewCallOp(); unique_ptr ops(new OpVec()); ops->push_back(unique_ptr(op)); @@ -256,10 +254,6 @@ NAN_METHOD(Server::AddHttp2Port) { "addHttp2Port's second argument must be ServerCredentials"); } Server *server = ObjectWrap::Unwrap(args.This()); - if (server->wrapped_server == NULL) { - return NanThrowError( - "addHttp2Port cannot be called on a shut down Server"); - } ServerCredentials *creds_object = ObjectWrap::Unwrap( args[1]->ToObject()); grpc_server_credentials *creds = creds_object->GetWrappedServerCredentials(); @@ -281,21 +275,30 @@ NAN_METHOD(Server::Start) { return NanThrowTypeError("start can only be called on a Server"); } Server *server = ObjectWrap::Unwrap(args.This()); - if (server->wrapped_server == NULL) { - return NanThrowError("start cannot be called on a shut down Server"); - } grpc_server_start(server->wrapped_server); NanReturnUndefined(); } -NAN_METHOD(ShutdownCallback) { +NAN_METHOD(Server::TryShutdown) { + NanScope(); + if (!HasInstance(args.This())) { + return NanThrowTypeError("tryShutdown can only be called on a Server"); + } + Server *server = ObjectWrap::Unwrap(args.This()); + unique_ptr ops(new OpVec()); + grpc_server_shutdown_and_notify( + server->wrapped_server, + CompletionQueueAsyncWorker::GetQueue(), + new struct tag(new NanCallback(args[0].As()), ops.release(), + shared_ptr(nullptr))); + CompletionQueueAsyncWorker::Next(); NanReturnUndefined(); } -NAN_METHOD(Server::Shutdown) { +NAN_METHOD(Server::ForceShutdown) { NanScope(); if (!HasInstance(args.This())) { - return NanThrowTypeError("shutdown can only be called on a Server"); + return NanThrowTypeError("forceShutdown can only be called on a Server"); } Server *server = ObjectWrap::Unwrap(args.This()); server->ShutdownServer(); diff --git a/src/node/ext/server.h b/src/node/ext/server.h index faab7e3418c..e7d5c3fb11a 100644 --- a/src/node/ext/server.h +++ b/src/node/ext/server.h @@ -67,7 +67,8 @@ class Server : public ::node::ObjectWrap { static NAN_METHOD(RequestCall); static NAN_METHOD(AddHttp2Port); static NAN_METHOD(Start); - static NAN_METHOD(Shutdown); + static NAN_METHOD(TryShutdown); + static NAN_METHOD(ForceShutdown); static NanCallback *constructor; static v8::Persistent fun_tpl; diff --git a/src/node/ext/server_credentials.cc b/src/node/ext/server_credentials.cc index 6e17197e160..b1201eb6641 100644 --- a/src/node/ext/server_credentials.cc +++ b/src/node/ext/server_credentials.cc @@ -178,11 +178,8 @@ NAN_METHOD(ServerCredentials::CreateSsl) { key_cert_pairs[i].cert_chain = ::node::Buffer::Data( pair_obj->Get(cert_key)); } - grpc_server_credentials *creds = - grpc_ssl_server_credentials_create(root_certs, - key_cert_pairs, - key_cert_pair_count, - force_client_auth); + grpc_server_credentials *creds = grpc_ssl_server_credentials_create( + root_certs, key_cert_pairs, key_cert_pair_count, force_client_auth, NULL); delete key_cert_pairs; if (creds == NULL) { NanReturnNull(); diff --git a/src/node/src/server.js b/src/node/src/server.js index 5037abae434..137f60ed122 100644 --- a/src/node/src/server.js +++ b/src/node/src/server.js @@ -623,11 +623,26 @@ function Server(options) { } server.requestCall(handleNewCall); }; + + /** + * Gracefully shuts down the server. The server will stop receiving new calls, + * and any pending calls will complete. The callback will be called when all + * pending calls have completed and the server is fully shut down. This method + * is idempotent with itself and forceShutdown. + * @param {function()} callback The shutdown complete callback + */ + this.tryShutdown = function(callback) { + server.tryShutdown(callback); + }; + /** - * Shuts down the server. + * Forcibly shuts down the server. The server will stop receiving new calls + * and cancel all pending calls. When it returns, the server has shut down. + * This method is idempotent with itself and tryShutdown, and it will trigger + * any outstanding tryShutdown callbacks. */ - this.shutdown = function() { - server.shutdown(); + this.forceShutdown = function() { + server.forceShutdown(); }; } diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js index 8d0f20b0747..e7f071bcd53 100644 --- a/src/node/test/call_test.js +++ b/src/node/test/call_test.js @@ -61,7 +61,7 @@ describe('call', function() { channel = new grpc.Channel('localhost:' + port, insecureCreds); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); describe('constructor', function() { it('should reject anything less than 3 arguments', function() { diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js index 7574d98b8af..4b8da3bfb17 100644 --- a/src/node/test/end_to_end_test.js +++ b/src/node/test/end_to_end_test.js @@ -70,7 +70,7 @@ describe('end-to-end', function() { channel = new grpc.Channel('localhost:' + port_num, insecureCreds); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('should start and end a request without error', function(complete) { var done = multiDone(complete, 2); diff --git a/src/node/test/health_test.js b/src/node/test/health_test.js index 04959f5f552..9267bff7ebe 100644 --- a/src/node/test/health_test.js +++ b/src/node/test/health_test.js @@ -57,7 +57,7 @@ describe('Health Checking', function() { grpc.Credentials.createInsecure()); }); after(function() { - healthServer.shutdown(); + healthServer.forceShutdown(); }); it('should say an enabled service is SERVING', function(done) { healthClient.check({service: ''}, function(err, response) { diff --git a/src/node/test/interop_sanity_test.js b/src/node/test/interop_sanity_test.js index 0a5eb29c0c1..2ca07c1d50d 100644 --- a/src/node/test/interop_sanity_test.js +++ b/src/node/test/interop_sanity_test.js @@ -51,7 +51,7 @@ describe('Interop tests', function() { done(); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); // This depends on not using a binary stream it('should pass empty_unary', function(done) { diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js index ef01870a4c1..80b0c5ff2a9 100644 --- a/src/node/test/math_client_test.js +++ b/src/node/test/math_client_test.js @@ -59,7 +59,7 @@ describe('Math client', function() { done(); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('should handle a single request', function(done) { var arg = {dividend: 7, divisor: 4}; diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js index 78bac8da294..1e69d52e583 100644 --- a/src/node/test/server_test.js +++ b/src/node/test/server_test.js @@ -92,7 +92,7 @@ describe('server', function() { server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('should start without error', function() { assert.doesNotThrow(function() { @@ -100,4 +100,33 @@ describe('server', function() { }); }); }); + describe('shutdown', function() { + var server; + beforeEach(function() { + server = new grpc.Server(); + server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); + server.start(); + }); + afterEach(function() { + server.forceShutdown(); + }); + it('tryShutdown should shutdown successfully', function(done) { + server.tryShutdown(done); + }); + it('forceShutdown should shutdown successfully', function() { + server.forceShutdown(); + }); + it('tryShutdown should be idempotent', function(done) { + server.tryShutdown(done); + server.tryShutdown(function() {}); + }); + it('forceShutdown should be idempotent', function() { + server.forceShutdown(); + server.forceShutdown(); + }); + it('forceShutdown should trigger tryShutdown', function(done) { + server.tryShutdown(done); + server.forceShutdown(); + }); + }); }); diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index ec7ed87728d..6e45871fc8e 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -104,7 +104,7 @@ describe('Server.prototype.addProtoService', function() { server = new grpc.Server(); }); afterEach(function() { - server.shutdown(); + server.forceShutdown(); }); it('Should succeed with a single service', function() { assert.doesNotThrow(function() { @@ -148,7 +148,7 @@ describe('Client#$waitForReady', function() { client = new Client('localhost:' + port, grpc.Credentials.createInsecure()); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('should complete when called alone', function(done) { client.$waitForReady(Infinity, function(error) { @@ -203,7 +203,7 @@ describe('Echo service', function() { server.start(); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('should echo the recieved message directly', function(done) { client.echo({value: 'test value', value2: 3}, function(error, response) { @@ -248,7 +248,7 @@ describe('Generic client and server', function() { grpc.Credentials.createInsecure()); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('Should respond with a capitalized string', function(done) { client.capitalize('abc', function(err, response) { @@ -296,7 +296,7 @@ describe('Echo metadata', function() { server.start(); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('with unary call', function(done) { var call = client.unary({}, function(err, data) { @@ -419,7 +419,7 @@ describe('Other conditions', function() { server.start(); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('channel.getTarget should be available', function() { assert.strictEqual(typeof client.channel.getTarget(), 'string'); @@ -681,7 +681,7 @@ describe('Other conditions', function() { }); afterEach(function() { console.log('Shutting down server'); - proxy.shutdown(); + proxy.forceShutdown(); }); describe('Cancellation', function() { it('With a unary call', function(done) { @@ -847,7 +847,7 @@ describe('Cancelling surface client', function() { server.start(); }); after(function() { - server.shutdown(); + server.forceShutdown(); }); it('Should correctly cancel a unary call', function(done) { var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m index 0a54804bb2f..ce166553300 100644 --- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m +++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m @@ -49,7 +49,7 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return. return NULL; } - return grpc_ssl_credentials_create(contentInASCII.bytes, NULL); + return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL); } @implementation GRPCSecureChannel @@ -101,8 +101,9 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) - (instancetype)initWithHost:(NSString *)host credentials:(grpc_credentials *)credentials args:(grpc_channel_args *)args { - return (self = - [super initWithChannel:grpc_secure_channel_create(credentials, host.UTF8String, args)]); + return (self = [super + initWithChannel:grpc_secure_channel_create( + credentials, host.UTF8String, args, NULL)]); } // TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers diff --git a/src/objective-c/README.md b/src/objective-c/README.md index e997b76d14b..6c27657def0 100644 --- a/src/objective-c/README.md +++ b/src/objective-c/README.md @@ -30,7 +30,7 @@ proceed. ## Write your API declaration in proto format For this you can consult the [Protocol Buffers][]' official documentation, or learn from a quick -example [here](https://github.com/grpc/grpc-common#defining-a-service). +example [here](https://github.com/grpc/grpc/tree/master/examples#defining-a-service). ## Integrate a proto library in your project diff --git a/src/objective-c/tests/LocalClearTextTests.m b/src/objective-c/tests/LocalClearTextTests.m index 4317614dd9d..d01fe91afaf 100644 --- a/src/objective-c/tests/LocalClearTextTests.m +++ b/src/objective-c/tests/LocalClearTextTests.m @@ -42,7 +42,7 @@ #import // These tests require a gRPC "RouteGuide" sample server to be running locally. You can compile and -// run one by following the instructions here: https://github.com/grpc/grpc-common/blob/master/cpp/cpptutorial.md#try-it-out +// run one by following the instructions here: https://github.com/grpc/grpc/blob/master/examples/cpp/cpptutorial.md#try-it-out // Be sure to have the C gRPC library installed in your system (for example, by having followed the // instructions at https://github.com/grpc/homebrew-grpc diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c index 7a981675de5..a4313b6bd4c 100644 --- a/src/php/ext/grpc/channel.c +++ b/src/php/ext/grpc/channel.c @@ -169,7 +169,7 @@ PHP_METHOD(Channel, __construct) { } else { gpr_log(GPR_DEBUG, "Initialized secure channel"); channel->wrapped = - grpc_secure_channel_create(creds->wrapped, target, &args); + grpc_secure_channel_create(creds->wrapped, target, &args, NULL); } efree(args.args); } diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c index 01cb94e3aa1..0eba6608bb5 100644 --- a/src/php/ext/grpc/credentials.c +++ b/src/php/ext/grpc/credentials.c @@ -130,7 +130,7 @@ PHP_METHOD(Credentials, createSsl) { } grpc_credentials *creds = grpc_ssl_credentials_create( pem_root_certs, - pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair); + pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL); zval *creds_object = grpc_php_wrap_credentials(creds); RETURN_DESTROY_ZVAL(creds_object); } @@ -160,7 +160,7 @@ PHP_METHOD(Credentials, createComposite) { (wrapped_grpc_credentials *)zend_object_store_get_object( cred2_obj TSRMLS_CC); grpc_credentials *creds = - grpc_composite_credentials_create(cred1->wrapped, cred2->wrapped); + grpc_composite_credentials_create(cred1->wrapped, cred2->wrapped, NULL); zval *creds_object = grpc_php_wrap_credentials(creds); RETURN_DESTROY_ZVAL(creds_object); } @@ -170,7 +170,7 @@ PHP_METHOD(Credentials, createComposite) { * @return Credentials The new GCE credentials object */ PHP_METHOD(Credentials, createGce) { - grpc_credentials *creds = grpc_compute_engine_credentials_create(); + grpc_credentials *creds = grpc_compute_engine_credentials_create(NULL); zval *creds_object = grpc_php_wrap_credentials(creds); RETURN_DESTROY_ZVAL(creds_object); } diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c index e9183c45986..79188246bce 100644 --- a/src/php/ext/grpc/server_credentials.c +++ b/src/php/ext/grpc/server_credentials.c @@ -118,7 +118,7 @@ PHP_METHOD(ServerCredentials, createSsl) { /* TODO: add a force_client_auth field in ServerCredentials and pass it as * the last parameter. */ grpc_server_credentials *creds = grpc_ssl_server_credentials_create( - pem_root_certs, &pem_key_cert_pair, 1, 0); + pem_root_certs, &pem_key_cert_pair, 1, 0, NULL); zval *creds_object = grpc_php_wrap_server_credentials(creds); RETURN_DESTROY_ZVAL(creds_object); } diff --git a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php index 287621d9303..a368dd4ee02 100644 --- a/src/php/tests/generated_code/AbstractGeneratedCodeTest.php +++ b/src/php/tests/generated_code/AbstractGeneratedCodeTest.php @@ -47,6 +47,10 @@ abstract class AbstractGeneratedCodeTest extends PHPUnit_Framework_TestCase { $this->assertTrue(self::$client->waitForReady(250000)); } + public function testGetTarget() { + $this->assertTrue(is_string(self::$client->getTarget())); + } + public function testSimpleRequest() { $div_arg = new math\DivArgs(); $div_arg->setDividend(7); diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php index 376d306da03..bd15ee43031 100755 --- a/src/php/tests/interop/interop_client.php +++ b/src/php/tests/interop/interop_client.php @@ -332,11 +332,7 @@ if (in_array($args['test_case'], array( $opts['update_metadata'] = $auth->getUpdateMetadataFunc(); } -$internal_stub = new Grpc\BaseStub($server_address, $opts); -hardAssert(is_string($internal_stub->getTarget()), - 'Unexpected target URI value'); - -$stub = new grpc\testing\TestServiceClient($internal_stub); +$stub = new grpc\testing\TestServiceClient($server_address, $opts); echo "Connecting to $server_address\n"; echo "Running test case $args[test_case]\n"; @@ -372,6 +368,11 @@ switch ($args['test_case']) { case 'jwt_token_creds': jwtTokenCreds($stub, $args); break; + case 'cancel_after_begin': + // Currently unimplementable with the current API design + // Specifically, in the ClientStreamingCall->start() method, the + // messages are sent immediately after metadata is sent. There is + // currently no way to cancel before messages are sent. default: exit(1); } diff --git a/src/python/README.md b/src/python/README.md index de0142db05e..affce648843 100644 --- a/src/python/README.md +++ b/src/python/README.md @@ -52,9 +52,19 @@ BUILDING FROM SOURCE --------------------- - Clone this repository +- Initialize the git submodules +``` +$ git submodule update --init +``` + +- Make the libraries +``` +$ make +``` + - Use build_python.sh to build the Python code and install it into a virtual environment ``` -$ tools/run_tests/build_python.sh +$ CONFIG=opt tools/run_tests/build_python.sh 2.7 ``` TESTING @@ -62,7 +72,7 @@ TESTING - Use run_python.sh to run gRPC as it was installed into the virtual environment ``` -$ tools/run_tests/run_python.sh +$ CONFIG=opt PYVER=2.7 tools/run_tests/run_python.sh ``` PACKAGING diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c index c577ac05eb0..79d39c4391d 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c +++ b/src/python/grpcio/grpc/_adapter/_c/types/channel.c @@ -106,7 +106,8 @@ Channel *pygrpc_Channel_new( } self = (Channel *)type->tp_alloc(type, 0); if (creds) { - self->c_chan = grpc_secure_channel_create(creds->c_creds, target, &c_args); + self->c_chan = + grpc_secure_channel_create(creds->c_creds, target, &c_args, NULL); } else { self->c_chan = grpc_insecure_channel_create(target, &c_args, NULL); } @@ -164,7 +165,7 @@ PyObject *pygrpc_Channel_watch_connectivity_state( int last_observed_state; CompletionQueue *completion_queue; char *keywords[] = {"last_observed_state", "deadline", - "completion_queue", "tag"}; + "completion_queue", "tag", NULL}; if (!PyArg_ParseTupleAndKeywords( args, kwargs, "idO!O:watch_connectivity_state", keywords, &last_observed_state, &deadline, &pygrpc_CompletionQueue_type, diff --git a/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c index e314c153247..36fd207464b 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c +++ b/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c @@ -135,9 +135,10 @@ ClientCredentials *pygrpc_ClientCredentials_ssl( if (private_key && cert_chain) { key_cert_pair.private_key = private_key; key_cert_pair.cert_chain = cert_chain; - self->c_creds = grpc_ssl_credentials_create(root_certs, &key_cert_pair); + self->c_creds = + grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL); } else { - self->c_creds = grpc_ssl_credentials_create(root_certs, NULL); + self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL); } if (!self->c_creds) { Py_DECREF(self); @@ -159,8 +160,8 @@ ClientCredentials *pygrpc_ClientCredentials_composite( return NULL; } self = (ClientCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_composite_credentials_create( - creds1->c_creds, creds2->c_creds); + self->c_creds = + grpc_composite_credentials_create(creds1->c_creds, creds2->c_creds, NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials"); @@ -172,7 +173,7 @@ ClientCredentials *pygrpc_ClientCredentials_composite( ClientCredentials *pygrpc_ClientCredentials_compute_engine( PyTypeObject *type, PyObject *ignored) { ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_compute_engine_credentials_create(); + self->c_creds = grpc_compute_engine_credentials_create(NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, @@ -195,7 +196,7 @@ ClientCredentials *pygrpc_ClientCredentials_service_account( } self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_service_account_credentials_create( - json_key, scope, pygrpc_cast_double_to_gpr_timespec(lifetime)); + json_key, scope, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, @@ -218,7 +219,7 @@ ClientCredentials *pygrpc_ClientCredentials_jwt( } self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_service_account_jwt_access_credentials_create( - json_key, pygrpc_cast_double_to_gpr_timespec(lifetime)); + json_key, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create JWT credentials"); @@ -237,7 +238,8 @@ ClientCredentials *pygrpc_ClientCredentials_refresh_token( return NULL; } self = (ClientCredentials *)type->tp_alloc(type, 0); - self->c_creds = grpc_refresh_token_credentials_create(json_refresh_token); + self->c_creds = + grpc_refresh_token_credentials_create(json_refresh_token, NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, @@ -259,7 +261,7 @@ ClientCredentials *pygrpc_ClientCredentials_iam( } self = (ClientCredentials *)type->tp_alloc(type, 0); self->c_creds = grpc_iam_credentials_create(authorization_token, - authority_selector); + authority_selector, NULL); if (!self->c_creds) { Py_DECREF(self); PyErr_SetString(PyExc_RuntimeError, "couldn't create IAM credentials"); diff --git a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c index f6859b79d7d..df51a99b6a9 100644 --- a/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c +++ b/src/python/grpcio/grpc/_adapter/_c/types/server_credentials.c @@ -99,11 +99,13 @@ ServerCredentials *pygrpc_ServerCredentials_ssl( const char *root_certs; PyObject *py_key_cert_pairs; grpc_ssl_pem_key_cert_pair *key_cert_pairs; + int force_client_auth; size_t num_key_cert_pairs; size_t i; - static char *keywords[] = {"root_certs", "key_cert_pairs", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zO:ssl", keywords, - &root_certs, &py_key_cert_pairs)) { + static char *keywords[] = { + "root_certs", "key_cert_pairs", "force_client_auth", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zOi:ssl", keywords, + &root_certs, &py_key_cert_pairs, &force_client_auth)) { return NULL; } if (!PyList_Check(py_key_cert_pairs)) { @@ -128,11 +130,8 @@ ServerCredentials *pygrpc_ServerCredentials_ssl( } self = (ServerCredentials *)type->tp_alloc(type, 0); - /* TODO: Add a force_client_auth parameter in the python object and pass it - here as the last arg. */ self->c_creds = grpc_ssl_server_credentials_create( - root_certs, key_cert_pairs, num_key_cert_pairs, 0); + root_certs, key_cert_pairs, num_key_cert_pairs, force_client_auth, NULL); gpr_free(key_cert_pairs); return self; } - diff --git a/src/python/grpcio/grpc/_adapter/_intermediary_low.py b/src/python/grpcio/grpc/_adapter/_intermediary_low.py index e7bf9dc4621..06358e72bc2 100644 --- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py +++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py @@ -255,5 +255,6 @@ class ClientCredentials(object): class ServerCredentials(object): """Adapter from old _low.ServerCredentials interface to new _low.ServerCredentials.""" - def __init__(self, root_credentials, pair_sequence): - self._internal = _low.ServerCredentials.ssl(root_credentials, list(pair_sequence)) + def __init__(self, root_credentials, pair_sequence, force_client_auth): + self._internal = _low.ServerCredentials.ssl( + root_credentials, list(pair_sequence), force_client_auth) diff --git a/src/python/grpcio/grpc/_adapter/fore.py b/src/python/grpcio/grpc/_adapter/fore.py index 7d88bda2631..daa41e8bde5 100644 --- a/src/python/grpcio/grpc/_adapter/fore.py +++ b/src/python/grpcio/grpc/_adapter/fore.py @@ -288,7 +288,7 @@ class ForeLink(base_interfaces.ForeLink, activated.Activated): self._port = self._server.add_http2_addr(address) else: server_credentials = _low.ServerCredentials( - self._root_certificates, self._key_chain_pairs) + self._root_certificates, self._key_chain_pairs, False) self._server = _low.Server(self._completion_queue) self._port = self._server.add_secure_http2_addr( address, server_credentials) diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd index d0653835879..c793774c8d8 100644 --- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd +++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd @@ -332,7 +332,7 @@ cdef extern from "grpc/grpc_security.h": grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, - size_t num_key_cert_pairs); + size_t num_key_cert_pairs) void grpc_server_credentials_release(grpc_server_credentials *creds) int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, diff --git a/src/python/grpcio/grpc/_links/service.py b/src/python/grpcio/grpc/_links/service.py index 43c4c0e80ca..10634e43b5d 100644 --- a/src/python/grpcio/grpc/_links/service.py +++ b/src/python/grpcio/grpc/_links/service.py @@ -366,10 +366,10 @@ class ServiceLink(links.Link): """Adds a port on which to service RPCs after this link has been started. Args: - port: The port on which to service RPCs, or zero to request that a port be - automatically selected and used. - server_credentials: A ServerCredentials object, or None for insecure - service. + port: The port on which to service RPCs, or zero to request that a port + be automatically selected and used. + server_credentials: An _intermediary_low.ServerCredentials object, or + None for insecure service. Returns: A port on which RPCs will be serviced after this link has been started. diff --git a/src/python/grpcio/grpc/beta/__init__.py b/src/python/grpcio/grpc/beta/__init__.py new file mode 100644 index 00000000000..b89398809fa --- /dev/null +++ b/src/python/grpcio/grpc/beta/__init__.py @@ -0,0 +1,28 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/python/grpcio/grpc/beta/_connectivity_channel.py b/src/python/grpcio/grpc/beta/_connectivity_channel.py new file mode 100644 index 00000000000..457ede79f2e --- /dev/null +++ b/src/python/grpcio/grpc/beta/_connectivity_channel.py @@ -0,0 +1,148 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Affords a connectivity-state-listenable channel.""" + +import threading +import time + +from grpc._adapter import _low +from grpc.framework.foundation import callable_util + +_CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = ( + 'Exception calling channel subscription callback!') + + +class ConnectivityChannel(object): + + def __init__(self, low_channel, mapping): + self._lock = threading.Lock() + self._low_channel = low_channel + self._mapping = mapping + + self._polling = False + self._connectivity = None + self._try_to_connect = False + self._callbacks_and_connectivities = [] + self._delivering = False + + def _deliveries(self, connectivity): + callbacks_needing_update = [] + for callback_and_connectivity in self._callbacks_and_connectivities: + callback, callback_connectivity = callback_and_connectivity + if callback_connectivity is not connectivity: + callbacks_needing_update.append(callback) + callback_and_connectivity[1] = connectivity + return callbacks_needing_update + + def _deliver(self, initial_connectivity, initial_callbacks): + connectivity = initial_connectivity + callbacks = initial_callbacks + while True: + for callback in callbacks: + callable_util.call_logging_exceptions( + callback, _CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE, + connectivity) + with self._lock: + callbacks = self._deliveries(self._connectivity) + if callbacks: + connectivity = self._connectivity + else: + self._delivering = False + return + + def _spawn_delivery(self, connectivity, callbacks): + delivering_thread = threading.Thread( + target=self._deliver, args=(connectivity, callbacks,)) + delivering_thread.start() + self._delivering = True + + # TODO(issue 3064): Don't poll. + def _poll_connectivity(self, low_channel, initial_try_to_connect): + try_to_connect = initial_try_to_connect + low_connectivity = low_channel.check_connectivity_state(try_to_connect) + with self._lock: + self._connectivity = self._mapping[low_connectivity] + callbacks = tuple( + callback for callback, unused_but_known_to_be_none_connectivity + in self._callbacks_and_connectivities) + for callback_and_connectivity in self._callbacks_and_connectivities: + callback_and_connectivity[1] = self._connectivity + if callbacks: + self._spawn_delivery(self._connectivity, callbacks) + completion_queue = _low.CompletionQueue() + while True: + low_channel.watch_connectivity_state( + low_connectivity, time.time() + 0.2, completion_queue, None) + event = completion_queue.next() + with self._lock: + if not self._callbacks_and_connectivities and not self._try_to_connect: + self._polling = False + self._connectivity = None + completion_queue.shutdown() + break + try_to_connect = self._try_to_connect + self._try_to_connect = False + if event.success or try_to_connect: + low_connectivity = low_channel.check_connectivity_state(try_to_connect) + with self._lock: + self._connectivity = self._mapping[low_connectivity] + if not self._delivering: + callbacks = self._deliveries(self._connectivity) + if callbacks: + self._spawn_delivery(self._connectivity, callbacks) + + def subscribe(self, callback, try_to_connect): + with self._lock: + if not self._callbacks_and_connectivities and not self._polling: + polling_thread = threading.Thread( + target=self._poll_connectivity, + args=(self._low_channel, bool(try_to_connect))) + polling_thread.start() + self._polling = True + self._callbacks_and_connectivities.append([callback, None]) + elif not self._delivering and self._connectivity is not None: + self._spawn_delivery(self._connectivity, (callback,)) + self._try_to_connect |= bool(try_to_connect) + self._callbacks_and_connectivities.append( + [callback, self._connectivity]) + else: + self._try_to_connect |= bool(try_to_connect) + self._callbacks_and_connectivities.append([callback, None]) + + def unsubscribe(self, callback): + with self._lock: + for index, (subscribed_callback, unused_connectivity) in enumerate( + self._callbacks_and_connectivities): + if callback == subscribed_callback: + self._callbacks_and_connectivities.pop(index) + break + + def low_channel(self): + return self._low_channel diff --git a/src/python/grpcio/grpc/beta/beta.py b/src/python/grpcio/grpc/beta/beta.py new file mode 100644 index 00000000000..40cad5e4868 --- /dev/null +++ b/src/python/grpcio/grpc/beta/beta.py @@ -0,0 +1,114 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Entry points into gRPC Python Beta.""" + +import enum + +from grpc._adapter import _low +from grpc._adapter import _types +from grpc.beta import _connectivity_channel + +_CHANNEL_SUBSCRIPTION_CALLBACK_ERROR_LOG_MESSAGE = ( + 'Exception calling channel subscription callback!') + + +@enum.unique +class ChannelConnectivity(enum.Enum): + """Mirrors grpc_connectivity_state in the gRPC Core. + + Attributes: + IDLE: The channel is idle. + CONNECTING: The channel is connecting. + READY: The channel is ready to conduct RPCs. + TRANSIENT_FAILURE: The channel has seen a failure from which it expects to + recover. + FATAL_FAILURE: The channel has seen a failure from which it cannot recover. + """ + + IDLE = (_types.ConnectivityState.IDLE, 'idle',) + CONNECTING = (_types.ConnectivityState.CONNECTING, 'connecting',) + READY = (_types.ConnectivityState.READY, 'ready',) + TRANSIENT_FAILURE = ( + _types.ConnectivityState.TRANSIENT_FAILURE, 'transient failure',) + FATAL_FAILURE = (_types.ConnectivityState.FATAL_FAILURE, 'fatal failure',) + +_LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY = { + state: connectivity for state, connectivity in zip( + _types.ConnectivityState, ChannelConnectivity) +} + + +class Channel(object): + """A channel to a remote host through which RPCs may be conducted. + + Only the "subscribe" and "unsubscribe" methods are supported for application + use. This class' instance constructor and all other attributes are + unsupported. + """ + + def __init__(self, low_channel): + self._connectivity_channel = _connectivity_channel.ConnectivityChannel( + low_channel, _LOW_CONNECTIVITY_STATE_TO_CHANNEL_CONNECTIVITY) + + def subscribe(self, callback, try_to_connect=None): + """Subscribes to this Channel's connectivity. + + Args: + callback: A callable to be invoked and passed this Channel's connectivity. + The callable will be invoked immediately upon subscription and again for + every change to this Channel's connectivity thereafter until it is + unsubscribed. + try_to_connect: A boolean indicating whether or not this Channel should + attempt to connect if it is not already connected and ready to conduct + RPCs. + """ + self._connectivity_channel.subscribe(callback, try_to_connect) + + def unsubscribe(self, callback): + """Unsubscribes a callback from this Channel's connectivity. + + Args: + callback: A callable previously registered with this Channel from having + been passed to its "subscribe" method. + """ + self._connectivity_channel.unsubscribe(callback) + + +def create_insecure_channel(host, port): + """Creates an insecure Channel to a remote host. + + Args: + host: The name of the remote host to which to connect. + port: The port of the remote host to which to connect. + + Returns: + A Channel to the remote host through which RPCs may be conducted. + """ + return Channel(_low.Channel('%s:%d' % (host, port), ())) diff --git a/src/python/grpcio/grpc/beta/utilities.py b/src/python/grpcio/grpc/beta/utilities.py new file mode 100644 index 00000000000..1b5356e3ad9 --- /dev/null +++ b/src/python/grpcio/grpc/beta/utilities.py @@ -0,0 +1,161 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Utilities for the gRPC Python Beta API.""" + +import threading +import time + +from grpc.beta import beta +from grpc.framework.foundation import callable_util +from grpc.framework.foundation import future + +_DONE_CALLBACK_EXCEPTION_LOG_MESSAGE = ( + 'Exception calling connectivity future "done" callback!') + + +class _ChannelReadyFuture(future.Future): + + def __init__(self, channel): + self._condition = threading.Condition() + self._channel = channel + + self._matured = False + self._cancelled = False + self._done_callbacks = [] + + def _block(self, timeout): + until = None if timeout is None else time.time() + timeout + with self._condition: + while True: + if self._cancelled: + raise future.CancelledError() + elif self._matured: + return + else: + if until is None: + self._condition.wait() + else: + remaining = until - time.time() + if remaining < 0: + raise future.TimeoutError() + else: + self._condition.wait(timeout=remaining) + + def _update(self, connectivity): + with self._condition: + if not self._cancelled and connectivity is beta.ChannelConnectivity.READY: + self._matured = True + self._channel.unsubscribe(self._update) + self._condition.notify_all() + done_callbacks = tuple(self._done_callbacks) + self._done_callbacks = None + else: + return + + for done_callback in done_callbacks: + callable_util.call_logging_exceptions( + done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self) + + def cancel(self): + with self._condition: + if not self._matured: + self._cancelled = True + self._channel.unsubscribe(self._update) + self._condition.notify_all() + done_callbacks = tuple(self._done_callbacks) + self._done_callbacks = None + else: + return False + + for done_callback in done_callbacks: + callable_util.call_logging_exceptions( + done_callback, _DONE_CALLBACK_EXCEPTION_LOG_MESSAGE, self) + + def cancelled(self): + with self._condition: + return self._cancelled + + def running(self): + with self._condition: + return not self._cancelled and not self._matured + + def done(self): + with self._condition: + return self._cancelled or self._matured + + def result(self, timeout=None): + self._block(timeout) + return None + + def exception(self, timeout=None): + self._block(timeout) + return None + + def traceback(self, timeout=None): + self._block(timeout) + return None + + def add_done_callback(self, fn): + with self._condition: + if not self._cancelled and not self._matured: + self._done_callbacks.append(fn) + return + + fn(self) + + def start(self): + with self._condition: + self._channel.subscribe(self._update, try_to_connect=True) + + def __del__(self): + with self._condition: + if not self._cancelled and not self._matured: + self._channel.unsubscribe(self._update) + + +def channel_ready_future(channel): + """Creates a future.Future that matures when a beta.Channel is ready. + + Cancelling the returned future.Future does not tell the given beta.Channel to + abandon attempts it may have been making to connect; cancelling merely + deactivates the return future.Future's subscription to the given + beta.Channel's connectivity. + + Args: + channel: A beta.Channel. + + Returns: + A future.Future that matures when the given Channel has connectivity + beta.ChannelConnectivity.READY. + """ + ready_future = _ChannelReadyFuture(channel) + ready_future.start() + return ready_future + diff --git a/src/python/grpcio/grpc/framework/core/_context.py b/src/python/grpcio/grpc/framework/core/_context.py index 24a12b612e5..76b35345308 100644 --- a/src/python/grpcio/grpc/framework/core/_context.py +++ b/src/python/grpcio/grpc/framework/core/_context.py @@ -60,7 +60,7 @@ class OperationContext(base.OperationContext): with self._lock: if self._termination_manager.outcome is None: self._termination_manager.abort(outcome) - self._transmission_manager.abort(outcome) + self._transmission_manager.abort(outcome, None, None) self._expiration_manager.terminate() def outcome(self): diff --git a/src/python/grpcio/grpc/framework/core/_emission.py b/src/python/grpcio/grpc/framework/core/_emission.py index 7c702ab2ce0..2d7b2e2f100 100644 --- a/src/python/grpcio/grpc/framework/core/_emission.py +++ b/src/python/grpcio/grpc/framework/core/_emission.py @@ -82,7 +82,8 @@ class EmissionManager(_interfaces.EmissionManager): completion_present and self._completion_seen or allowance_present and allowance <= 0): self._termination_manager.abort(base.Outcome.LOCAL_FAILURE) - self._transmission_manager.abort(base.Outcome.LOCAL_FAILURE) + self._transmission_manager.abort( + base.Outcome.LOCAL_FAILURE, None, None) self._expiration_manager.terminate() else: self._initial_metadata_seen |= initial_metadata_present diff --git a/src/python/grpcio/grpc/framework/core/_expiration.py b/src/python/grpcio/grpc/framework/core/_expiration.py index d94bdf2d2b7..d8690b3a02a 100644 --- a/src/python/grpcio/grpc/framework/core/_expiration.py +++ b/src/python/grpcio/grpc/framework/core/_expiration.py @@ -73,7 +73,7 @@ class _ExpirationManager(_interfaces.ExpirationManager): if self._future is not None and index == self._index: self._future = None self._termination_manager.expire() - self._transmission_manager.abort(base.Outcome.EXPIRED) + self._transmission_manager.abort(base.Outcome.EXPIRED, None, None) return expire def start(self): diff --git a/src/python/grpcio/grpc/framework/core/_ingestion.py b/src/python/grpcio/grpc/framework/core/_ingestion.py index 59f7f8adc86..7b8127f3fce 100644 --- a/src/python/grpcio/grpc/framework/core/_ingestion.py +++ b/src/python/grpcio/grpc/framework/core/_ingestion.py @@ -31,6 +31,7 @@ import abc import collections +import enum from grpc.framework.core import _constants from grpc.framework.core import _interfaces @@ -42,21 +43,31 @@ _CREATE_SUBSCRIPTION_EXCEPTION_LOG_MESSAGE = 'Exception initializing ingestion!' _INGESTION_EXCEPTION_LOG_MESSAGE = 'Exception during ingestion!' -class _SubscriptionCreation(collections.namedtuple( - '_SubscriptionCreation', ('subscription', 'remote_error', 'abandoned'))): +class _SubscriptionCreation( + collections.namedtuple( + '_SubscriptionCreation', + ('kind', 'subscription', 'code', 'message',))): """A sum type for the outcome of ingestion initialization. - Either subscription will be non-None, remote_error will be True, or abandoned - will be True. - Attributes: - subscription: A base.Subscription describing the customer's interest in - operation values from the other side. - remote_error: A boolean indicating that the subscription could not be - created due to an error on the remote side of the operation. - abandoned: A boolean indicating that subscription creation was abandoned. + kind: A Kind value coarsely indicating how subscription creation completed. + subscription: The created subscription. Only present if kind is + Kind.SUBSCRIPTION. + code: A code value to be sent to the other side of the operation along with + an indication that the operation is being aborted due to an error on the + remote side of the operation. Only present if kind is Kind.REMOTE_ERROR. + message: A message value to be sent to the other side of the operation + along with an indication that the operation is being aborted due to an + error on the remote side of the operation. Only present if kind is + Kind.REMOTE_ERROR. """ + @enum.unique + class Kind(enum.Enum): + SUBSCRIPTION = 'subscription' + REMOTE_ERROR = 'remote error' + ABANDONED = 'abandoned' + class _SubscriptionCreator(object): """Common specification of subscription-creating behavior.""" @@ -101,12 +112,15 @@ class _ServiceSubscriptionCreator(_SubscriptionCreator): try: subscription = self._servicer.service( group, method, self._operation_context, self._output_operator) - except base.NoSuchMethodError: - return _SubscriptionCreation(None, True, False) + except base.NoSuchMethodError as e: + return _SubscriptionCreation( + _SubscriptionCreation.Kind.REMOTE_ERROR, None, e.code, e.message) except abandonment.Abandoned: - return _SubscriptionCreation(None, False, True) + return _SubscriptionCreation( + _SubscriptionCreation.Kind.ABANDONED, None, None, None) else: - return _SubscriptionCreation(subscription, False, False) + return _SubscriptionCreation( + _SubscriptionCreation.Kind.SUBSCRIPTION, subscription, None, None) def _wrap(behavior): @@ -176,10 +190,10 @@ class _IngestionManager(_interfaces.IngestionManager): self._pending_payloads = None self._pending_completion = None - def _abort_and_notify(self, outcome): + def _abort_and_notify(self, outcome, code, message): self._abort_internal_only() self._termination_manager.abort(outcome) - self._transmission_manager.abort(outcome) + self._transmission_manager.abort(outcome, code, message) self._expiration_manager.terminate() def _operator_next(self): @@ -236,12 +250,12 @@ class _IngestionManager(_interfaces.IngestionManager): else: with self._lock: if self._termination_manager.outcome is None: - self._abort_and_notify(base.Outcome.LOCAL_FAILURE) + self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None) return else: with self._lock: if self._termination_manager.outcome is None: - self._abort_and_notify(base.Outcome.LOCAL_FAILURE) + self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None) return def _operator_post_create(self, subscription): @@ -260,20 +274,22 @@ class _IngestionManager(_interfaces.IngestionManager): def _create(self, subscription_creator, group, name): outcome = callable_util.call_logging_exceptions( - subscription_creator.create, _CREATE_SUBSCRIPTION_EXCEPTION_LOG_MESSAGE, - group, name) + subscription_creator.create, + _CREATE_SUBSCRIPTION_EXCEPTION_LOG_MESSAGE, group, name) if outcome.return_value is None: with self._lock: if self._termination_manager.outcome is None: - self._abort_and_notify(base.Outcome.LOCAL_FAILURE) - elif outcome.return_value.abandoned: + self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None) + elif outcome.return_value.kind is _SubscriptionCreation.Kind.ABANDONED: with self._lock: if self._termination_manager.outcome is None: - self._abort_and_notify(base.Outcome.LOCAL_FAILURE) - elif outcome.return_value.remote_error: + self._abort_and_notify(base.Outcome.LOCAL_FAILURE, None, None) + elif outcome.return_value.kind is _SubscriptionCreation.Kind.REMOTE_ERROR: + code = outcome.return_value.code + message = outcome.return_value.message with self._lock: if self._termination_manager.outcome is None: - self._abort_and_notify(base.Outcome.REMOTE_FAILURE) + self._abort_and_notify(base.Outcome.REMOTE_FAILURE, code, message) elif outcome.return_value.subscription.kind is base.Subscription.Kind.FULL: self._operator_post_create(outcome.return_value.subscription) else: diff --git a/src/python/grpcio/grpc/framework/core/_interfaces.py b/src/python/grpcio/grpc/framework/core/_interfaces.py index a626b9f7679..deb5f34f9b4 100644 --- a/src/python/grpcio/grpc/framework/core/_interfaces.py +++ b/src/python/grpcio/grpc/framework/core/_interfaces.py @@ -155,13 +155,19 @@ class TransmissionManager(object): raise NotImplementedError() @abc.abstractmethod - def abort(self, outcome): + def abort(self, outcome, code, message): """Indicates that the operation has aborted. Args: outcome: An interfaces.Outcome for the operation. If None, indicates that the operation abortion should not be communicated to the other side of the operation. + code: A code value to communicate to the other side of the operation + along with indication of operation abortion. May be None, and has no + effect if outcome is None. + message: A message value to communicate to the other side of the + operation along with indication of operation abortion. May be None, and + has no effect if outcome is None. """ raise NotImplementedError() diff --git a/src/python/grpcio/grpc/framework/core/_operation.py b/src/python/grpcio/grpc/framework/core/_operation.py index d20e40a53da..cc873c03f93 100644 --- a/src/python/grpcio/grpc/framework/core/_operation.py +++ b/src/python/grpcio/grpc/framework/core/_operation.py @@ -79,7 +79,7 @@ class _EasyOperation(_interfaces.Operation): with self._lock: if self._termination_manager.outcome is None: self._termination_manager.abort(outcome) - self._transmission_manager.abort(outcome) + self._transmission_manager.abort(outcome, None, None) self._expiration_manager.terminate() diff --git a/src/python/grpcio/grpc/framework/core/_reception.py b/src/python/grpcio/grpc/framework/core/_reception.py index 0858f64ff6b..1cebe3874ba 100644 --- a/src/python/grpcio/grpc/framework/core/_reception.py +++ b/src/python/grpcio/grpc/framework/core/_reception.py @@ -73,7 +73,7 @@ class ReceptionManager(_interfaces.ReceptionManager): self._aborted = True if self._termination_manager.outcome is None: self._termination_manager.abort(outcome) - self._transmission_manager.abort(None) + self._transmission_manager.abort(None, None, None) self._expiration_manager.terminate() def _sequence_failure(self, ticket): diff --git a/src/python/grpcio/grpc/framework/core/_transmission.py b/src/python/grpcio/grpc/framework/core/_transmission.py index 03644f4d491..efef87dd4c6 100644 --- a/src/python/grpcio/grpc/framework/core/_transmission.py +++ b/src/python/grpcio/grpc/framework/core/_transmission.py @@ -104,9 +104,13 @@ class TransmissionManager(_interfaces.TransmissionManager): return None else: self._abortion_outcome = None + if self._completion is None: + code, message = None, None + else: + code, message = self._completion.code, self._completion.message return links.Ticket( self._operation_id, self._lowest_unused_sequence_number, None, - None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, code, message, termination, None) action = False @@ -277,7 +281,7 @@ class TransmissionManager(_interfaces.TransmissionManager): self._remote_complete = True self._local_allowance = 0 - def abort(self, outcome): + def abort(self, outcome, code, message): """See _interfaces.TransmissionManager.abort for specification.""" if self._transmitting: self._aborted, self._abortion_outcome = True, outcome @@ -287,8 +291,12 @@ class TransmissionManager(_interfaces.TransmissionManager): termination = _constants.ABORTION_OUTCOME_TO_TICKET_TERMINATION[ outcome] if termination is not None: + if self._completion is None: + code, message = None, None + else: + code, message = self._completion.code, self._completion.message ticket = links.Ticket( self._operation_id, self._lowest_unused_sequence_number, None, - None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, code, message, termination, None) self._transmit(ticket) diff --git a/src/python/grpcio/grpc/framework/crust/__init__.py b/src/python/grpcio/grpc/framework/crust/__init__.py new file mode 100644 index 00000000000..70865191060 --- /dev/null +++ b/src/python/grpcio/grpc/framework/crust/__init__.py @@ -0,0 +1,30 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + diff --git a/src/python/grpcio/grpc/framework/crust/_calls.py b/src/python/grpcio/grpc/framework/crust/_calls.py new file mode 100644 index 00000000000..f9077bedfe1 --- /dev/null +++ b/src/python/grpcio/grpc/framework/crust/_calls.py @@ -0,0 +1,204 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Utility functions for invoking RPCs.""" + +from grpc.framework.crust import _control +from grpc.framework.interfaces.base import utilities +from grpc.framework.interfaces.face import face + +_ITERATOR_EXCEPTION_LOG_MESSAGE = 'Exception iterating over requests!' + +_EMPTY_COMPLETION = utilities.completion(None, None, None) + + +def _invoke(end, group, method, timeout, initial_metadata, payload, complete): + rendezvous = _control.Rendezvous(None, None) + operation_context, operator = end.operate( + group, method, utilities.full_subscription(rendezvous), timeout, + initial_metadata=initial_metadata, payload=payload, + completion=_EMPTY_COMPLETION if complete else None) + rendezvous.set_operator_and_context(operator, operation_context) + outcome = operation_context.add_termination_callback(rendezvous.set_outcome) + if outcome is not None: + rendezvous.set_outcome(outcome) + return rendezvous, operation_context, outcome + + +def _event_return_unary( + receiver, abortion_callback, rendezvous, operation_context, outcome, pool): + if outcome is None: + def in_pool(): + abortion = rendezvous.add_abortion_callback(abortion_callback) + if abortion is None: + try: + receiver.initial_metadata(rendezvous.initial_metadata()) + receiver.response(next(rendezvous)) + receiver.complete( + rendezvous.terminal_metadata(), rendezvous.code(), + rendezvous.details()) + except face.AbortionError: + pass + else: + abortion_callback(abortion) + pool.submit(_control.pool_wrap(in_pool, operation_context)) + return rendezvous + + +def _event_return_stream( + receiver, abortion_callback, rendezvous, operation_context, outcome, pool): + if outcome is None: + def in_pool(): + abortion = rendezvous.add_abortion_callback(abortion_callback) + if abortion is None: + try: + receiver.initial_metadata(rendezvous.initial_metadata()) + for response in rendezvous: + receiver.response(response) + receiver.complete( + rendezvous.terminal_metadata(), rendezvous.code(), + rendezvous.details()) + except face.AbortionError: + pass + else: + abortion_callback(abortion) + pool.submit(_control.pool_wrap(in_pool, operation_context)) + return rendezvous + + +def blocking_unary_unary( + end, group, method, timeout, with_call, initial_metadata, payload): + """Services in a blocking fashion a unary-unary servicer method.""" + rendezvous, unused_operation_context, unused_outcome = _invoke( + end, group, method, timeout, initial_metadata, payload, True) + if with_call: + return next(rendezvous, rendezvous) + else: + return next(rendezvous) + + +def future_unary_unary(end, group, method, timeout, initial_metadata, payload): + """Services a value-in value-out servicer method by returning a Future.""" + rendezvous, unused_operation_context, unused_outcome = _invoke( + end, group, method, timeout, initial_metadata, payload, True) + return rendezvous + + +def inline_unary_stream(end, group, method, timeout, initial_metadata, payload): + """Services a value-in stream-out servicer method.""" + rendezvous, unused_operation_context, unused_outcome = _invoke( + end, group, method, timeout, initial_metadata, payload, True) + return rendezvous + + +def blocking_stream_unary( + end, group, method, timeout, with_call, initial_metadata, payload_iterator, + pool): + """Services in a blocking fashion a stream-in value-out servicer method.""" + rendezvous, operation_context, outcome = _invoke( + end, group, method, timeout, initial_metadata, None, False) + if outcome is None: + def in_pool(): + for payload in payload_iterator: + rendezvous.consume(payload) + rendezvous.terminate() + pool.submit(_control.pool_wrap(in_pool, operation_context)) + if with_call: + return next(rendezvous), rendezvous + else: + return next(rendezvous) + else: + if with_call: + return next(rendezvous), rendezvous + else: + return next(rendezvous) + + +def future_stream_unary( + end, group, method, timeout, initial_metadata, payload_iterator, pool): + """Services a stream-in value-out servicer method by returning a Future.""" + rendezvous, operation_context, outcome = _invoke( + end, group, method, timeout, initial_metadata, None, False) + if outcome is None: + def in_pool(): + for payload in payload_iterator: + rendezvous.consume(payload) + rendezvous.terminate() + pool.submit(_control.pool_wrap(in_pool, operation_context)) + return rendezvous + + +def inline_stream_stream( + end, group, method, timeout, initial_metadata, payload_iterator, pool): + """Services a stream-in stream-out servicer method.""" + rendezvous, operation_context, outcome = _invoke( + end, group, method, timeout, initial_metadata, None, False) + if outcome is None: + def in_pool(): + for payload in payload_iterator: + rendezvous.consume(payload) + rendezvous.terminate() + pool.submit(_control.pool_wrap(in_pool, operation_context)) + return rendezvous + + +def event_unary_unary( + end, group, method, timeout, initial_metadata, payload, receiver, + abortion_callback, pool): + rendezvous, operation_context, outcome = _invoke( + end, group, method, timeout, initial_metadata, payload, True) + return _event_return_unary( + receiver, abortion_callback, rendezvous, operation_context, outcome, pool) + + +def event_unary_stream( + end, group, method, timeout, initial_metadata, payload, + receiver, abortion_callback, pool): + rendezvous, operation_context, outcome = _invoke( + end, group, method, timeout, initial_metadata, payload, True) + return _event_return_stream( + receiver, abortion_callback, rendezvous, operation_context, outcome, pool) + + +def event_stream_unary( + end, group, method, timeout, initial_metadata, receiver, abortion_callback, + pool): + rendezvous, operation_context, outcome = _invoke( + end, group, method, timeout, initial_metadata, None, False) + return _event_return_unary( + receiver, abortion_callback, rendezvous, operation_context, outcome, pool) + + +def event_stream_stream( + end, group, method, timeout, initial_metadata, receiver, abortion_callback, + pool): + rendezvous, operation_context, outcome = _invoke( + end, group, method, timeout, initial_metadata, None, False) + return _event_return_stream( + receiver, abortion_callback, rendezvous, operation_context, outcome, pool) diff --git a/src/python/grpcio/grpc/framework/crust/_control.py b/src/python/grpcio/grpc/framework/crust/_control.py new file mode 100644 index 00000000000..01de3c15bd1 --- /dev/null +++ b/src/python/grpcio/grpc/framework/crust/_control.py @@ -0,0 +1,545 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""State and behavior for translating between sync and async control flow.""" + +import collections +import enum +import sys +import threading +import time + +from grpc.framework.foundation import abandonment +from grpc.framework.foundation import callable_util +from grpc.framework.foundation import future +from grpc.framework.foundation import stream +from grpc.framework.interfaces.base import base +from grpc.framework.interfaces.base import utilities +from grpc.framework.interfaces.face import face + +_DONE_CALLBACK_LOG_MESSAGE = 'Exception calling Future "done" callback!' +_INTERNAL_ERROR_LOG_MESSAGE = ':-( RPC Framework (Crust) Internal Error! )-:' + +_CANNOT_SET_INITIAL_METADATA = ( + 'Could not set initial metadata - has it already been set, or has a ' + + 'payload already been sent?') +_CANNOT_SET_TERMINAL_METADATA = ( + 'Could not set terminal metadata - has it already been set, or has RPC ' + + 'completion already been indicated?') +_CANNOT_SET_CODE = ( + 'Could not set code - has it already been set, or has RPC completion ' + + 'already been indicated?') +_CANNOT_SET_DETAILS = ( + 'Could not set details - has it already been set, or has RPC completion ' + + 'already been indicated?') + + +class _DummyOperator(base.Operator): + + def advance( + self, initial_metadata=None, payload=None, completion=None, + allowance=None): + pass + +_DUMMY_OPERATOR = _DummyOperator() + + +class _Awaited( + collections.namedtuple('_Awaited', ('kind', 'value',))): + + @enum.unique + class Kind(enum.Enum): + NOT_YET_ARRIVED = 'not yet arrived' + ARRIVED = 'arrived' + +_NOT_YET_ARRIVED = _Awaited(_Awaited.Kind.NOT_YET_ARRIVED, None) +_ARRIVED_AND_NONE = _Awaited(_Awaited.Kind.ARRIVED, None) + + +class _Transitory( + collections.namedtuple('_Transitory', ('kind', 'value',))): + + @enum.unique + class Kind(enum.Enum): + NOT_YET_SEEN = 'not yet seen' + PRESENT = 'present' + GONE = 'gone' + +_NOT_YET_SEEN = _Transitory(_Transitory.Kind.NOT_YET_SEEN, None) +_GONE = _Transitory(_Transitory.Kind.GONE, None) + + +class _Termination( + collections.namedtuple( + '_Termination', ('terminated', 'abortion', 'abortion_error',))): + """Values indicating whether and how an RPC has terminated. + + Attributes: + terminated: A boolean indicating whether or not the RPC has terminated. + abortion: A face.Abortion value describing the RPC's abortion or None if the + RPC did not abort. + abortion_error: A face.AbortionError describing the RPC's abortion or None + if the RPC did not abort. + """ + +_NOT_TERMINATED = _Termination(False, None, None) + +_OPERATION_OUTCOME_TO_TERMINATION_CONSTRUCTOR = { + base.Outcome.COMPLETED: lambda *unused_args: _Termination(True, None, None), + base.Outcome.CANCELLED: lambda *args: _Termination( + True, face.Abortion(face.Abortion.Kind.CANCELLED, *args), + face.CancellationError(*args)), + base.Outcome.EXPIRED: lambda *args: _Termination( + True, face.Abortion(face.Abortion.Kind.EXPIRED, *args), + face.ExpirationError(*args)), + base.Outcome.LOCAL_SHUTDOWN: lambda *args: _Termination( + True, face.Abortion(face.Abortion.Kind.LOCAL_SHUTDOWN, *args), + face.LocalShutdownError(*args)), + base.Outcome.REMOTE_SHUTDOWN: lambda *args: _Termination( + True, face.Abortion(face.Abortion.Kind.REMOTE_SHUTDOWN, *args), + face.RemoteShutdownError(*args)), + base.Outcome.RECEPTION_FAILURE: lambda *args: _Termination( + True, face.Abortion(face.Abortion.Kind.NETWORK_FAILURE, *args), + face.NetworkError(*args)), + base.Outcome.TRANSMISSION_FAILURE: lambda *args: _Termination( + True, face.Abortion(face.Abortion.Kind.NETWORK_FAILURE, *args), + face.NetworkError(*args)), + base.Outcome.LOCAL_FAILURE: lambda *args: _Termination( + True, face.Abortion(face.Abortion.Kind.LOCAL_FAILURE, *args), + face.LocalError(*args)), + base.Outcome.REMOTE_FAILURE: lambda *args: _Termination( + True, face.Abortion(face.Abortion.Kind.REMOTE_FAILURE, *args), + face.RemoteError(*args)), +} + + +def _wait_once_until(condition, until): + if until is None: + condition.wait() + else: + remaining = until - time.time() + if remaining < 0: + raise future.TimeoutError() + else: + condition.wait(timeout=remaining) + + +def _done_callback_as_operation_termination_callback( + done_callback, rendezvous): + def operation_termination_callback(operation_outcome): + rendezvous.set_outcome(operation_outcome) + done_callback(rendezvous) + return operation_termination_callback + + +def _abortion_callback_as_operation_termination_callback( + rpc_abortion_callback, rendezvous_set_outcome): + def operation_termination_callback(operation_outcome): + termination = rendezvous_set_outcome(operation_outcome) + if termination.abortion is not None: + rpc_abortion_callback(termination.abortion) + return operation_termination_callback + + +class Rendezvous(base.Operator, future.Future, stream.Consumer, face.Call): + """A rendez-vous for the threads of an operation. + + Instances of this object present iterator and stream.Consumer interfaces for + interacting with application code and present a base.Operator interface and + maintain a base.Operator internally for interacting with base interface code. + """ + + def __init__(self, operator, operation_context): + self._condition = threading.Condition() + + self._operator = operator + self._operation_context = operation_context + + self._up_initial_metadata = _NOT_YET_ARRIVED + self._up_payload = None + self._up_allowance = 1 + self._up_completion = _NOT_YET_ARRIVED + self._down_initial_metadata = _NOT_YET_SEEN + self._down_payload = None + self._down_allowance = 1 + self._down_terminal_metadata = _NOT_YET_SEEN + self._down_code = _NOT_YET_SEEN + self._down_details = _NOT_YET_SEEN + + self._termination = _NOT_TERMINATED + + # The semantics of future.Future.cancel and future.Future.cancelled are + # slightly wonky, so they have to be tracked separately from the rest of the + # result of the RPC. This field tracks whether cancellation was requested + # prior to termination of the RPC + self._cancelled = False + + def set_operator_and_context(self, operator, operation_context): + with self._condition: + self._operator = operator + self._operation_context = operation_context + + def _down_completion(self): + if self._down_terminal_metadata.kind is _Transitory.Kind.NOT_YET_SEEN: + terminal_metadata = None + self._down_terminal_metadata = _GONE + elif self._down_terminal_metadata.kind is _Transitory.Kind.PRESENT: + terminal_metadata = self._down_terminal_metadata.value + self._down_terminal_metadata = _GONE + else: + terminal_metadata = None + if self._down_code.kind is _Transitory.Kind.NOT_YET_SEEN: + code = None + self._down_code = _GONE + elif self._down_code.kind is _Transitory.Kind.PRESENT: + code = self._down_code.value + self._down_code = _GONE + else: + code = None + if self._down_details.kind is _Transitory.Kind.NOT_YET_SEEN: + details = None + self._down_details = _GONE + elif self._down_details.kind is _Transitory.Kind.PRESENT: + details = self._down_details.value + self._down_details = _GONE + else: + details = None + return utilities.completion(terminal_metadata, code, details) + + def _set_outcome(self, outcome): + if not self._termination.terminated: + self._operator = _DUMMY_OPERATOR + self._operation_context = None + self._down_initial_metadata = _GONE + self._down_payload = None + self._down_terminal_metadata = _GONE + self._down_code = _GONE + self._down_details = _GONE + + if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED: + initial_metadata = None + else: + initial_metadata = self._up_initial_metadata.value + if self._up_completion.kind is _Awaited.Kind.NOT_YET_ARRIVED: + terminal_metadata, code, details = None, None, None + else: + terminal_metadata = self._up_completion.value.terminal_metadata + code = self._up_completion.value.code + details = self._up_completion.value.message + self._termination = _OPERATION_OUTCOME_TO_TERMINATION_CONSTRUCTOR[ + outcome](initial_metadata, terminal_metadata, code, details) + + self._condition.notify_all() + + return self._termination + + def advance( + self, initial_metadata=None, payload=None, completion=None, + allowance=None): + with self._condition: + if initial_metadata is not None: + self._up_initial_metadata = _Awaited( + _Awaited.Kind.ARRIVED, initial_metadata) + if payload is not None: + if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED: + self._up_initial_metadata = _ARRIVED_AND_NONE + self._up_payload = payload + self._up_allowance -= 1 + if completion is not None: + if self._up_initial_metadata.kind is _Awaited.Kind.NOT_YET_ARRIVED: + self._up_initial_metadata = _ARRIVED_AND_NONE + self._up_completion = _Awaited( + _Awaited.Kind.ARRIVED, completion) + if allowance is not None: + if self._down_payload is not None: + self._operator.advance(payload=self._down_payload) + self._down_payload = None + self._down_allowance += allowance - 1 + else: + self._down_allowance += allowance + self._condition.notify_all() + + def cancel(self): + with self._condition: + if self._operation_context is not None: + self._operation_context.cancel() + self._cancelled = True + return False + + def cancelled(self): + with self._condition: + return self._cancelled + + def running(self): + with self._condition: + return not self._termination.terminated + + def done(self): + with self._condition: + return self._termination.terminated + + def result(self, timeout=None): + until = None if timeout is None else time.time() + timeout + with self._condition: + while True: + if self._termination.terminated: + if self._termination.abortion is None: + return self._up_payload + elif self._termination.abortion.kind is face.Abortion.Kind.CANCELLED: + raise future.CancelledError() + else: + raise self._termination.abortion_error # pylint: disable=raising-bad-type + else: + _wait_once_until(self._condition, until) + + def exception(self, timeout=None): + until = None if timeout is None else time.time() + timeout + with self._condition: + while True: + if self._termination.terminated: + if self._termination.abortion is None: + return None + else: + return self._termination.abortion_error + else: + _wait_once_until(self._condition, until) + + def traceback(self, timeout=None): + until = None if timeout is None else time.time() + timeout + with self._condition: + while True: + if self._termination.terminated: + if self._termination.abortion_error is None: + return None + else: + abortion_error = self._termination.abortion_error + break + else: + _wait_once_until(self._condition, until) + + try: + raise abortion_error + except face.AbortionError: + return sys.exc_info()[2] + + def add_done_callback(self, fn): + with self._condition: + if self._operation_context is not None: + outcome = self._operation_context.add_termination_callback( + _done_callback_as_operation_termination_callback(fn, self)) + if outcome is None: + return + else: + self._set_outcome(outcome) + + fn(self) + + def consume(self, value): + with self._condition: + while True: + if self._termination.terminated: + return + elif 0 < self._down_allowance: + self._operator.advance(payload=value) + self._down_allowance -= 1 + return + else: + self._condition.wait() + + def terminate(self): + with self._condition: + if self._termination.terminated: + return + elif self._down_code.kind is _Transitory.Kind.GONE: + # Conform to specified idempotence of terminate by ignoring extra calls. + return + else: + completion = self._down_completion() + self._operator.advance(completion=completion) + + def consume_and_terminate(self, value): + with self._condition: + while True: + if self._termination.terminated: + return + elif 0 < self._down_allowance: + completion = self._down_completion() + self._operator.advance(payload=value, completion=completion) + return + else: + self._condition.wait() + + def __iter__(self): + return self + + def next(self): + with self._condition: + while True: + if self._termination.abortion_error is not None: + raise self._termination.abortion_error + elif self._up_payload is not None: + payload = self._up_payload + self._up_payload = None + if self._up_completion.kind is _Awaited.Kind.NOT_YET_ARRIVED: + self._operator.advance(allowance=1) + return payload + elif self._up_completion.kind is _Awaited.Kind.ARRIVED: + raise StopIteration() + else: + self._condition.wait() + + def is_active(self): + with self._condition: + return not self._termination.terminated + + def time_remaining(self): + if self._operation_context is None: + return 0 + else: + return self._operation_context.time_remaining() + + def add_abortion_callback(self, abortion_callback): + with self._condition: + if self._operation_context is None: + return self._termination.abortion + else: + outcome = self._operation_context.add_termination_callback( + _abortion_callback_as_operation_termination_callback( + abortion_callback, self.set_outcome)) + if outcome is not None: + return self._set_outcome(outcome).abortion + else: + return self._termination.abortion + + def initial_metadata(self): + with self._condition: + while True: + if self._up_initial_metadata.kind is _Awaited.Kind.ARRIVED: + return self._up_initial_metadata.value + elif self._termination.terminated: + return None + else: + self._condition.wait() + + def terminal_metadata(self): + with self._condition: + while True: + if self._up_completion.kind is _Awaited.Kind.ARRIVED: + return self._up_completion.value.terminal_metadata + elif self._termination.terminated: + return None + else: + self._condition.wait() + + def code(self): + with self._condition: + while True: + if self._up_completion.kind is _Awaited.Kind.ARRIVED: + return self._up_completion.value.code + elif self._termination.terminated: + return None + else: + self._condition.wait() + + def details(self): + with self._condition: + while True: + if self._up_completion.kind is _Awaited.Kind.ARRIVED: + return self._up_completion.value.message + elif self._termination.terminated: + return None + else: + self._condition.wait() + + def set_initial_metadata(self, initial_metadata): + with self._condition: + if (self._down_initial_metadata.kind is not + _Transitory.Kind.NOT_YET_SEEN): + raise ValueError(_CANNOT_SET_INITIAL_METADATA) + else: + self._down_initial_metadata = _GONE + self._operator.advance(initial_metadata=initial_metadata) + + def set_terminal_metadata(self, terminal_metadata): + with self._condition: + if (self._down_terminal_metadata.kind is not + _Transitory.Kind.NOT_YET_SEEN): + raise ValueError(_CANNOT_SET_TERMINAL_METADATA) + else: + self._down_terminal_metadata = _Transitory( + _Transitory.Kind.PRESENT, terminal_metadata) + + def set_code(self, code): + with self._condition: + if self._down_code.kind is not _Transitory.Kind.NOT_YET_SEEN: + raise ValueError(_CANNOT_SET_CODE) + else: + self._down_code = _Transitory(_Transitory.Kind.PRESENT, code) + + def set_details(self, details): + with self._condition: + if self._down_details.kind is not _Transitory.Kind.NOT_YET_SEEN: + raise ValueError(_CANNOT_SET_DETAILS) + else: + self._down_details = _Transitory(_Transitory.Kind.PRESENT, details) + + def set_outcome(self, outcome): + with self._condition: + return self._set_outcome(outcome) + + +def pool_wrap(behavior, operation_context): + """Wraps an operation-related behavior so that it may be called in a pool. + + Args: + behavior: A callable related to carrying out an operation. + operation_context: A base_interfaces.OperationContext for the operation. + + Returns: + A callable that when called carries out the behavior of the given callable + and handles whatever exceptions it raises appropriately. + """ + def translation(*args): + try: + behavior(*args) + except ( + abandonment.Abandoned, + face.CancellationError, + face.ExpirationError, + face.LocalShutdownError, + face.RemoteShutdownError, + face.NetworkError, + face.RemoteError, + ) as e: + if operation_context.outcome() is None: + operation_context.fail(e) + except Exception as e: + operation_context.fail(e) + return callable_util.with_exceptions_logged( + translation, _INTERNAL_ERROR_LOG_MESSAGE) diff --git a/src/python/grpcio/grpc/framework/crust/_service.py b/src/python/grpcio/grpc/framework/crust/_service.py new file mode 100644 index 00000000000..2455a58f59a --- /dev/null +++ b/src/python/grpcio/grpc/framework/crust/_service.py @@ -0,0 +1,166 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Behaviors for servicing RPCs.""" + +from grpc.framework.crust import _control +from grpc.framework.foundation import abandonment +from grpc.framework.interfaces.base import utilities +from grpc.framework.interfaces.face import face + + +class _ServicerContext(face.ServicerContext): + + def __init__(self, rendezvous): + self._rendezvous = rendezvous + + def is_active(self): + return self._rendezvous.is_active() + + def time_remaining(self): + return self._rendezvous.time_remaining() + + def add_abortion_callback(self, abortion_callback): + return self._rendezvous.add_abortion_callback(abortion_callback) + + def cancel(self): + self._rendezvous.cancel() + + def invocation_metadata(self): + return self._rendezvous.initial_metadata() + + def initial_metadata(self, initial_metadata): + self._rendezvous.set_initial_metadata(initial_metadata) + + def terminal_metadata(self, terminal_metadata): + self._rendezvous.set_terminal_metadata(terminal_metadata) + + def code(self, code): + self._rendezvous.set_code(code) + + def details(self, details): + self._rendezvous.set_details(details) + + +def _adaptation(pool, in_pool): + def adaptation(operator, operation_context): + rendezvous = _control.Rendezvous(operator, operation_context) + outcome = operation_context.add_termination_callback(rendezvous.set_outcome) + if outcome is None: + pool.submit(_control.pool_wrap(in_pool, operation_context), rendezvous) + return utilities.full_subscription(rendezvous) + else: + raise abandonment.Abandoned() + return adaptation + + +def adapt_inline_unary_unary(method, pool): + def in_pool(rendezvous): + request = next(rendezvous) + response = method(request, _ServicerContext(rendezvous)) + rendezvous.consume_and_terminate(response) + return _adaptation(pool, in_pool) + + +def adapt_inline_unary_stream(method, pool): + def in_pool(rendezvous): + request = next(rendezvous) + response_iterator = method(request, _ServicerContext(rendezvous)) + for response in response_iterator: + rendezvous.consume(response) + rendezvous.terminate() + return _adaptation(pool, in_pool) + + +def adapt_inline_stream_unary(method, pool): + def in_pool(rendezvous): + response = method(rendezvous, _ServicerContext(rendezvous)) + rendezvous.consume_and_terminate(response) + return _adaptation(pool, in_pool) + + +def adapt_inline_stream_stream(method, pool): + def in_pool(rendezvous): + response_iterator = method(rendezvous, _ServicerContext(rendezvous)) + for response in response_iterator: + rendezvous.consume(response) + rendezvous.terminate() + return _adaptation(pool, in_pool) + + +def adapt_event_unary_unary(method, pool): + def in_pool(rendezvous): + request = next(rendezvous) + method( + request, rendezvous.consume_and_terminate, _ServicerContext(rendezvous)) + return _adaptation(pool, in_pool) + + +def adapt_event_unary_stream(method, pool): + def in_pool(rendezvous): + request = next(rendezvous) + method(request, rendezvous, _ServicerContext(rendezvous)) + return _adaptation(pool, in_pool) + + +def adapt_event_stream_unary(method, pool): + def in_pool(rendezvous): + request_consumer = method( + rendezvous.consume_and_terminate, _ServicerContext(rendezvous)) + for request in rendezvous: + request_consumer.consume(request) + request_consumer.terminate() + return _adaptation(pool, in_pool) + + +def adapt_event_stream_stream(method, pool): + def in_pool(rendezvous): + request_consumer = method(rendezvous, _ServicerContext(rendezvous)) + for request in rendezvous: + request_consumer.consume(request) + request_consumer.terminate() + return _adaptation(pool, in_pool) + + +def adapt_multi_method(multi_method, pool): + def adaptation(group, method, operator, operation_context): + rendezvous = _control.Rendezvous(operator, operation_context) + outcome = operation_context.add_termination_callback(rendezvous.set_outcome) + if outcome is None: + def in_pool(): + request_consumer = multi_method( + group, method, rendezvous, _ServicerContext(rendezvous)) + for request in rendezvous: + request_consumer.consume(request) + request_consumer.terminate() + pool.submit(_control.pool_wrap(in_pool, operation_context), rendezvous) + return utilities.full_subscription(rendezvous) + else: + raise abandonment.Abandoned() + return adaptation diff --git a/src/python/grpcio/grpc/framework/crust/implementations.py b/src/python/grpcio/grpc/framework/crust/implementations.py new file mode 100644 index 00000000000..12f7e796419 --- /dev/null +++ b/src/python/grpcio/grpc/framework/crust/implementations.py @@ -0,0 +1,352 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Entry points into the Crust layer of RPC Framework.""" + +from grpc.framework.common import cardinality +from grpc.framework.common import style +from grpc.framework.crust import _calls +from grpc.framework.crust import _service +from grpc.framework.interfaces.base import base +from grpc.framework.interfaces.face import face + + +class _BaseServicer(base.Servicer): + + def __init__(self, adapted_methods, adapted_multi_method): + self._adapted_methods = adapted_methods + self._adapted_multi_method = adapted_multi_method + + def service(self, group, method, context, output_operator): + adapted_method = self._adapted_methods.get((group, method), None) + if adapted_method is not None: + return adapted_method(output_operator, context) + elif self._adapted_multi_method is not None: + try: + return self._adapted_multi_method.service( + group, method, output_operator, context) + except face.NoSuchMethodError: + raise base.NoSuchMethodError() + else: + raise base.NoSuchMethodError() + + +class _UnaryUnaryMultiCallable(face.UnaryUnaryMultiCallable): + + def __init__(self, end, group, method, pool): + self._end = end + self._group = group + self._method = method + self._pool = pool + + def __call__( + self, request, timeout, metadata=None, with_call=False): + return _calls.blocking_unary_unary( + self._end, self._group, self._method, timeout, with_call, + metadata, request) + + def future(self, request, timeout, metadata=None): + return _calls.future_unary_unary( + self._end, self._group, self._method, timeout, metadata, + request) + + def event( + self, request, receiver, abortion_callback, timeout, + metadata=None): + return _calls.event_unary_unary( + self._end, self._group, self._method, timeout, metadata, + request, receiver, abortion_callback, self._pool) + + +class _UnaryStreamMultiCallable(face.UnaryStreamMultiCallable): + + def __init__(self, end, group, method, pool): + self._end = end + self._group = group + self._method = method + self._pool = pool + + def __call__(self, request, timeout, metadata=None): + return _calls.inline_unary_stream( + self._end, self._group, self._method, timeout, metadata, + request) + + def event( + self, request, receiver, abortion_callback, timeout, + metadata=None): + return _calls.event_unary_stream( + self._end, self._group, self._method, timeout, metadata, + request, receiver, abortion_callback, self._pool) + + +class _StreamUnaryMultiCallable(face.StreamUnaryMultiCallable): + + def __init__(self, end, group, method, pool): + self._end = end + self._group = group + self._method = method + self._pool = pool + + def __call__( + self, request_iterator, timeout, metadata=None, + with_call=False): + return _calls.blocking_stream_unary( + self._end, self._group, self._method, timeout, with_call, + metadata, request_iterator, self._pool) + + def future(self, request_iterator, timeout, metadata=None): + return _calls.future_stream_unary( + self._end, self._group, self._method, timeout, metadata, + request_iterator, self._pool) + + def event( + self, receiver, abortion_callback, timeout, metadata=None): + return _calls.event_stream_unary( + self._end, self._group, self._method, timeout, metadata, + receiver, abortion_callback, self._pool) + + +class _StreamStreamMultiCallable(face.StreamStreamMultiCallable): + + def __init__(self, end, group, method, pool): + self._end = end + self._group = group + self._method = method + self._pool = pool + + def __call__(self, request_iterator, timeout, metadata=None): + return _calls.inline_stream_stream( + self._end, self._group, self._method, timeout, metadata, + request_iterator, self._pool) + + def event( + self, receiver, abortion_callback, timeout, metadata=None): + return _calls.event_stream_stream( + self._end, self._group, self._method, timeout, metadata, + receiver, abortion_callback, self._pool) + + +class _GenericStub(face.GenericStub): + """An face.GenericStub implementation.""" + + def __init__(self, end, pool): + self._end = end + self._pool = pool + + def blocking_unary_unary( + self, group, method, request, timeout, metadata=None, + with_call=None): + return _calls.blocking_unary_unary( + self._end, group, method, timeout, with_call, metadata, + request) + + def future_unary_unary( + self, group, method, request, timeout, metadata=None): + return _calls.future_unary_unary( + self._end, group, method, timeout, metadata, request) + + def inline_unary_stream( + self, group, method, request, timeout, metadata=None): + return _calls.inline_unary_stream( + self._end, group, method, timeout, metadata, request) + + def blocking_stream_unary( + self, group, method, request_iterator, timeout, metadata=None, + with_call=None): + return _calls.blocking_stream_unary( + self._end, group, method, timeout, with_call, metadata, + request_iterator, self._pool) + + def future_stream_unary( + self, group, method, request_iterator, timeout, metadata=None): + return _calls.future_stream_unary( + self._end, group, method, timeout, metadata, + request_iterator, self._pool) + + def inline_stream_stream( + self, group, method, request_iterator, timeout, metadata=None): + return _calls.inline_stream_stream( + self._end, group, method, timeout, metadata, + request_iterator, self._pool) + + def event_unary_unary( + self, group, method, request, receiver, abortion_callback, timeout, + metadata=None): + return _calls.event_unary_unary( + self._end, group, method, timeout, metadata, request, + receiver, abortion_callback, self._pool) + + def event_unary_stream( + self, group, method, request, receiver, abortion_callback, timeout, + metadata=None): + return _calls.event_unary_stream( + self._end, group, method, timeout, metadata, request, + receiver, abortion_callback, self._pool) + + def event_stream_unary( + self, group, method, receiver, abortion_callback, timeout, + metadata=None): + return _calls.event_stream_unary( + self._end, group, method, timeout, metadata, receiver, + abortion_callback, self._pool) + + def event_stream_stream( + self, group, method, receiver, abortion_callback, timeout, + metadata=None): + return _calls.event_stream_stream( + self._end, group, method, timeout, metadata, receiver, + abortion_callback, self._pool) + + def unary_unary(self, group, method): + return _UnaryUnaryMultiCallable(self._end, group, method, self._pool) + + def unary_stream(self, group, method): + return _UnaryStreamMultiCallable(self._end, group, method, self._pool) + + def stream_unary(self, group, method): + return _StreamUnaryMultiCallable(self._end, group, method, self._pool) + + def stream_stream(self, group, method): + return _StreamStreamMultiCallable(self._end, group, method, self._pool) + + +class _DynamicStub(face.DynamicStub): + """An face.DynamicStub implementation.""" + + def __init__(self, end, group, cardinalities, pool): + self._end = end + self._group = group + self._cardinalities = cardinalities + self._pool = pool + + def __getattr__(self, attr): + method_cardinality = self._cardinalities.get(attr) + if method_cardinality is cardinality.Cardinality.UNARY_UNARY: + return _UnaryUnaryMultiCallable(self._end, self._group, attr, self._pool) + elif method_cardinality is cardinality.Cardinality.UNARY_STREAM: + return _UnaryStreamMultiCallable(self._end, self._group, attr, self._pool) + elif method_cardinality is cardinality.Cardinality.STREAM_UNARY: + return _StreamUnaryMultiCallable(self._end, self._group, attr, self._pool) + elif method_cardinality is cardinality.Cardinality.STREAM_STREAM: + return _StreamStreamMultiCallable( + self._end, self._group, attr, self._pool) + else: + raise AttributeError('_DynamicStub object has no attribute "%s"!' % attr) + + +def _adapt_method_implementations(method_implementations, pool): + adapted_implementations = {} + for name, method_implementation in method_implementations.iteritems(): + if method_implementation.style is style.Service.INLINE: + if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY: + adapted_implementations[name] = _service.adapt_inline_unary_unary( + method_implementation.unary_unary_inline, pool) + elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM: + adapted_implementations[name] = _service.adapt_inline_unary_stream( + method_implementation.unary_stream_inline, pool) + elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY: + adapted_implementations[name] = _service.adapt_inline_stream_unary( + method_implementation.stream_unary_inline, pool) + elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM: + adapted_implementations[name] = _service.adapt_inline_stream_stream( + method_implementation.stream_stream_inline, pool) + elif method_implementation.style is style.Service.EVENT: + if method_implementation.cardinality is cardinality.Cardinality.UNARY_UNARY: + adapted_implementations[name] = _service.adapt_event_unary_unary( + method_implementation.unary_unary_event, pool) + elif method_implementation.cardinality is cardinality.Cardinality.UNARY_STREAM: + adapted_implementations[name] = _service.adapt_event_unary_stream( + method_implementation.unary_stream_event, pool) + elif method_implementation.cardinality is cardinality.Cardinality.STREAM_UNARY: + adapted_implementations[name] = _service.adapt_event_stream_unary( + method_implementation.stream_unary_event, pool) + elif method_implementation.cardinality is cardinality.Cardinality.STREAM_STREAM: + adapted_implementations[name] = _service.adapt_event_stream_stream( + method_implementation.stream_stream_event, pool) + return adapted_implementations + + +def servicer(method_implementations, multi_method_implementation, pool): + """Creates a base.Servicer. + + It is guaranteed that any passed face.MultiMethodImplementation will + only be called to service an RPC if there is no + face.MethodImplementation for the RPC method in the passed + method_implementations dictionary. + + Args: + method_implementations: A dictionary from RPC method name to + face.MethodImplementation object to be used to service the named + RPC method. + multi_method_implementation: An face.MultiMethodImplementation to be + used to service any RPCs not serviced by the + face.MethodImplementations given in the method_implementations + dictionary, or None. + pool: A thread pool. + + Returns: + A base.Servicer that services RPCs via the given implementations. + """ + adapted_implementations = _adapt_method_implementations( + method_implementations, pool) + adapted_multi_method_implementation = _service.adapt_multi_method( + multi_method_implementation, pool) + return _BaseServicer( + adapted_implementations, adapted_multi_method_implementation) + + +def generic_stub(end, pool): + """Creates an face.GenericStub. + + Args: + end: A base.End. + pool: A futures.ThreadPoolExecutor. + + Returns: + A face.GenericStub that performs RPCs via the given base.End. + """ + return _GenericStub(end, pool) + + +def dynamic_stub(end, group, cardinalities, pool): + """Creates an face.DynamicStub. + + Args: + end: A base.End. + group: The group identifier for all RPCs to be made with the created + face.DynamicStub. + cardinalities: A dict from method identifier to cardinality.Cardinality + value identifying the cardinality of every RPC method to be supported by + the created face.DynamicStub. + pool: A futures.ThreadPoolExecutor. + + Returns: + A face.DynamicStub that performs RPCs via the given base.End. + """ + return _DynamicStub(end, group, cardinalities, pool) diff --git a/src/python/grpcio/grpc/framework/interfaces/base/base.py b/src/python/grpcio/grpc/framework/interfaces/base/base.py index 76e0a5bdaea..bc52efb4c5a 100644 --- a/src/python/grpcio/grpc/framework/interfaces/base/base.py +++ b/src/python/grpcio/grpc/framework/interfaces/base/base.py @@ -47,7 +47,26 @@ from grpc.framework.foundation import abandonment # pylint: disable=unused-impo class NoSuchMethodError(Exception): - """Indicates that an unrecognized operation has been called.""" + """Indicates that an unrecognized operation has been called. + + Attributes: + code: A code value to communicate to the other side of the operation along + with indication of operation termination. May be None. + details: A details value to communicate to the other side of the operation + along with indication of operation termination. May be None. + """ + + def __init__(self, code, details): + """Constructor. + + Args: + code: A code value to communicate to the other side of the operation + along with indication of operation termination. May be None. + details: A details value to communicate to the other side of the + operation along with indication of operation termination. May be None. + """ + self.code = code + self.details = details @enum.unique diff --git a/src/python/grpcio_test/grpc_interop/client.py b/src/python/grpcio_test/grpc_interop/client.py index 2dd2103cbec..36afe6c0965 100644 --- a/src/python/grpcio_test/grpc_interop/client.py +++ b/src/python/grpcio_test/grpc_interop/client.py @@ -70,7 +70,13 @@ def _oauth_access_token(args): def _stub(args): if args.oauth_scope: - metadata_transformer = lambda x: [('Authorization', 'Bearer %s' % _oauth_access_token(args))] + if args.test_case == 'oauth2_auth_token': + access_token = _oauth_access_token(args) + metadata_transformer = lambda x: [ + ('Authorization', 'Bearer %s' % access_token)] + else: + metadata_transformer = lambda x: [ + ('Authorization', 'Bearer %s' % _oauth_access_token(args))] else: metadata_transformer = lambda x: [] if args.use_tls: diff --git a/src/python/grpcio_test/grpc_interop/methods.py b/src/python/grpcio_test/grpc_interop/methods.py index 7a831f3cbd2..642458e892a 100644 --- a/src/python/grpcio_test/grpc_interop/methods.py +++ b/src/python/grpcio_test/grpc_interop/methods.py @@ -360,6 +360,19 @@ def _service_account_creds(stub, args): (response.oauth_scope, args.oauth_scope)) +def _oauth2_auth_token(stub, args): + json_key_filename = os.environ[ + oauth2client_client.GOOGLE_APPLICATION_CREDENTIALS] + wanted_email = json.load(open(json_key_filename, 'rb'))['client_email'] + response = _large_unary_common_behavior(stub, True, True) + if wanted_email != response.username: + raise ValueError( + 'expected username %s, got %s' % (wanted_email, response.username)) + if args.oauth_scope.find(response.oauth_scope) == -1: + raise ValueError( + 'expected to find oauth scope "%s" in received "%s"' % + (response.oauth_scope, args.oauth_scope)) + @enum.unique class TestCase(enum.Enum): EMPTY_UNARY = 'empty_unary' @@ -371,6 +384,7 @@ class TestCase(enum.Enum): CANCEL_AFTER_FIRST_RESPONSE = 'cancel_after_first_response' COMPUTE_ENGINE_CREDS = 'compute_engine_creds' SERVICE_ACCOUNT_CREDS = 'service_account_creds' + OAUTH2_AUTH_TOKEN = 'oauth2_auth_token' TIMEOUT_ON_SLEEPING_SERVER = 'timeout_on_sleeping_server' def test_interoperability(self, stub, args): @@ -394,5 +408,7 @@ class TestCase(enum.Enum): _compute_engine_creds(stub, args) elif self is TestCase.SERVICE_ACCOUNT_CREDS: _service_account_creds(stub, args) + elif self is TestCase.OAUTH2_AUTH_TOKEN: + _oauth2_auth_token(stub, args) else: raise NotImplementedError('Test case "%s" not implemented!' % self.name) diff --git a/src/python/grpcio_test/grpc_test/_adapter/_links_test.py b/src/python/grpcio_test/grpc_test/_adapter/_links_test.py index c4686b327a9..4077b8e3503 100644 --- a/src/python/grpcio_test/grpc_test/_adapter/_links_test.py +++ b/src/python/grpcio_test/grpc_test/_adapter/_links_test.py @@ -46,8 +46,8 @@ _TIMEOUT = 32 # TODO(nathaniel): End-to-end metadata testing. def _transform_metadata(unused_metadata): return ( - ('one unused key', 'one unused value'), - ('another unused key', 'another unused value'), + ('one_unused_key', 'one unused value'), + ('another_unused_key', 'another unused value'), ) diff --git a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py b/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py index 72b1ae56426..7fa90fe35f0 100644 --- a/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py +++ b/src/python/grpcio_test/grpc_test/_core_over_links_base_interface_test.py @@ -27,7 +27,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""Tests the RPC Framework Core's implementation of the Base interface.""" +"""Tests Base interface compliance of the core-over-gRPC-links stack.""" import collections import logging diff --git a/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py b/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py new file mode 100644 index 00000000000..25b99cbbaf5 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/_crust_over_core_over_links_face_interface_test.py @@ -0,0 +1,160 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests Face compliance of the crust-over-core-over-gRPC-links stack.""" + +import collections +import unittest + +from grpc._adapter import _intermediary_low +from grpc._links import invocation +from grpc._links import service +from grpc.framework.core import implementations as core_implementations +from grpc.framework.crust import implementations as crust_implementations +from grpc.framework.foundation import logging_pool +from grpc.framework.interfaces.links import utilities +from grpc_test import test_common +from grpc_test.framework.common import test_constants +from grpc_test.framework.interfaces.face import test_cases +from grpc_test.framework.interfaces.face import test_interfaces +from grpc_test.framework.interfaces.links import test_utilities + + +class _SerializationBehaviors( + collections.namedtuple( + '_SerializationBehaviors', + ('request_serializers', 'request_deserializers', 'response_serializers', + 'response_deserializers',))): + pass + + +def _serialization_behaviors_from_test_methods(test_methods): + request_serializers = {} + request_deserializers = {} + response_serializers = {} + response_deserializers = {} + for (group, method), test_method in test_methods.iteritems(): + request_serializers[group, method] = test_method.serialize_request + request_deserializers[group, method] = test_method.deserialize_request + response_serializers[group, method] = test_method.serialize_response + response_deserializers[group, method] = test_method.deserialize_response + return _SerializationBehaviors( + request_serializers, request_deserializers, response_serializers, + response_deserializers) + + +class _Implementation(test_interfaces.Implementation): + + def instantiate( + self, methods, method_implementations, multi_method_implementation): + pool = logging_pool.pool(test_constants.POOL_SIZE) + servicer = crust_implementations.servicer( + method_implementations, multi_method_implementation, pool) + serialization_behaviors = _serialization_behaviors_from_test_methods( + methods) + invocation_end_link = core_implementations.invocation_end_link() + service_end_link = core_implementations.service_end_link( + servicer, test_constants.DEFAULT_TIMEOUT, + test_constants.MAXIMUM_TIMEOUT) + service_grpc_link = service.service_link( + serialization_behaviors.request_deserializers, + serialization_behaviors.response_serializers) + port = service_grpc_link.add_port(0, None) + channel = _intermediary_low.Channel('localhost:%d' % port, None) + invocation_grpc_link = invocation.invocation_link( + channel, b'localhost', + serialization_behaviors.request_serializers, + serialization_behaviors.response_deserializers) + + invocation_end_link.join_link(invocation_grpc_link) + invocation_grpc_link.join_link(invocation_end_link) + service_grpc_link.join_link(service_end_link) + service_end_link.join_link(service_grpc_link) + service_end_link.start() + invocation_end_link.start() + invocation_grpc_link.start() + service_grpc_link.start() + + generic_stub = crust_implementations.generic_stub(invocation_end_link, pool) + # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest. + group = next(iter(methods))[0] + # TODO(nathaniel): Add a "cardinalities_by_group" attribute to + # _digest.TestServiceDigest. + cardinalities = { + method: method_object.cardinality() + for (group, method), method_object in methods.iteritems()} + dynamic_stub = crust_implementations.dynamic_stub( + invocation_end_link, group, cardinalities, pool) + + return generic_stub, {group: dynamic_stub}, ( + invocation_end_link, invocation_grpc_link, service_grpc_link, + service_end_link, pool) + + def destantiate(self, memo): + (invocation_end_link, invocation_grpc_link, service_grpc_link, + service_end_link, pool) = memo + invocation_end_link.stop(0).wait() + invocation_grpc_link.stop() + service_grpc_link.stop_gracefully() + service_end_link.stop(0).wait() + invocation_end_link.join_link(utilities.NULL_LINK) + invocation_grpc_link.join_link(utilities.NULL_LINK) + service_grpc_link.join_link(utilities.NULL_LINK) + service_end_link.join_link(utilities.NULL_LINK) + pool.shutdown(wait=True) + + def invocation_metadata(self): + return test_common.INVOCATION_INITIAL_METADATA + + def initial_metadata(self): + return test_common.SERVICE_INITIAL_METADATA + + def terminal_metadata(self): + return test_common.SERVICE_TERMINAL_METADATA + + def code(self): + return _intermediary_low.Code.OK + + def details(self): + return test_common.DETAILS + + def metadata_transmitted(self, original_metadata, transmitted_metadata): + return original_metadata is None or grpc_test_common.metadata_transmitted( + original_metadata, transmitted_metadata) + + +def load_tests(loader, tests, pattern): + return unittest.TestSuite( + tests=tuple( + loader.loadTestsFromTestCase(test_case_class) + for test_case_class in test_cases.test_cases(_Implementation()))) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py b/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py index 9bab930e56e..f1bec238cf5 100644 --- a/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py +++ b/src/python/grpcio_test/grpc_test/_cython/adapter_low_test.py @@ -76,7 +76,7 @@ class InsecureServerInsecureClient(unittest.TestCase): CLIENT_METADATA_BIN_VALUE = b'\0'*1000 SERVER_INITIAL_METADATA_KEY = 'init_me_me_me' SERVER_INITIAL_METADATA_VALUE = 'whodawha?' - SERVER_TRAILING_METADATA_KEY = 'California_is_in_a_drought' + SERVER_TRAILING_METADATA_KEY = 'california_is_in_a_drought' SERVER_TRAILING_METADATA_VALUE = 'zomg it is' SERVER_STATUS_CODE = _types.StatusCode.OK SERVER_STATUS_DETAILS = 'our work is never over' diff --git a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py b/src/python/grpcio_test/grpc_test/_links/_transmission_test.py index 02ddd512c22..db011bca66d 100644 --- a/src/python/grpcio_test/grpc_test/_links/_transmission_test.py +++ b/src/python/grpcio_test/grpc_test/_links/_transmission_test.py @@ -66,9 +66,9 @@ class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase): def create_invocation_initial_metadata(self): return ( - ('first invocation initial metadata key', 'just a string value'), - ('second invocation initial metadata key', '0123456789'), - ('third invocation initial metadata key-bin', '\x00\x57' * 100), + ('first_invocation_initial_metadata_key', 'just a string value'), + ('second_invocation_initial_metadata_key', '0123456789'), + ('third_invocation_initial_metadata_key-bin', '\x00\x57' * 100), ) def create_invocation_terminal_metadata(self): @@ -76,16 +76,16 @@ class TransmissionTest(test_cases.TransmissionTest, unittest.TestCase): def create_service_initial_metadata(self): return ( - ('first service initial metadata key', 'just another string value'), - ('second service initial metadata key', '9876543210'), - ('third service initial metadata key-bin', '\x00\x59\x02' * 100), + ('first_service_initial_metadata_key', 'just another string value'), + ('second_service_initial_metadata_key', '9876543210'), + ('third_service_initial_metadata_key-bin', '\x00\x59\x02' * 100), ) def create_service_terminal_metadata(self): return ( - ('first service terminal metadata key', 'yet another string value'), - ('second service terminal metadata key', 'abcdefghij'), - ('third service terminal metadata key-bin', '\x00\x37' * 100), + ('first_service_terminal_metadata_key', 'yet another string value'), + ('second_service_terminal_metadata_key', 'abcdefghij'), + ('third_service_terminal_metadata_key-bin', '\x00\x37' * 100), ) def create_invocation_completion(self): diff --git a/src/python/grpcio_test/grpc_test/beta/__init__.py b/src/python/grpcio_test/grpc_test/beta/__init__.py new file mode 100644 index 00000000000..70865191060 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/beta/__init__.py @@ -0,0 +1,30 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + diff --git a/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py b/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py new file mode 100644 index 00000000000..038464889d6 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/beta/_connectivity_channel_test.py @@ -0,0 +1,180 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests of grpc.beta._connectivity_channel.""" + +import threading +import time +import unittest + +from grpc._adapter import _low +from grpc._adapter import _types +from grpc.beta import _connectivity_channel +from grpc_test.framework.common import test_constants + +_MAPPING_FUNCTION = lambda integer: integer * 200 + 17 +_MAPPING = { + state: _MAPPING_FUNCTION(state) for state in _types.ConnectivityState} +_IDLE, _CONNECTING, _READY, _TRANSIENT_FAILURE, _FATAL_FAILURE = map( + _MAPPING_FUNCTION, _types.ConnectivityState) + + +def _drive_completion_queue(completion_queue): + while True: + event = completion_queue.next(time.time() + 24 * 60 * 60) + if event.type == _types.EventType.QUEUE_SHUTDOWN: + break + + +class _Callback(object): + + def __init__(self): + self._condition = threading.Condition() + self._connectivities = [] + + def update(self, connectivity): + with self._condition: + self._connectivities.append(connectivity) + self._condition.notify() + + def connectivities(self): + with self._condition: + return tuple(self._connectivities) + + def block_until_connectivities_satisfy(self, predicate): + with self._condition: + while True: + connectivities = tuple(self._connectivities) + if predicate(connectivities): + return connectivities + else: + self._condition.wait() + + +class ChannelConnectivityTest(unittest.TestCase): + + def test_lonely_channel_connectivity(self): + low_channel = _low.Channel('localhost:12345', ()) + callback = _Callback() + + connectivity_channel = _connectivity_channel.ConnectivityChannel( + low_channel, _MAPPING) + connectivity_channel.subscribe(callback.update, try_to_connect=False) + first_connectivities = callback.block_until_connectivities_satisfy(bool) + connectivity_channel.subscribe(callback.update, try_to_connect=True) + second_connectivities = callback.block_until_connectivities_satisfy( + lambda connectivities: 2 <= len(connectivities)) + # Wait for a connection that will never happen. + time.sleep(test_constants.SHORT_TIMEOUT) + third_connectivities = callback.connectivities() + connectivity_channel.unsubscribe(callback.update) + fourth_connectivities = callback.connectivities() + connectivity_channel.unsubscribe(callback.update) + fifth_connectivities = callback.connectivities() + + self.assertSequenceEqual((_IDLE,), first_connectivities) + self.assertNotIn(_READY, second_connectivities) + self.assertNotIn(_READY, third_connectivities) + self.assertNotIn(_READY, fourth_connectivities) + self.assertNotIn(_READY, fifth_connectivities) + + def test_immediately_connectable_channel_connectivity(self): + server_completion_queue = _low.CompletionQueue() + server = _low.Server(server_completion_queue, []) + port = server.add_http2_port('[::]:0') + server.start() + server_completion_queue_thread = threading.Thread( + target=_drive_completion_queue, args=(server_completion_queue,)) + server_completion_queue_thread.start() + low_channel = _low.Channel('localhost:%d' % port, ()) + first_callback = _Callback() + second_callback = _Callback() + + connectivity_channel = _connectivity_channel.ConnectivityChannel( + low_channel, _MAPPING) + connectivity_channel.subscribe(first_callback.update, try_to_connect=False) + first_connectivities = first_callback.block_until_connectivities_satisfy( + bool) + # Wait for a connection that will never happen because try_to_connect=True + # has not yet been passed. + time.sleep(test_constants.SHORT_TIMEOUT) + second_connectivities = first_callback.connectivities() + connectivity_channel.subscribe(second_callback.update, try_to_connect=True) + third_connectivities = first_callback.block_until_connectivities_satisfy( + lambda connectivities: 2 <= len(connectivities)) + fourth_connectivities = second_callback.block_until_connectivities_satisfy( + bool) + # Wait for a connection that will happen (or may already have happened). + first_callback.block_until_connectivities_satisfy( + lambda connectivities: _READY in connectivities) + second_callback.block_until_connectivities_satisfy( + lambda connectivities: _READY in connectivities) + connectivity_channel.unsubscribe(first_callback.update) + connectivity_channel.unsubscribe(second_callback.update) + + server.shutdown() + server_completion_queue.shutdown() + server_completion_queue_thread.join() + + self.assertSequenceEqual((_IDLE,), first_connectivities) + self.assertSequenceEqual((_IDLE,), second_connectivities) + self.assertNotIn(_TRANSIENT_FAILURE, third_connectivities) + self.assertNotIn(_FATAL_FAILURE, third_connectivities) + self.assertNotIn(_TRANSIENT_FAILURE, fourth_connectivities) + self.assertNotIn(_FATAL_FAILURE, fourth_connectivities) + + def test_reachable_then_unreachable_channel_connectivity(self): + server_completion_queue = _low.CompletionQueue() + server = _low.Server(server_completion_queue, []) + port = server.add_http2_port('[::]:0') + server.start() + server_completion_queue_thread = threading.Thread( + target=_drive_completion_queue, args=(server_completion_queue,)) + server_completion_queue_thread.start() + low_channel = _low.Channel('localhost:%d' % port, ()) + callback = _Callback() + + connectivity_channel = _connectivity_channel.ConnectivityChannel( + low_channel, _MAPPING) + connectivity_channel.subscribe(callback.update, try_to_connect=True) + callback.block_until_connectivities_satisfy( + lambda connectivities: _READY in connectivities) + # Now take down the server and confirm that channel readiness is repudiated. + server.shutdown() + callback.block_until_connectivities_satisfy( + lambda connectivities: connectivities[-1] is not _READY) + connectivity_channel.unsubscribe(callback.update) + + server.shutdown() + server_completion_queue.shutdown() + server_completion_queue_thread.join() + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_test/grpc_test/beta/_utilities_test.py b/src/python/grpcio_test/grpc_test/beta/_utilities_test.py new file mode 100644 index 00000000000..998e74ccf48 --- /dev/null +++ b/src/python/grpcio_test/grpc_test/beta/_utilities_test.py @@ -0,0 +1,123 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests of grpc.beta.utilities.""" + +import threading +import time +import unittest + +from grpc._adapter import _low +from grpc._adapter import _types +from grpc.beta import beta +from grpc.beta import utilities +from grpc.framework.foundation import future +from grpc_test.framework.common import test_constants + + +def _drive_completion_queue(completion_queue): + while True: + event = completion_queue.next(time.time() + 24 * 60 * 60) + if event.type == _types.EventType.QUEUE_SHUTDOWN: + break + + +class _Callback(object): + + def __init__(self): + self._condition = threading.Condition() + self._value = None + + def accept_value(self, value): + with self._condition: + self._value = value + self._condition.notify_all() + + def block_until_called(self): + with self._condition: + while self._value is None: + self._condition.wait() + return self._value + + +class ChannelConnectivityTest(unittest.TestCase): + + def test_lonely_channel_connectivity(self): + channel = beta.create_insecure_channel('localhost', 12345) + callback = _Callback() + + ready_future = utilities.channel_ready_future(channel) + ready_future.add_done_callback(callback.accept_value) + with self.assertRaises(future.TimeoutError): + ready_future.result(test_constants.SHORT_TIMEOUT) + self.assertFalse(ready_future.cancelled()) + self.assertFalse(ready_future.done()) + self.assertTrue(ready_future.running()) + ready_future.cancel() + value_passed_to_callback = callback.block_until_called() + self.assertIs(ready_future, value_passed_to_callback) + self.assertTrue(ready_future.cancelled()) + self.assertTrue(ready_future.done()) + self.assertFalse(ready_future.running()) + + def test_immediately_connectable_channel_connectivity(self): + server_completion_queue = _low.CompletionQueue() + server = _low.Server(server_completion_queue, []) + port = server.add_http2_port('[::]:0') + server.start() + server_completion_queue_thread = threading.Thread( + target=_drive_completion_queue, args=(server_completion_queue,)) + server_completion_queue_thread.start() + channel = beta.create_insecure_channel('localhost', port) + callback = _Callback() + + try: + ready_future = utilities.channel_ready_future(channel) + ready_future.add_done_callback(callback.accept_value) + self.assertIsNone( + ready_future.result(test_constants.SHORT_TIMEOUT)) + value_passed_to_callback = callback.block_until_called() + self.assertIs(ready_future, value_passed_to_callback) + self.assertFalse(ready_future.cancelled()) + self.assertTrue(ready_future.done()) + self.assertFalse(ready_future.running()) + # Cancellation after maturity has no effect. + ready_future.cancel() + self.assertFalse(ready_future.cancelled()) + self.assertTrue(ready_future.done()) + self.assertFalse(ready_future.running()) + finally: + ready_future.cancel() + server.shutdown() + server_completion_queue.shutdown() + server_completion_queue_thread.join() + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py b/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py new file mode 100644 index 00000000000..30bb85f6c3b --- /dev/null +++ b/src/python/grpcio_test/grpc_test/framework/_crust_over_core_face_interface_test.py @@ -0,0 +1,111 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Tests Face interface compliance of the crust-over-core stack.""" + +import collections +import unittest + +from grpc.framework.core import implementations as core_implementations +from grpc.framework.crust import implementations as crust_implementations +from grpc.framework.foundation import logging_pool +from grpc.framework.interfaces.links import utilities +from grpc_test.framework.common import test_constants +from grpc_test.framework.interfaces.face import test_cases +from grpc_test.framework.interfaces.face import test_interfaces +from grpc_test.framework.interfaces.links import test_utilities + + +class _Implementation(test_interfaces.Implementation): + + def instantiate( + self, methods, method_implementations, multi_method_implementation): + pool = logging_pool.pool(test_constants.POOL_SIZE) + servicer = crust_implementations.servicer( + method_implementations, multi_method_implementation, pool) + + service_end_link = core_implementations.service_end_link( + servicer, test_constants.DEFAULT_TIMEOUT, + test_constants.MAXIMUM_TIMEOUT) + invocation_end_link = core_implementations.invocation_end_link() + invocation_end_link.join_link(service_end_link) + service_end_link.join_link(invocation_end_link) + service_end_link.start() + invocation_end_link.start() + + generic_stub = crust_implementations.generic_stub(invocation_end_link, pool) + # TODO(nathaniel): Add a "groups" attribute to _digest.TestServiceDigest. + group = next(iter(methods))[0] + # TODO(nathaniel): Add a "cardinalities_by_group" attribute to + # _digest.TestServiceDigest. + cardinalities = { + method: method_object.cardinality() + for (group, method), method_object in methods.iteritems()} + dynamic_stub = crust_implementations.dynamic_stub( + invocation_end_link, group, cardinalities, pool) + + return generic_stub, {group: dynamic_stub}, ( + invocation_end_link, service_end_link, pool) + + def destantiate(self, memo): + invocation_end_link, service_end_link, pool = memo + invocation_end_link.stop(0).wait() + service_end_link.stop(0).wait() + invocation_end_link.join_link(utilities.NULL_LINK) + service_end_link.join_link(utilities.NULL_LINK) + pool.shutdown(wait=True) + + def invocation_metadata(self): + return object() + + def initial_metadata(self): + return object() + + def terminal_metadata(self): + return object() + + def code(self): + return object() + + def details(self): + return object() + + def metadata_transmitted(self, original_metadata, transmitted_metadata): + return original_metadata is transmitted_metadata + + +def load_tests(loader, tests, pattern): + return unittest.TestSuite( + tests=tuple( + loader.loadTestsFromTestCase(test_case_class) + for test_case_class in test_cases.test_cases(_Implementation()))) + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py index 5c8b176da4f..87332cf612e 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/base/test_cases.py @@ -134,7 +134,7 @@ class _Servicer(base.Servicer): if group != self._group or method != self._method: controller.fail( '%s != %s or %s != %s' % (group, self._group, method, self._method)) - raise base.NoSuchMethodError() + raise base.NoSuchMethodError(None, None) else: operator = _Operator( controller, controller.on_service_advance, self._pool, diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py new file mode 100644 index 00000000000..363d9ce8f1c --- /dev/null +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_3069_test_constant.py @@ -0,0 +1,37 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""A test constant working around issue 3069.""" + +# test_constants is referenced from specification in this module. +from grpc_test.framework.common import test_constants # pylint: disable=unused-import + +# TODO(issue 3069): Replace uses of this constant with +# test_constants.SHORT_TIMEOUT. +REALLY_SHORT_TIMEOUT = 0.1 diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py index 857ad5cf3e0..8804f3f2233 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_blocking_invocation_inline_service.py @@ -37,6 +37,7 @@ from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage +from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _stock_service from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import @@ -170,7 +171,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(), self.assertRaises( face.ExpirationError): self._invoker.blocking(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) def testExpiredUnaryRequestStreamResponse(self): for (group, method), test_messages_sequence in ( @@ -181,7 +182,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(), self.assertRaises( face.ExpirationError): response_iterator = self._invoker.blocking(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testExpiredStreamRequestUnaryResponse(self): @@ -193,7 +194,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(), self.assertRaises( face.ExpirationError): self._invoker.blocking(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) def testExpiredStreamRequestStreamResponse(self): for (group, method), test_messages_sequence in ( @@ -204,7 +205,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(), self.assertRaises( face.ExpirationError): response_iterator = self._invoker.blocking(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testFailedUnaryRequestUnaryResponse(self): diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py index ea5cdeaea30..5a78b4bed24 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_event_invocation_synchronous_event_service.py @@ -37,6 +37,7 @@ from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage +from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _receiver from grpc_test.framework.interfaces.face import _stock_service @@ -264,7 +265,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): self._invoker.event(group, method)( - request, receiver, receiver.abort, test_constants.SHORT_TIMEOUT) + request, receiver, receiver.abort, + _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) @@ -278,7 +280,8 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): self._invoker.event(group, method)( - request, receiver, receiver.abort, test_constants.SHORT_TIMEOUT) + request, receiver, receiver.abort, + _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) @@ -290,7 +293,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): receiver = _receiver.Receiver() self._invoker.event(group, method)( - receiver, receiver.abort, test_constants.SHORT_TIMEOUT) + receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT) receiver.block_until_terminated() self.assertIs(face.Abortion.Kind.EXPIRED, receiver.abortion().kind) @@ -303,7 +306,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): receiver = _receiver.Receiver() call_consumer = self._invoker.event(group, method)( - receiver, receiver.abort, test_constants.SHORT_TIMEOUT) + receiver, receiver.abort, _3069_test_constant.REALLY_SHORT_TIMEOUT) for request in requests: call_consumer.consume(request) receiver.block_until_terminated() diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py index a649362cef8..d1107e1576d 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_future_invocation_asynchronous_event_service.py @@ -40,6 +40,7 @@ from grpc.framework.interfaces.face import face from grpc_test.framework.common import test_constants from grpc_test.framework.common import test_control from grpc_test.framework.common import test_coverage +from grpc_test.framework.interfaces.face import _3069_test_constant from grpc_test.framework.interfaces.face import _digest from grpc_test.framework.interfaces.face import _stock_service from grpc_test.framework.interfaces.face import test_interfaces # pylint: disable=unused-import @@ -265,7 +266,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): response_future = self._invoker.future( - group, method)(request, test_constants.SHORT_TIMEOUT) + group, method)(request, _3069_test_constant.REALLY_SHORT_TIMEOUT) self.assertIsInstance( response_future.exception(), face.ExpirationError) with self.assertRaises(face.ExpirationError): @@ -279,7 +280,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): response_iterator = self._invoker.future(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): list(response_iterator) @@ -291,7 +292,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): response_future = self._invoker.future(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) self.assertIsInstance( response_future.exception(), face.ExpirationError) with self.assertRaises(face.ExpirationError): @@ -305,7 +306,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.pause(): response_iterator = self._invoker.future(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) with self.assertRaises(face.ExpirationError): list(response_iterator) @@ -317,7 +318,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.fail(): response_future = self._invoker.future(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is @@ -340,7 +341,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): # expiration of the RPC. with self._control.fail(), self.assertRaises(face.ExpirationError): response_iterator = self._invoker.future(group, method)( - request, test_constants.SHORT_TIMEOUT) + request, _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) def testFailedStreamRequestUnaryResponse(self): @@ -351,7 +352,7 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): with self._control.fail(): response_future = self._invoker.future(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) # Because the servicer fails outside of the thread from which the # servicer-side runtime called into it its failure is @@ -374,5 +375,5 @@ class TestCase(test_coverage.Coverage, unittest.TestCase): # expiration of the RPC. with self._control.fail(), self.assertRaises(face.ExpirationError): response_iterator = self._invoker.future(group, method)( - iter(requests), test_constants.SHORT_TIMEOUT) + iter(requests), _3069_test_constant.REALLY_SHORT_TIMEOUT) list(response_iterator) diff --git a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py index 1dd2ec36331..808e2c4e36a 100644 --- a/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py +++ b/src/python/grpcio_test/grpc_test/framework/interfaces/face/_stock_service.py @@ -1,4 +1,4 @@ -B# Copyright 2015, Google Inc. +# Copyright 2015, Google Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 6491aa4fb4b..90afdc3fe11 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -150,7 +150,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { ch = grpc_insecure_channel_create(target_chars, &args, NULL); } else { creds = grpc_rb_get_wrapped_credentials(credentials); - ch = grpc_secure_channel_create(creds, target_chars, &args); + ch = grpc_secure_channel_create(creds, target_chars, &args, NULL); } if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c index a9dcdbce9f2..ac3804df6ff 100644 --- a/src/ruby/ext/grpc/rb_credentials.c +++ b/src/ruby/ext/grpc/rb_credentials.c @@ -154,7 +154,7 @@ static VALUE grpc_rb_default_credentials_create(VALUE cls) { Creates the default credential instances. */ static VALUE grpc_rb_compute_engine_credentials_create(VALUE cls) { grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials); - wrapper->wrapped = grpc_compute_engine_credentials_create(); + wrapper->wrapped = grpc_compute_engine_credentials_create(NULL); if (wrapper->wrapped == NULL) { rb_raise(rb_eRuntimeError, "could not create composite engine credentials, not sure why"); @@ -181,8 +181,8 @@ static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) { TypedData_Get_Struct(other, grpc_rb_credentials, &grpc_rb_credentials_data_type, other_wrapper); wrapper = ALLOC(grpc_rb_credentials); - wrapper->wrapped = grpc_composite_credentials_create(self_wrapper->wrapped, - other_wrapper->wrapped); + wrapper->wrapped = grpc_composite_credentials_create( + self_wrapper->wrapped, other_wrapper->wrapped, NULL); if (wrapper->wrapped == NULL) { rb_raise(rb_eRuntimeError, "could not create composite credentials, not sure why"); @@ -234,12 +234,13 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) { return Qnil; } if (pem_private_key == Qnil && pem_cert_chain == Qnil) { - creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL); + creds = + grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL, NULL); } else { key_cert_pair.private_key = RSTRING_PTR(pem_private_key); key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain); creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), - &key_cert_pair); + &key_cert_pair, NULL); } if (creds == NULL) { rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c index 62c211d7691..6af4c86c459 100644 --- a/src/ruby/ext/grpc/rb_server_credentials.c +++ b/src/ruby/ext/grpc/rb_server_credentials.c @@ -178,10 +178,11 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs, key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain); /* TODO Add a force_client_auth parameter and pass it here. */ if (pem_root_certs == Qnil) { - creds = grpc_ssl_server_credentials_create(NULL, &key_cert_pair, 1, 0); + creds = + grpc_ssl_server_credentials_create(NULL, &key_cert_pair, 1, 0, NULL); } else { creds = grpc_ssl_server_credentials_create(RSTRING_PTR(pem_root_certs), - &key_cert_pair, 1, 0); + &key_cert_pair, 1, 0, NULL); } if (creds == NULL) { rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why"); diff --git a/templates/Makefile.template b/templates/Makefile.template index 00582a22f8d..797f0ab57fa 100644 --- a/templates/Makefile.template +++ b/templates/Makefile.template @@ -859,8 +859,8 @@ else $(Q)(cd third_party/openssl ; CC="$(CC) $(PIC_CPPFLAGS) -fvisibility=hidden $(CPPFLAGS_$(CONFIG)) $(OPENSSL_CFLAGS_$(CONFIG)) $(OPENSSL_CFLAGS_EXTRA)" ./config no-asm $(OPENSSL_CONFIG_$(CONFIG))) endif endif - $(Q)$(MAKE) -C third_party/openssl clean - $(Q)(unset CPPFLAGS; $(MAKE) -C third_party/openssl build_crypto build_ssl) + $(Q)$(MAKE) -j 1 -C third_party/openssl clean + $(Q)(unset CPPFLAGS; $(MAKE) -j 1 -C third_party/openssl build_crypto build_ssl) $(Q)mkdir -p $(LIBDIR)/$(CONFIG)/openssl $(Q)cp third_party/openssl/libssl.a third_party/openssl/libcrypto.a $(LIBDIR)/$(CONFIG)/openssl diff --git a/templates/vsprojects/vcxproj_defs.include b/templates/vsprojects/vcxproj_defs.include index 507c9a52042..b1ed89897f1 100644 --- a/templates/vsprojects/vcxproj_defs.include +++ b/templates/vsprojects/vcxproj_defs.include @@ -23,7 +23,7 @@ props.extend(['cpptest']) if configuration_type == 'Application': if target.build == 'protoc': - props.extend(['protoc']) + props.extend(['protoc', 'protobuf']) else: props.extend(['winsock', 'protobuf', 'zlib', 'openssl']) else: diff --git a/test/core/end2end/fixtures/chttp2_fake_security.c b/test/core/end2end/fixtures/chttp2_fake_security.c index a0a67939a21..b4a248fb52c 100644 --- a/test/core/end2end/fixtures/chttp2_fake_security.c +++ b/test/core/end2end/fixtures/chttp2_fake_security.c @@ -77,7 +77,8 @@ static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, grpc_credentials *creds) { fullstack_secure_fixture_data *ffd = f->fixture_data; - f->client = grpc_secure_channel_create(creds, ffd->localaddr, client_args); + f->client = + grpc_secure_channel_create(creds, ffd->localaddr, client_args, NULL); GPR_ASSERT(f->client != NULL); grpc_credentials_release(creds); } diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c index beae24136cd..201d202dff9 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c @@ -80,7 +80,8 @@ static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, grpc_credentials *creds) { fullstack_secure_fixture_data *ffd = f->fixture_data; - f->client = grpc_secure_channel_create(creds, ffd->localaddr, client_args); + f->client = + grpc_secure_channel_create(creds, ffd->localaddr, client_args, NULL); GPR_ASSERT(f->client != NULL); grpc_credentials_release(creds); } @@ -108,7 +109,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { static void chttp2_init_client_simple_ssl_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { - grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL); + grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); grpc_arg ssl_name_override = {GRPC_ARG_STRING, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, {"foo.test.google.fr"}}; @@ -135,7 +136,7 @@ static void chttp2_init_server_simple_ssl_secure_fullstack( grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = - grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0); + grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0, NULL); if (fail_server_auth_check(server_args)) { grpc_auth_metadata_processor processor = {process_auth_failure, NULL}; grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor); diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c index c8971be5966..e7375f15e66 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_poll.c @@ -80,7 +80,8 @@ static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, grpc_credentials *creds) { fullstack_secure_fixture_data *ffd = f->fixture_data; - f->client = grpc_secure_channel_create(creds, ffd->localaddr, client_args); + f->client = + grpc_secure_channel_create(creds, ffd->localaddr, client_args, NULL); GPR_ASSERT(f->client != NULL); grpc_credentials_release(creds); } @@ -108,7 +109,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { static void chttp2_init_client_simple_ssl_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { - grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL); + grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); grpc_arg ssl_name_override = {GRPC_ARG_STRING, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, {"foo.test.google.fr"}}; @@ -135,7 +136,7 @@ static void chttp2_init_server_simple_ssl_secure_fullstack( grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = - grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0); + grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0, NULL); if (fail_server_auth_check(server_args)) { grpc_auth_metadata_processor processor = {process_auth_failure, NULL}; grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor); diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c index a518a7da15b..be0dda25a64 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c @@ -58,7 +58,7 @@ static grpc_server *create_proxy_server(const char *port) { grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = - grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0); + grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0, NULL); GPR_ASSERT(grpc_server_add_secure_http2_port(s, port, ssl_creds)); grpc_server_credentials_release(ssl_creds); return s; @@ -66,14 +66,14 @@ static grpc_server *create_proxy_server(const char *port) { static grpc_channel *create_proxy_client(const char *target) { grpc_channel *channel; - grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL); + grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); grpc_arg ssl_name_override = {GRPC_ARG_STRING, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, {"foo.test.google.fr"}}; grpc_channel_args client_args; client_args.num_args = 1; client_args.args = &ssl_name_override; - channel = grpc_secure_channel_create(ssl_creds, target, &client_args); + channel = grpc_secure_channel_create(ssl_creds, target, &client_args, NULL); grpc_credentials_release(ssl_creds); return channel; } @@ -109,7 +109,8 @@ static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_credentials *creds) { fullstack_secure_fixture_data *ffd = f->fixture_data; f->client = grpc_secure_channel_create( - creds, grpc_end2end_proxy_get_client_target(ffd->proxy), client_args); + creds, grpc_end2end_proxy_get_client_target(ffd->proxy), client_args, + NULL); GPR_ASSERT(f->client != NULL); grpc_credentials_release(creds); } @@ -137,7 +138,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { static void chttp2_init_client_simple_ssl_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { - grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL); + grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); grpc_arg ssl_name_override = {GRPC_ARG_STRING, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, {"foo.test.google.fr"}}; @@ -164,7 +165,7 @@ static void chttp2_init_server_simple_ssl_secure_fullstack( grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = - grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0); + grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0, NULL); if (fail_server_auth_check(server_args)) { grpc_auth_metadata_processor processor = {process_auth_failure, NULL}; grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor); diff --git a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c index 7f11028cb5a..9a545b1e3d5 100644 --- a/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c +++ b/test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c @@ -113,7 +113,8 @@ static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, grpc_channel_args *client_args, grpc_credentials *creds) { fullstack_secure_fixture_data *ffd = f->fixture_data; - f->client = grpc_secure_channel_create(creds, ffd->localaddr, client_args); + f->client = + grpc_secure_channel_create(creds, ffd->localaddr, client_args, NULL); GPR_ASSERT(f->client != NULL); grpc_credentials_release(creds); } @@ -142,11 +143,11 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) { static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack( grpc_end2end_test_fixture *f, grpc_channel_args *client_args) { grpc_credentials *ssl_creds = - grpc_ssl_credentials_create(test_root_cert, NULL); + grpc_ssl_credentials_create(test_root_cert, NULL, NULL); grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create("Authorization", oauth2_md, 1); grpc_credentials *ssl_oauth2_creds = - grpc_composite_credentials_create(ssl_creds, oauth2_creds); + grpc_composite_credentials_create(ssl_creds, oauth2_creds, NULL); grpc_arg ssl_name_override = {GRPC_ARG_STRING, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, {"foo.test.google.fr"}}; @@ -175,7 +176,7 @@ static void chttp2_init_server_simple_ssl_secure_fullstack( grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key, test_server1_cert}; grpc_server_credentials *ssl_creds = - grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1, 0); + grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1, 0, NULL); grpc_auth_metadata_processor processor; processor.state = NULL; if (fail_server_auth_check(server_args)) { diff --git a/test/core/end2end/tests/default_host.c b/test/core/end2end/tests/default_host.c index 97c19db331d..57f65b834b0 100644 --- a/test/core/end2end/tests/default_host.c +++ b/test/core/end2end/tests/default_host.c @@ -201,7 +201,7 @@ static void simple_request_body(grpc_end2end_test_fixture f) { GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED); GPR_ASSERT(0 == strcmp(details, "xyz")); GPR_ASSERT(0 == strcmp(call_details.method, "/foo")); - GPR_ASSERT(0 == strcmp(call_details.host, "localhost")); + GPR_ASSERT(0 == strncmp(call_details.host, "localhost", 9)); GPR_ASSERT(was_cancelled == 1); gpr_free(details); diff --git a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c index d862274fe31..48dd0aa2cee 100644 --- a/test/core/end2end/tests/request_response_with_payload_and_call_creds.c +++ b/test/core/end2end/tests/request_response_with_payload_and_call_creds.c @@ -190,7 +190,7 @@ static void request_response_with_payload_and_call_creds( c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, "/foo", "foo.test.google.fr", deadline, NULL); GPR_ASSERT(c); - creds = grpc_iam_credentials_create(iam_token, iam_selector); + creds = grpc_iam_credentials_create(iam_token, iam_selector, NULL); GPR_ASSERT(creds != NULL); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); switch (mode) { @@ -199,7 +199,7 @@ static void request_response_with_payload_and_call_creds( case OVERRIDE: grpc_credentials_release(creds); creds = grpc_iam_credentials_create(overridden_iam_token, - overridden_iam_selector); + overridden_iam_selector, NULL); GPR_ASSERT(creds != NULL); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); break; @@ -421,7 +421,7 @@ static void test_request_with_server_rejecting_client_creds( "/foo", "foo.test.google.fr", deadline, NULL); GPR_ASSERT(c); - creds = grpc_iam_credentials_create(iam_token, iam_selector); + creds = grpc_iam_credentials_create(iam_token, iam_selector, NULL); GPR_ASSERT(creds != NULL); GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK); grpc_credentials_release(creds); diff --git a/test/core/fling/server.c b/test/core/fling/server.c index 010217939d0..0430ff9ab72 100644 --- a/test/core/fling/server.c +++ b/test/core/fling/server.c @@ -215,8 +215,8 @@ int main(int argc, char **argv) { if (secure) { grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key, test_server1_cert}; - grpc_server_credentials *ssl_creds = - grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1, 0); + grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create( + NULL, &pem_key_cert_pair, 1, 0, NULL); server = grpc_server_create(NULL, NULL); GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr, ssl_creds)); grpc_server_credentials_release(ssl_creds); diff --git a/test/core/iomgr/tcp_client_posix_test.c b/test/core/iomgr/tcp_client_posix_test.c index dea0b33b8e9..f0e2de24d95 100644 --- a/test/core/iomgr/tcp_client_posix_test.c +++ b/test/core/iomgr/tcp_client_posix_test.c @@ -39,10 +39,12 @@ #include #include -#include "src/core/iomgr/iomgr.h" -#include "src/core/iomgr/socket_utils_posix.h" +#include #include #include + +#include "src/core/iomgr/iomgr.h" +#include "src/core/iomgr/socket_utils_posix.h" #include "test/core/util/test_config.h" static grpc_pollset_set g_pollset_set; @@ -198,16 +200,21 @@ void test_times_out(void) { /* Make sure the event doesn't trigger early */ gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); - while (gpr_time_cmp(gpr_time_add(connect_deadline, - gpr_time_from_seconds(2, GPR_TIMESPAN)), - gpr_now(connect_deadline.clock_type)) > 0) { - int is_after_deadline = - gpr_time_cmp(connect_deadline, gpr_now(GPR_CLOCK_MONOTONIC)) <= 0; + for (;;) { grpc_pollset_worker worker; + gpr_timespec now = gpr_now(connect_deadline.clock_type); + gpr_timespec continue_verifying_time = gpr_time_from_seconds(2, GPR_TIMESPAN); + gpr_timespec grace_time = gpr_time_from_seconds(1, GPR_TIMESPAN); + gpr_timespec finish_time = gpr_time_add(connect_deadline, continue_verifying_time); + gpr_timespec restart_verifying_time = gpr_time_add(connect_deadline, grace_time); + int is_after_deadline = gpr_time_cmp(now, connect_deadline) > 0; + if (gpr_time_cmp(now, finish_time) > 0) { + break; + } + gpr_log(GPR_DEBUG, "now=%d.%09d connect_deadline=%d.%09d", + now.tv_sec, now.tv_nsec, connect_deadline.tv_sec, connect_deadline.tv_nsec); if (is_after_deadline && - gpr_time_cmp(gpr_time_add(connect_deadline, - gpr_time_from_seconds(1, GPR_TIMESPAN)), - gpr_now(GPR_CLOCK_MONOTONIC)) > 0) { + gpr_time_cmp(now, restart_verifying_time) <= 0) { /* allow some slack before insisting that things be done */ } else { GPR_ASSERT(g_connections_complete == @@ -228,7 +235,7 @@ static void destroy_pollset(void *p) { grpc_pollset_destroy(p); } int main(int argc, char **argv) { grpc_test_init(argc, argv); - grpc_iomgr_init(); + grpc_init(); grpc_pollset_set_init(&g_pollset_set); grpc_pollset_init(&g_pollset); grpc_pollset_set_add_pollset(&g_pollset_set, &g_pollset); @@ -238,6 +245,6 @@ int main(int argc, char **argv) { test_times_out(); grpc_pollset_set_destroy(&g_pollset_set); grpc_pollset_shutdown(&g_pollset, destroy_pollset, &g_pollset); - grpc_iomgr_shutdown(); + grpc_shutdown(); return 0; } diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c index 471d5b50c7c..c91752b9373 100644 --- a/test/core/iomgr/udp_server_test.c +++ b/test/core/iomgr/udp_server_test.c @@ -135,7 +135,7 @@ static void test_receive(int number_of_clients) { gpr_mu_lock(GRPC_POLLSET_MU(&g_pollset)); for (i = 0; i < number_of_clients; i++) { - deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(4000); + deadline = GRPC_TIMEOUT_SECONDS_TO_DEADLINE(10); number_of_reads_before = g_number_of_reads; /* Create a socket, send a packet to the UDP server. */ diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c index e4a8144eaff..880fc5da1e1 100644 --- a/test/core/security/credentials_test.c +++ b/test/core/security/credentials_test.c @@ -329,7 +329,7 @@ static void check_iam_metadata(void *user_data, grpc_credentials_md *md_elems, static void test_iam_creds(void) { grpc_credentials *creds = grpc_iam_credentials_create( - test_iam_authorization_token, test_iam_authority_selector); + test_iam_authorization_token, test_iam_authority_selector, NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds)); grpc_credentials_get_request_metadata(creds, NULL, test_service_url, @@ -349,7 +349,7 @@ static void check_access_token_metadata(void *user_data, } static void test_access_token_creds(void) { - grpc_credentials *creds = grpc_access_token_credentials_create("blah"); + grpc_credentials *creds = grpc_access_token_credentials_create("blah", NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds)); GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_OAUTH2) == 0); @@ -371,12 +371,12 @@ static void check_ssl_oauth2_composite_metadata( static void test_ssl_oauth2_composite_creds(void) { grpc_credentials *ssl_creds = - grpc_ssl_credentials_create(test_root_cert, NULL); + grpc_ssl_credentials_create(test_root_cert, NULL, NULL); const grpc_credentials_array *creds_array; grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create( "Authorization", test_oauth2_bearer_token, 0); grpc_credentials *composite_creds = - grpc_composite_credentials_create(ssl_creds, oauth2_creds); + grpc_composite_credentials_create(ssl_creds, oauth2_creds, NULL); grpc_credentials_unref(ssl_creds); grpc_credentials_unref(oauth2_creds); GPR_ASSERT(strcmp(composite_creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == @@ -395,13 +395,13 @@ static void test_ssl_oauth2_composite_creds(void) { } void test_ssl_fake_transport_security_composite_creds_failure(void) { - grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL); + grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL); grpc_credentials *fake_transport_security_creds = grpc_fake_transport_security_credentials_create(); /* 2 connector credentials: should not work. */ GPR_ASSERT(grpc_composite_credentials_create( - ssl_creds, fake_transport_security_creds) == NULL); + ssl_creds, fake_transport_security_creds, NULL) == NULL); grpc_credentials_unref(ssl_creds); grpc_credentials_unref(fake_transport_security_creds); } @@ -422,16 +422,16 @@ static void check_ssl_oauth2_iam_composite_metadata( static void test_ssl_oauth2_iam_composite_creds(void) { grpc_credentials *ssl_creds = - grpc_ssl_credentials_create(test_root_cert, NULL); + grpc_ssl_credentials_create(test_root_cert, NULL, NULL); const grpc_credentials_array *creds_array; grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create( "Authorization", test_oauth2_bearer_token, 0); grpc_credentials *aux_creds = - grpc_composite_credentials_create(ssl_creds, oauth2_creds); + grpc_composite_credentials_create(ssl_creds, oauth2_creds, NULL); grpc_credentials *iam_creds = grpc_iam_credentials_create( - test_iam_authorization_token, test_iam_authority_selector); + test_iam_authorization_token, test_iam_authority_selector, NULL); grpc_credentials *composite_creds = - grpc_composite_credentials_create(aux_creds, iam_creds); + grpc_composite_credentials_create(aux_creds, iam_creds, NULL); grpc_credentials_unref(ssl_creds); grpc_credentials_unref(oauth2_creds); grpc_credentials_unref(aux_creds); @@ -524,7 +524,7 @@ static int httpcli_get_should_not_be_called( static void test_compute_engine_creds_success(void) { grpc_credentials *compute_engine_creds = - grpc_compute_engine_credentials_create(); + grpc_compute_engine_credentials_create(NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds)); @@ -548,7 +548,7 @@ static void test_compute_engine_creds_success(void) { static void test_compute_engine_creds_failure(void) { grpc_credentials *compute_engine_creds = - grpc_compute_engine_credentials_create(); + grpc_compute_engine_credentials_create(NULL); grpc_httpcli_set_override(compute_engine_httpcli_get_failure_override, httpcli_post_should_not_be_called); GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds)); @@ -605,7 +605,7 @@ static int refresh_token_httpcli_post_failure( static void test_refresh_token_creds_success(void) { grpc_credentials *refresh_token_creds = - grpc_refresh_token_credentials_create(test_refresh_token_str); + grpc_refresh_token_credentials_create(test_refresh_token_str, NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(refresh_token_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(refresh_token_creds)); @@ -629,7 +629,7 @@ static void test_refresh_token_creds_success(void) { static void test_refresh_token_creds_failure(void) { grpc_credentials *refresh_token_creds = - grpc_refresh_token_credentials_create(test_refresh_token_str); + grpc_refresh_token_credentials_create(test_refresh_token_str, NULL); grpc_httpcli_set_override(httpcli_get_should_not_be_called, refresh_token_httpcli_post_failure); GPR_ASSERT(grpc_credentials_has_request_metadata(refresh_token_creds)); @@ -731,7 +731,7 @@ static void test_service_account_creds_success(void) { char *json_key_string = test_json_key_str(); grpc_credentials *service_account_creds = grpc_service_account_credentials_create(json_key_string, test_scope, - grpc_max_auth_token_lifetime); + grpc_max_auth_token_lifetime, NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(service_account_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(service_account_creds)); @@ -761,8 +761,8 @@ static void test_service_account_creds_success(void) { static void test_service_account_creds_http_failure(void) { char *json_key_string = test_json_key_str(); grpc_credentials *service_account_creds = - grpc_service_account_credentials_create(json_key_string, test_scope, - grpc_max_auth_token_lifetime); + grpc_service_account_credentials_create( + json_key_string, test_scope, grpc_max_auth_token_lifetime, NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(service_account_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(service_account_creds)); @@ -781,8 +781,8 @@ static void test_service_account_creds_http_failure(void) { static void test_service_account_creds_signing_failure(void) { char *json_key_string = test_json_key_str(); grpc_credentials *service_account_creds = - grpc_service_account_credentials_create(json_key_string, test_scope, - grpc_max_auth_token_lifetime); + grpc_service_account_credentials_create( + json_key_string, test_scope, grpc_max_auth_token_lifetime, NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(service_account_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(service_account_creds)); @@ -828,7 +828,7 @@ static void test_jwt_creds_success(void) { char *json_key_string = test_json_key_str(); grpc_credentials *jwt_creds = grpc_service_account_jwt_access_credentials_create( - json_key_string, grpc_max_auth_token_lifetime); + json_key_string, grpc_max_auth_token_lifetime, NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds)); @@ -861,7 +861,7 @@ static void test_jwt_creds_signing_failure(void) { char *json_key_string = test_json_key_str(); grpc_credentials *jwt_creds = grpc_service_account_jwt_access_credentials_create( - json_key_string, grpc_max_auth_token_lifetime); + json_key_string, grpc_max_auth_token_lifetime, NULL); GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds)); GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds)); diff --git a/test/core/security/fetch_oauth2.c b/test/core/security/fetch_oauth2.c index 64c4dde5d98..7354a9f8f77 100644 --- a/test/core/security/fetch_oauth2.c +++ b/test/core/security/fetch_oauth2.c @@ -56,7 +56,7 @@ static grpc_credentials *create_service_account_creds( } return grpc_service_account_credentials_create( (const char *)GPR_SLICE_START_PTR(json_key), scope, - grpc_max_auth_token_lifetime); + grpc_max_auth_token_lifetime, NULL); } static grpc_credentials *create_refresh_token_creds( @@ -69,7 +69,7 @@ static grpc_credentials *create_refresh_token_creds( exit(1); } return grpc_refresh_token_credentials_create( - (const char *)GPR_SLICE_START_PTR(refresh_token)); + (const char *)GPR_SLICE_START_PTR(refresh_token), NULL); } int main(int argc, char **argv) { @@ -112,7 +112,7 @@ int main(int argc, char **argv) { "Ignoring json key and scope to get a token from the GCE " "metadata server."); } - creds = grpc_compute_engine_credentials_create(); + creds = grpc_compute_engine_credentials_create(NULL); if (creds == NULL) { gpr_log(GPR_ERROR, "Could not create gce credentials."); exit(1); diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h index b2cc40bb47b..ccef8620c13 100644 --- a/test/core/util/test_config.h +++ b/test/core/util/test_config.h @@ -56,7 +56,7 @@ extern double g_fixture_slowdown_factor; #define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x) \ gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), \ - gpr_time_from_micros(GRPC_TEST_SLOWDOWN_FACTOR * 1e6 * (x), \ + gpr_time_from_millis(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x), \ GPR_TIMESPAN)) #define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x) \ diff --git a/test/cpp/common/auth_property_iterator_test.cc b/test/cpp/common/auth_property_iterator_test.cc index 630c38c7f67..e6226d6a093 100644 --- a/test/cpp/common/auth_property_iterator_test.cc +++ b/test/cpp/common/auth_property_iterator_test.cc @@ -35,11 +35,14 @@ #include #include #include "src/cpp/common/secure_auth_context.h" +#include "test/cpp/util/string_ref_helper.h" extern "C" { #include "src/core/security/security_context.h" } +using ::grpc::testing::ToString; + namespace grpc { namespace { @@ -84,12 +87,12 @@ TEST_F(AuthPropertyIteratorTest, GeneralTest) { AuthProperty p1 = *iter; iter++; AuthProperty p2 = *iter; - EXPECT_EQ("name", p0.first); - EXPECT_EQ("chapi", p0.second); - EXPECT_EQ("name", p1.first); - EXPECT_EQ("chapo", p1.second); - EXPECT_EQ("foo", p2.first); - EXPECT_EQ("bar", p2.second); + EXPECT_EQ("name", ToString(p0.first)); + EXPECT_EQ("chapi", ToString(p0.second)); + EXPECT_EQ("name", ToString(p1.first)); + EXPECT_EQ("chapo", ToString(p1.second)); + EXPECT_EQ("foo", ToString(p2.first)); + EXPECT_EQ("bar", ToString(p2.second)); ++iter; EXPECT_EQ(empty_iter, iter); } diff --git a/test/cpp/common/secure_auth_context_test.cc b/test/cpp/common/secure_auth_context_test.cc index c71ef58023f..25538c18537 100644 --- a/test/cpp/common/secure_auth_context_test.cc +++ b/test/cpp/common/secure_auth_context_test.cc @@ -35,11 +35,14 @@ #include #include #include "src/cpp/common/secure_auth_context.h" +#include "test/cpp/util/string_ref_helper.h" extern "C" { #include "src/core/security/security_context.h" } +using grpc::testing::ToString; + namespace grpc { namespace { @@ -63,14 +66,14 @@ TEST_F(SecureAuthContextTest, Properties) { EXPECT_EQ(1, grpc_auth_context_set_peer_identity_property_name(ctx, "name")); SecureAuthContext context(ctx); - std::vector peer_identity = context.GetPeerIdentity(); + std::vector peer_identity = context.GetPeerIdentity(); EXPECT_EQ(2u, peer_identity.size()); - EXPECT_EQ("chapi", peer_identity[0]); - EXPECT_EQ("chapo", peer_identity[1]); + EXPECT_EQ("chapi", ToString(peer_identity[0])); + EXPECT_EQ("chapo", ToString(peer_identity[1])); EXPECT_EQ("name", context.GetPeerIdentityPropertyName()); - std::vector bar = context.FindPropertyValues("foo"); + std::vector bar = context.FindPropertyValues("foo"); EXPECT_EQ(1u, bar.size()); - EXPECT_EQ("bar", bar[0]); + EXPECT_EQ("bar", ToString(bar[0])); } TEST_F(SecureAuthContextTest, Iterators) { @@ -88,12 +91,12 @@ TEST_F(SecureAuthContextTest, Iterators) { AuthProperty p1 = *iter; iter++; AuthProperty p2 = *iter; - EXPECT_EQ("name", p0.first); - EXPECT_EQ("chapi", p0.second); - EXPECT_EQ("name", p1.first); - EXPECT_EQ("chapo", p1.second); - EXPECT_EQ("foo", p2.first); - EXPECT_EQ("bar", p2.second); + EXPECT_EQ("name", ToString(p0.first)); + EXPECT_EQ("chapi", ToString(p0.second)); + EXPECT_EQ("name", ToString(p1.first)); + EXPECT_EQ("chapo", ToString(p1.second)); + EXPECT_EQ("foo", ToString(p2.first)); + EXPECT_EQ("bar", ToString(p2.second)); ++iter; EXPECT_EQ(context.end(), iter); } diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 6343810ee93..bbcac9ba343 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -50,6 +50,7 @@ #include "test/core/util/test_config.h" #include "test/cpp/util/echo_duplicate.grpc.pb.h" #include "test/cpp/util/echo.grpc.pb.h" +#include "test/cpp/util/string_ref_helper.h" #ifdef GPR_POSIX_SOCKET #include "src/core/iomgr/pollset_posix.h" @@ -199,8 +200,8 @@ class AsyncEnd2endTest : public ::testing::TestWithParam { } void ResetStub() { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel)); } @@ -484,8 +485,10 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) { Verifier(GetParam()).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); auto client_initial_metadata = srv_ctx.client_metadata(); - EXPECT_EQ(meta1.second, client_initial_metadata.find(meta1.first)->second); - EXPECT_EQ(meta2.second, client_initial_metadata.find(meta2.first)->second); + EXPECT_EQ(meta1.second, + ToString(client_initial_metadata.find(meta1.first)->second)); + EXPECT_EQ(meta2.second, + ToString(client_initial_metadata.find(meta2.first)->second)); EXPECT_GE(client_initial_metadata.size(), static_cast(2)); send_response.set_message(recv_request.message()); @@ -532,8 +535,10 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) { response_reader->ReadInitialMetadata(tag(4)); Verifier(GetParam()).Expect(4, true).Verify(cq_.get()); auto server_initial_metadata = cli_ctx.GetServerInitialMetadata(); - EXPECT_EQ(meta1.second, server_initial_metadata.find(meta1.first)->second); - EXPECT_EQ(meta2.second, server_initial_metadata.find(meta2.first)->second); + EXPECT_EQ(meta1.second, + ToString(server_initial_metadata.find(meta1.first)->second)); + EXPECT_EQ(meta2.second, + ToString(server_initial_metadata.find(meta2.first)->second)); EXPECT_EQ(static_cast(2), server_initial_metadata.size()); send_response.set_message(recv_request.message()); @@ -586,8 +591,10 @@ TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) { EXPECT_EQ(send_response.message(), recv_response.message()); EXPECT_TRUE(recv_status.ok()); auto server_trailing_metadata = cli_ctx.GetServerTrailingMetadata(); - EXPECT_EQ(meta1.second, server_trailing_metadata.find(meta1.first)->second); - EXPECT_EQ(meta2.second, server_trailing_metadata.find(meta2.first)->second); + EXPECT_EQ(meta1.second, + ToString(server_trailing_metadata.find(meta1.first)->second)); + EXPECT_EQ(meta2.second, + ToString(server_trailing_metadata.find(meta2.first)->second)); EXPECT_EQ(static_cast(2), server_trailing_metadata.size()); } @@ -631,8 +638,10 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { Verifier(GetParam()).Expect(2, true).Verify(cq_.get()); EXPECT_EQ(send_request.message(), recv_request.message()); auto client_initial_metadata = srv_ctx.client_metadata(); - EXPECT_EQ(meta1.second, client_initial_metadata.find(meta1.first)->second); - EXPECT_EQ(meta2.second, client_initial_metadata.find(meta2.first)->second); + EXPECT_EQ(meta1.second, + ToString(client_initial_metadata.find(meta1.first)->second)); + EXPECT_EQ(meta2.second, + ToString(client_initial_metadata.find(meta2.first)->second)); EXPECT_GE(client_initial_metadata.size(), static_cast(2)); srv_ctx.AddInitialMetadata(meta3.first, meta3.second); @@ -642,8 +651,10 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { response_reader->ReadInitialMetadata(tag(4)); Verifier(GetParam()).Expect(4, true).Verify(cq_.get()); auto server_initial_metadata = cli_ctx.GetServerInitialMetadata(); - EXPECT_EQ(meta3.second, server_initial_metadata.find(meta3.first)->second); - EXPECT_EQ(meta4.second, server_initial_metadata.find(meta4.first)->second); + EXPECT_EQ(meta3.second, + ToString(server_initial_metadata.find(meta3.first)->second)); + EXPECT_EQ(meta4.second, + ToString(server_initial_metadata.find(meta4.first)->second)); EXPECT_GE(server_initial_metadata.size(), static_cast(2)); send_response.set_message(recv_request.message()); @@ -658,8 +669,10 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) { EXPECT_EQ(send_response.message(), recv_response.message()); EXPECT_TRUE(recv_status.ok()); auto server_trailing_metadata = cli_ctx.GetServerTrailingMetadata(); - EXPECT_EQ(meta5.second, server_trailing_metadata.find(meta5.first)->second); - EXPECT_EQ(meta6.second, server_trailing_metadata.find(meta6.first)->second); + EXPECT_EQ(meta5.second, + ToString(server_trailing_metadata.find(meta5.first)->second)); + EXPECT_EQ(meta6.second, + ToString(server_trailing_metadata.find(meta6.first)->second)); EXPECT_GE(server_trailing_metadata.size(), static_cast(2)); } @@ -737,8 +750,8 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) { } TEST_P(AsyncEnd2endTest, UnimplementedRpc) { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); std::unique_ptr stub; stub = std::move(grpc::cpp::test::util::UnimplementedService::NewStub(channel)); diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc index 3359080cec5..3a6e55216af 100644 --- a/test/cpp/end2end/client_crash_test.cc +++ b/test/cpp/end2end/client_crash_test.cc @@ -76,7 +76,7 @@ class CrashTest : public ::testing::Test { })); GPR_ASSERT(server_); return grpc::cpp::test::util::TestService::NewStub( - CreateChannel(addr, InsecureCredentials(), ChannelArguments())); + CreateChannel(addr, InsecureCredentials())); } void KillServer() { server_.reset(); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 2728dce07e5..37a6e693e66 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -53,6 +53,7 @@ #include "test/core/util/test_config.h" #include "test/cpp/util/echo_duplicate.grpc.pb.h" #include "test/cpp/util/echo.grpc.pb.h" +#include "test/cpp/util/string_ref_helper.h" using grpc::cpp::test::util::EchoRequest; using grpc::cpp::test::util::EchoResponse; @@ -80,10 +81,10 @@ void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request, void CheckServerAuthContext(const ServerContext* context) { std::shared_ptr auth_ctx = context->auth_context(); - std::vector ssl = + std::vector ssl = auth_ctx->FindPropertyValues("transport_security_type"); EXPECT_EQ(1u, ssl.size()); - EXPECT_EQ("ssl", ssl[0]); + EXPECT_EQ("ssl", ToString(ssl[0])); EXPECT_TRUE(auth_ctx->GetPeerIdentityPropertyName().empty()); EXPECT_TRUE(auth_ctx->GetPeerIdentity().empty()); } @@ -152,12 +153,13 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { } if (request->has_param() && request->param().echo_metadata()) { - const std::multimap& client_metadata = + const std::multimap& client_metadata = context->client_metadata(); - for (std::multimap::const_iterator iter = - client_metadata.begin(); + for (std::multimap::const_iterator + iter = client_metadata.begin(); iter != client_metadata.end(); ++iter) { - context->AddTrailingMetadata((*iter).first, (*iter).second); + context->AddTrailingMetadata(ToString(iter->first), + ToString(iter->second)); } } if (request->has_param() && request->param().check_auth_context()) { @@ -182,12 +184,12 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { EchoRequest request; response->set_message(""); int cancel_after_reads = 0; - const std::multimap client_initial_metadata = - context->client_metadata(); + const std::multimap& + client_initial_metadata = context->client_metadata(); if (client_initial_metadata.find(kServerCancelAfterReads) != client_initial_metadata.end()) { - std::istringstream iss( - client_initial_metadata.find(kServerCancelAfterReads)->second); + std::istringstream iss(ToString( + client_initial_metadata.find(kServerCancelAfterReads)->second)); iss >> cancel_after_reads; gpr_log(GPR_INFO, "cancel_after_reads %d", cancel_after_reads); } @@ -289,8 +291,8 @@ class End2endTest : public ::testing::TestWithParam { ChannelArguments args; args.SetSslTargetNameOverride("foo.test.google.fr"); args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test"); - channel_ = - CreateChannel(server_address_.str(), SslCredentials(ssl_opts), args); + channel_ = CreateCustomChannel(server_address_.str(), + SslCredentials(ssl_opts), args); } void ResetStub(bool use_proxy) { @@ -305,8 +307,7 @@ class End2endTest : public ::testing::TestWithParam { builder.RegisterService(proxy_service_.get()); proxy_server_ = builder.BuildAndStart(); - channel_ = CreateChannel(proxyaddr.str(), InsecureCredentials(), - ChannelArguments()); + channel_ = CreateChannel(proxyaddr.str(), InsecureCredentials()); } stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); @@ -564,7 +565,7 @@ TEST_F(End2endTest, BadCredentials) { std::shared_ptr bad_creds = ServiceAccountCredentials("", "", 1); EXPECT_EQ(static_cast(nullptr), bad_creds.get()); std::shared_ptr channel = - CreateChannel(server_address_.str(), bad_creds, ChannelArguments()); + CreateChannel(server_address_.str(), bad_creds); std::unique_ptr stub( grpc::cpp::test::util::TestService::NewStub(channel)); EchoRequest request; @@ -721,14 +722,15 @@ TEST_F(End2endTest, RpcMaxMessageSize) { EXPECT_FALSE(s.ok()); } -bool MetadataContains(const std::multimap& metadata, - const grpc::string& key, const grpc::string& value) { +bool MetadataContains( + const std::multimap& metadata, + const grpc::string& key, const grpc::string& value) { int count = 0; - for (std::multimap::const_iterator iter = + for (std::multimap::const_iterator iter = metadata.begin(); iter != metadata.end(); ++iter) { - if ((*iter).first == key && (*iter).second == value) { + if (ToString(iter->first) == key && ToString(iter->second) == value) { count++; } } @@ -837,16 +839,17 @@ TEST_F(End2endTest, ClientAuthContext) { EXPECT_TRUE(s.ok()); std::shared_ptr auth_ctx = context.auth_context(); - std::vector ssl = + std::vector ssl = auth_ctx->FindPropertyValues("transport_security_type"); EXPECT_EQ(1u, ssl.size()); - EXPECT_EQ("ssl", ssl[0]); + EXPECT_EQ("ssl", ToString(ssl[0])); EXPECT_EQ("x509_subject_alternative_name", auth_ctx->GetPeerIdentityPropertyName()); EXPECT_EQ(3u, auth_ctx->GetPeerIdentity().size()); - EXPECT_EQ("*.test.google.fr", auth_ctx->GetPeerIdentity()[0]); - EXPECT_EQ("waterzooi.test.google.be", auth_ctx->GetPeerIdentity()[1]); - EXPECT_EQ("*.test.youtube.com", auth_ctx->GetPeerIdentity()[2]); + EXPECT_EQ("*.test.google.fr", ToString(auth_ctx->GetPeerIdentity()[0])); + EXPECT_EQ("waterzooi.test.google.be", + ToString(auth_ctx->GetPeerIdentity()[1])); + EXPECT_EQ("*.test.youtube.com", ToString(auth_ctx->GetPeerIdentity()[2])); } // Make the response larger than the flow control window. diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc index de7eab8dc29..7acbc711fb8 100644 --- a/test/cpp/end2end/generic_end2end_test.cc +++ b/test/cpp/end2end/generic_end2end_test.cc @@ -121,8 +121,8 @@ class GenericEnd2endTest : public ::testing::Test { } void ResetStub() { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); generic_stub_.reset(new GenericStub(channel)); } @@ -160,7 +160,7 @@ class GenericEnd2endTest : public ::testing::Test { srv_cq_.get(), tag(4)); verify_ok(srv_cq_.get(), 4, true); - EXPECT_EQ(server_host_, srv_ctx.host()); + EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length())); EXPECT_EQ(kMethodName, srv_ctx.method()); ByteBuffer recv_buffer; stream.Read(&recv_buffer, tag(5)); @@ -233,7 +233,7 @@ TEST_F(GenericEnd2endTest, SimpleBidiStreaming) { srv_cq_.get(), tag(2)); verify_ok(srv_cq_.get(), 2, true); - EXPECT_EQ(server_host_, srv_ctx.host()); + EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length())); EXPECT_EQ(kMethodName, srv_ctx.method()); std::unique_ptr send_buffer = diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc index b2c6dc39a81..077d21aa729 100644 --- a/test/cpp/end2end/mock_test.cc +++ b/test/cpp/end2end/mock_test.cc @@ -245,8 +245,8 @@ class MockTest : public ::testing::Test { void TearDown() GRPC_OVERRIDE { server_->Shutdown(); } void ResetStub() { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel)); } diff --git a/test/cpp/end2end/server_crash_test_client.cc b/test/cpp/end2end/server_crash_test_client.cc index 7ca43a0c5b8..6ff42fcb301 100644 --- a/test/cpp/end2end/server_crash_test_client.cc +++ b/test/cpp/end2end/server_crash_test_client.cc @@ -58,8 +58,8 @@ using namespace gflags; int main(int argc, char** argv) { ParseCommandLineFlags(&argc, &argv, true); - auto stub = grpc::cpp::test::util::TestService::NewStub(grpc::CreateChannel( - FLAGS_address, grpc::InsecureCredentials(), grpc::ChannelArguments())); + auto stub = grpc::cpp::test::util::TestService::NewStub( + grpc::CreateChannel(FLAGS_address, grpc::InsecureCredentials())); EchoRequest request; EchoResponse response; diff --git a/test/cpp/end2end/shutdown_test.cc b/test/cpp/end2end/shutdown_test.cc index e83f86f7ec5..59fec6ad406 100644 --- a/test/cpp/end2end/shutdown_test.cc +++ b/test/cpp/end2end/shutdown_test.cc @@ -95,7 +95,7 @@ class ShutdownTest : public ::testing::Test { void ResetStub() { string target = "dns:localhost:" + to_string(port_); - channel_ = CreateChannel(target, InsecureCredentials(), ChannelArguments()); + channel_ = CreateChannel(target, InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); } diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc index 8304f04d56a..2a164819725 100644 --- a/test/cpp/end2end/thread_stress_test.cc +++ b/test/cpp/end2end/thread_stress_test.cc @@ -191,8 +191,8 @@ class End2endTest : public ::testing::Test { void TearDown() GRPC_OVERRIDE { server_->Shutdown(); } void ResetStub() { - std::shared_ptr channel = CreateChannel( - server_address_.str(), InsecureCredentials(), ChannelArguments()); + std::shared_ptr channel = + CreateChannel(server_address_.str(), InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel)); } diff --git a/test/cpp/end2end/zookeeper_test.cc b/test/cpp/end2end/zookeeper_test.cc index e7d95b1c462..931541ca344 100644 --- a/test/cpp/end2end/zookeeper_test.cc +++ b/test/cpp/end2end/zookeeper_test.cc @@ -159,7 +159,7 @@ class ZookeeperTest : public ::testing::Test { void ResetStub() { string target = "zookeeper://" + zookeeper_address_ + "/test"; - channel_ = CreateChannel(target, InsecureCredentials(), ChannelArguments()); + channel_ = CreateChannel(target, InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); } diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc index 3bd61ea4e8b..0e771d6b815 100644 --- a/test/cpp/qps/driver.cc +++ b/test/cpp/qps/driver.cc @@ -154,8 +154,8 @@ std::unique_ptr RunScenario( // where class contained in std::vector must have a copy constructor auto* servers = new ServerData[num_servers]; for (size_t i = 0; i < num_servers; i++) { - servers[i].stub = std::move(Worker::NewStub( - CreateChannel(workers[i], InsecureCredentials(), ChannelArguments()))); + servers[i].stub = std::move( + Worker::NewStub(CreateChannel(workers[i], InsecureCredentials()))); ServerArgs args; result_server_config = server_config; result_server_config.set_host(workers[i]); @@ -182,8 +182,8 @@ std::unique_ptr RunScenario( // where class contained in std::vector must have a copy constructor auto* clients = new ClientData[num_clients]; for (size_t i = 0; i < num_clients; i++) { - clients[i].stub = std::move(Worker::NewStub(CreateChannel( - workers[i + num_servers], InsecureCredentials(), ChannelArguments()))); + clients[i].stub = std::move(Worker::NewStub( + CreateChannel(workers[i + num_servers], InsecureCredentials()))); ClientArgs args; result_client_config = client_config; result_client_config.set_host(workers[i + num_servers]); diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h index 620abade39b..5914fc4e308 100644 --- a/test/cpp/qps/report.h +++ b/test/cpp/qps/report.h @@ -116,8 +116,8 @@ class PerfDbReporter : public Reporter { test_name_(test_name), sys_info_(sys_info), tag_(tag) { - perf_db_client_.init(grpc::CreateChannel( - server_address, grpc::InsecureCredentials(), ChannelArguments())); + perf_db_client_.init( + grpc::CreateChannel(server_address, grpc::InsecureCredentials())); } ~PerfDbReporter() GRPC_OVERRIDE { SendData(); }; diff --git a/test/cpp/util/cli_call.cc b/test/cpp/util/cli_call.cc index d60cee9c024..9a769848a4b 100644 --- a/test/cpp/util/cli_call.cc +++ b/test/cpp/util/cli_call.cc @@ -51,14 +51,14 @@ void* tag(int i) { return (void*)(gpr_intptr)i; } Status CliCall::Call(std::shared_ptr channel, const grpc::string& method, const grpc::string& request, - grpc::string* response, const MetadataContainer& metadata, - MetadataContainer* server_initial_metadata, - MetadataContainer* server_trailing_metadata) { + grpc::string* response, + const OutgoingMetadataContainer& metadata, + IncomingMetadataContainer* server_initial_metadata, + IncomingMetadataContainer* server_trailing_metadata) { std::unique_ptr stub(new grpc::GenericStub(channel)); grpc::ClientContext ctx; if (!metadata.empty()) { - for (std::multimap::const_iterator iter = - metadata.begin(); + for (OutgoingMetadataContainer::const_iterator iter = metadata.begin(); iter != metadata.end(); ++iter) { ctx.AddMetadata(iter->first, iter->second); } diff --git a/test/cpp/util/cli_call.h b/test/cpp/util/cli_call.h index 7a3dcf2e9f6..2fbc9618b64 100644 --- a/test/cpp/util/cli_call.h +++ b/test/cpp/util/cli_call.h @@ -38,18 +38,22 @@ #include #include +#include namespace grpc { namespace testing { class CliCall GRPC_FINAL { public: - typedef std::multimap MetadataContainer; + typedef std::multimap OutgoingMetadataContainer; + typedef std::multimap + IncomingMetadataContainer; static Status Call(std::shared_ptr channel, const grpc::string& method, const grpc::string& request, - grpc::string* response, const MetadataContainer& metadata, - MetadataContainer* server_initial_metadata, - MetadataContainer* server_trailing_metadata); + grpc::string* response, + const OutgoingMetadataContainer& metadata, + IncomingMetadataContainer* server_initial_metadata, + IncomingMetadataContainer* server_trailing_metadata); }; } // namespace testing diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc index 35bfad202f0..0efa2016220 100644 --- a/test/cpp/util/cli_call_test.cc +++ b/test/cpp/util/cli_call_test.cc @@ -47,6 +47,7 @@ #include "test/core/util/port.h" #include "test/core/util/test_config.h" #include "test/cpp/util/echo.grpc.pb.h" +#include "test/cpp/util/string_ref_helper.h" using grpc::cpp::test::util::EchoRequest; using grpc::cpp::test::util::EchoResponse; @@ -59,10 +60,11 @@ class TestServiceImpl : public ::grpc::cpp::test::util::TestService::Service { Status Echo(ServerContext* context, const EchoRequest* request, EchoResponse* response) GRPC_OVERRIDE { if (!context->client_metadata().empty()) { - for (std::multimap::const_iterator iter = - context->client_metadata().begin(); + for (std::multimap::const_iterator + iter = context->client_metadata().begin(); iter != context->client_metadata().end(); ++iter) { - context->AddInitialMetadata(iter->first, iter->second); + context->AddInitialMetadata(ToString(iter->first), + ToString(iter->second)); } } context->AddTrailingMetadata("trailing_key", "trailing_value"); @@ -89,8 +91,7 @@ class CliCallTest : public ::testing::Test { void TearDown() GRPC_OVERRIDE { server_->Shutdown(); } void ResetStub() { - channel_ = CreateChannel(server_address_.str(), InsecureCredentials(), - ChannelArguments()); + channel_ = CreateChannel(server_address_.str(), InsecureCredentials()); stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_)); } @@ -119,8 +120,9 @@ TEST_F(CliCallTest, SimpleRpc) { grpc::string request_bin, response_bin, expected_response_bin; EXPECT_TRUE(request.SerializeToString(&request_bin)); EXPECT_TRUE(response.SerializeToString(&expected_response_bin)); - std::multimap client_metadata, - server_initial_metadata, server_trailing_metadata; + std::multimap client_metadata; + std::multimap server_initial_metadata, + server_trailing_metadata; client_metadata.insert(std::pair("key1", "val1")); Status s2 = CliCall::Call(channel_, kMethod, request_bin, &response_bin, client_metadata, &server_initial_metadata, diff --git a/test/cpp/util/create_test_channel.cc b/test/cpp/util/create_test_channel.cc index 161b4bdc1d5..e993d14e716 100644 --- a/test/cpp/util/create_test_channel.cc +++ b/test/cpp/util/create_test_channel.cc @@ -74,9 +74,9 @@ std::shared_ptr CreateTestChannel( if (creds.get()) { channel_creds = CompositeCredentials(creds, channel_creds); } - return CreateChannel(connect_to, channel_creds, channel_args); + return CreateCustomChannel(connect_to, channel_creds, channel_args); } else { - return CreateChannel(server, InsecureCredentials(), channel_args); + return CreateChannel(server, InsecureCredentials()); } } diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc index 746d67deeb9..22cac21f77e 100644 --- a/test/cpp/util/grpc_cli.cc +++ b/test/cpp/util/grpc_cli.cc @@ -68,8 +68,10 @@ #include #include #include +#include #include "test/cpp/util/cli_call.h" +#include "test/cpp/util/string_ref_helper.h" #include "test/cpp/util/test_config.h" DEFINE_bool(enable_ssl, true, "Whether to use ssl/tls."); @@ -104,16 +106,19 @@ void ParseMetadataFlag( } } -void PrintMetadata(const std::multimap& m, - const grpc::string& message) { +template +void PrintMetadata(const T& m, const grpc::string& message) { if (m.empty()) { return; } std::cout << message << std::endl; - for (std::multimap::const_iterator iter = - m.begin(); - iter != m.end(); ++iter) { - std::cout << iter->first << " : " << iter->second << std::endl; + grpc::string pair; + for (typename T::const_iterator iter = m.begin(); iter != m.end(); ++iter) { + pair.clear(); + pair.append(iter->first.data(), iter->first.size()); + pair.append(" : "); + pair.append(iter->second.data(), iter->second.size()); + std::cout << pair << std::endl; } } @@ -154,11 +159,12 @@ int main(int argc, char** argv) { } } std::shared_ptr channel = - grpc::CreateChannel(server_address, creds, grpc::ChannelArguments()); + grpc::CreateChannel(server_address, creds); grpc::string response; - std::multimap client_metadata, - server_initial_metadata, server_trailing_metadata; + std::multimap client_metadata; + std::multimap server_initial_metadata, + server_trailing_metadata; ParseMetadataFlag(&client_metadata); PrintMetadata(client_metadata, "Sending client initial metadata:"); grpc::Status s = grpc::testing::CliCall::Call( diff --git a/test/cpp/util/string_ref_helper.cc b/test/cpp/util/string_ref_helper.cc new file mode 100644 index 00000000000..4eb4fe03575 --- /dev/null +++ b/test/cpp/util/string_ref_helper.cc @@ -0,0 +1,44 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "test/cpp/util/string_ref_helper.h" + +namespace grpc { +namespace testing { + +grpc::string ToString(const grpc::string_ref& r) { + return grpc::string(r.data(), r.size()); +} + +} // namespace testing +} // namespace grpc diff --git a/examples/pubsub/publisher.h b/test/cpp/util/string_ref_helper.h similarity index 67% rename from examples/pubsub/publisher.h rename to test/cpp/util/string_ref_helper.h index 02e6194b0bd..ac94bcd018a 100644 --- a/examples/pubsub/publisher.h +++ b/test/cpp/util/string_ref_helper.h @@ -31,36 +31,17 @@ * */ -#ifndef GRPC_EXAMPLES_PUBSUB_PUBLISHER_H -#define GRPC_EXAMPLES_PUBSUB_PUBLISHER_H +#ifndef GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H +#define GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H -#include - -#include "examples/pubsub/pubsub.grpc.pb.h" +#include namespace grpc { -namespace examples { -namespace pubsub { - -class Publisher { - public: - Publisher(std::shared_ptr channel); - void Shutdown(); - - Status CreateTopic(const grpc::string& topic); - Status GetTopic(const grpc::string& topic); - Status DeleteTopic(const grpc::string& topic); - Status ListTopics(const grpc::string& project_id, - std::vector* topics); - - Status Publish(const grpc::string& topic, const grpc::string& data); +namespace testing { - private: - std::unique_ptr stub_; -}; +grpc::string ToString(const grpc::string_ref& r); -} // namespace pubsub -} // namespace examples +} // namespace testing } // namespace grpc -#endif // GRPC_EXAMPLES_PUBSUB_PUBLISHER_H +#endif // GRPC_TEST_CPP_UTIL_STRING_REF_HELPER_H diff --git a/test/cpp/util/string_ref_test.cc b/test/cpp/util/string_ref_test.cc index c4ca4fce848..465072d43eb 100644 --- a/test/cpp/util/string_ref_test.cc +++ b/test/cpp/util/string_ref_test.cc @@ -100,8 +100,8 @@ TEST_F(StringRefTest, Assignment) { TEST_F(StringRefTest, Iterator) { string_ref s(kTestString); size_t i = 0; - for (char c : s) { - EXPECT_EQ(kTestString[i++], c); + for (auto it = s.cbegin(); it != s.cend(); ++it) { + EXPECT_EQ(kTestString[i++], *it); } EXPECT_EQ(strlen(kTestString), i); } diff --git a/tools/codegen/core/gen_legal_metadata_characters.c b/tools/codegen/core/gen_legal_metadata_characters.c new file mode 100644 index 00000000000..0fbc545d8d1 --- /dev/null +++ b/tools/codegen/core/gen_legal_metadata_characters.c @@ -0,0 +1,76 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* generates constant table for metadata.c */ + +#include +#include + +static unsigned char legal_bits[256 / 8]; + +static void legal(int x) { + int byte = x / 8; + int bit = x % 8; + legal_bits[byte] |= 1 << bit; +} + +static void dump(void) { + int i; + + printf("static const gpr_uint8 legal_header_bits[256/8] = "); + for (i = 0; i < 256 / 8; i++) + printf("%c 0x%02x", i ? ',' : '{', legal_bits[i]); + printf(" };\n"); +} + +static void clear(void) { memset(legal_bits, 0, sizeof(legal_bits)); } + +int main(void) { + int i; + + clear(); + for (i = 'a'; i <= 'z'; i++) legal(i); + for (i = '0'; i <= '9'; i++) legal(i); + legal('-'); + legal('_'); + dump(); + + clear(); + for (i = 32; i <= 126; i++) { + if (i == ',') continue; + legal(i); + } + dump(); + + return 0; +} diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 1fe43efe46a..1e97047e6f5 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -845,7 +845,6 @@ src/core/json/json_common.h \ src/core/json/json_reader.h \ src/core/json/json_writer.h \ src/core/profiling/timers.h \ -src/core/profiling/timers_preciseclock.h \ src/core/statistics/census_interface.h \ src/core/statistics/census_rpc_stats.h \ src/core/surface/byte_buffer_queue.h \ @@ -1057,6 +1056,7 @@ src/core/support/stack_lockfree.h \ src/core/support/string.h \ src/core/support/string_win32.h \ src/core/support/thd_internal.h \ +src/core/support/time_precise.h \ src/core/support/alloc.c \ src/core/support/cmdline.c \ src/core/support/cpu_iphone.c \ diff --git a/tools/run_tests/build_php.sh b/tools/run_tests/build_php.sh index 2d52a6e33b4..1d81779b6ac 100755 --- a/tools/run_tests/build_php.sh +++ b/tools/run_tests/build_php.sh @@ -37,6 +37,7 @@ cd $(dirname $0)/../.. root=`pwd` export GRPC_LIB_SUBDIR=libs/$CONFIG +export CFLAGS="-Wno-parentheses-equality" # build php cd src/php diff --git a/tools/run_tests/run_csharp.bat b/tools/run_tests/run_csharp.bat index c86136767c2..310cfe0d2fe 100644 --- a/tools/run_tests/run_csharp.bat +++ b/tools/run_tests/run_csharp.bat @@ -8,7 +8,7 @@ cd /d %~dp0\..\..\src\csharp @rem set UUID variable to a random GUID, we will use it to put TestResults.xml to a dedicated directory, so that parallel test runs don't collide for /F %%i in ('powershell -Command "[guid]::NewGuid().ToString()"') do (set UUID=%%i) -packages\NUnit.Runners.2.6.4\tools\nunit-console-x86.exe -labels "%1/bin/Debug/%1.dll" -work test-results/%UUID% || goto :error +packages\NUnit.Runners.2.6.4\tools\nunit-console-x86.exe /domain:None -labels "%1/bin/Debug/%1.dll" -work test-results/%UUID% || goto :error endlocal diff --git a/tools/run_tests/run_python.sh b/tools/run_tests/run_python.sh index 858f3008009..fe5685f793e 100755 --- a/tools/run_tests/run_python.sh +++ b/tools/run_tests/run_python.sh @@ -45,6 +45,8 @@ source "python"$PYVER"_virtual_environment"/bin/activate # py.test (or find another tool or *something*) that's acceptable to the rest of # the team... "python"$PYVER -m grpc_test._core_over_links_base_interface_test +"python"$PYVER -m grpc_test._crust_over_core_over_links_face_interface_test +"python"$PYVER -m grpc_test.framework._crust_over_core_face_interface_test "python"$PYVER -m grpc_test.framework.core._base_interface_test "python"$PYVER $GRPCIO_TEST/setup.py test -a "-n8 --cov=grpc --junitxml=./report.xml --timeout=300" diff --git a/tools/run_tests/run_sanity.sh b/tools/run_tests/run_sanity.sh index ac331b54d32..2737e564c6d 100755 --- a/tools/run_tests/run_sanity.sh +++ b/tools/run_tests/run_sanity.sh @@ -46,7 +46,7 @@ diff -u $submodules - << EOF 05b155ff59114735ec8cd089f669c4c3d8f59029 third_party/gflags (v2.1.0-45-g05b155f) c99458533a9b4c743ed51537e25989ea55944908 third_party/googletest (release-1.7.0) 33dd08320648ac71d7d9d732be774ed3818dccc5 third_party/openssl (OpenSSL_1_0_2d) - 3e2c8a5dd79481e1d36572cdf65be93514ba6581 third_party/protobuf (v3.0.0-alpha-1-1048-g3e2c8a5) + 23408684b4d2bf1b25e14314413a14d542c18bc4 third_party/protobuf (v3.0.0-alpha-1-1592-g2340868) 50893291621658f355bc5b4d450a8d06a563053d third_party/zlib (v1.2.8) EOF diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index beb43438e58..64900b62008 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -70,13 +70,14 @@ def platform_string(): # SimpleConfig: just compile with CONFIG=config, and run the binary to test class SimpleConfig(object): - def __init__(self, config, environ=None): + def __init__(self, config, environ=None, timeout_seconds=5*60): if environ is None: environ = {} self.build_config = config self.allow_hashing = (config != 'gcov') self.environ = environ self.environ['CONFIG'] = config + self.timeout_seconds = timeout_seconds def job_spec(self, cmdline, hash_targets, shortname=None, environ={}): """Construct a jobset.JobSpec for a test under this config @@ -96,6 +97,7 @@ class SimpleConfig(object): return jobset.JobSpec(cmdline=cmdline, shortname=shortname, environ=actual_environ, + timeout_seconds=self.timeout_seconds, hash_targets=hash_targets if self.allow_hashing else None) @@ -354,11 +356,11 @@ class Build(object): _CONFIGS = { 'dbg': SimpleConfig('dbg'), 'opt': SimpleConfig('opt'), - 'tsan': SimpleConfig('tsan', environ={ + 'tsan': SimpleConfig('tsan', timeout_seconds=10*60, environ={ 'TSAN_OPTIONS': 'suppressions=tools/tsan_suppressions.txt:halt_on_error=1:second_deadlock_stack=1'}), - 'msan': SimpleConfig('msan'), + 'msan': SimpleConfig('msan', timeout_seconds=7*60), 'ubsan': SimpleConfig('ubsan'), - 'asan': SimpleConfig('asan', environ={ + 'asan': SimpleConfig('asan', timeout_seconds=7*60, environ={ 'ASAN_OPTIONS': 'detect_leaks=1:color=always:suppressions=tools/tsan_suppressions.txt', 'LSAN_OPTIONS': 'report_objects=1'}), 'asan-noleaks': SimpleConfig('asan', environ={ @@ -465,7 +467,8 @@ if len(build_configs) > 1: if platform.system() == 'Windows': def make_jobspec(cfg, targets): return jobset.JobSpec(['make.bat', 'CONFIG=%s' % cfg] + targets, - cwd='vsprojects', shell=True) + cwd='vsprojects', shell=True, + timeout_seconds=30*60) else: def make_jobspec(cfg, targets): return jobset.JobSpec([os.getenv('MAKE', 'make'), @@ -535,7 +538,8 @@ def _start_port_server(port_server_port): # if not running ==> start a new one # otherwise, leave it up try: - version = urllib2.urlopen('http://localhost:%d/version' % port_server_port).read() + version = urllib2.urlopen('http://localhost:%d/version' % port_server_port, + timeout=1).read() running = True except Exception: running = False @@ -553,12 +557,20 @@ def _start_port_server(port_server_port): stderr=subprocess.STDOUT, stdout=port_log) # ensure port server is up + waits = 0 while True: + if waits > 10: + port_server.kill() + print "port_server failed to start" + sys.exit(1) try: - urllib2.urlopen('http://localhost:%d/get' % port_server_port).read() + urllib2.urlopen('http://localhost:%d/get' % port_server_port, + timeout=1).read() break except urllib2.URLError: + print "waiting for port_server" time.sleep(0.5) + waits += 1 except: port_server.kill() raise diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index e8cd3ef1bf8..1aa5973df01 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -237,6 +237,15 @@ "tools/codegen/core/gen_hpack_tables.c" ] }, + { + "deps": [], + "headers": [], + "language": "c", + "name": "gen_legal_metadata_characters", + "src": [ + "tools/codegen/core/gen_legal_metadata_characters.c" + ] + }, { "deps": [ "gpr", @@ -1068,8 +1077,11 @@ { "deps": [ "gpr", + "gpr_test_util", "grpc", - "grpc++" + "grpc++", + "grpc++_test_util", + "grpc_test_util" ], "headers": [], "language": "c++", @@ -1376,57 +1388,6 @@ "test/cpp/end2end/mock_test.cc" ] }, - { - "deps": [ - "gpr", - "gpr_test_util", - "grpc", - "grpc++", - "grpc++_test_config", - "grpc_test_util", - "pubsub_client_lib" - ], - "headers": [], - "language": "c++", - "name": "pubsub_client", - "src": [ - "examples/pubsub/main.cc" - ] - }, - { - "deps": [ - "gpr", - "gpr_test_util", - "grpc", - "grpc++", - "grpc++_test_util", - "grpc_test_util", - "pubsub_client_lib" - ], - "headers": [], - "language": "c++", - "name": "pubsub_publisher_test", - "src": [ - "examples/pubsub/publisher_test.cc" - ] - }, - { - "deps": [ - "gpr", - "gpr_test_util", - "grpc", - "grpc++", - "grpc++_test_util", - "grpc_test_util", - "pubsub_client_lib" - ], - "headers": [], - "language": "c++", - "name": "pubsub_subscriber_test", - "src": [ - "examples/pubsub/subscriber_test.cc" - ] - }, { "deps": [ "gpr", @@ -1573,8 +1534,11 @@ { "deps": [ "gpr", + "gpr_test_util", "grpc", - "grpc++" + "grpc++", + "grpc++_test_util", + "grpc_test_util" ], "headers": [], "language": "c++", @@ -12159,7 +12123,8 @@ "src/core/support/stack_lockfree.h", "src/core/support/string.h", "src/core/support/string_win32.h", - "src/core/support/thd_internal.h" + "src/core/support/thd_internal.h", + "src/core/support/time_precise.h" ], "language": "c", "name": "gpr", @@ -12233,6 +12198,7 @@ "src/core/support/thd_win32.c", "src/core/support/time.c", "src/core/support/time_posix.c", + "src/core/support/time_precise.h", "src/core/support/time_win32.c", "src/core/support/tls_pthread.c" ] @@ -12330,7 +12296,6 @@ "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/security/auth_filters.h", "src/core/security/base64.h", "src/core/security/credentials.h", @@ -12532,7 +12497,6 @@ "src/core/profiling/basic_timers.c", "src/core/profiling/stap_timers.c", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/security/auth_filters.h", "src/core/security/base64.c", "src/core/security/base64.h", @@ -12808,7 +12772,6 @@ "src/core/json/json_reader.h", "src/core/json/json_writer.h", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/statistics/census_interface.h", "src/core/statistics/census_rpc_stats.h", "src/core/surface/byte_buffer_queue.h", @@ -12995,7 +12958,6 @@ "src/core/profiling/basic_timers.c", "src/core/profiling/stap_timers.c", "src/core/profiling/timers.h", - "src/core/profiling/timers_preciseclock.h", "src/core/statistics/census_interface.h", "src/core/statistics/census_rpc_stats.h", "src/core/surface/byte_buffer.c", @@ -13278,6 +13240,7 @@ "test/cpp/util/echo_duplicate.pb.h", "test/cpp/util/messages.grpc.pb.h", "test/cpp/util/messages.pb.h", + "test/cpp/util/string_ref_helper.h", "test/cpp/util/subprocess.h" ], "language": "c++", @@ -13287,6 +13250,8 @@ "test/cpp/util/cli_call.h", "test/cpp/util/create_test_channel.cc", "test/cpp/util/create_test_channel.h", + "test/cpp/util/string_ref_helper.cc", + "test/cpp/util/string_ref_helper.h", "test/cpp/util/subprocess.cc", "test/cpp/util/subprocess.h" ] @@ -13552,31 +13517,6 @@ "test/cpp/interop/server.cc" ] }, - { - "deps": [ - "gpr", - "grpc", - "grpc++" - ], - "headers": [ - "examples/pubsub/empty.grpc.pb.h", - "examples/pubsub/empty.pb.h", - "examples/pubsub/label.grpc.pb.h", - "examples/pubsub/label.pb.h", - "examples/pubsub/publisher.h", - "examples/pubsub/pubsub.grpc.pb.h", - "examples/pubsub/pubsub.pb.h", - "examples/pubsub/subscriber.h" - ], - "language": "c++", - "name": "pubsub_client_lib", - "src": [ - "examples/pubsub/publisher.cc", - "examples/pubsub/publisher.h", - "examples/pubsub/subscriber.cc", - "examples/pubsub/subscriber.h" - ] - }, { "deps": [ "grpc++", diff --git a/vsprojects/Grpc.mak b/vsprojects/Grpc.mak index 2893b72c5de..15a500dcae5 100644 --- a/vsprojects/Grpc.mak +++ b/vsprojects/Grpc.mak @@ -183,6 +183,14 @@ gen_hpack_tables: gen_hpack_tables.exe echo Running gen_hpack_tables $(OUT_DIR)\gen_hpack_tables.exe +gen_legal_metadata_characters.exe: $(OUT_DIR) + echo Building gen_legal_metadata_characters + $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\tools\codegen\core\gen_legal_metadata_characters.c + $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\gen_legal_metadata_characters.exe" $(LIBS) $(OUT_DIR)\gen_legal_metadata_characters.obj +gen_legal_metadata_characters: gen_legal_metadata_characters.exe + echo Running gen_legal_metadata_characters + $(OUT_DIR)\gen_legal_metadata_characters.exe + gpr_cmdline_test.exe: build_gpr_test_util build_gpr $(OUT_DIR) echo Building gpr_cmdline_test $(CC) $(CFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\core\support\cmdline_test.c @@ -615,10 +623,10 @@ async_end2end_test: async_end2end_test.exe echo Running async_end2end_test $(OUT_DIR)\async_end2end_test.exe -auth_property_iterator_test.exe: build_grpc++ build_grpc build_gpr $(OUT_DIR) +auth_property_iterator_test.exe: Debug\grpc++_test_util.lib build_grpc_test_util build_grpc++ build_grpc build_gpr_test_util build_gpr $(OUT_DIR) echo Building auth_property_iterator_test $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\common\auth_property_iterator_test.cc - $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\auth_property_iterator_test.exe" Debug\grpc++.lib Debug\grpc.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\auth_property_iterator_test.obj + $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\auth_property_iterator_test.exe" Debug\grpc++_test_util.lib Debug\grpc_test_util.lib Debug\grpc++.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\auth_property_iterator_test.obj auth_property_iterator_test: auth_property_iterator_test.exe echo Running auth_property_iterator_test $(OUT_DIR)\auth_property_iterator_test.exe @@ -751,10 +759,10 @@ reconnect_interop_server: reconnect_interop_server.exe echo Running reconnect_interop_server $(OUT_DIR)\reconnect_interop_server.exe -secure_auth_context_test.exe: build_grpc++ build_grpc build_gpr $(OUT_DIR) +secure_auth_context_test.exe: Debug\grpc++_test_util.lib build_grpc_test_util build_grpc++ build_grpc build_gpr_test_util build_gpr $(OUT_DIR) echo Building secure_auth_context_test $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\common\secure_auth_context_test.cc - $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\secure_auth_context_test.exe" Debug\grpc++.lib Debug\grpc.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\secure_auth_context_test.obj + $(LINK) $(LFLAGS) /OUT:"$(OUT_DIR)\secure_auth_context_test.exe" Debug\grpc++_test_util.lib Debug\grpc_test_util.lib Debug\grpc++.lib Debug\grpc.lib Debug\gpr_test_util.lib Debug\gpr.lib $(CXX_LIBS) $(LIBS) $(OUT_DIR)\secure_auth_context_test.obj secure_auth_context_test: secure_auth_context_test.exe echo Running secure_auth_context_test $(OUT_DIR)\secure_auth_context_test.exe @@ -4744,8 +4752,8 @@ Debug\grpc++_test_config.lib: $(OUT_DIR) Debug\grpc++_test_util.lib: $(OUT_DIR) echo Building grpc++_test_util - $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\util\cli_call.cc $(REPO_ROOT)\test\cpp\util\create_test_channel.cc $(REPO_ROOT)\test\cpp\util\subprocess.cc $(REPO_ROOT)\test\cpp\util\messages.pb.cc $(REPO_ROOT)\test\cpp\util\messages.grpc.pb.cc $(REPO_ROOT)\test\cpp\util\echo.pb.cc $(REPO_ROOT)\test\cpp\util\echo.grpc.pb.cc $(REPO_ROOT)\test\cpp\util\echo_duplicate.pb.cc $(REPO_ROOT)\test\cpp\util\echo_duplicate.grpc.pb.cc - $(LIBTOOL) /OUT:"Debug\grpc++_test_util.lib" $(OUT_DIR)\cli_call.obj $(OUT_DIR)\create_test_channel.obj $(OUT_DIR)\subprocess.obj $(OUT_DIR)\messages.pb.obj $(OUT_DIR)\messages.grpc.pb.obj $(OUT_DIR)\echo.pb.obj $(OUT_DIR)\echo.grpc.pb.obj $(OUT_DIR)\echo_duplicate.pb.obj $(OUT_DIR)\echo_duplicate.grpc.pb.obj + $(CC) $(CXXFLAGS) /Fo:$(OUT_DIR)\ $(REPO_ROOT)\test\cpp\util\cli_call.cc $(REPO_ROOT)\test\cpp\util\create_test_channel.cc $(REPO_ROOT)\test\cpp\util\string_ref_helper.cc $(REPO_ROOT)\test\cpp\util\subprocess.cc $(REPO_ROOT)\test\cpp\util\messages.pb.cc $(REPO_ROOT)\test\cpp\util\messages.grpc.pb.cc $(REPO_ROOT)\test\cpp\util\echo.pb.cc $(REPO_ROOT)\test\cpp\util\echo.grpc.pb.cc $(REPO_ROOT)\test\cpp\util\echo_duplicate.pb.cc $(REPO_ROOT)\test\cpp\util\echo_duplicate.grpc.pb.cc + $(LIBTOOL) /OUT:"Debug\grpc++_test_util.lib" $(OUT_DIR)\cli_call.obj $(OUT_DIR)\create_test_channel.obj $(OUT_DIR)\string_ref_helper.obj $(OUT_DIR)\subprocess.obj $(OUT_DIR)\messages.pb.obj $(OUT_DIR)\messages.grpc.pb.obj $(OUT_DIR)\echo.pb.obj $(OUT_DIR)\echo.grpc.pb.obj $(OUT_DIR)\echo_duplicate.pb.obj $(OUT_DIR)\echo_duplicate.grpc.pb.obj build_grpc++_unsecure: msbuild grpc.sln /t:grpc++_unsecure /p:Configuration=Debug /p:Linkage-grpc_dependencies_zlib=static diff --git a/vsprojects/README.md b/vsprojects/README.md index e6cbf833590..b95b468465c 100644 --- a/vsprojects/README.md +++ b/vsprojects/README.md @@ -80,7 +80,12 @@ Individual tests can be run by directly running the executable in `/vsprojects/r For generating service stub code, gRPC relies on plugins for `protoc` (the protocol buffer compiler). The solution `grpc_protoc_plugins.sln` allows you to build Windows .exe binaries of gRPC protoc plugins. -1. Open solution `third_party\protobuf\vsprojects\protobuf.sln` -2. Accept the conversion to newer Visual Studio version and ignore errors about gtest. -3. Build libprotoc in Release mode. -4. Open solution `vsprojects\grpc_protoc_plugins.sln` and build it in Release mode. As a result, you should obtain a set of gRPC protoc plugin binaries (`grpc_cpp_plugin.exe`, `grpc_csharp_plugin.exe`, ...) +1. Follow instructions in `third_party\protobuf\cmake\README.md` to create Visual Studio 2013 projects for protobuf. +``` +$ cd third_party/protobuf/cmake +$ cmake -G "Visual Studio 12 2013" +``` + +2. Open solution `third_party\protobuf\cmake\protobuf.sln` and build it in Release mode. That will build libraries `libprotobuf.lib` and `libprotoc.lib` needed for the next step. + +3. Open solution `vsprojects\grpc_protoc_plugins.sln` and build it in Release mode. As a result, you should obtain a set of gRPC protoc plugin binaries (`grpc_cpp_plugin.exe`, `grpc_csharp_plugin.exe`, ...) diff --git a/vsprojects/build_plugins.bat b/vsprojects/build_plugins.bat new file mode 100644 index 00000000000..4c33a584ad4 --- /dev/null +++ b/vsprojects/build_plugins.bat @@ -0,0 +1,23 @@ +@rem Convenience script to build gRPC protoc plugins from command line. protoc plugins are used to generate service stub code from .proto service defintions. + +setlocal + +@rem enter this directory +cd /d %~dp0 + +@rem Set VS variables (uses Visual Studio 2013) +@call "%VS120COMNTOOLS%\..\..\vc\vcvarsall.bat" x86 + +@rem Build third_party/protobuf +msbuild ..\third_party\protobuf\cmake\protobuf.sln /p:Configuration=Release || goto :error + +@rem Build the C# protoc plugins +msbuild grpc_protoc_plugins.sln /p:Configuration=Release || goto :error + +endlocal + +goto :EOF + +:error +echo Failed! +exit /b %errorlevel% diff --git a/vsprojects/gpr/gpr.vcxproj b/vsprojects/gpr/gpr.vcxproj index 83c295625d8..3f8f554fd31 100644 --- a/vsprojects/gpr/gpr.vcxproj +++ b/vsprojects/gpr/gpr.vcxproj @@ -158,6 +158,7 @@ + diff --git a/vsprojects/gpr/gpr.vcxproj.filters b/vsprojects/gpr/gpr.vcxproj.filters index 64b90924ab4..b6ac061e05f 100644 --- a/vsprojects/gpr/gpr.vcxproj.filters +++ b/vsprojects/gpr/gpr.vcxproj.filters @@ -218,6 +218,9 @@ src\core\support + + src\core\support + diff --git a/vsprojects/grpc/grpc.vcxproj b/vsprojects/grpc/grpc.vcxproj index fdb637b590e..49b8a6f015c 100644 --- a/vsprojects/grpc/grpc.vcxproj +++ b/vsprojects/grpc/grpc.vcxproj @@ -307,7 +307,6 @@ - diff --git a/vsprojects/grpc/grpc.vcxproj.filters b/vsprojects/grpc/grpc.vcxproj.filters index 10ec6e62039..eaee49ed080 100644 --- a/vsprojects/grpc/grpc.vcxproj.filters +++ b/vsprojects/grpc/grpc.vcxproj.filters @@ -677,9 +677,6 @@ src\core\profiling - - src\core\profiling - src\core\statistics diff --git a/vsprojects/grpc_cpp_plugin/grpc_cpp_plugin.vcxproj b/vsprojects/grpc_cpp_plugin/grpc_cpp_plugin.vcxproj index 1693a48438a..1fd03e185d4 100644 --- a/vsprojects/grpc_cpp_plugin/grpc_cpp_plugin.vcxproj +++ b/vsprojects/grpc_cpp_plugin/grpc_cpp_plugin.vcxproj @@ -48,6 +48,7 @@ + diff --git a/vsprojects/grpc_csharp_plugin/grpc_csharp_plugin.vcxproj b/vsprojects/grpc_csharp_plugin/grpc_csharp_plugin.vcxproj index aae82723e44..2d63a8496ba 100644 --- a/vsprojects/grpc_csharp_plugin/grpc_csharp_plugin.vcxproj +++ b/vsprojects/grpc_csharp_plugin/grpc_csharp_plugin.vcxproj @@ -48,6 +48,7 @@ + diff --git a/vsprojects/grpc_objective_c_plugin/grpc_objective_c_plugin.vcxproj b/vsprojects/grpc_objective_c_plugin/grpc_objective_c_plugin.vcxproj index 07a837a8042..46e064f3e35 100644 --- a/vsprojects/grpc_objective_c_plugin/grpc_objective_c_plugin.vcxproj +++ b/vsprojects/grpc_objective_c_plugin/grpc_objective_c_plugin.vcxproj @@ -48,6 +48,7 @@ + diff --git a/vsprojects/grpc_python_plugin/grpc_python_plugin.vcxproj b/vsprojects/grpc_python_plugin/grpc_python_plugin.vcxproj index 02bab1c61b5..a1e3a4aa6c6 100644 --- a/vsprojects/grpc_python_plugin/grpc_python_plugin.vcxproj +++ b/vsprojects/grpc_python_plugin/grpc_python_plugin.vcxproj @@ -48,6 +48,7 @@ + diff --git a/vsprojects/grpc_ruby_plugin/grpc_ruby_plugin.vcxproj b/vsprojects/grpc_ruby_plugin/grpc_ruby_plugin.vcxproj index 4763d148580..7f316785300 100644 --- a/vsprojects/grpc_ruby_plugin/grpc_ruby_plugin.vcxproj +++ b/vsprojects/grpc_ruby_plugin/grpc_ruby_plugin.vcxproj @@ -48,6 +48,7 @@ + diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj index 93e1e0fc292..6326c89df1e 100644 --- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj @@ -290,7 +290,6 @@ - diff --git a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters index ed0896c81a0..e3d2f437cac 100644 --- a/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -575,9 +575,6 @@ src\core\profiling - - src\core\profiling - src\core\statistics diff --git a/vsprojects/protobuf.props b/vsprojects/protobuf.props index d2685f7762b..4a3c49266f0 100644 --- a/vsprojects/protobuf.props +++ b/vsprojects/protobuf.props @@ -6,7 +6,7 @@ libprotobuf.lib;%(AdditionalDependencies) - $(ProjectDir)\..\..\third_party\protobuf\vsprojects\$(Configuration);%(AdditionalLibraryDirectories) + $(ProjectDir)\..\..\third_party\protobuf\cmake\$(Configuration);%(AdditionalLibraryDirectories) diff --git a/vsprojects/protoc.props b/vsprojects/protoc.props index 6024022690f..fc89694633d 100644 --- a/vsprojects/protoc.props +++ b/vsprojects/protoc.props @@ -6,7 +6,7 @@ libprotoc.lib;%(AdditionalDependencies) - $(ProjectDir)\..\..\third_party\protobuf\vsprojects\$(Configuration);%(AdditionalLibraryDirectories) + $(ProjectDir)\..\..\third_party\protobuf\cmake\$(Configuration);%(AdditionalLibraryDirectories)