├── third_party ├── BUILD ├── lz4.BUILD └── snappy.BUILD ├── src ├── include │ └── srpc │ │ ├── rpc_basic.h │ │ ├── rpc_buffer.h │ │ ├── rpc_client.h │ │ ├── rpc_define.h │ │ ├── rpc_global.h │ │ ├── rpc_server.h │ │ ├── rpc_task.inl │ │ ├── rpc_types.h │ │ ├── rpc_var.h │ │ ├── parser.h │ │ ├── printer.h │ │ ├── rpc_context.h │ │ ├── rpc_context.inl │ │ ├── rpc_options.h │ │ ├── rpc_service.h │ │ ├── descriptor.h │ │ ├── generator.h │ │ ├── rpc_filter.h │ │ ├── rpc_message.h │ │ ├── rpc_module.h │ │ ├── ckms_quantiles.h │ │ ├── rpc_compress.h │ │ ├── rpc_thrift_idl.h │ │ ├── rpc_compress_lz4.h │ │ ├── rpc_message_brpc.h │ │ ├── rpc_message_srpc.h │ │ ├── rpc_message_trpc.h │ │ ├── rpc_thrift_buffer.h │ │ ├── rpc_thrift_enum.h │ │ ├── rpc_thrift_idl.inl │ │ ├── rpc_trace_filter.h │ │ ├── rpc_trace_module.h │ │ ├── rpc_zero_copy_stream.h │ │ ├── rpc_compress_gzip.h │ │ ├── rpc_message_thrift.h │ │ ├── rpc_metrics_filter.h │ │ ├── rpc_metrics_module.h │ │ ├── time_window_quantiles.h │ │ └── rpc_compress_snappy.h ├── thrift │ ├── CMakeLists.txt │ ├── rpc_thrift_enum.h │ ├── rpc_thrift_idl.h │ └── rpc_thrift_buffer.h ├── var │ ├── CMakeLists.txt │ └── time_window_quantiles.h ├── http │ ├── CMakeLists.txt │ ├── http_server.h │ ├── http_module.h │ ├── http_client.h │ └── http_server.cc ├── generator │ ├── CMakeLists.txt │ ├── generator.h │ └── parser.h ├── message │ ├── CMakeLists.txt │ ├── rpc_meta.proto │ └── rpc_meta_trpc.proto ├── module │ ├── CMakeLists.txt │ ├── proto │ │ ├── opentelemetry_resource.proto │ │ ├── opentelemetry_metrics_service.proto │ │ └── opentelemetry_common.proto │ ├── rpc_metrics_module.cc │ └── rpc_metrics_module.h ├── compress │ ├── CMakeLists.txt │ ├── rpc_compress_snappy.h │ ├── rpc_compress.cc │ └── rpc_compress_snappy.cc ├── rpc_global.h ├── rpc_define.h ├── rpc_basic.cc ├── rpc_options.h ├── rpc_service.h ├── rpc_zero_copy_stream.h └── rpc_global.cc ├── tools ├── templates │ ├── file │ │ ├── 404.html │ │ ├── index.html │ │ ├── server.conf │ │ ├── 50x.html │ │ ├── server_main.cc │ │ ├── file_service.h │ │ └── file_service.cc │ ├── rpc │ │ ├── server.conf │ │ ├── rpc.thrift │ │ ├── client.conf │ │ ├── rpc.proto │ │ ├── server_thrift.cc │ │ ├── server_protobuf.cc │ │ ├── client_protobuf.cc │ │ ├── client_thrift.cc │ │ └── CMakeLists.txt │ ├── basic │ │ ├── server.conf │ │ ├── client.conf │ │ ├── server_main.cc │ │ ├── client_main.cc │ │ └── compute_server_main.cc │ ├── proxy │ │ ├── proxy.conf │ │ ├── client_rpc.conf │ │ ├── proxy_main_proto.cc │ │ └── proxy_main.cc │ ├── common │ │ ├── GNUmakefile │ │ ├── util.h │ │ ├── CMakeLists.txt │ │ └── config.json │ └── config │ │ ├── config_simple.h │ │ └── config_full.h ├── GNUmakefile ├── CMakeLists.txt └── srpc_ctl.cc ├── docs ├── images │ ├── benchmark1.png │ ├── benchmark2.png │ ├── benchmark3.png │ ├── benchmark4.png │ ├── benchmark5.png │ └── benchmark6.png ├── docs-01-idl.md ├── en │ ├── docs-01-idl.md │ ├── docs-02-service.md │ ├── docs-04-client.md │ ├── docs-03-server.md │ └── docs-05-context.md ├── docs-02-service.md ├── docs-04-client.md ├── docs-03-server.md ├── docs-05-context.md └── installation.md ├── .bazelignore ├── .editorconfig ├── benchmark ├── benchmark_thrift.thrift ├── benchmark_pb.proto ├── test.py ├── GNUmakefile └── thrift_server.cc ├── test ├── test_thrift.thrift ├── test_pb.proto ├── GNUmakefile └── var_unittest.cc ├── tutorial ├── echo_thrift.thrift ├── helloworld.proto ├── echo_pb.proto ├── GNUmakefile ├── tutorial-07-thrift_thrift_server.cc ├── tutorial-02-srpc_pb_client.cc ├── tutorial-01-srpc_pb_server.cc ├── tutorial-03-srpc_thrift_server.cc ├── tutorial-14-trpc_http_client.cc ├── tutorial-12-trpc_pb_client.cc ├── tutorial-18-http_client.cc ├── tutorial-05-brpc_pb_server.cc ├── tutorial-06-brpc_pb_client.cc ├── tutorial-17-http_server.cc ├── tutorial-09-client_task.cc ├── tutorial-04-srpc_thrift_client.cc ├── tutorial-11-trpc_pb_server.cc ├── tutorial-13-trpc_http_server.cc ├── tutorial-15-srpc_pb_proxy.cc ├── tutorial-10-server_async.cc ├── tutorial-08-thrift_thrift_client.cc └── tutorial-16-server_with_metrics.cc ├── .gitmodules ├── srpc-config.cmake.in ├── .gitignore ├── WORKSPACE ├── CMakeLists_Headers.txt ├── GNUmakefile ├── srpc.bzl ├── .github └── workflows │ └── ci.yml └── CODE_OF_CONDUCT.md /third_party/BUILD: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/include/srpc/rpc_basic.h: -------------------------------------------------------------------------------- 1 | ../../rpc_basic.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_buffer.h: -------------------------------------------------------------------------------- 1 | ../../rpc_buffer.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_client.h: -------------------------------------------------------------------------------- 1 | ../../rpc_client.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_define.h: -------------------------------------------------------------------------------- 1 | ../../rpc_define.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_global.h: -------------------------------------------------------------------------------- 1 | ../../rpc_global.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_server.h: -------------------------------------------------------------------------------- 1 | ../../rpc_server.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_task.inl: -------------------------------------------------------------------------------- 1 | ../../rpc_task.inl -------------------------------------------------------------------------------- /src/include/srpc/rpc_types.h: -------------------------------------------------------------------------------- 1 | ../../rpc_types.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_var.h: -------------------------------------------------------------------------------- 1 | ../../var/rpc_var.h -------------------------------------------------------------------------------- /src/include/srpc/parser.h: -------------------------------------------------------------------------------- 1 | ../../generator/parser.h -------------------------------------------------------------------------------- /src/include/srpc/printer.h: -------------------------------------------------------------------------------- 1 | ../../generator/printer.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_context.h: -------------------------------------------------------------------------------- 1 | ../../rpc_context.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_context.inl: -------------------------------------------------------------------------------- 1 | ../../rpc_context.inl -------------------------------------------------------------------------------- /src/include/srpc/rpc_options.h: -------------------------------------------------------------------------------- 1 | ../../rpc_options.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_service.h: -------------------------------------------------------------------------------- 1 | ../../rpc_service.h -------------------------------------------------------------------------------- /src/include/srpc/descriptor.h: -------------------------------------------------------------------------------- 1 | ../../generator/descriptor.h -------------------------------------------------------------------------------- /src/include/srpc/generator.h: -------------------------------------------------------------------------------- 1 | ../../generator/generator.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_filter.h: -------------------------------------------------------------------------------- 1 | ../../module/rpc_filter.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_message.h: -------------------------------------------------------------------------------- 1 | ../../message/rpc_message.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_module.h: -------------------------------------------------------------------------------- 1 | ../../module/rpc_module.h -------------------------------------------------------------------------------- /src/include/srpc/ckms_quantiles.h: -------------------------------------------------------------------------------- 1 | ../../var/ckms_quantiles.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_compress.h: -------------------------------------------------------------------------------- 1 | ../../compress/rpc_compress.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_thrift_idl.h: -------------------------------------------------------------------------------- 1 | ../../thrift/rpc_thrift_idl.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_compress_lz4.h: -------------------------------------------------------------------------------- 1 | ../../compress/rpc_compress_lz4.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_message_brpc.h: -------------------------------------------------------------------------------- 1 | ../../message/rpc_message_brpc.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_message_srpc.h: -------------------------------------------------------------------------------- 1 | ../../message/rpc_message_srpc.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_message_trpc.h: -------------------------------------------------------------------------------- 1 | ../../message/rpc_message_trpc.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_thrift_buffer.h: -------------------------------------------------------------------------------- 1 | ../../thrift/rpc_thrift_buffer.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_thrift_enum.h: -------------------------------------------------------------------------------- 1 | ../../thrift/rpc_thrift_enum.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_thrift_idl.inl: -------------------------------------------------------------------------------- 1 | ../../thrift/rpc_thrift_idl.inl -------------------------------------------------------------------------------- /src/include/srpc/rpc_trace_filter.h: -------------------------------------------------------------------------------- 1 | ../../module/rpc_trace_filter.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_trace_module.h: -------------------------------------------------------------------------------- 1 | ../../module/rpc_trace_module.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_zero_copy_stream.h: -------------------------------------------------------------------------------- 1 | ../../rpc_zero_copy_stream.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_compress_gzip.h: -------------------------------------------------------------------------------- 1 | ../../compress/rpc_compress_gzip.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_message_thrift.h: -------------------------------------------------------------------------------- 1 | ../../message/rpc_message_thrift.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_metrics_filter.h: -------------------------------------------------------------------------------- 1 | ../../module/rpc_metrics_filter.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_metrics_module.h: -------------------------------------------------------------------------------- 1 | ../../module/rpc_metrics_module.h -------------------------------------------------------------------------------- /src/include/srpc/time_window_quantiles.h: -------------------------------------------------------------------------------- 1 | ../../var/time_window_quantiles.h -------------------------------------------------------------------------------- /src/include/srpc/rpc_compress_snappy.h: -------------------------------------------------------------------------------- 1 | ../../compress/rpc_compress_snappy.h -------------------------------------------------------------------------------- /tools/templates/file/404.html: -------------------------------------------------------------------------------- 1 | This is not the web page you are looking for. 2 | -------------------------------------------------------------------------------- /tools/templates/file/index.html: -------------------------------------------------------------------------------- 1 | Hello from workflow and srpc file server! 2 | -------------------------------------------------------------------------------- /docs/images/benchmark1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sogou/srpc/HEAD/docs/images/benchmark1.png -------------------------------------------------------------------------------- /docs/images/benchmark2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sogou/srpc/HEAD/docs/images/benchmark2.png -------------------------------------------------------------------------------- /docs/images/benchmark3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sogou/srpc/HEAD/docs/images/benchmark3.png -------------------------------------------------------------------------------- /docs/images/benchmark4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sogou/srpc/HEAD/docs/images/benchmark4.png -------------------------------------------------------------------------------- /docs/images/benchmark5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sogou/srpc/HEAD/docs/images/benchmark5.png -------------------------------------------------------------------------------- /docs/images/benchmark6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sogou/srpc/HEAD/docs/images/benchmark6.png -------------------------------------------------------------------------------- /tools/templates/rpc/server.conf: -------------------------------------------------------------------------------- 1 | { 2 | "server": 3 | { 4 | "port": 1412 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tools/templates/basic/server.conf: -------------------------------------------------------------------------------- 1 | { 2 | "server": 3 | { 4 | "port": %u 5 | } 6 | } 7 | 8 | -------------------------------------------------------------------------------- /.bazelignore: -------------------------------------------------------------------------------- 1 | ./third_party/snappy/third_party/benchmark 2 | ./third_party/snappy/third_party/googletest 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # all files 5 | [*] 6 | indent_style = tab 7 | indent_size = 4 8 | -------------------------------------------------------------------------------- /benchmark/benchmark_thrift.thrift: -------------------------------------------------------------------------------- 1 | service BenchmarkThrift 2 | { 3 | void echo_thrift(1:string msg); 4 | void slow_thrift(1:string msg); 5 | } 6 | 7 | -------------------------------------------------------------------------------- /tools/templates/basic/client.conf: -------------------------------------------------------------------------------- 1 | { 2 | "client": 3 | { 4 | "remote_host": "127.0.0.1", 5 | "remote_port": %u,%s 6 | "retry_max": 2%s 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /test/test_thrift.thrift: -------------------------------------------------------------------------------- 1 | namespace cpp unit; 2 | 3 | service TestThrift { 4 | i32 add(1:i32 a, 2:i32 b); 5 | string substr(1:string str, 2:i32 idx, 3:i32 length); 6 | }; 7 | 8 | -------------------------------------------------------------------------------- /src/thrift/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(thrift) 3 | 4 | set(SRC 5 | rpc_thrift_buffer.cc 6 | rpc_thrift_idl.cc 7 | ) 8 | 9 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 10 | 11 | -------------------------------------------------------------------------------- /tools/templates/rpc/rpc.thrift: -------------------------------------------------------------------------------- 1 | struct EchoResult { 2 | 1:required string message; 3 | 2:optional i32 state; 4 | 3:optional i32 error; 5 | } 6 | 7 | service %s { 8 | EchoResult Echo(1:string message); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /tools/templates/proxy/proxy.conf: -------------------------------------------------------------------------------- 1 | { 2 | "server": 3 | { 4 | "port": %s 5 | }, 6 | 7 | "client": 8 | { 9 | "remote_host": "127.0.0.1", 10 | "remote_port": %s, 11 | "retry_max": 2 12 | } 13 | } 14 | 15 | -------------------------------------------------------------------------------- /tools/templates/rpc/client.conf: -------------------------------------------------------------------------------- 1 | { 2 | "client": 3 | { 4 | "remote_host": "127.0.0.1", 5 | "remote_port": 1412, 6 | "is_ssl" : false, 7 | "retry_max": 1, 8 | "callee" : "rpc_client" 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/var/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(var) 3 | 4 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 5 | 6 | set(SRC 7 | rpc_var.cc 8 | ) 9 | 10 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 11 | 12 | -------------------------------------------------------------------------------- /tools/templates/proxy/client_rpc.conf: -------------------------------------------------------------------------------- 1 | { 2 | "client": 3 | { 4 | "remote_host": "127.0.0.1", 5 | "remote_port": 1411, 6 | "is_ssl" : false, 7 | "retry_max": 1, 8 | "callee" : "rpc_client" 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /tutorial/echo_thrift.thrift: -------------------------------------------------------------------------------- 1 | struct EchoResult { 2 | 1:required string message; 3 | 2:optional i32 state; 4 | 3:optional i32 error; 5 | } 6 | 7 | service Example { 8 | EchoResult Echo(1:string message, 2:string name); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /benchmark/benchmark_pb.proto: -------------------------------------------------------------------------------- 1 | syntax="proto3"; 2 | 3 | message EmptyPBMsg { } 4 | 5 | message FixLengthPBMsg { bytes msg = 1; } 6 | 7 | service BenchmarkPB 8 | { 9 | rpc echo_pb(FixLengthPBMsg) returns (EmptyPBMsg); 10 | rpc slow_pb(FixLengthPBMsg) returns (EmptyPBMsg); 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tools/templates/rpc/rpc.proto: -------------------------------------------------------------------------------- 1 | syntax="proto2"; 2 | 3 | message EchoRequest { 4 | required string message = 1; 5 | }; 6 | 7 | message EchoResponse { 8 | required string message = 1; 9 | optional int32 state = 2; 10 | optional int32 error = 3; 11 | }; 12 | 13 | service %s { 14 | rpc Echo(EchoRequest) returns (EchoResponse); 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "workflow"] 2 | path = workflow 3 | url = https://github.com/sogou/workflow.git 4 | [submodule "third_party/snappy"] 5 | path = third_party/snappy 6 | url = https://github.com/google/snappy 7 | branch = 1.1.9 8 | [submodule "third_party/lz4"] 9 | path = third_party/lz4 10 | url = https://github.com/lz4/lz4 11 | branch = v1.9.3 12 | -------------------------------------------------------------------------------- /tools/templates/file/server.conf: -------------------------------------------------------------------------------- 1 | { 2 | "server": 3 | { 4 | "port": 8080, 5 | "root": "./html/", 6 | "error_page" : [ 7 | { 8 | "error" : [ 404 ], 9 | "page" : "404.html" 10 | }, 11 | { 12 | "error" : [ 500, 502, 503, 504], 13 | "page" : "50x.html" 14 | } 15 | ] 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tutorial/helloworld.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package trpc.test.helloworld; 4 | 5 | service Greeter { 6 | rpc SayHello (HelloRequest) returns (HelloReply) {} 7 | rpc SayHi (HelloRequest) returns (HelloReply) {} 8 | } 9 | 10 | message HelloRequest { 11 | string msg = 1; 12 | } 13 | 14 | message HelloReply { 15 | string msg = 1; 16 | } 17 | -------------------------------------------------------------------------------- /tutorial/echo_pb.proto: -------------------------------------------------------------------------------- 1 | syntax="proto2"; 2 | 3 | message EchoRequest { 4 | required string message = 1; 5 | required string name = 2; 6 | }; 7 | 8 | message EchoResponse { 9 | required string message = 1; 10 | optional int32 state = 2; 11 | optional int32 error = 3; 12 | }; 13 | 14 | service Example { 15 | rpc Echo(EchoRequest) returns (EchoResponse); 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /third_party/lz4.BUILD: -------------------------------------------------------------------------------- 1 | cc_library( 2 | name = "lz4", 3 | srcs = [ 4 | 'lib/lz4.c', 5 | 'lib/lz4hc.c', 6 | 'lib/lz4frame.c', 7 | 'lib/xxhash.c', 8 | ], 9 | hdrs = [ 10 | 'lib/lz4.h', 11 | 'lib/lz4.c', 12 | 'lib/lz4hc.h', 13 | 'lib/lz4frame.h', 14 | 'lib/xxhash.h', 15 | ], 16 | includes = ['lib'], 17 | visibility = ["//visibility:public"], 18 | ) 19 | -------------------------------------------------------------------------------- /tools/templates/common/GNUmakefile: -------------------------------------------------------------------------------- 1 | ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 2 | BUILD_DIR := build.cmake 3 | 4 | .PHONY: all clean 5 | 6 | all: base 7 | make -C $(BUILD_DIR) -f Makefile 8 | 9 | base: 10 | mkdir -p $(BUILD_DIR) 11 | cd $(BUILD_DIR) && cmake $(ROOT_DIR) 12 | 13 | clean: 14 | ifeq ($(BUILD_DIR), $(wildcard $(BUILD_DIR))) 15 | make -C $(BUILD_DIR) clean 16 | rm -rf $(BUILD_DIR) 17 | endif 18 | 19 | -------------------------------------------------------------------------------- /srpc-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set(SRPC_VERSION "@srpc_VERSION@") 4 | set_and_check(SRPC_INCLUDE_DIR "@PACKAGE_CONFIG_INC_DIR@") 5 | set_and_check(SRPC_LIB_DIR "@PACKAGE_CONFIG_LIB_DIR@") 6 | set_and_check(SRPC_BIN_DIR "@PACKAGE_CONFIG_BIN_DIR@") 7 | 8 | if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/srpc-targets.cmake") 9 | include ("${CMAKE_CURRENT_LIST_DIR}/srpc-targets.cmake") 10 | endif () 11 | 12 | check_required_components(srpc) 13 | 14 | -------------------------------------------------------------------------------- /tools/GNUmakefile: -------------------------------------------------------------------------------- 1 | ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 2 | BUILD_DIR := build.cmake 3 | 4 | .PHONY: all clean 5 | 6 | all: base 7 | make -C $(BUILD_DIR) -f Makefile 8 | 9 | base: 10 | mkdir -p $(BUILD_DIR) 11 | cd $(BUILD_DIR) && cmake -D CMAKE_BUILD_TYPE=Debug $(ROOT_DIR) 12 | 13 | clean: 14 | ifeq ($(BUILD_DIR), $(wildcard $(BUILD_DIR))) 15 | make -C $(BUILD_DIR) clean 16 | rm -rf $(BUILD_DIR) 17 | endif 18 | 19 | -------------------------------------------------------------------------------- /src/http/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(http) 3 | 4 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 5 | 6 | set(SRC 7 | http_module.cc 8 | http_task.cc 9 | http_client.cc 10 | http_server.cc 11 | ) 12 | 13 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 14 | if (WIN32) 15 | target_compile_definitions( 16 | ${PROJECT_NAME} PRIVATE 17 | strdup=_strdup 18 | strcasecmp=_stricmp 19 | strncasecmp=_strnicmp 20 | ) 21 | endif () 22 | 23 | -------------------------------------------------------------------------------- /src/generator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(srpc_generator) 3 | 4 | set(SRC 5 | compiler.cc 6 | generator.cc 7 | parser.cc 8 | ) 9 | 10 | add_executable(${PROJECT_NAME} ${SRC}) 11 | if (WIN32) 12 | target_compile_definitions( 13 | ${PROJECT_NAME} PRIVATE 14 | getcwd=_getcwd 15 | strdup=_strdup 16 | strcasecmp=_stricmp 17 | strncasecmp=_strnicmp 18 | ) 19 | endif () 20 | 21 | install( 22 | TARGETS ${PROJECT_NAME} 23 | RUNTIME 24 | DESTINATION ${CMAKE_INSTALL_BINDIR} 25 | COMPONENT devel 26 | ) 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.bak 3 | *.gz 4 | *.zip 5 | *.tar 6 | *.la 7 | *.lo 8 | *.o 9 | *.rpm 10 | *.so 11 | *.so.* 12 | *.cmake 13 | *.vcxproj 14 | *.filters 15 | *.sln 16 | *.pb.h 17 | *.pb.cc 18 | *.log 19 | *.srpc.h 20 | *.thrift.h 21 | *.pb_skeleton.h 22 | *.pb_skeleton.cc 23 | *.thrift_skeleton.h 24 | *.thrift_skeleton.cc 25 | 26 | _bin/ 27 | _include/ 28 | _lib/ 29 | .deps/ 30 | build/ 31 | build_pkg/ 32 | CMakeFiles/ 33 | Debug/ 34 | Release/ 35 | 36 | missing 37 | SRCINFO 38 | SRCNUMVER 39 | SRCVERSION 40 | CMakeCache.txt 41 | Makefile 42 | 43 | bazel-* 44 | -------------------------------------------------------------------------------- /test/test_pb.proto: -------------------------------------------------------------------------------- 1 | syntax="proto2"; 2 | package unit; 3 | 4 | message AddRequest { 5 | required int32 a = 1; 6 | required int32 b = 2; 7 | }; 8 | 9 | message AddResponse { 10 | required int32 c = 1; 11 | }; 12 | 13 | message SubstrRequest { 14 | required string str = 1; 15 | required int32 idx = 2; 16 | optional int32 length = 3; 17 | }; 18 | 19 | message SubstrResponse { 20 | required string str = 1; 21 | }; 22 | 23 | service TestPB { 24 | rpc Add(AddRequest) returns (AddResponse); 25 | rpc Substr(SubstrRequest) returns (SubstrResponse); 26 | }; 27 | 28 | -------------------------------------------------------------------------------- /tools/templates/file/50x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 12 | 13 | 14 |

An error occurred.

15 |

Sorry, the page you are looking for is currently unavailable.
16 | Please try again later.

17 |

If you are the system administrator of this resource then you should check 18 | the srpc-ctl README.md for details.

19 |

Faithfully yours, srpc.

20 | 21 | 22 | -------------------------------------------------------------------------------- /src/message/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(message) 3 | 4 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 5 | 6 | set(PROTO_LIST rpc_meta.proto rpc_meta_brpc.proto rpc_meta_trpc.proto) 7 | protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_LIST}) 8 | 9 | set(SRC 10 | rpc_message_brpc.cc 11 | rpc_message_srpc.cc 12 | rpc_message_thrift.cc 13 | rpc_message_trpc.cc 14 | ${PROTO_SRCS} ${PROTO_HDRS} 15 | ) 16 | 17 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 18 | if (WIN32) 19 | target_compile_definitions( 20 | ${PROJECT_NAME} PRIVATE 21 | strdup=_strdup 22 | strcasecmp=_stricmp 23 | strncasecmp=_strnicmp 24 | ) 25 | endif () 26 | 27 | -------------------------------------------------------------------------------- /docs/docs-01-idl.md: -------------------------------------------------------------------------------- 1 | [English version](/docs/en/docs-01-idl.md) 2 | 3 | ## 01 - RPC IDL 4 | - 描述文件 5 | - 前后兼容 6 | - Protobuf/Thrift 7 | 8 | ### 示例 9 | 下面我们通过一个具体例子来呈现 10 | - 我们拿pb举例,定义一个ServiceName为``Example``的``example.proto``文件 11 | - rpc接口名为``Echo``,输入参数为``EchoRequest``,输出参数为``EchoResponse`` 12 | - ``EchoRequest``包括两个string:``message``和``name`` 13 | - ``EchoResponse``包括一个string:``message`` 14 | 15 | ~~~proto 16 | syntax="proto2"; 17 | 18 | message EchoRequest { 19 | optional string message = 1; 20 | optional string name = 2; 21 | }; 22 | 23 | message EchoResponse { 24 | optional string message = 1; 25 | }; 26 | 27 | service Example { 28 | rpc Echo(EchoRequest) returns (EchoResponse); 29 | }; 30 | ~~~ 31 | 32 | -------------------------------------------------------------------------------- /benchmark/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | #serverlist = [("srpc", "pb"), ("brpc", "pb"), ("thrift", "thrift")] 5 | serverlist = [("thrift", "thrift")] 6 | #reqlist = [16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768] 7 | parlist = [1, 2, 4, 8, 16, 32, 64, 128, 256] 8 | 9 | for server, idl in serverlist: 10 | #os.system("nohup ./server 8811 %s &" % server) 11 | for par in parlist: 12 | #for reqsize in reqlist: 13 | #cmd = "./echo_client %s" % reqsize 14 | #cmd = "./client 127.0.0.1 8811 %s %s 100 %s" % (server, idl, reqsize) 15 | cmd = "./client 127.0.0.1 8811 %s %s %s 1024" % (server, idl, par) 16 | print cmd 17 | os.system(cmd); 18 | time.sleep(1); 19 | 20 | #os.system("killall server") 21 | 22 | -------------------------------------------------------------------------------- /tools/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | project(srpc-ctl 4 | VERSION 0.10.3 5 | LANGUAGES C CXX 6 | ) 7 | 8 | set(CMAKE_CXX_STANDARD 11) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 11 | 12 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}) 13 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}) 14 | 15 | set(generator_code 16 | "../src/generator/generator.cc" 17 | "../src/generator/parser.cc") 18 | 19 | set(srpc_ctl_code 20 | "srpc_ctl.cc" 21 | "srpc_config.cc" 22 | "srpc_controller.cc" 23 | "srpc_basic_controller.cc" 24 | "srpc_rpc_controller.cc" 25 | "srpc_proxy_controller.cc") 26 | 27 | include_directories("../src/") 28 | add_executable(srpc ${srpc_ctl_code} ${generator_code}) 29 | target_link_libraries(srpc ${LIBRARY_NAME}) 30 | 31 | -------------------------------------------------------------------------------- /src/module/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(module) 3 | 4 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 5 | 6 | set(PROTO_LIST 7 | proto/opentelemetry_common.proto 8 | proto/opentelemetry_resource.proto 9 | proto/opentelemetry_trace.proto 10 | proto/opentelemetry_metrics.proto 11 | proto/opentelemetry_metrics_service.proto) 12 | 13 | protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_LIST}) 14 | 15 | set(SRC 16 | rpc_module.cc 17 | rpc_trace_module.cc 18 | rpc_metrics_module.cc 19 | rpc_trace_filter.cc 20 | rpc_metrics_filter.cc 21 | ${PROTO_SRCS} ${PROTO_HDRS} 22 | ) 23 | 24 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 25 | 26 | if (WIN32) 27 | target_compile_definitions( 28 | ${PROJECT_NAME} PRIVATE 29 | strdup=_strdup 30 | strcasecmp=_stricmp 31 | strncasecmp=_strnicmp 32 | ) 33 | endif () 34 | 35 | -------------------------------------------------------------------------------- /src/message/rpc_meta.proto: -------------------------------------------------------------------------------- 1 | syntax="proto2"; 2 | 3 | message RPCMetaKeyValue { 4 | required string key = 1; 5 | oneof value 6 | { 7 | int32 int_value = 2; 8 | string str_value = 3; 9 | bytes bytes_value = 4; 10 | } 11 | }; 12 | 13 | message RPCRequestMeta { 14 | optional string service_name = 1; 15 | optional string method_name = 2; 16 | optional int64 log_id = 3; 17 | }; 18 | 19 | message RPCResponseMeta { 20 | optional int32 status_code = 1 [default = 0]; 21 | optional int32 error = 2 [default = 0]; 22 | }; 23 | 24 | message RPCMeta { 25 | optional RPCRequestMeta request = 1; 26 | optional RPCResponseMeta response = 2; 27 | optional uint32 srpc_version = 3; 28 | optional int32 compress_type = 4 [default = 0]; 29 | optional int32 origin_size = 5; 30 | optional int32 compressed_size = 6; 31 | optional int32 data_type = 7; 32 | repeated RPCMetaKeyValue trans_info = 8; 33 | }; 34 | -------------------------------------------------------------------------------- /docs/en/docs-01-idl.md: -------------------------------------------------------------------------------- 1 | [中文版](/docs/docs-01-idl.md) 2 | 3 | ## 01 - RPC IDL 4 | 5 | - Interface Description Languaue file 6 | - Backward and forward compatibility 7 | - Protobuf/Thrift 8 | 9 | ### Sample 10 | 11 | You can follow the detailed example below: 12 | 13 | - Take pb as an example. First, define an `example.proto` file with the ServiceName as `Example`. 14 | - The name of the rpc interface is `Echo`, with the input parameter as `EchoRequest`, and the output parameter as `EchoResponse`. 15 | - `EchoRequest` consists of two strings: `message` and `name`. 16 | - `EchoResponse` consists of one string: `message`. 17 | 18 | ~~~proto 19 | syntax="proto2"; 20 | 21 | message EchoRequest { 22 | optional string message = 1; 23 | optional string name = 2; 24 | }; 25 | 26 | message EchoResponse { 27 | optional string message = 1; 28 | }; 29 | 30 | service Example { 31 | rpc Echo(EchoRequest) returns (EchoResponse); 32 | }; 33 | ~~~ 34 | 35 | -------------------------------------------------------------------------------- /docs/docs-02-service.md: -------------------------------------------------------------------------------- 1 | [English version](/docs/en/docs-02-service.md) 2 | 3 | ## 02 - RPC Service 4 | - 组成SRPC服务的基本单元 5 | - 每一个Service一定由某一种IDL生成 6 | - Service只与IDL有关,与网络通信具体协议无关 7 | 8 | ### 示例 9 | 下面我们通过一个具体例子来呈现 10 | - 沿用上面的``example.proto``IDL描述文件 11 | - 执行官方的``protoc example.proto --cpp_out=./ --proto_path=./``获得``example.pb.h``和``example.pb.cpp``两个文件 12 | - 执行SRPC的``srpc_generator protobuf ./example.proto ./``获得``example.srpc.h``文件 13 | - 我们派生``Example::Service``来实现具体的rpc业务逻辑,这就是一个RPC Service 14 | - 注意这个Service没有任何网络、端口、通信协议等概念,仅仅负责完成实现从``EchoRequest``输入到输出``EchoResponse``的业务逻辑 15 | 16 | ~~~cpp 17 | class ExampleServiceImpl : public Example::Service 18 | { 19 | public: 20 | void Echo(EchoRequest *request, EchoResponse *response, RPCContext *ctx) override 21 | { 22 | response->set_message("Hi, " + request->name()); 23 | 24 | printf("get_req:\n%s\nset_resp:\n%s\n", 25 | request->DebugString().c_str(), 26 | response->DebugString().c_str()); 27 | } 28 | }; 29 | ~~~ 30 | 31 | -------------------------------------------------------------------------------- /tutorial/GNUmakefile: -------------------------------------------------------------------------------- 1 | ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 2 | ALL_TARGETS := all clean 3 | MAKE_FILE := Makefile 4 | 5 | DEFAULT_BUILD_DIR := build.cmake 6 | BUILD_DIR := $(shell if [ -f $(MAKE_FILE) ]; then echo "."; else echo $(DEFAULT_BUILD_DIR); fi) 7 | CMAKE3 := $(shell if which cmake3>/dev/null ; then echo cmake3; else echo cmake; fi;) 8 | 9 | .PHONY: $(ALL_TARGETS) 10 | 11 | all: 12 | mkdir -p $(BUILD_DIR) 13 | ifeq ($(DEBUG),y) 14 | cd $(BUILD_DIR) && $(CMAKE3) -D CMAKE_BUILD_TYPE=Debug $(ROOT_DIR) 15 | else ifneq ("${Workflow_DIR}workflow", "workflow") 16 | cd $(BUILD_DIR) && $(CMAKE3) -DWorkflow_DIR:STRING=${Workflow_DIR} $(ROOT_DIR) 17 | else 18 | cd $(BUILD_DIR) && $(CMAKE3) $(ROOT_DIR) 19 | endif 20 | make -C $(BUILD_DIR) -f Makefile 21 | 22 | clean: 23 | ifeq ($(MAKE_FILE), $(wildcard $(MAKE_FILE))) 24 | -make -f Makefile clean 25 | else ifeq ($(DEFAULT_BUILD_DIR), $(wildcard $(DEFAULT_BUILD_DIR))) 26 | -make -C $(DEFAULT_BUILD_DIR) clean 27 | endif 28 | rm -rf $(DEFAULT_BUILD_DIR) 29 | 30 | -------------------------------------------------------------------------------- /test/GNUmakefile: -------------------------------------------------------------------------------- 1 | ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 2 | ALL_TARGETS := all check clean 3 | MAKE_FILE := Makefile 4 | 5 | DEFAULT_BUILD_DIR := build.cmake 6 | BUILD_DIR := $(shell if [ -f $(MAKE_FILE) ]; then echo "."; else echo $(DEFAULT_BUILD_DIR); fi) 7 | CMAKE3 := $(shell if which cmake3 ; then echo cmake3; else echo cmake; fi;) 8 | 9 | .PHONY: $(ALL_TARGETS) 10 | 11 | all: 12 | mkdir -p $(BUILD_DIR) 13 | ifeq ($(DEBUG),y) 14 | cd $(BUILD_DIR) && $(CMAKE3) -D CMAKE_BUILD_TYPE=Debug $(ROOT_DIR) 15 | else ifneq ("${Workflow_DIR}workflow", "workflow") 16 | cd $(BUILD_DIR) && $(CMAKE3) -DWorkflow_DIR:STRING=${Workflow_DIR} $(ROOT_DIR) 17 | else 18 | cd $(BUILD_DIR) && $(CMAKE3) $(ROOT_DIR) 19 | endif 20 | make -C $(BUILD_DIR) -f Makefile 21 | 22 | check: 23 | mkdir -p $(BUILD_DIR) 24 | cd $(BUILD_DIR) && $(CMAKE3) $(ROOT_DIR) 25 | make -C $(BUILD_DIR) check CTEST_OUTPUT_ON_FAILURE=1 26 | 27 | clean: 28 | ifeq ($(MAKE_FILE), $(wildcard $(MAKE_FILE))) 29 | -make -f Makefile clean 30 | endif 31 | rm -rf $(DEFAULT_BUILD_DIR) 32 | 33 | -------------------------------------------------------------------------------- /benchmark/GNUmakefile: -------------------------------------------------------------------------------- 1 | ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 2 | ALL_TARGETS := all clean 3 | MAKE_FILE := Makefile 4 | 5 | DEFAULT_BUILD_DIR := build.cmake 6 | BUILD_DIR := $(shell if [ -f $(MAKE_FILE) ]; then echo "."; else echo $(DEFAULT_BUILD_DIR); fi) 7 | CMAKE3 := $(shell if which cmake3>/dev/null ; then echo cmake3; else echo cmake; fi;) 8 | 9 | .PHONY: $(ALL_TARGETS) 10 | 11 | all: 12 | mkdir -p $(BUILD_DIR) 13 | ifeq ($(DEBUG),y) 14 | cd $(BUILD_DIR) && $(CMAKE3) -D CMAKE_BUILD_TYPE=Debug $(ROOT_DIR) 15 | else ifneq ("${Workflow_DIR}workflow", "workflow") 16 | cd $(BUILD_DIR) && $(CMAKE3) -DWorkflow_DIR:STRING=${Workflow_DIR} $(ROOT_DIR) 17 | else 18 | cd $(BUILD_DIR) && $(CMAKE3) $(ROOT_DIR) 19 | endif 20 | make -C $(BUILD_DIR) -f Makefile 21 | 22 | clean: 23 | ifeq ($(MAKE_FILE), $(wildcard $(MAKE_FILE))) 24 | -make -f Makefile clean 25 | else ifeq ($(DEFAULT_BUILD_DIR), $(wildcard $(DEFAULT_BUILD_DIR))) 26 | -make -C $(DEFAULT_BUILD_DIR) clean 27 | endif 28 | rm -rf $(DEFAULT_BUILD_DIR) 29 | 30 | #g++ -o thrift_server thrift_server.cc gen-cpp/*.cpp -O2 -g -lthrift -lthriftnb -levent -lpthread -std=c++11 31 | -------------------------------------------------------------------------------- /tools/templates/basic/server_main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "workflow/WF%sServer.h" 4 | #include "workflow/WFFacilities.h" 5 | 6 | #include "config/util.h" 7 | #include "config/config.h" 8 | 9 | static WFFacilities::WaitGroup wait_group(1); 10 | static srpc::RPCConfig config; 11 | 12 | void sig_handler(int signo) 13 | { 14 | wait_group.done(); 15 | } 16 | 17 | void init() 18 | { 19 | if (config.load("./server.conf") == false) 20 | { 21 | perror("Load config failed"); 22 | exit(1); 23 | } 24 | 25 | signal(SIGINT, sig_handler); 26 | signal(SIGTERM, sig_handler); 27 | } 28 | 29 | void process(WF%sTask *task) 30 | { 31 | // delete the example codes and fill your logic 32 | %s 33 | } 34 | 35 | int main() 36 | { 37 | init(); 38 | 39 | WF%sServer server(process); 40 | 41 | if (server.start(config.server_port()) == 0) 42 | { 43 | fprintf(stderr, "%s server started, port %%u\n", config.server_port()); 44 | wait_group.wait(); 45 | server.stop(); 46 | } 47 | else 48 | perror("server start"); 49 | 50 | return 0; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /tools/templates/common/util.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "workflow/WFTaskFactory.h" 7 | 8 | template 9 | void print_peer_address(TASK *server_task) 10 | { 11 | char addrstr[128]; 12 | struct sockaddr_storage addr; 13 | socklen_t l = sizeof addr; 14 | unsigned short port = 0; 15 | long long seq = server_task->get_task_seq(); 16 | 17 | server_task->get_peer_addr((struct sockaddr *)&addr, &l); 18 | if (addr.ss_family == AF_INET) 19 | { 20 | struct sockaddr_in *sin = (struct sockaddr_in *)&addr; 21 | inet_ntop(AF_INET, &sin->sin_addr, addrstr, 128); 22 | port = ntohs(sin->sin_port); 23 | } 24 | else if (addr.ss_family == AF_INET6) 25 | { 26 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; 27 | inet_ntop(AF_INET6, &sin6->sin6_addr, addrstr, 128); 28 | port = ntohs(sin6->sin6_port); 29 | } 30 | else 31 | strcpy(addrstr, "Unknown"); 32 | 33 | fprintf(stderr, "peer address: %s:%d, seq: %lld.\n", addrstr, port, seq); 34 | } 35 | 36 | -------------------------------------------------------------------------------- /third_party/snappy.BUILD: -------------------------------------------------------------------------------- 1 | genrule( 2 | name = "snappy_stubs_public_h", 3 | srcs = [ 4 | "snappy-stubs-public.h.in", 5 | ], 6 | outs = [ 7 | "snappy-stubs-public.h", 8 | ], 9 | cmd = "sed 's/$${HAVE_SYS_UIO_H_01}/true/g' $(<) | " + 10 | "sed 's/$${PROJECT_VERSION_MAJOR}/0/g' | " + 11 | "sed 's/$${PROJECT_VERSION_MINOR}/9/g' | " + 12 | "sed 's/$${PROJECT_VERSION_PATCH}/2/g' >$(@)", 13 | ) 14 | 15 | 16 | cc_library( 17 | name = "snappy", 18 | srcs = [ 19 | "snappy.cc", 20 | "snappy-c.cc", 21 | "snappy-sinksource.cc", 22 | "snappy-stubs-internal.cc", 23 | ], 24 | hdrs = [ 25 | ":snappy_stubs_public_h", 26 | "snappy.h", 27 | "snappy-c.h", 28 | "snappy-internal.h", 29 | "snappy-sinksource.h", 30 | "snappy-stubs-internal.h", 31 | "snappy-stubs-public.h.in", 32 | ], 33 | copts = [ 34 | "-Wno-non-virtual-dtor", 35 | "-Wno-unused-variable", 36 | "-Wno-implicit-fallthrough", 37 | "-Wno-unused-function", 38 | ], 39 | includes = ["."], 40 | visibility = ["//visibility:public"], 41 | ) 42 | -------------------------------------------------------------------------------- /tools/templates/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(%s LANGUAGES CXX) 3 | set(CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 5 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 6 | 7 | # Find all the dependencies 8 | find_package(OpenSSL REQUIRED) 9 | set(Workflow_DIR "%s") 10 | find_package(Workflow REQUIRED CONFIG HINTS ${Workflow_DIR}) 11 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}) 12 | 13 | # Prefer to static link first 14 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ${CMAKE_FIND_LIBRARY_SUFFIXES}) 15 | find_library(Workflow_LIB workflow HINTS ${Workflow_DIR}/_lib) 16 | 17 | # Set all the libraries here 18 | set(LIB ${Workflow_LIB} pthread OpenSSL::SSL OpenSSL::Crypto) 19 | 20 | # Add all the common codes here 21 | set(COMMON_CODE config/config.cc config/Json.cc%s) 22 | 23 | # Add header directories and library directories here 24 | include_directories(${OPENSSL_INCLUDE_DIR} ${WORKFLOW_INCLUDE_DIR}) 25 | link_directories(${OPENSSL_LINK_DIR} ${WORKFLOW_LIB_DIR}) 26 | 27 | # Build executable outputs 28 | set(PROJECT_OUTPUT server%s) 29 | foreach(output ${PROJECT_OUTPUT}) 30 | add_executable(${output} ${output}_main.cc ${COMMON_CODE}) 31 | target_link_libraries(${output} ${LIB}) 32 | endforeach() 33 | 34 | -------------------------------------------------------------------------------- /src/module/proto/opentelemetry_resource.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2019, OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package opentelemetry.proto.resource.v1; 18 | 19 | import "opentelemetry_common.proto"; 20 | 21 | // Resource information. 22 | message Resource { 23 | // Set of attributes that describe the resource. 24 | // Attribute keys MUST be unique (it is not allowed to have more than one 25 | // attribute with the same key). 26 | repeated opentelemetry.proto.common.v1.KeyValue attributes = 1; 27 | 28 | // dropped_attributes_count is the number of dropped attributes. If the value is 0, then 29 | // no attributes were dropped. 30 | uint32 dropped_attributes_count = 2; 31 | } 32 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "srpc") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 4 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository") 5 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 6 | 7 | http_archive( 8 | name = "rules_proto", 9 | sha256 = "d8992e6eeec276d49f1d4e63cfa05bbed6d4a26cfe6ca63c972827a0d141ea3b", 10 | strip_prefix = "rules_proto-cfdc2fa31879c0aebe31ce7702b1a9c8a4be02d2", 11 | urls = [ 12 | "https://github.com/bazelbuild/rules_proto/archive/cfdc2fa31879c0aebe31ce7702b1a9c8a4be02d2.tar.gz", 13 | ], 14 | ) 15 | load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") 16 | rules_proto_dependencies() 17 | rules_proto_toolchains() 18 | 19 | git_repository( 20 | name = "workflow", 21 | commit = "2421bab69935ff3b2d01cb46f11051166333df65", 22 | remote = "https://github.com/sogou/workflow.git") 23 | 24 | new_git_repository( 25 | name = "lz4", 26 | build_file = "@//third_party:lz4.BUILD", 27 | tag = "v1.9.3", 28 | remote = "https://github.com/lz4/lz4.git") 29 | 30 | new_git_repository( 31 | name = "snappy", 32 | build_file = "@//third_party:snappy.BUILD", 33 | tag = "1.1.9", 34 | remote = "https://github.com/google/snappy.git") 35 | 36 | -------------------------------------------------------------------------------- /tools/templates/basic/client_main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "workflow/%sMessage.h" 4 | #include "workflow/WFTaskFactory.h" 5 | #include "workflow/WFFacilities.h" 6 | 7 | #include "config/config.h" 8 | 9 | static WFFacilities::WaitGroup wait_group(1); 10 | static srpc::RPCConfig config; 11 | 12 | void sig_handler(int signo) 13 | { 14 | wait_group.done(); 15 | } 16 | 17 | void init() 18 | { 19 | if (config.load("./client.conf") == false) 20 | { 21 | perror("Load config failed"); 22 | exit(1); 23 | } 24 | 25 | signal(SIGINT, sig_handler); 26 | signal(SIGTERM, sig_handler); 27 | } 28 | 29 | void callback(WF%sTask *task) 30 | { 31 | int state = task->get_state(); 32 | int error = task->get_error(); 33 | fprintf(stderr, "%s client state = %%d error = %%d\n", state, error); 34 | %s 35 | } 36 | 37 | int main() 38 | { 39 | init(); 40 | 41 | std::string url = std::string("%s://") + %sconfig.client_host() + 42 | std::string(":") + std::to_string(config.client_port()); 43 | 44 | WF%sTask *task = WFTaskFactory::create_%s_task(url,%s 45 | config.retry_max(), 46 | callback); 47 | %s 48 | task->start(); 49 | 50 | wait_group.wait(); 51 | return 0; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /docs/en/docs-02-service.md: -------------------------------------------------------------------------------- 1 | [中文版](/docs/docs-02-service.md) 2 | 3 | ## 02 - RPC Service 4 | 5 | - It is the basic unit for SRPC services. 6 | - Each service must be generated by one type of IDLs. 7 | - Service is determined by IDL type, not by specific network communication protocol. 8 | 9 | ### Sample 10 | 11 | You can follow the detailed example below: 12 | 13 | - Use the same `example.proto` IDL above. 14 | - Run the official `protoc example.proto --cpp_out=./ --proto_path=./` to get two files: `example.pb.h` and `example.pb.cpp`. 15 | - Run the `srpc_generator protobuf ./example.proto ./` in SRPC to get `example.srpc.h`. 16 | - Derive `Example::Service` to implement the rpc business logic, which is an RPC Service. 17 | - Please note that this Service does not involve any concepts such as network, port, communication protocol, etc., and it is only responsible for completing the business logic that convert `EchoRequest` to `EchoResponse`. 18 | 19 | ~~~cpp 20 | class ExampleServiceImpl : public Example::Service 21 | { 22 | public: 23 | void Echo(EchoRequest *request, EchoResponse *response, RPCContext *ctx) override 24 | { 25 | response->set_message("Hi, " + request->name()); 26 | 27 | printf("get_req:\n%s\nset_resp:\n%s\n", 28 | request->DebugString().c_str(), 29 | response->DebugString().c_str()); 30 | } 31 | }; 32 | ~~~ 33 | 34 | -------------------------------------------------------------------------------- /src/http/http_server.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_HTTP_SERVER_H__ 18 | #define __RPC_HTTP_SERVER_H__ 19 | 20 | #include "workflow/WFHttpServer.h" 21 | #include "rpc_basic.h" 22 | #include "rpc_filter.h" 23 | #include "rpc_module.h" 24 | 25 | namespace srpc 26 | { 27 | 28 | class HttpServer : public WFHttpServer 29 | { 30 | public: 31 | HttpServer(http_process_t proc) : 32 | WFHttpServer(std::move(proc)), 33 | listen_port(0) 34 | { 35 | } 36 | 37 | void add_filter(RPCFilter *filter); 38 | 39 | protected: 40 | CommSession *new_session(long long seq, CommConnection *conn) override; 41 | 42 | private: 43 | unsigned short get_listen_port(); 44 | 45 | private: 46 | std::mutex mutex; 47 | RPCModule *modules[SRPC_MODULE_MAX] = { NULL }; 48 | unsigned short listen_port; 49 | }; 50 | 51 | } // namespace srpc 52 | 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /tools/templates/rpc/server_thrift.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "workflow/WFFacilities.h" 5 | #include "srpc/rpc_types.h" 6 | 7 | #include "config/config.h" 8 | #include "%s.srpc.h" 9 | 10 | using namespace srpc; 11 | 12 | static WFFacilities::WaitGroup wait_group(1); 13 | static srpc::RPCConfig config; 14 | 15 | void sig_handler(int signo) 16 | { 17 | wait_group.done(); 18 | } 19 | 20 | void init() 21 | { 22 | if (config.load("./server.conf") == false) 23 | { 24 | perror("Load config failed"); 25 | exit(1); 26 | } 27 | } 28 | 29 | class ServiceImpl : public %s::Service 30 | { 31 | public: 32 | void Echo(EchoResult& _return, const std::string& message) override 33 | { 34 | %s// 4. delete the following codes and fill your logic 35 | fprintf(stderr, "get req. %%s\n", message.c_str()); 36 | _return.message = "Hi back."; 37 | } 38 | }; 39 | 40 | int main() 41 | { 42 | // 1. load config 43 | init(); 44 | 45 | // 2. start server 46 | %sServer server; 47 | ServiceImpl impl; 48 | server.add_service(&impl); 49 | 50 | config.load_filter(server); 51 | 52 | if (server.start(config.server_port()) == 0) 53 | { 54 | // 3. success and wait 55 | printf("%s %s server started, port %%u\n", config.server_port()); 56 | wait_group.wait(); 57 | server.stop(); 58 | } 59 | else 60 | perror("server start"); 61 | 62 | return 0; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/compress/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(compress) 3 | 4 | set(SRC 5 | rpc_compress.cc 6 | rpc_compress_snappy.cc 7 | ) 8 | 9 | set_property(SOURCE rpc_compress_snappy.cc APPEND PROPERTY COMPILE_OPTIONS "-fno-rtti") 10 | 11 | if (WITH_VCPKG_TOOLCHAIN) 12 | add_library(${PROJECT_NAME} OBJECT ${SRC}) 13 | target_link_libraries(${PROJECT_NAME} lz4 snappy) 14 | else () 15 | if (SNAPPY_INSTALLED) 16 | set(SNAPPY_LIB snappy) 17 | else () 18 | set(SNAPPY_SRC 19 | ../../third_party/snappy/config.h 20 | ../../third_party/snappy/snappy-internal.h 21 | ../../third_party/snappy/snappy-sinksource.cc 22 | ../../third_party/snappy/snappy-sinksource.h 23 | ../../third_party/snappy/snappy-stubs-internal.cc 24 | ../../third_party/snappy/snappy-stubs-internal.h 25 | ../../third_party/snappy/snappy-stubs-public.h 26 | ../../third_party/snappy/snappy.cc 27 | ../../third_party/snappy/snappy.h 28 | ) 29 | endif () 30 | 31 | if (LZ4_INSTALLED) 32 | set(LZ4_LIB lz4) 33 | else () 34 | set(LZ4_SRC 35 | ../../third_party/lz4/lib/lz4.c 36 | ../../third_party/lz4/lib/lz4.h 37 | ../../third_party/lz4/lib/lz4hc.h 38 | ../../third_party/lz4/lib/lz4hc.c 39 | ../../third_party/lz4/lib/lz4frame.h 40 | ../../third_party/lz4/lib/lz4frame.c 41 | ../../third_party/lz4/lib/xxhash.c 42 | ../../third_party/lz4/lib/xxhash.h 43 | ) 44 | endif () 45 | 46 | add_library( 47 | ${PROJECT_NAME} OBJECT 48 | ${SRC} 49 | ${SNAPPY_SRC} 50 | ${LZ4_SRC} 51 | ) 52 | endif() 53 | 54 | -------------------------------------------------------------------------------- /src/http/http_module.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_HTTP_MODULE_H__ 18 | #define __RPC_HTTP_MODULE_H__ 19 | 20 | #include "rpc_basic.h" 21 | #include "rpc_module.h" 22 | #include "rpc_trace_module.h" 23 | #include "rpc_metrics_module.h" 24 | 25 | namespace srpc 26 | { 27 | 28 | class HttpTraceModule : public TraceModule 29 | { 30 | public: 31 | bool client_begin(SubTask *task, RPCModuleData& data) override; 32 | bool client_end(SubTask *task, RPCModuleData& data) override; 33 | bool server_begin(SubTask *task, RPCModuleData& data) override; 34 | bool server_end(SubTask *task, RPCModuleData& data) override; 35 | }; 36 | 37 | class HttpMetricsModule : public MetricsModule 38 | { 39 | public: 40 | bool client_begin(SubTask *task, RPCModuleData& data) override; 41 | bool server_begin(SubTask *task, RPCModuleData& data) override; 42 | }; 43 | 44 | using HttpCustomModule = CustomModule; 45 | 46 | } // end namespace srpc 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /tools/templates/rpc/server_protobuf.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "workflow/WFFacilities.h" 5 | #include "srpc/rpc_types.h" 6 | 7 | #include "config/config.h" 8 | #include "%s.srpc.h" 9 | 10 | using namespace srpc; 11 | 12 | static WFFacilities::WaitGroup wait_group(1); 13 | static srpc::RPCConfig config; 14 | 15 | void sig_handler(int signo) 16 | { 17 | wait_group.done(); 18 | } 19 | 20 | void init() 21 | { 22 | if (config.load("./server.conf") == false) 23 | { 24 | perror("Load config failed"); 25 | exit(1); 26 | } 27 | 28 | signal(SIGINT, sig_handler); 29 | signal(SIGTERM, sig_handler); 30 | } 31 | 32 | class ServiceImpl : public %s::Service 33 | { 34 | public: 35 | void Echo(EchoRequest *req, EchoResponse *resp, RPCContext *ctx) override 36 | { 37 | %s// 4. delete the following codes and fill your logic 38 | fprintf(stderr, "get req. %%s\n", req->DebugString().c_str()); 39 | resp->set_message("Hi back"); 40 | } 41 | }; 42 | 43 | int main() 44 | { 45 | // 1. load config 46 | init(); 47 | 48 | // 2. start server 49 | %sServer server; 50 | ServiceImpl impl; 51 | server.add_service(&impl); 52 | 53 | config.load_filter(server); 54 | 55 | if (server.start(config.server_port()) == 0) 56 | { 57 | // 3. success and wait 58 | fprintf(stderr, "%s %s server started, port %%u\n", config.server_port()); 59 | wait_group.wait(); 60 | server.stop(); 61 | } 62 | else 63 | perror("server start"); 64 | 65 | return 0; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /tools/templates/file/server_main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "workflow/HttpMessage.h" 4 | #include "workflow/HttpUtil.h" 5 | #include "workflow/WFHttpServer.h" 6 | #include "workflow/WFFacilities.h" 7 | 8 | #include "config/config.h" 9 | #include "file_service.h" 10 | 11 | using namespace protocol; 12 | 13 | static WFFacilities::WaitGroup wait_group(1); 14 | static srpc::RPCConfig config; 15 | 16 | void sig_handler(int signo) 17 | { 18 | wait_group.done(); 19 | } 20 | 21 | void init() 22 | { 23 | if (config.load("./server.conf") == false) 24 | { 25 | perror("Load config failed"); 26 | exit(1); 27 | } 28 | 29 | signal(SIGINT, sig_handler); 30 | } 31 | 32 | int main() 33 | { 34 | init(); 35 | 36 | unsigned short port = config.server_port(); 37 | const char *cert_file = config.server_cert_file(); 38 | const char *file_key = config.server_file_key(); 39 | 40 | FileService service(config.get_root_path(), config.get_error_page()); 41 | auto&& proc = std::bind(&FileService::process, &service, 42 | std::placeholders::_1); 43 | 44 | int ret; 45 | WFHttpServer server(proc); 46 | 47 | if (strlen(cert_file) != 0 && strlen(file_key) != 0) 48 | ret = server.start(port, cert_file, file_key); 49 | else 50 | ret = server.start(port); 51 | 52 | if (ret == 0) 53 | { 54 | fprintf(stderr, "http file service start, port %u\n", port); 55 | wait_group.wait(); 56 | server.stop(); 57 | } 58 | else 59 | perror("http file service start"); 60 | 61 | return 0; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /src/rpc_global.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_GLOBAL_H__ 18 | #define __RPC_GLOBAL_H__ 19 | 20 | #include 21 | #include 22 | #include "rpc_options.h" 23 | #include "rpc_module.h" 24 | 25 | namespace srpc 26 | { 27 | 28 | class SRPCGlobal 29 | { 30 | public: 31 | static SRPCGlobal *get_instance() 32 | { 33 | static SRPCGlobal kInstance; 34 | 35 | return &kInstance; 36 | } 37 | 38 | public: 39 | const char *get_srpc_version() const; 40 | 41 | bool task_init(RPCClientParams& params, ParsedURI& uri, 42 | struct sockaddr_storage *ss, socklen_t *ss_len) const; 43 | 44 | unsigned long long get_random(); 45 | void set_group_id(unsigned short id) { this->group_id = id; } 46 | void set_machine_id(unsigned short id) { this->machine_id = id; } 47 | 48 | private: 49 | SRPCGlobal(); 50 | SnowFlake snowflake; 51 | std::random_device rd; 52 | std::mt19937 gen; 53 | unsigned short group_id; 54 | unsigned short machine_id; 55 | }; 56 | 57 | } // namespace srpc 58 | 59 | #endif 60 | 61 | -------------------------------------------------------------------------------- /benchmark/thrift_server.cc: -------------------------------------------------------------------------------- 1 | #include "gen-cpp/BenchmarkThrift.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace ::apache::thrift; 10 | using namespace ::apache::thrift::protocol; 11 | using namespace ::apache::thrift::transport; 12 | using namespace ::apache::thrift::server; 13 | using namespace ::apache::thrift::concurrency; 14 | 15 | using boost::shared_ptr; 16 | 17 | class BenchmarkThriftHandler : virtual public BenchmarkThriftIf { 18 | public: 19 | void echo_thrift(const std::string& msg) { } 20 | void slow_thrift(const std::string& msg) { 21 | usleep(15000); 22 | } 23 | }; 24 | 25 | int main(int argc, char **argv) { 26 | int port = 8811; 27 | shared_ptr handler(new BenchmarkThriftHandler()); 28 | shared_ptr processor(new BenchmarkThriftProcessor(handler)); 29 | shared_ptr protocolFactory(new TBinaryProtocolFactory()); 30 | boost::shared_ptr threadManager = ThreadManager::newSimpleThreadManager(16); 31 | boost::shared_ptr threadFactory = boost::shared_ptr(new PosixThreadFactory()); 32 | 33 | TNonblockingServer server(processor, protocolFactory, port, threadManager); 34 | server.setMaxConnections(2048); 35 | server.setNumIOThreads(16); 36 | threadManager->threadFactory(threadFactory); 37 | threadManager->start(); 38 | server.serve(); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /tools/templates/file/file_service.h: -------------------------------------------------------------------------------- 1 | #ifndef _RPC_FILE_SERVICE_H_ 2 | #define _RPC_FILE_SERVICE_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "workflow/Workflow.h" 8 | #include "workflow/HttpMessage.h" 9 | #include "workflow/HttpUtil.h" 10 | #include "workflow/WFHttpServer.h" 11 | #include "workflow/WFFacilities.h" 12 | 13 | // This is a simple exmaple for file service 14 | 15 | class FileService 16 | { 17 | public: 18 | using ErrorPageMap = std::unordered_map; 19 | 20 | void process(WFHttpTask *server_task); 21 | void pread_callback(WFFileIOTask *task); 22 | protected: 23 | struct ModuleCtx 24 | { 25 | protocol::HttpResponse *resp; 26 | void *buf; 27 | bool is_error_set; 28 | ModuleCtx(protocol::HttpResponse * resp) : 29 | resp(resp), 30 | buf(NULL), 31 | is_error_set(false) 32 | { 33 | } 34 | }; 35 | 36 | private: 37 | WFModuleTask *create_module(WFHttpTask *task, const std::string& path); 38 | SubTask *create_file_task(const std::string& path, struct ModuleCtx *ctx); 39 | SubTask *create_error_task(int code, struct ModuleCtx *ctx); 40 | 41 | public: 42 | FileService(std::string root, const ErrorPageMap& error_page) : 43 | root(std::move(root)), 44 | error_page(error_page) 45 | { 46 | if (this->root.empty()) 47 | root = "./"; 48 | else if (this->root.at(this->root.length() - 1) != '/') 49 | root += "/"; 50 | } 51 | 52 | private: 53 | std::string root; 54 | const ErrorPageMap& error_page; 55 | }; 56 | 57 | #endif 58 | 59 | -------------------------------------------------------------------------------- /tools/templates/config/config_simple.h: -------------------------------------------------------------------------------- 1 | #ifndef _RPC_CONFIG_H_ 2 | #define _RPC_CONFIG_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Json.h" 8 | 9 | namespace srpc 10 | { 11 | 12 | class RPCConfig 13 | { 14 | public: 15 | using ErrorPageMap = std::unordered_map; 16 | 17 | bool load(const char *file); 18 | 19 | unsigned short server_port() const { return this->s_port; } 20 | const char *server_cert_file() const { return this->s_cert_file.c_str(); } 21 | const char *server_file_key() const { return this->s_file_key.c_str(); } 22 | unsigned short client_port() const { return this->c_port; } 23 | const char *client_host() const { return this->c_host.c_str(); } 24 | int redirect_max() const { return this->c_redirect_max; } 25 | int retry_max() const { return this->c_retry_max; } 26 | const char *client_user_name() const { return this->c_user_name.c_str(); } 27 | const char *client_password() const { return this->c_password.c_str(); } 28 | const char *get_root_path() const { return this->root_path.c_str(); } 29 | const ErrorPageMap& get_error_page() const { return this->error_page; } 30 | 31 | public: 32 | RPCConfig() : s_port(0), c_port(0), c_redirect_max(0), c_retry_max(0) { } 33 | ~RPCConfig(); 34 | 35 | private: 36 | void load_server(); 37 | void load_client(); 38 | 39 | wfrest::Json data; 40 | unsigned short s_port; 41 | std::string s_cert_file; 42 | std::string s_file_key; 43 | std::string c_host; 44 | unsigned short c_port; 45 | int c_redirect_max; 46 | int c_retry_max; 47 | std::string c_user_name; 48 | std::string c_password; 49 | std::string root_path; 50 | ErrorPageMap error_page; 51 | }; 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/module/proto/opentelemetry_metrics_service.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2019, OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package opentelemetry.proto.collector.metrics.v1; 18 | 19 | import "opentelemetry_metrics.proto"; 20 | 21 | // Service that can be used to push metrics between one Application 22 | // instrumented with OpenTelemetry and a collector, or between a collector and a 23 | // central collector. 24 | service MetricsService { 25 | // For performance reasons, it is recommended to keep this RPC 26 | // alive for the entire life of the application. 27 | rpc Export(ExportMetricsServiceRequest) returns (ExportMetricsServiceResponse) {} 28 | } 29 | 30 | message ExportMetricsServiceRequest { 31 | // An array of ResourceMetrics. 32 | // For data coming from a single resource this array will typically contain one 33 | // element. Intermediary nodes (such as OpenTelemetry Collector) that receive 34 | // data from multiple origins typically batch the data before forwarding further and 35 | // in that case this array will contain multiple elements. 36 | repeated opentelemetry.proto.metrics.v1.ResourceMetrics resource_metrics = 1; 37 | } 38 | 39 | message ExportMetricsServiceResponse { 40 | } 41 | -------------------------------------------------------------------------------- /CMakeLists_Headers.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | set(SRC_HEADERS 4 | src/compress/rpc_compress.h 5 | src/compress/rpc_compress_gzip.h 6 | src/message/rpc_message.h 7 | src/message/rpc_message_srpc.h 8 | src/message/rpc_message_thrift.h 9 | src/message/rpc_message_brpc.h 10 | src/message/rpc_message_trpc.h 11 | src/thrift/rpc_thrift_buffer.h 12 | src/thrift/rpc_thrift_enum.h 13 | src/thrift/rpc_thrift_idl.h 14 | src/thrift/rpc_thrift_idl.inl 15 | src/var/ckms_quantiles.h 16 | src/var/time_window_quantiles.h 17 | src/var/rpc_var.h 18 | src/module/rpc_module.h 19 | src/module/rpc_trace_module.h 20 | src/module/rpc_metrics_module.h 21 | src/module/rpc_filter.h 22 | src/module/rpc_trace_filter.h 23 | src/module/rpc_metrics_filter.h 24 | src/rpc_basic.h 25 | src/rpc_buffer.h 26 | src/rpc_client.h 27 | src/rpc_context.h 28 | src/rpc_context.inl 29 | src/rpc_global.h 30 | src/rpc_options.h 31 | src/rpc_server.h 32 | src/rpc_service.h 33 | src/rpc_task.inl 34 | src/rpc_types.h 35 | src/rpc_zero_copy_stream.h 36 | src/rpc_define.h 37 | ) 38 | 39 | if (NOT WIN32) 40 | set(SRC_HEADERS 41 | ${SRC_HEADERS} 42 | src/http/http_task.h 43 | src/http/http_module.h 44 | src/http/http_client.h 45 | src/http/http_server.h 46 | ) 47 | endif () 48 | 49 | if (NOT SNAPPY_INSTALLED) 50 | set(SNAPPY_HEADERS 51 | third_party/snappy/snappy.h 52 | third_party/snappy/snappy-c.h 53 | third_party/snappy/snappy-sinksource.h 54 | third_party/snappy/snappy-stubs-public.h 55 | ) 56 | endif () 57 | 58 | if (NOT LZ4_INSTALLED) 59 | set(LZ4_HEADERS 60 | third_party/lz4/lib/lz4.h 61 | third_party/lz4/lib/lz4frame.h 62 | ) 63 | endif () 64 | 65 | if (WITH_VCPKG_TOOLCHAIN) 66 | set(INCLUDE_HEADERS ${SRC_HEADERS}) 67 | else() 68 | set(INCLUDE_HEADERS ${SRC_HEADERS} ${SNAPPY_HEADERS} ${LZ4_HEADERS}) 69 | endif() 70 | 71 | -------------------------------------------------------------------------------- /tutorial/tutorial-07-thrift_thrift_server.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "echo_thrift.srpc.h" 19 | #include "workflow/WFFacilities.h" 20 | 21 | using namespace srpc; 22 | 23 | static WFFacilities::WaitGroup wait_group(1); 24 | 25 | class ExampleServiceImpl : public Example::Service 26 | { 27 | public: 28 | void Echo(EchoResult& _return, const std::string& message, 29 | const std::string& name) override 30 | { 31 | _return.message = "Hi back, " + name; 32 | 33 | printf("Server Echo()\nreq_message:\n%s\nresp_message:\n%s\n", 34 | message.c_str(), _return.message.c_str()); 35 | } 36 | }; 37 | 38 | static void sig_handler(int signo) 39 | { 40 | wait_group.done(); 41 | } 42 | 43 | int main() 44 | { 45 | signal(SIGINT, sig_handler); 46 | signal(SIGTERM, sig_handler); 47 | 48 | ThriftServer server; 49 | ExampleServiceImpl impl; 50 | 51 | server.add_service(&impl); 52 | 53 | if (server.start(1412) == 0) 54 | { 55 | printf("SRPC framework Thrift protocol server with thrift IDL is running on 1412\n" 56 | "Try ./thrift_thrift_client to send requests.\n\n"); 57 | wait_group.wait(); 58 | server.stop(); 59 | } 60 | else 61 | perror("server start"); 62 | 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /tools/templates/rpc/client_protobuf.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "workflow/WFFacilities.h" 3 | #include "srpc/rpc_types.h" 4 | #include "%s.srpc.h" 5 | #include "config/config.h" 6 | 7 | using namespace srpc; 8 | 9 | static WFFacilities::WaitGroup wait_group(1); 10 | static srpc::RPCConfig config; 11 | 12 | void init() 13 | { 14 | if (config.load("./client.conf") == false) 15 | { 16 | perror("Load config failed"); 17 | exit(1); 18 | } 19 | } 20 | 21 | int main() 22 | { 23 | // 1. load config 24 | init(); 25 | 26 | // 2. start client 27 | RPCClientParams params = RPC_CLIENT_PARAMS_DEFAULT; 28 | params.host = config.client_host(); 29 | params.port = config.client_port(); 30 | %s 31 | %s::%sClient client(¶ms); 32 | config.load_filter(client); 33 | 34 | // 3. request with sync api 35 | EchoRequest req; 36 | EchoResponse resp; 37 | RPCSyncContext ctx; 38 | 39 | req.set_message("Hello, this is sync request!"); 40 | client.Echo(&req, &resp, &ctx); 41 | 42 | if (ctx.success) 43 | fprintf(stderr, "sync resp. %%s\n", resp.DebugString().c_str()); 44 | else 45 | fprintf(stderr, "sync status[%%d] error[%%d] errmsg:%%s\n", 46 | ctx.status_code, ctx.error, ctx.errmsg.c_str()); 47 | 48 | // 4. request with async api 49 | 50 | req.set_message("Hello, this is async request!"); 51 | 52 | client.Echo(&req, [](EchoResponse *resp, RPCContext *ctx) { 53 | if (ctx->success()) 54 | fprintf(stderr, "async resp. %%s\n", resp->DebugString().c_str()); 55 | else 56 | fprintf(stderr, "async status[%%d] error[%%d] errmsg:%%s\n", 57 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 58 | wait_group.done(); 59 | }); 60 | 61 | wait_group.wait(); 62 | 63 | return 0; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /tutorial/tutorial-02-srpc_pb_client.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "workflow/WFFacilities.h" 19 | #include "echo_pb.srpc.h" 20 | #include "srpc/rpc_types.h" 21 | 22 | using namespace srpc; 23 | 24 | static WFFacilities::WaitGroup wait_group(1); 25 | 26 | int main() 27 | { 28 | Example::SRPCClient client("127.0.0.1", 1412); 29 | 30 | //async 31 | EchoRequest req; 32 | req.set_message("Hello, srpc!"); 33 | req.set_name("1412"); 34 | 35 | client.Echo(&req, [](EchoResponse *resp, RPCContext *ctx) { 36 | if (ctx->success()) 37 | printf("%s\n", resp->DebugString().c_str()); 38 | else 39 | printf("status[%d] error[%d] errmsg:%s\n", 40 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 41 | wait_group.done(); 42 | }); 43 | 44 | //sync 45 | EchoRequest sync_req; 46 | EchoResponse sync_resp; 47 | RPCSyncContext sync_ctx; 48 | 49 | sync_req.set_message("Hello, srpc!"); 50 | sync_req.set_name("Sync"); 51 | client.Echo(&sync_req, &sync_resp, &sync_ctx); 52 | if (sync_ctx.success) 53 | printf("%s\n", sync_resp.DebugString().c_str()); 54 | else 55 | printf("status[%d] error[%d] errmsg:%s\n", 56 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 57 | 58 | wait_group.wait(); 59 | return 0; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /tutorial/tutorial-01-srpc_pb_server.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "echo_pb.srpc.h" 19 | #include "workflow/WFFacilities.h" 20 | #include "srpc/rpc_types.h" 21 | 22 | using namespace srpc; 23 | 24 | static WFFacilities::WaitGroup wait_group(1); 25 | 26 | class ExampleServiceImpl : public Example::Service 27 | { 28 | public: 29 | void Echo(EchoRequest *req, EchoResponse *resp, RPCContext *ctx) override 30 | { 31 | resp->set_message("Hi back"); 32 | 33 | printf("Server Echo()\nget_req:\n%s\nset_resp:\n%s\n", 34 | req->DebugString().c_str(), resp->DebugString().c_str()); 35 | } 36 | }; 37 | 38 | static void sig_handler(int signo) 39 | { 40 | wait_group.done(); 41 | } 42 | 43 | int main() 44 | { 45 | GOOGLE_PROTOBUF_VERIFY_VERSION; 46 | signal(SIGINT, sig_handler); 47 | signal(SIGTERM, sig_handler); 48 | 49 | SRPCServer server; 50 | ExampleServiceImpl impl; 51 | 52 | server.add_service(&impl); 53 | 54 | if (server.start(1412) == 0) 55 | { 56 | printf("SRPC framework SRPC Protobuf server is running on 1412\n" 57 | "Try ./srpc_pb_client to send requests.\n\n"); 58 | wait_group.wait(); 59 | server.stop(); 60 | } 61 | else 62 | perror("server start"); 63 | 64 | google::protobuf::ShutdownProtobufLibrary(); 65 | return 0; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /tools/templates/rpc/client_thrift.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "workflow/WFFacilities.h" 3 | #include "srpc/rpc_types.h" 4 | #include "%s.srpc.h" 5 | #include "config/config.h" 6 | 7 | using namespace srpc; 8 | 9 | static WFFacilities::WaitGroup wait_group(1); 10 | static srpc::RPCConfig config; 11 | 12 | void init() 13 | { 14 | if (config.load("./client.conf") == false) 15 | { 16 | perror("Load config failed"); 17 | exit(1); 18 | } 19 | } 20 | 21 | int main() 22 | { 23 | // 1. load config 24 | init(); 25 | 26 | // 2. start client 27 | RPCClientParams params = RPC_CLIENT_PARAMS_DEFAULT; 28 | params.host = config.client_host(); 29 | params.port = config.client_port(); 30 | %s 31 | %s::%sClient client(¶ms); 32 | config.load_filter(client); 33 | 34 | // 3. request with sync api 35 | EchoResult res; 36 | 37 | client.Echo(res, "Hello, this is sync request!"); 38 | 39 | if (client.thrift_last_sync_success()) 40 | fprintf(stderr, "sync resp. %%s\n", res.message.c_str()); 41 | else 42 | { 43 | const auto& sync_ctx = client.thrift_last_sync_ctx(); 44 | 45 | fprintf(stderr, "sync status[%%d] error[%%d] errmsg:%%s\n", 46 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 47 | } 48 | 49 | // 4. request with async api 50 | %s::EchoRequest req; 51 | req.message = "Hello, this is async request!"; 52 | 53 | client.Echo(&req, [](%s::EchoResponse *resp, RPCContext *ctx) { 54 | if (ctx->success()) 55 | fprintf(stderr, "async resp. %%s\n", resp->result.message.c_str()); 56 | else 57 | fprintf(stderr, "async status[%%d] error[%%d] errmsg:%%s\n", 58 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 59 | wait_group.done(); 60 | }); 61 | 62 | wait_group.wait(); 63 | 64 | return 0; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /tutorial/tutorial-03-srpc_thrift_server.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "echo_thrift.srpc.h" 19 | #include "workflow/WFFacilities.h" 20 | 21 | using namespace srpc; 22 | 23 | static WFFacilities::WaitGroup wait_group(1); 24 | 25 | class ExampleServiceImpl : public Example::Service 26 | { 27 | public: 28 | void Echo(EchoResult& _return, const std::string& message, 29 | const std::string& name) override 30 | { 31 | _return.message = "Hi back, " + name; 32 | 33 | printf("Server Echo()\nreq_message:\n%s\nresp_message:\n%s\n", 34 | message.c_str(), _return.message.c_str()); 35 | } 36 | }; 37 | 38 | static void sig_handler(int signo) 39 | { 40 | wait_group.done(); 41 | } 42 | 43 | int main() 44 | { 45 | GOOGLE_PROTOBUF_VERIFY_VERSION; 46 | signal(SIGINT, sig_handler); 47 | signal(SIGTERM, sig_handler); 48 | 49 | SRPCServer server; 50 | ExampleServiceImpl impl; 51 | 52 | server.add_service(&impl); 53 | 54 | if (server.start(1412) == 0) 55 | { 56 | printf("SRPC framework SRPC protocol server with thrift IDL is running on 1412\n" 57 | "Try ./srpc_thrift_client to send requests.\n\n"); 58 | wait_group.wait(); 59 | server.stop(); 60 | } 61 | else 62 | perror("server start"); 63 | 64 | google::protobuf::ShutdownProtobufLibrary(); 65 | return 0; 66 | } 67 | 68 | -------------------------------------------------------------------------------- /docs/docs-04-client.md: -------------------------------------------------------------------------------- 1 | [English version](/docs/en/docs-04-client.md) 2 | 3 | ## 04 - RPC Client 4 | - 每一个Client对应着一个确定的目标/一个确定的集群 5 | - 每一个Client对应着一个确定的网络通信协议 6 | - 每一个Client对应着一个确定的IDL 7 | 8 | ### 示例 9 | 下面我们通过一个具体例子来呈现 10 | - 沿用上面的例子,client相对简单,直接调用即可 11 | - 通过``Example::XXXClient``创建某种RPC的client实例,需要目标的ip+port或url 12 | - 利用client实例直接调用rpc函数``Echo``即可,这是一次异步请求,请求完成后会进入回调函数 13 | - 具体的RPC Context用法请看下一个段落 14 | 15 | ~~~cpp 16 | #include 17 | #include "example.srpc.h" 18 | #include "workflow/WFFacilities.h" 19 | 20 | using namespace srpc; 21 | 22 | int main() 23 | { 24 | Example::SRPCClient client("127.0.0.1", 1412); 25 | EchoRequest req; 26 | req.set_message("Hello!"); 27 | req.set_name("SRPCClient"); 28 | 29 | WFFacilities::WaitGroup wait_group(1); 30 | 31 | client.Echo(&req, [&wait_group](EchoResponse *response, RPCContext *ctx) { 32 | if (ctx->success()) 33 | printf("%s\n", response->DebugString().c_str()); 34 | else 35 | printf("status[%d] error[%d] errmsg:%s\n", 36 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 37 | wait_group.done(); 38 | }); 39 | 40 | wait_group.wait(); 41 | return 0; 42 | } 43 | ~~~ 44 | 45 | ### 启动参数 46 | 47 | Client可以直接通过传入ip、port启动,或者通过参数启动。 48 | 49 | 上面的例子: 50 | 51 | ~~~cpp 52 | Example::SRPCClient client("127.0.0.1", 1412); 53 | ~~~ 54 | 55 | 等同于: 56 | 57 | ~~~cpp 58 | struct RPCClientParams param = RPC_CLIENT_PARAMS_DEFAULT; 59 | param.host = "127.0.0.1"; 60 | param.port = 1412; 61 | Example::SRPCClient client(¶m); 62 | ~~~ 63 | 64 | 也等同于: 65 | 66 | ~~~cpp 67 | struct RPCClientParams param = RPC_CLIENT_PARAMS_DEFAULT; 68 | param.url = "srpc://127.0.0.1:1412"; 69 | Example::SRPCClient client(¶m); 70 | ~~~ 71 | 72 | 注意这里一定要使用`RPC_CLIENT_PARAMS_DEFAULT`去初始化我们的参数,里边包含了一个`RPCTaskParams`,包括默认的data_type、compress_type、重试次数和多种超时,具体结构可以参考[rpc_options.h](/src/rpc_options.h)。 73 | 74 | -------------------------------------------------------------------------------- /src/compress/rpc_compress_snappy.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_COMPRESS_SNAPPY_H__ 18 | #define __RPC_COMPRESS_SNAPPY_H__ 19 | 20 | #include "rpc_buffer.h" 21 | 22 | namespace srpc 23 | { 24 | 25 | class SnappyManager 26 | { 27 | public: 28 | /* 29 | * compress serialized msg into buf. 30 | * ret: -1: failed 31 | * >0: byte count of compressed data 32 | */ 33 | static int SnappyCompress(const char *msg, size_t msglen, char *buf, size_t buflen); 34 | 35 | /* 36 | * decompress and parse buf into msg 37 | * ret: -1: failed 38 | * >0: byte count of compressed data 39 | */ 40 | static int SnappyDecompress(const char *buf, size_t buflen, char *msg, size_t msglen); 41 | 42 | /* 43 | * compress RPCBuffer src(Source) into RPCBuffer dst(Sink) 44 | * ret: -1: failed 45 | * >0: byte count of compressed data 46 | */ 47 | static int SnappyCompressIOVec(RPCBuffer *src, RPCBuffer *dst); 48 | 49 | /* 50 | * decompress RPCBuffer src(Source) into RPCBuffer dst(Sink) 51 | * ret: -1: failed 52 | * >0: byte count of compressed data 53 | */ 54 | static int SnappyDecompressIOVec(RPCBuffer *src, RPCBuffer *dst); 55 | 56 | /* 57 | * lease size after compress origin_size data 58 | */ 59 | static int SnappyLeaseSize(size_t origin_size); 60 | }; 61 | 62 | } // end namespace srpc 63 | 64 | #endif 65 | 66 | -------------------------------------------------------------------------------- /tutorial/tutorial-14-trpc_http_client.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "workflow/WFFacilities.h" 19 | #include "helloworld.srpc.h" 20 | #include "srpc/rpc_types.h" 21 | 22 | using namespace srpc; 23 | using namespace trpc::test::helloworld; 24 | 25 | static WFFacilities::WaitGroup wait_group(1); 26 | 27 | int main() 28 | { 29 | Greeter::TRPCHttpClient client("127.0.0.1", 1412); 30 | 31 | //async 32 | HelloRequest req; 33 | req.set_msg("Hello, trpc-http server. This is srpc framework trpc-http client!"); 34 | 35 | client.SayHello(&req, [](HelloReply *resp, RPCContext *ctx) { 36 | if (ctx->success()) 37 | printf("%s\n", resp->DebugString().c_str()); 38 | else 39 | printf("status[%d] error[%d] errmsg:%s\n", 40 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 41 | }); 42 | 43 | //sync 44 | HelloRequest sync_req; 45 | HelloReply sync_resp; 46 | RPCSyncContext sync_ctx; 47 | 48 | sync_req.set_msg("Hi, trpc-http server. This is srpc framework trpc-http client!"); 49 | client.SayHi(&sync_req, &sync_resp, &sync_ctx); 50 | if (sync_ctx.success) 51 | printf("%s\n", sync_resp.DebugString().c_str()); 52 | else 53 | printf("status[%d] error[%d] errmsg:%s\n", 54 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 55 | 56 | wait_group.wait(); 57 | return 0; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /tutorial/tutorial-12-trpc_pb_client.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "workflow/WFFacilities.h" 19 | #include "helloworld.srpc.h" 20 | #include "srpc/rpc_types.h" 21 | 22 | using namespace srpc; 23 | using namespace trpc::test::helloworld; 24 | 25 | static WFFacilities::WaitGroup wait_group(1); 26 | 27 | int main() 28 | { 29 | Greeter::TRPCClient client("127.0.0.1", 1412); 30 | 31 | //async 32 | HelloRequest req; 33 | req.set_msg("Hello, trpc server. This is srpc framework trpc client!"); 34 | 35 | client.SayHello(&req, [](HelloReply *resp, RPCContext *ctx) { 36 | if (ctx->success()) 37 | printf("%s\n", resp->DebugString().c_str()); 38 | else 39 | printf("status[%d] error[%d] errmsg:%s\n", 40 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 41 | wait_group.done(); 42 | }); 43 | 44 | //sync 45 | HelloRequest sync_req; 46 | HelloReply sync_resp; 47 | RPCSyncContext sync_ctx; 48 | 49 | sync_req.set_msg("Hi, trpc server. This is srpc framework trpc client!"); 50 | client.SayHi(&sync_req, &sync_resp, &sync_ctx); 51 | 52 | if (sync_ctx.success) 53 | printf("%s\n", sync_resp.DebugString().c_str()); 54 | else 55 | printf("status[%d] error[%d] errmsg:%s\n", 56 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 57 | 58 | wait_group.wait(); 59 | return 0; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/thrift/rpc_thrift_enum.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_THRIFT_ENUM_H__ 18 | #define __RPC_THRIFT_ENUM_H__ 19 | 20 | namespace srpc 21 | { 22 | 23 | static constexpr int THRIFT_STRUCT_FIELD_REQUIRED = 0; 24 | static constexpr int THRIFT_STRUCT_FIELD_OPTIONAL = 1; 25 | static constexpr int THRIFT_STRUCT_FIELD_DEFAULT = 2; 26 | 27 | enum ThriftMessageType 28 | { 29 | TMT_CALL = 1, 30 | TMT_REPLY = 2, 31 | TMT_EXCEPTION = 3, 32 | TMT_ONEWAY = 4 33 | }; 34 | 35 | enum ThriftDataType 36 | { 37 | TDT_STOP = 0, 38 | TDT_VOID = 1, 39 | TDT_BOOL = 2, 40 | TDT_BYTE = 3, 41 | TDT_I08 = 3, 42 | TDT_I16 = 6, 43 | TDT_I32 = 8, 44 | TDT_U64 = 9, 45 | TDT_I64 = 10, 46 | TDT_DOUBLE = 4, 47 | TDT_STRING = 11, 48 | TDT_UTF7 = 11, 49 | TDT_STRUCT = 12, 50 | TDT_MAP = 13, 51 | TDT_SET = 14, 52 | TDT_LIST = 15, 53 | TDT_UTF8 = 16, 54 | TDT_UTF16 = 17 55 | }; 56 | 57 | enum ThriftExceptionType 58 | { 59 | TET_UNKNOWN = 0, 60 | TET_UNKNOWN_METHOD = 1, 61 | TET_INVALID_MESSAGE_TYPE = 2, 62 | TET_WRONG_METHOD_NAME = 3, 63 | TET_BAD_SEQUENCE_ID = 4, 64 | TET_MISSING_RESULT = 5, 65 | TET_INTERNAL_ERROR = 6, 66 | TET_PROTOCOL_ERROR = 7, 67 | TET_INVALID_TRANSFORM = 8, 68 | TET_INVALID_PROTOCOL = 9, 69 | TET_UNSUPPORTED_CLIENT_TYPE = 10 70 | }; 71 | 72 | } // end namespace srpc 73 | 74 | #endif 75 | 76 | -------------------------------------------------------------------------------- /tutorial/tutorial-18-http_client.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "workflow/WFFacilities.h" 19 | #include "srpc/http_client.h" 20 | #include "srpc/rpc_types.h" 21 | #include "srpc/rpc_metrics_filter.h" 22 | #include "srpc/rpc_trace_filter.h" 23 | 24 | using namespace srpc; 25 | 26 | #define REDIRECT_MAX 5 27 | #define RETRY_MAX 2 28 | 29 | srpc::RPCTraceDefault trace_log; 30 | static WFFacilities::WaitGroup wait_group(1); 31 | 32 | void callback(WFHttpTask *task) 33 | { 34 | int state = task->get_state(); 35 | int error = task->get_error(); 36 | fprintf(stderr, "callback. state = %d error = %d\n", state, error); 37 | 38 | if (state == WFT_STATE_SUCCESS) // print server response body 39 | { 40 | const void *body; 41 | size_t body_len; 42 | 43 | task->get_resp()->get_parsed_body(&body, &body_len); 44 | fwrite(body, 1, body_len, stdout); 45 | fflush(stdout); 46 | fprintf(stderr, "\nfinish print body. body_len = %zu\n", body_len); 47 | } 48 | 49 | wait_group.done(); 50 | } 51 | 52 | int main() 53 | { 54 | srpc::HttpClient client; 55 | client.add_filter(&trace_log); 56 | 57 | WFHttpTask *task = client.create_http_task("http://127.0.0.1:1412", 58 | REDIRECT_MAX, 59 | RETRY_MAX, 60 | callback); 61 | task->start(); 62 | wait_group.wait(); 63 | 64 | return 0; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 2 | ALL_TARGETS := all base check install preinstall package rpm clean tutorial example 3 | MAKE_FILE := Makefile 4 | 5 | DEFAULT_BUILD_DIR := build.cmake 6 | BUILD_DIR := $(shell if [ -f $(MAKE_FILE) ]; then echo "."; else echo $(DEFAULT_BUILD_DIR); fi) 7 | CMAKE3 := $(shell if which cmake3>/dev/null ; then echo cmake3; else echo cmake; fi;) 8 | WORKFLOW := $(shell if [ -f "workflow/workflow-config.cmake.in" ]; then echo "Found"; else echo "NotFound"; fi) 9 | 10 | .PHONY: $(ALL_TARGETS) 11 | 12 | all: base 13 | make -C $(BUILD_DIR) -f Makefile 14 | 15 | base: 16 | 17 | ifeq ("$(WORKFLOW)","Found") 18 | make -C workflow 19 | endif 20 | 21 | mkdir -p $(BUILD_DIR) 22 | 23 | ifeq ($(DEBUG),y) 24 | cd $(BUILD_DIR) && $(CMAKE3) -D CMAKE_BUILD_TYPE=Debug $(ROOT_DIR) 25 | else ifneq ("${INSTALL_PREFIX}install_prefix", "install_prefix") 26 | cd $(BUILD_DIR) && $(CMAKE3) -DCMAKE_INSTALL_PREFIX:STRING=${INSTALL_PREFIX} $(ROOT_DIR) 27 | else 28 | cd $(BUILD_DIR) && $(CMAKE3) $(ROOT_DIR) 29 | endif 30 | 31 | tutorial: all 32 | make -C tutorial 33 | 34 | check: all 35 | make -C test check 36 | 37 | install preinstall package: base 38 | mkdir -p $(BUILD_DIR) 39 | cd $(BUILD_DIR) && $(CMAKE3) $(ROOT_DIR) 40 | make -C $(BUILD_DIR) -f Makefile $@ 41 | 42 | rpm: package 43 | ifneq ($(BUILD_DIR),.) 44 | mv $(BUILD_DIR)/*.rpm ./ 45 | endif 46 | 47 | clean: 48 | ifeq ("$(WORKFLOW)","Found") 49 | -make -C workflow clean 50 | endif 51 | -make -C test clean 52 | -make -C tutorial clean 53 | -make -C benchmark clean 54 | rm -rf $(DEFAULT_BUILD_DIR) 55 | rm -rf _include 56 | rm -rf _lib 57 | rm -rf _bin 58 | rm -f SRCINFO SRCNUMVER SRCVERSION 59 | rm -f ./*.rpm 60 | rm -f src/message/*.pb.h src/message/*.pb.cc 61 | find . -name CMakeCache.txt | xargs rm -f 62 | find . -name Makefile | xargs rm -f 63 | find . -name "*.cmake" | xargs rm -f 64 | find . -name CMakeFiles | xargs rm -rf 65 | 66 | -------------------------------------------------------------------------------- /tutorial/tutorial-05-brpc_pb_server.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "echo_pb.srpc.h" 19 | #include "workflow/WFFacilities.h" 20 | 21 | using namespace srpc; 22 | 23 | static WFFacilities::WaitGroup wait_group(1); 24 | 25 | char attachment[10] = "ATTACH"; 26 | 27 | class ExampleServiceImpl : public Example::Service 28 | { 29 | public: 30 | void Echo(EchoRequest *req, EchoResponse *resp, RPCContext *ctx) override 31 | { 32 | resp->set_message("Hi back, " + req->name()); 33 | ctx->set_attachment_nocopy(attachment, strlen(attachment)); 34 | 35 | printf("Server Echo()\nget_req:\n%s\nset_resp:\n%s\n", 36 | req->DebugString().c_str(), resp->DebugString().c_str()); 37 | } 38 | }; 39 | 40 | static void sig_handler(int signo) 41 | { 42 | wait_group.done(); 43 | } 44 | 45 | int main() 46 | { 47 | GOOGLE_PROTOBUF_VERIFY_VERSION; 48 | signal(SIGINT, sig_handler); 49 | signal(SIGTERM, sig_handler); 50 | 51 | BRPCServer server; 52 | ExampleServiceImpl impl; 53 | 54 | server.add_service(&impl); 55 | 56 | if (server.start(1412) == 0) 57 | { 58 | printf("SRPC framework BRPC Protobuf server is running on 1412\n" 59 | "Try ./brpc_pb_client to send requests.\n\n"); 60 | wait_group.wait(); 61 | server.stop(); 62 | } 63 | else 64 | perror("server start"); 65 | 66 | google::protobuf::ShutdownProtobufLibrary(); 67 | return 0; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /tutorial/tutorial-06-brpc_pb_client.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "workflow/WFFacilities.h" 19 | #include "echo_pb.srpc.h" 20 | 21 | using namespace srpc; 22 | 23 | static WFFacilities::WaitGroup wait_group(1); 24 | 25 | int main() 26 | { 27 | Example::BRPCClient client("127.0.0.1", 1412); 28 | 29 | //async 30 | EchoRequest req; 31 | req.set_message("Hello, srpc!"); 32 | req.set_name("1412"); 33 | 34 | client.Echo(&req, [](EchoResponse *resp, RPCContext *ctx) { 35 | if (ctx->success()) 36 | printf("%s\n", resp->DebugString().c_str()); 37 | else 38 | printf("status[%d] error[%d] errmsg:%s\n", 39 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 40 | 41 | const char *attachment; 42 | size_t len; 43 | 44 | while (ctx->get_attachment(&attachment, &len)) 45 | printf("get attachment [%.*s] len=%zu\n", (int)len, attachment, len); 46 | 47 | wait_group.done(); 48 | }); 49 | 50 | //sync 51 | EchoRequest sync_req; 52 | EchoResponse sync_resp; 53 | RPCSyncContext sync_ctx; 54 | 55 | sync_req.set_message("Hello, srpc!"); 56 | sync_req.set_name("Sync"); 57 | 58 | client.Echo(&sync_req, &sync_resp, &sync_ctx); 59 | 60 | if (sync_ctx.success) 61 | printf("%s\n", sync_resp.DebugString().c_str()); 62 | else 63 | printf("status[%d] error[%d] errmsg:%s\n", 64 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 65 | 66 | wait_group.wait(); 67 | return 0; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/rpc_define.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_DEFINE_H__ 18 | #define __RPC_DEFINE_H__ 19 | 20 | #if __cplusplus < 201100 21 | #error CPLUSPLUS VERSION required at least C++11. Please use "-std=c++11". 22 | #include 23 | #endif 24 | 25 | #include "rpc_server.h" 26 | #include "rpc_client.h" 27 | 28 | namespace srpc 29 | { 30 | 31 | using SRPCServer = RPCServer; 32 | using SRPCClient = RPCClient; 33 | using SRPCClientTask = SRPCClient::TASK; 34 | 35 | using SRPCHttpServer = RPCServer; 36 | using SRPCHttpClient = RPCClient; 37 | using SRPCHttpClientTask = SRPCHttpClient::TASK; 38 | 39 | using BRPCServer = RPCServer; 40 | using BRPCClient = RPCClient; 41 | using BRPCClientTask = BRPCClient::TASK; 42 | 43 | using ThriftServer = RPCServer; 44 | using ThriftClient = RPCClient; 45 | using ThriftClientTask = ThriftClient::TASK; 46 | 47 | using ThriftHttpServer = RPCServer; 48 | using ThriftHttpClient = RPCClient; 49 | using ThriftHttpClientTask = ThriftHttpClient::TASK; 50 | 51 | using TRPCServer = RPCServer; 52 | using TRPCClient = RPCClient; 53 | using TRPCClientTask = TRPCClient::TASK; 54 | 55 | using TRPCHttpServer = RPCServer; 56 | using TRPCHttpClient = RPCClient; 57 | using TRPCHttpClientTask = TRPCHttpClient::TASK; 58 | 59 | } // namespace srpc 60 | 61 | #endif 62 | 63 | -------------------------------------------------------------------------------- /srpc.bzl: -------------------------------------------------------------------------------- 1 | """ 2 | Rules for building C++ srpc with Bazel. 3 | """ 4 | 5 | load("@rules_cc//cc:defs.bzl", "cc_library") 6 | 7 | tool_path = ":srpc_generator" 8 | 9 | def srpc_cc_library( 10 | name, 11 | srcs, 12 | deps = [], 13 | type = "proto", 14 | out_prefix = "", 15 | visibility = None): 16 | output_directory = ( 17 | ("$(@D)/%s" % (out_prefix)) if len(srcs) > 1 else ("$(@D)") 18 | ) 19 | 20 | proto_output_headers = [ 21 | (out_prefix + "%s.srpc.h") % (s.replace(".%s" % type, "").split("/")[-1]) 22 | for s in srcs 23 | ] 24 | thrift_output_headers = [ 25 | (out_prefix + "%s.thrift.h") % (s.replace(".%s" % type, "").split("/")[-1]) 26 | for s in srcs 27 | ] 28 | 29 | if type == "thrift": 30 | output_headers = proto_output_headers + thrift_output_headers 31 | gen_proto = "thrift" 32 | if type == "proto": 33 | output_headers = proto_output_headers 34 | gen_proto = "protobuf" 35 | 36 | genrule_cmd = " ".join([ 37 | "SRCS=($(SRCS));", 38 | "for f in $${SRCS[@]:0:%s}; do" % len(srcs), 39 | "$(location %s)" % (tool_path), 40 | " %s " % gen_proto, 41 | "$$f", 42 | output_directory + ";", 43 | "done", 44 | ]) 45 | 46 | srcs_lib = "%s_srcs" % (name) 47 | 48 | native.genrule( 49 | name = srcs_lib, 50 | srcs = srcs, 51 | outs = output_headers, 52 | tools = [tool_path], 53 | cmd = genrule_cmd, 54 | output_to_bindir = True, 55 | message = "Generating srpc files for %s:" % (name), 56 | ) 57 | 58 | runtime_deps = deps + [":srpc"] 59 | print(runtime_deps) 60 | 61 | cc_library( 62 | name = name, 63 | hdrs = [ 64 | ":" + srcs_lib, 65 | ], 66 | srcs = [ 67 | ":" + srcs_lib, 68 | ], 69 | features = [ 70 | "-parse_headers", 71 | ], 72 | deps = runtime_deps, 73 | includes = [], 74 | linkstatic = 1, 75 | visibility = visibility, 76 | ) 77 | -------------------------------------------------------------------------------- /src/rpc_basic.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | 18 | #ifdef _WIN32 19 | #include 20 | #else 21 | #include 22 | #include 23 | #endif 24 | #include "rpc_basic.h" 25 | #include "rpc_module.h" 26 | 27 | namespace srpc 28 | { 29 | 30 | void RPCCommon::log_format(std::string& key, std::string& value, 31 | const RPCLogVector& fields) 32 | { 33 | if (fields.size() == 0) 34 | return; 35 | 36 | char buffer[100]; 37 | snprintf(buffer, 100, "%s%c%lld", SRPC_SPAN_LOG, ' ', GET_CURRENT_MS()); 38 | key = std::move(buffer); 39 | value = "{\""; 40 | 41 | for (auto& field : fields) 42 | { 43 | value = value + std::move(field.first) + "\":\"" 44 | + std::move(field.second) + "\","; 45 | } 46 | 47 | value[value.length() - 1] = '}'; 48 | } 49 | 50 | bool RPCCommon::addr_to_string(const struct sockaddr *addr, 51 | char *ip_str, socklen_t len, 52 | unsigned short *port) 53 | { 54 | const char *ret = NULL; 55 | 56 | if (addr->sa_family == AF_INET) 57 | { 58 | struct sockaddr_in *sin = (struct sockaddr_in *)addr; 59 | 60 | ret = inet_ntop(AF_INET, &sin->sin_addr, ip_str, len); 61 | *port = ntohs(sin->sin_port); 62 | } 63 | else if (addr->sa_family == AF_INET6) 64 | { 65 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; 66 | 67 | ret = inet_ntop(AF_INET6, &sin6->sin6_addr, ip_str, len); 68 | *port = ntohs(sin6->sin6_port); 69 | } 70 | else 71 | errno = EINVAL; 72 | 73 | return ret != NULL; 74 | } 75 | 76 | } // namespace srpc 77 | 78 | -------------------------------------------------------------------------------- /docs/docs-03-server.md: -------------------------------------------------------------------------------- 1 | [English version](/docs/en/docs-03-server.md) 2 | 3 | ## 03 - RPC Server 4 | - 每一个Server对应一个端口 5 | - 每一个Server对应一个确定的网络通信协议 6 | - 每一个Service可以添加到任意的Server里 7 | - 每一个Server可以拥有任意的Service,但在当前Server里ServiceName必须唯一 8 | - 不同IDL的Service是可以放进同一个Server中的 9 | 10 | ### 示例 11 | 下面我们通过一个具体例子来呈现 12 | - 沿用上面的``ExampleServiceImpl``Service 13 | - 首先,我们创建1个RPC Server、需要确定协议 14 | - 然后,我们可以创建任意个数的Service实例、任意不同proto形成的Service,把这些Service通过``add_service()``接口添加到Server里 15 | - 最后,通过Server的``start``或者``serve``开启服务,处理即将到来的rpc请求 16 | - 想像一下,我们也可以从``Example::Service``派生更多的功能的rpc``Echo``不同实现的Service 17 | - 想像一下,我们可以在N个不同的端口创建N个不同的RPC Server、代表着不同的协议 18 | - 想像一下,我们可以把同一个ServiceIMPL实例``add_service``到不同的Server上,我们也可以把不同的ServiceIMPL实例``add_service``到同一个Server上 19 | - 想像一下,我们可以用同一个``ExampleServiceImpl``,在三个不同端口、同时服务于BRPC-STD、SRPC-STD、SRPC-Http 20 | - 甚至,我们可以将1个PB的``ExampleServiceImpl``和1个Thrift的``AnotherThriftServiceImpl``,``add_service``到同一个SRPC-STD Server,两种IDL在同一个端口上完美工作! 21 | 22 | ~~~cpp 23 | int main() 24 | { 25 | SRPCServer server_srpc; 26 | SRPCHttpServer server_srpc_http; 27 | BRPCServer server_brpc; 28 | ThriftServer server_thrift; 29 | TRPCServer server_trpc; 30 | TRPCHttpServer server_trpc_http; 31 | 32 | ExampleServiceImpl impl_pb; 33 | AnotherThriftServiceImpl impl_thrift; 34 | 35 | server_srpc.add_service(&impl_pb); 36 | server_srpc.add_service(&impl_thrift); 37 | server_srpc_http.add_service(&impl_pb); 38 | server_srpc_http.add_service(&impl_thrift); 39 | server_brpc.add_service(&impl_pb); 40 | server_thrift.add_service(&impl_thrift); 41 | server_trpc.add_service(&impl_pb); 42 | server_trpc_http.add_service(&impl_thrift); 43 | 44 | server_srpc.start(1412); 45 | server_srpc_http.start(8811); 46 | server_brpc.start(2020); 47 | server_thrift.start(9090); 48 | server_trpc.start(2022); 49 | server_trpc_http.start(8822); 50 | 51 | getchar(); 52 | server_trpc_http.stop(); 53 | server_trpc.stop(); 54 | server_thrift.stop(); 55 | server_brpc.stop(); 56 | server_srpc_http.stop(); 57 | server_srpc.stop(); 58 | 59 | return 0; 60 | } 61 | ~~~ 62 | 63 | -------------------------------------------------------------------------------- /tutorial/tutorial-17-http_server.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "workflow/WFFacilities.h" 19 | #include "srpc/http_server.h" 20 | #include "srpc/rpc_types.h" 21 | #include "srpc/rpc_metrics_filter.h" 22 | #include "srpc/rpc_trace_filter.h" 23 | 24 | static WFFacilities::WaitGroup wait_group(1); 25 | 26 | srpc::RPCMetricsPull exporter; 27 | srpc::RPCTraceDefault trace_log; 28 | //srpc::RPCTraceOpenTelemetry otel("http://127.0.0.1:4318"); 29 | 30 | static void sig_handler(int signo) 31 | { 32 | wait_group.done(); 33 | } 34 | 35 | void process(WFHttpTask *task) 36 | { 37 | fprintf(stderr, "http server get request_uri: %s\n", 38 | task->get_req()->get_request_uri()); 39 | 40 | task->get_resp()->append_output_body("Hello from server!"); 41 | } 42 | 43 | int main() 44 | { 45 | signal(SIGINT, sig_handler); 46 | signal(SIGTERM, sig_handler); 47 | 48 | srpc::HttpServer server(process); 49 | 50 | exporter.init(8080); /* export port for prometheus */ 51 | exporter.create_histogram("echo_request_size", "Echo request size", 52 | {1, 10, 100}); 53 | exporter.create_summary("echo_test_quantiles", "Test quantile", 54 | {{0.5, 0.05}, {0.9, 0.01}}); 55 | 56 | server.add_filter(&trace_log); 57 | // server.add_filter(&otel); 58 | server.add_filter(&exporter); 59 | 60 | if (server.start(1412) == 0) 61 | { 62 | printf("HTTP protocol server is running on 1412\n" 63 | "Try ./http_client to send requests.\n\n"); 64 | wait_group.wait(); 65 | server.stop(); 66 | } 67 | else 68 | perror("server start"); 69 | 70 | exporter.deinit(); 71 | return 0; 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/module/rpc_metrics_module.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include "rpc_metrics_module.h" 18 | 19 | namespace srpc 20 | { 21 | 22 | bool MetricsModule::client_begin(SubTask *task, RPCModuleData& data) 23 | { 24 | data[SRPC_START_TIMESTAMP] = std::to_string(GET_CURRENT_NS()); 25 | // clear other unnecessary module_data since the data comes from series 26 | data.erase(SRPC_DURATION); 27 | data.erase(SRPC_FINISH_TIMESTAMP); 28 | 29 | return true; 30 | } 31 | 32 | bool MetricsModule::client_end(SubTask *task, RPCModuleData& data) 33 | { 34 | if (data.find(SRPC_START_TIMESTAMP) != data.end() && 35 | data.find(SRPC_DURATION) == data.end()) 36 | { 37 | unsigned long long end_time = GET_CURRENT_NS(); 38 | data[SRPC_FINISH_TIMESTAMP] = std::to_string(end_time); 39 | data[SRPC_DURATION] = std::to_string(end_time - 40 | atoll(data[SRPC_START_TIMESTAMP].data())); 41 | } 42 | 43 | return true; 44 | } 45 | 46 | bool MetricsModule::server_begin(SubTask *task, RPCModuleData& data) 47 | { 48 | if (data.find(SRPC_START_TIMESTAMP) == data.end()) 49 | data[SRPC_START_TIMESTAMP] = std::to_string(GET_CURRENT_NS()); 50 | 51 | return true; 52 | } 53 | 54 | bool MetricsModule::server_end(SubTask *task, RPCModuleData& data) 55 | { 56 | if (data.find(SRPC_START_TIMESTAMP) != data.end() && 57 | data.find(SRPC_DURATION) == data.end()) 58 | { 59 | unsigned long long end_time = GET_CURRENT_NS(); 60 | 61 | data[SRPC_FINISH_TIMESTAMP] = std::to_string(end_time); 62 | data[SRPC_DURATION] = std::to_string(end_time - 63 | atoll(data[SRPC_START_TIMESTAMP].data())); 64 | } 65 | 66 | return true; 67 | } 68 | 69 | } // end namespace srpc 70 | 71 | -------------------------------------------------------------------------------- /tutorial/tutorial-09-client_task.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include "echo_pb.srpc.h" 20 | #include "workflow/WFFacilities.h" 21 | 22 | using namespace srpc; 23 | 24 | int main() 25 | { 26 | Example::SRPCClient client("127.0.0.1", 1412); 27 | 28 | EchoRequest req; 29 | req.set_message("Hello, srpc!"); 30 | req.set_name("1412"); 31 | 32 | auto *rpc_task = client.create_Echo_task([](EchoResponse *resp, 33 | RPCContext *ctx) 34 | { 35 | if (ctx->success()) 36 | printf("%s\n", resp->DebugString().c_str()); 37 | else 38 | printf("status[%d] error[%d] errmsg:%s\n", 39 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 40 | }); 41 | 42 | auto *http_task = WFTaskFactory::create_http_task("https://www.sogou.com", 43 | 0, 0, 44 | [](WFHttpTask *task) 45 | { 46 | if (task->get_state() == WFT_STATE_SUCCESS) 47 | { 48 | std::string body; 49 | const void *data; 50 | size_t len; 51 | 52 | task->get_resp()->get_parsed_body(&data, &len); 53 | body.assign((const char *)data, len); 54 | printf("%s\n\n", body.c_str()); 55 | } 56 | else 57 | printf("Http request fail\n\n"); 58 | }); 59 | 60 | rpc_task->serialize_input(&req); 61 | rpc_task->log({{"event", "info"}, {"message", "rpc client task log."}}); 62 | 63 | WFFacilities::WaitGroup wait_group(1); 64 | 65 | SeriesWork *series = Workflow::create_series_work(http_task, [&wait_group](const SeriesWork *) { 66 | wait_group.done(); 67 | }); 68 | series->push_back(rpc_task); 69 | series->start(); 70 | 71 | wait_group.wait(); 72 | return 0; 73 | } 74 | 75 | -------------------------------------------------------------------------------- /tutorial/tutorial-04-srpc_thrift_client.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "workflow/WFFacilities.h" 19 | #include "echo_thrift.srpc.h" 20 | 21 | using namespace srpc; 22 | 23 | static WFFacilities::WaitGroup wait_group(1); 24 | 25 | int main() 26 | { 27 | Example::SRPCClient client("127.0.0.1", 1412); 28 | 29 | //sync 30 | EchoResult sync_res; 31 | 32 | client.Echo(sync_res, "Hello, srpc!", "1412"); 33 | 34 | if (client.thrift_last_sync_success()) 35 | printf("%s\n", sync_res.message.c_str()); 36 | else 37 | { 38 | const auto& sync_ctx = client.thrift_last_sync_ctx(); 39 | 40 | printf("status[%d] error[%d] errmsg:%s\n", 41 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 42 | } 43 | 44 | //async 45 | Example::EchoRequest req; 46 | req.message = "Hello, srpc!"; 47 | req.name = "1412"; 48 | 49 | client.Echo(&req, [](Example::EchoResponse *resp, RPCContext *ctx) { 50 | if (ctx->success()) 51 | printf("%s\n", resp->result.message.c_str()); 52 | else 53 | printf("status[%d] error[%d] errmsg:%s\n", 54 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 55 | wait_group.done(); 56 | }); 57 | 58 | //sync 59 | Example::EchoRequest sync_req; 60 | Example::EchoResponse sync_resp; 61 | RPCSyncContext sync_ctx; 62 | 63 | sync_req.message = "Hello, srpc!"; 64 | sync_req.name = "Sync"; 65 | 66 | client.Echo(&sync_req, &sync_resp, &sync_ctx); 67 | 68 | if (sync_ctx.success) 69 | printf("%s\n", sync_resp.result.message.c_str()); 70 | else 71 | printf("status[%d] error[%d] errmsg:%s\n", 72 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 73 | 74 | wait_group.wait(); 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /tutorial/tutorial-11-trpc_pb_server.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "helloworld.srpc.h" 19 | #include "workflow/WFFacilities.h" 20 | #include "srpc/rpc_types.h" 21 | 22 | using namespace srpc; 23 | using namespace trpc::test::helloworld; 24 | 25 | static WFFacilities::WaitGroup wait_group(1); 26 | 27 | class GreeterServiceImpl : public Greeter::Service 28 | { 29 | public: 30 | void SayHello(HelloRequest *req, HelloReply *resp, RPCContext *ctx) override 31 | { 32 | ctx->set_compress_type(RPCCompressGzip); 33 | resp->set_msg("This is SRPC framework TRPC protocol. Hello back."); 34 | 35 | printf("Server SayHello()\nget_req:\n%s\nset_resp:\n%s\n", 36 | req->DebugString().c_str(), resp->DebugString().c_str()); 37 | } 38 | 39 | void SayHi(HelloRequest *req, HelloReply *resp, RPCContext *ctx) override 40 | { 41 | resp->set_msg("This is SRPC framework TRPC protocol. Hi back."); 42 | 43 | printf("Server SayHi()\nget_req:\n%s\nset_resp:\n%s\n", 44 | req->DebugString().c_str(), resp->DebugString().c_str()); 45 | } 46 | }; 47 | 48 | static void sig_handler(int signo) 49 | { 50 | wait_group.done(); 51 | } 52 | 53 | int main() 54 | { 55 | GOOGLE_PROTOBUF_VERIFY_VERSION; 56 | signal(SIGINT, sig_handler); 57 | signal(SIGTERM, sig_handler); 58 | 59 | TRPCServer server; 60 | GreeterServiceImpl impl; 61 | 62 | server.add_service(&impl); 63 | 64 | if (server.start(1412) == 0) 65 | { 66 | printf("SRPC framework TRPC server is running on 1412\n" 67 | "Try ./trpc_pb_client to send requests.\n\n"); 68 | wait_group.wait(); 69 | server.stop(); 70 | } 71 | else 72 | perror("server start"); 73 | 74 | google::protobuf::ShutdownProtobufLibrary(); 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /tutorial/tutorial-13-trpc_http_server.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2021 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "helloworld.srpc.h" 19 | #include "workflow/WFFacilities.h" 20 | #include "srpc/rpc_types.h" 21 | 22 | using namespace srpc; 23 | using namespace trpc::test::helloworld; 24 | 25 | static WFFacilities::WaitGroup wait_group(1); 26 | 27 | class GreeterServiceImpl : public Greeter::Service 28 | { 29 | public: 30 | void SayHello(HelloRequest *req, HelloReply *resp, RPCContext *ctx) override 31 | { 32 | ctx->set_compress_type(RPCCompressGzip); 33 | resp->set_msg("This is SRPC framework TRPC protocol. Hello back."); 34 | 35 | printf("Server SayHello()\nget_req:\n%s\nset_resp:\n%s\n", 36 | req->DebugString().c_str(), resp->DebugString().c_str()); 37 | } 38 | 39 | void SayHi(HelloRequest *req, HelloReply *resp, RPCContext *ctx) override 40 | { 41 | resp->set_msg("This is SRPC framework TRPC protocol. Hi back."); 42 | 43 | printf("Server SayHi()\nget_req:\n%s\nset_resp:\n%s\n", 44 | req->DebugString().c_str(), resp->DebugString().c_str()); 45 | } 46 | }; 47 | 48 | static void sig_handler(int signo) 49 | { 50 | wait_group.done(); 51 | } 52 | 53 | int main() 54 | { 55 | GOOGLE_PROTOBUF_VERIFY_VERSION; 56 | signal(SIGINT, sig_handler); 57 | signal(SIGTERM, sig_handler); 58 | 59 | TRPCHttpServer server; 60 | GreeterServiceImpl impl; 61 | 62 | server.add_service(&impl); 63 | 64 | if (server.start(1412) == 0) 65 | { 66 | printf("SRPC framework TRPCHttp server is running on 1412\n" 67 | "Try ./trpc_http_client to send requests.\n\n"); 68 | wait_group.wait(); 69 | server.stop(); 70 | } 71 | else 72 | perror("server start"); 73 | 74 | google::protobuf::ShutdownProtobufLibrary(); 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /docs/docs-05-context.md: -------------------------------------------------------------------------------- 1 | [English version](/docs/en/docs-05-context.md) 2 | 3 | ## 05 - RPC Context 4 | - RPCContext专门用来辅助异步接口,Service和Client通用 5 | - 每一个异步接口都会提供Context,用来给用户提供更高级的功能,比如获取对方ip、获取连接seqid等 6 | - Context上一些功能是Server或Client独有的,比如Server可以设置回复数据的压缩方式,Client可以获取请求成功或失败 7 | - Context上可以通过get_series获得所在的series,与workflow的异步模式无缝结合 8 | 9 | ### RPCContext API - Common 10 | #### ``long long get_seqid() const;`` 11 | 请求+回复视为1次完整通信,获得当前socket连接上的通信sequence id,seqid=0代表第1次 12 | 13 | #### ``std::string get_remote_ip() const;`` 14 | 获得对方IP地址,支持ipv4/ipv6 15 | 16 | #### ``int get_peer_addr(struct sockaddr *addr, socklen_t *addrlen) const;`` 17 | 获得对方地址,in/out参数为更底层的数据结构sockaddr 18 | 19 | #### ``const std::string& get_service_name() const;`` 20 | 获取RPC Service Name 21 | 22 | #### ``const std::string& get_method_name() const;`` 23 | 获取RPC Methode Name 24 | 25 | #### ``SeriesWork *get_series() const;`` 26 | 获取当前ServerTask/ClientTask所在series 27 | 28 | ### RPCContext API - Only for client done 29 | #### ``bool success() const;`` 30 | client专用。这次请求是否成功 31 | 32 | #### ``int get_status_code() const;`` 33 | client专用。这次请求的rpc status code 34 | 35 | #### ``const char *get_errmsg() const;`` 36 | client专用。这次请求的错误信息 37 | 38 | #### ``int get_error() const;`` 39 | client专用。这次请求的错误码 40 | 41 | #### ``void *get_user_data() const;`` 42 | client专用。获取ClientTask的user_data。如果用户通过create_xxx_task接口产生task,则可以通过user_data域记录上下文,在创建task时设置,在回调函数中拿回。 43 | 44 | ### RPCContext API - Only for server process 45 | #### ``void set_data_type(RPCDataType type);`` 46 | Server专用。设置数据打包类型 47 | - RPCDataProtobuf 48 | - RPCDataThrift 49 | - RPCDataJson 50 | 51 | #### ``void set_compress_type(RPCCompressType type);`` 52 | Server专用。设置数据压缩类型(注:Client的压缩类型在Client或Task上设置) 53 | - RPCCompressNone 54 | - RPCCompressSnappy 55 | - RPCCompressGzip 56 | - RPCCompressZlib 57 | - RPCCompressLz4 58 | 59 | #### ``void set_attachment_nocopy(const char *attachment, size_t len);`` 60 | Server专用。设置attachment附件。 61 | 62 | #### ``bool get_attachment(const char **attachment, size_t *len) const;`` 63 | Server专用。获取attachment附件。 64 | 65 | #### ``void set_reply_callback(std::function cb);`` 66 | Server专用。设置reply callback,操作系统写入socket缓冲区成功后被调用。 67 | 68 | #### ``void set_send_timeout(int timeout);`` 69 | Server专用。设置发送超时,单位毫秒。-1代表无限。 70 | 71 | #### ``void set_keep_alive(int timeout);`` 72 | Server专用。设置连接保活时间,单位毫秒。-1代表无限。 73 | 74 | -------------------------------------------------------------------------------- /src/rpc_options.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_OPTIONS_H__ 18 | #define __RPC_OPTIONS_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "rpc_basic.h" 25 | 26 | namespace srpc { 27 | 28 | struct RPCTaskParams 29 | { 30 | int send_timeout; 31 | int receive_timeout; 32 | int watch_timeout; 33 | int keep_alive_timeout; 34 | int retry_max; 35 | int compress_type; //RPCCompressType 36 | int data_type; //RPCDataType 37 | }; 38 | 39 | struct RPCClientParams 40 | { 41 | RPCTaskParams task_params; 42 | enum TransportType transport_type; 43 | //host + port + is_ssl 44 | std::string host; 45 | unsigned short port; 46 | bool is_ssl; 47 | //or URL 48 | std::string url; 49 | int callee_timeout; 50 | std::string caller; 51 | }; 52 | 53 | struct RPCServerParams : public WFServerParams 54 | { 55 | RPCServerParams() : WFServerParams(SERVER_PARAMS_DEFAULT) 56 | { 57 | this->request_size_limit = RPC_BODY_SIZE_LIMIT; 58 | } 59 | }; 60 | 61 | static constexpr struct RPCTaskParams RPC_TASK_PARAMS_DEFAULT = 62 | { 63 | /* .send_timeout = */ -1, 64 | /* .receive_timeout = */ -1, 65 | /* .watch_timeout = */ 0, 66 | /* .keep_alive_timeout = */ 30 * 1000, 67 | /* .retry_max = */ 0, 68 | /* .compress_type = */ RPCCompressNone, 69 | /* .data_type = */ RPCDataUndefined 70 | }; 71 | 72 | static const struct RPCClientParams RPC_CLIENT_PARAMS_DEFAULT = 73 | { 74 | /* .task_params = */ RPC_TASK_PARAMS_DEFAULT, 75 | /* .transport_type = */ TT_TCP, 76 | /* .host = */ "", 77 | /* .port = */ SRPC_DEFAULT_PORT, 78 | /* .is_ssl = */ false, 79 | /* .url = */ "", 80 | /* .callee_timeout = */ -1, 81 | /* .caller = */ "" 82 | }; 83 | 84 | static const RPCServerParams RPC_SERVER_PARAMS_DEFAULT; 85 | 86 | } // end namespace 87 | 88 | #endif 89 | 90 | -------------------------------------------------------------------------------- /tools/templates/basic/compute_server_main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "workflow/WFHttpServer.h" 5 | #include "workflow/WFFacilities.h" 6 | #include "config/config.h" 7 | 8 | static WFFacilities::WaitGroup wait_group(1); 9 | static srpc::RPCConfig config; 10 | 11 | void sig_handler(int signo) 12 | { 13 | wait_group.done(); 14 | } 15 | 16 | void init() 17 | { 18 | if (config.load("./server.conf") == false) 19 | { 20 | perror("Load config failed"); 21 | exit(1); 22 | } 23 | 24 | signal(SIGINT, sig_handler); 25 | signal(SIGTERM, sig_handler); 26 | } 27 | 28 | // Example for Fibonacci. 29 | void Fibonacci(int n, protocol::HttpResponse *resp) 30 | { 31 | unsigned long long x = 0, y = 1; 32 | char buf[256]; 33 | int i; 34 | 35 | if (n <= 0 || n > 94) 36 | { 37 | resp->append_output_body_nocopy("Invalid Number.", 38 | strlen("Invalid Number.")); 39 | return; 40 | } 41 | 42 | resp->append_output_body_nocopy("", strlen("")); 43 | for (i = 2; i < n; i++) 44 | { 45 | sprintf(buf, "

%llu + %llu = %llu.

", x, y, x + y); 46 | resp->append_output_body(buf); 47 | y = x + y; 48 | x = y - x; 49 | } 50 | 51 | if (n == 1) 52 | y = 0; 53 | sprintf(buf, "

The No. %d Fibonacci number is: %llu.

", n, y); 54 | resp->append_output_body(buf); 55 | resp->append_output_body_nocopy("", strlen("")); 56 | } 57 | 58 | void process(WFHttpTask *task) 59 | { 60 | const char *uri = task->get_req()->get_request_uri(); 61 | if (*uri == '/') 62 | uri++; 63 | 64 | int n = atoi(uri); 65 | protocol::HttpResponse *resp = task->get_resp(); 66 | fprintf(stderr, "server get request. n = %d\n", n); 67 | 68 | // All calculations can be encapsulated by 'go_task' 69 | WFGoTask *go_task = WFTaskFactory::create_go_task("go", Fibonacci, n, resp); 70 | 71 | // Tasks will be dispatch asynchonously after 'push_back()' 72 | series_of(task)->push_back(go_task); 73 | } 74 | 75 | int main() 76 | { 77 | init(); 78 | 79 | WFHttpServer server(process); 80 | 81 | if (server.start(config.server_port()) == 0) 82 | { 83 | fprintf(stderr, "Computing server started, port %u\n", config.server_port()); 84 | wait_group.wait(); 85 | server.stop(); 86 | } 87 | else 88 | perror("server start"); 89 | 90 | return 0; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /tutorial/tutorial-15-srpc_pb_proxy.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "echo_pb.srpc.h" 19 | #include "workflow/WFFacilities.h" 20 | #include "srpc/rpc_types.h" 21 | 22 | using namespace srpc; 23 | 24 | static WFFacilities::WaitGroup wait_group(1); 25 | 26 | template 27 | class ExampleProxyServiceImpl : public Example::Service 28 | { 29 | public: 30 | ExampleProxyServiceImpl(CLIENT *client) 31 | { 32 | this->client = client; 33 | } 34 | 35 | private: 36 | CLIENT *client; 37 | 38 | public: 39 | void Echo(EchoRequest *request, EchoResponse *response, RPCContext *context) override 40 | { 41 | printf("Proxy Server Echo() get and transfer request:\n%s\n", 42 | request->DebugString().c_str()); 43 | 44 | auto *task = this->client->create_Echo_task([response](EchoResponse *resp, 45 | RPCContext *ctx) { 46 | printf("Proxy Server Echo() get and transfer response:\n%s\n", 47 | resp->DebugString().c_str()); 48 | if (ctx->success()) 49 | *response = std::move(*resp); 50 | }); 51 | task->serialize_input(request); 52 | context->get_series()->push_back(task); 53 | } 54 | }; 55 | 56 | static void sig_handler(int signo) 57 | { 58 | wait_group.done(); 59 | } 60 | 61 | int main() 62 | { 63 | GOOGLE_PROTOBUF_VERIFY_VERSION; 64 | signal(SIGINT, sig_handler); 65 | signal(SIGTERM, sig_handler); 66 | 67 | SRPCServer server; 68 | Example::SRPCClient client("127.0.0.1", 1412); 69 | ExampleProxyServiceImpl impl(&client); 70 | 71 | server.add_service(&impl); 72 | 73 | if (server.start(61412) == 0) 74 | { 75 | printf("Proxy server serving on 61412 and redirect to backend server 127.0.0.1:1412\n" 76 | "Try start ./srpc_pb_server as backend and send requests to 61412.\n\n"); 77 | wait_group.wait(); 78 | server.stop(); 79 | } 80 | else 81 | perror("server start"); 82 | 83 | google::protobuf::ShutdownProtobufLibrary(); 84 | return 0; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | 11 | ubuntu-cmake: 12 | name: ubuntu 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@master 17 | - name: install deps 18 | run: | 19 | sudo apt-get update 20 | sudo apt-get install -y libprotobuf-dev protobuf-compiler libgtest-dev valgrind 21 | - name: update submodules 22 | run: git submodule update --init --recursive 23 | - name: make 24 | run: make -j4 25 | - name: make tutorial 26 | run: make tutorial -j4 27 | - name: make check 28 | run: make check -j4 29 | - name: make install 30 | run: sudo make install 31 | 32 | fedora-cmake: 33 | name: fedora 34 | runs-on: ubuntu-latest 35 | 36 | steps: 37 | - name: Setup Podman 38 | run: | 39 | sudo apt update 40 | sudo apt-get -y install podman 41 | podman pull fedora:rawhide 42 | - name: Get source 43 | uses: actions/checkout@master 44 | with: 45 | path: 'workflow' 46 | - name: Create container and run tests 47 | run: | 48 | { 49 | echo 'FROM fedora:rawhide' 50 | echo 'RUN dnf -y update' 51 | echo 'RUN dnf -y install cmake gcc-c++ gtest-devel git make' 52 | echo 'RUN dnf -y install openssl-devel protobuf-devel' 53 | echo 'RUN dnf -y install lz4-devel snappy-devel' 54 | echo 'RUN dnf clean all' 55 | echo 'COPY workflow workflow' 56 | echo 'WORKDIR /workflow' 57 | echo 'RUN git submodule update --init --recursive' 58 | echo 'RUN cmake' 59 | echo 'RUN make' 60 | echo 'RUN make check' 61 | echo 'RUN make tutorial' 62 | } > podmanfile 63 | podman build --tag fedorarawhide -f ./podmanfile 64 | 65 | ubuntu-bazel: 66 | name: bazel 67 | runs-on: ubuntu-latest 68 | 69 | steps: 70 | - uses: actions/checkout@master 71 | - name: Install Bazel 5.4.0 72 | run: | 73 | sudo apt-get update 74 | sudo apt-get install -y apt-transport-https curl gnupg 75 | curl -LO "https://releases.bazel.build/5.4.0/release/bazel-5.4.0-linux-x86_64" 76 | chmod +x bazel-5.4.0-linux-x86_64 77 | sudo mv bazel-5.4.0-linux-x86_64 /usr/local/bin/bazel 78 | - name: bazel build 79 | run: bazel build ... 80 | 81 | -------------------------------------------------------------------------------- /tutorial/tutorial-10-server_async.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include "echo_pb.srpc.h" 20 | #include "workflow/WFFacilities.h" 21 | 22 | using namespace srpc; 23 | 24 | static WFFacilities::WaitGroup wait_group(1); 25 | 26 | class ExampleServiceImpl : public Example::Service 27 | { 28 | public: 29 | void Echo(EchoRequest *req, EchoResponse *resp, RPCContext *ctx) override 30 | { 31 | ctx->set_compress_type(RPCCompressGzip); 32 | ctx->log({{"event", "info"}, {"message", "rpc server echo() end."}}); 33 | 34 | auto *task = WFTaskFactory::create_http_task("https://www.sogou.com", 35 | 0, 0, 36 | [req, resp](WFHttpTask *task) 37 | { 38 | if (task->get_state() == WFT_STATE_SUCCESS) 39 | { 40 | const void *data; 41 | size_t len; 42 | task->get_resp()->get_parsed_body(&data, &len); 43 | resp->mutable_message()->assign((const char *)data, len); 44 | } 45 | else 46 | resp->set_message("Error: " + std::to_string(task->get_error())); 47 | 48 | printf("Server Echo()\nget_req:\n%s\nset_resp:\n%s\n", 49 | req->DebugString().c_str(), resp->DebugString().c_str()); 50 | }); 51 | 52 | ctx->get_series()->push_back(task); 53 | } 54 | }; 55 | 56 | static void sig_handler(int signo) 57 | { 58 | wait_group.done(); 59 | } 60 | 61 | int main(int argc, char *argv[]) 62 | { 63 | GOOGLE_PROTOBUF_VERIFY_VERSION; 64 | signal(SIGINT, sig_handler); 65 | signal(SIGTERM, sig_handler); 66 | 67 | SRPCServer server; 68 | ExampleServiceImpl impl; 69 | 70 | server.add_service(&impl); 71 | 72 | if (server.start(1412) == 0) 73 | { 74 | printf("Asynchronous server with HTTP requests is running on 1412\n" 75 | "Try ./client_task or ./srpc_pb_client to trigger this example.\n\n"); 76 | wait_group.wait(); 77 | server.stop(); 78 | } 79 | else 80 | perror("server start"); 81 | 82 | google::protobuf::ShutdownProtobufLibrary(); 83 | return 0; 84 | } 85 | 86 | -------------------------------------------------------------------------------- /tools/templates/proxy/proxy_main_proto.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "workflow/WFFacilities.h" 5 | #include "srpc/rpc_types.h" 6 | 7 | #include "config/config.h" 8 | #include "%s.srpc.h" 9 | 10 | using namespace srpc; 11 | 12 | static srpc::RPCConfig config; 13 | static WFFacilities::WaitGroup wait_group(1); 14 | 15 | static void sig_handler(int signo) 16 | { 17 | wait_group.done(); 18 | } 19 | 20 | static void init() 21 | { 22 | if (config.load("./proxy.conf") == false) 23 | { 24 | perror("Load config failed"); 25 | exit(1); 26 | } 27 | 28 | signal(SIGINT, sig_handler); 29 | signal(SIGTERM, sig_handler); 30 | } 31 | 32 | class ProxyServiceImpl : public %s::Service 33 | { 34 | public: 35 | void Echo(EchoRequest *request, EchoResponse *response, 36 | RPCContext *context) override 37 | { 38 | fprintf(stderr, "%s proxy get request from client. ip : %%s\n%%s\n", 39 | context->get_remote_ip().c_str(), request->DebugString().c_str()); 40 | 41 | // 5. process() : get request from client and send to remote server 42 | auto *task = this->client.create_Echo_task([response](EchoResponse *resp, 43 | RPCContext *ctx) { 44 | // 6. callback() : fill remote server response to client 45 | if (ctx->success()) 46 | *response = std::move(*resp); 47 | }); 48 | task->serialize_input(request); 49 | context->get_series()->push_back(task); 50 | } 51 | 52 | public: 53 | ProxyServiceImpl(RPCClientParams *params) : 54 | client(params) 55 | { 56 | } 57 | 58 | private: 59 | %s::%sClient client; 60 | }; 61 | 62 | int main() 63 | { 64 | // 1. load config 65 | init(); 66 | 67 | // 2. make client for remote server 68 | RPCClientParams client_params = RPC_CLIENT_PARAMS_DEFAULT; 69 | client_params.host = config.client_host(); 70 | client_params.port = config.client_port(); 71 | 72 | // 3. start proxy server 73 | %sServer server; 74 | ProxyServiceImpl impl(&client_params); 75 | server.add_service(&impl); 76 | config.load_filter(server); 77 | 78 | if (server.start(config.server_port()) == 0) 79 | { 80 | // 4. main thread success and wait 81 | fprintf(stderr, "%s [%s]-[%s] proxy started, port %%u\n", 82 | config.server_port()); 83 | wait_group.wait(); 84 | server.stop(); 85 | } 86 | else 87 | perror("server start"); 88 | 89 | return 0; 90 | } 91 | 92 | -------------------------------------------------------------------------------- /tutorial/tutorial-08-thrift_thrift_client.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "echo_thrift.srpc.h" 19 | 20 | using namespace srpc; 21 | 22 | int main() 23 | { 24 | Example::ThriftClient client("127.0.0.1", 1412); 25 | 26 | //sync 27 | EchoResult sync_res; 28 | 29 | client.Echo(sync_res, "Hello, srpc!", "1412"); 30 | if (client.thrift_last_sync_success()) 31 | printf("%s\n", sync_res.message.c_str()); 32 | else 33 | { 34 | const auto& sync_ctx = client.thrift_last_sync_ctx(); 35 | 36 | printf("status[%d] error[%d] errmsg:%s\n", 37 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 38 | } 39 | 40 | //send/recv 41 | client.send_Echo("Hello, srpc!", "1412"); 42 | //do anything you want 43 | client.recv_Echo(sync_res); 44 | 45 | if (client.thrift_last_sync_success()) 46 | printf("%s\n", sync_res.message.c_str()); 47 | else 48 | { 49 | const auto& sync_ctx = client.thrift_last_sync_ctx(); 50 | 51 | printf("status[%d] error[%d] errmsg:%s\n", 52 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 53 | } 54 | 55 | //async 56 | Example::EchoRequest req; 57 | req.message = "Hello, srpc!"; 58 | req.name = "1412"; 59 | 60 | client.Echo(&req, [](Example::EchoResponse *resp, RPCContext *ctx) { 61 | if (ctx->success()) 62 | printf("%s\n", resp->result.message.c_str()); 63 | else 64 | printf("status[%d] error[%d] errmsg:%s\n", 65 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 66 | }); 67 | 68 | //sync 69 | Example::EchoRequest sync_req; 70 | Example::EchoResponse sync_resp; 71 | RPCSyncContext sync_ctx; 72 | 73 | sync_req.message = "Hello, srpc!"; 74 | sync_req.name = "Sync"; 75 | client.Echo(&sync_req, &sync_resp, &sync_ctx); 76 | 77 | if (sync_ctx.success) 78 | printf("%s\n", sync_resp.result.message.c_str()); 79 | else 80 | printf("status[%d] error[%d] errmsg:%s\n", 81 | sync_ctx.status_code, sync_ctx.error, sync_ctx.errmsg.c_str()); 82 | 83 | return 0; 84 | } 85 | 86 | -------------------------------------------------------------------------------- /docs/en/docs-04-client.md: -------------------------------------------------------------------------------- 1 | [中文版](/docs/docs-04-client.md) 2 | 3 | ## 04 - RPC Client 4 | 5 | - Each Client corresponds to one specific target/one specific cluster 6 | - Each Client corresponds to one specific network communication protocol 7 | - Each Client corresponds to one specific IDL 8 | 9 | ### Sample 10 | 11 | You can follow the detailed example below: 12 | 13 | - Following the above example, the client is relatively simple and you can call the method directly. 14 | - Use `Example::XXXClient` to create a client instance of some RPC. The IP+port or URL of the target is required. 15 | - With the client instance, directly call the rpc function `Echo`. This is an asynchronous request, and the callback function will be invoked after the request is completed. 16 | - For the usage of the RPC Context, please check [RPC Context](/docs/en/rpc.md#rpc-context). 17 | 18 | ~~~cpp 19 | #include 20 | #include "example.srpc.h" 21 | #include "workflow/WFFacilities.h" 22 | 23 | using namespace srpc; 24 | 25 | int main() 26 | { 27 | Example::SRPCClient client("127.0.0.1", 1412); 28 | EchoRequest req; 29 | req.set_message("Hello!"); 30 | req.set_name("SRPCClient"); 31 | 32 | WFFacilities::WaitGroup wait_group(1); 33 | 34 | client.Echo(&req, [&wait_group](EchoResponse *response, RPCContext *ctx) { 35 | if (ctx->success()) 36 | printf("%s\n", response->DebugString().c_str()); 37 | else 38 | printf("status[%d] error[%d] errmsg:%s\n", 39 | ctx->get_status_code(), ctx->get_error(), ctx->get_errmsg()); 40 | wait_group.done(); 41 | }); 42 | 43 | wait_group.wait(); 44 | return 0; 45 | } 46 | ~~~ 47 | 48 | ### Client startup parameters 49 | 50 | Client can be started directly by passing in ip, port, or through client startup parameters. 51 | 52 | The above example: 53 | 54 | ~~~cpp 55 | Example::SRPCClient client("127.0.0.1", 1412); 56 | ~~~ 57 | 58 | is equivalent to: 59 | 60 | ~~~cpp 61 | struct RPCClientParams param = RPC_CLIENT_PARAMS_DEFAULT; 62 | param.host = "127.0.0.1"; 63 | param.port = 1412; 64 | Example::SRPCClient client(¶m); 65 | ~~~ 66 | 67 | also equivalent to: 68 | 69 | ~~~cpp 70 | struct RPCClientParams param = RPC_CLIENT_PARAMS_DEFAULT; 71 | param.url = "srpc://127.0.0.1:1412"; 72 | Example::SRPCClient client(¶m); 73 | ~~~ 74 | 75 | Note that `RPC_CLIENT_PARAMS_DEFAULT` must be used to initialize the client's parameters, which contains a `RPCTaskParams`, including the default data_type, compress_type, retry_max and various timeouts. The specific struct can refer to [rpc_options.h](/src/rpc_options.h). 76 | 77 | -------------------------------------------------------------------------------- /tools/templates/proxy/proxy_main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "workflow/WFTaskFactory.h" 4 | #include "workflow/WF%sServer.h" 5 | #include "workflow/WFFacilities.h" 6 | 7 | #include "config/config.h" 8 | #include "config/util.h" 9 | 10 | static WFFacilities::WaitGroup wait_group(1); 11 | static srpc::RPCConfig config; 12 | 13 | void sig_handler(int signo) 14 | { 15 | wait_group.done(); 16 | } 17 | 18 | void init() 19 | { 20 | if (config.load("./proxy.conf") == false) 21 | { 22 | perror("Load config failed"); 23 | exit(1); 24 | } 25 | 26 | signal(SIGINT, sig_handler); 27 | signal(SIGTERM, sig_handler); 28 | } 29 | 30 | void callback(WF%sTask *client_task) 31 | { 32 | int state = client_task->get_state(); 33 | int error = client_task->get_error(); 34 | SeriesWork *series = series_of(client_task); 35 | protocol::%sResponse *resp = client_task->get_resp(); 36 | protocol::%sResponse *proxy_resp = (protocol::%sResponse *)series->get_context(); 37 | 38 | // Copy the remote server's response, to proxy response. 39 | if (state == WFT_STATE_SUCCESS)%s 40 | fprintf(stderr, "backend server state = %%d error = %%d. response client.\n", 41 | state, error); 42 | } 43 | 44 | void process(WF%sTask *server_task) 45 | { 46 | protocol::%sRequest *req = server_task->get_req(); 47 | std::string backend_server = config.client_host(); 48 | unsigned short backend_server_port = config.client_port(); 49 | std::string url = std::string("%s://") + backend_server + 50 | std::string(":") + std::to_string(backend_server_port); 51 | 52 | WF%sTask *client_task = WFTaskFactory::create_%s_task(url,%s 53 | config.retry_max(), 54 | callback); 55 | 56 | // Copy user's request to the new task's request using std::move() 57 | %s 58 | SeriesWork *series = series_of(server_task); 59 | series->set_context(server_task->get_resp()); 60 | series->push_back(client_task); 61 | 62 | fprintf(stderr, "proxy get request from client: "); 63 | print_peer_address(server_task); 64 | } 65 | 66 | int main() 67 | { 68 | init(); 69 | 70 | WF%sServer proxy_server(process); 71 | 72 | if (proxy_server.start(config.server_port()) == 0) 73 | { 74 | fprintf(stderr, "[%s]-[%s] proxy started, port %%u\n", config.server_port()); 75 | wait_group.wait(); 76 | proxy_server.stop(); 77 | } 78 | else 79 | perror("server start"); 80 | 81 | return 0; 82 | } 83 | 84 | -------------------------------------------------------------------------------- /src/generator/generator.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_GENERATOR_H__ 18 | #define __RPC_GENERATOR_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "printer.h" 30 | #include "parser.h" 31 | 32 | struct GeneratorParams 33 | { 34 | const char *out_dir; 35 | bool generate_skeleton; 36 | std::string idl_file; 37 | std::string input_dir; 38 | 39 | GeneratorParams() : out_dir(NULL), generate_skeleton(true) { } 40 | }; 41 | 42 | class Generator 43 | { 44 | public: 45 | Generator(bool is_thrift): 46 | parser(is_thrift), 47 | printer(is_thrift) 48 | { 49 | this->suffix = ".srpc."; 50 | this->thrift_suffix = ".thrift."; 51 | this->skeleton_suffix = ".skeleton."; 52 | this->is_thrift = is_thrift; 53 | } 54 | 55 | bool generate(struct GeneratorParams& params); 56 | 57 | protected: 58 | virtual bool generate_server_cpp_file(const idl_info& cur_info, 59 | const std::string& idle_file_name); 60 | virtual bool generate_client_cpp_file(const idl_info& cur_info, 61 | const std::string& idle_file_name); 62 | 63 | std::string server_cpp_file; 64 | std::string client_cpp_file; 65 | 66 | private: 67 | bool generate_header(idl_info& cur_info, struct GeneratorParams& params); 68 | void generate_skeleton(const std::string& idl_file); 69 | 70 | bool generate_srpc_file(const idl_info& cur_info); 71 | bool generate_thrift_type_file(idl_info& cur_info); 72 | void thrift_replace_include(const idl_info& cur_info, 73 | std::vector& params); 74 | 75 | bool init_file_names(const std::string& idl_file, const char *out_dir); 76 | 77 | Parser parser; 78 | Printer printer; 79 | idl_info info; 80 | std::string out_dir; 81 | std::string suffix; 82 | std::string thrift_suffix; 83 | std::string skeleton_suffix; 84 | std::string prefix; 85 | std::string srpc_file; 86 | std::string thrift_type_file; 87 | bool is_thrift; 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /tools/templates/common/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "server": 3 | { 4 | "port": 8080 5 | }, 6 | 7 | "client": 8 | { 9 | "transport_type": "TT_TCP", 10 | "remote_host": "127.0.0.1", 11 | "remote_port": 8080, 12 | "is_ssl" : false, 13 | "retry_max": 1, 14 | "user_name": "root", 15 | "password": "", 16 | "callee" : "rpc_client" 17 | }, 18 | 19 | "global": 20 | { 21 | "poller_threads": 4, 22 | "handler_threads": 20, 23 | "dns_threads": 4, 24 | "compute_threads": -1, 25 | "dns_ttl_default": 43200, 26 | "dns_ttl_min": 180, 27 | "resolv_conf_path": "/etc/resolv.conf", 28 | "hosts_path": "/etc/hosts", 29 | "endpoint_params": 30 | { 31 | "max_connections": 200, 32 | "connect_timeout": 10000, 33 | "response_timeout": 10000, 34 | "ssl_connect_timeout": 10000, 35 | "use_tls_sni": false 36 | }, 37 | "dns_server_params": 38 | { 39 | "max_connections": 200 40 | } 41 | }, 42 | 43 | "metrics":[ 44 | { 45 | "filter": "prometheus", 46 | "port": 8000 47 | }, 48 | { 49 | "filter": "opentelemetry", 50 | "filter_name": "otel_reporter1", 51 | "address": "http://opentelemetry.com:4389", 52 | "redirect_max": 0, 53 | "retry_max": 1, 54 | "report_threshold": 100, 55 | "report_interval_ms": 1000, 56 | "attributes": [ 57 | { 58 | "key": "tenant.id", 59 | "value": "abcd" 60 | } 61 | ] 62 | } 63 | ], 64 | 65 | "trace":[ 66 | { 67 | "filter": "default", 68 | "span_per_second": 1000 69 | }, 70 | { 71 | "filter": "opentelemetry", 72 | "address": "http://opentelemetry.com:4389", 73 | "redirect_max": 0, 74 | "retry_max": 1, 75 | "span_per_second": 1000, 76 | "report_threshold": 100, 77 | "report_interval_ms": 1000, 78 | "attributes": [ 79 | { 80 | "key": "tenant.id", 81 | "value": "abcd" 82 | } 83 | ] 84 | } 85 | ], 86 | 87 | "upstream":[ 88 | { 89 | "name": "test_weighted_random_host", 90 | "type": "weighted_random", 91 | "try_another": false, 92 | "server":[ 93 | { "host": "127.0.0.1:8080", "params": {"weight": 2} }, 94 | { "host": "127.0.0.1:8081" } 95 | ] 96 | }, 97 | 98 | { 99 | "name": "test_consistent_hash_host", 100 | "type": "consistent_hash", 101 | "server":[ 102 | { "host": "127.0.0.1:8083" }, 103 | { "host": "127.0.0.1:8084" } 104 | ] 105 | } 106 | ] 107 | } 108 | 109 | -------------------------------------------------------------------------------- /src/module/rpc_metrics_module.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_METRICS_MODULE_H__ 18 | #define __RPC_METRICS_MODULE_H__ 19 | 20 | #include "rpc_basic.h" 21 | #include "rpc_context.h" 22 | #include "rpc_module.h" 23 | 24 | namespace srpc 25 | { 26 | 27 | // Basic MetricsModlue for generating general metrics data. 28 | // Each kind of network task can derived its own MetricsModlue. 29 | 30 | class MetricsModule : public RPCModule 31 | { 32 | public: 33 | bool client_begin(SubTask *task, RPCModuleData& data) override; 34 | bool client_end(SubTask *task, RPCModuleData& data) override; 35 | bool server_begin(SubTask *task, RPCModuleData& data) override; 36 | bool server_end(SubTask *task, RPCModuleData& data) override; 37 | 38 | public: 39 | MetricsModule() : RPCModule(RPCModuleTypeMetrics) { } 40 | }; 41 | 42 | // Fill RPC related data in metrics module 43 | 44 | template 45 | class RPCMetricsModule : public MetricsModule 46 | { 47 | public: 48 | bool client_begin(SubTask *task, RPCModuleData& data) override; 49 | bool server_begin(SubTask *task, RPCModuleData& data) override; 50 | }; 51 | 52 | ////////// impl 53 | 54 | template 55 | bool RPCMetricsModule::client_begin(SubTask *task, 56 | RPCModuleData& data) 57 | { 58 | MetricsModule::client_begin(task, data); 59 | 60 | auto *client_task = static_cast(task); 61 | auto *req = client_task->get_req(); 62 | 63 | data[OTLP_SERVICE_NAME] = req->get_service_name(); 64 | data[OTLP_METHOD_NAME] = req->get_method_name(); 65 | 66 | return true; 67 | } 68 | 69 | template 70 | bool RPCMetricsModule::server_begin(SubTask *task, 71 | RPCModuleData& data) 72 | { 73 | MetricsModule::server_begin(task, data); 74 | 75 | auto *server_task = static_cast(task); 76 | auto *req = server_task->get_req(); 77 | 78 | data[OTLP_SERVICE_NAME] = req->get_service_name(); 79 | data[OTLP_METHOD_NAME] = req->get_method_name(); 80 | 81 | return true; 82 | } 83 | 84 | } // end namespace srpc 85 | 86 | #endif 87 | 88 | -------------------------------------------------------------------------------- /src/compress/rpc_compress.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include "rpc_compress.h" 18 | #include "rpc_compress_gzip.h" 19 | #include "rpc_compress_snappy.h" 20 | #include "rpc_compress_lz4.h" 21 | 22 | namespace srpc 23 | { 24 | 25 | int RPCCompressor::add(RPCCompressType type) 26 | { 27 | if (type >= RPCCompressMax || type <= RPCCompressNone) 28 | return -2; 29 | 30 | int ret = 0; 31 | 32 | if (this->handler[type].compress 33 | && this->handler[type].decompress 34 | && this->handler[type].lease_size) 35 | { 36 | ret = 1; 37 | } 38 | 39 | //this->handler[type].type = type; 40 | 41 | switch (type) 42 | { 43 | case RPCCompressSnappy: 44 | this->handler[type].compress = SnappyManager::SnappyCompress; 45 | this->handler[type].decompress = SnappyManager::SnappyDecompress; 46 | this->handler[type].compress_iovec = SnappyManager::SnappyCompressIOVec; 47 | this->handler[type].decompress_iovec = SnappyManager::SnappyDecompressIOVec; 48 | this->handler[type].lease_size = SnappyManager::SnappyLeaseSize; 49 | break; 50 | case RPCCompressGzip: 51 | this->handler[type].compress = GzipCompress; 52 | this->handler[type].decompress = GzipDecompress; 53 | this->handler[type].compress_iovec = GzipCompressIOVec; 54 | this->handler[type].decompress_iovec = GzipDecompressIOVec; 55 | this->handler[type].lease_size = GzipLeaseSize; 56 | break; 57 | case RPCCompressZlib: 58 | this->handler[type].compress = ZlibCompress; 59 | this->handler[type].decompress = ZlibDecompress; 60 | this->handler[type].compress_iovec = ZlibCompressIOVec; 61 | this->handler[type].decompress_iovec = ZlibDecompressIOVec; 62 | this->handler[type].lease_size = ZlibLeaseSize; 63 | break; 64 | case RPCCompressLz4: 65 | this->handler[type].compress = LZ4Compress; 66 | this->handler[type].decompress = LZ4Decompress; 67 | this->handler[type].compress_iovec = LZ4CompressIOVec; 68 | this->handler[type].decompress_iovec = LZ4DecompressIOVec; 69 | this->handler[type].lease_size = LZ4LeaseSize; 70 | break; 71 | default: 72 | ret = -2; 73 | break; 74 | } 75 | 76 | return ret; 77 | } 78 | 79 | } // namespace srpc 80 | 81 | -------------------------------------------------------------------------------- /src/rpc_service.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_SERVICE_H__ 18 | #define __RPC_SERVICE_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "rpc_context.h" 24 | #include "rpc_options.h" 25 | 26 | namespace srpc 27 | { 28 | 29 | class RPCService 30 | { 31 | protected: 32 | using rpc_method_t = std::function; 33 | 34 | public: 35 | RPCService(const std::string& name) : name_(name) { } 36 | RPCService(RPCService&& move) = delete; 37 | RPCService& operator=(RPCService&& move) = delete; 38 | RPCService(const RPCService& copy) = delete; 39 | RPCService& operator=(const RPCService& copy) = delete; 40 | virtual ~RPCService() { }; 41 | 42 | const std::string& get_name() const { return name_; } 43 | const rpc_method_t *find_method(const std::string& method_name) const; 44 | 45 | protected: 46 | void add_method(const std::string& method_name, rpc_method_t&& method); 47 | 48 | private: 49 | std::unordered_map methods_; 50 | std::string name_; 51 | }; 52 | 53 | //////// 54 | // inl 55 | 56 | template 57 | static inline int 58 | ServiceRPCCallImpl(SERVICE *service, 59 | RPCWorker& worker, 60 | void (SERVICE::*rpc)(INPUT *, OUTPUT *, RPCContext *)) 61 | { 62 | auto *in = new INPUT; 63 | 64 | worker.set_server_input(in); 65 | int status_code = worker.req->deserialize(in); 66 | 67 | if (status_code == RPCStatusOK) 68 | { 69 | auto *out = new OUTPUT; 70 | 71 | worker.set_server_output(out); 72 | (service->*rpc)(in, out, worker.ctx); 73 | } 74 | 75 | return status_code; 76 | } 77 | 78 | inline void RPCService::add_method(const std::string& method_name, rpc_method_t&& method) 79 | { 80 | methods_.emplace(method_name, std::move(method)); 81 | } 82 | 83 | inline const RPCService::rpc_method_t *RPCService::find_method(const std::string& method_name) const 84 | { 85 | const auto it = methods_.find(method_name); 86 | 87 | if (it != methods_.cend()) 88 | return &it->second; 89 | 90 | return NULL; 91 | } 92 | 93 | } // namespace srpc 94 | 95 | #endif 96 | 97 | -------------------------------------------------------------------------------- /test/var_unittest.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "srpc/rpc_var.h" 28 | 29 | using namespace srpc; 30 | 31 | RPCVar *get_and_reduce(std::string&& var_name) 32 | { 33 | RPCVar *result = NULL; 34 | RPCVarGlobal *global_var = RPCVarGlobal::get_instance(); 35 | std::unordered_map::iterator it; 36 | 37 | global_var->mutex.lock(); 38 | for (RPCVarLocal *local : global_var->local_vars) 39 | { 40 | local->mutex.lock(); 41 | it = local->vars.find(var_name); 42 | if (it != local->vars.end()) 43 | { 44 | if (result == NULL) 45 | result = it->second->create(true); 46 | else 47 | result->reduce(it->second->get_data(), it->second->get_size()); 48 | } 49 | local->mutex.unlock(); 50 | } 51 | global_var->mutex.unlock(); 52 | 53 | return result; 54 | } 55 | 56 | TEST(var_unittest, GaugeVar) 57 | { 58 | GaugeVar *req = new GaugeVar("req", "total req"); 59 | RPCVarLocal::get_instance()->add("req", req); 60 | 61 | RPCVarFactory::gauge("req")->increase(); 62 | 63 | GaugeVar *gauge = (GaugeVar *)get_and_reduce("req"); 64 | EXPECT_EQ(gauge->get(), 1.0); 65 | delete gauge; 66 | } 67 | 68 | TEST(var_unittest, TimedGaugeVar) 69 | { 70 | TimedGaugeVar *qps = new TimedGaugeVar("qps", "req per second", 71 | std::chrono::seconds(1), 4); 72 | RPCVarLocal::get_instance()->add("qps", qps); 73 | 74 | RPCVarFactory::gauge("qps")->increase(); 75 | RPCVarFactory::gauge("qps")->increase(); 76 | 77 | GaugeVar *gauge = (GaugeVar *)get_and_reduce("qps"); 78 | EXPECT_EQ(gauge->get(), 2.0); 79 | delete gauge; 80 | 81 | usleep(500000); 82 | RPCVarFactory::gauge("qps")->increase(); 83 | gauge = (GaugeVar *)get_and_reduce("qps"); 84 | EXPECT_EQ(gauge->get(), 3.0); 85 | delete gauge; 86 | 87 | usleep(500000); 88 | gauge = (GaugeVar *)get_and_reduce("qps"); 89 | EXPECT_EQ(gauge->get(), 1.0); 90 | delete gauge; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /tutorial/tutorial-16-server_with_metrics.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "echo_pb.srpc.h" 19 | #include "workflow/WFFacilities.h" 20 | #include "srpc/rpc_types.h" 21 | #include "srpc/rpc_metrics_filter.h" 22 | 23 | using namespace srpc; 24 | 25 | static WFFacilities::WaitGroup wait_group(1); 26 | 27 | class ExampleServiceImpl : public Example::Service 28 | { 29 | public: 30 | void Echo(EchoRequest *req, EchoResponse *resp, RPCContext *ctx) override 31 | { 32 | resp->set_message("Hi back"); 33 | 34 | printf("Server Echo()\nget_req:\n%s\nset_resp:\n%s\n", 35 | req->DebugString().c_str(), resp->DebugString().c_str()); 36 | 37 | this->filter->histogram("echo_request_size")->observe(req->ByteSizeLong()); 38 | 39 | for (size_t i = 1; i <= 10; i++) 40 | this->filter->summary("echo_test_quantiles")->observe(0.01 * i); 41 | } 42 | 43 | void set_filter(RPCMetricsPull *filter) { this->filter = filter; } 44 | 45 | private: 46 | RPCMetricsPull *filter; 47 | }; 48 | 49 | static void sig_handler(int signo) 50 | { 51 | wait_group.done(); 52 | } 53 | 54 | int main() 55 | { 56 | GOOGLE_PROTOBUF_VERIFY_VERSION; 57 | signal(SIGINT, sig_handler); 58 | signal(SIGTERM, sig_handler); 59 | 60 | SRPCServer server; 61 | ExampleServiceImpl impl; 62 | RPCMetricsPull filter; 63 | 64 | filter.init(8080); /* export port for prometheus */ 65 | filter.create_histogram("echo_request_size", "Echo request size", 66 | {1, 10, 100}); 67 | filter.create_summary("echo_test_quantiles", "Test quantile", 68 | {{0.5, 0.05}, {0.9, 0.01}}); 69 | impl.set_filter(&filter); 70 | 71 | server.add_filter(&filter); 72 | server.add_service(&impl); 73 | 74 | if (server.start(1412) == 0) 75 | { 76 | printf("Server with metrics for Promethes(port:8080) is running on 1412\n" 77 | "Try ./srpc_pb_client to send requests.\n" 78 | "Try ' curl http://localhost:8080/metrics ' to get prometheus data.\n"); 79 | wait_group.wait(); 80 | server.stop(); 81 | } 82 | else 83 | perror("server start"); 84 | 85 | filter.deinit(); 86 | google::protobuf::ShutdownProtobufLibrary(); 87 | return 0; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/thrift/rpc_thrift_idl.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_THRIFT_IDL_H__ 18 | #define __RPC_THRIFT_IDL_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "rpc_thrift_buffer.h" 26 | 27 | namespace srpc 28 | { 29 | 30 | class ThriftDescriptor 31 | { 32 | public: 33 | int8_t data_type; 34 | 35 | protected: 36 | using ReaderFunctionPTR = bool (*)(ThriftBuffer *, void *); 37 | using WriterFunctionPTR = bool (*)(const void *, ThriftBuffer *); 38 | virtual ~ThriftDescriptor() { } 39 | 40 | ThriftDescriptor(): 41 | reader(nullptr), 42 | writer(nullptr), 43 | json_reader(nullptr), 44 | json_writer(nullptr) 45 | {} 46 | 47 | ThriftDescriptor(const ReaderFunctionPTR r, 48 | const WriterFunctionPTR w, 49 | const ReaderFunctionPTR jr, 50 | const WriterFunctionPTR jw): 51 | reader(r), 52 | writer(w), 53 | json_reader(jr), 54 | json_writer(jw) 55 | {} 56 | 57 | public: 58 | const ReaderFunctionPTR reader; 59 | const WriterFunctionPTR writer; 60 | const ReaderFunctionPTR json_reader; 61 | const WriterFunctionPTR json_writer; 62 | }; 63 | 64 | struct struct_element 65 | { 66 | const ThriftDescriptor *desc; 67 | const char *name; 68 | ptrdiff_t isset_offset; 69 | ptrdiff_t data_offset; 70 | int16_t field_id; 71 | int8_t required_state; 72 | }; 73 | 74 | template 75 | class ThriftElementsImpl 76 | { 77 | public: 78 | static const std::list *get_elements_instance() 79 | { 80 | static const ThriftElementsImpl kInstance; 81 | 82 | return &kInstance.elements; 83 | } 84 | 85 | private: 86 | ThriftElementsImpl() 87 | { 88 | T::StaticElementsImpl(&this->elements); 89 | } 90 | 91 | std::list elements; 92 | }; 93 | 94 | class ThriftIDLMessage 95 | { 96 | public: 97 | const ThriftDescriptor *descriptor = nullptr; 98 | const std::list *elements = nullptr; 99 | 100 | std::string debug_string() const { return ""; } 101 | 102 | virtual ~ThriftIDLMessage() { } 103 | }; 104 | 105 | } // end namespace srpc 106 | 107 | #include "rpc_thrift_idl.inl" 108 | 109 | #endif 110 | 111 | -------------------------------------------------------------------------------- /src/http/http_client.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_HTTP_CLIENT_H__ 18 | #define __RPC_HTTP_CLIENT_H__ 19 | 20 | #include "workflow/WFTask.h" 21 | #include "workflow/HttpMessage.h" 22 | #include "workflow/WFTaskFactory.h" 23 | #include "rpc_options.h" 24 | #include "rpc_basic.h" 25 | #include "http_task.h" 26 | 27 | namespace srpc 28 | { 29 | 30 | #define HTTP_REDIRECT_DEFAULT 2 31 | #define HTTP_RETRY_DEFAULT 5 32 | #define HTTP_KEEPALIVE_DEFAULT (60 * 1000) 33 | 34 | struct HttpTaskParams 35 | { 36 | int send_timeout; 37 | int receive_timeout; 38 | int watch_timeout; 39 | int keep_alive_timeout; 40 | int redirect_max; 41 | int retry_max; 42 | }; 43 | 44 | struct HttpClientParams 45 | { 46 | HttpTaskParams task_params; 47 | bool is_ssl; 48 | std::string url; // can be empty 49 | ParsedURI uri; 50 | }; 51 | 52 | static constexpr struct HttpTaskParams HTTP_TASK_PARAMS_DEFAULT = 53 | { 54 | /* .send_timeout = */ -1, 55 | /* .receive_timeout = */ -1, 56 | /* .watch_timeout = */ 0, 57 | /* .keep_alive_timeout = */ HTTP_KEEPALIVE_DEFAULT, 58 | /* .retry_max = */ HTTP_REDIRECT_DEFAULT, 59 | /* .redirect_max = */ HTTP_RETRY_DEFAULT, 60 | }; 61 | 62 | static const struct HttpClientParams HTTP_CLIENT_PARAMS_DEFAULT = 63 | { 64 | /* .task_params = */ HTTP_TASK_PARAMS_DEFAULT, 65 | /* .is_ssl = */ false, 66 | /* .url = */ "", 67 | /* .uri = */ 68 | }; 69 | 70 | class HttpClient 71 | { 72 | public: 73 | HttpClient() { } 74 | 75 | WFHttpTask *create_http_task(const std::string& url, 76 | int redirect_max, 77 | int retry_max, 78 | http_callback_t callback); 79 | 80 | WFHttpTask *create_http_task(const ParsedURI& uri, 81 | int redirect_max, 82 | int retry_max, 83 | http_callback_t callback); 84 | 85 | void add_filter(RPCFilter *filter); 86 | 87 | private: 88 | void callback(WFHttpTask *task); 89 | void init(); 90 | void task_init(HttpClientTask *task); 91 | 92 | protected: 93 | HttpClientParams params; 94 | ParsedURI uri; 95 | 96 | private: 97 | std::mutex mutex; 98 | RPCModule *modules[SRPC_MODULE_MAX] = { 0 }; 99 | }; 100 | 101 | } // end namespace srpc 102 | 103 | #endif 104 | 105 | -------------------------------------------------------------------------------- /docs/en/docs-03-server.md: -------------------------------------------------------------------------------- 1 | [中文版](/docs/docs-03-server.md) 2 | 3 | ## 03 - RPC Server 4 | 5 | - Each server corresponds to one port 6 | - Each server corresponds to one specific network communication protocol 7 | - One service may be added into multiple Servers 8 | - One Server may have one or more Services, but the ServiceName must be unique within that Server 9 | - Services from different IDLs can be added into the same Server 10 | 11 | ### Sample 12 | 13 | You can follow the detailed example below: 14 | 15 | - Follow the above `ExampleServiceImpl` Service 16 | - First, create an RPC Server and determine the proto file. 17 | - Then, create any number of Service instances and any number of Services for different protocols, and add these services to the Server through the `add_service()`interface. 18 | - Finally, use `start()` or `serve()` to start the services in the Server and handle the upcoming rpc requests through the Server. 19 | - Imagine that we can also derive more Serivce from `Example::Service`, which have different implementations of rpc `Echo`. 20 | - Imagine that we can create N different RPC Servers on N different ports, serving on different network protocols. 21 | - Imagine that we can use `add_service()` to add the same ServiceIMPL instance on different Servers, or we can use `add_service()` to add different ServiceIMPL instances on the same server. 22 | - Imagine that we can use the same `ExampleServiceImpl`, serving BRPC-STD, SRPC-STD, SRPC-Http at three different ports at the same time. 23 | - And we can use `add_service()` to add one `ExampleServiceImpl` related to Protobuf IDL and one `AnotherThriftServiceImpl` related to Thrift IDL to the same SRPC-STD Server, and the two IDLs work perfectly on the same port! 24 | 25 | ~~~cpp 26 | int main() 27 | { 28 | SRPCServer server_srpc; 29 | SRPCHttpServer server_srpc_http; 30 | BRPCServer server_brpc; 31 | ThriftServer server_thrift; 32 | TRPCServer server_trpc; 33 | TRPCHttpServer server_trpc_http; 34 | 35 | ExampleServiceImpl impl_pb; 36 | AnotherThriftServiceImpl impl_thrift; 37 | 38 | server_srpc.add_service(&impl_pb); 39 | server_srpc.add_service(&impl_thrift); 40 | server_srpc_http.add_service(&impl_pb); 41 | server_srpc_http.add_service(&impl_thrift); 42 | server_brpc.add_service(&impl_pb); 43 | server_thrift.add_service(&impl_thrift); 44 | server_trpc.add_service(&impl_pb); 45 | server_trpc_http.add_service(&impl_pb); 46 | 47 | server_srpc.start(1412); 48 | server_srpc_http.start(8811); 49 | server_brpc.start(2020); 50 | server_thrift.start(9090); 51 | server_trpc.start(2022); 52 | server_trpc_http.start(8822); 53 | 54 | getchar(); 55 | server_trpc_http.stop(); 56 | server_trpc.stop(); 57 | server_thrift.stop(); 58 | server_brpc.stop(); 59 | server_srpc_http.stop(); 60 | server_srpc.stop(); 61 | 62 | return 0; 63 | } 64 | ~~~ 65 | 66 | -------------------------------------------------------------------------------- /tools/srpc_ctl.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2022 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include 18 | #include "srpc_controller.h" 19 | 20 | static void usage(const char *name) 21 | { 22 | printf(COLOR_PINK"Description:\n" 23 | COLOR_PURPLE" Simple generator for building Workflow and SRPC projects.\n\n" 24 | COLOR_PINK"Usage:\n" 25 | COLOR_INFO" %s" COLOR_COMMAND " " 26 | COLOR_INFO" " COLOR_FLAG " [FLAGS]\n\n" 27 | COLOR_PINK"Available Commands:\n" 28 | COLOR_COMMAND" http" 29 | COLOR_WHITE" - create project with both client and server\n" 30 | COLOR_COMMAND" redis" 31 | COLOR_WHITE" - create project with both client and server\n" 32 | COLOR_COMMAND" rpc" 33 | COLOR_WHITE" - create project with both client and server\n" 34 | COLOR_COMMAND" api" 35 | COLOR_WHITE" - create protobuf or thrift IDL api\n" 36 | COLOR_COMMAND" proxy" 37 | COLOR_WHITE" - create proxy for some client and server protocol\n" 38 | COLOR_COMMAND" file" 39 | COLOR_WHITE" - create project with asynchronous file service\n" 40 | COLOR_COMMAND" compute" 41 | COLOR_WHITE" - create project with asynchronous computing service\n" 42 | COLOR_OFF, name); 43 | } 44 | 45 | int main(int argc, const char *argv[]) 46 | { 47 | if (argc < 2) 48 | { 49 | usage(argv[0]); 50 | return 0; 51 | } 52 | 53 | CommandController *ctl; 54 | 55 | if (strcasecmp(argv[1], "http") == 0) 56 | { 57 | ctl = new HttpController; 58 | } 59 | else if (strcasecmp(argv[1], "redis") == 0) 60 | { 61 | ctl = new RedisController; 62 | } 63 | else if (strcasecmp(argv[1], "rpc") == 0) 64 | { 65 | ctl = new RPCController; 66 | } 67 | else if (strcasecmp(argv[1], "api") == 0) 68 | { 69 | ctl = new APIController; 70 | } 71 | else if (strcasecmp(argv[1], "proxy") == 0) 72 | { 73 | ctl = new ProxyController; 74 | } 75 | else if (strcasecmp(argv[1], "file") == 0) 76 | { 77 | ctl = new FileServiceController; 78 | } 79 | else if (strcasecmp(argv[1], "compute") == 0) 80 | { 81 | ctl = new ComputeController; 82 | } 83 | else 84 | { 85 | usage(argv[0]); 86 | return 0; 87 | } 88 | 89 | if (ctl->parse_args(argc, argv) == true) 90 | { 91 | if (ctl->dependencies_and_dir() == true) 92 | { 93 | if (ctl->copy_files() == true) 94 | ctl->print_success_info(); 95 | } 96 | } 97 | else 98 | ctl->print_usage(argv[0]); 99 | 100 | delete ctl; 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /src/http/http_server.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2023 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include "http_server.h" 18 | #include "http_task.h" 19 | #include "http_module.h" 20 | 21 | #ifdef _WIN32 22 | #include 23 | #else 24 | #include 25 | #include 26 | #endif 27 | 28 | namespace srpc 29 | { 30 | 31 | void HttpServer::add_filter(RPCFilter *filter) 32 | { 33 | int type = filter->get_module_type(); 34 | 35 | this->mutex.lock(); 36 | if (type < SRPC_MODULE_MAX && type >= 0) 37 | { 38 | RPCModule *module = this->modules[type]; 39 | 40 | if (!module) 41 | { 42 | switch (type) 43 | { 44 | case RPCModuleTypeTrace: 45 | module = new HttpTraceModule(); 46 | break; 47 | case RPCModuleTypeMetrics: 48 | module = new HttpMetricsModule(); 49 | break; 50 | case RPCModuleTypeCustom: 51 | module = new HttpCustomModule(); 52 | break; 53 | default: 54 | break; 55 | } 56 | this->modules[type] = module; 57 | } 58 | 59 | if (module) 60 | module->add_filter(filter); 61 | } 62 | 63 | this->mutex.unlock(); 64 | return; 65 | } 66 | 67 | CommSession *HttpServer::new_session(long long seq, CommConnection *conn) 68 | { 69 | HttpServerTask *task; 70 | 71 | std::list module; 72 | for (int i = 0; i < SRPC_MODULE_MAX; i++) 73 | { 74 | if (this->modules[i]) 75 | module.push_back(this->modules[i]); 76 | } 77 | 78 | task = new HttpServerTask(this, std::move(module), this->process); 79 | task->set_keep_alive(this->params.keep_alive_timeout); 80 | task->set_receive_timeout(this->params.receive_timeout); 81 | task->get_req()->set_size_limit(this->params.request_size_limit); 82 | task->set_is_ssl(this->get_ssl_ctx() != NULL); 83 | task->set_listen_port(this->get_listen_port()); 84 | 85 | return task; 86 | } 87 | 88 | unsigned short HttpServer::get_listen_port() 89 | { 90 | if (this->listen_port == 0) 91 | { 92 | struct sockaddr_storage addr; 93 | socklen_t l = sizeof addr; 94 | this->get_listen_addr((struct sockaddr *)&addr, &l); 95 | if (addr.ss_family == AF_INET) 96 | { 97 | struct sockaddr_in *sin = (struct sockaddr_in *)&addr; 98 | this->listen_port = ntohs(sin->sin_port); 99 | } 100 | else // if (addr.ss_family == AF_INET6) 101 | { 102 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; 103 | this->listen_port = ntohs(sin6->sin6_port); 104 | } 105 | } 106 | 107 | return this->listen_port; 108 | } 109 | 110 | } // namespace srpc 111 | 112 | -------------------------------------------------------------------------------- /src/message/rpc_meta_trpc.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | enum TrpcMagic { 4 | TRPC_DEFAULT_NONE = 0x00; 5 | TRPC_MAGIC_VALUE = 0x930; 6 | } 7 | 8 | enum TrpcDataFrameType { 9 | TRPC_UNARY_FRAME = 0x00; 10 | TRPC_STREAM_FRAME = 0x01; 11 | } 12 | 13 | enum TrpcDataFrameState { 14 | TRPC_NO_STATE = 0x00; 15 | TRPC_STREAM_FINISH = 0x01; 16 | } 17 | 18 | enum TrpcProtoVersion { 19 | TRPC_PROTO_V1 = 0; 20 | } 21 | 22 | enum TrpcCallType { 23 | TRPC_UNARY_CALL = 0; 24 | TRPC_ONEWAY_CALL = 1; 25 | TRPC_CLIENT_STREAM_CALL = 2; 26 | TRPC_SERVER_STREAM_CALL = 3; 27 | TRPC_BIDI_STREAM_CALL = 4; 28 | } 29 | enum TrpcMessageType { 30 | TRPC_DEFAULT = 0x00; 31 | TRPC_DYEING_MESSAGE = 0x01; 32 | TRPC_TRACE_MESSAGE = 0x02; 33 | TRPC_MULTI_ENV_MESSAGE = 0x04; 34 | TRPC_GRID_MESSAGE = 0x08; 35 | TRPC_SETNAME_MESSAGE = 0x10; 36 | } 37 | 38 | enum TrpcContentEncodeType { 39 | TRPC_PROTO_ENCODE = 0; 40 | TRPC_JCE_ENCODE = 1; 41 | TRPC_JSON_ENCODE = 2; 42 | TRPC_FLATBUFFER_ENCODE = 3; 43 | TRPC_NOOP_ENCODE = 4; 44 | } 45 | 46 | enum TrpcCompressType { 47 | TRPC_DEFAULT_COMPRESS = 0; 48 | TRPC_GZIP_COMPRESS = 1; 49 | TRPC_SNAPPY_COMPRESS = 2; 50 | // srpc framework support zlib and lz4 51 | TRPC_ZLIB_COMPRESS = 3; 52 | TRPC_LZ4_COMPRESS = 4; 53 | } 54 | 55 | enum TrpcRetCode { 56 | TRPC_INVOKE_SUCCESS = 0; 57 | TRPC_SERVER_DECODE_ERR = 1; 58 | TRPC_SERVER_ENCODE_ERR = 2; 59 | 60 | TRPC_SERVER_NOSERVICE_ERR = 11; 61 | TRPC_SERVER_NOFUNC_ERR = 12; 62 | 63 | TRPC_SERVER_TIMEOUT_ERR = 21; 64 | TRPC_SERVER_OVERLOAD_ERR = 22; 65 | 66 | TRPC_SERVER_SYSTEM_ERR = 31; 67 | 68 | TRPC_SERVER_AUTH_ERR = 41; 69 | 70 | TRPC_CLIENT_INVOKE_TIMEOUT_ERR = 101; 71 | 72 | TRPC_CLIENT_CONNECT_ERR = 111; 73 | 74 | TRPC_CLIENT_ENCODE_ERR = 121; 75 | TRPC_CLIENT_DECODE_ERR = 122; 76 | 77 | TRPC_CLIENT_ROUTER_ERR = 131; 78 | 79 | TRPC_CLINET_NETWORK_ERR = 141; 80 | 81 | TRPC_INVOKE_UNKNOWN_ERR = 999; 82 | } 83 | 84 | message RequestProtocol { 85 | uint32 version = 1; 86 | uint32 call_type = 2; 87 | uint32 request_id = 3; 88 | uint32 timeout = 4; 89 | bytes caller = 5; 90 | bytes callee = 6; 91 | bytes func = 7; 92 | uint32 message_type = 8; 93 | map trans_info = 9; 94 | uint32 content_type = 10; 95 | uint32 content_encoding = 11; 96 | } 97 | 98 | message ResponseProtocol { 99 | uint32 version = 1; 100 | uint32 call_type = 2; 101 | uint32 request_id = 3; 102 | int32 ret = 4; 103 | int32 func_ret = 5; 104 | bytes error_msg = 6; 105 | uint32 message_type = 7; 106 | map trans_info = 8; 107 | uint32 content_type = 9; 108 | uint32 content_encoding = 10; 109 | } 110 | -------------------------------------------------------------------------------- /tools/templates/rpc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | project(%s LANGUAGES CXX) 3 | set(CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 5 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 6 | 7 | set(Protobuf_ERROR_MSG "ERROR: Failed to find protobuf. Some suggestions for installation.") 8 | set(Protobuf_ERROR_MSG_LINUX "${Protobuf_ERROR_MSG} 9 | For Debian / Ubuntu ...: 10 | sudo apt-get update 11 | sudo apt-get install -y libprotobuf-dev protobuf-compiler 12 | For RedHat / Fedora / CentOS ...: 13 | sudo yum makecache 14 | sudo yum install -y protobuf-devel protobuf-compiler") 15 | 16 | set(Protobuf_ERROR_MSG_MACOS "${Protobuf_ERROR_MSG} 17 | For MacOS : 18 | sudo brew update 19 | sudo brew install protobuf protobuf-c") 20 | 21 | # Find all the dependencies 22 | find_package(OpenSSL REQUIRED) 23 | 24 | set(Workflow_DIR "%s") 25 | find_package(Workflow REQUIRED CONFIG HINTS ${Workflow_DIR}) 26 | 27 | set(Srpc_DIR "%s") 28 | find_package(srpc REQUIRED CONFIG HINTS ${Srpc_DIR}) 29 | 30 | find_package(Protobuf) 31 | if ("x${Protobuf_DIR}" STREQUAL "xProtobuf_DIR-NOTFOUND") 32 | if (APPLE) 33 | message (FATAL_ERROR ${Protobuf_ERROR_MSG_MACOS}) 34 | else () 35 | message (FATAL_ERROR ${Protobuf_ERROR_MSG_LINUX}) 36 | endif () 37 | endif () 38 | 39 | get_filename_component(Protobuf_LIB_DIR ${Protobuf_LIBRARY} DIRECTORY) 40 | 41 | if (NOT EXISTS "${Srpc_DIR}/third_party/lz4/lib/lz4.h") 42 | set(LZ4_LIB lz4) 43 | endif () 44 | 45 | if (NOT EXISTS "${Srpc_DIR}/third_party/snappy/cmake") 46 | set(SNAPPY_LIB snappy) 47 | endif () 48 | 49 | find_package(ZLIB REQUIRED) 50 | 51 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}) 52 | 53 | # Generate idl code: xx.srpc.h xx.pb.h xx.pb.cc xx.thrift.h 54 | set(IDL_FILE %s) 55 | set(SRPC_GEN_PROGRAM ${SRPC_BIN_DIR}/srpc_generator) %s 56 | 57 | add_custom_target(SRPC_GEN ALL 58 | COMMAND ${SRPC_GEN_PROGRAM} ${PROJECT_SOURCE_DIR}/${IDL_FILE} ${PROJECT_SOURCE_DIR} -s 59 | COMMENT "srpc generator..." 60 | ) 61 | 62 | # Prefer to static link first 63 | set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ${CMAKE_FIND_LIBRARY_SUFFIXES}) 64 | find_library(Workflow_LIB workflow HINTS ${Workflow_DIR}/_lib) 65 | find_library(Srpc_LIB srpc HINTS ${Srpc_DIR}/_lib) 66 | 67 | # Set all the libraries here 68 | set(LIB ${Srpc_LIB} ${Workflow_LIB} pthread OpenSSL::SSL OpenSSL::Crypto 69 | protobuf z ${SNAPPY_LIB} ${LZ4_LIB}) 70 | 71 | # Add all the common code here 72 | set(COMMON_CODE config/config.cc config/Json.cc ${PROTO_SRCS}) 73 | 74 | # Add header directories and library directories here 75 | include_directories(${OPENSSL_INCLUDE_DIR} ${Protobuf_INCLUDE_DIR} 76 | ${WORKFLOW_INCLUDE_DIR} ${SRPC_INCLUDE_DIR} 77 | ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 78 | link_directories(${OPENSSL_LINK_DIR} ${Protobuf_LIB_DIR} 79 | ${WORKFLOW_LIB_DIR} ${SRPC_LIB_DIR}) 80 | 81 | # Build executable outputs 82 | set(PROJECT_OUTPUT server client%s) 83 | foreach(output ${PROJECT_OUTPUT}) 84 | add_executable(${output} ${output}_main.cc ${COMMON_CODE}) 85 | target_link_libraries(${output} ${LIB}) 86 | endforeach() 87 | 88 | -------------------------------------------------------------------------------- /src/rpc_zero_copy_stream.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_ZERO_COPY_STREAM_H__ 18 | #define __RPC_ZERO_COPY_STREAM_H__ 19 | 20 | #include 21 | 22 | namespace srpc 23 | { 24 | 25 | class RPCOutputStream : public google::protobuf::io::ZeroCopyOutputStream 26 | { 27 | public: 28 | RPCOutputStream(RPCBuffer *buf, size_t size); 29 | bool Next(void **data, int *size) override; 30 | void BackUp(int count) override; 31 | int64_t ByteCount() const override; 32 | 33 | private: 34 | RPCBuffer *buf; 35 | size_t size; 36 | }; 37 | 38 | class RPCInputStream : public google::protobuf::io::ZeroCopyInputStream 39 | { 40 | public: 41 | RPCInputStream(RPCBuffer *buf); 42 | bool Next(const void **data, int *size) override; 43 | void BackUp(int count) override; 44 | bool Skip(int count) override; 45 | int64_t ByteCount() const override; 46 | 47 | private: 48 | RPCBuffer *buf; 49 | }; 50 | 51 | inline RPCOutputStream::RPCOutputStream(RPCBuffer *buf, size_t size) 52 | { 53 | this->buf = buf; 54 | this->size = size; 55 | } 56 | 57 | inline bool RPCOutputStream::Next(void **data, int *size) 58 | { 59 | size_t tmp; 60 | 61 | if (this->size > 0) 62 | { 63 | tmp = this->size; 64 | if (this->buf->acquire(data, &tmp)) 65 | { 66 | this->size -= tmp; 67 | *size = (int)tmp; 68 | return true; 69 | } 70 | } 71 | else 72 | { 73 | tmp = this->buf->acquire(data); 74 | if (tmp > 0) 75 | { 76 | *size = (int)tmp; 77 | return true; 78 | } 79 | } 80 | 81 | return false; 82 | } 83 | 84 | inline void RPCOutputStream::BackUp(int count) 85 | { 86 | this->buf->backup(count); 87 | } 88 | 89 | inline int64_t RPCOutputStream::ByteCount() const 90 | { 91 | return this->buf->size(); 92 | } 93 | 94 | inline RPCInputStream::RPCInputStream(RPCBuffer *buf) 95 | { 96 | this->buf = buf; 97 | } 98 | 99 | inline bool RPCInputStream::Next(const void **data, int *size) 100 | { 101 | size_t len = this->buf->fetch(data); 102 | 103 | if (len == 0) 104 | return false; 105 | 106 | *size = (int)len; 107 | return true; 108 | } 109 | 110 | inline bool RPCInputStream::Skip(int count) 111 | { 112 | return this->buf->seek(count) == count ? true : false; 113 | } 114 | 115 | inline void RPCInputStream::BackUp(int count) 116 | { 117 | this->buf->seek(0 - count); 118 | } 119 | 120 | inline int64_t RPCInputStream::ByteCount() const 121 | { 122 | return (int64_t)this->buf->size(); 123 | } 124 | 125 | } // namespace srpc 126 | 127 | #endif 128 | 129 | -------------------------------------------------------------------------------- /src/thrift/rpc_thrift_buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_THRIFT_BUFFER_H__ 18 | #define __RPC_THRIFT_BUFFER_H__ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "rpc_thrift_enum.h" 24 | #include "rpc_buffer.h" 25 | 26 | namespace srpc 27 | { 28 | 29 | static constexpr int32_t THRIFT_VERSION_MASK = ((int32_t)0xffff0000); 30 | static constexpr int32_t THRIFT_VERSION_1 = ((int32_t)0x80010000); 31 | 32 | enum 33 | { 34 | //THRIFT_PARSE_INIT = 0, 35 | THRIFT_GET_FRAME_SIZE = 1, 36 | THRIFT_GET_DATA, 37 | THRIFT_PARSE_END 38 | }; 39 | 40 | class ThriftMeta 41 | { 42 | public: 43 | std::string writebuf; 44 | std::string method_name; 45 | int seqid = 0; 46 | int8_t message_type = TMT_CALL; 47 | bool is_strict = true; 48 | 49 | public: 50 | ThriftMeta() = default; 51 | ThriftMeta(const ThriftMeta&) = delete; 52 | ThriftMeta& operator= (const ThriftMeta&) = delete; 53 | ThriftMeta(ThriftMeta&& move) = delete; 54 | ThriftMeta& operator= (ThriftMeta &&move) = delete; 55 | bool writeI08(int8_t val); 56 | bool writeI32(int32_t val); 57 | bool writeString(const std::string& str); 58 | }; 59 | 60 | class ThriftBuffer 61 | { 62 | public: 63 | ThriftMeta meta; 64 | RPCBuffer *buffer; 65 | size_t readbuf_size = 0; 66 | size_t framesize_read_byte = 0; 67 | int32_t framesize = 0; 68 | int status = THRIFT_GET_FRAME_SIZE; 69 | 70 | public: 71 | ThriftBuffer(RPCBuffer *buf): buffer(buf) { } 72 | 73 | ThriftBuffer(const ThriftBuffer&) = delete; 74 | ThriftBuffer& operator= (const ThriftBuffer&) = delete; 75 | ThriftBuffer(ThriftBuffer&& move) = delete; 76 | ThriftBuffer& operator= (ThriftBuffer &&move) = delete; 77 | 78 | public: 79 | bool readMessageBegin(); 80 | bool readFieldBegin(int8_t& field_type, int16_t& field_id); 81 | bool readI08(int8_t& val); 82 | bool readI16(int16_t& val); 83 | bool readI32(int32_t& val); 84 | bool readI64(int64_t& val); 85 | bool readU64(uint64_t& val); 86 | bool readString(std::string& str); 87 | bool readStringBody(std::string& str, int32_t slen); 88 | bool skip(int8_t field_type); 89 | 90 | bool writeMessageBegin(); 91 | bool writeFieldBegin(int8_t field_type, int16_t field_id); 92 | bool writeFieldStop(); 93 | bool writeI08(int8_t val); 94 | bool writeI16(int16_t val); 95 | bool writeI32(int32_t val); 96 | bool writeI64(int64_t val); 97 | bool writeU64(uint64_t val); 98 | bool writeString(const std::string& str); 99 | bool writeStringBody(const std::string& str); 100 | }; 101 | 102 | } // end namespace srpc 103 | 104 | #endif 105 | 106 | -------------------------------------------------------------------------------- /tools/templates/config/config_full.h: -------------------------------------------------------------------------------- 1 | #ifndef _RPC_CONFIG_H_ 2 | #define _RPC_CONFIG_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "Json.h" 8 | #include "srpc/rpc_types.h" 9 | #include "srpc/rpc_define.h" 10 | #include "srpc/rpc_filter.h" 11 | 12 | namespace srpc 13 | { 14 | 15 | class RPCConfig 16 | { 17 | public: 18 | using ErrorPageMap = std::unordered_map; 19 | 20 | bool load(const char *file); 21 | 22 | void load_filter(SRPCServer& server); 23 | void load_filter(SRPCClient& client); 24 | 25 | void load_filter(SRPCHttpServer& server); 26 | void load_filter(SRPCHttpClient& client); 27 | 28 | void load_filter(BRPCServer& server); 29 | void load_filter(BRPCClient& client); 30 | 31 | void load_filter(ThriftServer& server); 32 | void load_filter(ThriftClient& client); 33 | 34 | void load_filter(ThriftHttpServer& server); 35 | void load_filter(ThriftHttpClient& client); 36 | 37 | void load_filter(TRPCServer& server); 38 | void load_filter(TRPCClient& client); 39 | 40 | void load_filter(TRPCHttpServer& server); 41 | void load_filter(TRPCHttpClient& client); 42 | 43 | unsigned short server_port() const { return this->s_port; } 44 | const char *server_cert_file() const { return this->s_cert_file.c_str(); } 45 | const char *server_file_key() const { return this->s_file_key.c_str(); } 46 | enum TransportType client_transport_type() const { return this->c_transport_type; } 47 | const char *client_host() const { return this->c_host.c_str(); } 48 | unsigned short client_port() const { return this->c_port; } 49 | bool client_is_ssl() const { return this->c_is_ssl; } 50 | const char *client_url() const { return this->c_url.c_str(); } 51 | int client_callee_timeout() const { return this->c_callee_timeout; } 52 | const char *client_caller() const { return this->c_caller.c_str(); } 53 | int redirect_max() const { return this->c_redirect_max; } 54 | int retry_max() const { return this->c_retry_max; } 55 | const char *client_user_name() const { return this->c_user_name.c_str(); } 56 | const char *client_password() const { return this->c_password.c_str(); } 57 | const char *get_root_path() const { return this->root_path.c_str(); } 58 | const ErrorPageMap& get_error_page() const { return this->error_page; } 59 | 60 | public: 61 | RPCConfig() : 62 | s_port(0), c_transport_type(TT_TCP), c_port(0), c_is_ssl(false), c_redirect_max(0), c_retry_max(0) 63 | { } 64 | ~RPCConfig(); 65 | 66 | private: 67 | void load_server(); 68 | void load_client(); 69 | void load_metrics(); 70 | void load_trace(); 71 | 72 | wfrest::Json data; 73 | std::vector filters; 74 | unsigned short s_port; 75 | std::string s_cert_file; 76 | std::string s_file_key; 77 | enum TransportType c_transport_type; 78 | std::string c_host; 79 | unsigned short c_port; 80 | bool c_is_ssl; 81 | std::string c_url; 82 | int c_callee_timeout; 83 | std::string c_caller; 84 | int c_redirect_max; 85 | int c_retry_max; 86 | std::string c_user_name; 87 | std::string c_password; 88 | std::string root_path; 89 | ErrorPageMap error_page; 90 | }; 91 | 92 | } 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others’ private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at liyingxin@sogou-inc.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # 安装 2 | 3 | ## 1. Linux源码安装 4 | 5 | 源码安装需要一些前置依赖:CMake(要求3.6以上)、OpenSSL(推荐1.1及以上)、Protobuf(要求3.5及以上) 6 | 7 | 默认会编译出: 8 | 1. 静态库:libsrpc.a(或者dylib) 9 | 2. 动态库:libsrpc.so(或者dll) 10 | 3. 用于生成代码的二进制工具:srpc_generator 11 | 12 | - **cmake** 13 | ~~~sh 14 | git clone --recursive https://github.com/sogou/srpc.git 15 | cd srpc 16 | make 17 | make install 18 | 19 | # 编译示例 20 | cd tutorial 21 | make 22 | ~~~ 23 | 24 | - **bazel(二选一)** 25 | ~~~sh 26 | git clone --recursive https://github.com/sogou/srpc.git 27 | cd srpc 28 | bazel build ... 29 | # 在bazel-bin/目录下,编译出lib和srpc_generator以及所有示例编译出来的可执行文件 30 | ~~~ 31 | 32 | 此外,还可以借助srpc_tools安装和部署脚手架。小工具用法参考:[srpc/tools/README_cn.md](srpc/tools/README_cn.md) 33 | 34 | Workflow、snappy和lz4也可以系统预装,如果third_party中没有通过`--recursive`参数拉取源码依赖,则会从系统默认安装路径寻找,snappy的预装要求版本是v1.1.6或以上。 35 | 36 | 如果需要源码安装`Protobuf`,参考命令: 37 | ~~~sh 38 | git clone -b 3.20.x https://github.com/protocolbuffers/protobuf.git protobuf.3.20 39 | cd protobuf.3.20 40 | sh autogen.sh 41 | ./configure 42 | make 43 | make install 44 | ~~~ 45 | 46 | ## 2. Debian Linux和Ubuntu自带安装包 47 | 48 | SRPC已经打包到Debian,目前是Debian sid(unstable)的自带安装包,最终会进入stable的repository。 49 | 50 | 需要编辑/etc/apt/sources.list文件,才能访问unstable的repository: 51 | 52 | sources.list文件格式: `deb ` 53 | 54 | 将'unstable'字段加到我们的repo中,作为sub branch之一: 55 | ~~~~sh 56 | deb http://deb.debian.org/ main contrib non-free 57 | 58 | --> 59 | 60 | deb http://deb.debian.org/ unstable main contrib non-free 61 | ~~~~ 62 | 63 | 然后update我们的repo列表,就可以安装SRPC: 64 | 65 | ~~~~sh 66 | sudo apt-get update 67 | ~~~~ 68 | 69 | 安装SRPC库用于开发: 70 | 71 | ~~~~sh 72 | sudo apt-get install libsrpc-dev 73 | ~~~~ 74 | 75 | 安装SRPC库用于部署: 76 | 77 | ~~~~sh 78 | sudo apt-get install libsrpc 79 | ~~~~ 80 | 81 | ## 3. Fedora Linux自带安装包 82 | 83 | SRPC已经是Fedora系统的自带安装包。 84 | 85 | 为了开发目的安装srpc库: 86 | ~~~sh 87 | sudo dnf install srpc-devel 88 | ~~~ 89 | 90 | 要安装srpc库以进行部署,请执行以下操作: 91 | ~~~sh 92 | sudo dnf install srpc 93 | ~~~ 94 | 95 | ## 4. Windows下安装 96 | 97 | Windows版下srpc代码无差异,注意需要依赖Workflow的[windows分支](https://github.com/sogou/workflow/tree/windows)。 98 | 99 | 另外,srpc_tools暂时不支持Windows下使用。 100 | 101 | ## 5. MacOS源码安装 102 | 103 | - 安装依赖 `OpenSSL` 104 | ``` 105 | brew install openssl 106 | ``` 107 | 108 | - 安装 `CMake` 109 | ``` 110 | brew install cmake 111 | ``` 112 | 113 | - 指定 `OpenSSL` 环境变量 114 | 由于MacOS下默认有LibreSSL,因此在brew安装后,并不会自动建软链,我们需要手动把执行路径、编译路径、cmake时的find_package路径都配置到bash的环境变量中。用户可以执行`brew info openssl`查看相关信息,也可以如下配置: 115 | ``` 116 | echo 'export PATH="/usr/local/opt/openssl@1.1/bin:$PATH"' >> ~/.bash_profile 117 | echo 'export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"' >> ~/.bash_profile 118 | echo 'export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"' >> ~/.bash_profile 119 | echo 'export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig"' >> ~/.bash_profile 120 | echo 'export OPENSSL_ROOT_DIR=/usr/local/opt/openssl' >> ~/.bash_profile 121 | echo 'export OPENSSL_LIBRARIES=/usr/local/opt/openssl/lib' >> ~/.bash_profile 122 | ``` 123 | 如果使用zsh,则还需要以下一步,把bash的配置加载一下: 124 | ``` 125 | echo 'test -f ~/.bash_profile && source ~/.bash_profile' >> ~/.zshrc 126 | source ~/.zshrc 127 | ``` 128 | 剩下的步骤和Linux下编译没有区别。 129 | -------------------------------------------------------------------------------- /src/compress/rpc_compress_snappy.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #include "snappy.h" 18 | #include "snappy-sinksource.h" 19 | #include "rpc_compress_snappy.h" 20 | 21 | namespace srpc 22 | { 23 | 24 | class RPCSnappySink : public snappy::Sink 25 | { 26 | public: 27 | RPCSnappySink(RPCBuffer *buf) 28 | { 29 | this->buf = buf; 30 | } 31 | 32 | void Append(const char *bytes, size_t n) override 33 | { 34 | this->buf->append(bytes, n, BUFFER_MODE_COPY); 35 | } 36 | 37 | size_t size() const 38 | { 39 | return this->buf->size(); 40 | } 41 | 42 | private: 43 | RPCBuffer *buf; 44 | }; 45 | 46 | class RPCSnappySource : public snappy::Source 47 | { 48 | public: 49 | RPCSnappySource(RPCBuffer *buf) 50 | { 51 | this->buf = buf; 52 | this->buf_size = this->buf->size(); 53 | this->pos = 0; 54 | } 55 | 56 | size_t Available() const override 57 | { 58 | return this->buf_size - this->pos; 59 | } 60 | 61 | const char *Peek(size_t *len) override 62 | { 63 | const void *pos; 64 | 65 | *len = this->buf->peek(&pos); 66 | return (const char *)pos; 67 | } 68 | 69 | void Skip(size_t n) override 70 | { 71 | this->pos += this->buf->seek(n); 72 | } 73 | 74 | private: 75 | RPCBuffer *buf; 76 | size_t buf_size; 77 | size_t pos; 78 | }; 79 | 80 | int SnappyManager::SnappyCompress(const char *msg, size_t msglen, 81 | char *buf, size_t buflen) 82 | { 83 | size_t compressed_len = buflen; 84 | 85 | snappy::RawCompress(msg, msglen, buf, &compressed_len); 86 | if (compressed_len > buflen) 87 | return -1; 88 | 89 | return (int)compressed_len; 90 | } 91 | 92 | int SnappyManager::SnappyDecompress(const char *buf, size_t buflen, 93 | char *msg, size_t msglen) 94 | { 95 | size_t origin_len; 96 | 97 | if (snappy::GetUncompressedLength(buf, buflen, &origin_len) && 98 | origin_len <= msglen && 99 | snappy::RawUncompress(buf, buflen, msg)) 100 | { 101 | return (int)origin_len; 102 | } 103 | 104 | return -1; 105 | } 106 | 107 | int SnappyManager::SnappyCompressIOVec(RPCBuffer *src, RPCBuffer *dst) 108 | { 109 | RPCSnappySource source(src); 110 | RPCSnappySink sink(dst); 111 | 112 | return (int)snappy::Compress(&source, &sink); 113 | } 114 | 115 | int SnappyManager::SnappyDecompressIOVec(RPCBuffer *src, RPCBuffer *dst) 116 | { 117 | RPCSnappySource source(src); 118 | RPCSnappySink sink(dst); 119 | 120 | // if (snappy::IsValidCompressed(&source)) 121 | // if (snappy::GetUncompressedLength(&source, &origin_len)) 122 | return (int)snappy::Uncompress(&source, &sink) ? sink.size() : -1; 123 | } 124 | 125 | int SnappyManager::SnappyLeaseSize(size_t origin_size) 126 | { 127 | return (int)snappy::MaxCompressedLength(origin_size); 128 | } 129 | 130 | } // end namespace srpc 131 | -------------------------------------------------------------------------------- /src/generator/parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifndef __RPC_PARSER_H__ 18 | #define __RPC_PARSER_H__ 19 | 20 | #define PARSER_ST_BLOCK_MASK 0x01 21 | #define PARSER_ST_OUTSIDE_BLOCK 0x00 22 | #define PARSER_ST_INSIDE_BLOCK 0x01 23 | #define PARSER_ST_OUTSIDE_BLOCK_MASK 0xFFFE 24 | 25 | #define PARSER_ST_COMMENT_MASK 0x10 26 | #define PARSER_ST_INSIDE_COMMENT 0x10 27 | #define PARSER_ST_OUTSIDE_COMMENT_MASK 0xFFFD 28 | #define PARSER_ST_INSIDE_COMMENT_MASK 0xFFFF 29 | 30 | #define DIRECTORY_LENGTH 2048 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "descriptor.h" 43 | 44 | class Parser 45 | { 46 | public: 47 | bool parse(const std::string& proto_file, idl_info& info); 48 | std::string find_typedef_mapping_type(std::string& type_name, 49 | size_t& cur, idl_info& info); 50 | void build_typedef_mapping(idl_info& info); 51 | int find_valid(const std::string& line); 52 | bool check_block_begin(FILE *in, std::string& line); 53 | bool check_block_begin(const std::string& line); 54 | bool check_block_end(const std::string& line); 55 | void check_single_comments(std::string& line); 56 | bool parse_block_name(const std::string& line, 57 | std::string& block_name, 58 | std::string& block_name_value, 59 | std::string& extend_type); 60 | bool parse_service_pb(const std::string& block, Descriptor& desc); 61 | std::vector split_thrift_rpc(const std::string &str); 62 | bool parse_thrift_typedef(const std::string& line, 63 | std::string& old_type_name, 64 | std::string& new_type_name, 65 | idl_info& info); 66 | bool parse_rpc_param_thrift(const std::string& file_name_prefix, 67 | const std::string &str, 68 | std::vector ¶ms, 69 | idl_info& info); 70 | bool parse_service_thrift(const std::string& file_name_prefix, 71 | const std::string& block, 72 | Descriptor& desc, 73 | idl_info& info); 74 | bool parse_struct_thrift(const std::string& file_name_prefix, 75 | const std::string& block, 76 | Descriptor& desc, idl_info& info); 77 | bool parse_enum_thrift(const std::string& block, Descriptor& desc); 78 | bool parse_package_name(const std::string& line, 79 | std::vector& package_name); 80 | bool parse_include_file(const std::string& line, std::string& file_name); 81 | bool check_multi_comments_begin(std::string& line); 82 | bool check_multi_comments_end(std::string& line); 83 | int parse_pb_rpc_option(const std::string& line); 84 | Parser(bool is_thrift) { this->is_thrift = is_thrift; } 85 | 86 | private: 87 | bool is_thrift; 88 | }; 89 | 90 | #endif 91 | 92 | -------------------------------------------------------------------------------- /src/var/time_window_quantiles.h: -------------------------------------------------------------------------------- 1 | #ifndef __TIME_WINDOW_QUANTILES_H__ 2 | #define __TIME_WINDOW_QUANTILES_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "ckms_quantiles.h" 12 | 13 | namespace srpc 14 | { 15 | 16 | template 17 | class TimeWindowQuantiles 18 | { 19 | public: 20 | using Clock = std::chrono::steady_clock; 21 | 22 | size_t get(double quantile, TYPE *value); 23 | void insert(TYPE value); 24 | TYPE get_sum() { return this->ckms_quantiles[current_bucket].get_sum(); } 25 | 26 | private: 27 | CKMSQuantiles& rotate(); 28 | 29 | const std::vector *quantiles; 30 | std::vector> ckms_quantiles; 31 | size_t current_bucket; 32 | 33 | Clock::time_point last_rotation; 34 | Clock::duration rotation_interval; 35 | 36 | public: 37 | TimeWindowQuantiles(const std::vector *quantiles, 38 | Clock::duration max_age_seconds, 39 | int age_buckets); 40 | 41 | TimeWindowQuantiles(const TimeWindowQuantiles& copy); 42 | TimeWindowQuantiles& operator= (const TimeWindowQuantiles& copy); 43 | }; 44 | 45 | ////////// impl 46 | 47 | template 48 | TimeWindowQuantiles::TimeWindowQuantiles(const std::vector *q, 49 | const Clock::duration max_age, 50 | const int age_buckets) : 51 | quantiles(q), 52 | ckms_quantiles(age_buckets, CKMSQuantiles(this->quantiles)), 53 | rotation_interval(max_age / age_buckets) 54 | { 55 | this->current_bucket = 0; 56 | this->last_rotation = Clock::now(); 57 | } 58 | 59 | template 60 | TimeWindowQuantiles::TimeWindowQuantiles(const TimeWindowQuantiles& copy) 61 | { 62 | this->operator= (copy); 63 | } 64 | 65 | template 66 | TimeWindowQuantiles& TimeWindowQuantiles::operator= (const TimeWindowQuantiles& copy) 67 | { 68 | if (this != ©) 69 | { 70 | this->quantiles = copy.quantiles; 71 | this->ckms_quantiles = copy.ckms_quantiles; 72 | this->current_bucket = copy.current_bucket; 73 | this->last_rotation = copy.last_rotation; 74 | this->rotation_interval = copy.rotation_interval; 75 | } 76 | 77 | return *this; 78 | } 79 | 80 | template 81 | size_t TimeWindowQuantiles::get(double quantile, TYPE *value) 82 | { 83 | CKMSQuantiles& current_bucket = this->rotate(); 84 | 85 | *value = current_bucket.get(quantile); 86 | return current_bucket.get_count(); 87 | } 88 | 89 | template 90 | void TimeWindowQuantiles::insert(TYPE value) 91 | { 92 | this->rotate(); 93 | 94 | for (auto& bucket : this->ckms_quantiles) 95 | bucket.insert(value); 96 | } 97 | 98 | template 99 | CKMSQuantiles& TimeWindowQuantiles::rotate() 100 | { 101 | auto delta = Clock::now() - this->last_rotation; 102 | 103 | while (delta > this->rotation_interval) 104 | { 105 | this->ckms_quantiles[this->current_bucket].reset(); 106 | 107 | if (++this->current_bucket >= this->ckms_quantiles.size()) 108 | this->current_bucket = 0; 109 | 110 | delta -= this->rotation_interval; 111 | this->last_rotation += this->rotation_interval; 112 | } 113 | 114 | return this->ckms_quantiles[this->current_bucket]; 115 | } 116 | 117 | } // end namespace srpc 118 | 119 | #endif 120 | 121 | -------------------------------------------------------------------------------- /src/module/proto/opentelemetry_common.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2019, OpenTelemetry Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package opentelemetry.proto.common.v1; 18 | 19 | // AnyValue is used to represent any type of attribute value. AnyValue may contain a 20 | // primitive value such as a string or integer or it may contain an arbitrary nested 21 | // object containing arrays, key-value lists and primitives. 22 | message AnyValue { 23 | // The value is one of the listed fields. It is valid for all values to be unspecified 24 | // in which case this AnyValue is considered to be "null". 25 | oneof value { 26 | string string_value = 1; 27 | bool bool_value = 2; 28 | int64 int_value = 3; 29 | double double_value = 4; 30 | ArrayValue array_value = 5; 31 | KeyValueList kvlist_value = 6; 32 | bytes bytes_value = 7; 33 | } 34 | } 35 | 36 | // ArrayValue is a list of AnyValue messages. We need ArrayValue as a message 37 | // since oneof in AnyValue does not allow repeated fields. 38 | message ArrayValue { 39 | // Array of values. The array may be empty (contain 0 elements). 40 | repeated AnyValue values = 1; 41 | } 42 | 43 | // KeyValueList is a list of KeyValue messages. We need KeyValueList as a message 44 | // since `oneof` in AnyValue does not allow repeated fields. Everywhere else where we need 45 | // a list of KeyValue messages (e.g. in Span) we use `repeated KeyValue` directly to 46 | // avoid unnecessary extra wrapping (which slows down the protocol). The 2 approaches 47 | // are semantically equivalent. 48 | message KeyValueList { 49 | // A collection of key/value pairs of key-value pairs. The list may be empty (may 50 | // contain 0 elements). 51 | // The keys MUST be unique (it is not allowed to have more than one 52 | // value with the same key). 53 | repeated KeyValue values = 1; 54 | } 55 | 56 | // KeyValue is a key-value pair that is used to store Span attributes, Link 57 | // attributes, etc. 58 | message KeyValue { 59 | string key = 1; 60 | AnyValue value = 2; 61 | } 62 | 63 | // StringKeyValue is a pair of key/value strings. This is the simpler (and faster) version 64 | // of KeyValue that only supports string values. 65 | message StringKeyValue { 66 | option deprecated = true; 67 | 68 | string key = 1; 69 | string value = 2; 70 | } 71 | 72 | ////////// deprecated 73 | // InstrumentationLibrary is a message representing the instrumentation library information 74 | // such as the fully qualified name and version. 75 | message InstrumentationLibrary { 76 | // An empty instrumentation library name means the name is unknown. 77 | string name = 1; 78 | string version = 2; 79 | } 80 | 81 | // such as the fully qualified name and version. 82 | message InstrumentationScope { 83 | // An empty instrumentation scope name means the name is unknown. 84 | string name = 1; 85 | string version = 2; 86 | repeated KeyValue attributes = 3; 87 | uint32 dropped_attributes_count = 4; 88 | } 89 | -------------------------------------------------------------------------------- /tools/templates/file/file_service.cc: -------------------------------------------------------------------------------- 1 | #include "file_service.h" 2 | 3 | SubTask *FileService::create_error_task(int code, 4 | struct FileService::ModuleCtx *ctx) 5 | { 6 | if (ctx->is_error_set == false) 7 | { 8 | ctx->resp->set_status_code(std::to_string(code)); 9 | ctx->is_error_set = true; 10 | const auto it = this->error_page.find(code); 11 | if (it != this->error_page.end()) 12 | return this->create_file_task(it->second, ctx); 13 | } 14 | 15 | return WFTaskFactory::create_empty_task(); 16 | } 17 | 18 | void FileService::pread_callback(WFFileIOTask *task) 19 | { 20 | FileIOArgs *args = task->get_args(); 21 | long ret = task->get_retval(); 22 | struct ModuleCtx *ctx = (struct ModuleCtx *)series_of(task)->get_context(); 23 | protocol::HttpResponse *resp = ctx->resp; 24 | 25 | if (task->get_state() == WFT_STATE_SUCCESS) 26 | { 27 | resp->append_output_body_nocopy(args->buf, ret); 28 | } 29 | else 30 | { 31 | auto *error_task = this->create_error_task(503, ctx); 32 | series_of(task)->push_back(error_task); 33 | } 34 | } 35 | 36 | SubTask *FileService::create_file_task(const std::string& path, 37 | struct FileService::ModuleCtx *ctx) 38 | { 39 | SubTask *task; 40 | struct stat st; 41 | std::string abs_path = this->root + path; 42 | if (abs_path.back() == '/') 43 | abs_path += "index.html"; 44 | 45 | if (stat(abs_path.c_str(), &st) >= 0) 46 | { 47 | size_t size = st.st_size; 48 | void *buf = malloc(size); 49 | if (buf) 50 | { 51 | ctx->buf = buf; 52 | auto&& cb = std::bind(&FileService::pread_callback, 53 | this, std::placeholders::_1); 54 | task = WFTaskFactory::create_pread_task(abs_path, buf, size, 0, cb); 55 | } 56 | else 57 | { 58 | task = this->create_error_task(503, ctx); 59 | } 60 | } 61 | else 62 | { 63 | task = this->create_error_task(404, ctx); 64 | } 65 | 66 | return task; 67 | } 68 | 69 | WFModuleTask *FileService::create_module(WFHttpTask *server_task, 70 | const std::string& path) 71 | { 72 | fprintf(stderr, "file service get request: %s\n", path.c_str()); 73 | struct ModuleCtx *ctx = new ModuleCtx(server_task->get_resp()); 74 | SubTask *next = this->create_file_task(path, ctx); 75 | WFModuleTask *module = WFTaskFactory::create_module_task(next, 76 | [server_task](const WFModuleTask *mod) 77 | { 78 | struct ModuleCtx *ctx; 79 | ctx = (struct ModuleCtx *)mod->sub_series()->get_context(); 80 | void *buf = ctx->buf; 81 | server_task->set_callback([buf](WFHttpTask *t){ free(buf); }); 82 | delete ctx; 83 | }); 84 | 85 | module->sub_series()->set_context(ctx); 86 | return module; 87 | } 88 | 89 | void FileService::process(WFHttpTask *server_task) 90 | { 91 | protocol::HttpRequest *req = server_task->get_req(); 92 | protocol::HttpResponse *resp = server_task->get_resp(); 93 | std::string path = req->get_request_uri(); 94 | auto pos = path.find_first_of('?'); 95 | if (pos != std::string::npos) 96 | path = path.substr(0, pos); 97 | 98 | resp->add_header_pair("Server", "SRPC HTTP File Server"); 99 | 100 | WFModuleTask *module = this->create_module(server_task, path); 101 | series_of(server_task)->push_back(module); 102 | } 103 | -------------------------------------------------------------------------------- /docs/en/docs-05-context.md: -------------------------------------------------------------------------------- 1 | [中文版](/docs/docs-05-context.md) 2 | 3 | ## 05 - RPC Context 4 | 5 | - RPCContext is used specially to assist asynchronous interfaces, and can be used in both Service and Client. 6 | - Each asynchronous interface will provide a Context, which offers higher-level functions, such as obtaining the remote IP, the connection seqid, and so on. 7 | - Some functions on Context are unique to Server or Client. For example, you can set the compression mode of the response data on Server, and you can obtain the success or failure status of a request on Client. 8 | - On the Context, you can use ``get_series()`` to obtain the SeriesWork, which is seamlessly integrated with the asynchronous mode of Workflow. 9 | 10 | ### RPCContext API - Common 11 | 12 | #### `long long get_seqid() const;` 13 | 14 | One complete communication consists of request+response. The sequence id of the communication on the current socket connection can be obtained, and seqid=0 indicates the first communication. 15 | 16 | #### `std::string get_remote_ip() const;` 17 | 18 | Get the remote IP address. IPv4/IPv6 is supported. 19 | 20 | #### `int get_peer_addr(struct sockaddr *addr, socklen_t *addrlen) const;` 21 | 22 | Get the remote address. The in/out parameter is the lower-level data structure sockaddr. 23 | 24 | #### `const std::string& get_service_name() const;` 25 | 26 | Get RPC Service Name. 27 | 28 | #### `const std::string& get_method_name() const;` 29 | 30 | Get RPC Method Name. 31 | 32 | #### `SeriesWork *get_series() const;` 33 | 34 | Get the SeriesWork of the current ServerTask/ClientTask. 35 | 36 | ### RPCContext API - Only for client done 37 | 38 | #### `bool success() const;` 39 | 40 | For client only. The success or failure of the request. 41 | 42 | #### `int get_status_code() const;` 43 | 44 | For client only. The rpc status code of the request. 45 | 46 | #### `const char *get_errmsg() const;` 47 | 48 | For client only. The error info of the request. 49 | 50 | #### `int get_error() const;` 51 | 52 | For client only. The error code of the request. 53 | 54 | #### `void *get_user_data() const;` 55 | 56 | For client only. Get the user\_data of the ClientTask. If a user generates a task through the ``create_xxx_task()`` interface, the context can be recorded in the user_data field. You can set that field when creating the task, and retrieve it in the callback function. 57 | 58 | ### RPCContext API - Only for server process 59 | 60 | #### `void set_data_type(RPCDataType type);` 61 | 62 | For Server only. Set the data packaging type 63 | 64 | - RPCDataProtobuf 65 | - RPCDataThrift 66 | - RPCDataJson 67 | 68 | #### `void set_compress_type(RPCCompressType type);` 69 | 70 | For Server only. Set the data compression type (note: the compression type for the Client is set on Client or Task) 71 | 72 | - RPCCompressNone 73 | - RPCCompressSnappy 74 | - RPCCompressGzip 75 | - RPCCompressZlib 76 | - RPCCompressLz4 77 | 78 | #### `void set_attachment_nocopy(const char *attachment, size_t len);` 79 | 80 | For Server only. Set the attachment. 81 | 82 | #### `bool get_attachment(const char **attachment, size_t *len) const;` 83 | 84 | For Server only. Get the attachment. 85 | 86 | #### `void set_reply_callback(std::function cb);` 87 | 88 | For Server only. Set reply callback, which is called after the operating system successfully writes the data into the socket buffer. 89 | 90 | #### `void set_send_timeout(int timeout);` 91 | 92 | For Server only. Set the maximum time for sending the message, in milliseconds. -1 indicates unlimited time. 93 | 94 | #### `void set_keep_alive(int timeout);` 95 | For Server only. Set the maximum connection keep-alive time, in milliseconds. -1 indicates unlimited time. 96 | 97 | -------------------------------------------------------------------------------- /src/rpc_global.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2020 Sogou, Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | #ifdef _WIN32 18 | #include 19 | #else 20 | #include 21 | #include 22 | #include 23 | #endif 24 | 25 | #include 26 | #include 27 | #include "rpc_basic.h" 28 | #include "rpc_global.h" 29 | 30 | namespace srpc 31 | { 32 | 33 | SRPCGlobal::SRPCGlobal() : 34 | gen(rd()) 35 | { 36 | WFGlobal::register_scheme_port(SRPC_SCHEME, SRPC_DEFAULT_PORT); 37 | WFGlobal::register_scheme_port(SRPC_SSL_SCHEME, SRPC_SSL_DEFAULT_PORT); 38 | this->group_id = this->gen() % (1 << SRPC_GROUP_BITS); 39 | this->machine_id = this->gen() % (1 << SRPC_MACHINE_BITS); 40 | } 41 | 42 | static int __get_addr_info(const std::string& host, unsigned short port, 43 | struct sockaddr_storage *ss, socklen_t *ss_len) 44 | { 45 | if (!host.empty()) 46 | { 47 | char front = host.front(); 48 | char back = host.back(); 49 | 50 | if (host.find(':') != std::string::npos) 51 | { 52 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; 53 | 54 | memset(sin6, 0, sizeof (struct sockaddr_in6)); 55 | if (inet_pton(AF_INET6, host.c_str(), &sin6->sin6_addr) == 1) 56 | { 57 | sin6->sin6_family = AF_INET6; 58 | sin6->sin6_port = htons(port); 59 | *ss_len = sizeof (struct sockaddr_in6); 60 | return 0; 61 | } 62 | } 63 | else if (isdigit(back) && isdigit(front)) 64 | { 65 | struct sockaddr_in *sin = (struct sockaddr_in *)ss; 66 | 67 | memset(sin, 0, sizeof (struct sockaddr_in)); 68 | if (inet_pton(AF_INET, host.c_str(), &sin->sin_addr) == 1) 69 | { 70 | sin->sin_family = AF_INET; 71 | sin->sin_port = htons(port); 72 | *ss_len = sizeof (struct sockaddr_in); 73 | return 0; 74 | } 75 | } 76 | } 77 | 78 | return -1; 79 | } 80 | 81 | bool SRPCGlobal::task_init(RPCClientParams& params, ParsedURI& uri, 82 | struct sockaddr_storage *ss, socklen_t *ss_len) const 83 | { 84 | if (!params.host.empty()) 85 | { 86 | if (__get_addr_info(params.host, params.port, ss, ss_len) == 0) 87 | return true; 88 | 89 | if (params.is_ssl) 90 | uri.scheme = strdup(SRPC_SSL_SCHEME); 91 | else 92 | uri.scheme = strdup(SRPC_SCHEME); 93 | 94 | uri.host = strdup(params.host.c_str()); 95 | uri.port = strdup(std::to_string(params.port).c_str()); 96 | if (uri.scheme && uri.host && uri.port) 97 | uri.state = URI_STATE_SUCCESS; 98 | else 99 | { 100 | uri.state = URI_STATE_ERROR; 101 | uri.error = errno; 102 | } 103 | } 104 | else 105 | { 106 | URIParser::parse(params.url, uri); 107 | params.is_ssl = (uri.scheme && 108 | (strcasecmp(uri.scheme, "https") == 0 || 109 | strcasecmp(uri.scheme, "srpcs") == 0)); 110 | } 111 | 112 | return false; 113 | } 114 | 115 | unsigned long long SRPCGlobal::get_random() 116 | { 117 | unsigned long long id = 0; 118 | this->snowflake.get_id(this->group_id, this->machine_id, &id); 119 | return id; 120 | } 121 | 122 | static const SRPCGlobal *srpc_global = SRPCGlobal::get_instance(); 123 | 124 | } // namespace srpc 125 | 126 | --------------------------------------------------------------------------------