├── .cargo └── config.toml ├── .clang-format ├── .clang-tidy ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── something-else.md ├── PULL_REQUEST_TEMPLATE │ ├── bug_fix.md │ ├── feature.md │ └── something-else.md └── workflows │ ├── 31167.supp │ └── ci.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── LICENSE ├── README.md ├── benchmark ├── Cargo.toml ├── README.md └── src │ ├── bench.rs │ ├── client.rs │ ├── lib.rs │ ├── main.rs │ ├── server.rs │ ├── util.rs │ └── worker.rs ├── compiler ├── Cargo.toml └── src │ ├── bin │ ├── grpc_rust_plugin.rs │ └── grpc_rust_prost.rs │ ├── codegen.rs │ ├── lib.rs │ ├── prost_codegen.rs │ └── util.rs ├── cross_compile.md ├── grpc-sys ├── Cargo.toml ├── bindings │ └── bindings.rs ├── build.rs ├── grpc_wrap.cc ├── link-deps.rs └── src │ ├── grpc_wrap.rs │ └── lib.rs ├── health ├── Cargo.toml ├── README.md ├── src │ ├── lib.rs │ ├── proto.rs │ ├── proto │ │ ├── prost │ │ │ └── grpc.health.v1.rs │ │ ├── protobuf │ │ │ ├── health.rs │ │ │ └── health_grpc.rs │ │ └── protobuf_v3 │ │ │ ├── health.rs │ │ │ ├── health_grpc.rs │ │ │ └── mod.rs │ └── service.rs └── tests │ └── health_check.rs ├── interop ├── Cargo.toml ├── src │ ├── bin │ │ ├── client.rs │ │ └── server.rs │ ├── client.rs │ ├── lib.rs │ └── server.rs └── tests │ └── tests.rs ├── proto ├── Cargo.toml ├── data │ ├── ca.pem │ ├── server1.key │ └── server1.pem ├── proto │ ├── google │ │ ├── protobuf │ │ │ └── any.proto │ │ └── rpc │ │ │ └── status.proto │ └── grpc │ │ ├── example │ │ ├── helloworld.proto │ │ └── route_guide.proto │ │ ├── health │ │ └── v1 │ │ │ └── health.proto │ │ └── testing │ │ ├── control.proto │ │ ├── empty.proto │ │ ├── messages.proto │ │ ├── payloads.proto │ │ ├── services.proto │ │ ├── stats.proto │ │ └── test.proto └── src │ ├── lib.rs │ ├── proto.rs │ ├── proto │ ├── prost │ │ ├── example │ │ │ ├── helloworld.rs │ │ │ └── routeguide.rs │ │ ├── google │ │ │ └── rpc │ │ │ │ └── google.rpc.rs │ │ └── testing │ │ │ └── grpc.testing.rs │ ├── protobuf │ │ ├── example │ │ │ ├── helloworld.rs │ │ │ ├── helloworld_grpc.rs │ │ │ ├── route_guide.rs │ │ │ └── route_guide_grpc.rs │ │ ├── google │ │ │ └── rpc │ │ │ │ └── status.rs │ │ └── testing │ │ │ ├── control.rs │ │ │ ├── empty.rs │ │ │ ├── messages.rs │ │ │ ├── payloads.rs │ │ │ ├── services.rs │ │ │ ├── services_grpc.rs │ │ │ ├── stats.rs │ │ │ ├── test.rs │ │ │ └── test_grpc.rs │ └── protobuf_v3 │ │ ├── example │ │ ├── helloworld.rs │ │ ├── helloworld_grpc.rs │ │ ├── mod.rs │ │ ├── route_guide.rs │ │ └── route_guide_grpc.rs │ │ ├── google │ │ └── rpc │ │ │ ├── mod.rs │ │ │ └── status.rs │ │ └── testing │ │ ├── control.rs │ │ ├── empty.rs │ │ ├── messages.rs │ │ ├── mod.rs │ │ ├── payloads.rs │ │ ├── services.rs │ │ ├── services_grpc.rs │ │ ├── stats.rs │ │ ├── test.rs │ │ └── test_grpc.rs │ └── util.rs ├── src ├── buf.rs ├── call │ ├── client.rs │ ├── mod.rs │ └── server.rs ├── channel.rs ├── channelz.rs ├── client.rs ├── codec.rs ├── cq.rs ├── env.rs ├── error.rs ├── lib.rs ├── log_util.rs ├── metadata.rs ├── quota.rs ├── security │ ├── auth_context.rs │ ├── credentials.rs │ └── mod.rs ├── server.rs └── task │ ├── callback.rs │ ├── executor.rs │ ├── mod.rs │ └── promise.rs ├── tests-and-examples ├── Cargo.toml ├── examples │ ├── hello_world │ │ ├── client.rs │ │ └── server.rs │ ├── load_balancing │ │ ├── client.rs │ │ └── server.rs │ ├── log_util.rs │ └── route_guide │ │ ├── client.rs │ │ ├── db.json │ │ ├── server.rs │ │ └── util.rs ├── src │ ├── lib.rs │ └── util.rs └── tests │ ├── cases │ ├── auth_context.rs │ ├── cancel.rs │ ├── credential.rs │ ├── kick.rs │ ├── metadata.rs │ ├── misc.rs │ ├── mod.rs │ └── stream.rs │ └── tests.rs └── xtask ├── Cargo.toml └── src └── main.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | xtask = "run --manifest-path ./xtask/Cargo.toml --" 3 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | grpc-sys/grpc/.clang-format -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | grpc-sys/grpc/.clang-tidy -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Found a bug? Help us squash it! 4 | --- 5 | 6 | **Describe the bug** 7 | A clear and concise description of what the bug is. 8 | 9 | **To Reproduce** 10 | Steps to reproduce the behavior: 11 | 1. Go to '...' 12 | 2. Click on '....' 13 | 3. Scroll down to '....' 14 | 4. See error 15 | 16 | **Expected behavior** 17 | A clear and concise description of what you expected to happen. 18 | 19 | **System information** 20 | * CPU architecture: 21 | * Distribution and kernel version: 22 | * SELinux on?: 23 | * Any other system details we should know?: 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Help us develop our roadmap and direction. 4 | --- 5 | 6 | **Is your feature request related to a problem? Please describe.** 7 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 8 | 9 | **Describe the solution you'd like** 10 | A clear and concise description of what you want to happen. 11 | 12 | **Describe alternatives you've considered** 13 | A clear and concise description of any alternative solutions or features you've considered. 14 | 15 | **Additional context** 16 | Add any other context or screenshots about the feature request here. 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/something-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Something Else 3 | about: Just give me a text box! 4 | --- 5 | 6 | 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/bug_fix.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug fix 3 | about: A bug squashed. 4 | 5 | --- 6 | 7 | **Related bugs:** 8 | This bug fix closes issue #???. 9 | 10 | **Description of problem:** 11 | Describe what was causing the related issue to happen. 12 | 13 | **Description of solution:** 14 | Describe the rationale behind the fix. 15 | 16 | **Checklist:** 17 | The CI will check all of these, but you'll need to have done them: 18 | 19 | * [ ] `cargo fmt -- --check` passes. 20 | * [ ] `cargo +nightly clippy` has no warnings. 21 | * [ ] `cargo test` passes. 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature 3 | about: The dawn of a new era. 4 | 5 | --- 6 | 7 | **Related features:** 8 | This feature resolves issue #???. 9 | 10 | **Description of feature:** 11 | A short description of the feature implemented. 12 | 13 | **Implementation:** 14 | Describe any pieces of the implementation that deserve further explanation. 15 | Detail any gotchas, uncertainties, or open questions about the implementation. 16 | 17 | **Checklist:** 18 | 19 | The CI will check all of these, but you'll need to have done them: 20 | 21 | * [ ] `cargo fmt -- --check` passes. 22 | * [ ] `cargo +nightly clippy` has no warnings. 23 | * [ ] `cargo test` passes. 24 | 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/something-else.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Something Else 3 | about: Just give me a text box! 4 | 5 | --- 6 | 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/31167.supp: -------------------------------------------------------------------------------- 1 | interceptor_via_fun:grpc_error_set_str 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | - v0.* 9 | schedule: 10 | - cron: '0 22 * * *' 11 | 12 | env: 13 | RUST_BACKTRACE: 1 14 | # Some of the bindgen tests generate "deref-nullptr" warnings, see https://github.com/rust-lang/rust-bindgen/issues/1651 15 | RUSTFLAGS: "--deny=warnings --allow deref-nullptr" 16 | TEST_BIND: 1 17 | GRPC_VERBOSITY: "info" 18 | 19 | jobs: 20 | Linux-Format: 21 | name: Linux-Format 22 | runs-on: ubuntu-latest 23 | steps: 24 | - uses: actions/checkout@v2 25 | - run: which cargo && cargo version && clang --version && openssl version && which cmake && cmake --version 26 | - run: cargo xtask submodule 27 | - run: cargo fmt --all -- --check 28 | - run: cargo clippy --all -- -D clippy::all && cargo clippy --all --no-default-features --features prost-codec -- -D clippy::all 29 | - run: cargo xtask clang-lint && git diff-index --quiet HEAD 30 | 31 | Linux-Stable: 32 | strategy: 33 | matrix: 34 | include: 35 | - host: ubuntu-latest 36 | profile: 37 | suffix: 38 | name: Linux-Stable${{ matrix.suffix }} 39 | runs-on: ${{ matrix.host }} 40 | steps: 41 | - uses: actions/checkout@v2 42 | - run: sudo apt install -y protobuf-compiler 43 | - run: which cargo && cargo version && clang --version && openssl version 44 | - run: cargo xtask submodule 45 | - run: env TEST_BIND=0 cargo xtask bindgen && git diff --exit-code HEAD 46 | - run: cargo xtask codegen && git diff --exit-code HEAD; 47 | - run: cargo xtask bindgen 48 | - run: cargo build --no-default-features 49 | - run: cargo build --no-default-features --features protobuf-codec 50 | - run: cargo build --no-default-features --features protobufv3-codec 51 | - run: cargo build --no-default-features --features prost-codec 52 | - run: cd proto && cargo build --no-default-features --features prost-codec 53 | - run: cargo build 54 | - run: cargo test --all ${{ matrix.profile }} 55 | 56 | Linux-Stable-openssl: 57 | strategy: 58 | matrix: 59 | include: 60 | - host: ubuntu-latest 61 | profile: 62 | suffix: 63 | name: Linux-Stable-openssl${{ matrix.suffix }} 64 | runs-on: ${{ matrix.host }} 65 | steps: 66 | - uses: actions/checkout@v2 67 | - run: which cargo && cargo version && clang --version && openssl version 68 | - run: cargo xtask submodule 69 | - run: cargo test --features "openssl-vendored" --all ${{ matrix.profile }} 70 | - run: cargo clean 71 | - run: cargo test --features "openssl" --all ${{ matrix.profile }} 72 | 73 | Linux-Nightly: 74 | name: Linux-Nightly 75 | runs-on: ubuntu-latest 76 | steps: 77 | - uses: actions/checkout@v2 78 | - run: rustup default nightly 79 | - run: sudo ln -s /usr/bin/llvm-symbolizer-14 /usr/bin/llvm-symbolizer 80 | - run: which cargo && cargo version && clang --version && openssl version 81 | - run: cargo xtask submodule 82 | - run: cargo build --no-default-features 83 | - run: cargo build --no-default-features --features protobuf-codec 84 | - run: cargo build --no-default-features --features protobufv3-codec 85 | - run: cargo build --no-default-features --features prost-codec 86 | - run: cargo build 87 | - run: cargo test --all 88 | # See https://github.com/grpc/grpc/pull/31167 89 | - run: RUSTFLAGS="-Z sanitizer=address" ASAN_OPTIONS=suppressions=`pwd`/.github/workflows/31167.supp cargo test --all --target x86_64-unknown-linux-gnu 90 | - run: cargo test --features "nightly" 91 | 92 | Mac: 93 | name: Mac 94 | runs-on: macos-latest 95 | steps: 96 | - uses: actions/checkout@v2 97 | - run: which cargo && cargo version && clang --version && openssl version 98 | - run: cargo xtask submodule 99 | - run: env TEST_BIND=0 cargo xtask bindgen && git diff --exit-code HEAD 100 | - run: cargo xtask bindgen 101 | - run: cargo build --no-default-features 102 | - run: cargo build --no-default-features --features "protobuf-codec" 103 | - run: cargo build --no-default-features --features "protobufv3-codec" 104 | - run: cargo build --no-default-features --features "prost-codec" 105 | - run: cargo build 106 | - run: cargo test --all 107 | - run: cargo test --features "nightly" 108 | 109 | Mac-openssl: 110 | name: Mac-openssl 111 | runs-on: macos-latest 112 | steps: 113 | - uses: actions/checkout@v2 114 | - run: brew update && brew upgrade openssl@1.1 115 | - run: which cargo && cargo version && clang --version && openssl version 116 | - run: cargo xtask submodule 117 | - run: OPENSSL_ROOT_DIR="/usr/local/opt/openssl@1.1/" cargo test --features "openssl" --all 118 | - run: cargo test --features "openssl-vendored" --all 119 | 120 | Win: 121 | name: Windows 122 | runs-on: windows-latest 123 | env: 124 | LIBCLANG_PATH: 'C:\Program Files\LLVM\bin' 125 | RUSTFLAGS: "" 126 | steps: 127 | - uses: actions/checkout@v2 128 | - run: choco install -y llvm 129 | - run: Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1 130 | - run: go version ; cargo version ; cmake --version 131 | - run: cargo xtask submodule 132 | - run: cargo build 133 | - run: cargo test --all 134 | - run: cargo test --features "nightly" 135 | 136 | Pre-Release: 137 | name: Pre-Release 138 | runs-on: ubuntu-latest 139 | steps: 140 | - uses: actions/checkout@v2 141 | - run: cargo xtask submodule 142 | - run: cd grpc-sys && cargo publish --dry-run 143 | - name: Check generated package size 144 | run: | 145 | ls -alh target/package/grpcio-sys-*.crate 146 | test `cat target/package/grpcio-sys-*.crate | wc -c` -le 10485760 147 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | *.rs.bk 4 | *.rs.fmt 5 | .vscode 6 | .idea 7 | *.o 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "grpc-sys/grpc"] 2 | path = grpc-sys/grpc 3 | url = https://github.com/pingcap/grpc.git 4 | branch = rs-release 5 | -------------------------------------------------------------------------------- /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 both within project spaces and in public spaces when an individual is representing the project or its community. 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 coc@pingcap.com. The project team will review and investigate all complaints, and will respond in a way that it deems 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 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "grpcio" 3 | version = "0.13.0" 4 | edition = "2018" 5 | authors = ["The TiKV Project Developers"] 6 | license = "Apache-2.0" 7 | keywords = ["grpc", "protobuf", "rpc", "tls", "http2"] 8 | repository = "https://github.com/tikv/grpc-rs" 9 | readme = "README.md" 10 | homepage = "https://github.com/tikv/grpc-rs" 11 | documentation = "https://docs.rs/grpcio" 12 | description = "The rust language implementation of gRPC, base on the gRPC c core library." 13 | categories = ["asynchronous", "network-programming"] 14 | autoexamples = false 15 | 16 | [package.metadata.docs.rs] 17 | all-features = true 18 | 19 | [dependencies] 20 | grpcio-sys = { path = "grpc-sys", version = "0.13.0", default-features = false } 21 | libc = "0.2" 22 | futures-executor = "0.3" 23 | futures-util = { version = "0.3", default-features = false, features = ["std", "sink"] } 24 | protobuf = { version = "2.0", optional = true } 25 | protobufv3 = { package = "protobuf", version = "3.2", optional = true } 26 | prost = { version = "0.13", optional = true } 27 | bytes = { version = "1.0", optional = true } 28 | log = "0.4" 29 | parking_lot = "0.12" 30 | 31 | [workspace] 32 | members = [ 33 | "proto", 34 | "benchmark", 35 | "compiler", 36 | "health", 37 | "interop", 38 | "tests-and-examples", 39 | ] 40 | # Don't include it in workspace to make it possible to use different version of 41 | # rust-protobuf. 42 | exclude = ["xtask"] 43 | 44 | [features] 45 | default = ["protobuf-codec", "boringssl"] 46 | _secure = [] 47 | protobuf-codec = ["protobuf"] 48 | protobufv3-codec = ["protobufv3"] 49 | prost-codec = ["prost", "bytes"] 50 | nightly = [] 51 | boringssl = ["grpcio-sys/boringssl", "_secure"] 52 | openssl = ["_secure", "grpcio-sys/openssl"] 53 | openssl-vendored = ["_secure", "grpcio-sys/openssl-vendored"] 54 | no-omit-frame-pointer = ["grpcio-sys/no-omit-frame-pointer"] 55 | 56 | [badges] 57 | travis-ci = { repository = "tikv/grpc-rs" } 58 | 59 | [patch.crates-io] 60 | grpcio-compiler = { path = "compiler", version = "0.13.0" } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gRPC-rs 2 | 3 | `gRPC-rs` is a Rust wrapper of [gRPC Core](https://github.com/grpc/grpc). [gRPC](http://www.grpc.io) is a high performance, open source universal RPC framework that puts mobile and HTTP/2 first. 4 | 5 | [![Crates.io](https://img.shields.io/crates/v/grpcio.svg?maxAge=2592000)](https://crates.io/crates/grpcio) 6 | [![docs.rs](https://docs.rs/grpcio/badge.svg)](https://docs.rs/grpcio) 7 | [![Build Status](https://github.com/tikv/grpc-rs/workflows/CI/badge.svg)](https://github.com/tikv/grpc-rs/actions) 8 | [![Build Status](https://travis-ci.org/tikv/grpc-rs.svg)](https://travis-ci.org/tikv/grpc-rs) 9 | 10 | ## Status 11 | 12 | This project is still under development. The following features with the check marks are supported: 13 | 14 | - [x] Basic asynchronous unary/steaming call 15 | - [x] SSL 16 | - [x] Generic call 17 | - [x] Connection level compression 18 | - [x] Interoperability test 19 | - [x] QPS benchmark 20 | - [ ] Custom metadata 21 | - [x] Health check 22 | - [ ] Reflection 23 | - [X] Authentication 24 | - [ ] Load balance, client side is fully supported, server side load report is not implemented yet. 25 | 26 | ## Prerequisites 27 | 28 | - CMake >= 3.8.0 29 | - Rust >= 1.36.0 30 | - binutils >= 2.22 31 | - LLVM and Clang >= 3.9 if you need to generate bindings at compile time. 32 | 33 | For Linux and MacOS, you also need to install gcc 7.3+ (or clang 6+) too. 34 | 35 | Bindings are pre-generated for x86_64/arm64 Linux. For other platforms, bindings are generated at compile time. 36 | 37 | For Windows, you also need to install following software: 38 | 39 | - Active State Perl 40 | - yasm 41 | - Visual Studio 2015+ 42 | 43 | ## Build 44 | 45 | ``` 46 | $ cargo xtask submodule # if you just cloned the repository 47 | $ cargo build 48 | ``` 49 | 50 | ### Error linking OpenSSL 51 | 52 | If you're getting linker errors when building your project using `gRPC-rs`, head 53 | down to the `openssl` feature section for a possible fix. 54 | 55 | ## Usage 56 | 57 | To generate the sources from proto files: 58 | 59 | ### Option 1 - Manual Generation 60 | 61 | 1. Install the protobuf compiler: 62 | 63 | ``` 64 | $ cargo install protobuf-codegen 65 | ``` 66 | 67 | 2. Install the gRPC compiler: 68 | 69 | ``` 70 | $ cargo install grpcio-compiler 71 | ``` 72 | 73 | 3. Generate the sources: 74 | 75 | ``` 76 | $ protoc --rust_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_rust_plugin` example.proto 77 | ``` 78 | 79 | 80 | ### Option 2 - Programmatic Generation 81 | 82 | Programmatic generation can be used to generate Rust modules from proto files 83 | via your `build.rs` by using [protoc-grpcio](https://crates.io/crates/protoc-grpcio). 84 | 85 | For more information and examples see 86 | [README](https://github.com/mtp401/protoc-grpcio/blob/master/README.md). 87 | 88 | To include this project as a dependency: 89 | 90 | ``` 91 | [dependencies] 92 | grpcio = "0.13" 93 | ``` 94 | 95 | ### Feature `boringssl` 96 | 97 | `boringssl` feature enables support for TLS encryption and some authentication 98 | mechanism. When you do not need it, for example when working in intranet, 99 | you can disable it by using the following configuration: 100 | ``` 101 | [dependencies] 102 | grpcio = { version = "0.13", default-features = false, features = ["protobuf-codec"] } 103 | ``` 104 | 105 | ### Feature `prost-codec` and `protobuf-codec` 106 | 107 | `gRPC-rs` uses `protobuf` crate by default. If you want to use `prost` instead, you can enable 108 | `prost-codec` feature. You probably only want to enable only one of the two features. Though 109 | grpcio is completely fine with both features enabled at the same time, grpcio-compiler 110 | will not going to work as expected. 111 | 112 | ### Feature `openssl` and `openssl-vendored` 113 | 114 | `gRPC-rs` comes vendored with `gRPC Core`, which by default uses BoringSSL 115 | instead of OpenSSL. This may cause linking issues due to symbol clashes and/or 116 | missing symbols when another one of your dependencies uses OpenSSL. To resolve 117 | this, you can tell `gRPC-rs` to use OpenSSL too by specifying `"openssl"` in 118 | your `Cargo.toml`'s features list for `gprcio`, which requires openssl (>=1.0.2). E.g.: 119 | 120 | ```toml 121 | [dependencies] 122 | grpcio = { version = "0.13", features = ["openssl"] } 123 | ``` 124 | 125 | Feature `openssl-vendored` is the same as feature `openssl` except it will build openssl from 126 | bundled sources. 127 | 128 | ## Performance 129 | 130 | See [benchmark](https://github.com/tikv/grpc-rs/tree/master/benchmark) to find out how to run a benchmark by yourself. 131 | 132 | Cross Compile 133 | ------------- 134 | See [cross_compile](cross_compile.md) 135 | 136 | Contributing 137 | ------------ 138 | 139 | Make sure to format and test the code before sending a PR. 140 | 141 | If the content in grpc-sys/grpc is updated, you may need to regenerate bindings: 142 | 143 | ``` 144 | $ cargo xtask bindgen 145 | ``` 146 | -------------------------------------------------------------------------------- /benchmark/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "benchmark" 3 | version = "0.1.0" 4 | edition = "2018" 5 | publish = false 6 | 7 | [features] 8 | default = ["protobuf-codec"] 9 | protobuf-codec = ["grpcio/protobuf-codec", "grpcio-proto/protobuf-codec", "dep:protobuf"] 10 | protobufv3-codec = ["grpcio/protobufv3-codec", "grpcio-proto/protobufv3-codec", "dep:protobufv3"] 11 | prost-codec = ["grpcio/prost-codec", "grpcio-proto/prost-codec"] 12 | 13 | [dependencies] 14 | grpcio = { path = "..", default-features = false, features = ["boringssl"] } 15 | grpcio-proto = { path = "../proto", default-features = false } 16 | futures-channel = "0.3" 17 | futures-executor = "0.3" 18 | futures-util = { version = "0.3", default-features = false, features = ["std", "sink"] } 19 | libc = "0.2" 20 | grpcio-sys = { path = "../grpc-sys" } 21 | rand = "0.8" 22 | rand_distr = "0.4" 23 | rand_xorshift = "0.3" 24 | futures-timer = "3.0" 25 | clap = "4.5" 26 | log = "0.4" 27 | slog = "2.0" 28 | slog-async = "2.1" 29 | slog-stdlog = "4.0" 30 | slog-scope = "4.0" 31 | slog-term = "2.2" 32 | protobuf = { version = "2", optional = true } 33 | protobufv3 = { package = "protobuf", version = "3.2", optional = true } 34 | 35 | [[bin]] 36 | name = "qps_worker" 37 | path = "src/main.rs" 38 | -------------------------------------------------------------------------------- /benchmark/README.md: -------------------------------------------------------------------------------- 1 | For benchmark design details, see [benchmarking](http://www.grpc.io/docs/guides/benchmarking.html). 2 | 3 | Quick Start 4 | =========== 5 | 6 | 1. Clone grpc-rs 7 | 8 | ``` 9 | $ git clone https://github.com/tikv/grpc-rs.git 10 | ``` 11 | 12 | 2. Clone grpc 13 | 14 | ``` 15 | $ git clone https://github.com/pingcap/grpc.git 16 | ``` 17 | 18 | 3. Build benchmark 19 | 20 | ``` 21 | $ cd grpc-rs 22 | $ cargo xtask submodule 23 | $ cargo build -p benchmark --release 24 | ``` 25 | 26 | 4. Run benchmark 27 | 28 | ``` 29 | $ cd ../grpc 30 | $ python3 tools/run_tests/run_performance_tests.py -l rust 31 | ``` 32 | 33 | Checkout `python3 tools/run_tests/run_performance_tests.py --help` to see custom options. 34 | 35 | Flame Graph 36 | =========== 37 | 38 | To generate flame graph, please download FrameGraph release package and extract them in grpc directory. 39 | Please make sure the name of extracted directory is FlameGraph. Then run following command: 40 | 41 | ``` 42 | # python3 tools/run_tests/run_performance_tests.py -l rust --perf_args="record -F 99 -g" 43 | ``` 44 | -------------------------------------------------------------------------------- /benchmark/src/bench.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #![allow(renamed_and_removed_lints)] 4 | 5 | use std::io::Read; 6 | use std::sync::atomic::{AtomicBool, Ordering}; 7 | use std::sync::Arc; 8 | 9 | use futures_util::{ 10 | FutureExt as _, SinkExt as _, StreamExt as _, TryFutureExt as _, TryStreamExt as _, 11 | }; 12 | use grpc::{ 13 | self, ClientStreamingSink, DuplexSink, MessageReader, Method, MethodType, RequestStream, 14 | RpcContext, ServiceBuilder, UnarySink, WriteFlags, 15 | }; 16 | use grpc_proto::testing::messages::{SimpleRequest, SimpleResponse}; 17 | use grpc_proto::testing::services_grpc::BenchmarkService; 18 | use grpc_proto::util; 19 | use grpcio::GrpcSlice; 20 | 21 | fn gen_resp(req: &SimpleRequest) -> SimpleResponse { 22 | let payload = util::new_payload(req.response_size as usize); 23 | SimpleResponse { 24 | payload: Some(payload).into(), 25 | ..SimpleResponse::default() 26 | } 27 | } 28 | 29 | #[derive(Clone)] 30 | pub struct Benchmark { 31 | pub keep_running: Arc, 32 | } 33 | 34 | impl BenchmarkService for Benchmark { 35 | fn unary_call(&mut self, ctx: RpcContext, req: SimpleRequest, sink: UnarySink) { 36 | let f = sink.success(gen_resp(&req)); 37 | let keep_running = self.keep_running.clone(); 38 | spawn!(ctx, keep_running, "unary", f) 39 | } 40 | 41 | fn streaming_call( 42 | &mut self, 43 | ctx: RpcContext, 44 | stream: RequestStream, 45 | mut sink: DuplexSink, 46 | ) { 47 | let f = async move { 48 | sink.send_all( 49 | &mut stream.map(|req| req.map(|req| (gen_resp(&req), WriteFlags::default()))), 50 | ) 51 | .await?; 52 | sink.close().await?; 53 | Ok(()) 54 | }; 55 | let keep_running = self.keep_running.clone(); 56 | spawn!(ctx, keep_running, "streaming", f) 57 | } 58 | 59 | fn streaming_from_client( 60 | &mut self, 61 | ctx: RpcContext, 62 | mut stream: RequestStream, 63 | sink: ClientStreamingSink, 64 | ) { 65 | let f = async move { 66 | let mut req = SimpleRequest::default(); 67 | while let Some(r) = stream.try_next().await? { 68 | req = r; 69 | } 70 | sink.success(gen_resp(&req)); 71 | Ok(()) 72 | }; 73 | let keep_running = self.keep_running.clone(); 74 | spawn!(ctx, keep_running, "streaming from client", f) 75 | } 76 | } 77 | 78 | #[derive(Clone)] 79 | pub struct Generic { 80 | pub keep_running: Arc, 81 | } 82 | 83 | impl Generic { 84 | pub fn streaming_call( 85 | &self, 86 | ctx: &RpcContext, 87 | stream: RequestStream>, 88 | mut sink: DuplexSink>, 89 | ) { 90 | let f = async move { 91 | sink.send_all(&mut stream.map(|req| req.map(|req| (req, WriteFlags::default())))) 92 | .await?; 93 | sink.close().await?; 94 | Ok(()) 95 | }; 96 | let keep_running = self.keep_running.clone(); 97 | spawn!(ctx, keep_running, "streaming", f) 98 | } 99 | } 100 | 101 | #[inline] 102 | #[allow(clippy::ptr_arg)] 103 | pub fn bin_ser(t: &Vec, buf: &mut GrpcSlice) -> grpc::Result<()> { 104 | unsafe { 105 | let bytes = buf.realloc(t.len()); 106 | let b = &mut *(bytes as *mut [std::mem::MaybeUninit] as *mut [u8]); 107 | b.copy_from_slice(t); 108 | } 109 | Ok(()) 110 | } 111 | 112 | #[inline] 113 | pub fn bin_de(mut reader: MessageReader) -> grpc::Result> { 114 | let mut buf = vec![]; 115 | reader.read_to_end(&mut buf).unwrap(); 116 | Ok(buf) 117 | } 118 | 119 | pub const METHOD_BENCHMARK_SERVICE_GENERIC_CALL: Method, Vec> = Method { 120 | ty: MethodType::Duplex, 121 | name: "/grpc.testing.BenchmarkService/StreamingCall", 122 | req_mar: crate::grpc::Marshaller { 123 | ser: bin_ser, 124 | de: bin_de, 125 | }, 126 | resp_mar: crate::grpc::Marshaller { 127 | ser: bin_ser, 128 | de: bin_de, 129 | }, 130 | }; 131 | 132 | pub fn create_generic_service(s: Generic) -> crate::grpc::Service { 133 | ServiceBuilder::new() 134 | .add_duplex_streaming_handler( 135 | &METHOD_BENCHMARK_SERVICE_GENERIC_CALL, 136 | move |ctx, req, resp| s.streaming_call(&ctx, req, resp), 137 | ) 138 | .build() 139 | } 140 | -------------------------------------------------------------------------------- /benchmark/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #![allow(unknown_lints)] 4 | 5 | extern crate grpcio as grpc; 6 | extern crate grpcio_proto as grpc_proto; 7 | extern crate grpcio_sys as grpc_sys; 8 | #[cfg(target_os = "linux")] 9 | extern crate libc; 10 | #[macro_use] 11 | extern crate log; 12 | 13 | // Since impl trait is not stable yet, implement this as a function is impossible without box. 14 | macro_rules! spawn { 15 | ($exec:ident, $keep_running:expr, $tag:expr, $f:expr) => { 16 | $exec.spawn( 17 | $f.map_err(move |e: grpcio::Error| { 18 | if $keep_running.load(Ordering::SeqCst) { 19 | error!("failed to execute {}: {:?}", $tag, e); 20 | } 21 | }) 22 | .map(|_| ()), 23 | ) 24 | }; 25 | } 26 | 27 | mod bench; 28 | mod client; 29 | mod server; 30 | mod util; 31 | mod worker; 32 | 33 | pub use crate::util::log_util::init_log; 34 | pub use crate::worker::Worker; 35 | -------------------------------------------------------------------------------- /benchmark/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | extern crate grpcio as grpc; 4 | extern crate grpcio_proto as grpc_proto; 5 | #[macro_use] 6 | extern crate log; 7 | 8 | use std::env; 9 | use std::sync::Arc; 10 | 11 | use benchmark::{init_log, Worker}; 12 | use clap::Parser; 13 | use futures_channel::oneshot; 14 | use grpc::{Environment, ServerBuilder, ServerCredentials}; 15 | use grpc_proto::testing::services_grpc::create_worker_service; 16 | use rand::Rng; 17 | 18 | const LOG_FILE: &str = "GRPCIO_BENCHMARK_LOG_FILE"; 19 | 20 | /// Benchmark QpsWorker 21 | /// 22 | /// ref http://www.grpc.io/docs/guides/benchmarking.html. 23 | #[derive(Parser)] 24 | struct WorkerCli { 25 | /// The port the worker should listen on. For example, 8080 26 | #[arg(long)] 27 | driver_port: Option, 28 | } 29 | 30 | fn main() { 31 | let cli = WorkerCli::parse(); 32 | let port = cli.driver_port.unwrap_or(8080); 33 | 34 | let _log_guard = init_log( 35 | env::var(LOG_FILE) 36 | .ok() 37 | .map(|lf| format!("{}.{}", lf, rand::thread_rng().gen::())), 38 | ); 39 | let env = Arc::new(Environment::new(2)); 40 | let (tx, rx) = oneshot::channel(); 41 | let worker = Worker::new(tx); 42 | let service = create_worker_service(worker); 43 | let mut server = ServerBuilder::new(env) 44 | .register_service(service) 45 | .build() 46 | .unwrap(); 47 | let port = server 48 | .add_listening_port(format!("[::]:{port}"), ServerCredentials::insecure()) 49 | .unwrap(); 50 | 51 | info!("listening on [::]:{}", port); 52 | 53 | server.start(); 54 | 55 | let _ = futures_executor::block_on(rx); 56 | let _ = futures_executor::block_on(server.shutdown()); 57 | } 58 | -------------------------------------------------------------------------------- /benchmark/src/server.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::ffi::CString; 4 | use std::sync::atomic::{AtomicBool, Ordering}; 5 | use std::sync::Arc; 6 | 7 | use grpc::ServerCredentials; 8 | use grpc_proto::testing::control::{ServerConfig, ServerStatus, ServerType}; 9 | use grpc_proto::testing::services_grpc::create_benchmark_service; 10 | use grpc_proto::testing::stats::ServerStats; 11 | use grpc_proto::util as proto_util; 12 | use grpcio::{ 13 | ChannelBuilder, EnvBuilder, Result, Server as GrpcServer, ServerBuilder, ShutdownFuture, 14 | }; 15 | 16 | use crate::bench::{self, Benchmark, Generic}; 17 | use crate::util::{self, CpuRecorder}; 18 | 19 | pub struct Server { 20 | server: GrpcServer, 21 | port: u16, 22 | recorder: CpuRecorder, 23 | keep_running: Arc, 24 | } 25 | 26 | impl Server { 27 | #[allow(clippy::new_ret_no_self)] 28 | pub fn new(cfg: &ServerConfig) -> Result { 29 | #[cfg(feature = "protobuf-codec")] 30 | let server_type = cfg.server_type; 31 | #[cfg(feature = "protobufv3-codec")] 32 | let server_type = cfg.server_type.enum_value().unwrap(); 33 | 34 | let mut builder = EnvBuilder::new(); 35 | let thd_cnt = cfg.async_server_threads as usize; 36 | if thd_cnt != 0 { 37 | builder = builder.cq_count(thd_cnt); 38 | } 39 | let env = Arc::new(builder.build()); 40 | if cfg.core_limit > 0 { 41 | warn!("server config core limit is set but ignored"); 42 | } 43 | let keep_running = Arc::new(AtomicBool::new(true)); 44 | let keep_running1 = keep_running.clone(); 45 | let service = match server_type { 46 | ServerType::ASYNC_SERVER => { 47 | let b = Benchmark { keep_running }; 48 | create_benchmark_service(b) 49 | } 50 | ServerType::ASYNC_GENERIC_SERVER => { 51 | let g = Generic { keep_running }; 52 | bench::create_generic_service(g) 53 | } 54 | _ => unimplemented!(), 55 | }; 56 | let mut builder = ServerBuilder::new(env.clone()).register_service(service); 57 | if !cfg.channel_args.is_empty() { 58 | let mut ch_builder = ChannelBuilder::new(env); 59 | for arg in &cfg.channel_args { 60 | let key = CString::new(arg.name.clone()).unwrap(); 61 | if arg.has_str_value() { 62 | #[cfg(feature = "protobuf-codec")] 63 | let val = CString::new(arg.get_str_value()).unwrap(); 64 | #[cfg(feature = "protobufv3-codec")] 65 | let val = CString::new(arg.str_value()).unwrap(); 66 | ch_builder = ch_builder.raw_cfg_string(key, val); 67 | } else if arg.has_int_value() { 68 | #[cfg(feature = "protobuf-codec")] 69 | let val = arg.get_int_value(); 70 | #[cfg(feature = "protobufv3-codec")] 71 | let val = arg.int_value(); 72 | ch_builder = ch_builder.raw_cfg_int(key, val); 73 | } 74 | } 75 | builder = builder.channel_args(ch_builder.build_args()); 76 | } 77 | let mut s = builder.build().unwrap(); 78 | 79 | #[cfg(feature = "protobuf-codec")] 80 | let has_security_param = cfg.has_security_params(); 81 | #[cfg(feature = "protobufv3-codec")] 82 | let has_security_param = cfg.security_params.0.is_some(); 83 | let creds = if has_security_param { 84 | proto_util::create_test_server_credentials() 85 | } else { 86 | ServerCredentials::insecure() 87 | }; 88 | let port = s 89 | .add_listening_port(format!("[::]:{}", cfg.port), creds) 90 | .unwrap(); 91 | s.start(); 92 | Ok(Server { 93 | server: s, 94 | port, 95 | recorder: CpuRecorder::new(), 96 | keep_running: keep_running1, 97 | }) 98 | } 99 | 100 | pub fn get_stats(&mut self, reset: bool) -> ServerStats { 101 | let sample = self.recorder.cpu_time(reset); 102 | ServerStats { 103 | time_elapsed: sample.real_time, 104 | time_user: sample.user_time, 105 | time_system: sample.sys_time, 106 | total_cpu_time: sample.total_cpu, 107 | idle_cpu_time: sample.idle_cpu, 108 | ..ServerStats::default() 109 | } 110 | } 111 | 112 | pub fn shutdown(&mut self) -> ShutdownFuture { 113 | self.keep_running.store(false, Ordering::SeqCst); 114 | self.server.shutdown() 115 | } 116 | 117 | pub fn get_status(&self) -> ServerStatus { 118 | ServerStatus { 119 | port: self.port as i32, 120 | cores: util::cpu_num_cores() as i32, 121 | ..ServerStatus::default() 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /benchmark/src/worker.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::sync::{Arc, Mutex}; 4 | 5 | use futures_channel::oneshot::Sender; 6 | use futures_util::{FutureExt as _, SinkExt as _, TryFutureExt as _, TryStreamExt as _}; 7 | use grpc_proto::testing::control::{ 8 | ClientArgs, ClientStatus, CoreRequest, CoreResponse, ServerArgs, ServerStatus, Void, 9 | }; 10 | use grpc_proto::testing::services_grpc::WorkerService; 11 | use grpcio::{DuplexSink, RequestStream, RpcContext, UnarySink, WriteFlags}; 12 | 13 | use crate::client::Client; 14 | use crate::server::Server; 15 | use crate::util; 16 | 17 | #[derive(Clone)] 18 | pub struct Worker { 19 | shutdown_notifier: Arc>>>, 20 | } 21 | 22 | impl Worker { 23 | pub fn new(sender: Sender<()>) -> Worker { 24 | Worker { 25 | shutdown_notifier: Arc::new(Mutex::new(Some(sender))), 26 | } 27 | } 28 | } 29 | 30 | impl WorkerService for Worker { 31 | fn run_server( 32 | &mut self, 33 | ctx: RpcContext, 34 | mut stream: RequestStream, 35 | mut sink: DuplexSink, 36 | ) { 37 | let f = async move { 38 | let arg = match stream.try_next().await? { 39 | None => return sink.close().await, 40 | Some(arg) => arg, 41 | }; 42 | #[cfg(feature = "protobuf-codec")] 43 | let cfg = arg.get_setup(); 44 | #[cfg(feature = "protobufv3-codec")] 45 | let cfg = arg.setup(); 46 | info!("receive server setup: {:?}", cfg); 47 | let mut server = Server::new(cfg)?; 48 | let status = server.get_status(); 49 | sink.send((status, WriteFlags::default())).await?; 50 | while let Some(arg) = stream.try_next().await? { 51 | #[cfg(feature = "protobuf-codec")] 52 | let mark = arg.get_mark(); 53 | #[cfg(feature = "protobufv3-codec")] 54 | let mark = arg.mark(); 55 | 56 | info!("receive server mark: {:?}", mark); 57 | let stats = server.get_stats(mark.reset); 58 | let mut status = server.get_status(); 59 | status.stats = Some(stats).into(); 60 | sink.send((status, WriteFlags::default())).await?; 61 | } 62 | server.shutdown().await?; 63 | sink.close().await?; 64 | Ok(()) 65 | } 66 | .map_err(|e| error!("run server failed: {:?}", e)) 67 | .map(|_| info!("server shutdown.")); 68 | ctx.spawn(f) 69 | } 70 | 71 | fn run_client( 72 | &mut self, 73 | ctx: RpcContext, 74 | mut stream: RequestStream, 75 | mut sink: DuplexSink, 76 | ) { 77 | let f = async move { 78 | let arg = match stream.try_next().await? { 79 | None => return sink.close().await, 80 | Some(arg) => arg, 81 | }; 82 | #[cfg(feature = "protobuf-codec")] 83 | let cfg = arg.get_setup(); 84 | #[cfg(feature = "protobufv3-codec")] 85 | let cfg = arg.setup(); 86 | info!("receive client setup: {:?}", cfg); 87 | let mut client = Client::new(cfg); 88 | sink.send((ClientStatus::default(), WriteFlags::default())) 89 | .await?; 90 | while let Some(arg) = stream.try_next().await? { 91 | #[cfg(feature = "protobuf-codec")] 92 | let mark = arg.get_mark(); 93 | #[cfg(feature = "protobufv3-codec")] 94 | let mark = arg.mark(); 95 | 96 | info!("receive client mark: {:?}", mark); 97 | let stats = client.get_stats(mark.reset); 98 | let status = ClientStatus { 99 | stats: Some(stats).into(), 100 | ..ClientStatus::default() 101 | }; 102 | sink.send((status, WriteFlags::default())).await?; 103 | } 104 | client.shutdown().await; 105 | sink.close().await?; 106 | Ok(()) 107 | } 108 | .map_err(|e| error!("run client failed: {:?}", e)) 109 | .map(|_| info!("client shutdown.")); 110 | ctx.spawn(f) 111 | } 112 | 113 | fn core_count(&mut self, ctx: RpcContext, _: CoreRequest, sink: UnarySink) { 114 | let cpu_count = util::cpu_num_cores(); 115 | let resp = CoreResponse { 116 | cores: cpu_count as i32, 117 | ..CoreResponse::default() 118 | }; 119 | ctx.spawn( 120 | sink.success(resp) 121 | .map_err(|e| error!("failed to report cpu count: {:?}", e)) 122 | .map(|_| ()), 123 | ) 124 | } 125 | 126 | fn quit_worker(&mut self, ctx: RpcContext, _: Void, sink: crate::grpc::UnarySink) { 127 | let notifier = self.shutdown_notifier.lock().unwrap().take(); 128 | if let Some(notifier) = notifier { 129 | let _ = notifier.send(()); 130 | } 131 | ctx.spawn( 132 | sink.success(Void::default()) 133 | .map_err(|e| error!("failed to report quick worker: {:?}", e)) 134 | .map(|_| ()), 135 | ); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /compiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "grpcio-compiler" 3 | version = "0.13.0" 4 | edition = "2018" 5 | authors = ["The TiKV Project Developers"] 6 | license = "Apache-2.0" 7 | keywords = ["compiler", "grpc", "protobuf"] 8 | repository = "https://github.com/tikv/grpc-rs" 9 | homepage = "https://github.com/tikv/grpc-rs" 10 | documentation = "https://docs.rs/grpcio-compiler" 11 | description = "gRPC compiler for grpcio" 12 | categories = ["network-programming"] 13 | 14 | [features] 15 | default = ["protobuf-codec"] 16 | protobuf-codec = ["protobuf"] 17 | prost-codec = ["prost-build", "prost-types", "prost", "derive-new", "tempfile"] 18 | 19 | [dependencies] 20 | protobuf = { version = "2", optional = true } 21 | prost = { version = "0.13", optional = true } 22 | prost-build = { version = "0.13", optional = true } 23 | prost-types = { version = "0.13", optional = true } 24 | derive-new = { version = "0.6", optional = true } 25 | tempfile = { version = "3.0", optional = true } 26 | 27 | [[bin]] 28 | name = "grpc_rust_plugin" 29 | required-features = ["protobuf-codec"] 30 | 31 | [[bin]] 32 | name = "grpc_rust_prost" 33 | required-features = ["prost-codec"] 34 | -------------------------------------------------------------------------------- /compiler/src/bin/grpc_rust_plugin.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | // Copyright (c) 2016, Stepan Koltsov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining 6 | // a copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | extern crate grpcio_compiler; 25 | 26 | use grpcio_compiler::codegen; 27 | 28 | fn main() { 29 | codegen::protoc_gen_grpc_rust_main(); 30 | } 31 | -------------------------------------------------------------------------------- /compiler/src/bin/grpc_rust_prost.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | extern crate grpcio_compiler; 4 | 5 | use grpcio_compiler::prost_codegen; 6 | 7 | fn main() { 8 | prost_codegen::protoc_gen_grpc_rust_main(); 9 | } 10 | -------------------------------------------------------------------------------- /compiler/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #[cfg(feature = "protobuf-codec")] 4 | pub mod codegen; 5 | #[cfg(feature = "prost-codec")] 6 | pub mod prost_codegen; 7 | 8 | mod util; 9 | -------------------------------------------------------------------------------- /compiler/src/util.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::fmt; 4 | use std::str; 5 | 6 | // A struct that divide a name into serveral parts that meets rust's guidelines. 7 | struct NameSpliter<'a> { 8 | name: &'a [u8], 9 | pos: usize, 10 | } 11 | 12 | impl NameSpliter<'_> { 13 | fn new(s: &str) -> NameSpliter { 14 | NameSpliter { 15 | name: s.as_bytes(), 16 | pos: 0, 17 | } 18 | } 19 | } 20 | 21 | impl<'a> Iterator for NameSpliter<'a> { 22 | type Item = &'a str; 23 | 24 | fn next(&mut self) -> Option<&'a str> { 25 | if self.pos == self.name.len() { 26 | return None; 27 | } 28 | // skip all prefix '_' 29 | while self.pos < self.name.len() && self.name[self.pos] == b'_' { 30 | self.pos += 1; 31 | } 32 | let mut pos = self.name.len(); 33 | let mut upper_len = 0; 34 | let mut meet_lower = false; 35 | for i in self.pos..self.name.len() { 36 | let c = self.name[i]; 37 | if c.is_ascii_uppercase() { 38 | if meet_lower { 39 | // So it should be AaA or aaA 40 | pos = i; 41 | break; 42 | } 43 | upper_len += 1; 44 | } else if c == b'_' { 45 | pos = i; 46 | break; 47 | } else { 48 | meet_lower = true; 49 | if upper_len > 1 { 50 | // So it should be AAa 51 | pos = i - 1; 52 | break; 53 | } 54 | } 55 | } 56 | let s = str::from_utf8(&self.name[self.pos..pos]).unwrap(); 57 | self.pos = pos; 58 | Some(s) 59 | } 60 | } 61 | 62 | /// Adjust method name to follow rust-guidelines. 63 | pub fn to_snake_case(name: &str) -> String { 64 | let mut snake_method_name = String::with_capacity(name.len()); 65 | for s in NameSpliter::new(name) { 66 | snake_method_name.push_str(&s.to_lowercase()); 67 | snake_method_name.push('_'); 68 | } 69 | snake_method_name.pop(); 70 | snake_method_name 71 | } 72 | 73 | #[cfg(feature = "protobuf-codec")] 74 | pub fn to_camel_case(name: &str) -> String { 75 | let mut camel_case_name = String::with_capacity(name.len()); 76 | for s in NameSpliter::new(name) { 77 | let mut chs = s.chars(); 78 | camel_case_name.extend(chs.next().unwrap().to_uppercase()); 79 | camel_case_name.push_str(&s[1..].to_lowercase()); 80 | } 81 | camel_case_name 82 | } 83 | 84 | pub fn fq_grpc(item: &str) -> String { 85 | format!("::grpcio::{item}") 86 | } 87 | 88 | pub enum MethodType { 89 | Unary, 90 | ClientStreaming, 91 | ServerStreaming, 92 | Duplex, 93 | } 94 | 95 | impl fmt::Display for MethodType { 96 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 97 | write!( 98 | f, 99 | "{}", 100 | match self { 101 | MethodType::Unary => "MethodType::Unary", 102 | MethodType::ClientStreaming => "MethodType::ClientStreaming", 103 | MethodType::ServerStreaming => "MethodType::ServerStreaming", 104 | MethodType::Duplex => "MethodType::Duplex", 105 | } 106 | ) 107 | } 108 | } 109 | 110 | #[cfg(test)] 111 | mod test { 112 | #[test] 113 | fn test_snake_name() { 114 | let cases = vec![ 115 | ("AsyncRequest", "async_request"), 116 | ("asyncRequest", "async_request"), 117 | ("async_request", "async_request"), 118 | ("createID", "create_id"), 119 | ("AsyncRClient", "async_r_client"), 120 | ("CreateIDForReq", "create_id_for_req"), 121 | ("Create_ID_For_Req", "create_id_for_req"), 122 | ("Create_ID_For__Req", "create_id_for_req"), 123 | ("ID", "id"), 124 | ("id", "id"), 125 | ]; 126 | 127 | for (origin, exp) in cases { 128 | let res = super::to_snake_case(origin); 129 | assert_eq!(res, exp); 130 | } 131 | } 132 | 133 | #[test] 134 | #[cfg(feature = "protobuf-codec")] 135 | fn test_camel_name() { 136 | let cases = vec![ 137 | ("AsyncRequest", "AsyncRequest"), 138 | ("asyncRequest", "AsyncRequest"), 139 | ("async_request", "AsyncRequest"), 140 | ("createID", "CreateId"), 141 | ("AsyncRClient", "AsyncRClient"), 142 | ("async_r_client", "AsyncRClient"), 143 | ("CreateIDForReq", "CreateIdForReq"), 144 | ("Create_ID_For_Req", "CreateIdForReq"), 145 | ("Create_ID_For__Req", "CreateIdForReq"), 146 | ("ID", "Id"), 147 | ("id", "Id"), 148 | ]; 149 | 150 | for (origin, exp) in cases { 151 | let res = super::to_camel_case(origin); 152 | assert_eq!(res, exp); 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /cross_compile.md: -------------------------------------------------------------------------------- 1 | # Cross Compile gRPC-rs(0.2.1) to Windows under *nix 2 | 3 | ## First you need to install mingw 4 | 5 | ```bash 6 | # macOS 7 | brew install mingw-w64 8 | 9 | # CentOS 10 | yum install mingw64-openssl-static mingw64-zlib-static mingw64-winpthreads-static 11 | ``` 12 | 13 | ## Fix CMake 14 | 15 | ``` 16 | # modify grpc-rs/grpc-sys/build.rs 17 | # fix SYSTEM_PROCESSOR 18 | "CMAKE_SYSTEM_PROCESSOR", get_env("CARGO_CFG_TARGET_ARCH").unwrap() 19 | # fix try_run 20 | "CMAKE_CROSSCOMPILING", "true" 21 | ``` 22 | 23 | ### All diff in `fn build_grpc` 24 | 25 | ```rust 26 | let dst = { 27 | let mut config = Config::new("grpc"); 28 | if get_env("CARGO_CFG_TARGET_OS").map_or(false, |s| s == "macos") { 29 | config.cxxflag("-stdlib=libc++"); 30 | } 31 | config 32 | .define("CMAKE_SYSTEM_PROCESSOR", get_env("CARGO_CFG_TARGET_ARCH").unwrap()) 33 | .define("CMAKE_CROSSCOMPILING", "true") 34 | .build_target(library) 35 | .build() 36 | }; 37 | ``` 38 | 39 | ### Fix find zlib 40 | 41 | ```rust 42 | // try these values 43 | let mut zlib = "z"; 44 | let mut zlib = "zlibstatic"; 45 | let mut zlib = "zlibstaticd"; 46 | ``` 47 | 48 | ## Fix WIN32 API 49 | 50 | ``` 51 | # grpc-rs/grpc-sys/grpc/CMakeLists.txt 52 | # add these code after about line number 295 53 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WIN32_WINNT=0x600") 54 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WIN32_WINNT=0x600") 55 | set(C_CXX_FLAGS "${C_CXX_FLAGS} -D_WIN32_WINNT=0x600") 56 | ``` 57 | 58 | ## Fix boringssl 59 | 60 | Just update third_party/boringssl 61 | 62 | ```bash 63 | cd third_party/boringssl 64 | git checkout master 65 | git pull 66 | ``` 67 | -------------------------------------------------------------------------------- /grpc-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "grpcio-sys" 3 | version = "0.13.0+1.56.2-patched" 4 | authors = ["The TiKV Project Developers"] 5 | license = "Apache-2.0" 6 | keywords = ["grpc", "bindings"] 7 | repository = "https://github.com/tikv/grpc-rs" 8 | homepage = "https://github.com/tikv/grpc-rs" 9 | documentation = "https://docs.rs/grpcio-sys" 10 | description = "FFI bindings to gRPC c core library" 11 | categories = ["external-ffi-bindings", "network-programming"] 12 | build = "build.rs" 13 | edition = "2018" 14 | exclude = [ 15 | "grpc/doc/*", 16 | "grpc/etc/*", 17 | "grpc/examples/*", 18 | "grpc/Makefile", 19 | "grpc/templates/*", 20 | "grpc/src/android/*", 21 | "grpc/src/csharp/*", 22 | "grpc/src/node/*", 23 | "grpc/src/objective-c/*", 24 | "grpc/src/php/*", 25 | "grpc/src/python/*", 26 | "grpc/src/ruby/*", 27 | "grpc/test/core/end2end/*", 28 | "grpc/third_party/zlib/*", 29 | "grpc/third_party/abseil-cpp/absl/time/internal/cctz/testdata", 30 | "grpc/third_party/benchmark/*", 31 | "grpc/third_party/bloaty/*", 32 | "grpc/third_party/boringssl-with-bazel/*", 33 | "grpc/third_party/libuv/*", 34 | "grpc/third_party/gflags/*", 35 | "grpc/third_party/googletest/*", 36 | "grpc/third_party/objective_c/*", 37 | "grpc/third_party/protobuf/*", 38 | "grpc/third_party/toolchans/*", 39 | "grpc/third_party/envoy-api/*", 40 | "grpc/third_party/googleapis/*", 41 | "grpc/third_party/protoc-gen-validate/*", 42 | "grpc/third_party/udpa/*", 43 | "grpc/tools/run_tests/generated/*", 44 | "grpc/test/core/", 45 | "!grpc/test/core/security/*.cc", 46 | "!grpc/test/core/util/cmdline.cc", 47 | "grpc/test/cpp", 48 | "!grpc/test/core/**/*.proto", 49 | # fool cmake to not update submodules. 50 | "!grpc/third_party/envoy-api/README.md", 51 | "!grpc/third_party/googleapis/README.md", 52 | ] 53 | 54 | [dependencies] 55 | libc = "0.2" 56 | openssl-sys = { version = "0.9", optional = true, features = ["vendored"] } 57 | libz-sys = { version = "1.1.3", default-features = false, features = ["libc", "static"] } 58 | 59 | [features] 60 | # A hidden feature indicating that secure features should be enabled. 61 | _secure = [] 62 | boringssl = ["boringssl-src", "_secure"] 63 | openssl = ["_secure"] 64 | openssl-vendored = ["openssl", "openssl-sys"] 65 | no-omit-frame-pointer = [] 66 | # A hidden feature that is used to force regenerating bindings. 67 | _gen-bindings = ["bindgen"] 68 | _list-package = [] 69 | 70 | [target.'cfg(not(all(any(target_os = "linux", target_os = "macos"), any(target_arch = "x86_64", target_arch = "aarch64"))))'.build-dependencies] 71 | bindgen = { version = "0.69.0", default-features = false, features = ["runtime"] } 72 | 73 | [build-dependencies] 74 | cc = "1.0" 75 | cmake = "0.1" 76 | pkg-config = "0.3" 77 | walkdir = "2.2.9" 78 | # Because of rust-lang/cargo#5237, bindgen should not be upgraded util a minor or major release. 79 | bindgen = { version = "0.69.0", default-features = false, optional = true, features = ["runtime"] } 80 | boringssl-src = { version = "0.6.0", optional = true } 81 | -------------------------------------------------------------------------------- /grpc-sys/link-deps.rs: -------------------------------------------------------------------------------- 1 | /// Following two arrays are generated by running pkg-config manually. We can 2 | /// also choose to run pkg-config at build time, but it will requires pkg-config 3 | /// in path, which is unfriendly for platforms like Windows. 4 | const COMMON_DEPS: &[&str] = &[ 5 | "absl_bad_optional_access", 6 | "absl_bad_variant_access", 7 | "absl_base", 8 | "absl_city", 9 | "absl_civil_time", 10 | "absl_cord", 11 | "absl_cord_internal", 12 | "absl_cordz_functions", 13 | "absl_cordz_handle", 14 | "absl_cordz_info", 15 | "absl_crc32c", 16 | "absl_crc_cord_state", 17 | "absl_crc_cpu_detect", 18 | "absl_crc_internal", 19 | "absl_debugging_internal", 20 | "absl_demangle_internal", 21 | "absl_exponential_biased", 22 | "absl_flags", 23 | "absl_flags_commandlineflag", 24 | "absl_flags_commandlineflag_internal", 25 | "absl_flags_config", 26 | "absl_flags_internal", 27 | "absl_flags_marshalling", 28 | "absl_flags_private_handle_accessor", 29 | "absl_flags_program_name", 30 | "absl_flags_reflection", 31 | "absl_graphcycles_internal", 32 | "absl_hash", 33 | "absl_hashtablez_sampler", 34 | "absl_int128", 35 | "absl_log_severity", 36 | "absl_low_level_hash", 37 | "absl_malloc_internal", 38 | "absl_random_distributions", 39 | "absl_random_internal_platform", 40 | "absl_random_internal_pool_urbg", 41 | "absl_random_internal_randen", 42 | "absl_random_internal_randen_hwaes", 43 | "absl_random_internal_randen_hwaes_impl", 44 | "absl_random_internal_randen_slow", 45 | "absl_random_internal_seed_material", 46 | "absl_random_seed_gen_exception", 47 | "absl_random_seed_sequences", 48 | "absl_raw_hash_set", 49 | "absl_raw_logging_internal", 50 | "absl_spinlock_wait", 51 | "absl_stacktrace", 52 | "absl_status", 53 | "absl_statusor", 54 | "absl_str_format_internal", 55 | "absl_strerror", 56 | "absl_strings", 57 | "absl_strings_internal", 58 | "absl_symbolize", 59 | "absl_synchronization", 60 | "absl_throw_delegate", 61 | "absl_time", 62 | "absl_time_zone", 63 | "address_sorting", 64 | "cares", 65 | "gpr", 66 | "re2", 67 | "upb", 68 | "z", 69 | ]; 70 | const GRPC_DEPS: &[&str] = &["grpc"]; 71 | const GRPC_UNSECURE_DEPS: &[&str] = &["grpc_unsecure"]; 72 | -------------------------------------------------------------------------------- /grpc-sys/src/grpc_wrap.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use super::*; 4 | 5 | use std::time::Duration; 6 | 7 | impl gpr_timespec { 8 | pub fn inf_future() -> gpr_timespec { 9 | unsafe { gpr_inf_future(gpr_clock_type::GPR_CLOCK_REALTIME) } 10 | } 11 | } 12 | 13 | impl From for gpr_timespec { 14 | fn from(dur: Duration) -> gpr_timespec { 15 | gpr_timespec { 16 | tv_sec: dur.as_secs() as i64, 17 | tv_nsec: dur.subsec_nanos() as i32, 18 | clock_type: gpr_clock_type::GPR_TIMESPAN, 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /grpc-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #![allow(non_camel_case_types)] 4 | #![allow(non_snake_case)] 5 | #![allow(non_upper_case_globals)] 6 | #[allow(clippy::all)] 7 | #[allow(rustdoc::all)] 8 | mod bindings { 9 | include!(env!("BINDING_PATH")); 10 | } 11 | mod grpc_wrap; 12 | 13 | pub use bindings::*; 14 | -------------------------------------------------------------------------------- /health/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "grpcio-health" 3 | version = "0.13.0" 4 | edition = "2018" 5 | authors = ["The TiKV Project Developers"] 6 | license = "Apache-2.0" 7 | keywords = ["grpc", "healthcheck"] 8 | repository = "https://github.com/tikv/grpc-rs" 9 | homepage = "https://github.com/tikv/grpc-rs" 10 | documentation = "https://docs.rs/grpcio-health" 11 | description = "Health check wrappers for grpcio" 12 | categories = ["network-programming"] 13 | readme = "README.md" 14 | 15 | [features] 16 | default = ["protobuf-codec"] 17 | protobuf-codec = ["grpcio/protobuf-codec", "protobuf"] 18 | protobufv3-codec = ["grpcio/protobufv3-codec", "protobufv3"] 19 | prost-codec = ["grpcio/prost-codec", "prost"] 20 | 21 | [dependencies] 22 | futures-executor = "0.3" 23 | futures-util = { version = "0.3", default-features = false, features = ["std"] } 24 | grpcio = { path = "..", version = "0.13.0", default-features = false } 25 | prost = { version = "0.13", optional = true } 26 | protobuf = { version = "2", optional = true } 27 | protobufv3 = { package = "protobuf", version = "3.2", optional = true } 28 | log = "0.4" 29 | -------------------------------------------------------------------------------- /health/README.md: -------------------------------------------------------------------------------- 1 | # grpcio-healthcheck 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/grpcio-health.svg?maxAge=2592000)](https://crates.io/crates/grpcio-health) 4 | [![docs.rs](https://docs.rs/grpcio-health/badge.svg)](https://docs.rs/grpcio-health) 5 | 6 | grpcio-health provides health check protos as well as some helper structs to make 7 | health check easily. 8 | 9 | -------------------------------------------------------------------------------- /health/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | //! grpcio-health provides health check protos as well as some helper structs to make 4 | //! health check easily. For the detail design of health checking service, see 5 | //! https://github.com/grpc/grpc/blob/master/doc/health-checking.md. 6 | //! 7 | //! ### Usage 8 | //! 9 | //! The crate provides a default implementation of `Health` service, you can use it 10 | //! to maintain the service states. First, you need to register it to the server builder 11 | //! so that it can serve health check service later. 12 | //! ```ignore 13 | //! use grpcio_health::{HealthService, create_health}; 14 | //! 15 | //! let service = HealthService::default(); 16 | //! let builder = builder.register_service(create_health(service.clone())); 17 | //! ``` 18 | //! Then insert service status for query. 19 | //! ```ignore 20 | //! service.set_serving_status("", ServingStatus::Serving); 21 | //! ``` 22 | //! `""` means overall health status. You can also provide specific service name. 23 | //! 24 | //! Client can either use `check` to do one time query or `watch` to observe status changes. 25 | //! ```ignore 26 | //! use grpcio_health::proto::HealthCheckRequest; 27 | //! 28 | //! let client = HealthClient::new(ch); 29 | //! let req = HealthCheckRequest { service: "".to_string(), ..Default::default() }; 30 | //! let status_resp = client.check_async(&req).await.unwrap(); 31 | //! assert_eq!(statuss_resp.status, ServingStatus::Serving); 32 | //! ``` 33 | 34 | #[allow(renamed_and_removed_lints)] 35 | #[allow(static_mut_refs)] 36 | pub mod proto; 37 | mod service; 38 | 39 | pub use self::proto::{create_health, HealthClient}; 40 | pub use self::service::HealthService; 41 | 42 | #[cfg(feature = "protobuf-codec")] 43 | pub use self::proto::ServingStatus; 44 | 45 | #[cfg(feature = "protobufv3-codec")] 46 | pub use self::proto::health_check_response::ServingStatus; 47 | -------------------------------------------------------------------------------- /health/src/proto.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #[cfg(feature = "prost-codec")] 4 | mod reexports { 5 | include!("proto/prost/grpc.health.v1.rs"); 6 | 7 | pub use self::health_check_response::ServingStatus; 8 | } 9 | 10 | #[cfg(feature = "protobuf-codec")] 11 | mod protobuf { 12 | #[allow(deprecated)] 13 | pub mod health; 14 | pub mod health_grpc; 15 | } 16 | #[cfg(feature = "protobufv3-codec")] 17 | mod protobuf_v3 { 18 | #[allow(deprecated)] 19 | pub mod health; 20 | pub mod health_grpc; 21 | } 22 | #[cfg(feature = "protobuf-codec")] 23 | mod reexports { 24 | pub use super::protobuf::health::*; 25 | // Following is included in health import above. 26 | // pub use super::protobuf::health_grpc::*; 27 | } 28 | #[cfg(feature = "protobufv3-codec")] 29 | mod reexports { 30 | pub use super::protobuf_v3::health::*; 31 | pub use super::protobuf_v3::health_grpc::*; 32 | } 33 | 34 | pub use self::reexports::*; 35 | -------------------------------------------------------------------------------- /health/src/proto/protobuf/health_grpc.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | #![allow(box_pointers)] 8 | #![allow(dead_code)] 9 | #![allow(missing_docs)] 10 | #![allow(non_camel_case_types)] 11 | #![allow(non_snake_case)] 12 | #![allow(non_upper_case_globals)] 13 | #![allow(trivial_casts)] 14 | #![allow(unsafe_code)] 15 | #![allow(unused_imports)] 16 | #![allow(unused_results)] 17 | 18 | const METHOD_HEALTH_CHECK: ::grpcio::Method< 19 | super::health::HealthCheckRequest, 20 | super::health::HealthCheckResponse, 21 | > = ::grpcio::Method { 22 | ty: ::grpcio::MethodType::Unary, 23 | name: "/grpc.health.v1.Health/Check", 24 | req_mar: ::grpcio::Marshaller { 25 | ser: ::grpcio::pb_ser, 26 | de: ::grpcio::pb_de, 27 | }, 28 | resp_mar: ::grpcio::Marshaller { 29 | ser: ::grpcio::pb_ser, 30 | de: ::grpcio::pb_de, 31 | }, 32 | }; 33 | 34 | const METHOD_HEALTH_WATCH: ::grpcio::Method< 35 | super::health::HealthCheckRequest, 36 | super::health::HealthCheckResponse, 37 | > = ::grpcio::Method { 38 | ty: ::grpcio::MethodType::ServerStreaming, 39 | name: "/grpc.health.v1.Health/Watch", 40 | req_mar: ::grpcio::Marshaller { 41 | ser: ::grpcio::pb_ser, 42 | de: ::grpcio::pb_de, 43 | }, 44 | resp_mar: ::grpcio::Marshaller { 45 | ser: ::grpcio::pb_ser, 46 | de: ::grpcio::pb_de, 47 | }, 48 | }; 49 | 50 | #[derive(Clone)] 51 | pub struct HealthClient { 52 | pub client: ::grpcio::Client, 53 | } 54 | 55 | impl HealthClient { 56 | pub fn new(channel: ::grpcio::Channel) -> Self { 57 | HealthClient { 58 | client: ::grpcio::Client::new(channel), 59 | } 60 | } 61 | 62 | pub fn check_opt( 63 | &self, 64 | req: &super::health::HealthCheckRequest, 65 | opt: ::grpcio::CallOption, 66 | ) -> ::grpcio::Result { 67 | self.client.unary_call(&METHOD_HEALTH_CHECK, req, opt) 68 | } 69 | 70 | pub fn check( 71 | &self, 72 | req: &super::health::HealthCheckRequest, 73 | ) -> ::grpcio::Result { 74 | self.check_opt(req, ::grpcio::CallOption::default()) 75 | } 76 | 77 | pub fn check_async_opt( 78 | &self, 79 | req: &super::health::HealthCheckRequest, 80 | opt: ::grpcio::CallOption, 81 | ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 82 | self.client.unary_call_async(&METHOD_HEALTH_CHECK, req, opt) 83 | } 84 | 85 | pub fn check_async( 86 | &self, 87 | req: &super::health::HealthCheckRequest, 88 | ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 89 | self.check_async_opt(req, ::grpcio::CallOption::default()) 90 | } 91 | 92 | pub fn watch_opt( 93 | &self, 94 | req: &super::health::HealthCheckRequest, 95 | opt: ::grpcio::CallOption, 96 | ) -> ::grpcio::Result<::grpcio::ClientSStreamReceiver> { 97 | self.client.server_streaming(&METHOD_HEALTH_WATCH, req, opt) 98 | } 99 | 100 | pub fn watch( 101 | &self, 102 | req: &super::health::HealthCheckRequest, 103 | ) -> ::grpcio::Result<::grpcio::ClientSStreamReceiver> { 104 | self.watch_opt(req, ::grpcio::CallOption::default()) 105 | } 106 | pub fn spawn(&self, f: F) 107 | where 108 | F: ::std::future::Future + Send + 'static, 109 | { 110 | self.client.spawn(f) 111 | } 112 | } 113 | 114 | pub trait Health { 115 | fn check( 116 | &mut self, 117 | ctx: ::grpcio::RpcContext, 118 | _req: super::health::HealthCheckRequest, 119 | sink: ::grpcio::UnarySink, 120 | ) { 121 | grpcio::unimplemented_call!(ctx, sink) 122 | } 123 | fn watch( 124 | &mut self, 125 | ctx: ::grpcio::RpcContext, 126 | _req: super::health::HealthCheckRequest, 127 | sink: ::grpcio::ServerStreamingSink, 128 | ) { 129 | grpcio::unimplemented_call!(ctx, sink) 130 | } 131 | } 132 | 133 | pub fn create_health(s: S) -> ::grpcio::Service { 134 | let mut builder = ::grpcio::ServiceBuilder::new(); 135 | let mut instance = s.clone(); 136 | builder = builder.add_unary_handler(&METHOD_HEALTH_CHECK, move |ctx, req, resp| { 137 | instance.check(ctx, req, resp) 138 | }); 139 | let mut instance = s; 140 | builder = builder.add_server_streaming_handler(&METHOD_HEALTH_WATCH, move |ctx, req, resp| { 141 | instance.watch(ctx, req, resp) 142 | }); 143 | builder.build() 144 | } 145 | -------------------------------------------------------------------------------- /health/src/proto/protobuf_v3/health_grpc.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | #![allow(box_pointers)] 8 | #![allow(dead_code)] 9 | #![allow(missing_docs)] 10 | #![allow(non_camel_case_types)] 11 | #![allow(non_snake_case)] 12 | #![allow(non_upper_case_globals)] 13 | #![allow(trivial_casts)] 14 | #![allow(unsafe_code)] 15 | #![allow(unused_imports)] 16 | #![allow(unused_results)] 17 | 18 | const METHOD_HEALTH_CHECK: ::grpcio::Method< 19 | super::health::HealthCheckRequest, 20 | super::health::HealthCheckResponse, 21 | > = ::grpcio::Method { 22 | ty: ::grpcio::MethodType::Unary, 23 | name: "/grpc.health.v1.Health/Check", 24 | req_mar: ::grpcio::Marshaller { 25 | ser: ::grpcio::pb_ser, 26 | de: ::grpcio::pb_de, 27 | }, 28 | resp_mar: ::grpcio::Marshaller { 29 | ser: ::grpcio::pb_ser, 30 | de: ::grpcio::pb_de, 31 | }, 32 | }; 33 | 34 | const METHOD_HEALTH_WATCH: ::grpcio::Method< 35 | super::health::HealthCheckRequest, 36 | super::health::HealthCheckResponse, 37 | > = ::grpcio::Method { 38 | ty: ::grpcio::MethodType::ServerStreaming, 39 | name: "/grpc.health.v1.Health/Watch", 40 | req_mar: ::grpcio::Marshaller { 41 | ser: ::grpcio::pb_ser, 42 | de: ::grpcio::pb_de, 43 | }, 44 | resp_mar: ::grpcio::Marshaller { 45 | ser: ::grpcio::pb_ser, 46 | de: ::grpcio::pb_de, 47 | }, 48 | }; 49 | 50 | #[derive(Clone)] 51 | pub struct HealthClient { 52 | pub client: ::grpcio::Client, 53 | } 54 | 55 | impl HealthClient { 56 | pub fn new(channel: ::grpcio::Channel) -> Self { 57 | HealthClient { 58 | client: ::grpcio::Client::new(channel), 59 | } 60 | } 61 | 62 | pub fn check_opt( 63 | &self, 64 | req: &super::health::HealthCheckRequest, 65 | opt: ::grpcio::CallOption, 66 | ) -> ::grpcio::Result { 67 | self.client.unary_call(&METHOD_HEALTH_CHECK, req, opt) 68 | } 69 | 70 | pub fn check( 71 | &self, 72 | req: &super::health::HealthCheckRequest, 73 | ) -> ::grpcio::Result { 74 | self.check_opt(req, ::grpcio::CallOption::default()) 75 | } 76 | 77 | pub fn check_async_opt( 78 | &self, 79 | req: &super::health::HealthCheckRequest, 80 | opt: ::grpcio::CallOption, 81 | ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 82 | self.client.unary_call_async(&METHOD_HEALTH_CHECK, req, opt) 83 | } 84 | 85 | pub fn check_async( 86 | &self, 87 | req: &super::health::HealthCheckRequest, 88 | ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 89 | self.check_async_opt(req, ::grpcio::CallOption::default()) 90 | } 91 | 92 | pub fn watch_opt( 93 | &self, 94 | req: &super::health::HealthCheckRequest, 95 | opt: ::grpcio::CallOption, 96 | ) -> ::grpcio::Result<::grpcio::ClientSStreamReceiver> { 97 | self.client.server_streaming(&METHOD_HEALTH_WATCH, req, opt) 98 | } 99 | 100 | pub fn watch( 101 | &self, 102 | req: &super::health::HealthCheckRequest, 103 | ) -> ::grpcio::Result<::grpcio::ClientSStreamReceiver> { 104 | self.watch_opt(req, ::grpcio::CallOption::default()) 105 | } 106 | pub fn spawn(&self, f: F) 107 | where 108 | F: ::std::future::Future + Send + 'static, 109 | { 110 | self.client.spawn(f) 111 | } 112 | } 113 | 114 | pub trait Health { 115 | fn check( 116 | &mut self, 117 | ctx: ::grpcio::RpcContext, 118 | _req: super::health::HealthCheckRequest, 119 | sink: ::grpcio::UnarySink, 120 | ) { 121 | grpcio::unimplemented_call!(ctx, sink) 122 | } 123 | fn watch( 124 | &mut self, 125 | ctx: ::grpcio::RpcContext, 126 | _req: super::health::HealthCheckRequest, 127 | sink: ::grpcio::ServerStreamingSink, 128 | ) { 129 | grpcio::unimplemented_call!(ctx, sink) 130 | } 131 | } 132 | 133 | pub fn create_health(s: S) -> ::grpcio::Service { 134 | let mut builder = ::grpcio::ServiceBuilder::new(); 135 | let mut instance = s.clone(); 136 | builder = builder.add_unary_handler(&METHOD_HEALTH_CHECK, move |ctx, req, resp| { 137 | instance.check(ctx, req, resp) 138 | }); 139 | let mut instance = s; 140 | builder = builder.add_server_streaming_handler(&METHOD_HEALTH_WATCH, move |ctx, req, resp| { 141 | instance.watch(ctx, req, resp) 142 | }); 143 | builder.build() 144 | } 145 | -------------------------------------------------------------------------------- /health/src/proto/protobuf_v3/mod.rs: -------------------------------------------------------------------------------- 1 | // @generated 2 | 3 | pub mod health; 4 | -------------------------------------------------------------------------------- /interop/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "interop" 3 | version = "0.1.0" 4 | edition = "2018" 5 | publish = false 6 | 7 | [features] 8 | default = ["protobuf-codec"] 9 | protobuf-codec = ["protobuf", "grpcio/protobuf-codec", "grpcio-proto/protobuf-codec"] 10 | protobufv3-codec = ["protobufv3", "grpcio/protobufv3-codec", "grpcio-proto/protobufv3-codec"] 11 | 12 | [dependencies] 13 | grpcio = { path = "..", default-features = false, features = ["boringssl"]} 14 | grpcio-sys = { path = "../grpc-sys", default-features = false} 15 | grpcio-proto = { path = "../proto", default-features = false} 16 | protobuf = { version = "2", optional = true } 17 | protobufv3 = { package = "protobuf", version = "3.2", optional = true } 18 | futures-executor = "0.3" 19 | futures-util = { version = "0.3", default-features = false, features = ["std"] } 20 | log = "0.4" 21 | clap = { version = "4.5", features = ["derive"] } 22 | futures-timer = "3.0" 23 | 24 | [[bin]] 25 | name = "interop_client" 26 | path = "src/bin/client.rs" 27 | 28 | [[bin]] 29 | name = "interop_server" 30 | path = "src/bin/server.rs" 31 | -------------------------------------------------------------------------------- /interop/src/bin/client.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | extern crate clap; 4 | extern crate grpcio as grpc; 5 | extern crate grpcio_proto as grpc_proto; 6 | extern crate interop; 7 | 8 | use crate::grpc::{ChannelBuilder, ChannelCredentialsBuilder, Environment}; 9 | use crate::grpc_proto::util; 10 | use clap::Parser; 11 | use std::sync::Arc; 12 | 13 | use interop::Client; 14 | 15 | /// Interoperability Test Client 16 | /// 17 | /// ref https://github.com/grpc/grpc/blob/v1.3.x/doc/interop-test-descriptions.md. 18 | #[derive(Parser)] 19 | struct ClientCli { 20 | /// The server host to connect to. For example, "localhost" or "127.0.0.1" 21 | #[arg(long)] 22 | host: Option, 23 | /// The server host client pretend to connect. It's used for testing SSL/TLS to an arbitrary host. 24 | #[arg(long)] 25 | host_override: Option, 26 | /// The server port to connect to. For example, 8080 27 | #[arg(long)] 28 | port: Option, 29 | /// The name of the test case to execute. For example, "empty_unary" 30 | #[arg(long)] 31 | case: Option, 32 | /// Whether to use a plaintext or encrypted connection 33 | #[arg(long)] 34 | use_tls: Option, 35 | /// Whether to replace platform root CAs with ca.pem as the CA root 36 | #[arg(long)] 37 | use_test_ca: Option, 38 | } 39 | 40 | fn main() { 41 | let cli = ClientCli::parse(); 42 | let host = cli.host.as_deref().unwrap_or("127.0.0.1"); 43 | let host_override = cli.host_override.as_deref().unwrap_or("foo.test.google.fr"); 44 | let port = cli.port.unwrap_or(8080); 45 | let case = cli.case.as_deref(); 46 | let use_tls = cli.use_tls.unwrap_or(false); 47 | let use_test_ca = cli.use_test_ca.unwrap_or(false); 48 | 49 | let env = Arc::new(Environment::new(1)); 50 | let mut builder = ChannelBuilder::new(env).override_ssl_target(host_override.to_owned()); 51 | if use_tls { 52 | let creds = if use_test_ca { 53 | util::create_test_channel_credentials() 54 | } else { 55 | ChannelCredentialsBuilder::new().build() 56 | }; 57 | builder = builder.set_credentials(creds); 58 | } 59 | let channel = builder.connect(&format!("{host}:{port}")); 60 | 61 | let client = Client::new(channel); 62 | futures_executor::block_on(run_test(client, case)).unwrap(); 63 | } 64 | 65 | async fn run_test(client: Client, case: Option<&str>) -> grpcio::Result<()> { 66 | let case_str = match case { 67 | None => { 68 | return client.test_all().await; 69 | } 70 | Some(s) => s, 71 | }; 72 | 73 | match case_str.to_uppercase().as_str() { 74 | "EMPTY_UNARY" => client.empty_unary().await, 75 | "LARGE_UNARY" => client.large_unary().await, 76 | "CLIENT_STREAMING" => client.client_streaming().await, 77 | "SERVER_STREAMING" => client.server_streaming().await, 78 | "PING_PONG" => client.ping_pong().await, 79 | "CUSTOM_METADATA" => client.custom_metadata().await, 80 | "EMPTY_STREAM" => client.empty_stream().await, 81 | "CANCEL_AFTER_BEGIN" => client.cancel_after_begin().await, 82 | "CANCEL_AFTER_FIRST_RESPONSE" => client.cancel_after_first_response().await, 83 | "TIMEOUT_ON_SLEEPING_SERVER" => client.timeout_on_sleeping_server().await, 84 | "STATUS_CODE_AND_MESSAGE" => client.status_code_and_message().await, 85 | "UNIMPLEMENTED_METHOD" => client.unimplemented_method().await, 86 | "UNIMPLEMENTED_SERVICE" => client.unimplemented_service().await, 87 | _ => panic!("unknown case: {:?}", case), 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /interop/src/bin/server.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | extern crate grpcio as grpc; 4 | extern crate grpcio_proto as grpc_proto; 5 | #[macro_use] 6 | extern crate log; 7 | 8 | use std::sync::Arc; 9 | 10 | use clap::Parser; 11 | use futures_executor::block_on; 12 | use grpc::{Environment, ServerBuilder, ServerCredentials}; 13 | use grpc_proto::testing::test_grpc::create_test_service; 14 | use grpc_proto::util; 15 | use interop::InteropTestService; 16 | 17 | /// Interoperability Test Server 18 | /// 19 | /// ref https://github.com/grpc/grpc/blob/v1.3.x/doc/interop-test-descriptions.md. 20 | #[derive(Parser)] 21 | struct ServerCli { 22 | /// The server host to listen to. For example, "localhost" or "127.0.0.1" 23 | #[arg(long)] 24 | host: Option, 25 | /// The port to listen on. For example, 8080 26 | #[arg(long)] 27 | port: Option, 28 | /// Whether to use a plaintext or encrypted connection 29 | #[arg(long)] 30 | use_tls: Option, 31 | } 32 | 33 | fn main() { 34 | let cli = ServerCli::parse(); 35 | let host = cli.host.as_deref().unwrap_or("127.0.0.1"); 36 | let mut port: u16 = cli.port.unwrap_or(8080); 37 | let use_tls: bool = cli.use_tls.unwrap_or(false); 38 | 39 | let env = Arc::new(Environment::new(2)); 40 | let service = create_test_service(InteropTestService); 41 | let mut server = ServerBuilder::new(env) 42 | .register_service(service) 43 | .build() 44 | .unwrap(); 45 | let creds = if use_tls { 46 | util::create_test_server_credentials() 47 | } else { 48 | ServerCredentials::insecure() 49 | }; 50 | port = server 51 | .add_listening_port(format!("{host}:{port}"), creds) 52 | .unwrap(); 53 | info!("listening on {}:{}", host, port); 54 | server.start(); 55 | 56 | block_on(futures_util::future::pending::<()>()); 57 | } 58 | -------------------------------------------------------------------------------- /interop/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #![allow(unknown_lints)] 4 | 5 | extern crate grpcio as grpc; 6 | extern crate grpcio_proto as grpc_proto; 7 | #[macro_use] 8 | extern crate log; 9 | extern crate futures_timer; 10 | 11 | mod client; 12 | mod server; 13 | 14 | pub use self::client::Client; 15 | pub use self::server::InteropTestService; 16 | -------------------------------------------------------------------------------- /interop/tests/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | extern crate grpcio as grpc; 4 | extern crate grpcio_proto as grpc_proto; 5 | extern crate interop; 6 | 7 | macro_rules! mk_test { 8 | ($case_name:ident, $func:ident, $use_tls:expr) => { 9 | #[test] 10 | fn $case_name() { 11 | let env = Arc::new(Environment::new(2)); 12 | 13 | let service = create_test_service(InteropTestService); 14 | let mut server = ServerBuilder::new(env.clone()) 15 | .register_service(service) 16 | .build() 17 | .unwrap(); 18 | let creds = if $use_tls { 19 | util::create_test_server_credentials() 20 | } else { 21 | grpcio::ServerCredentials::insecure() 22 | }; 23 | let port = server.add_listening_port("127.0.0.1:0", creds).unwrap(); 24 | server.start(); 25 | 26 | let mut builder = 27 | ChannelBuilder::new(env.clone()).override_ssl_target("foo.test.google.fr"); 28 | if $use_tls { 29 | let creds = util::create_test_channel_credentials(); 30 | builder = builder.set_credentials(creds); 31 | } 32 | let channel = builder.connect(&format!("127.0.0.1:{port}")); 33 | let client = Client::new(channel); 34 | block_on(client.$func()).unwrap(); 35 | } 36 | }; 37 | ($func:ident) => { 38 | mod $func { 39 | use std::sync::Arc; 40 | 41 | use futures_executor::block_on; 42 | use grpc::{ChannelBuilder, Environment, ServerBuilder}; 43 | use grpc_proto::testing::test_grpc::create_test_service; 44 | use grpc_proto::util; 45 | use interop::{Client, InteropTestService}; 46 | 47 | mk_test!(test_insecure, $func, false); 48 | mk_test!(test_secure, $func, true); 49 | } 50 | }; 51 | } 52 | 53 | mk_test!(empty_unary); 54 | mk_test!(large_unary); 55 | // FIXME(#305) Intermittent test. 56 | mk_test!(client_streaming); 57 | mk_test!(server_streaming); 58 | // FIXME(#306) Intermittent test. 59 | mk_test!(ping_pong); 60 | mk_test!(custom_metadata); 61 | mk_test!(empty_stream); 62 | mk_test!(cancel_after_begin); 63 | mk_test!(cancel_after_first_response); 64 | mk_test!(timeout_on_sleeping_server); 65 | mk_test!(status_code_and_message); 66 | mk_test!(unimplemented_method); 67 | mk_test!(unimplemented_service); 68 | -------------------------------------------------------------------------------- /proto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "grpcio-proto" 3 | version = "0.13.0" 4 | edition = "2018" 5 | authors = ["The TiKV Project Developers"] 6 | license = "Apache-2.0" 7 | keywords = ["grpc", "proto"] 8 | repository = "https://github.com/tikv/grpc-rs" 9 | homepage = "https://github.com/tikv/grpc-rs" 10 | documentation = "https://docs.rs/grpcio-sys" 11 | description = "Public proto files for grpcio." 12 | categories = ["network-programming"] 13 | 14 | [features] 15 | default = ["protobuf-codec"] 16 | protobuf-codec = ["grpcio/protobuf-codec", "protobuf"] 17 | protobufv3-codec = ["grpcio/protobufv3-codec", "protobufv3"] 18 | prost-codec = ["prost-build", "prost-derive", "prost-types", "bytes", "lazy_static", "grpcio/prost-codec", "prost"] 19 | 20 | [dependencies] 21 | grpcio = { path = "..", features = ["boringssl"], version = "0.13.0", default-features = false } 22 | bytes = { version = "1.0", optional = true } 23 | prost = { version = "0.13", optional = true } 24 | prost-derive = { version = "0.13", optional = true } 25 | prost-types = { version = "0.13", optional = true } 26 | protobuf = { version = "2", optional = true } 27 | protobufv3 = { package = "protobuf", version = "3.2", optional = true } 28 | lazy_static = { version = "1.3", optional = true } 29 | 30 | [build-dependencies] 31 | prost-build = { version = "0.13", optional = true } 32 | walkdir = "2.2" 33 | -------------------------------------------------------------------------------- /proto/data/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDWjCCAkKgAwIBAgIUWrP0VvHcy+LP6UuYNtiL9gBhD5owDQYJKoZIhvcNAQEL 3 | BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTIw 5 | MDMxNzE4NTk1MVoXDTMwMDMxNTE4NTk1MVowVjELMAkGA1UEBhMCQVUxEzARBgNV 6 | BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 7 | ZDEPMA0GA1UEAwwGdGVzdGNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC 8 | AQEAsGL0oXflF0LzoM+Bh+qUU9yhqzw2w8OOX5mu/iNCyUOBrqaHi7mGHx73GD01 9 | diNzCzvlcQqdNIH6NQSL7DTpBjca66jYT9u73vZe2MDrr1nVbuLvfu9850cdxiUO 10 | Inv5xf8+sTHG0C+a+VAvMhsLiRjsq+lXKRJyk5zkbbsETybqpxoJ+K7CoSy3yc/k 11 | QIY3TipwEtwkKP4hzyo6KiGd/DPexie4nBUInN3bS1BUeNZ5zeaIC2eg3bkeeW7c 12 | qT55b+Yen6CxY0TEkzBK6AKt/WUialKMgT0wbTxRZO7kUCH3Sq6e/wXeFdJ+HvdV 13 | LPlAg5TnMaNpRdQih/8nRFpsdwIDAQABoyAwHjAMBgNVHRMEBTADAQH/MA4GA1Ud 14 | DwEB/wQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEAkTrKZjBrJXHps/HrjNCFPb5a 15 | THuGPCSsepe1wkKdSp1h4HGRpLoCgcLysCJ5hZhRpHkRihhef+rFHEe60UePQO3S 16 | CVTtdJB4CYWpcNyXOdqefrbJW5QNljxgi6Fhvs7JJkBqdXIkWXtFk2eRgOIP2Eo9 17 | /OHQHlYnwZFrk6sp4wPyR+A95S0toZBcyDVz7u+hOW0pGK3wviOe9lvRgj/H3Pwt 18 | bewb0l+MhRig0/DVHamyVxrDRbqInU1/GTNCwcZkXKYFWSf92U+kIcTth24Q1gcw 19 | eZiLl5FfrWokUNytFElXob0V0a5/kbhiLc3yWmvWqHTpqCALbVyF+rKJo2f5Kw== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /proto/data/server1.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDnE443EknxvxBq 3 | 6+hvn/t09hl8hx366EBYvZmVM/NC+7igXRAjiJiA/mIaCvL3MS0Iz5hBLxSGICU+ 4 | WproA3GCIFITIwcf/ETyWj/5xpgZ4AKrLrjQmmX8mhwUajfF3UvwMJrCOVqPp67t 5 | PtP+2kBXaqrXdvnvXR41FsIB8V7zIAuIZB6bHQhiGVlc1sgZYsE2EGG9WMmHtS86 6 | qkAOTjG2XyjmPTGAwhGDpYkYrpzp99IiDh4/Veai81hn0ssQkbry0XRD/Ig3jcHh 7 | 23WiriPNJ0JsbgXUSLKRPZObA9VgOLy2aXoN84IMaeK3yy+cwSYG/99w93fUZJte 8 | MXwz4oYZAgMBAAECggEBAIVn2Ncai+4xbH0OLWckabwgyJ4IM9rDc0LIU368O1kU 9 | koais8qP9dujAWgfoh3sGh/YGgKn96VnsZjKHlyMgF+r4TaDJn3k2rlAOWcurGlj 10 | 1qaVlsV4HiEzp7pxiDmHhWvp4672Bb6iBG+bsjCUOEk/n9o9KhZzIBluRhtxCmw5 11 | nw4Do7z00PTvN81260uPWSc04IrytvZUiAIx/5qxD72bij2xJ8t/I9GI8g4FtoVB 12 | 8pB6S/hJX1PZhh9VlU6Yk+TOfOVnbebG4W5138LkB835eqk3Zz0qsbc2euoi8Hxi 13 | y1VGwQEmMQ63jXz4c6g+X55ifvUK9Jpn5E8pq+pMd7ECgYEA93lYq+Cr54K4ey5t 14 | sWMa+ye5RqxjzgXj2Kqr55jb54VWG7wp2iGbg8FMlkQwzTJwebzDyCSatguEZLuB 15 | gRGroRnsUOy9vBvhKPOch9bfKIl6qOgzMJB267fBVWx5ybnRbWN/I7RvMQf3k+9y 16 | biCIVnxDLEEYyx7z85/5qxsXg/MCgYEA7wmWKtCTn032Hy9P8OL49T0X6Z8FlkDC 17 | Rk42ygrc/MUbugq9RGUxcCxoImOG9JXUpEtUe31YDm2j+/nbvrjl6/bP2qWs0V7l 18 | dTJl6dABP51pCw8+l4cWgBBX08Lkeen812AAFNrjmDCjX6rHjWHLJcpS18fnRRkP 19 | V1d/AHWX7MMCgYEA6Gsw2guhp0Zf2GCcaNK5DlQab8OL4Hwrpttzo4kuTlwtqNKp 20 | Q9H4al9qfF4Cr1TFya98+EVYf8yFRM3NLNjZpe3gwYf2EerlJj7VLcahw0KKzoN1 21 | QBENfwgPLRk5sDkx9VhSmcfl/diLroZdpAwtv3vo4nEoxeuGFbKTGx3Qkf0CgYEA 22 | xyR+dcb05Ygm3w4klHQTowQ10s1H80iaUcZBgQuR1ghEtDbUPZHsoR5t1xCB02ys 23 | DgAwLv1bChIvxvH/L6KM8ovZ2LekBX4AviWxoBxJnfz/EVau98B0b1auRN6eSC83 24 | FRuGldlSOW1z/nSh8ViizSYE5H5HX1qkXEippvFRE88CgYB3Bfu3YQY60ITWIShv 25 | nNkdcbTT9eoP9suaRJjw92Ln+7ZpALYlQMKUZmJ/5uBmLs4RFwUTQruLOPL4yLTH 26 | awADWUzs3IRr1fwn9E+zM8JVyKCnUEM3w4N5UZskGO2klashAd30hWO+knRv/y0r 27 | uGIYs9Ek7YXlXIRVrzMwcsrt1w== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /proto/data/server1.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDtDCCApygAwIBAgIUbJfTREJ6k6/+oInWhV1O1j3ZT0IwDQYJKoZIhvcNAQEL 3 | BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTIw 5 | MDMxODAzMTA0MloXDTMwMDMxNjAzMTA0MlowZTELMAkGA1UEBhMCVVMxETAPBgNV 6 | BAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRUwEwYDVQQKDAxFeGFtcGxl 7 | LCBDby4xGjAYBgNVBAMMESoudGVzdC5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B 8 | AQEFAAOCAQ8AMIIBCgKCAQEA5xOONxJJ8b8Qauvob5/7dPYZfIcd+uhAWL2ZlTPz 9 | Qvu4oF0QI4iYgP5iGgry9zEtCM+YQS8UhiAlPlqa6ANxgiBSEyMHH/xE8lo/+caY 10 | GeACqy640Jpl/JocFGo3xd1L8DCawjlaj6eu7T7T/tpAV2qq13b5710eNRbCAfFe 11 | 8yALiGQemx0IYhlZXNbIGWLBNhBhvVjJh7UvOqpADk4xtl8o5j0xgMIRg6WJGK6c 12 | 6ffSIg4eP1XmovNYZ9LLEJG68tF0Q/yIN43B4dt1oq4jzSdCbG4F1EiykT2TmwPV 13 | YDi8tml6DfOCDGnit8svnMEmBv/fcPd31GSbXjF8M+KGGQIDAQABo2swaTAJBgNV 14 | HRMEAjAAMAsGA1UdDwQEAwIF4DBPBgNVHREESDBGghAqLnRlc3QuZ29vZ2xlLmZy 15 | ghh3YXRlcnpvb2kudGVzdC5nb29nbGUuYmWCEioudGVzdC55b3V0dWJlLmNvbYcE 16 | wKgBAzANBgkqhkiG9w0BAQsFAAOCAQEAS8hDQA8PSgipgAml7Q3/djwQ644ghWQv 17 | C2Kb+r30RCY1EyKNhnQnIIh/OUbBZvh0M0iYsy6xqXgfDhCB93AA6j0i5cS8fkhH 18 | Jl4RK0tSkGQ3YNY4NzXwQP/vmUgfkw8VBAZ4Y4GKxppdATjffIW+srbAmdDruIRM 19 | wPeikgOoRrXf0LA1fi4TqxARzeRwenQpayNfGHTvVF9aJkl8HoaMunTAdG5pIVcr 20 | 9GKi/gEMpXUJbbVv3U5frX1Wo4CFo+rZWJ/LyCMeb0jciNLxSdMwj/E/ZuExlyeZ 21 | gc9ctPjSMvgSyXEKv6Vwobleeg88V2ZgzenziORoWj4KszG/lbQZvg== 22 | -----END CERTIFICATE----- 23 | -------------------------------------------------------------------------------- /proto/proto/google/rpc/status.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. 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 google.rpc; 18 | 19 | import "google/protobuf/any.proto"; 20 | 21 | option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; 22 | option java_multiple_files = true; 23 | option java_outer_classname = "StatusProto"; 24 | option java_package = "com.google.rpc"; 25 | option objc_class_prefix = "RPC"; 26 | 27 | 28 | // The `Status` type defines a logical error model that is suitable for different 29 | // programming environments, including REST APIs and RPC APIs. It is used by 30 | // [gRPC](https://github.com/grpc). The error model is designed to be: 31 | // 32 | // - Simple to use and understand for most users 33 | // - Flexible enough to meet unexpected needs 34 | // 35 | // # Overview 36 | // 37 | // The `Status` message contains three pieces of data: error code, error message, 38 | // and error details. The error code should be an enum value of 39 | // [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed. The 40 | // error message should be a developer-facing English message that helps 41 | // developers *understand* and *resolve* the error. If a localized user-facing 42 | // error message is needed, put the localized message in the error details or 43 | // localize it in the client. The optional error details may contain arbitrary 44 | // information about the error. There is a predefined set of error detail types 45 | // in the package `google.rpc` which can be used for common error conditions. 46 | // 47 | // # Language mapping 48 | // 49 | // The `Status` message is the logical representation of the error model, but it 50 | // is not necessarily the actual wire format. When the `Status` message is 51 | // exposed in different client libraries and different wire protocols, it can be 52 | // mapped differently. For example, it will likely be mapped to some exceptions 53 | // in Java, but more likely mapped to some error codes in C. 54 | // 55 | // # Other uses 56 | // 57 | // The error model and the `Status` message can be used in a variety of 58 | // environments, either with or without APIs, to provide a 59 | // consistent developer experience across different environments. 60 | // 61 | // Example uses of this error model include: 62 | // 63 | // - Partial errors. If a service needs to return partial errors to the client, 64 | // it may embed the `Status` in the normal response to indicate the partial 65 | // errors. 66 | // 67 | // - Workflow errors. A typical workflow has multiple steps. Each step may 68 | // have a `Status` message for error reporting purpose. 69 | // 70 | // - Batch operations. If a client uses batch request and batch response, the 71 | // `Status` message should be used directly inside batch response, one for 72 | // each error sub-response. 73 | // 74 | // - Asynchronous operations. If an API call embeds asynchronous operation 75 | // results in its response, the status of those operations should be 76 | // represented directly using the `Status` message. 77 | // 78 | // - Logging. If some API errors are stored in logs, the message `Status` could 79 | // be used directly after any stripping needed for security/privacy reasons. 80 | message Status { 81 | // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. 82 | int32 code = 1; 83 | 84 | // A developer-facing error message, which should be in English. Any 85 | // user-facing error message should be localized and sent in the 86 | // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. 87 | string message = 2; 88 | 89 | // A list of messages that carry the error details. There will be a 90 | // common set of message types for APIs to use. 91 | repeated google.protobuf.Any details = 3; 92 | } 93 | -------------------------------------------------------------------------------- /proto/proto/grpc/example/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC 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 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.helloworld"; 19 | option java_outer_classname = "HelloWorldProto"; 20 | option objc_class_prefix = "HLW"; 21 | 22 | package helloworld; 23 | 24 | // The greeting service definition. 25 | service Greeter { 26 | // Sends a greeting 27 | rpc SayHello (HelloRequest) returns (HelloReply) {} 28 | } 29 | 30 | // The request message containing the user's name. 31 | message HelloRequest { 32 | string name = 1; 33 | } 34 | 35 | // The response message containing the greetings 36 | message HelloReply { 37 | string message = 1; 38 | } 39 | -------------------------------------------------------------------------------- /proto/proto/grpc/example/route_guide.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC 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 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.routeguide"; 19 | option java_outer_classname = "RouteGuideProto"; 20 | option objc_class_prefix = "RTG"; 21 | 22 | package routeguide; 23 | 24 | // Interface exported by the server. 25 | service RouteGuide { 26 | // A simple RPC. 27 | // 28 | // Obtains the feature at a given position. 29 | // 30 | // A feature with an empty name is returned if there's no feature at the given 31 | // position. 32 | rpc GetFeature(Point) returns (Feature) {} 33 | 34 | // A server-to-client streaming RPC. 35 | // 36 | // Obtains the Features available within the given Rectangle. Results are 37 | // streamed rather than returned at once (e.g. in a response message with a 38 | // repeated field), as the rectangle may cover a large area and contain a 39 | // huge number of features. 40 | rpc ListFeatures(Rectangle) returns (stream Feature) {} 41 | 42 | // A client-to-server streaming RPC. 43 | // 44 | // Accepts a stream of Points on a route being traversed, returning a 45 | // RouteSummary when traversal is completed. 46 | rpc RecordRoute(stream Point) returns (RouteSummary) {} 47 | 48 | // A Bidirectional streaming RPC. 49 | // 50 | // Accepts a stream of RouteNotes sent while a route is being traversed, 51 | // while receiving other RouteNotes (e.g. from other users). 52 | rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} 53 | } 54 | 55 | // Points are represented as latitude-longitude pairs in the E7 representation 56 | // (degrees multiplied by 10**7 and rounded to the nearest integer). 57 | // Latitudes should be in the range +/- 90 degrees and longitude should be in 58 | // the range +/- 180 degrees (inclusive). 59 | message Point { 60 | int32 latitude = 1; 61 | int32 longitude = 2; 62 | } 63 | 64 | // A latitude-longitude rectangle, represented as two diagonally opposite 65 | // points "lo" and "hi". 66 | message Rectangle { 67 | // One corner of the rectangle. 68 | Point lo = 1; 69 | 70 | // The other corner of the rectangle. 71 | Point hi = 2; 72 | } 73 | 74 | // A feature names something at a given point. 75 | // 76 | // If a feature could not be named, the name is empty. 77 | message Feature { 78 | // The name of the feature. 79 | string name = 1; 80 | 81 | // The point where the feature is detected. 82 | Point location = 2; 83 | } 84 | 85 | // A RouteNote is a message sent while at a given point. 86 | message RouteNote { 87 | // The location from which the message is sent. 88 | Point location = 1; 89 | 90 | // The message to be sent. 91 | string message = 2; 92 | } 93 | 94 | // A RouteSummary is received in response to a RecordRoute rpc. 95 | // 96 | // It contains the number of individual points received, the number of 97 | // detected features, and the total distance covered as the cumulative sum of 98 | // the distance between each point. 99 | message RouteSummary { 100 | // The number of points received. 101 | int32 point_count = 1; 102 | 103 | // The number of known features passed while traversing the route. 104 | int32 feature_count = 2; 105 | 106 | // The distance covered in metres. 107 | int32 distance = 3; 108 | 109 | // The duration of the traversal in seconds. 110 | int32 elapsed_time = 4; 111 | } 112 | -------------------------------------------------------------------------------- /proto/proto/grpc/health/v1/health.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC 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 grpc.health.v1; 18 | option csharp_namespace = "Grpc.Health.V1"; 19 | 20 | message HealthCheckRequest { 21 | string service = 1; 22 | } 23 | 24 | message HealthCheckResponse { 25 | enum ServingStatus { 26 | UNKNOWN = 0; 27 | SERVING = 1; 28 | NOT_SERVING = 2; 29 | } 30 | ServingStatus status = 1; 31 | } 32 | 33 | service Health { 34 | rpc Check(HealthCheckRequest) returns (HealthCheckResponse); 35 | } 36 | -------------------------------------------------------------------------------- /proto/proto/grpc/testing/empty.proto: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2015 gRPC authors. 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 | syntax = "proto3"; 17 | 18 | package grpc.testing; 19 | 20 | // An empty message that you can re-use to avoid defining duplicated empty 21 | // messages in your project. A typical example is to use it as argument or the 22 | // return value of a service API. For instance: 23 | // 24 | // service Foo { 25 | // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; 26 | // }; 27 | // 28 | message Empty {} 29 | -------------------------------------------------------------------------------- /proto/proto/grpc/testing/messages.proto: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2015-2016 gRPC authors. 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 | // Message definitions to be used by integration test service definitions. 17 | 18 | syntax = "proto3"; 19 | 20 | package grpc.testing; 21 | 22 | // TODO(dgq): Go back to using well-known types once 23 | // https://github.com/grpc/grpc/issues/6980 has been fixed. 24 | // import "google/protobuf/wrappers.proto"; 25 | message BoolValue { 26 | // The bool value. 27 | bool value = 1; 28 | } 29 | 30 | // DEPRECATED, don't use. To be removed shortly. 31 | // The type of payload that should be returned. 32 | enum PayloadType { 33 | // Compressable text format. 34 | COMPRESSABLE = 0; 35 | } 36 | 37 | // A block of data, to simply increase gRPC message size. 38 | message Payload { 39 | // DEPRECATED, don't use. To be removed shortly. 40 | // The type of data in body. 41 | PayloadType type = 1; 42 | // Primary contents of payload. 43 | bytes body = 2; 44 | } 45 | 46 | // A protobuf representation for grpc status. This is used by test 47 | // clients to specify a status that the server should attempt to return. 48 | message EchoStatus { 49 | int32 code = 1; 50 | string message = 2; 51 | } 52 | 53 | // Unary request. 54 | message SimpleRequest { 55 | // DEPRECATED, don't use. To be removed shortly. 56 | // Desired payload type in the response from the server. 57 | // If response_type is RANDOM, server randomly chooses one from other formats. 58 | PayloadType response_type = 1; 59 | 60 | // Desired payload size in the response from the server. 61 | int32 response_size = 2; 62 | 63 | // Optional input payload sent along with the request. 64 | Payload payload = 3; 65 | 66 | // Whether SimpleResponse should include username. 67 | bool fill_username = 4; 68 | 69 | // Whether SimpleResponse should include OAuth scope. 70 | bool fill_oauth_scope = 5; 71 | 72 | // Whether to request the server to compress the response. This field is 73 | // "nullable" in order to interoperate seamlessly with clients not able to 74 | // implement the full compression tests by introspecting the call to verify 75 | // the response's compression status. 76 | BoolValue response_compressed = 6; 77 | 78 | // Whether server should return a given status 79 | EchoStatus response_status = 7; 80 | 81 | // Whether the server should expect this request to be compressed. 82 | BoolValue expect_compressed = 8; 83 | } 84 | 85 | // Unary response, as configured by the request. 86 | message SimpleResponse { 87 | // Payload to increase message size. 88 | Payload payload = 1; 89 | // The user the request came from, for verifying authentication was 90 | // successful when the client expected it. 91 | string username = 2; 92 | // OAuth scope. 93 | string oauth_scope = 3; 94 | } 95 | 96 | // Client-streaming request. 97 | message StreamingInputCallRequest { 98 | // Optional input payload sent along with the request. 99 | Payload payload = 1; 100 | 101 | // Whether the server should expect this request to be compressed. This field 102 | // is "nullable" in order to interoperate seamlessly with servers not able to 103 | // implement the full compression tests by introspecting the call to verify 104 | // the request's compression status. 105 | BoolValue expect_compressed = 2; 106 | 107 | // Not expecting any payload from the response. 108 | } 109 | 110 | // Client-streaming response. 111 | message StreamingInputCallResponse { 112 | // Aggregated size of payloads received from the client. 113 | int32 aggregated_payload_size = 1; 114 | } 115 | 116 | // Configuration for a particular response. 117 | message ResponseParameters { 118 | // Desired payload sizes in responses from the server. 119 | int32 size = 1; 120 | 121 | // Desired interval between consecutive responses in the response stream in 122 | // microseconds. 123 | int32 interval_us = 2; 124 | 125 | // Whether to request the server to compress the response. This field is 126 | // "nullable" in order to interoperate seamlessly with clients not able to 127 | // implement the full compression tests by introspecting the call to verify 128 | // the response's compression status. 129 | BoolValue compressed = 3; 130 | } 131 | 132 | // Server-streaming request. 133 | message StreamingOutputCallRequest { 134 | // DEPRECATED, don't use. To be removed shortly. 135 | // Desired payload type in the response from the server. 136 | // If response_type is RANDOM, the payload from each response in the stream 137 | // might be of different types. This is to simulate a mixed type of payload 138 | // stream. 139 | PayloadType response_type = 1; 140 | 141 | // Configuration for each expected response message. 142 | repeated ResponseParameters response_parameters = 2; 143 | 144 | // Optional input payload sent along with the request. 145 | Payload payload = 3; 146 | 147 | // Whether server should return a given status 148 | EchoStatus response_status = 7; 149 | } 150 | 151 | // Server-streaming response, as configured by the request and parameters. 152 | message StreamingOutputCallResponse { 153 | // Payload to increase response size. 154 | Payload payload = 1; 155 | } 156 | 157 | // For reconnect interop test only. 158 | // Client tells server what reconnection parameters it used. 159 | message ReconnectParams { 160 | int32 max_reconnect_backoff_ms = 1; 161 | } 162 | 163 | // For reconnect interop test only. 164 | // Server tells client whether its reconnects are following the spec and the 165 | // reconnect backoffs it saw. 166 | message ReconnectInfo { 167 | bool passed = 1; 168 | repeated int32 backoff_ms = 2; 169 | } 170 | -------------------------------------------------------------------------------- /proto/proto/grpc/testing/payloads.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC 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 grpc.testing; 18 | 19 | message ByteBufferParams { 20 | int32 req_size = 1; 21 | int32 resp_size = 2; 22 | } 23 | 24 | message SimpleProtoParams { 25 | int32 req_size = 1; 26 | int32 resp_size = 2; 27 | } 28 | 29 | message ComplexProtoParams { 30 | // TODO (vpai): Fill this in once the details of complex, representative 31 | // protos are decided 32 | } 33 | 34 | message PayloadConfig { 35 | oneof payload { 36 | ByteBufferParams bytebuf_params = 1; 37 | SimpleProtoParams simple_params = 2; 38 | ComplexProtoParams complex_params = 3; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /proto/proto/grpc/testing/services.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC 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 | // An integration test service that covers all the method signature permutations 16 | // of unary/streaming requests/responses. 17 | syntax = "proto3"; 18 | 19 | import "grpc/testing/messages.proto"; 20 | import "grpc/testing/control.proto"; 21 | import "grpc/testing/stats.proto"; 22 | 23 | package grpc.testing; 24 | 25 | service BenchmarkService { 26 | // One request followed by one response. 27 | // The server returns the client payload as-is. 28 | rpc UnaryCall(SimpleRequest) returns (SimpleResponse); 29 | 30 | // Repeated sequence of one request followed by one response. 31 | // Should be called streaming ping-pong 32 | // The server returns the client payload as-is on each response 33 | rpc StreamingCall(stream SimpleRequest) returns (stream SimpleResponse); 34 | 35 | // Single-sided unbounded streaming from client to server 36 | // The server returns the client payload as-is once the client does WritesDone 37 | rpc StreamingFromClient(stream SimpleRequest) returns (SimpleResponse); 38 | 39 | // Single-sided unbounded streaming from server to client 40 | // The server repeatedly returns the client payload as-is 41 | rpc StreamingFromServer(SimpleRequest) returns (stream SimpleResponse); 42 | 43 | // Two-sided unbounded streaming between server to client 44 | // Both sides send the content of their own choice to the other 45 | rpc StreamingBothWays(stream SimpleRequest) returns (stream SimpleResponse); 46 | } 47 | 48 | service WorkerService { 49 | // Start server with specified workload. 50 | // First request sent specifies the ServerConfig followed by ServerStatus 51 | // response. After that, a "Mark" can be sent anytime to request the latest 52 | // stats. Closing the stream will initiate shutdown of the test server 53 | // and once the shutdown has finished, the OK status is sent to terminate 54 | // this RPC. 55 | rpc RunServer(stream ServerArgs) returns (stream ServerStatus); 56 | 57 | // Start client with specified workload. 58 | // First request sent specifies the ClientConfig followed by ClientStatus 59 | // response. After that, a "Mark" can be sent anytime to request the latest 60 | // stats. Closing the stream will initiate shutdown of the test client 61 | // and once the shutdown has finished, the OK status is sent to terminate 62 | // this RPC. 63 | rpc RunClient(stream ClientArgs) returns (stream ClientStatus); 64 | 65 | // Just return the core count - unary call 66 | rpc CoreCount(CoreRequest) returns (CoreResponse); 67 | 68 | // Quit this worker 69 | rpc QuitWorker(Void) returns (Void); 70 | } 71 | 72 | service ReportQpsScenarioService { 73 | // Report results of a QPS test benchmark scenario. 74 | rpc ReportScenario(ScenarioResult) returns (Void); 75 | } 76 | -------------------------------------------------------------------------------- /proto/proto/grpc/testing/stats.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC 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 grpc.testing; 18 | 19 | message ServerStats { 20 | // wall clock time change in seconds since last reset 21 | double time_elapsed = 1; 22 | 23 | // change in user time (in seconds) used by the server since last reset 24 | double time_user = 2; 25 | 26 | // change in server time (in seconds) used by the server process and all 27 | // threads since last reset 28 | double time_system = 3; 29 | 30 | // change in total cpu time of the server (data from proc/stat) 31 | uint64 total_cpu_time = 4; 32 | 33 | // change in idle time of the server (data from proc/stat) 34 | uint64 idle_cpu_time = 5; 35 | 36 | // Number of polls called inside completion queue 37 | uint64 cq_poll_count = 6; 38 | } 39 | 40 | // Histogram params based on grpc/support/histogram.c 41 | message HistogramParams { 42 | double resolution = 1; // first bucket is [0, 1 + resolution) 43 | double max_possible = 2; // use enough buckets to allow this value 44 | } 45 | 46 | // Histogram data based on grpc/support/histogram.c 47 | message HistogramData { 48 | repeated uint32 bucket = 1; 49 | double min_seen = 2; 50 | double max_seen = 3; 51 | double sum = 4; 52 | double sum_of_squares = 5; 53 | double count = 6; 54 | } 55 | 56 | message RequestResultCount { 57 | int32 status_code = 1; 58 | int64 count = 2; 59 | } 60 | 61 | message ClientStats { 62 | // Latency histogram. Data points are in nanoseconds. 63 | HistogramData latencies = 1; 64 | 65 | // See ServerStats for details. 66 | double time_elapsed = 2; 67 | double time_user = 3; 68 | double time_system = 4; 69 | 70 | // Number of failed requests (one row per status code seen) 71 | repeated RequestResultCount request_results = 5; 72 | 73 | // Number of polls called inside completion queue 74 | uint64 cq_poll_count = 6; 75 | } 76 | -------------------------------------------------------------------------------- /proto/proto/grpc/testing/test.proto: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2015-2016 gRPC authors. 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 | // An integration test service that covers all the method signature permutations 17 | // of unary/streaming requests/responses. 18 | 19 | syntax = "proto3"; 20 | 21 | import "grpc/testing/empty.proto"; 22 | import "grpc/testing/messages.proto"; 23 | 24 | package grpc.testing; 25 | 26 | // A simple service to test the various types of RPCs and experiment with 27 | // performance with various types of payload. 28 | service TestService { 29 | // One empty request followed by one empty response. 30 | rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); 31 | 32 | // One request followed by one response. 33 | rpc UnaryCall(SimpleRequest) returns (SimpleResponse); 34 | 35 | // One request followed by one response. Response has cache control 36 | // headers set such that a caching HTTP proxy (such as GFE) can 37 | // satisfy subsequent requests. 38 | rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse); 39 | 40 | // One request followed by a sequence of responses (streamed download). 41 | // The server returns the payload with client desired type and sizes. 42 | rpc StreamingOutputCall(StreamingOutputCallRequest) 43 | returns (stream StreamingOutputCallResponse); 44 | 45 | // A sequence of requests followed by one response (streamed upload). 46 | // The server returns the aggregated size of client payload as the result. 47 | rpc StreamingInputCall(stream StreamingInputCallRequest) 48 | returns (StreamingInputCallResponse); 49 | 50 | // A sequence of requests with each request served by the server immediately. 51 | // As one request could lead to multiple responses, this interface 52 | // demonstrates the idea of full duplexing. 53 | rpc FullDuplexCall(stream StreamingOutputCallRequest) 54 | returns (stream StreamingOutputCallResponse); 55 | 56 | // A sequence of requests followed by a sequence of responses. 57 | // The server buffers all the client requests and then serves them in order. A 58 | // stream of responses are returned to the client when the server starts with 59 | // first request. 60 | rpc HalfDuplexCall(stream StreamingOutputCallRequest) 61 | returns (stream StreamingOutputCallResponse); 62 | 63 | // The test server will not implement this method. It will be used 64 | // to test the behavior when clients call unimplemented methods. 65 | rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); 66 | } 67 | 68 | // A simple service NOT implemented at servers so clients can test for 69 | // that case. 70 | service UnimplementedService { 71 | // A call that no server should implement 72 | rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); 73 | } 74 | 75 | // A service used to control reconnect server. 76 | service ReconnectService { 77 | rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty); 78 | rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); 79 | } 80 | -------------------------------------------------------------------------------- /proto/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #[allow(renamed_and_removed_lints)] 4 | #[allow(static_mut_refs)] 5 | mod proto; 6 | 7 | #[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] 8 | pub use proto::protobuf::*; 9 | 10 | #[cfg(feature = "prost-codec")] 11 | pub use proto::prost::*; 12 | 13 | pub mod util; 14 | -------------------------------------------------------------------------------- /proto/src/proto/prost/example/helloworld.rs: -------------------------------------------------------------------------------- 1 | // This file is @generated by prost-build. 2 | /// The request message containing the user's name. 3 | #[derive(Clone, PartialEq, ::prost::Message)] 4 | pub struct HelloRequest { 5 | #[prost(string, tag = "1")] 6 | pub name: ::prost::alloc::string::String, 7 | } 8 | /// The response message containing the greetings 9 | #[derive(Clone, PartialEq, ::prost::Message)] 10 | pub struct HelloReply { 11 | #[prost(string, tag = "1")] 12 | pub message: ::prost::alloc::string::String, 13 | } 14 | const METHOD_GREETER_SAY_HELLO: ::grpcio::Method = ::grpcio::Method { 15 | ty: ::grpcio::MethodType::Unary, 16 | name: "/helloworld.Greeter/SayHello", 17 | req_mar: ::grpcio::Marshaller { 18 | ser: ::grpcio::pr_ser, 19 | de: ::grpcio::pr_de, 20 | }, 21 | resp_mar: ::grpcio::Marshaller { 22 | ser: ::grpcio::pr_ser, 23 | de: ::grpcio::pr_de, 24 | }, 25 | }; 26 | #[derive(Clone)] 27 | pub struct GreeterClient { 28 | pub client: ::grpcio::Client, 29 | } 30 | impl GreeterClient { 31 | pub fn new(channel: ::grpcio::Channel) -> Self { 32 | GreeterClient { 33 | client: ::grpcio::Client::new(channel), 34 | } 35 | } 36 | pub fn say_hello_opt( 37 | &self, 38 | req: &HelloRequest, 39 | opt: ::grpcio::CallOption, 40 | ) -> ::grpcio::Result { 41 | self.client.unary_call(&METHOD_GREETER_SAY_HELLO, req, opt) 42 | } 43 | pub fn say_hello(&self, req: &HelloRequest) -> ::grpcio::Result { 44 | self.say_hello_opt(req, ::grpcio::CallOption::default()) 45 | } 46 | pub fn say_hello_async_opt( 47 | &self, 48 | req: &HelloRequest, 49 | opt: ::grpcio::CallOption, 50 | ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 51 | self.client 52 | .unary_call_async(&METHOD_GREETER_SAY_HELLO, req, opt) 53 | } 54 | pub fn say_hello_async( 55 | &self, 56 | req: &HelloRequest, 57 | ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 58 | self.say_hello_async_opt(req, ::grpcio::CallOption::default()) 59 | } 60 | pub fn spawn(&self, f: F) 61 | where 62 | F: ::std::future::Future + Send + 'static, 63 | { 64 | self.client.spawn(f) 65 | } 66 | } 67 | pub trait Greeter { 68 | fn say_hello( 69 | &mut self, 70 | ctx: ::grpcio::RpcContext, 71 | _req: HelloRequest, 72 | sink: ::grpcio::UnarySink, 73 | ) { 74 | grpcio::unimplemented_call!(ctx, sink) 75 | } 76 | } 77 | pub fn create_greeter(s: S) -> ::grpcio::Service { 78 | let mut builder = ::grpcio::ServiceBuilder::new(); 79 | let mut instance = s; 80 | builder = builder.add_unary_handler(&METHOD_GREETER_SAY_HELLO, move |ctx, req, resp| { 81 | instance.say_hello(ctx, req, resp) 82 | }); 83 | builder.build() 84 | } 85 | -------------------------------------------------------------------------------- /proto/src/proto/prost/google/rpc/google.rpc.rs: -------------------------------------------------------------------------------- 1 | // This file is @generated by prost-build. 2 | /// The `Status` type defines a logical error model that is suitable for different 3 | /// programming environments, including REST APIs and RPC APIs. It is used by 4 | /// [gRPC](). The error model is designed to be: 5 | /// 6 | /// - Simple to use and understand for most users 7 | /// - Flexible enough to meet unexpected needs 8 | /// 9 | /// # Overview 10 | /// 11 | /// The `Status` message contains three pieces of data: error code, error message, 12 | /// and error details. The error code should be an enum value of 13 | /// [google.rpc.Code][google.rpc.Code], but it may accept additional error codes if needed. The 14 | /// error message should be a developer-facing English message that helps 15 | /// developers *understand* and *resolve* the error. If a localized user-facing 16 | /// error message is needed, put the localized message in the error details or 17 | /// localize it in the client. The optional error details may contain arbitrary 18 | /// information about the error. There is a predefined set of error detail types 19 | /// in the package `google.rpc` which can be used for common error conditions. 20 | /// 21 | /// # Language mapping 22 | /// 23 | /// The `Status` message is the logical representation of the error model, but it 24 | /// is not necessarily the actual wire format. When the `Status` message is 25 | /// exposed in different client libraries and different wire protocols, it can be 26 | /// mapped differently. For example, it will likely be mapped to some exceptions 27 | /// in Java, but more likely mapped to some error codes in C. 28 | /// 29 | /// # Other uses 30 | /// 31 | /// The error model and the `Status` message can be used in a variety of 32 | /// environments, either with or without APIs, to provide a 33 | /// consistent developer experience across different environments. 34 | /// 35 | /// Example uses of this error model include: 36 | /// 37 | /// - Partial errors. If a service needs to return partial errors to the client, 38 | /// it may embed the `Status` in the normal response to indicate the partial 39 | /// errors. 40 | /// 41 | /// - Workflow errors. A typical workflow has multiple steps. Each step may 42 | /// have a `Status` message for error reporting purpose. 43 | /// 44 | /// - Batch operations. If a client uses batch request and batch response, the 45 | /// `Status` message should be used directly inside batch response, one for 46 | /// each error sub-response. 47 | /// 48 | /// - Asynchronous operations. If an API call embeds asynchronous operation 49 | /// results in its response, the status of those operations should be 50 | /// represented directly using the `Status` message. 51 | /// 52 | /// - Logging. If some API errors are stored in logs, the message `Status` could 53 | /// be used directly after any stripping needed for security/privacy reasons. 54 | #[derive(Clone, PartialEq, ::prost::Message)] 55 | pub struct Status { 56 | /// The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. 57 | #[prost(int32, tag = "1")] 58 | pub code: i32, 59 | /// A developer-facing error message, which should be in English. Any 60 | /// user-facing error message should be localized and sent in the 61 | /// [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. 62 | #[prost(string, tag = "2")] 63 | pub message: ::prost::alloc::string::String, 64 | /// A list of messages that carry the error details. There will be a 65 | /// common set of message types for APIs to use. 66 | #[prost(message, repeated, tag = "3")] 67 | pub details: ::prost::alloc::vec::Vec<::prost_types::Any>, 68 | } 69 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf/example/helloworld_grpc.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | #![allow(box_pointers)] 8 | #![allow(dead_code)] 9 | #![allow(missing_docs)] 10 | #![allow(non_camel_case_types)] 11 | #![allow(non_snake_case)] 12 | #![allow(non_upper_case_globals)] 13 | #![allow(trivial_casts)] 14 | #![allow(unsafe_code)] 15 | #![allow(unused_imports)] 16 | #![allow(unused_results)] 17 | 18 | const METHOD_GREETER_SAY_HELLO: ::grpcio::Method< 19 | super::helloworld::HelloRequest, 20 | super::helloworld::HelloReply, 21 | > = ::grpcio::Method { 22 | ty: ::grpcio::MethodType::Unary, 23 | name: "/helloworld.Greeter/SayHello", 24 | req_mar: ::grpcio::Marshaller { 25 | ser: ::grpcio::pb_ser, 26 | de: ::grpcio::pb_de, 27 | }, 28 | resp_mar: ::grpcio::Marshaller { 29 | ser: ::grpcio::pb_ser, 30 | de: ::grpcio::pb_de, 31 | }, 32 | }; 33 | 34 | #[derive(Clone)] 35 | pub struct GreeterClient { 36 | pub client: ::grpcio::Client, 37 | } 38 | 39 | impl GreeterClient { 40 | pub fn new(channel: ::grpcio::Channel) -> Self { 41 | GreeterClient { 42 | client: ::grpcio::Client::new(channel), 43 | } 44 | } 45 | 46 | pub fn say_hello_opt( 47 | &self, 48 | req: &super::helloworld::HelloRequest, 49 | opt: ::grpcio::CallOption, 50 | ) -> ::grpcio::Result { 51 | self.client.unary_call(&METHOD_GREETER_SAY_HELLO, req, opt) 52 | } 53 | 54 | pub fn say_hello( 55 | &self, 56 | req: &super::helloworld::HelloRequest, 57 | ) -> ::grpcio::Result { 58 | self.say_hello_opt(req, ::grpcio::CallOption::default()) 59 | } 60 | 61 | pub fn say_hello_async_opt( 62 | &self, 63 | req: &super::helloworld::HelloRequest, 64 | opt: ::grpcio::CallOption, 65 | ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 66 | self.client 67 | .unary_call_async(&METHOD_GREETER_SAY_HELLO, req, opt) 68 | } 69 | 70 | pub fn say_hello_async( 71 | &self, 72 | req: &super::helloworld::HelloRequest, 73 | ) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 74 | self.say_hello_async_opt(req, ::grpcio::CallOption::default()) 75 | } 76 | pub fn spawn(&self, f: F) 77 | where 78 | F: ::std::future::Future + Send + 'static, 79 | { 80 | self.client.spawn(f) 81 | } 82 | } 83 | 84 | pub trait Greeter { 85 | fn say_hello( 86 | &mut self, 87 | ctx: ::grpcio::RpcContext, 88 | _req: super::helloworld::HelloRequest, 89 | sink: ::grpcio::UnarySink, 90 | ) { 91 | grpcio::unimplemented_call!(ctx, sink) 92 | } 93 | } 94 | 95 | pub fn create_greeter(s: S) -> ::grpcio::Service { 96 | let mut builder = ::grpcio::ServiceBuilder::new(); 97 | let mut instance = s; 98 | builder = builder.add_unary_handler(&METHOD_GREETER_SAY_HELLO, move |ctx, req, resp| { 99 | instance.say_hello(ctx, req, resp) 100 | }); 101 | builder.build() 102 | } 103 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf/testing/empty.rs: -------------------------------------------------------------------------------- 1 | // This file is generated by rust-protobuf 2.8.2. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | //! Generated file from `grpc/testing/empty.proto` 21 | 22 | use protobuf::Message as Message_imported_for_functions; 23 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 24 | 25 | /// Generated files are compatible only with the same version 26 | /// of protobuf runtime. 27 | 28 | #[derive(PartialEq,Clone,Default)] 29 | pub struct Empty { 30 | // special fields 31 | pub unknown_fields: ::protobuf::UnknownFields, 32 | pub cached_size: ::protobuf::CachedSize, 33 | } 34 | 35 | impl<'a> ::std::default::Default for &'a Empty { 36 | fn default() -> &'a Empty { 37 | ::default_instance() 38 | } 39 | } 40 | 41 | impl Empty { 42 | pub fn new() -> Empty { 43 | ::std::default::Default::default() 44 | } 45 | } 46 | 47 | impl ::protobuf::Message for Empty { 48 | fn is_initialized(&self) -> bool { 49 | true 50 | } 51 | 52 | fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { 53 | while !is.eof()? { 54 | let (field_number, wire_type) = is.read_tag_unpack()?; 55 | match field_number { 56 | _ => { 57 | ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; 58 | }, 59 | }; 60 | } 61 | ::std::result::Result::Ok(()) 62 | } 63 | 64 | // Compute sizes of nested messages 65 | #[allow(unused_variables)] 66 | fn compute_size(&self) -> u32 { 67 | let mut my_size = 0; 68 | my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); 69 | self.cached_size.set(my_size); 70 | my_size 71 | } 72 | 73 | fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { 74 | os.write_unknown_fields(self.get_unknown_fields())?; 75 | ::std::result::Result::Ok(()) 76 | } 77 | 78 | fn get_cached_size(&self) -> u32 { 79 | self.cached_size.get() 80 | } 81 | 82 | fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { 83 | &self.unknown_fields 84 | } 85 | 86 | fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { 87 | &mut self.unknown_fields 88 | } 89 | 90 | fn as_any(&self) -> &dyn (::std::any::Any) { 91 | self as &dyn (::std::any::Any) 92 | } 93 | fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { 94 | self as &mut dyn (::std::any::Any) 95 | } 96 | fn into_any(self: Box) -> ::std::boxed::Box { 97 | self 98 | } 99 | 100 | fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { 101 | Self::descriptor_static() 102 | } 103 | 104 | fn new() -> Empty { 105 | Empty::new() 106 | } 107 | 108 | fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { 109 | static mut descriptor: ::protobuf::lazy::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::lazy::Lazy { 110 | lock: ::protobuf::lazy::ONCE_INIT, 111 | ptr: 0 as *const ::protobuf::reflect::MessageDescriptor, 112 | }; 113 | unsafe { 114 | descriptor.get(|| { 115 | let fields = ::std::vec::Vec::new(); 116 | ::protobuf::reflect::MessageDescriptor::new::( 117 | "Empty", 118 | fields, 119 | file_descriptor_proto() 120 | ) 121 | }) 122 | } 123 | } 124 | 125 | fn default_instance() -> &'static Empty { 126 | static mut instance: ::protobuf::lazy::Lazy = ::protobuf::lazy::Lazy { 127 | lock: ::protobuf::lazy::ONCE_INIT, 128 | ptr: 0 as *const Empty, 129 | }; 130 | unsafe { 131 | instance.get(Empty::new) 132 | } 133 | } 134 | } 135 | 136 | impl ::protobuf::Clear for Empty { 137 | fn clear(&mut self) { 138 | self.unknown_fields.clear(); 139 | } 140 | } 141 | 142 | impl ::std::fmt::Debug for Empty { 143 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 144 | ::protobuf::text_format::fmt(self, f) 145 | } 146 | } 147 | 148 | impl ::protobuf::reflect::ProtobufValue for Empty { 149 | fn as_ref(&self) -> ::protobuf::reflect::ProtobufValueRef { 150 | ::protobuf::reflect::ProtobufValueRef::Message(self) 151 | } 152 | } 153 | 154 | static file_descriptor_proto_data: &'static [u8] = b"\ 155 | \n\x18grpc/testing/empty.proto\x12\x0cgrpc.testing\"\x07\n\x05Emptyb\x06\ 156 | proto3\ 157 | "; 158 | 159 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { 160 | lock: ::protobuf::lazy::ONCE_INIT, 161 | ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, 162 | }; 163 | 164 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 165 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 166 | } 167 | 168 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 169 | unsafe { 170 | file_descriptor_proto_lazy.get(|| { 171 | parse_descriptor_proto() 172 | }) 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf/testing/services.rs: -------------------------------------------------------------------------------- 1 | // This file is generated by rust-protobuf 2.8.2. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | //! Generated file from `grpc/testing/services.proto` 21 | 22 | use protobuf::Message as Message_imported_for_functions; 23 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 24 | 25 | /// Generated files are compatible only with the same version 26 | /// of protobuf runtime. 27 | 28 | static file_descriptor_proto_data: &'static [u8] = b"\ 29 | \n\x1bgrpc/testing/services.proto\x12\x0cgrpc.testing\x1a\x1bgrpc/testin\ 30 | g/messages.proto\x1a\x1agrpc/testing/control.proto\x1a\x18grpc/testing/s\ 31 | tats.proto2\xa6\x03\n\x10BenchmarkService\x12F\n\tUnaryCall\x12\x1b.grpc\ 32 | .testing.SimpleRequest\x1a\x1c.grpc.testing.SimpleResponse\x12N\n\rStrea\ 33 | mingCall\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testing.SimpleR\ 34 | esponse(\x010\x01\x12R\n\x13StreamingFromClient\x12\x1b.grpc.testing.Sim\ 35 | pleRequest\x1a\x1c.grpc.testing.SimpleResponse(\x01\x12R\n\x13StreamingF\ 36 | romServer\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testing.Simple\ 37 | Response0\x01\x12R\n\x11StreamingBothWays\x12\x1b.grpc.testing.SimpleReq\ 38 | uest\x1a\x1c.grpc.testing.SimpleResponse(\x010\x012\x97\x02\n\rWorkerSer\ 39 | vice\x12E\n\tRunServer\x12\x18.grpc.testing.ServerArgs\x1a\x1a.grpc.test\ 40 | ing.ServerStatus(\x010\x01\x12E\n\tRunClient\x12\x18.grpc.testing.Client\ 41 | Args\x1a\x1a.grpc.testing.ClientStatus(\x010\x01\x12B\n\tCoreCount\x12\ 42 | \x19.grpc.testing.CoreRequest\x1a\x1a.grpc.testing.CoreResponse\x124\n\n\ 43 | QuitWorker\x12\x12.grpc.testing.Void\x1a\x12.grpc.testing.Void2^\n\x18Re\ 44 | portQpsScenarioService\x12B\n\x0eReportScenario\x12\x1c.grpc.testing.Sce\ 45 | narioResult\x1a\x12.grpc.testing.Voidb\x06proto3\ 46 | "; 47 | 48 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { 49 | lock: ::protobuf::lazy::ONCE_INIT, 50 | ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, 51 | }; 52 | 53 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 54 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 55 | } 56 | 57 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 58 | unsafe { 59 | file_descriptor_proto_lazy.get(|| { 60 | parse_descriptor_proto() 61 | }) 62 | } 63 | } 64 | 65 | pub use super::services_grpc::*; 66 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf/testing/test.rs: -------------------------------------------------------------------------------- 1 | // This file is generated by rust-protobuf 2.8.2. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | 8 | #![cfg_attr(rustfmt, rustfmt_skip)] 9 | 10 | #![allow(box_pointers)] 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unsafe_code)] 18 | #![allow(unused_imports)] 19 | #![allow(unused_results)] 20 | //! Generated file from `grpc/testing/test.proto` 21 | 22 | use protobuf::Message as Message_imported_for_functions; 23 | use protobuf::ProtobufEnum as ProtobufEnum_imported_for_functions; 24 | 25 | /// Generated files are compatible only with the same version 26 | /// of protobuf runtime. 27 | 28 | static file_descriptor_proto_data: &'static [u8] = b"\ 29 | \n\x17grpc/testing/test.proto\x12\x0cgrpc.testing\x1a\x18grpc/testing/em\ 30 | pty.proto\x1a\x1bgrpc/testing/messages.proto2\xcb\x05\n\x0bTestService\ 31 | \x125\n\tEmptyCall\x12\x13.grpc.testing.Empty\x1a\x13.grpc.testing.Empty\ 32 | \x12F\n\tUnaryCall\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testi\ 33 | ng.SimpleResponse\x12O\n\x12CacheableUnaryCall\x12\x1b.grpc.testing.Simp\ 34 | leRequest\x1a\x1c.grpc.testing.SimpleResponse\x12l\n\x13StreamingOutputC\ 35 | all\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.Strea\ 36 | mingOutputCallResponse0\x01\x12i\n\x12StreamingInputCall\x12'.grpc.testi\ 37 | ng.StreamingInputCallRequest\x1a(.grpc.testing.StreamingInputCallRespons\ 38 | e(\x01\x12i\n\x0eFullDuplexCall\x12(.grpc.testing.StreamingOutputCallReq\ 39 | uest\x1a).grpc.testing.StreamingOutputCallResponse(\x010\x01\x12i\n\x0eH\ 40 | alfDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.tes\ 41 | ting.StreamingOutputCallResponse(\x010\x01\x12=\n\x11UnimplementedCall\ 42 | \x12\x13.grpc.testing.Empty\x1a\x13.grpc.testing.Empty2U\n\x14Unimplemen\ 43 | tedService\x12=\n\x11UnimplementedCall\x12\x13.grpc.testing.Empty\x1a\ 44 | \x13.grpc.testing.Empty2\x89\x01\n\x10ReconnectService\x12;\n\x05Start\ 45 | \x12\x1d.grpc.testing.ReconnectParams\x1a\x13.grpc.testing.Empty\x128\n\ 46 | \x04Stop\x12\x13.grpc.testing.Empty\x1a\x1b.grpc.testing.ReconnectInfob\ 47 | \x06proto3\ 48 | "; 49 | 50 | static mut file_descriptor_proto_lazy: ::protobuf::lazy::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::lazy::Lazy { 51 | lock: ::protobuf::lazy::ONCE_INIT, 52 | ptr: 0 as *const ::protobuf::descriptor::FileDescriptorProto, 53 | }; 54 | 55 | fn parse_descriptor_proto() -> ::protobuf::descriptor::FileDescriptorProto { 56 | ::protobuf::parse_from_bytes(file_descriptor_proto_data).unwrap() 57 | } 58 | 59 | pub fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto { 60 | unsafe { 61 | file_descriptor_proto_lazy.get(|| { 62 | parse_descriptor_proto() 63 | }) 64 | } 65 | } 66 | 67 | pub use super::test_grpc::*; 68 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf_v3/example/helloworld_grpc.rs: -------------------------------------------------------------------------------- 1 | // This file is generated. Do not edit 2 | // @generated 3 | 4 | // https://github.com/Manishearth/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | 8 | #![allow(box_pointers)] 9 | #![allow(dead_code)] 10 | #![allow(missing_docs)] 11 | #![allow(non_camel_case_types)] 12 | #![allow(non_snake_case)] 13 | #![allow(non_upper_case_globals)] 14 | #![allow(trivial_casts)] 15 | #![allow(unsafe_code)] 16 | #![allow(unused_imports)] 17 | #![allow(unused_results)] 18 | 19 | const METHOD_GREETER_SAY_HELLO: ::grpcio::Method = ::grpcio::Method { 20 | ty: ::grpcio::MethodType::Unary, 21 | name: "/helloworld.Greeter/SayHello", 22 | req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de }, 23 | resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de }, 24 | }; 25 | 26 | #[derive(Clone)] 27 | pub struct GreeterClient { 28 | pub client: ::grpcio::Client, 29 | } 30 | 31 | impl GreeterClient { 32 | pub fn new(channel: ::grpcio::Channel) -> Self { 33 | GreeterClient { 34 | client: ::grpcio::Client::new(channel), 35 | } 36 | } 37 | 38 | pub fn say_hello_opt(&self, req: &super::helloworld::HelloRequest, opt: ::grpcio::CallOption) -> ::grpcio::Result { 39 | self.client.unary_call(&METHOD_GREETER_SAY_HELLO, req, opt) 40 | } 41 | 42 | pub fn say_hello(&self, req: &super::helloworld::HelloRequest) -> ::grpcio::Result { 43 | self.say_hello_opt(req, ::grpcio::CallOption::default()) 44 | } 45 | 46 | pub fn say_hello_async_opt(&self, req: &super::helloworld::HelloRequest, opt: ::grpcio::CallOption) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 47 | self.client.unary_call_async(&METHOD_GREETER_SAY_HELLO, req, opt) 48 | } 49 | 50 | pub fn say_hello_async(&self, req: &super::helloworld::HelloRequest) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver> { 51 | self.say_hello_async_opt(req, ::grpcio::CallOption::default()) 52 | } 53 | pub fn spawn(&self, f: F) where F: ::std::future::Future + Send + 'static { 54 | self.client.spawn(f) 55 | } 56 | } 57 | 58 | pub trait Greeter { 59 | fn say_hello(&mut self, ctx: ::grpcio::RpcContext, _req: super::helloworld::HelloRequest, sink: ::grpcio::UnarySink) { 60 | grpcio::unimplemented_call!(ctx, sink) 61 | } 62 | } 63 | 64 | pub fn create_greeter(s: S) -> ::grpcio::Service { 65 | let mut builder = ::grpcio::ServiceBuilder::new(); 66 | let mut instance = s; 67 | builder = builder.add_unary_handler(&METHOD_GREETER_SAY_HELLO, move |ctx, req, resp| { 68 | instance.say_hello(ctx, req, resp) 69 | }); 70 | builder.build() 71 | } 72 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf_v3/example/mod.rs: -------------------------------------------------------------------------------- 1 | // @generated 2 | 3 | pub mod helloworld; 4 | pub mod route_guide; 5 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf_v3/google/rpc/mod.rs: -------------------------------------------------------------------------------- 1 | // @generated 2 | 3 | pub mod status; 4 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf_v3/testing/mod.rs: -------------------------------------------------------------------------------- 1 | // @generated 2 | 3 | pub mod control; 4 | pub mod empty; 5 | pub mod messages; 6 | pub mod payloads; 7 | pub mod services; 8 | pub mod stats; 9 | pub mod test; 10 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf_v3/testing/services.rs: -------------------------------------------------------------------------------- 1 | // This file is generated by rust-protobuf 3.7.2. Do not edit 2 | // @generated 3 | 4 | // https://github.com/rust-lang/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | 8 | #![allow(unused_attributes)] 9 | #![cfg_attr(rustfmt, rustfmt::skip)] 10 | 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unused_results)] 18 | #![allow(unused_mut)] 19 | 20 | //! Generated file from `grpc/testing/services.proto` 21 | 22 | /// Generated files are compatible only with the same version 23 | /// of protobuf runtime. 24 | const _PROTOBUF_VERSION_CHECK: () = ::protobufv3::VERSION_3_7_2; 25 | 26 | static file_descriptor_proto_data: &'static [u8] = b"\ 27 | \n\x1bgrpc/testing/services.proto\x12\x0cgrpc.testing\x1a\x1bgrpc/testin\ 28 | g/messages.proto\x1a\x1agrpc/testing/control.proto\x1a\x18grpc/testing/s\ 29 | tats.proto2\xa6\x03\n\x10BenchmarkService\x12F\n\tUnaryCall\x12\x1b.grpc\ 30 | .testing.SimpleRequest\x1a\x1c.grpc.testing.SimpleResponse\x12N\n\rStrea\ 31 | mingCall\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testing.SimpleR\ 32 | esponse(\x010\x01\x12R\n\x13StreamingFromClient\x12\x1b.grpc.testing.Sim\ 33 | pleRequest\x1a\x1c.grpc.testing.SimpleResponse(\x01\x12R\n\x13StreamingF\ 34 | romServer\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testing.Simple\ 35 | Response0\x01\x12R\n\x11StreamingBothWays\x12\x1b.grpc.testing.SimpleReq\ 36 | uest\x1a\x1c.grpc.testing.SimpleResponse(\x010\x012\x97\x02\n\rWorkerSer\ 37 | vice\x12E\n\tRunServer\x12\x18.grpc.testing.ServerArgs\x1a\x1a.grpc.test\ 38 | ing.ServerStatus(\x010\x01\x12E\n\tRunClient\x12\x18.grpc.testing.Client\ 39 | Args\x1a\x1a.grpc.testing.ClientStatus(\x010\x01\x12B\n\tCoreCount\x12\ 40 | \x19.grpc.testing.CoreRequest\x1a\x1a.grpc.testing.CoreResponse\x124\n\n\ 41 | QuitWorker\x12\x12.grpc.testing.Void\x1a\x12.grpc.testing.Void2^\n\x18Re\ 42 | portQpsScenarioService\x12B\n\x0eReportScenario\x12\x1c.grpc.testing.Sce\ 43 | narioResult\x1a\x12.grpc.testing.Voidb\x06proto3\ 44 | "; 45 | 46 | /// `FileDescriptorProto` object which was a source for this generated file 47 | fn file_descriptor_proto() -> &'static ::protobufv3::descriptor::FileDescriptorProto { 48 | static file_descriptor_proto_lazy: ::protobufv3::rt::Lazy<::protobufv3::descriptor::FileDescriptorProto> = ::protobufv3::rt::Lazy::new(); 49 | file_descriptor_proto_lazy.get(|| { 50 | ::protobufv3::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() 51 | }) 52 | } 53 | 54 | /// `FileDescriptor` object which allows dynamic access to files 55 | pub fn file_descriptor() -> &'static ::protobufv3::reflect::FileDescriptor { 56 | static generated_file_descriptor_lazy: ::protobufv3::rt::Lazy<::protobufv3::reflect::GeneratedFileDescriptor> = ::protobufv3::rt::Lazy::new(); 57 | static file_descriptor: ::protobufv3::rt::Lazy<::protobufv3::reflect::FileDescriptor> = ::protobufv3::rt::Lazy::new(); 58 | file_descriptor.get(|| { 59 | let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { 60 | let mut deps = ::std::vec::Vec::with_capacity(3); 61 | deps.push(super::messages::file_descriptor().clone()); 62 | deps.push(super::control::file_descriptor().clone()); 63 | deps.push(super::stats::file_descriptor().clone()); 64 | let mut messages = ::std::vec::Vec::with_capacity(0); 65 | let mut enums = ::std::vec::Vec::with_capacity(0); 66 | ::protobufv3::reflect::GeneratedFileDescriptor::new_generated( 67 | file_descriptor_proto(), 68 | deps, 69 | messages, 70 | enums, 71 | ) 72 | }); 73 | ::protobufv3::reflect::FileDescriptor::new_generated_2(generated_file_descriptor) 74 | }) 75 | } 76 | 77 | pub use super::services_grpc::*; 78 | -------------------------------------------------------------------------------- /proto/src/proto/protobuf_v3/testing/test.rs: -------------------------------------------------------------------------------- 1 | // This file is generated by rust-protobuf 3.7.2. Do not edit 2 | // @generated 3 | 4 | // https://github.com/rust-lang/rust-clippy/issues/702 5 | #![allow(unknown_lints)] 6 | #![allow(clippy::all)] 7 | 8 | #![allow(unused_attributes)] 9 | #![cfg_attr(rustfmt, rustfmt::skip)] 10 | 11 | #![allow(dead_code)] 12 | #![allow(missing_docs)] 13 | #![allow(non_camel_case_types)] 14 | #![allow(non_snake_case)] 15 | #![allow(non_upper_case_globals)] 16 | #![allow(trivial_casts)] 17 | #![allow(unused_results)] 18 | #![allow(unused_mut)] 19 | 20 | //! Generated file from `grpc/testing/test.proto` 21 | 22 | /// Generated files are compatible only with the same version 23 | /// of protobuf runtime. 24 | const _PROTOBUF_VERSION_CHECK: () = ::protobufv3::VERSION_3_7_2; 25 | 26 | static file_descriptor_proto_data: &'static [u8] = b"\ 27 | \n\x17grpc/testing/test.proto\x12\x0cgrpc.testing\x1a\x18grpc/testing/em\ 28 | pty.proto\x1a\x1bgrpc/testing/messages.proto2\xcb\x05\n\x0bTestService\ 29 | \x125\n\tEmptyCall\x12\x13.grpc.testing.Empty\x1a\x13.grpc.testing.Empty\ 30 | \x12F\n\tUnaryCall\x12\x1b.grpc.testing.SimpleRequest\x1a\x1c.grpc.testi\ 31 | ng.SimpleResponse\x12O\n\x12CacheableUnaryCall\x12\x1b.grpc.testing.Simp\ 32 | leRequest\x1a\x1c.grpc.testing.SimpleResponse\x12l\n\x13StreamingOutputC\ 33 | all\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.testing.Strea\ 34 | mingOutputCallResponse0\x01\x12i\n\x12StreamingInputCall\x12'.grpc.testi\ 35 | ng.StreamingInputCallRequest\x1a(.grpc.testing.StreamingInputCallRespons\ 36 | e(\x01\x12i\n\x0eFullDuplexCall\x12(.grpc.testing.StreamingOutputCallReq\ 37 | uest\x1a).grpc.testing.StreamingOutputCallResponse(\x010\x01\x12i\n\x0eH\ 38 | alfDuplexCall\x12(.grpc.testing.StreamingOutputCallRequest\x1a).grpc.tes\ 39 | ting.StreamingOutputCallResponse(\x010\x01\x12=\n\x11UnimplementedCall\ 40 | \x12\x13.grpc.testing.Empty\x1a\x13.grpc.testing.Empty2U\n\x14Unimplemen\ 41 | tedService\x12=\n\x11UnimplementedCall\x12\x13.grpc.testing.Empty\x1a\ 42 | \x13.grpc.testing.Empty2\x89\x01\n\x10ReconnectService\x12;\n\x05Start\ 43 | \x12\x1d.grpc.testing.ReconnectParams\x1a\x13.grpc.testing.Empty\x128\n\ 44 | \x04Stop\x12\x13.grpc.testing.Empty\x1a\x1b.grpc.testing.ReconnectInfob\ 45 | \x06proto3\ 46 | "; 47 | 48 | /// `FileDescriptorProto` object which was a source for this generated file 49 | fn file_descriptor_proto() -> &'static ::protobufv3::descriptor::FileDescriptorProto { 50 | static file_descriptor_proto_lazy: ::protobufv3::rt::Lazy<::protobufv3::descriptor::FileDescriptorProto> = ::protobufv3::rt::Lazy::new(); 51 | file_descriptor_proto_lazy.get(|| { 52 | ::protobufv3::Message::parse_from_bytes(file_descriptor_proto_data).unwrap() 53 | }) 54 | } 55 | 56 | /// `FileDescriptor` object which allows dynamic access to files 57 | pub fn file_descriptor() -> &'static ::protobufv3::reflect::FileDescriptor { 58 | static generated_file_descriptor_lazy: ::protobufv3::rt::Lazy<::protobufv3::reflect::GeneratedFileDescriptor> = ::protobufv3::rt::Lazy::new(); 59 | static file_descriptor: ::protobufv3::rt::Lazy<::protobufv3::reflect::FileDescriptor> = ::protobufv3::rt::Lazy::new(); 60 | file_descriptor.get(|| { 61 | let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { 62 | let mut deps = ::std::vec::Vec::with_capacity(2); 63 | deps.push(super::empty::file_descriptor().clone()); 64 | deps.push(super::messages::file_descriptor().clone()); 65 | let mut messages = ::std::vec::Vec::with_capacity(0); 66 | let mut enums = ::std::vec::Vec::with_capacity(0); 67 | ::protobufv3::reflect::GeneratedFileDescriptor::new_generated( 68 | file_descriptor_proto(), 69 | deps, 70 | messages, 71 | enums, 72 | ) 73 | }); 74 | ::protobufv3::reflect::FileDescriptor::new_generated_2(generated_file_descriptor) 75 | }) 76 | } 77 | 78 | pub use super::test_grpc::*; 79 | -------------------------------------------------------------------------------- /proto/src/util.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use crate::google::rpc::Status; 4 | use grpcio::{ 5 | ChannelCredentials, ChannelCredentialsBuilder, ServerCredentials, ServerCredentialsBuilder, 6 | }; 7 | use std::convert::TryFrom; 8 | 9 | #[cfg(all( 10 | any(feature = "protobuf-codec", feature = "protobufv3-codec"), 11 | not(feature = "prost-codec") 12 | ))] 13 | use crate::proto::protobuf::testing::messages::{Payload, ResponseParameters}; 14 | #[cfg(feature = "prost-codec")] 15 | use crate::testing::{Payload, ResponseParameters}; 16 | 17 | #[cfg(feature = "protobufv3-codec")] 18 | use protobufv3 as protobuf; 19 | 20 | /// Create a payload with the specified size. 21 | pub fn new_payload(size: usize) -> Payload { 22 | Payload { 23 | body: vec![0; size], 24 | ..Default::default() 25 | } 26 | } 27 | 28 | pub fn new_parameters(size: i32) -> ResponseParameters { 29 | ResponseParameters { 30 | size, 31 | ..Default::default() 32 | } 33 | } 34 | 35 | pub fn create_test_server_credentials() -> ServerCredentials { 36 | let private_key = include_str!("../data/server1.key"); 37 | let cert = include_str!("../data/server1.pem"); 38 | ServerCredentialsBuilder::new() 39 | .add_cert(cert.into(), private_key.into()) 40 | .build() 41 | } 42 | 43 | pub fn create_test_channel_credentials() -> ChannelCredentials { 44 | let ca = include_str!("../data/ca.pem"); 45 | ChannelCredentialsBuilder::new() 46 | .root_cert(ca.into()) 47 | .build() 48 | } 49 | 50 | impl TryFrom for Status { 51 | type Error = grpcio::Error; 52 | 53 | fn try_from(value: grpcio::RpcStatus) -> grpcio::Result { 54 | let mut s = Status::default(); 55 | #[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] 56 | protobuf::Message::merge_from_bytes(&mut s, value.details())?; 57 | #[cfg(feature = "prost-codec")] 58 | prost::Message::merge(&mut s, value.details())?; 59 | if s.code == value.code().into() { 60 | if s.message == value.message() { 61 | Ok(s) 62 | } else { 63 | Err(grpcio::Error::Codec( 64 | format!( 65 | "message doesn't match {:?} != {:?}", 66 | s.message, 67 | value.message() 68 | ) 69 | .into(), 70 | )) 71 | } 72 | } else { 73 | Err(grpcio::Error::Codec( 74 | format!("code doesn't match {} != {}", s.code, value.code()).into(), 75 | )) 76 | } 77 | } 78 | } 79 | 80 | impl TryFrom for grpcio::RpcStatus { 81 | type Error = grpcio::Error; 82 | 83 | fn try_from(value: Status) -> grpcio::Result { 84 | #[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] 85 | let details = protobuf::Message::write_to_bytes(&value)?; 86 | #[cfg(feature = "prost-codec")] 87 | let details = { 88 | let mut v = vec![]; 89 | prost::Message::encode(&value, &mut v).unwrap(); 90 | v 91 | }; 92 | Ok(grpcio::RpcStatus::with_details( 93 | value.code, 94 | value.message, 95 | details, 96 | )) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/channelz.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | //! Channelz provides channel level debug information. In short, There are four types of 4 | //! top level entities: channel, subchannel, socket and server. All entities are 5 | //! identified by an positive unique integer, which is allocated in order. For more 6 | //! explanation, see . 7 | //! 8 | //! A full support requires a service that allow remote querying. But for now it's 9 | //! too complicated to add full support. Because gRPC C core exposes the information 10 | //! using JSON format, and there is no protobuf library that supports parsing json 11 | //! format in Rust. So this module only provides safe APIs to access the informations. 12 | 13 | use std::ffi::CStr; 14 | use std::{cmp, str}; 15 | 16 | macro_rules! visit { 17 | ($ptr:expr, $visitor:ident) => {{ 18 | let s_ptr = $ptr; 19 | let res; 20 | if !s_ptr.is_null() { 21 | let c_s = CStr::from_ptr(s_ptr); 22 | // It's json string, so it must be utf8 compatible. 23 | let s = str::from_utf8_unchecked(c_s.to_bytes()); 24 | res = $visitor(s); 25 | grpcio_sys::gpr_free(s_ptr as _); 26 | } else { 27 | res = $visitor(""); 28 | } 29 | res 30 | }}; 31 | } 32 | 33 | /// Gets all root channels (i.e. channels the application has directly created). This 34 | /// does not include subchannels nor non-top level channels. 35 | pub fn get_top_channels(start_channel_id: u64, visitor: V) -> R 36 | where 37 | V: FnOnce(&str) -> R, 38 | { 39 | unsafe { 40 | visit!( 41 | grpcio_sys::grpc_channelz_get_top_channels(start_channel_id as _), 42 | visitor 43 | ) 44 | } 45 | } 46 | 47 | /// Gets all servers that exist in the process. 48 | pub fn get_servers(start_server_id: u64, visitor: V) -> R 49 | where 50 | V: FnOnce(&str) -> R, 51 | { 52 | unsafe { 53 | visit!( 54 | grpcio_sys::grpc_channelz_get_servers(start_server_id as _), 55 | visitor 56 | ) 57 | } 58 | } 59 | 60 | /// Returns a single Server, or else an empty string. 61 | pub fn get_server(server_id: u64, visitor: V) -> R 62 | where 63 | V: FnOnce(&str) -> R, 64 | { 65 | unsafe { 66 | visit!( 67 | grpcio_sys::grpc_channelz_get_server(server_id as _), 68 | visitor 69 | ) 70 | } 71 | } 72 | 73 | /// Gets all server sockets that exist in the server. 74 | pub fn get_server_sockets( 75 | server_id: u64, 76 | start_socket_id: u64, 77 | max_results: usize, 78 | visitor: V, 79 | ) -> R 80 | where 81 | V: FnOnce(&str) -> R, 82 | { 83 | let max_results = cmp::min(isize::MAX as usize, max_results) as isize; 84 | unsafe { 85 | visit!( 86 | grpcio_sys::grpc_channelz_get_server_sockets( 87 | server_id as _, 88 | start_socket_id as _, 89 | max_results 90 | ), 91 | visitor 92 | ) 93 | } 94 | } 95 | 96 | /// Returns a single Channel, or else an empty string. 97 | pub fn get_channel(channel_id: u64, visitor: V) -> R 98 | where 99 | V: FnOnce(&str) -> R, 100 | { 101 | unsafe { 102 | visit!( 103 | grpcio_sys::grpc_channelz_get_channel(channel_id as _), 104 | visitor 105 | ) 106 | } 107 | } 108 | 109 | /// Returns a single Subchannel, or else an empty string. 110 | pub fn get_subchannel(subchannel_id: u64, visitor: V) -> R 111 | where 112 | V: FnOnce(&str) -> R, 113 | { 114 | unsafe { 115 | visit!( 116 | grpcio_sys::grpc_channelz_get_subchannel(subchannel_id as _), 117 | visitor 118 | ) 119 | } 120 | } 121 | 122 | /// Returns a single Socket, or else an empty string. 123 | pub fn get_socket(socket_id: u64, visitor: V) -> R 124 | where 125 | V: FnOnce(&str) -> R, 126 | { 127 | unsafe { 128 | visit!( 129 | grpcio_sys::grpc_channelz_get_socket(socket_id as _), 130 | visitor 131 | ) 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/client.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::future::Future; 4 | 5 | use crate::call::client::{ 6 | CallOption, ClientCStreamReceiver, ClientCStreamSender, ClientDuplexReceiver, 7 | ClientDuplexSender, ClientSStreamReceiver, ClientUnaryReceiver, 8 | }; 9 | use crate::call::{Call, Method}; 10 | use crate::channel::Channel; 11 | use crate::error::Result; 12 | use crate::task::Executor; 13 | use crate::task::Kicker; 14 | use futures_executor::block_on; 15 | 16 | /// A generic client for making RPC calls. 17 | #[derive(Clone)] 18 | pub struct Client { 19 | channel: Channel, 20 | // Used to kick its completion queue. 21 | kicker: Kicker, 22 | } 23 | 24 | impl Client { 25 | /// Initialize a new [`Client`]. 26 | pub fn new(channel: Channel) -> Client { 27 | let kicker = channel.create_kicker().unwrap(); 28 | Client { channel, kicker } 29 | } 30 | 31 | /// Create a synchronized unary RPC call. 32 | /// 33 | /// It uses futures_executor::block_on to wait for the futures. It's recommended to use 34 | /// the asynchronous version. 35 | pub fn unary_call( 36 | &self, 37 | method: &Method, 38 | req: &Req, 39 | opt: CallOption, 40 | ) -> Result { 41 | block_on(self.unary_call_async(method, req, opt)?) 42 | } 43 | 44 | /// Create an asynchronized unary RPC call. 45 | pub fn unary_call_async( 46 | &self, 47 | method: &Method, 48 | req: &Req, 49 | opt: CallOption, 50 | ) -> Result> { 51 | Call::unary_async(&self.channel, method, req, opt) 52 | } 53 | 54 | /// Create an asynchronized client streaming call. 55 | /// 56 | /// Client can send a stream of requests and server responds with a single response. 57 | pub fn client_streaming( 58 | &self, 59 | method: &Method, 60 | opt: CallOption, 61 | ) -> Result<(ClientCStreamSender, ClientCStreamReceiver)> { 62 | Call::client_streaming(&self.channel, method, opt) 63 | } 64 | 65 | /// Create an asynchronized server streaming call. 66 | /// 67 | /// Client sends on request and server responds with a stream of responses. 68 | pub fn server_streaming( 69 | &self, 70 | method: &Method, 71 | req: &Req, 72 | opt: CallOption, 73 | ) -> Result> { 74 | Call::server_streaming(&self.channel, method, req, opt) 75 | } 76 | 77 | /// Create an asynchronized duplex streaming call. 78 | /// 79 | /// Client sends a stream of requests and server responds with a stream of responses. 80 | /// The response stream is completely independent and both side can be sending messages 81 | /// at the same time. 82 | pub fn duplex_streaming( 83 | &self, 84 | method: &Method, 85 | opt: CallOption, 86 | ) -> Result<(ClientDuplexSender, ClientDuplexReceiver)> { 87 | Call::duplex_streaming(&self.channel, method, opt) 88 | } 89 | 90 | /// Spawn the future into current gRPC poll thread. 91 | /// 92 | /// This can reduce a lot of context switching, but please make 93 | /// sure there is no heavy work in the future. 94 | pub fn spawn(&self, f: F) 95 | where 96 | F: Future + Send + 'static, 97 | { 98 | let kicker = self.kicker.clone(); 99 | Executor::new(self.channel.cq()).spawn(f, kicker) 100 | } 101 | 102 | /// Get the underlying channel. 103 | #[inline] 104 | pub fn channel(&self) -> &Channel { 105 | &self.channel 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/codec.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use crate::buf::GrpcSlice; 4 | use crate::call::MessageReader; 5 | use crate::error::Result; 6 | 7 | pub type DeserializeFn = fn(MessageReader) -> Result; 8 | pub type SerializeFn = fn(&T, &mut GrpcSlice) -> Result<()>; 9 | 10 | /// According to , grpc uses 11 | /// a four bytes to describe the length of a message, so it should not exceed u32::MAX. 12 | pub const MAX_MESSAGE_SIZE: usize = u32::MAX as usize; 13 | 14 | /// Defines how to serialize and deserialize between the specialized type and byte slice. 15 | pub struct Marshaller { 16 | // Use function pointer here to simplify the signature. 17 | // Compiler will probably inline the function so performance 18 | // impact can be omitted. 19 | // 20 | // Using trait will require a trait object or generic, which will 21 | // either have performance impact or make signature complicated. 22 | // 23 | // const function is not stable yet (rust-lang/rust#24111), hence 24 | // make all fields public. 25 | /// The serialize function. 26 | pub ser: SerializeFn, 27 | 28 | /// The deserialize function. 29 | pub de: DeserializeFn, 30 | } 31 | 32 | #[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] 33 | pub mod pb_codec { 34 | #[cfg(feature = "protobuf-codec")] 35 | use protobuf::{CodedOutputStream, Message}; 36 | 37 | #[cfg(feature = "protobufv3-codec")] 38 | use protobufv3::{CodedOutputStream, Message}; 39 | 40 | use super::{from_buf_read, MessageReader, MAX_MESSAGE_SIZE}; 41 | use crate::buf::GrpcSlice; 42 | use crate::error::{Error, Result}; 43 | 44 | #[inline] 45 | pub fn ser(t: &T, buf: &mut GrpcSlice) -> Result<()> { 46 | let cap = t.compute_size() as usize; 47 | // FIXME: This is not a practical fix until stepancheg/rust-protobuf#530 is fixed. 48 | if cap <= MAX_MESSAGE_SIZE { 49 | unsafe { 50 | let bytes = buf.realloc(cap); 51 | let raw_bytes = &mut *(bytes as *mut [std::mem::MaybeUninit] as *mut [u8]); 52 | let mut s = CodedOutputStream::bytes(raw_bytes); 53 | t.write_to_with_cached_sizes(&mut s).map_err(Into::into) 54 | } 55 | } else { 56 | Err(Error::Codec( 57 | format!("message is too large: {cap} > {MAX_MESSAGE_SIZE}").into(), 58 | )) 59 | } 60 | } 61 | 62 | #[inline] 63 | pub fn de(mut reader: MessageReader) -> Result { 64 | let mut s = from_buf_read(&mut reader); 65 | let mut m = T::new(); 66 | m.merge_from(&mut s)?; 67 | Ok(m) 68 | } 69 | } 70 | 71 | #[cfg(feature = "protobuf-codec")] 72 | fn from_buf_read(reader: &mut MessageReader) -> protobuf::CodedInputStream { 73 | protobuf::CodedInputStream::from_buffered_reader(reader) 74 | } 75 | 76 | #[cfg(feature = "protobufv3-codec")] 77 | fn from_buf_read(reader: &mut MessageReader) -> protobufv3::CodedInputStream { 78 | protobufv3::CodedInputStream::from_buf_read(reader) 79 | } 80 | 81 | #[cfg(feature = "prost-codec")] 82 | pub mod pr_codec { 83 | use prost::Message; 84 | 85 | use super::{MessageReader, MAX_MESSAGE_SIZE}; 86 | use crate::buf::GrpcSlice; 87 | use crate::error::{Error, Result}; 88 | 89 | #[inline] 90 | pub fn ser(msg: &M, buf: &mut GrpcSlice) -> Result<()> { 91 | let size = msg.encoded_len(); 92 | if size <= MAX_MESSAGE_SIZE { 93 | unsafe { 94 | let bytes = buf.realloc(size); 95 | let mut b = &mut *(bytes as *mut [std::mem::MaybeUninit] as *mut [u8]); 96 | msg.encode(&mut b)?; 97 | debug_assert!(b.is_empty()); 98 | } 99 | Ok(()) 100 | } else { 101 | Err(Error::Codec( 102 | format!("message is too large: {size} > {MAX_MESSAGE_SIZE}").into(), 103 | )) 104 | } 105 | } 106 | 107 | #[inline] 108 | pub fn de(mut reader: MessageReader) -> Result { 109 | use bytes::buf::Buf; 110 | reader.advance(0); 111 | M::decode(reader).map_err(Into::into) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::ffi::CString; 4 | use std::{error, fmt, result}; 5 | 6 | use crate::call::RpcStatus; 7 | use crate::grpc_sys::grpc_call_error; 8 | 9 | #[cfg(feature = "protobuf-codec")] 10 | use protobuf::ProtobufError; 11 | 12 | #[cfg(feature = "protobufv3-codec")] 13 | use protobufv3::Error as ProtobufError; 14 | 15 | /// Errors generated from this library. 16 | #[derive(Debug)] 17 | pub enum Error { 18 | /// Codec error. 19 | Codec(Box), 20 | /// Failed to start an internal async call. 21 | CallFailure(grpc_call_error), 22 | /// Rpc request fail. 23 | RpcFailure(RpcStatus), 24 | /// Try to write to a finished rpc call. 25 | RpcFinished(Option), 26 | /// Remote is stopped. 27 | RemoteStopped, 28 | /// Failed to shutdown. 29 | ShutdownFailed, 30 | /// Failed to bind. 31 | BindFail(CString), 32 | /// gRPC completion queue is shutdown. 33 | QueueShutdown, 34 | /// Failed to create Google default credentials. 35 | GoogleAuthenticationFailed, 36 | /// Invalid format of metadata. 37 | InvalidMetadata(String), 38 | } 39 | 40 | impl fmt::Display for Error { 41 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 42 | match self { 43 | Error::RpcFailure(s) => { 44 | if s.message().is_empty() { 45 | write!(fmt, "RpcFailure: {}", s.code()) 46 | } else { 47 | write!(fmt, "RpcFailure: {} {}", s.code(), s.message()) 48 | } 49 | } 50 | other_error => write!(fmt, "{other_error:?}"), 51 | } 52 | } 53 | } 54 | 55 | impl error::Error for Error { 56 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { 57 | match *self { 58 | Error::Codec(ref e) => Some(e.as_ref()), 59 | _ => None, 60 | } 61 | } 62 | } 63 | 64 | #[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] 65 | impl From for Error { 66 | fn from(e: ProtobufError) -> Error { 67 | Error::Codec(Box::new(e)) 68 | } 69 | } 70 | 71 | #[cfg(feature = "prost-codec")] 72 | impl From for Error { 73 | fn from(e: prost::DecodeError) -> Error { 74 | Error::Codec(Box::new(e)) 75 | } 76 | } 77 | 78 | #[cfg(feature = "prost-codec")] 79 | impl From for Error { 80 | fn from(e: prost::EncodeError) -> Error { 81 | Error::Codec(Box::new(e)) 82 | } 83 | } 84 | 85 | /// Type alias to use this library's [`Error`] type in a `Result`. 86 | pub type Result = result::Result; 87 | 88 | #[cfg(all(test, feature = "protobuf-codec"))] 89 | mod tests { 90 | use std::error::Error as StdError; 91 | 92 | use protobuf::error::WireError; 93 | use protobuf::ProtobufError; 94 | 95 | use super::Error; 96 | 97 | #[test] 98 | fn test_convert() { 99 | let error = ProtobufError::WireError(WireError::UnexpectedEof); 100 | let e: Error = error.into(); 101 | assert_eq!(e.to_string(), "Codec(WireError(UnexpectedEof))"); 102 | assert!(e.source().is_some()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | /*! 4 | 5 | [grpcio] is a Rust implementation of [gRPC], which is a high performance, open source universal RPC 6 | framework that puts mobile and HTTP/2 first. grpcio is built on [gRPC Core] and [futures-rs]. 7 | 8 | [grpcio]: https://github.com/tikv/grpc-rs/ 9 | [gRPC]: https://grpc.io/ 10 | [gRPC Core]: https://github.com/grpc/grpc 11 | [futures-rs]: https://github.com/rust-lang/futures-rs 12 | 13 | ## Optional features 14 | 15 | - **`boringssl`** *(enabled by default)* - Enables support for TLS encryption and some authentication 16 | mechanisms. 17 | - **`openssl`** - Same as `boringssl`, but base on the system openssl. 18 | - **`openssl-vendored`** - Same as `openssl`, but build openssl from source. 19 | 20 | */ 21 | 22 | #![allow(clippy::new_without_default)] 23 | #![allow(clippy::new_without_default)] 24 | #![allow(clippy::cast_lossless)] 25 | #![allow(clippy::option_map_unit_fn)] 26 | #![allow(clippy::derive_partial_eq_without_eq)] 27 | 28 | use grpcio_sys as grpc_sys; 29 | #[macro_use] 30 | extern crate log; 31 | 32 | mod buf; 33 | mod call; 34 | mod channel; 35 | pub mod channelz; 36 | mod client; 37 | mod codec; 38 | mod cq; 39 | mod env; 40 | mod error; 41 | mod log_util; 42 | mod metadata; 43 | mod quota; 44 | mod security; 45 | mod server; 46 | mod task; 47 | 48 | pub use crate::buf::GrpcSlice; 49 | pub use crate::call::client::{ 50 | CallOption, ClientCStreamReceiver, ClientCStreamSender, ClientDuplexReceiver, 51 | ClientDuplexSender, ClientSStreamReceiver, ClientUnaryReceiver, StreamingCallSink, 52 | }; 53 | pub use crate::call::server::{ 54 | ClientStreamingSink, ClientStreamingSinkResult, Deadline, DuplexSink, DuplexSinkFailure, 55 | RequestStream, RpcContext, ServerStreamingSink, ServerStreamingSinkFailure, UnarySink, 56 | UnarySinkResult, 57 | }; 58 | pub use crate::call::{MessageReader, Method, MethodType, RpcStatus, RpcStatusCode, WriteFlags}; 59 | pub use crate::channel::{ 60 | Channel, ChannelBuilder, CompressionAlgorithms, CompressionLevel, ConnectivityState, LbPolicy, 61 | OptTarget, 62 | }; 63 | pub use crate::client::Client; 64 | 65 | #[cfg(any(feature = "protobuf-codec", feature = "protobufv3-codec"))] 66 | pub use crate::codec::pb_codec::{de as pb_de, ser as pb_ser}; 67 | #[cfg(feature = "prost-codec")] 68 | pub use crate::codec::pr_codec::{de as pr_de, ser as pr_ser}; 69 | 70 | pub use crate::codec::{Marshaller, MAX_MESSAGE_SIZE}; 71 | pub use crate::env::{EnvBuilder, Environment}; 72 | pub use crate::error::{Error, Result}; 73 | pub use crate::log_util::redirect_log; 74 | pub use crate::metadata::{Metadata, MetadataBuilder, MetadataIter}; 75 | pub use crate::quota::ResourceQuota; 76 | pub use crate::security::*; 77 | pub use crate::server::{ 78 | CheckResult, Server, ServerBuilder, ServerChecker, Service, ServiceBuilder, ShutdownFuture, 79 | }; 80 | 81 | /// A shortcut for implementing a service method by returning `UNIMPLEMENTED` status code. 82 | /// 83 | /// Compiler will provide a default implementations for all methods to invoke this macro, so 84 | /// you usually won't call it directly. If you really need to, just call it like: 85 | /// ```ignored 86 | /// fn method(&self, ctx: grpcio::RpcContext, req: Request, resp: UnarySink) { 87 | /// unimplemented_call!(ctx, resp); 88 | /// } 89 | /// ``` 90 | #[macro_export] 91 | macro_rules! unimplemented_call { 92 | ($ctx:ident, $sink:ident) => {{ 93 | let f = async move { 94 | let _ = $sink 95 | .fail($crate::RpcStatus::new($crate::RpcStatusCode::UNIMPLEMENTED)) 96 | .await; 97 | }; 98 | $ctx.spawn(f) 99 | }}; 100 | } 101 | -------------------------------------------------------------------------------- /src/log_util.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::ffi::CStr; 4 | 5 | use crate::grpc_sys::{self, gpr_log_func_args, gpr_log_severity}; 6 | use log::{self, Level, LevelFilter, Record}; 7 | 8 | #[inline] 9 | fn severity_to_log_level(severity: gpr_log_severity) -> Level { 10 | match severity { 11 | gpr_log_severity::GPR_LOG_SEVERITY_DEBUG => Level::Debug, 12 | gpr_log_severity::GPR_LOG_SEVERITY_INFO => Level::Info, 13 | gpr_log_severity::GPR_LOG_SEVERITY_ERROR => Level::Error, 14 | } 15 | } 16 | 17 | extern "C" fn delegate(c_args: *mut gpr_log_func_args) { 18 | let args = unsafe { &*c_args }; 19 | let level = severity_to_log_level(args.severity); 20 | if !log_enabled!(level) { 21 | return; 22 | } 23 | 24 | // can't panic. 25 | let file_str = unsafe { CStr::from_ptr(args.file).to_str().unwrap() }; 26 | let line = args.line as u32; 27 | 28 | let msg = unsafe { CStr::from_ptr(args.message).to_string_lossy() }; 29 | log::logger().log( 30 | &Record::builder() 31 | .args(format_args!("{msg}")) 32 | .level(level) 33 | .file_static(file_str.into()) 34 | .line(line.into()) 35 | .module_path_static(module_path!().into()) 36 | .build(), 37 | ); 38 | } 39 | 40 | /// Redirect grpc log to rust's log implementation. 41 | pub fn redirect_log() { 42 | let level = match log::max_level() { 43 | LevelFilter::Off => unsafe { 44 | // disable log. 45 | grpc_sys::gpr_set_log_function(None); 46 | return; 47 | }, 48 | LevelFilter::Error | LevelFilter::Warn => gpr_log_severity::GPR_LOG_SEVERITY_ERROR, 49 | LevelFilter::Info => gpr_log_severity::GPR_LOG_SEVERITY_INFO, 50 | LevelFilter::Debug | LevelFilter::Trace => gpr_log_severity::GPR_LOG_SEVERITY_DEBUG, 51 | }; 52 | 53 | unsafe { 54 | grpc_sys::gpr_set_log_verbosity(level); 55 | grpc_sys::gpr_set_log_function(Some(delegate)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/quota.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use crate::grpc_sys::{self, grpc_resource_quota}; 4 | use std::ffi::CString; 5 | use std::ptr; 6 | 7 | /// ResourceQuota represents a bound on memory and thread usage by the gRPC. 8 | /// NOTE: The management of threads created in grpc-core don't use ResourceQuota. 9 | /// TODO: Manage the poller threads created in grpc-rs with this ResourceQuota later. 10 | pub struct ResourceQuota { 11 | raw: *mut grpc_resource_quota, 12 | } 13 | 14 | impl ResourceQuota { 15 | /// Create a control block for resource quota. If a name is 16 | /// not declared for this control block, a name is automatically 17 | /// generated in grpc core. 18 | pub fn new(name: Option<&str>) -> ResourceQuota { 19 | match name { 20 | Some(name_str) => { 21 | let name_cstr = CString::new(name_str).unwrap(); 22 | ResourceQuota { 23 | raw: unsafe { grpc_sys::grpc_resource_quota_create(name_cstr.as_ptr() as _) }, 24 | } 25 | } 26 | None => ResourceQuota { 27 | raw: unsafe { grpc_sys::grpc_resource_quota_create(ptr::null()) }, 28 | }, 29 | } 30 | } 31 | 32 | /// Resize this ResourceQuota to a new memory size. 33 | pub fn resize_memory(self, new_size: usize) -> ResourceQuota { 34 | unsafe { grpc_sys::grpc_resource_quota_resize(self.raw, new_size) }; 35 | self 36 | } 37 | 38 | pub(crate) fn get_ptr(&self) -> *mut grpc_resource_quota { 39 | self.raw 40 | } 41 | } 42 | 43 | impl Clone for ResourceQuota { 44 | fn clone(&self) -> Self { 45 | unsafe { 46 | grpc_sys::grpc_resource_quota_ref(self.raw); 47 | } 48 | Self { raw: self.raw } 49 | } 50 | } 51 | 52 | impl Drop for ResourceQuota { 53 | fn drop(&mut self) { 54 | unsafe { 55 | grpc_sys::grpc_resource_quota_unref(self.raw); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/security/auth_context.rs: -------------------------------------------------------------------------------- 1 | //! API for authenticating peer 2 | //! Based on . 3 | 4 | use std::ffi::CStr; 5 | use std::marker::PhantomData; 6 | use std::ptr::NonNull; 7 | 8 | use crate::grpc_sys::{ 9 | self, grpc_auth_context, grpc_auth_property, grpc_auth_property_iterator, grpc_call, 10 | }; 11 | 12 | /// To perform server-side authentication, gRPC exposes the authentication context 13 | /// for each call. The context exposes important authentication-related information 14 | /// about the RPC such as the type of security/authentication type being used and 15 | /// the peer identity. 16 | /// 17 | /// The authentication context is structured as a multi-map of key-value pairs - 18 | /// the auth properties. In addition to that, for authenticated RPCs, the set of 19 | /// properties corresponding to a selected key will represent the verified identity 20 | /// of the caller - the peer identity. 21 | /// 22 | /// The contents of the auth properties are populated by an auth interceptor within 23 | /// gRPC Core. The interceptor also chooses which property key will act as the peer 24 | /// identity (e.g. for client certificate authentication this property will be 25 | /// `x509_common_name` or `x509_subject_alternative_name`). 26 | pub struct AuthContext { 27 | ctx: NonNull, 28 | } 29 | 30 | /// Binding to gRPC Core AuthContext 31 | impl AuthContext { 32 | pub(crate) unsafe fn from_call_ptr(call: *mut grpc_call) -> Option { 33 | NonNull::new(grpc_sys::grpc_call_auth_context(call)).map(|ctx| AuthContext { ctx }) 34 | } 35 | 36 | /// The name of the property gRPC Core has chosen as main peer identity property, 37 | /// if any. 38 | pub fn peer_identity_property_name(&self) -> Option<&str> { 39 | unsafe { 40 | let p = grpc_sys::grpc_auth_context_peer_identity_property_name(self.ctx.as_ref()); 41 | if p.is_null() { 42 | None 43 | } else { 44 | Some(CStr::from_ptr(p).to_str().expect("valid UTF-8 data")) 45 | } 46 | } 47 | } 48 | 49 | /// `true` if the client has provided a valid certificate (or other auth method 50 | /// considered valid by gRPC). 51 | /// `false` in non-secure scenarios. 52 | pub fn peer_is_authenticated(&self) -> bool { 53 | unsafe { grpc_sys::grpc_auth_context_peer_is_authenticated(self.ctx.as_ref()) != 0 } 54 | } 55 | 56 | /// `AuthContext[peer_identity_property_name()]` 57 | /// 58 | /// There may be several of them (for instance if `x509_subject_alternative_name` is selected) 59 | pub fn peer_identity(&self) -> AuthPropertyIter { 60 | unsafe { 61 | // grpc_auth_context_peer_identity returns empty_iterator when self.ctx is NULL 62 | let iter = grpc_sys::grpc_auth_context_peer_identity(self.ctx.as_ref()); 63 | AuthPropertyIter { 64 | iter, 65 | _lifetime: PhantomData, 66 | } 67 | } 68 | } 69 | } 70 | 71 | impl<'a> IntoIterator for &'a AuthContext { 72 | type Item = AuthProperty<'a>; 73 | type IntoIter = AuthPropertyIter<'a>; 74 | 75 | /// Iterate over the AuthContext properties 76 | fn into_iter(self) -> Self::IntoIter { 77 | unsafe { 78 | // grpc_auth_context_property_iterator returns empty_iterator when self.ctx is NULL 79 | let iter = grpc_sys::grpc_auth_context_property_iterator(self.ctx.as_ref()); 80 | AuthPropertyIter { 81 | iter, 82 | _lifetime: PhantomData, 83 | } 84 | } 85 | } 86 | } 87 | 88 | impl Drop for AuthContext { 89 | fn drop(&mut self) { 90 | unsafe { grpc_sys::grpc_auth_context_release(self.ctx.as_ptr()) } 91 | } 92 | } 93 | 94 | pub struct AuthPropertyIter<'a> { 95 | iter: grpc_auth_property_iterator, 96 | _lifetime: PhantomData<&'a grpc_auth_property_iterator>, 97 | } 98 | 99 | impl<'a> Iterator for AuthPropertyIter<'a> { 100 | type Item = AuthProperty<'a>; 101 | 102 | fn next(&mut self) -> Option { 103 | // grpc_auth_property_iterator_next returns empty_iterator when self.iter is NULL 104 | let prop = unsafe { grpc_sys::grpc_auth_property_iterator_next(&mut self.iter) }; 105 | if prop.is_null() { 106 | None 107 | } else { 108 | Some(AuthProperty { 109 | prop, 110 | _lifetime: PhantomData, 111 | }) 112 | } 113 | } 114 | } 115 | 116 | /// Auth properties are elements of the AuthContext. They have a name 117 | /// (a key of type string) and a value which can be a string or binary data. 118 | pub struct AuthProperty<'a> { 119 | prop: *const grpc_auth_property, 120 | _lifetime: PhantomData<&'a grpc_auth_property>, 121 | } 122 | 123 | impl<'a> AuthProperty<'a> { 124 | pub fn name(&self) -> &'a str { 125 | unsafe { CStr::from_ptr((*self.prop).name) } 126 | .to_str() 127 | .expect("Auth property name should be valid UTF-8 data") 128 | } 129 | 130 | pub fn value(&self) -> &'a [u8] { 131 | unsafe { 132 | std::slice::from_raw_parts((*self.prop).value as *const u8, (*self.prop).value_length) 133 | } 134 | } 135 | 136 | pub fn value_str(&self) -> Result<&'a str, std::str::Utf8Error> { 137 | std::str::from_utf8(self.value()) 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/security/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #[cfg(feature = "_secure")] 4 | mod auth_context; 5 | #[cfg(feature = "_secure")] 6 | mod credentials; 7 | 8 | use grpcio_sys::{grpc_channel_credentials, grpc_server_credentials}; 9 | 10 | #[cfg(feature = "_secure")] 11 | pub use self::auth_context::*; 12 | #[cfg(feature = "_secure")] 13 | pub use self::credentials::{ 14 | CertificateRequestType, ChannelCredentialsBuilder, ServerCredentialsBuilder, 15 | ServerCredentialsFetcher, 16 | }; 17 | 18 | /// Client-side SSL credentials. 19 | /// 20 | /// Use [`ChannelCredentialsBuilder`] or [`ChannelCredentials::google_default_credentials`] to 21 | /// build a [`ChannelCredentials`]. 22 | pub struct ChannelCredentials { 23 | creds: *mut grpc_channel_credentials, 24 | } 25 | 26 | impl ChannelCredentials { 27 | pub fn as_mut_ptr(&mut self) -> *mut grpc_channel_credentials { 28 | self.creds 29 | } 30 | 31 | /// Creates an insecure channel credentials object. 32 | pub fn insecure() -> ChannelCredentials { 33 | unsafe { 34 | let creds = grpcio_sys::grpc_insecure_credentials_create(); 35 | ChannelCredentials { creds } 36 | } 37 | } 38 | } 39 | 40 | impl Drop for ChannelCredentials { 41 | fn drop(&mut self) { 42 | unsafe { grpcio_sys::grpc_channel_credentials_release(self.creds) } 43 | } 44 | } 45 | 46 | /// Server-side SSL credentials. 47 | /// 48 | /// Use [`ServerCredentialsBuilder`] to build a [`ServerCredentials`]. 49 | pub struct ServerCredentials { 50 | creds: *mut grpc_server_credentials, 51 | // Double allocation to get around C call. 52 | #[cfg(feature = "_secure")] 53 | _fetcher: Option>>, 54 | } 55 | 56 | unsafe impl Send for ServerCredentials {} 57 | 58 | impl ServerCredentials { 59 | /// Creates an insecure server credentials object. 60 | pub fn insecure() -> ServerCredentials { 61 | unsafe { 62 | let creds = grpcio_sys::grpc_insecure_server_credentials_create(); 63 | ServerCredentials::from_raw(creds) 64 | } 65 | } 66 | 67 | pub(crate) unsafe fn from_raw(creds: *mut grpc_server_credentials) -> ServerCredentials { 68 | ServerCredentials { 69 | creds, 70 | #[cfg(feature = "_secure")] 71 | _fetcher: None, 72 | } 73 | } 74 | 75 | pub fn as_mut_ptr(&mut self) -> *mut grpc_server_credentials { 76 | self.creds 77 | } 78 | } 79 | 80 | impl Drop for ServerCredentials { 81 | fn drop(&mut self) { 82 | unsafe { 83 | grpcio_sys::grpc_server_credentials_release(self.creds); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/task/callback.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use crate::call::server::{RequestContext, UnaryRequestContext}; 4 | use crate::call::{BatchContext, Call}; 5 | use crate::cq::CompletionQueue; 6 | use crate::server::{self, RequestCallContext}; 7 | 8 | pub struct Request { 9 | ctx: RequestContext, 10 | } 11 | 12 | impl Request { 13 | pub fn new(rc: RequestCallContext) -> Request { 14 | let ctx = RequestContext::new(rc); 15 | Request { ctx } 16 | } 17 | 18 | pub fn context(&self) -> &RequestContext { 19 | &self.ctx 20 | } 21 | 22 | pub fn resolve(mut self, cq: &CompletionQueue, success: bool) { 23 | let mut rc = self.ctx.take_request_call_context().unwrap(); 24 | if !success { 25 | server::request_call(rc, cq); 26 | return; 27 | } 28 | 29 | match self.ctx.handle_stream_req(cq, &mut rc) { 30 | Ok(_) => server::request_call(rc, cq), 31 | Err(ctx) => ctx.handle_unary_req(rc, cq), 32 | } 33 | } 34 | } 35 | 36 | pub struct UnaryRequest { 37 | ctx: UnaryRequestContext, 38 | } 39 | 40 | impl UnaryRequest { 41 | pub fn new(ctx: RequestContext, rc: RequestCallContext) -> UnaryRequest { 42 | let ctx = UnaryRequestContext::new(ctx, rc); 43 | UnaryRequest { ctx } 44 | } 45 | 46 | pub fn batch_ctx(&self) -> &BatchContext { 47 | self.ctx.batch_ctx() 48 | } 49 | 50 | pub fn request_ctx(&self) -> &RequestContext { 51 | self.ctx.request_ctx() 52 | } 53 | 54 | pub fn resolve(mut self, cq: &CompletionQueue, success: bool) { 55 | let mut rc = self.ctx.take_request_call_context().unwrap(); 56 | if !success { 57 | server::request_call(rc, cq); 58 | return; 59 | } 60 | 61 | let reader = self.ctx.batch_ctx_mut().recv_message(); 62 | self.ctx.handle(&mut rc, cq, reader); 63 | server::request_call(rc, cq); 64 | } 65 | } 66 | 67 | /// A callback to wait for status for the aborted rpc call to be sent. 68 | pub struct Abort { 69 | ctx: BatchContext, 70 | _call: Call, 71 | } 72 | 73 | impl Abort { 74 | pub fn new(call: Call) -> Abort { 75 | Abort { 76 | ctx: BatchContext::new(), 77 | _call: call, 78 | } 79 | } 80 | 81 | pub fn batch_ctx(&self) -> &BatchContext { 82 | &self.ctx 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/task/promise.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::fmt::{self, Debug, Formatter}; 4 | use std::sync::Arc; 5 | 6 | use super::Inner; 7 | use crate::call::{BatchContext, MessageReader, RpcStatusCode}; 8 | use crate::error::Error; 9 | use crate::metadata::UnownedMetadata; 10 | 11 | /// Batch job type. 12 | #[derive(PartialEq, Debug)] 13 | pub enum BatchType { 14 | /// Finish without reading any message. 15 | Finish, 16 | /// Extract one message when finish. 17 | Read, 18 | /// Check the rpc code and then extract one message. 19 | CheckRead, 20 | } 21 | 22 | /// A promise result which stores a message reader with bundled metadata. 23 | pub struct BatchResult { 24 | pub message_reader: Option, 25 | pub initial_metadata: UnownedMetadata, 26 | pub trailing_metadata: UnownedMetadata, 27 | } 28 | 29 | impl BatchResult { 30 | pub fn new( 31 | message_reader: Option, 32 | initial_metadata: Option, 33 | trailing_metadata: Option, 34 | ) -> BatchResult { 35 | let initial_metadata = if let Some(m) = initial_metadata { 36 | m 37 | } else { 38 | UnownedMetadata::empty() 39 | }; 40 | let trailing_metadata = if let Some(m) = trailing_metadata { 41 | m 42 | } else { 43 | UnownedMetadata::empty() 44 | }; 45 | BatchResult { 46 | message_reader, 47 | initial_metadata, 48 | trailing_metadata, 49 | } 50 | } 51 | } 52 | 53 | /// A promise used to resolve batch jobs. 54 | pub struct Batch { 55 | ty: BatchType, 56 | ctx: BatchContext, 57 | inner: Arc>, 58 | } 59 | 60 | impl Batch { 61 | pub fn new(ty: BatchType, inner: Arc>) -> Batch { 62 | Batch { 63 | ty, 64 | ctx: BatchContext::new(), 65 | inner, 66 | } 67 | } 68 | 69 | pub fn context(&self) -> &BatchContext { 70 | &self.ctx 71 | } 72 | 73 | fn read_one_msg(&mut self, success: bool) { 74 | let task = { 75 | let mut guard = self.inner.lock(); 76 | if success { 77 | guard.set_result(Ok(BatchResult::new(self.ctx.recv_message(), None, None))) 78 | } else { 79 | // rely on C core to handle the failed read (e.g. deliver approriate 80 | // statusCode on the clientside). 81 | guard.set_result(Ok(BatchResult::new(None, None, None))) 82 | } 83 | }; 84 | task.map(|t| t.wake()); 85 | } 86 | 87 | fn finish_response(&mut self, succeed: bool) { 88 | let task = { 89 | let mut guard = self.inner.lock(); 90 | if succeed { 91 | let status = self.ctx.rpc_status(); 92 | if status.code() == RpcStatusCode::OK { 93 | guard.set_result(Ok(BatchResult::new( 94 | None, 95 | Some(self.ctx.take_initial_metadata()), 96 | Some(self.ctx.take_trailing_metadata()), 97 | ))) 98 | } else { 99 | guard.set_result(Err(Error::RpcFailure(status))) 100 | } 101 | } else { 102 | guard.set_result(Err(Error::RemoteStopped)) 103 | } 104 | }; 105 | task.map(|t| t.wake()); 106 | } 107 | 108 | fn handle_unary_response(&mut self) { 109 | let task = { 110 | let mut guard = self.inner.lock(); 111 | let status = self.ctx.rpc_status(); 112 | if status.code() == RpcStatusCode::OK { 113 | guard.set_result(Ok(BatchResult::new( 114 | self.ctx.recv_message(), 115 | Some(self.ctx.take_initial_metadata()), 116 | Some(self.ctx.take_trailing_metadata()), 117 | ))) 118 | } else { 119 | guard.set_result(Err(Error::RpcFailure(status))) 120 | } 121 | }; 122 | task.map(|t| t.wake()); 123 | } 124 | 125 | pub fn resolve(mut self, success: bool) { 126 | match self.ty { 127 | BatchType::CheckRead => { 128 | assert!(success); 129 | self.handle_unary_response(); 130 | } 131 | BatchType::Finish => { 132 | self.finish_response(success); 133 | } 134 | BatchType::Read => { 135 | self.read_one_msg(success); 136 | } 137 | } 138 | } 139 | } 140 | 141 | impl Debug for Batch { 142 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 143 | write!(f, "Batch [{:?}]", self.ty) 144 | } 145 | } 146 | 147 | /// A promise used to resolve async action status. 148 | /// 149 | /// The action can only succeed or fail without extra error hint. 150 | pub struct Action { 151 | inner: Arc>, 152 | } 153 | 154 | impl Action { 155 | pub fn new(inner: Arc>) -> Action { 156 | Action { inner } 157 | } 158 | 159 | pub fn resolve(self, success: bool) { 160 | let task = { 161 | let mut guard = self.inner.lock(); 162 | guard.set_result(Ok(success)) 163 | }; 164 | task.map(|t| t.wake()); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /tests-and-examples/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tests-and-examples" 3 | version = "0.1.0" 4 | edition = "2018" 5 | autoexamples = false 6 | publish = false 7 | 8 | [features] 9 | default = ["protobuf-codec"] 10 | protobuf-codec = ["protobuf", "grpcio/protobuf-codec", "grpcio-proto/protobuf-codec", "grpcio-health/protobuf-codec"] 11 | protobufv3-codec = ["protobufv3", "grpcio/protobufv3-codec", "grpcio-proto/protobufv3-codec", "grpcio-health/protobufv3-codec"] 12 | prost-codec = ["prost", "bytes", "grpcio/prost-codec", "grpcio-proto/prost-codec", "grpcio-health/prost-codec"] 13 | 14 | [dependencies] 15 | grpcio-sys = { path = "../grpc-sys" } 16 | libc = "0.2" 17 | futures-channel = { version = "0.3", features = ["sink"] } 18 | futures-executor = "0.3" 19 | futures-util = { version = "0.3", features = ["sink"] } 20 | futures-timer = "3.0" 21 | protobuf = { version = "2", optional = true } 22 | protobufv3 = { package = "protobuf", version = "3.2", optional = true } 23 | prost = { version = "0.13", optional = true } 24 | bytes = { version = "1.0", optional = true } 25 | log = "0.4" 26 | grpcio = { path = "..", default-features = false, features = ["boringssl"] } 27 | grpcio-health = { path = "../health", default-features = false } 28 | 29 | [dev-dependencies] 30 | serde_json = "1.0" 31 | serde = "1.0" 32 | serde_derive = "1.0" 33 | grpcio-proto = { path = "../proto", default-features = false } 34 | rand = "0.8" 35 | slog = "2.0" 36 | slog-async = "2.1" 37 | slog-stdlog = "4.0" 38 | slog-scope = "4.0" 39 | slog-term = "2.2" 40 | 41 | [[example]] 42 | name = "route_guide_client" 43 | path = "examples/route_guide/client.rs" 44 | #required-features = "protobuf-codec" or "protobufv3-codec" 45 | 46 | [[example]] 47 | name = "route_guide_server" 48 | path = "examples/route_guide/server.rs" 49 | #required-features = "protobuf-codec" or "protobufv3-codec" 50 | 51 | [[example]] 52 | name = "greeter_client" 53 | path = "examples/hello_world/client.rs" 54 | #required-features = "protobuf-codec" or "protobufv3-codec" 55 | 56 | [[example]] 57 | name = "greeter_server" 58 | path = "examples/hello_world/server.rs" 59 | #required-features = "protobuf-codec" or "protobufv3-codec" 60 | 61 | [[example]] 62 | name = "lb_greeter_client" 63 | path = "examples/load_balancing/client.rs" 64 | #required-features = "protobuf-codec" or "protobufv3-codec" 65 | 66 | [[example]] 67 | name = "lb_greeter_server" 68 | path = "examples/load_balancing/server.rs" 69 | #required-features = "protobuf-codec" or "protobufv3-codec" 70 | -------------------------------------------------------------------------------- /tests-and-examples/examples/hello_world/client.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #[macro_use] 4 | extern crate log; 5 | 6 | #[path = "../log_util.rs"] 7 | mod log_util; 8 | 9 | use std::sync::Arc; 10 | 11 | use grpcio::{ChannelBuilder, EnvBuilder}; 12 | use grpcio_proto::example::helloworld::HelloRequest; 13 | use grpcio_proto::example::helloworld_grpc::GreeterClient; 14 | 15 | fn main() { 16 | let _guard = log_util::init_log(None); 17 | let env = Arc::new(EnvBuilder::new().build()); 18 | let ch = ChannelBuilder::new(env).connect("localhost:50051"); 19 | let client = GreeterClient::new(ch); 20 | 21 | let mut req = HelloRequest::default(); 22 | req.name = "world".to_owned(); 23 | let reply = client.say_hello(&req).expect("rpc"); 24 | info!("Greeter received: {}", reply.message); 25 | } 26 | -------------------------------------------------------------------------------- /tests-and-examples/examples/hello_world/server.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #[macro_use] 4 | extern crate log; 5 | 6 | #[path = "../log_util.rs"] 7 | mod log_util; 8 | 9 | use std::io::Read; 10 | use std::sync::Arc; 11 | use std::{io, thread}; 12 | 13 | use futures_channel::oneshot; 14 | use futures_executor::block_on; 15 | use futures_util::future::{FutureExt as _, TryFutureExt as _}; 16 | use grpcio::{ 17 | ChannelBuilder, Environment, ResourceQuota, RpcContext, ServerBuilder, ServerCredentials, 18 | UnarySink, 19 | }; 20 | 21 | use grpcio_proto::example::helloworld::{HelloReply, HelloRequest}; 22 | use grpcio_proto::example::helloworld_grpc::{create_greeter, Greeter}; 23 | 24 | #[derive(Clone)] 25 | struct GreeterService; 26 | 27 | impl Greeter for GreeterService { 28 | fn say_hello(&mut self, ctx: RpcContext<'_>, req: HelloRequest, sink: UnarySink) { 29 | let msg = format!("Hello {}", req.name); 30 | let mut resp = HelloReply::default(); 31 | resp.message = msg; 32 | let f = sink 33 | .success(resp) 34 | .map_err(move |e| error!("failed to reply {:?}: {:?}", req, e)) 35 | .map(|_| ()); 36 | ctx.spawn(f) 37 | } 38 | } 39 | 40 | fn main() { 41 | let _guard = log_util::init_log(None); 42 | let env = Arc::new(Environment::new(1)); 43 | let service = create_greeter(GreeterService); 44 | let addr = "127.0.0.1:50051"; 45 | 46 | let quota = ResourceQuota::new(Some("HelloServerQuota")).resize_memory(1024 * 1024); 47 | let ch_builder = ChannelBuilder::new(env.clone()).set_resource_quota(quota); 48 | 49 | let mut server = ServerBuilder::new(env) 50 | .register_service(service) 51 | .channel_args(ch_builder.build_args()) 52 | .build() 53 | .unwrap(); 54 | server 55 | .add_listening_port(addr, ServerCredentials::insecure()) 56 | .unwrap(); 57 | server.start(); 58 | info!("listening on {addr}"); 59 | let (tx, rx) = oneshot::channel(); 60 | thread::spawn(move || { 61 | info!("Press ENTER to exit..."); 62 | let _ = io::stdin().read(&mut [0]).unwrap(); 63 | tx.send(()) 64 | }); 65 | let _ = block_on(rx); 66 | let _ = block_on(server.shutdown()); 67 | } 68 | -------------------------------------------------------------------------------- /tests-and-examples/examples/load_balancing/client.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | //! A simple example shows that load balancing is working on the client side. 4 | //! 5 | //! For the design of load balancing, see https://github.com/grpc/grpc/blob/master/doc/load-balancing.md. 6 | //! 7 | //! Load report has not been implemented yet. 8 | 9 | #[macro_use] 10 | extern crate log; 11 | 12 | #[path = "../log_util.rs"] 13 | mod log_util; 14 | 15 | use std::sync::Arc; 16 | 17 | use grpcio::{ChannelBuilder, EnvBuilder, LbPolicy}; 18 | use grpcio_proto::example::helloworld::HelloRequest; 19 | use grpcio_proto::example::helloworld_grpc::GreeterClient; 20 | 21 | fn main() { 22 | let _guard = log_util::init_log(None); 23 | let env = Arc::new(EnvBuilder::new().build()); 24 | let ch = ChannelBuilder::new(env) 25 | .load_balancing_policy(LbPolicy::RoundRobin) 26 | .connect("ipv4:127.0.0.1:50051,127.0.0.1:50052"); 27 | let client = GreeterClient::new(ch); 28 | 29 | for _ in 0..2 { 30 | let mut req = HelloRequest::default(); 31 | req.name = "world".to_owned(); 32 | let reply = client.say_hello(&req).expect("rpc"); 33 | info!("Greeter received: {}", reply.message); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests-and-examples/examples/load_balancing/server.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #[macro_use] 4 | extern crate log; 5 | 6 | #[path = "../log_util.rs"] 7 | mod log_util; 8 | 9 | use std::io::Read; 10 | use std::sync::Arc; 11 | use std::{io, thread}; 12 | 13 | use futures_channel::oneshot; 14 | use futures_executor::block_on; 15 | use futures_util::future::{FutureExt as _, TryFutureExt as _}; 16 | use grpcio::{ 17 | ChannelBuilder, Environment, ResourceQuota, RpcContext, Server, ServerBuilder, 18 | ServerCredentials, UnarySink, 19 | }; 20 | 21 | use grpcio_proto::example::helloworld::{HelloReply, HelloRequest}; 22 | use grpcio_proto::example::helloworld_grpc::{create_greeter, Greeter}; 23 | 24 | #[derive(Clone)] 25 | struct GreeterService { 26 | name: String, 27 | } 28 | 29 | impl Greeter for GreeterService { 30 | fn say_hello(&mut self, ctx: RpcContext<'_>, req: HelloRequest, sink: UnarySink) { 31 | let msg = format!("Hello {}, I'm {}", req.name, self.name); 32 | let mut resp = HelloReply::default(); 33 | resp.message = msg; 34 | let f = sink 35 | .success(resp) 36 | .map_err(move |e| error!("failed to reply {:?}: {:?}", req, e)) 37 | .map(|_| ()); 38 | ctx.spawn(f) 39 | } 40 | } 41 | 42 | fn build_server(env: Arc, mut port: u16) -> Server { 43 | let service = create_greeter(GreeterService { 44 | name: format!("{port}"), 45 | }); 46 | let quota = ResourceQuota::new(Some("HelloServerQuota")).resize_memory(1024 * 1024); 47 | let ch_builder = ChannelBuilder::new(env.clone()).set_resource_quota(quota); 48 | 49 | let mut server = ServerBuilder::new(env) 50 | .register_service(service) 51 | .channel_args(ch_builder.build_args()) 52 | .build() 53 | .unwrap(); 54 | port = server 55 | .add_listening_port(&format!("127.0.0.1:{port}"), ServerCredentials::insecure()) 56 | .unwrap(); 57 | server.start(); 58 | info!("listening on 127.0.0.1:{port}"); 59 | server 60 | } 61 | 62 | fn main() { 63 | let _guard = log_util::init_log(None); 64 | let env = Arc::new(Environment::new(1)); 65 | let mut server1 = build_server(env.clone(), 50_051); 66 | let mut server2 = build_server(env, 50_052); 67 | let (tx, rx) = oneshot::channel(); 68 | thread::spawn(move || { 69 | info!("Press ENTER to exit..."); 70 | let _ = io::stdin().read(&mut [0]).unwrap(); 71 | tx.send(()) 72 | }); 73 | let _ = block_on(rx); 74 | let _ = block_on(server1.shutdown()); 75 | let _ = block_on(server2.shutdown()); 76 | } 77 | -------------------------------------------------------------------------------- /tests-and-examples/examples/log_util.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | extern crate slog; 4 | extern crate slog_async; 5 | extern crate slog_scope; 6 | extern crate slog_stdlog; 7 | extern crate slog_term; 8 | 9 | use std::fs::File; 10 | 11 | use self::slog::{Drain, Logger, OwnedKV}; 12 | use self::slog_scope::GlobalLoggerGuard; 13 | use self::slog_term::{Decorator, FullFormat, PlainSyncDecorator, TermDecorator}; 14 | 15 | pub fn init_log(log_file: Option) -> GlobalLoggerGuard { 16 | fn setup(decorator: D) -> GlobalLoggerGuard { 17 | let drain = FullFormat::new(decorator).build().fuse(); 18 | let drain = slog_async::Async::new(drain).build().fuse(); 19 | let logger = Logger::root(drain, OwnedKV(())); 20 | let guard = slog_scope::set_global_logger(logger); 21 | slog_stdlog::init().unwrap(); 22 | guard 23 | } 24 | 25 | match log_file { 26 | Some(path) => { 27 | let file = File::create(path).unwrap(); 28 | setup(PlainSyncDecorator::new(file)) 29 | } 30 | None => setup(TermDecorator::new().build()), 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests-and-examples/examples/route_guide/util.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | #![allow(unknown_lints)] 4 | // client and server share different parts of utils. 5 | #![allow(dead_code)] 6 | #![allow(clippy::cast_lossless)] 7 | 8 | use std::f64::consts::PI; 9 | 10 | use grpcio_proto::example::route_guide::*; 11 | 12 | #[derive(Serialize, Deserialize, Debug)] 13 | struct PointRef { 14 | latitude: i32, 15 | longitude: i32, 16 | } 17 | 18 | #[derive(Serialize, Deserialize, Debug)] 19 | struct FeatureRef { 20 | location: PointRef, 21 | name: String, 22 | } 23 | 24 | impl From for Feature { 25 | fn from(r: FeatureRef) -> Feature { 26 | let mut f = Feature::default(); 27 | f.name = r.name; 28 | let mut point = Point::new(); 29 | point.longitude = r.location.longitude; 30 | point.latitude = r.location.latitude; 31 | f.location = Some(point).into(); 32 | f 33 | } 34 | } 35 | 36 | pub fn load_db() -> Vec { 37 | let data = include_str!("db.json"); 38 | let features: Vec = serde_json::from_str(data).unwrap(); 39 | features.into_iter().map(From::from).collect() 40 | } 41 | 42 | pub fn same_point(lhs: &Point, rhs: &Point) -> bool { 43 | lhs.longitude == rhs.longitude && lhs.latitude == rhs.latitude 44 | } 45 | 46 | #[cfg(feature = "protobuf-codec")] 47 | pub fn fit_in(lhs: &Point, rhs: &Rectangle) -> bool { 48 | let hi = rhs.get_hi(); 49 | let lo = rhs.get_lo(); 50 | lhs.get_longitude() <= hi.get_longitude() 51 | && lhs.get_longitude() >= lo.get_longitude() 52 | && lhs.get_latitude() <= hi.get_latitude() 53 | && lhs.get_latitude() >= lo.get_latitude() 54 | } 55 | 56 | #[cfg(feature = "protobufv3-codec")] 57 | pub fn fit_in(lhs: &Point, rhs: &Rectangle) -> bool { 58 | lhs.longitude <= rhs.hi.longitude 59 | && lhs.longitude >= rhs.lo.longitude 60 | && lhs.latitude <= rhs.hi.latitude 61 | && lhs.latitude >= rhs.lo.latitude 62 | } 63 | 64 | const COORD_FACTOR: f64 = 10000000.0; 65 | 66 | pub fn convert_to_rad(num: f64) -> f64 { 67 | num * PI / 180.0 68 | } 69 | 70 | pub fn format_point(p: &Point) -> String { 71 | format!( 72 | "{}, {}", 73 | p.latitude as f64 / COORD_FACTOR, 74 | p.longitude as f64 / COORD_FACTOR 75 | ) 76 | } 77 | 78 | pub fn cal_distance(lhs: &Point, rhs: &Point) -> f64 { 79 | let lat1 = lhs.latitude as f64 / COORD_FACTOR; 80 | let lon1 = lhs.longitude as f64 / COORD_FACTOR; 81 | let lat2 = rhs.latitude as f64 / COORD_FACTOR; 82 | let lon2 = rhs.longitude as f64 / COORD_FACTOR; 83 | let lat_rad_1 = convert_to_rad(lat1); 84 | let lat_rad_2 = convert_to_rad(lat2); 85 | let delta_lat_rad = convert_to_rad(lat2 - lat1); 86 | let delta_lon_rad = convert_to_rad(lon2 - lon1); 87 | 88 | let a = (delta_lat_rad / 2.0).sin().powi(2) 89 | + lat_rad_1.cos() * lat_rad_2.cos() * (delta_lon_rad / 2.0).sin().powi(2); 90 | let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt()); 91 | let r = 6371000.0; // metres 92 | 93 | r * c 94 | } 95 | -------------------------------------------------------------------------------- /tests-and-examples/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | pub mod util; 4 | -------------------------------------------------------------------------------- /tests-and-examples/src/util.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use std::fs; 4 | use std::io::{self, Read}; 5 | 6 | const CERT_DIR: &str = "../grpc-sys/grpc/src/core/tsi/test_creds"; 7 | 8 | fn cert_path(name: &str, ext: &str) -> String { 9 | let p = format!("{CERT_DIR}/{name}.{ext}"); 10 | println!("reading {p}"); 11 | p 12 | } 13 | 14 | pub fn read_single_crt(name: &str) -> Result { 15 | let mut crt = String::new(); 16 | fs::File::open(cert_path(name, "pem"))?.read_to_string(&mut crt)?; 17 | Ok(crt) 18 | } 19 | 20 | pub fn read_cert_pair(name: &str) -> Result<(String, String), io::Error> { 21 | let mut crt = String::new(); 22 | let mut key = String::new(); 23 | fs::File::open(cert_path(name, "pem"))?.read_to_string(&mut crt)?; 24 | fs::File::open(cert_path(name, "key"))?.read_to_string(&mut key)?; 25 | Ok((crt, key)) 26 | } 27 | -------------------------------------------------------------------------------- /tests-and-examples/tests/cases/auth_context.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use futures_util::future::{FutureExt as _, TryFutureExt as _}; 4 | use grpcio::*; 5 | use grpcio_proto::example::helloworld::*; 6 | 7 | use std::collections::HashMap; 8 | use std::sync::mpsc::{self, Sender}; 9 | use std::sync::*; 10 | use std::time::*; 11 | 12 | use tests_and_examples::util::{read_cert_pair, read_single_crt}; 13 | 14 | #[derive(Clone)] 15 | struct GreeterService { 16 | tx: Sender>>, 17 | } 18 | 19 | impl Greeter for GreeterService { 20 | fn say_hello(&mut self, ctx: RpcContext<'_>, req: HelloRequest, sink: UnarySink) { 21 | if let Some(auth_context) = ctx.auth_context() { 22 | let mut ctx_map = HashMap::new(); 23 | for (key, value) in auth_context 24 | .into_iter() 25 | .map(|x| (x.name(), x.value_str().unwrap())) 26 | { 27 | ctx_map.insert(key.to_owned(), value.to_owned()); 28 | } 29 | self.tx.send(Some(ctx_map)).unwrap(); 30 | } 31 | 32 | let mut resp = HelloReply::default(); 33 | resp.message = format!("hello {}", req.name); 34 | ctx.spawn( 35 | sink.success(resp) 36 | .map_err(|e| panic!("failed to reply {:?}", e)) 37 | .map(|_| ()), 38 | ); 39 | } 40 | } 41 | 42 | #[test] 43 | fn test_auth_context() { 44 | let env = Arc::new(EnvBuilder::new().build()); 45 | let (tx, rx) = mpsc::channel(); 46 | let service = create_greeter(GreeterService { tx }); 47 | let (server_crt, server_key) = read_cert_pair("server1").unwrap(); 48 | let server_credentials = grpcio::ServerCredentialsBuilder::new() 49 | .root_cert( 50 | read_single_crt("ca").unwrap(), 51 | CertificateRequestType::RequestClientCertificateAndVerify, 52 | ) 53 | .add_cert(server_crt.into(), server_key.into()) 54 | .build(); 55 | let mut server = ServerBuilder::new(env.clone()) 56 | .register_service(service) 57 | .build() 58 | .unwrap(); 59 | let port = server 60 | .add_listening_port("127.0.0.1:0", server_credentials) 61 | .unwrap(); 62 | server.start(); 63 | 64 | let (client_crt, client_key) = read_cert_pair("client1").unwrap(); 65 | let client_credentials = ChannelCredentialsBuilder::new() 66 | .root_cert(read_single_crt("ca").unwrap().into()) 67 | .cert(client_crt.clone().into(), client_key.into()) 68 | .build(); 69 | let ch = ChannelBuilder::new(env) 70 | .override_ssl_target("rust.test.google.fr") 71 | .set_credentials(client_credentials) 72 | .connect(&format!("127.0.0.1:{port}")); 73 | let client = GreeterClient::new(ch); 74 | 75 | let mut req = HelloRequest::default(); 76 | req.name = "world".to_owned(); 77 | let resp = client.say_hello(&req).unwrap(); 78 | 79 | assert_eq!(resp.message, "hello world"); 80 | 81 | // Test auth_context keys 82 | let ctx_map = rx.recv_timeout(Duration::from_secs(1)).unwrap().unwrap(); 83 | 84 | assert_eq!(ctx_map.get("transport_security_type").unwrap(), "ssl"); 85 | assert_eq!(ctx_map.get("x509_common_name").unwrap(), "testclient1"); 86 | assert_eq!( 87 | ctx_map.get("x509_pem_cert").unwrap(), 88 | &client_crt.replace("\r\n", "\n") 89 | ); 90 | assert_eq!( 91 | ctx_map.get("security_level").unwrap(), 92 | "TSI_PRIVACY_AND_INTEGRITY" 93 | ); 94 | assert_eq!(ctx_map.get("ssl_session_reused").unwrap(), "false"); 95 | assert!(ctx_map.get("x509_subject_alternative_name").is_none()); 96 | } 97 | 98 | #[test] 99 | fn test_no_crash_on_insecure() { 100 | let env = Arc::new(EnvBuilder::new().build()); 101 | let (tx, rx) = mpsc::channel(); 102 | let service = create_greeter(GreeterService { tx }); 103 | let mut server = ServerBuilder::new(env.clone()) 104 | .register_service(service) 105 | .build() 106 | .unwrap(); 107 | let port = server 108 | .add_listening_port("127.0.0.1:0", ServerCredentials::insecure()) 109 | .unwrap(); 110 | server.start(); 111 | 112 | let ch = ChannelBuilder::new(env).connect(&format!("127.0.0.1:{port}")); 113 | let client = GreeterClient::new(ch); 114 | 115 | let mut req = HelloRequest::default(); 116 | req.name = "world".to_owned(); 117 | let resp = client.say_hello(&req).unwrap(); 118 | 119 | assert_eq!(resp.message, "hello world"); 120 | 121 | // Test auth_context keys 122 | let ctx_map = rx.recv_timeout(Duration::from_secs(1)).unwrap().unwrap(); 123 | assert_eq!(ctx_map.get("transport_security_type").unwrap(), "insecure"); 124 | assert_eq!(ctx_map.get("security_level").unwrap(), "TSI_SECURITY_NONE"); 125 | } 126 | -------------------------------------------------------------------------------- /tests-and-examples/tests/cases/metadata.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | use futures_executor::block_on; 4 | use futures_util::future::{FutureExt as _, TryFutureExt as _}; 5 | use futures_util::{SinkExt, TryStreamExt}; 6 | use grpcio::*; 7 | use grpcio_proto::example::helloworld::*; 8 | 9 | use grpcio_proto::example::route_guide::{Feature, Rectangle}; 10 | use grpcio_proto::example::route_guide_grpc::{create_route_guide, RouteGuide, RouteGuideClient}; 11 | use grpcio_proto::google::rpc::Status; 12 | use std::convert::TryInto; 13 | use std::sync::*; 14 | 15 | #[derive(Clone)] 16 | struct GreeterService; 17 | 18 | impl Greeter for GreeterService { 19 | fn say_hello( 20 | &mut self, 21 | ctx: RpcContext<'_>, 22 | req: HelloRequest, 23 | mut sink: UnarySink, 24 | ) { 25 | let headers = ctx.request_headers().clone(); 26 | sink.set_headers(headers); 27 | 28 | if req.name == "root" { 29 | let mut status = Status { 30 | code: RpcStatusCode::INVALID_ARGUMENT.into(), 31 | message: "name can't be root".to_owned(), 32 | ..Default::default() 33 | }; 34 | #[cfg(feature = "protobuf-codec")] 35 | let any = protobuf::well_known_types::Any::pack(&req).unwrap(); 36 | 37 | #[cfg(feature = "protobufv3-codec")] 38 | let any = protobufv3::well_known_types::any::Any::pack(&req).unwrap(); 39 | status.details.push(any); 40 | ctx.spawn( 41 | sink.fail(status.try_into().unwrap()) 42 | .map_err(|e| panic!("failed to report error: {:?}", e)) 43 | .map(|_| ()), 44 | ); 45 | return; 46 | } 47 | 48 | let mut resp = HelloReply::default(); 49 | resp.message = format!("hello {}", req.name); 50 | ctx.spawn( 51 | sink.success(resp) 52 | .map_err(|e| panic!("failed to reply {:?}", e)) 53 | .map(|_| ()), 54 | ); 55 | } 56 | } 57 | 58 | impl RouteGuide for GreeterService { 59 | fn list_features( 60 | &mut self, 61 | ctx: RpcContext, 62 | _req: Rectangle, 63 | mut sink: ServerStreamingSink, 64 | ) { 65 | let headers = ctx.request_headers().clone(); 66 | sink.set_headers(headers); 67 | ctx.spawn(async move { 68 | let f = Feature { 69 | name: "hello world".to_owned(), 70 | ..Default::default() 71 | }; 72 | sink.send((f, WriteFlags::default())).await.unwrap(); 73 | sink.close().await.unwrap(); 74 | }); 75 | } 76 | } 77 | 78 | // TODO: test it in interop tests once trailer is supported. 79 | #[test] 80 | fn test_metadata() { 81 | let env = Arc::new(EnvBuilder::new().build()); 82 | let service = create_route_guide(GreeterService); 83 | let mut server = ServerBuilder::new(env.clone()) 84 | .register_service(service) 85 | .build() 86 | .unwrap(); 87 | let port = server 88 | .add_listening_port("127.0.0.1:0", ServerCredentials::insecure()) 89 | .unwrap(); 90 | server.start(); 91 | let ch = ChannelBuilder::new(env).connect(&format!("127.0.0.1:{port}")); 92 | let client = RouteGuideClient::new(ch); 93 | 94 | let mut builder = MetadataBuilder::with_capacity(3); 95 | builder 96 | .add_str("k1", "v1") 97 | .unwrap() 98 | .add_bytes("k1-bin", &[0x00, 0x01, 0x02]) 99 | .unwrap(); 100 | let metadata = builder.build(); 101 | let call_opt = CallOption::default().headers(metadata); 102 | 103 | let mut req = HelloRequest::default(); 104 | req.name = "world".to_owned(); 105 | let mut resp = client 106 | .list_features_opt(&Default::default(), call_opt) 107 | .unwrap(); 108 | let headers = block_on(resp.headers()).unwrap(); 109 | 110 | // assert_eq!(msg.get_message(), "hello world"); 111 | let mut v: Vec<_> = headers.iter().collect(); 112 | v.sort(); 113 | assert_eq!(v[0], ("k1", b"v1" as &[u8])); 114 | assert_eq!(v[1], ("k1-bin", &[0x00u8, 0x01, 0x02] as &[u8])); 115 | let msg = block_on(resp.try_next()).unwrap(); 116 | assert_eq!( 117 | msg.as_ref().map(|f| f.name.as_str()), 118 | Some("hello world"), 119 | "{msg:?}" 120 | ); 121 | assert_eq!(block_on(resp.try_next()).unwrap(), None); 122 | } 123 | 124 | /// Tests rich error can be accessed correctly. 125 | #[test] 126 | fn test_rich_error() { 127 | let env = Arc::new(EnvBuilder::new().build()); 128 | let service = create_greeter(GreeterService); 129 | let mut server = ServerBuilder::new(env.clone()) 130 | .register_service(service) 131 | .build() 132 | .unwrap(); 133 | let port = server 134 | .add_listening_port("127.0.0.1:0", ServerCredentials::insecure()) 135 | .unwrap(); 136 | server.start(); 137 | let ch = ChannelBuilder::new(env).connect(&format!("127.0.0.1:{port}")); 138 | let client = GreeterClient::new(ch); 139 | 140 | let mut req = HelloRequest::default(); 141 | req.name = "root".to_owned(); 142 | let s: Status = match client.say_hello(&req) { 143 | Err(grpcio::Error::RpcFailure(s)) => s.try_into().unwrap(), 144 | res => panic!("expected failure, got {:?}", res), 145 | }; 146 | assert_eq!(s.code, RpcStatusCode::INVALID_ARGUMENT.into()); 147 | assert_eq!(s.message, "name can't be root"); 148 | let details: Option = s.details[0].unpack().unwrap(); 149 | assert_eq!(Some(req), details); 150 | } 151 | -------------------------------------------------------------------------------- /tests-and-examples/tests/cases/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | mod auth_context; 4 | mod cancel; 5 | mod credential; 6 | mod kick; 7 | mod metadata; 8 | mod misc; 9 | mod stream; 10 | -------------------------------------------------------------------------------- /tests-and-examples/tests/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0. 2 | 3 | mod cases; 4 | -------------------------------------------------------------------------------- /xtask/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xtask" 3 | version = "0.1.0" 4 | authors = ["Jay Lee "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | prost-build = "0.13" 11 | # Use an old enough version to make sure generated code with TiKV's fork. 12 | # TODO: use latest one when TiKV's fork is updated 13 | protoc-rust = "=2.8" 14 | protobuf-codegen = "3.2.0" 15 | --------------------------------------------------------------------------------